/* The marketing layer — page rhythm, fluid display type, container widths.
 *
 * 🔴 **THE RULE: this file declares NO COLOUR.** Not a hex, not an rgb(), not an
 * hsl(). Every colour on every web surface comes from `tokens.css`, which is
 * generated from `parisar.tokens.json` — Doc 3.2 rule zero. Colour is the one
 * thing the app and the web must never disagree about, because disagreeing
 * makes them two brands; everything else here is a page-layout concern the
 * Flutter app has no concept of.
 *
 * `tests/acceptance/test_design_tokens.py::test_the_marketing_layer_declares_no_colour`
 * fails the build on any colour literal in this file. Composed values are fine
 * and encouraged — `1px solid var(--border-hairline)` is a line treatment built
 * from an app role, not a new colour.
 *
 * ⚠️ Unlike `tokens.css` this file is hand-authored, because these values have
 * no counterpart in the app's token file and inventing one would put marketing
 * concerns into the design system the product runs on. That is a deliberate
 * split, not an oversight: the app tokens are shared truth, this is a surface.
 *
 * Every static step below resolves to an app token via `var(--text-*)`, so the
 * two scales cannot drift apart at the sizes they share. Only genuinely
 * web-only things — fluid clamps, section rhythm, measure — are new literals.
 */

:root {
  /* pending review: a self-hosted display serif. Falls back to the
  --font-display: var(--font-base);
  /* fluid marketing display type (app display tops out at 34px) */
  --step-mega: clamp(2.75rem,9vw,7rem);
  --step-numeral: clamp(3rem,7vw,5.5rem);
  --step-display-1: clamp(2.25rem,6vw,4.5rem);
  --step-display-2: clamp(1.875rem,4.4vw,3rem);
  --step-doc-title: clamp(1.75rem,3.4vw,2.5rem);
  --step-h1: clamp(1.625rem,3vw,2.25rem);
  --step-h2: clamp(1.5rem,2.6vw,2rem);
  --step-h3: clamp(1.375rem,2.4vw,1.75rem);
  --step-h2-static: clamp(1.375rem,2.2vw,1.75rem);
  --step-lead: clamp(1rem,1.3vw,1.125rem);
  --step-price: clamp(1.75rem,3vw,2.5rem);
  /* static steps map straight onto the app scale */
  --step-h3-static: var(--text-headline-size);
  --step-h4: var(--text-title-size);
  --step-h5: var(--text-title-size);
  --step-lg: var(--text-body-lg-size);
  --step-md: var(--text-body-lg-size);
  --step-base: var(--text-body-size);
  --step-sm-plus: var(--text-body-size);
  --step-sm: var(--text-label-size);
  --step-xs: var(--text-label-size);
  --step-2xs: var(--text-caption-size);
  --step-label: var(--text-caption-size);
  --step-label-lg: var(--text-caption-size);
  --step-label-sm: var(--text-caption-size);
  --step-wordmark: var(--text-title-size);
  --step-wordmark-sm: var(--text-title-size);
  --step-wordmark-xs: var(--text-body-lg-size);
  /* line height ratios for fluid type; the app ships fixed px pairs */
  --lh-display: 1.06;
  --lh-tight: 1.1;
  --lh-snug: 1.18;
  --lh-title: 1.25;
  --lh-heading: 1.35;
  --lh-body: 1.5;
  --lh-prose: 1.6;
  --lh-doc: 1.65;
  --track-display: -0.02em;
  --track-display-tight: -0.026em;
  --track-tight: -0.01em;
  --track-wordmark: 0.01em;
  --track-label-sm: var(--text-caption-tracking);
  --track-label: 0.08em;
  --track-label-lg: 0.1em;
  /* one spacing addition; the rest is the app scale */
  --space-5xl: 96px;
  --space-6xl: 128px;
  /* page rhythm */
  /* `--section-y` is the standard band; the -xs..-2xl ramp below is kept for
     sections that continue the one above them rather than starting a chapter. */
  --section-y: clamp(56px,8vw,120px);
  --section-y-2xl: clamp(48px,9vw,104px);
  --section-y-xl: clamp(48px,7vw,96px);
  --section-y-lg: clamp(40px,6vw,80px);
  --section-y-md: clamp(32px,5vw,56px);
  --section-y-sm: clamp(24px,4vw,40px);
  --section-y-xs: clamp(24px,3vw,32px);
  --gutter: clamp(20px,5vw,56px);
  --flow-gap: clamp(28px,4vw,60px);
  --pad-panel-lg: clamp(24px,3.5vw,40px);
  --pad-panel: clamp(24px,3vw,36px);
  --pad-row-lg: clamp(20px,3vw,32px);
  --pad-row: clamp(20px,2.5vw,28px);
  /* line treatments, composed from app colour roles */
  --line-hairline: 1px solid var(--border-hairline);
  --line-default: 1px solid var(--border-default);
  --line-strong: 1px solid var(--border-strong);
  --line-primary: 1px solid var(--primary-default);
  --line-primary-strong: 1.5px solid var(--primary-default);
  --line-dashed: 1px dashed var(--border-default);
  --rail-accent: 3px solid var(--primary-default);
  /* ⚠️ `--rail-accent` is PRIMARY-coloured and predates the role names. The
     canvas calls it `--rail-primary`; both resolve to the same declaration so
     existing pages keep working while new ones use the honest name. */
  --rail-primary: 3px solid var(--primary-default);
  --rail-clay: 3px solid var(--accent-default);
  /* containers */
  --w-wide: 1240px;
  --w-read: 820px;
  --measure: 66ch;
  --col-lg: 320px;
  --col-md: 280px;
  --col-sm: 260px;
  --media-h-xl: clamp(240px,32vw,420px);
  --media-h-lg: clamp(220px,28vw,360px);
  --media-h-md: clamp(200px,26vw,340px);
  --placeholder-fill: repeating-linear-gradient(135deg,var(--surface-sunken) 0 10px,var(--surface-raised) 10px 20px);
  --slot: repeating-linear-gradient(135deg,var(--surface-sunken) 0 12px,var(--surface-raised) 12px 24px);
}

/* Interaction states.
 *
 * The design canvas expresses hover with a `style-hover` attribute, which is an
 * editor construct and not CSS. There are exactly seven distinct patterns
 * across the whole site, so they become seven named classes rather than seven
 * hundred inline duplicates.
 *
 * 🔴 Every value is a var() from tokens.css — see the no-colour rule at the top
 * of this file. A hover state is where a stray literal is most likely to appear
 * and least likely to be noticed, because nobody screenshots a hover.
 *
 * ⚠️ Guarded by `@media (hover: hover)`. On a touch device a :hover rule sticks
 * after a tap until something else is tapped, so a "hovered" nav item stays
 * highlighted and reads as the current page. Most of this site's readers are on
 * a phone.
 */
@media (hover: hover) {
  .hv-link:hover      { color: var(--primary-default); }
  .hv-nav:hover       { background: var(--surface-sunken); color: var(--ink-default); }
  .hv-btn:hover       { background: var(--primary-pressed); }
  .hv-btn-ghost:hover { border-color: var(--ink-tertiary); background: var(--surface-sunken); }
  .hv-chip:hover      { color: var(--ink-default); border-color: var(--ink-tertiary); }
  .hv-border:hover    { border-color: var(--ink-tertiary); }
  .hv-raise:hover     { background: var(--surface-raised); }
}

/* Focus is NOT inside the hover guard. A keyboard user on a desktop and a
 * switch-control user on a phone both need the ring, and `hover: hover` is a
 * statement about pointers, not about keyboards. */
a:focus-visible,
button:focus-visible {
  outline: var(--focus-width) solid var(--focus-ring);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-xs);
}

/* The page body never scrolls sideways; wide content scrolls inside its own box. */
.scroll { overflow-x: auto; }


/* ============================================================================
 * Layout — the fix for the ceiling that made this site read thin.
 *
 * 🔴 **The shell must never constrain width; a section declares its own tier.**
 * `base.html` used to wrap every page in `max-width: 46rem`, so `--w-wide` and
 * `--w-read` were defined, requested by six pages, and unreachable by all of
 * them — every page rendered as one 736px document column at every breakpoint.
 * A token that is declared, asked for, and structurally impossible to reach is
 * the same defect shape this codebase keeps finding in Python; this was it in
 * CSS. If you are tempted to put a max-width back on `main`, that is the bug.
 * ========================================================================= */

.section { padding-block: var(--section-y); }
/* A section that continues the one above it rather than opening a chapter. */
.section--tight { padding-block: var(--section-y-sm); }
.section--flush-top { padding-block-start: 0; }

/* Surfaces carry the chapters. Squint at 10% zoom: 3-5 bands per page.
 * A hairline only where the tonal step is too small to read as a break. */
.section--sunken  { background: var(--surface-sunken); }
.section--default + .section--sunken { border-top: var(--line-hairline); }
.section--raised  { background: var(--surface-raised); }
.section--inverse { background: var(--surface-inverse); color: var(--ink-inverse); }
/* ⚠️ On the inverse band, `--accent-default` drops to 2.63:1. Clay text there
 * uses the far end of the ramp; see tokens `--accent-on-inverse`. */
.section--inverse .clay { color: var(--accent-on-inverse); }
.section--inverse a { color: var(--primary-tint); }

/* The tiers. Inner content sits on one of these; the band itself may be full
 * bleed, so a coloured background reaches the viewport edge while its text
 * keeps the gutter and nothing touches the screen edge on a 360px phone. */
.tier { margin-inline: auto; padding-inline: var(--gutter); }
.tier-wide    { max-width: var(--w-wide); }
.tier-read    { max-width: var(--w-read); }
.tier-measure { max-width: var(--measure); }
.prose { max-width: var(--measure); }

/* Every grid is one construction: 4 -> 2 -> 1 falls out intrinsically, with no
 * media query anywhere in this file. `min(100%, ...)` is what stops a 280px
 * track overflowing a 360px viewport. */
.grid { display: grid; gap: var(--space-lg); }
.grid-sm { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--col-sm)), 1fr)); }
.grid-md { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--col-md)), 1fr)); }
.grid-lg { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--col-lg)), 1fr)); }
/* Prose with a pull-out beside it. `align-items: start` keeps the aside at the
 * top rather than stretching it to the prose's height. */
.grid-aside {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--col-lg)), 1fr));
  align-items: start;
  gap: var(--space-2xl);
}

/* Skip link — the first thing a keyboard or screen-reader user meets. */
.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--surface-raised); color: var(--ink-default);
  padding: var(--space-sm) var(--space-md); border: var(--line-default);
  border-radius: var(--radius-sm); z-index: 10;
}
.skip:focus { left: var(--gutter); top: var(--space-sm); }

/* Navigation. No hamburger and no JS-only menu: the overflow is a native
 * <details>, which opens by keyboard and works with scripting disabled. */
.nav { display: flex; gap: var(--space-md); flex-wrap: wrap; align-items: baseline; }
.nav a { text-decoration: none; }
.nav [aria-current="page"] { color: var(--ink-default); font-weight: var(--text-label-weight); }
.nav-more > summary { cursor: pointer; list-style: none; color: var(--primary-default); }
.nav-more > summary::-webkit-details-marker { display: none; }
.nav-more > summary::after { content: " A"; }
.nav-more[open] > summary::after { content: " 9"; }
.nav-more .nav-more__panel {
  display: flex; flex-wrap: wrap; gap: var(--space-md);
  padding: var(--space-sm) 0 0;
}

/* Footer link groups. */
.foot-groups { display: grid; gap: var(--space-lg);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--col-sm)), 1fr)); }
.foot-groups h2 { font-size: var(--step-label); letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--ink-tertiary); margin: 0 0 var(--space-xs); }
.foot-groups ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-xxs); }
