/* ============================================================================
   Expeal design tokens — single source of truth.
   Implements design-direction.md §3 (color), §4 (type), §6 (spacing /
   breakpoints / elevation), §7.5 (icon system). Motion (§8 / D30) lands in
   Story 1.2.4 and extends this file.

   Token NAMES follow design-direction.md §3 (the spec), not the Phase-1
   prototype's abbreviated names — see docs/design/drift-log.md #3. The hex
   VALUES are the prototype's confirmed values, carried forward and then
   contrast-verified here (Story 1.2.1 / synthesis G1).

   Every ratio below is measured by scripts/check-contrast.mjs (WCAG 2.x
   relative-luminance). Run `node scripts/check-contrast.mjs` to re-verify;
   it exits non-zero if any gated pair drops below target. Targets per §3.5:
   body text ≥4.5:1, large text & non-text UI ≥3:1.
   ============================================================================ */

/* ── Font face (§4 / D13 / G3) ──────────────────────────────────────────────
   Atkinson Hyperlegible Next (Braille Institute, 2025), SELF-HOSTED — no font
   CDN (privacy posture). One variable woff2 covers the 400–700 range the scale
   uses; font-display:swap so first paint uses the system fallback and never
   blocks LCP. See src/assets/fonts/atkinson-hyperlegible-next/ (OFL 1.1). */
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("/assets/fonts/atkinson-hyperlegible-next/AtkinsonHyperlegibleNextVF-Variable.woff2")
       format("woff2-variations");
  font-weight: 400 700;   /* variable weight range exposed to CSS */
  font-style: normal;
  font-display: swap;
}

:root {
  /* ── Brand anchors (§3.1) ────────────────────────────────────────────────
     US-flag-derived (navy + Old Glory red): civic gravity, not partisanship. */
  --expeal-purple: #3C3B6E;   /* primary: logo, primary-CTA bg, active state-switcher */
  --expeal-red:    #B22234;   /* secondary/emphasis. NEVER a primary CTA or a form error */

  /* ── Purple interaction ramp (§3.6 / gap G2) ─────────────────────────────
     G2 DECISION: derive interaction states by DARKENING --expeal-purple; do
     NOT carry the legacy periwinkle tints (#b1afe9 / #d8d7f4). Rationale: the
     legacy tints are cool-leaning and fight the warm-neutral spine (§3.2); a
     darken-only ramp gives cleaner, higher-contrast hover/active states and
     matches the Phase-1 prototype (which shipped --purple-hover #302F58 and no
     periwinkle). Disabled state = reduced opacity on the neutral spine, not a
     periwinkle tint (defined with components in Epic 1.4). */
  --purple-hover:  #302F58;   /* primary-CTA hover — darken only, no transform. white label 12.55:1 */
  --purple-active: #26253F;   /* primary-CTA pressed/active.                    white label 14.80:1 */

  /* ── Warm-neutral spine (§3.2) ───────────────────────────────────────────
     "Community, not clinic." A warm cast separates us from SaaS gray + nonprofit navy. */
  --surface-primary:  #FBFAF5; /* page background — warm off-white, not stark #FFF */
  --surface-elevated: #FFFFFF; /* cards, modals, surfaces that sit proud of the page */
  --ink-body:  #1A1A22;        /* body copy.            16.54:1 on page · 17.29:1 on card */
  --ink-muted: #5A5A66;        /* captions, metadata.    6.51:1 on page ·  6.80:1 on card */

  /* ── Borders — two tokens, two obligations ───────────────────────────────
     --border-subtle is a DECORATIVE hairline (card edges, dividers): WCAG
     1.4.11 exempt because it is not the sole means of identifying a component
     (the surface shift is). --border-strong is for FORM INPUT chrome, whose
     boundary carries state the user must perceive — so it must clear 3:1. */
  --border-subtle: #E4E2DB;    /* card/divider hairline (1.24:1 — decorative, exempt) */
  --border-strong: #8C887E;    /* input border. 3.38:1 on page · 3.54:1 on card (≥3:1 ✓) */

  /* ── Informational accent (§3.3) ─────────────────────────────────────────
     A separate link blue so links don't collapse into brand purple. */
  --accent-info: #4A6FA5;      /* in-text links, "learn more". 4.89:1 on page · 5.11:1 on card */

  /* ── Functional status accents (§3.4) — status only, never decoration ─────
     Each result state pairs a tinted bg with a darker ink for its text. Color
     is never the sole signal (icon + word accompany it — §3.5 / eligibility). */
  --color-success:    #2E7D52; /* "qualifies" — forest green */
  --success-bg:       #E7F1EA;
  --success-border:   #D3E4D9;
  --success-ink:      #1F5C3B; /*  6.85:1 on --success-bg ✓ */
  --color-warning:    #8A6510; /* "may qualify" — warm amber */
  --warning-bg:       #F6EFD9;
  --warning-border:   #E8DCB8;
  --warning-ink:      #6E5210; /*  6.35:1 on --warning-bg ✓ */
  --color-neutral:    #5A5A66; /* "does not appear to qualify" — neutral, NOT red */
  --neutral-bg:       #F1F0EC;
  --neutral-ink:      #3A3A44; /*  9.86:1 on --neutral-bg ✓ */
  --color-error-form: #D63626; /* FORM VALIDATION ERRORS ONLY. 4.76:1 on card ✓.
                                  Distinct from --expeal-red so brand never reads as "you erred". */

  /* ── Focus ring (§3.5 / WCAG 2.4.11) ─────────────────────────────────────
     2px --accent-info; ≥3:1 against both surfaces (4.89:1 page / 5.11:1 card). */
  --focus-ring: 0 0 0 2px var(--accent-info);

  /* ══ TYPOGRAPHY (§4) ══════════════════════════════════════════════════════
     One family, humanist sans. 18px body floor is non-negotiable (§4.1). */
  --font: "Atkinson Hyperlegible Next", system-ui, -apple-system, BlinkMacSystemFont,
          "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* Weights — Atkinson Hyperlegible Next supplies all four (the original only
     had 400/700; choosing Next lets the scale hit 500/600 exactly — supersedes
     drift-log item #5). */
  --fw-regular: 400; --fw-medium: 500; --fw-semibold: 600; --fw-bold: 700;

  /* Modular 1.25 scale (§4.4). 10 size tokens, each with its own line-height —
     NOT the prototype's 2 global line-heights (drift-log #1). Display sizes use
     clamp() to scale fluidly between --bp-md and --bp-xl (§4.4); static sizes
     scale uniformly via root font-size.
        token          size (desktop)   line-height   weight   role */
  --fs-display-1: clamp(2.25rem, 0.94rem + 2.84vw, 3.5rem);  /* 36→56px  1.10  700  hero */
  --fs-display-2: clamp(2rem, 1.22rem + 1.70vw, 2.75rem);    /* 32→44px  1.15  700  topic H1 */
  --fs-h1:    2.125rem;   /* 34px   1.20  700  content-page H1 (statute/research) */
  --fs-h2:    1.75rem;    /* 28px   1.25  600  section heading */
  --fs-h3:    1.375rem;   /* 22px   1.30  600  sub-section heading */
  --fs-h4:    1.125rem;   /* 18px   1.40  600  minor heading / inline label */
  --fs-body:  1.125rem;   /* 18px   1.60  400  default body — the floor */
  --fs-body-lg: 1.25rem;  /* 20px   1.55  400  intro paragraph / dek */
  --fs-caption: 0.875rem; /* 14px   1.50  500  metadata, "last reviewed" stamp */
  --fs-micro: 0.75rem;    /* 12px   1.40  500  legal fine print only */

  --lh-display-1: 1.1;  --lh-display-2: 1.15;
  --lh-h1: 1.2;  --lh-h2: 1.25;  --lh-h3: 1.3;  --lh-h4: 1.4;
  --lh-body: 1.6;  --lh-body-lg: 1.55;  --lh-caption: 1.5;  --lh-micro: 1.4;

  --measure: 43.75rem;  /* 700px — long-form line length, 65–75ch (§4.6 / D15) */

  /* ══ SPACING (§6.2 / D23) ══════════════════════════════════════════════════
     8pt base, modular. "Calm rhythm over density." Usage bands (§6.2):
       within a component  --space-2…4   between components  --space-5…6
       between sections    --space-7…8   hero→first block    --space-8 min.
     Authored in rem (÷16) so spacing scales with the user's root font-size
     alongside the static type sizes (§6.3); the px equivalents are noted. */
  --space-1: 0.25rem;  /*   4px */
  --space-2: 0.5rem;   /*   8px */
  --space-3: 1rem;     /*  16px */
  --space-4: 1.5rem;   /*  24px */
  --space-5: 2rem;     /*  32px */
  --space-6: 3rem;     /*  48px */
  --space-7: 4rem;     /*  64px */
  --space-8: 6rem;     /*  96px */
  --space-9: 8rem;     /* 128px */

  /* ══ LAYOUT WIDTHS (§6.1 / D22) ════════════════════════════════════════════
     12-col grid; long-form measure caps at --content (= --measure, 680–720px);
     breakouts widen to media/feature rows; --content-full is the outer cap past
     which margins grow but content holds steady (§6.3 / --bp-xl behaviour). */
  --content:      var(--measure); /* 700px — default reading column */
  --content-wide: 60rem;          /* 960px — breakout rows (media, 2-up cards) */
  --content-full: 80rem;          /* 1280px — page container cap */

  /* ══ BREAKPOINTS (§6.3 / D24) ══════════════════════════════════════════════
     Three structural breakpoints, mobile-first min-width. PUBLISHED HERE AS
     TOKENS for reference/JS, but @media conditions CANNOT read custom props —
     the actual queries must hard-code the em literals below. Container queries
     (not these) are the primary component-responsiveness mechanism (§6.3); use
     these only for page-frame shifts (nav unfold, column count). */
  --bp-md: 46rem;  /* 736px — single-col → multi-col; tablets/foldables */
  --bp-lg: 68rem;  /* 1088px — desktop nav unfolds; sidebar-capable */
  --bp-xl: 90rem;  /* 1440px — container hits --content-full; margins grow only */

  /* ══ ELEVATION (§6.6 / D26 / gap G4) ═══════════════════════════════════════
     Exactly three levels — no more. Default is FLAT; shadow is reserved for
     true elevation, never decoration (§6.6 anti-pattern: "shadow-heavy cards").
     Cards use --border-subtle, NOT --shadow-1 (§6.5). Soft, low-alpha shadows
     tinted toward the warm-neutral ink so they read calm, not glossy/SaaS. */
  --shadow-0: none;                              /* Level 0 — flat (page, sections) */
  --shadow-1: 0 1px 4px rgba(26, 26, 34, 0.08);  /* Level 1 — elevated: optional on cards, sticky nav */
  --shadow-2: 0 4px 16px rgba(26, 26, 34, 0.12); /* Level 2 — floating: modals, dropdowns */

  /* ══ ICONOGRAPHY (§7.5 / D28 / gap G4) ═════════════════════════════════════
     LIBRARY = Lucide (ISC, lucide.dev — see src/_icons/LICENSE). One cohesive set, no icon-mixing.
     Line icons only, 1.5px stroke at 24px default (Lucide ships 2px → override
     to 1.5 via --icon-stroke when inlining). Icons are SELF-HOSTED static SVGs
     (no runtime JS, no CDN — privacy posture); every icon must communicate, no
     decorative ornaments (§7.5). Tier glyphs (⭐/○) are TEXT, not SVG imports
     (§11.11) — they are not part of this library. */
  --icon-size:   1.5rem;  /* 24px default */
  --icon-stroke: 1.5;     /* unitless; applied as stroke-width on inlined SVGs */

  /* ══ MOTION (§8 / D30 / gap G10) ═══════════════════════════════════════════
     "Motion is friction" (§8.1) — these tokens exist to keep the permitted set
     SMALL and uniform, never to invite animation. Motion is OPT-IN per component
     using these durations; nothing here animates on its own. The permitted set
     (§8.2): hover = color/background only; focus ring = opacity; dropdown/
     accordion = height+opacity; scroll-reveal = ≤8px translate + opacity. The
     global `prefers-reduced-motion` rule (style.css) collapses all of it to
     instant, so every transition MUST use one of these duration tokens to be
     caught by that rule. FORBIDDEN regardless (§8.3): autoplay, parallax,
     infinite spinners, decorative/looping animation, and ALL motion on
     disclosure surfaces (they simply opt into none of the below). */
  --dur-fast:  100ms;  /* focus-ring opacity (§8.2) */
  --dur-hover: 150ms;  /* hover color/background; scroll-reveal lower bound (§8.2) */
  --dur-panel: 200ms;  /* dropdown/accordion height+opacity; scroll-reveal upper bound (§8.2) */
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);  /* the ONLY curve — decelerating, never springy/bouncy (§8.2) */
  --reveal-shift: 8px; /* max scroll-reveal translate distance (§8.2) */
}
/* expeal.com — starter styles.
   Structural scaffold styles. Color now flows from the real design tokens in
   tokens.css (Story 1.2.1); the local aliases below just re-point the scaffold's
   existing selectors at the brand tokens. Type/spacing/layout tokens replace the
   remaining placeholders in Stories 1.2.2–1.2.3; motion tokens + the global
   reduced-motion rule arrive in Story 1.2.4 (see the bottom of this file). */

:root {
  --color-bg: var(--surface-primary);
  --color-text: var(--ink-body);
  --color-muted: var(--ink-muted);
  --color-accent: var(--accent-info);
  --color-border: var(--border-subtle);
  --max-width: 64rem;
  --space: 1rem;
  /* --font, type scale, and --measure now come from tokens.css (Story 1.2.2). */
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--color-text);
  background: var(--color-bg);
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

a {
  color: var(--color-accent);
  /* The one baseline motion in the scaffold: a color-only hover transition.
     Permitted on EVERY surface — §8.3 forbids hover animation on disclosure
     surfaces "beyond color change", so color is the exception that's always OK.
     Uses --dur-hover so the reduced-motion rule (bottom of file) collapses it. */
  transition: color var(--dur-hover) var(--ease-out);
}

main {
  flex: 1 0 auto;
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding: calc(var(--space) * 2) var(--space);
}

/* Accessibility: visible only when focused (skip link). */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  padding: 0.5rem 1rem;
  background: var(--color-text);
  color: #fff;
}
.skip-link:focus {
  left: 0;
  z-index: 10;
}

/* Header / nav */
.site-header {
  border-bottom: 1px solid var(--color-border);
}
.site-header__inner {
  max-width: var(--max-width);
  margin-inline: auto;
  padding: var(--space);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space);
}
.site-header__brand {
  font-weight: 700;
  font-size: 1.25rem;
  text-decoration: none;
  color: var(--color-text);
}
.site-nav__list {
  display: flex;
  gap: var(--space);
  margin: 0;
  padding: 0;
}
.site-nav__list a {
  text-decoration: none;
}

/* Hero (home) */
.hero {
  position: relative;
  isolation: isolate; /* contain the ::before's z-index so it can't slip under other layers */
  text-align: center;
  padding-block: clamp(3rem, 12vw, 8rem);
}
/* Hero imagery reconciliation (§7.3 / gap G7 / Story 1.2.5).
   Per the imagery sourcing decision (2026-06-23): the life-after photo library
   is DEFERRED to launch; the build ships minimal imagery. hero.jpg's heavy fade
   — flagged by G7 as conflicting with §7.3 "no heavy filters" — is reconciled by
   treating the photo as an INTENTIONAL low-opacity background wash rather than a
   featured photo. At ~10% over the warm page surface it reads as faint texture,
   so the heavy fade becomes a deliberate choice and body/heading contrast is
   unaffected (the solid token pairs the contrast gate checks still govern text). */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: url("/assets/images/hero.jpg") center / cover no-repeat;
  opacity: 0.1;
  pointer-events: none;
}
.hero__title {
  font-size: var(--fs-display-1);
  line-height: var(--lh-display-1);
  font-weight: var(--fw-bold);
  margin: 0 0 0.5rem;
}
.hero__tagline {
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body-lg);
  color: var(--color-muted);
  margin: 0;
}

/* Generic prose pages */
.prose {
  max-width: 42rem;
}

/* Footer */
.site-footer {
  flex-shrink: 0;
  border-top: 1px solid var(--color-border);
  color: var(--color-muted);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
}
.site-footer__inner {
  max-width: var(--max-width);
  margin-inline: auto;
  padding: var(--space);
}

/* ── Reduced motion (§8.4 / D30 / gap G10) ───────────────────────────────────
   GLOBAL kill-switch: when the OS signals prefers-reduced-motion, every
   animation and transition on the site collapses to ~instant. This is a
   site-wide guarantee (WCAG 2.3.3) — it catches all current and future motion
   without each component having to opt in, which is exactly why every permitted
   transition is built from the --dur-* tokens that this rule overrides.
   Durations are near-zero (not 0) so animationend/transitionend events still
   fire for any JS that waits on them. scroll-behavior is forced to auto so
   anchor jumps don't smooth-scroll. (Canonical snippet per design-direction §8.4.) */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── State-route stub scaffold (Story 1.3.3; Epic 1.4 replaces the layout) ────
   Moved here from inline style= attributes on _stub-state-page.njk so shipped
   pages honor the CSP's style-src 'self' (Story 2.9.2). Deliberately loud —
   the banner exists to be impossible to mistake for a real page. */
.scaffold { border: 2px dashed #b00; padding: 1rem; margin: 1rem; }
.scaffold__warning { font-weight: bold; color: #b00; }
/* layout.css — layout primitives for the chrome (Story 1.4.1). */
.container { width: 100%; max-width: var(--content-wide, 1200px); margin-inline: auto; padding-inline: var(--space-4); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.topnav__inner { display: flex; align-items: center; gap: var(--space-4); min-height: 64px; }
.topnav__links { display: flex; gap: var(--space-4); margin-inline-start: auto; }
.topnav__actions { display: flex; align-items: center; gap: var(--space-3); }
.topnav__hamburger { display: none; }
@media (max-width: 47.999rem) { /* below --bp-md 768px */
  .topnav__links, .topnav__actions { display: none; }
  .topnav__hamburger { display: inline-flex; margin-inline-start: auto; }
}
.footer__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-6) var(--space-5); padding-block: var(--space-7); }
@media (min-width: 48rem) { .footer__grid { grid-template-columns: repeat(4, 1fr); } }
/* components.css — chrome component styling (Story 1.4.1, COMPONENT-SPEC tokens). */

/* Button (COMPONENT-SPEC "Button") */
.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 48px; padding-inline: var(--space-4); border-radius: 8px; font-weight: 700; text-decoration: none; border: 1px solid transparent; }
.btn--primary { background: var(--expeal-purple); color: #fff; }
.btn--primary:hover { background: var(--purple-hover); }
.btn--primary:active { background: var(--purple-active); }
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* TopNav */
.topnav { background: var(--surface-primary); border-bottom: 1px solid var(--border-subtle); }
.topnav__brand { display: inline-flex; align-items: center; gap: var(--space-2); text-decoration: none; }
.topnav__wordmark { font-size: 23px; font-weight: 700; color: var(--expeal-purple); }
.topnav__links a, .topnav__signin { color: var(--ink-body); text-decoration: none; font-weight: 600; }
.topnav__signin { color: var(--accent-info); }

/* State switcher (COMPONENT-SPEC "StateSwitcher") — the one shadowed chrome element */
.switcher { position: relative; }
.switcher__trigger { display: inline-flex; align-items: center; gap: var(--space-2); min-height: 40px; padding-inline: var(--space-3); border: 1px solid var(--border-subtle); border-radius: 8px; cursor: pointer; list-style: none; }
.switcher__trigger::-webkit-details-marker { display: none; }
.switcher__panel { position: absolute; z-index: 20; margin-top: var(--space-2); min-width: 280px; background: var(--surface-elevated); border: 1px solid var(--border-subtle); border-radius: 8px; box-shadow: var(--shadow-2); padding: var(--space-3); }
.switcher__heading { font-size: var(--fs-caption); font-weight: 700; color: var(--ink-muted); text-transform: uppercase; }
.switcher__row { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2); border-radius: 6px; text-decoration: none; color: var(--ink-body); min-height: 44px; }
.switcher__row:hover { background: var(--surface-primary); }
.switcher__row.is-current { font-weight: 700; color: var(--expeal-purple); }
.switcher__filter input { width: 100%; min-height: 48px; padding-inline: var(--space-3); border: 1px solid var(--border-strong); border-radius: 8px; }
.switcher__list { max-height: 320px; overflow: auto; }
.switcher__directory { display: inline-block; margin-top: var(--space-2); color: var(--accent-info); font-weight: 700; text-decoration: none; }
/* Story 2.3.10 (WCAG 1.4.10 reflow): below the nav-collapse breakpoint the open panel
   pins to the viewport with side gutters — a 320px screen (or a zoomed-in viewport,
   which shrinks into the same range) must never horizontal-scroll to reach the state
   list or its type-to-filter. 47.999rem pairs with layout.css's md query. Regression
   coverage: Story 2.3.11's zoom/reflow pass (Sprint 2) re-measures this. */
@media (max-width: 47.999rem) {
  .switcher__panel { position: fixed; left: var(--space-3); right: var(--space-3); min-width: 0; }
  /* The nav ROW must fit too (surfaced once the panel stopped masking it): the
     trigger is the row's one shrinkable element — ellipsize its label rather than
     push the hamburger past the viewport edge. */
  .topnav__switcher { min-width: 0; flex: 1 1 auto; }
  .switcher__trigger { max-width: 100%; }
  .switcher__current { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* Mobile menu (COMPONENT-SPEC "MobileMenu") */
.mobile-menu { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-4); border-top: 1px solid var(--border-subtle); }
.mobile-menu[hidden] { display: none; }
.mobile-menu__links a { display: block; min-height: 52px; display: flex; align-items: center; border-bottom: 1px solid var(--border-subtle); text-decoration: none; color: var(--ink-body); }
.mobile-menu__cta { margin-top: auto; }

/* Footer (COMPONENT-SPEC "SiteFooter") */
.footer__crisis { background: var(--expeal-purple); color: #fff; padding-block: var(--space-5); }
.footer__crisis-lead { font-weight: 700; font-size: var(--fs-body-lg); }
/* 988 is a real tel: link (Story 2.3.4): inherit keeps it white on the purple band
   (the verified white/expeal-purple contrast pair); focus outline in currentColor so
   the indicator is visible against the purple, not the accent blue. */
.footer__988 { color: inherit; text-decoration: underline; }
.footer__988:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.footer__anti { background: var(--surface-primary); border-block: 1px solid var(--border-subtle); padding-block: var(--space-4); color: var(--ink-muted); }
.footer__head { font-size: 13px; font-weight: 700; text-transform: uppercase; color: var(--ink-body); }
.footer__col a { font-size: 15px; color: var(--ink-muted); text-decoration: none; }
.footer__bottom-inner { display: flex; align-items: center; gap: var(--space-2); padding-block: var(--space-4); }
.footer__bottom p { font-size: 14px; color: var(--ink-muted); }

/* Motion: dropdown 200ms on the full surface only; none on disclosure or reduced-motion */
@media (prefers-reduced-motion: no-preference) {
  .topnav:not(.topnav--minimal) .switcher__panel { transition: opacity var(--dur-panel, 200ms) var(--ease-out); }
}