/* ============================================================================
 * BABYWEEKS — DESIGN TOKENS (single source of truth, D-421 Part 1 + 6.3)
 * ============================================================================
 * This file is the ONE place a design value may live. The app, the workbench
 * and every chat mock reference these names; no value ships in two places.
 *
 * Three tiers (D-421):
 *   1. PRIMITIVE — raw values, named by value. The ONLY tier allowed to hold
 *      a literal. Never referenced directly by component CSS; go through
 *      the semantic tier.
 *   2. SEMANTIC — role/intent names referencing primitives. This is the tier
 *      surfaces use. Names stay identical across editions/themes; only the
 *      values behind them swap (see the [data-theme]/[data-edition] blocks).
 *   3. COMPONENT — component-scoped tokens referencing semantic. Only where
 *      a composite genuinely earns its keep.
 *
 * EXTRACTION INVENTORY (built 2026-07-03, extract-don't-invent):
 *   - web/css/app.css — the shipped shell stylesheet: the full :root palette
 *     (--paper/--ink/--hero/--warm family), every raw hex/rgba then in use
 *     (tab bar #fffbf2/#e6dfd0/#8a9aab/#2c4a6b, hovers #f0ebe1/#f9f5ec,
 *     washes #fff5e6/#fdf2e6, error #d32f2f/#ffe6e6, avatar #a8d8ea,
 *     log-suggest #f5f0e8/#e2d9c8, success #3a7d44, accent-hover #b24a27,
 *     alpha variants of ink/paper/sage/warm), the type steps 8–60px, the
 *     spacing increments 2–44px, radii 2/3/4/6/12/18/999px, the two shadows,
 *     z-index 95/99/100/200/1000, durations 100–300ms.
 *   - PALETTE LOCK (D-426, 2026-07-03) — palette #1 "TEAL": TEAL is the brand
 *     AND the primary interactive colour (buttons, links, focus, nav);
 *     GOLDEN is the accent/highlight (emphasis, badges, celebrate, warm
 *     notice+safety washes); NEUTRALS stay the warm cream from the animation
 *     (D-305), NOT the palette's warm greys; status = shared success/info/
 *     warning/error set. This RESTYLES: the old wordmark-only teal #2e5c5c and
 *     the warm-orange interactive accent are retired. Wordmark "BabyWeeks."
 *     stays Fraunces 600 (D-411), dot now teal-600 #23867a.
 *   - web/css/progress.css + weaning.css carry surface-local palettes not
 *     yet reconciled into this file — listed as follow-up in the PR.
 *
 * Dynamic Type (catalogue D-423): all type primitives are rem so the scale
 * follows the user's text-size setting (html { font-size: 100% }). Fluid
 * sizes use clamp() with a rem floor/ceiling — never raw cqi/vw alone,
 * which clips at 200% zoom.
 * ========================================================================== */

:root {

  /* ==========================================================================
   * TIER 1 — PRIMITIVE (raw values, named by value; literals live ONLY here)
   * ========================================================================== */

  /* ---- Colour: cream ladder (light → dark) ------------------------------- */
  --cream-50:  #fffbf2;   /* tab-bar surface */
  --cream-75:  #fdfaf3;   /* raised card surface — brighter, floats on deepened ground (2026-07-08) */
  --cream-100: #f9f5ec;   /* hover wash (chips, tiles, upload box) */
  --cream-150: #f5f0e8;   /* log-suggest row wash */
  --cream-200: #f5f0e0;   /* card surface (was --paper-card) */
  --cream-250: #f0ebe1;   /* card hover */
  --cream-300: #efe9d9;   /* paper ground (was --paper) */
  --cream-350: #e9e2ce;   /* deeper paper ground — gentle card-lift ΔL* ~5 (with crisp edge) */
  --cream-400: #e6dfca;   /* secondary surface (was --paper-2) */
  --cream-450: #e6dfd0;   /* tab-bar top border */
  --cream-500: #e2d9c8;   /* log-suggest border */
  --cream-600: #d8d2bf;   /* hairline rule (was --rule) */

  /* ---- Colour: ink ------------------------------------------------------- */
  --ink-900: #1a1a1a;     /* primary text (was --ink) */
  --ink-600: #5a5a55;     /* secondary text (was --ink-soft) */
  --ink-400: #8a8a82;     /* tertiary / disabled (was --ink-mute) */

  /* ---- Colour: teal (BRAND + primary interactive) ------------------------ */
  /* Palette #1 "TEAL" — locked 2026-07-03 (D-426). Brand AND primary
   * interactive colour (buttons, links, focus, nav). Supersedes the old
   * single --teal-600 #2e5c5c wordmark-only anchor and retires the warm-orange
   * interactive accent. */
  --teal-25:  #f7fcfb;   /* faintest wash — the live-phase box shade (602, Andrew 2026-07-25) */

  /* THE PHASE COLOURS (D-654) — five stops interpolated EVENLY in OKLab between
     teal-200 and teal-600 (the palette ramp's own rungs are uneven: dE .078/.104/.087/.070).
     Phase 1 pale -> Phase 5 = the primary brand teal. On-colours: ink for 1-3, cream 4-5. */
  --phase-1: #bce5df;   /* = teal-200 */
  --phase-2: #99cdc5;
  --phase-3: #75b5ab;
  --phase-4: #509d92;
  --phase-5: #23867a;   /* = teal-600, the brand anchor */
  --phase-1-on: var(--ink-900);
  --phase-2-on: var(--ink-900);
  --phase-3-on: var(--ink-900);
  --phase-4-on: var(--cream-50);
  --phase-5-on: var(--cream-50);
  --teal-50:  #f0faf8;
  --teal-100: #e0f2ef;
  --teal-200: #bce5df;
  --teal-300: #8cd4c9;   /* soft accent */
  --teal-400: #56b7aa;
  --teal-500: #2a9d8f;
  --teal-600: #23867a;   /* brand anchor — wordmark dot + primary buttons/links */
  --teal-700: #1c6e64;   /* hover / pressed */
  --teal-800: #155750;
  --teal-900: #103e3a;

  /* ---- Colour: golden (ACCENT / highlight) ------------------------------- */
  /* Palette #1 accent — golden, for emphasis / badges / celebrate / warm
   * washes (notice + safety cards stay warm on this). Locked 2026-07-03 (D-426). */
  --gold-50:  #fff9e6;   /* notice / selected-tile wash */
  --gold-75:  #fff5d3;   /* share-card safety wash — mid weight (D share-cards, 2026-07-05) */
  --gold-90:  #fff2c7;   /* share-card safety wash — chosen weight (D share-cards, 2026-07-05) */
  --gold-100: #fff0bf;   /* safety-card wash */
  --gold-200: #ffe58a;   /* soft highlight */
  --gold-300: #ffd34d;
  --gold-400: #fbbf24;
  --gold-500: #e0a800;   /* accent / highlight */
  --gold-600: #b88700;
  --gold-700: #8f6700;
  --gold-800: #664900;
  --gold-900: #402e00;

  /* ---- Colour: clay (kind-family "Do" — D-454, added 2026-07-07) ---------- */
  /* Muted terracotta, OKLCH hue ~35° (49° off gold, 148° off teal — a clean,
   * well-separated warm slot; NOT the retired warm-orange accent). Chroma held
   * ~0.85× the teal ramp so it stays calm on cream. Chip = clay-100 fill +
   * clay-600 glyph. Chosen over sage(green ~150°) which sits only 33° from teal
   * and blurs with it — the hue math ruled sage out (D-454 colour-growth pass). */
  --clay-50:  #fef5f3;
  --clay-100: #f8eae6;   /* Do chip fill */
  --clay-200: #f2d3cb;
  --clay-300: #e9b6a9;
  --clay-400: #d09282;
  --clay-500: #b77666;
  --clay-600: #9c6456;   /* Do glyph (AA on clay-100 + cream) */
  --clay-700: #815246;   /* Do glyph, higher-contrast option (≥5:1) */
  --clay-800: #664137;
  --clay-900: #492e27;

  /* ---- Colour: slate (kind-family "Track" — D-454, added 2026-07-07) ------ */
  /* Muted slate-blue, OKLCH hue ~250° (67° off teal — clearly cyan-vs-blue, not
   * a green neighbour; the cool "data" slot, blue-for-charts convention). Chroma
   * ~0.65× so it reads calm, not corporate-blue. Chosen over a warm neutral
   * "stone" which washed into the cream ground (Andrew, 2026-07-07). Chip =
   * slate-100 fill + slate-600 glyph. */
  --slate-50:  #f4f8fc;
  --slate-100: #e7eef6;  /* Track chip fill */
  --slate-200: #ceddee;
  --slate-300: #adc7e2;
  --slate-400: #87a7c9;
  --slate-500: #6b8db0;
  --slate-600: #5b7896;  /* Track glyph (AA on slate-100 + cream) */
  --slate-700: #4a627c;  /* Track glyph, higher-contrast option (≥5:1) */
  --slate-800: #3a4e62;
  --slate-900: #293746;

  /* ---- Colour: evergreen + sage (hero family — from the animation, kept) -- */
  --green-900: #1a3a30;   /* deep evergreen (was --hero) */
  --green-800: #244a3e;   /* hero gradient secondary (was --hero-2) */
  --sage-200:  #c8d2c8;   /* soft sage ornament (was --hero-soft) */

  /* ---- Colour: sky (avatar blue variant — still used by app.css) --------- */
  --sky-200:   #a8d8ea;   /* avatar blue variant */

  /* ---- Colour: semantic status (palette #1 shared set) ------------------- */
  --success-500: #22c55e;  --success-50: #ecfdf5;
  --info-500:    #0ea5e9;  --info-50:    #f0f9ff;
  --warning-500: #f59e0b;  --warning-50: #fffbeb;
  --error-600:   #e11d48;  --error-50:   #fff1f2;

  /* ---- Colour: white ------------------------------------------------------ */
  --white: #ffffff;

  /* ---- Colour: alpha variants (exact rgba values in use) ------------------ */
  --ink-900-a04:   rgba(26, 26, 26, 0.04);    /* card shadow */
  --ink-900-a08:   rgba(26, 26, 26, 0.08);    /* card shadow ambient */
  --ink-900-a12:   rgba(26, 26, 26, 0.12);    /* card shadow contact */
  --ink-900-a18:   rgba(26, 26, 26, 0.18);    /* sheet shadow */
  --ink-900-a55:   rgba(26, 26, 26, 0.55);    /* modal scrim */
  --black-a02:     rgba(0, 0, 0, 0.02);       /* row hover tint */
  --black-a08:     rgba(0, 0, 0, 0.08);       /* faint line fallback */
  --cream-300-a10: rgba(239, 233, 217, 0.1);
  --cream-300-a20: rgba(239, 233, 217, 0.2);
  --cream-300-a50: rgba(239, 233, 217, 0.5);
  --cream-300-a55: rgba(239, 233, 217, 0.55);
  --cream-300-a70: rgba(239, 233, 217, 0.7);
  --cream-300-a90: rgba(239, 233, 217, 0.9);
  --white-a72:     rgba(255, 255, 255, 0.72);
  --ink-warm-a12:  rgba(42, 38, 32, 0.12);     /* D-429 nav active-tab chip (warm ink, D-354 v10) */
  --sage-200-a18:  rgba(200, 210, 200, 0.18); /* hero ornament */
  --sage-200-a00:  rgba(200, 210, 200, 0);
  --orange-600-a55: rgba(35, 134, 122, 0.55); /* mic pulse — teal (var name kept; app.css refs it) */
  --orange-600-a00: rgba(35, 134, 122, 0);    /* rename to --teal-600-a* is a cosmetic follow-up */
  --ink-cool-a38:  rgba(21, 22, 26, 0.38);    /* page-label dev helper */

  /* ---- Type: family stacks ------------------------------------------------ */
  --font-stack-fraunces:  'Fraunces', Georgia, 'Times New Roman', serif;
  --font-stack-inter:     'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
  --font-stack-plex-mono: 'IBM Plex Mono', 'SF Mono', Menlo, monospace;
  /* D-429 (2026-07-04): Schibsted Grotesk is the label/eyebrow/nav-tab font —
   * an editorial-warm grotesque. Retires IBM Plex Mono from those roles (mono
   * read too techie for the warm register); mono stays for code/data/numbers. */
  --font-stack-schibsted: 'Schibsted Grotesk', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;

  /* ---- Type: weights ------------------------------------------------------ */
  --weight-300: 300;
  --weight-400: 400;
  --weight-500: 500;
  --weight-600: 600;   /* D-411 wordmark weight */
  --weight-700: 700;

  /* ---- Type: size steps (rem; named by px equivalent @ 16px root) --------- */
  --size-8:  0.5rem;
  --size-9:  0.5625rem;
  --size-10: 0.625rem;
  --size-11: 0.6875rem;
  --size-12: 0.75rem;
  --size-13: 0.8125rem;
  --size-14: 0.875rem;
  --size-15: 0.9375rem;
  --size-16: 1rem;
  --size-17: 1.0625rem;
  --size-18: 1.125rem;
  --size-20: 1.25rem;
  --size-22: 1.375rem;
  --size-24: 1.5rem;
  --size-26: 1.625rem;
  --size-28: 1.75rem;
  --size-32: 2rem;
  --size-34: 2.125rem;
  --size-36: 2.25rem;
  --size-40: 2.5rem;
  --size-44: 2.75rem;
  --size-60: 3.75rem;

  /* ---- Type: tracking (letter-spacing steps in use) ----------------------- */
  --tracking-neg-015: -0.015em;
  --tracking-neg-01:  -0.01em;
  --tracking-01:  0.01em;
  --tracking-02:  0.02em;
  --tracking-04:  0.04em;
  --tracking-05:  0.05em;
  --tracking-08:  0.08em;
  --tracking-10:  0.1em;
  --tracking-12:  0.12em;
  --tracking-14:  0.14em;

  /* ---- Type: leading (line-height steps in use; unitless) ----------------- */
  --leading-100: 1;
  --leading-110: 1.1;
  --leading-115: 1.15;
  --leading-120: 1.2;
  --leading-140: 1.4;
  --leading-145: 1.45;
  --leading-150: 1.5;
  --leading-155: 1.55;
  --leading-160: 1.6;
  --leading-165: 1.65;

  /* ══════════════════════════════════════════════════════════════════════════
   * THE GRID (D-511) — 4px. EVERY SPACING VALUE IN THE APP IS A MULTIPLE OF IT.
   * ══════════════════════════════════════════════════════════════════════════
   *
   * Andrew: "I want exceptions, but I want STANDARD exceptions — we break the space
   * into vertical and horizontal lines which are snapped to."
   *
   * THAT IS THIS. The grid IS the exception system. There is no blessed list of
   * legal gaps to memorise and no committee to ask: 24px is legal because 24 ÷ 4 = 6.
   * 37px is illegal because it isn't. A designer never has to wonder which it is, and
   * the linter never has to be taught.
   *
   * ⚠️ WHY THE OLD SCALE HAD TO GO. It was 2·3·4·5·6·8·10·12·14·16·18·20·22·24·28·32·
   * 40·44 — EIGHTEEN steps, eight of them off any grid. That is not a system, it is an
   * inventory of decisions somebody once made. With 2, 3, 5 AND 6 all available, "a
   * small gap" had four defensible answers, so the same gap came out differently on
   * every card — and nobody could tell whether a given 14px was a considered choice or
   * a typo. (It was a typo. See --rhythm-stand.)
   *
   * A coarse scale is not a limitation. It is the entire mechanism: fewer legal
   * answers ⇒ the same question gets the same answer twice.
   *
   * 🔴 THE ONE THING THAT MATTERS: --space-* IS FOR THE GAPS BETWEEN THINGS.
   *    IT IS NOT FOR HOW BIG A THING IS. Use --dim-* for that (below).
   *    They used to be the same scale, and that is precisely why snapping to a grid
   *    LOOKED terrifying: bumping "--space-6" from 6px to 8px would have made the
   *    carousel dots 33% fatter. A gap and a dot are not the same kind of number and
   *    must never again share a scale.
   */
  --grid-unit: 4px;

  --space-4:  4px;    /* 1× */
  --space-8:  8px;    /* 2× */
  --space-12: 12px;   /* 3× */
  --space-16: 16px;   /* 4× — the module inset. The most-used value in the app. */
  --space-20: 20px;   /* 5× */
  --space-24: 24px;   /* 6× */
  --space-28: 28px;   /* 7× */
  --space-32: 32px;   /* 8× */
  --space-40: 40px;   /* 10× */
  --space-48: 48px;   /* 12× */

  /* ── OPTICAL NUDGE (D-511) — THE STANDARD EXCEPTION, AND THE ONLY ONE ──────
   * The grid governs LAYOUT. It does not govern OPTICAL CORRECTION, and the difference
   * is not a loophole — it is a different kind of number.
   *
   * A play triangle inside a round button is mathematically centred and LOOKS 2px left,
   * because its visual mass is not its bounding box. Pushing it 2px right is not a gap;
   * it is compensating for a shape. Snap that to 4px and it goes from "slightly wrong"
   * to "obviously wrong" — the grid would have made the design worse, which is how
   * design systems get abandoned.
   *
   * ⚠️ SO IT IS A DIFFERENT TOKEN WITH A DIFFERENT NAME — not a small --space-*.
   * Nobody reaches for `--nudge-2` to set a gap, because it doesn't sound like one.
   * That is the whole trick: the escape hatch is a separate concept, so it cannot be
   * quietly used as a loophole. Check 23 enforces where it may appear. */
  --nudge-1: 1px;
  --nudge-2: 2px;
  --focus-offset: 2px;   /* the focus ring's breathing room — optical, not layout */

  /* ── DIMENSION (D-511) — HOW BIG A THING IS. NOT A GAP. NOT ON THE GRID. ───
   * A 44px play button is 44px because that is the touch floor. A 6px dot is 6px
   * because that is how big the dot looks right. Neither is negotiable by a grid, and
   * neither is spacing.
   *
   * These are the EXACT pixel values the app ships today — this scale was extracted,
   * not invented, so the split cost zero visual change. What it bought is that
   * --space-* can now be snapped freely without any of these moving.
   *
   * (Named by value, unlike --rhythm-*, and on purpose: a rhythm is a property of the
   * SURFACE and must be argued about once. An icon is 24px because it is 24px.) */
  --dim-4:   4px;
  --dim-5:   5px;
  --dim-6:   6px;    /* carousel dot · progress-track height */
  --dim-16: 16px;    /* inline icon */
  --dim-24: 24px;    /* tab icon */
  --dim-32: 32px;    /* avatar · small round chip */
  --dim-40: 40px;    /* kind chip · tab icon well */
  --dim-44: 44px;    /* play mark · step button — == --control-min */

  /* Bottom clearance on a scrolling surface, so the last card is not swallowed by the
   * tab bar: tab bar (~46 + safe area) + footer tag (~32) + air. On the grid (38 × 4). */
  --scroll-clear: 152px;

  /* ── MODULE RHYTHM (D-510) ────────────────────────────────────────────────
   * The vertical spacing INSIDE a home module. Every card used to invent its own,
   * which is exactly how card 104 shipped with a canyon around its standfirst — and
   * why nobody could tell whether the gap was a bug or a choice.
   *
   * ⚠️ NAMED BY ROLE, NOT BY SIZE. `--rhythm-stand` says WHAT it is; `--space-14`
   * only says how big it is. A card that wants "the gap under a standfirst" must not
   * be able to answer that question differently from every other card.
   *
   * Change these once, and the whole surface breathes the same way. Which is the
   * point: the rhythm is a property of the SURFACE, not of any one card. */
  --rhythm-inset:     var(--space-16);  /* left/right inset — every module, same edge */
  --rhythm-pad:       var(--space-16);  /* module top/bottom padding */
  --rhythm-head:      var(--space-4);   /* h2 → standfirst  (was 2px — snapped, D-511) */
  --rhythm-stand:     var(--space-16);  /* standfirst → content. THE ONE THAT BIT US. (was 14px) */
  --rhythm-body:      var(--space-12);  /* media → its caption/title (was 10px) */
  --rhythm-foot:      var(--space-12);  /* content → dots / footer */
  --rhythm-stack:     var(--space-12);  /* module → module (was 10px) */

  /* ---- Control heights (D-463 sizing contract) — interactive size floors ----
     Every tappable control must be >= --control-min. Use the named heights so
     surfaces never hard-code an undersized button/field. See
     docs-evidence-base/SIZING-CONTRACT.md. */
  --control-min: 44px;   /* absolute touch floor (Apple 44pt / Material 48dp; prefer 48) */
  --h-button:    48px;   /* primary button */
  --h-chip:      40px;   /* tappable chip / pill (min 32) */
  --h-search:    50px;   /* Home search field */
  --h-input:     52px;   /* form text input (Material 56dp band) */

  /* ---- Radii --------------------------------------------------------------- */
  --radius-2:  2px;
  --radius-3:  3px;
  --radius-4:  4px;
  --radius-6:  6px;    /* was --r-sm */
  --radius-12: 12px;   /* was --r-md */
  --radius-18: 18px;   /* was --r-lg */
  --radius-pill:  999px;
  --radius-round: 50%;

  /* ---- Layout widths -------------------------------------------------------- */
  --width-420: 420px;  /* content column (was --col-max) */
  --width-430: 430px;  /* tab-bar max width */

  /* ---- Motion (durations/easings in use; full spec lands with D-422) ------- */
  --duration-100: 0.1s;
  --duration-120: 0.12s;
  --duration-150: 0.15s;
  --duration-180: 0.18s;
  --duration-200: 0.2s;
  --duration-300: 0.3s;
  --ease-standard: ease;
  --ease-in-out: ease-in-out;

  /* ==========================================================================
   * TIER 2 — SEMANTIC (role names; everything is var(--primitive))
   * ========================================================================== */

  /* ---- Surfaces ------------------------------------------------------------ */
  --surface-ground:      var(--cream-350);   /* the paper the app sits on (gentle deepen + crisp card edge) */
  --surface-card:        var(--cream-75);    /* raised card — brighter, floats on deepened ground (V3) */
  --surface-card-hover:  var(--cream-150);
  --surface-sunken:      var(--cream-400);   /* recessed BANDS — full-width strips, banners (D-664) */
  /* D-664 — THE DEPTH OF A RECESS IS A FUNCTION OF ITS AREA. --surface-sunken is the darkest
   * cream we have (ΔL* 9.4 from --surface-card) and a full-width band carries that step fine
   * BECAUSE IT RUNS EDGE TO EDGE. On a 40px control the identical step stops reading as depth
   * and starts reading as a blob — it takes the eye before the wordmark does. So small
   * recessed controls (round icon buttons, well-set chips) use this instead: ΔL* 5.1, roughly
   * half the step. Present when looked for, silent when not. */
  --surface-well:        var(--cream-250);   /* recessed CONTROLS — small round buttons, wells (D-664) */
  --surface-bar:         var(--cream-50);    /* tab bar */
  --surface-hover-wash:  var(--cream-100);   /* chip/tile hover */
  --surface-inverse:     var(--ink-900);     /* mic dock, chat input, primary btn */
  --surface-hero:        var(--green-900);
  --surface-hero-2:      var(--green-800);
  --surface-notice:      var(--gold-50);     /* disclaimers, selected tiles (warm) */
  --surface-safety:      var(--gold-100);    /* safety card (warm) */
  --surface-highlight:   var(--gold-50);     /* golden-accent wash */
  --surface-danger:      var(--error-50);
  --surface-info:        var(--info-50);
  --surface-warning:     var(--warning-50);

  /* ---- Text ------------------------------------------------------------------ */
  --text-primary:   var(--ink-900);
  --text-secondary: var(--ink-600);
  --text-tertiary:  var(--ink-400);
  --text-on-dark:   var(--cream-300);   /* cream text on hero/ink surfaces */
  --text-on-accent: var(--cream-50);    /* light text on teal accent fills */
  --text-on-highlight: var(--ink-900);  /* dark text on golden highlight fills */

  /* ---- Borders ----------------------------------------------------------------- */
  --border-hairline: var(--cream-600);
  --border-bar:      var(--cream-450);
  --border-accent:   1px solid var(--accent);  /* teal ring — outlined icon buttons */

  /* ---- Brand + accent (palette #1, locked 2026-07-03 D-426) ---------------------- */
  --brand:        var(--teal-600);    /* wordmark dot + brand identity */
  --accent:       var(--teal-600);    /* primary interactive — buttons, links, focus */
  --accent-hover: var(--teal-700);
  --accent-soft:  var(--teal-300);
  --highlight:      var(--gold-500);  /* golden accent — emphasis, badges, celebrate */
  --highlight-soft: var(--gold-200);
  --danger:       var(--error-600);
  --success:      var(--success-500);
  --info:         var(--info-500);
  --warning:      var(--warning-500);
  --ornament:     var(--sage-200);

  /* ---- Kind-family (colour = consumption mode, D-454) ----------------------------- */
  /* An item's chip/tile colour encodes HOW you consume it (read / do / watch /
   * track), double-coded with the icon shape (= the exact kind). Four families,
   * cleanly mappable to the palette. Area/topic is still NEVER colour-coded
   * (12 topics, un-mappable — holds D-379/D-404). fill = chip background,
   * icon = glyph tone (AA on fill + on cream). Watch uses gold-700 per the gold
   * text rule (D-440); gold stays sparse because animations are rare (D-378). */
  --kind-read-fill:   var(--teal-100);   --kind-read-icon:   var(--teal-600);
  --kind-do-fill:     var(--clay-100);   --kind-do-icon:     var(--clay-600);
  --kind-watch-fill:  var(--gold-100);   --kind-watch-icon:  var(--gold-700);
  --kind-track-fill:  var(--slate-100);  --kind-track-icon:  var(--slate-600);

  /* ---- Navigation (tab bar — teal, palette #1) ------------------------------------ */
  --nav-active:      var(--teal-700);       /* active tab LABEL (teal) */
  --nav-active-icon: var(--teal-600);       /* active tab ICON glyph (brand teal, D-404) */
  --nav-active-chip: var(--ink-warm-a12);   /* soft round chip behind active icon (D-354 v10) */
  --nav-inactive:    var(--ink-400);        /* inactive icon + label (neutral, D-404) */

  /* ---- Fonts ---------------------------------------------------------------- */
  --font-display: var(--font-stack-fraunces);
  --font-body:    var(--font-stack-inter);
  --font-label:   var(--font-stack-schibsted);  /* D-429: eyebrows/kickers, labels, nav-tab labels */
  --font-mono:    var(--font-stack-plex-mono);   /* code/data/numbers only (no longer eyebrows/labels) */
  --weight-display:  var(--weight-500);   /* headings ship at 500 */
  --weight-wordmark: var(--weight-600);   /* D-411: "BabyWeeks." in Fraunces 600 */

  /* ---- Type roles (rem via primitives — Dynamic Type safe) ------------------- */
  --text-display-xl: var(--size-44);   /* h1 */
  --text-display-lg: var(--size-36);   /* hero headline, weekly h1 */
  --text-display-md: var(--size-32);   /* hero week number */
  --text-display-sm: var(--size-28);   /* h2 / .heading */
  --text-title:      var(--size-22);   /* h3 */
  --text-subtitle:   var(--size-18);   /* h4, card heads */
  --text-body-lg:    var(--size-16);
  --text-body:       var(--size-16);   /* re-anchored 15→16 — platform body floor (iOS 17 / Material 16), D-463 */
  --text-standfirst: var(--size-16);   /* subtitles / standfirsts sit AT body, never below */
  --text-body-sm:    var(--size-14);   /* secondary / meta */
  --text-caption:    var(--size-13);
  --text-meta:       var(--size-12);
  --text-label:      var(--size-11);   /* mono eyebrows */
  --text-micro:      var(--size-10);

  /* ---- Radius roles -------------------------------------------------------------- */
  --radius-control:  var(--radius-6);
  --radius-card:     var(--radius-12);
  --radius-card-lg:  var(--radius-18);

  /* ---- Shadows + scrims (geometry lives inside the composite) ------------------ */
  --shadow-card:  0 0 0 1px var(--ink-900-a08), 0 1px 3px var(--ink-900-a08), 0 8px 24px var(--ink-900-a08);
  --shadow-sheet: 0 -8px 30px var(--ink-900-a18);
  --overlay-scrim: var(--ink-900-a55);

  /* ---- Layout ---------------------------------------------------------------------- */
  --layout-col-max: var(--width-420);
  --layout-bar-max: var(--width-420); /* aligned to col-max so the fixed tabbar matches the content frame (was 430 → stuck out ~5px each side) */
  --tap-target:     var(--dim-44);   /* a touch floor is a SIZE, not a gap (D-511) */

  /* ---- Z-index scale --------------------------------------------------------------- */
  /* token-exception: z-index is an ordinal scale — the numbers ARE the
   * relationship, a primitive layer underneath would add nothing. */
  --z-dock:    95;    /* mic dock, chat input row */
  --z-float:   99;    /* footer tag */
  --z-nav:     100;   /* tab bar */
  --z-banner:  200;   /* offline banner, page label */
  --z-overlay: 1000;  /* modal overlay */

  /* ==========================================================================
   * TIER 3 — COMPONENT (only where a composite earns its keep)
   * ========================================================================== */
  --hero-gradient: linear-gradient(135deg, var(--surface-hero) 0%, var(--surface-hero-2) 100%);
  --card-padding:  var(--space-16);   /* was 16px 18px — 18 is off-grid; symmetric now (D-511) */
  --focus-ring:    2px solid var(--accent);
}

/* ============================================================================
 * THEME / EDITION BLOCKS — structure only (D-421 Part 3)
 * Semantic names stay identical; a theme/edition is a VALUE swap behind the
 * same names, never a component change. Populate later; do NOT design here.
 * ========================================================================== */

[data-theme="dark"] {
  /* placeholder — dark values TBD (not designed yet, deliberately).
   * When populated, override SEMANTIC tokens only, e.g.:
   *   --surface-ground: …; --surface-card: …; --text-primary: …;
   * Never override primitives; never add new names. */
}

[data-edition="nl"] {
  /* placeholder — same semantic names, edition-specific values later
   * (D-414 parallel editions). */
}
