/* =============================================================
   design-system.css — Lavender + Willow design system
   Portable token layer. Two source palettes:
     Lavender Veil → Lavender Purple  (primary / brand / interactive)
     Frosted Mint  → Willow Green     (secondary / positive / confirm)

   The five swatches in each source palette are all tints: none of
   them reaches 4.5:1 against white, so they are used as SURFACES
   and FILLS. Text and action colours are the derived 600–900 steps
   below. Every pairing marked ✓ was checked against WCAG 2.1 AA.
   ============================================================= */

/* The three faces, self-hosted (SIL Open Font License 1.1; licences in fonts/).
   Latin subset: characters outside it (subscript digits, most arrows) fall
   through to the system fonts further down each stack. */
@font-face {
  font-family: "Nunito";
  src: url("fonts/nunito-latin-wght-normal.woff2") format("woff2");
  font-weight: 200 1000; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("fonts/atkinson-hyperlegible-next-latin-wght-normal.woff2") format("woff2");
  font-weight: 200 800; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Atkinson Hyperlegible Mono";
  src: url("fonts/atkinson-hyperlegible-mono-latin-wght-normal.woff2") format("woff2");
  font-weight: 200 800; font-style: normal; font-display: swap;
}

:root {
  color-scheme: light;

  /* ---------- lavender ramp (50–400 are the source swatches) ---------- */
  --lav-50:  #ebe0ff;  /* Lavender Veil     */
  --lav-100: #dac7ff;  /* Periwinkle        */
  --lav-200: #c7adff;  /* Mauve             */
  --lav-300: #ac8bee;  /* Soft Periwinkle   */
  --lav-400: #916dd5;  /* Lavender Purple   */
  --lav-500: #7a52c4;  /* derived — smallest fill that holds white text ✓ 5.48 */
  --lav-600: #6340a6;  /* derived — text / links on white ✓ 7.46 */
  --lav-700: #4a2e7e;  /* derived — headings ✓ 10.59 */
  --lav-900: #2e1b52;  /* derived — deep surface, dark-mode base */

  /* ---------- willow ramp (50–400 are the source swatches) ---------- */
  --grn-50:  #e4fde1;  /* Frosted Mint (light) */
  --grn-100: #d5f5d2;  /* Frosted Mint        */
  --grn-200: #c6edc3;  /* Tea Green           */
  --grn-300: #a7dca5;  /* Celadon             */
  --grn-400: #90cf8e;  /* Willow Green        */
  --grn-500: #6fb86d;  /* derived — fill, pairs with ink not white */
  --grn-600: #4f9a50;  /* derived — icons / large text only (3.46) */
  --grn-700: #356e38;  /* derived — text & solid buttons ✓ 6.11 */
  --grn-900: #1e3f22;  /* derived — deep surface */

  /* ---------- neutrals (warmed toward lavender, not pure grey) ---------- */
  --ink:   #1c1725;   /* body text ✓ 17.5 on white  */
  --ink-2: #3b3450;   /* subheads ✓ 11.7            */
  --muted: #5b5470;   /* secondary text ✓ 7.1       */
  --faint: #8a7fa8;   /* placeholders, 3.7 — never body copy */
  --line:  #e5dcf5;
  --line-strong: #cdbfe8;

  /* ---------- surfaces ---------- */
  --bg:      #faf7ff;
  --bg-tint: #f6f2ff;
  --card:    #ffffff;
  --card-2:  var(--lav-50);
  --overlay: rgba(46, 27, 82, .48);

  /* ---------- semantic roles ---------- */
  --primary:        var(--lav-500);
  --primary-hover:  var(--lav-600);
  --primary-ink:    #ffffff;
  --primary-soft:   var(--lav-50);
  --primary-soft-ink: var(--lav-600);   /* ✓ 5.91 on --lav-50 */

  --accent:         var(--grn-700);
  --accent-hover:   var(--grn-900);
  --accent-ink:     #ffffff;
  --accent-soft:    var(--grn-50);
  --accent-soft-ink: var(--grn-700);    /* ✓ 5.65 on --grn-50 */

  --success:      var(--grn-700);
  --success-soft: var(--grn-50);
  --danger:       #b4304a;              /* ✓ 6.07 both directions */
  --danger-soft:  #fdeef1;
  --warn:         #b8721f;              /* fill only — pair with --ink, not white */
  --warn-ink:     #7a4a0f;
  --warn-soft:    #fdf3e3;

  --focus-ring: 0 0 0 3px rgba(122, 82, 196, .38);

  /* ---------- text roles that take a different step in dark mode ---------- */
  --link:  var(--primary-soft-ink);     /* links, eyebrows, ghost-button text */
  --title: var(--lav-700);              /* the page <h1> */

  /* ---------- elevation: lavender-tinted, never neutral grey ---------- */
  --shadow-1: 0 1px 2px rgba(46, 27, 82, .07);
  --shadow-2: 0 2px 4px rgba(46, 27, 82, .06), 0 10px 28px rgba(46, 27, 82, .08);
  --shadow-3: 0 8px 20px rgba(46, 27, 82, .10), 0 24px 60px rgba(46, 27, 82, .12);

  /* ---------- shape ---------- */
  --r-sm: 8px;
  --r-md: 14px;
  --r-lg: 22px;
  --r-pill: 999px;

  /* ---------- 4px spacing scale ---------- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;

  /* ---------- controls: one height for every button, field and toggle ---------- */
  --control-h: 44px;

  /* =============================================================
     TYPE — professional, plainly readable, zero network dependency.

     Three voices, each a variable font that ships in fonts/ beside this
     file, so the app looks the same on a Chromebook, a phone and a
     Windows laptop, and still renders with no connection. The old
     system stacks stay behind them as the fallback while a font loads.

     Softness comes from the letterform itself: Nunito's rounded
     terminals for headings (it is also the face of the wordmark), and
     Atkinson Hyperlegible for everything read closely, because it keeps
     I, l and 1, and O and 0, apart: exactly the characters a chemical
     formula cannot afford to blur.
     ============================================================= */

  /* headings and any type ≥ 20px */
  --font-display: "Nunito", Candara, "ui-rounded", "Segoe UI Variable Display",
                  Calibri, "Segoe UI", -apple-system, system-ui, Roboto,
                  "Helvetica Neue", Arial, sans-serif;
  /* body, labels, controls — everything below 20px */
  --font-body: "Atkinson Hyperlegible Next", Calibri, "ui-rounded", "Segoe UI Variable Text",
               "Segoe UI", -apple-system, system-ui, Roboto,
               "Helvetica Neue", Arial, sans-serif;
  /* the second voice, and it earns its keep: quantities, units,
     equations, anything that must align in a column */
  --font-mono: "Atkinson Hyperlegible Mono", Consolas, "Cascadia Mono", "SFMono-Regular", ui-monospace,
               Menlo, "JetBrains Mono", monospace;

  /* weights — one step apart. Body, labels and controls stop at 600;
     only headings go to 700 */
  --w-normal: 400;
  --w-medium: 500;
  --w-semi:   600;
  --w-bold:   600;
  --w-display: 700;   /* headings only: Nunito is a light face and needs the extra step to carry a title */

  /* line heights: a little looser throughout than a technical system
     would use — tight leading is part of what reads "hard" */
  --lh-display: 1.22;
  --lh-heading: 1.34;
  --lh-body:    1.68;   /* generous — this is a page students read slowly */
  --lh-tight:   1.45;

  /* measure: never let running text run wider than this */
  --measure: 66ch;
  --measure-narrow: 46ch;

  /* scale — 1.0rem base, ~1.22 ratio, deliberately shallow so nothing
     shouts and every step stays distinguishable */
  --fs-display: clamp(1.875rem, 1.55rem + 1.5vw, 2.375rem);
  --fs-h1:      clamp(1.5rem, 1.35rem + .75vw, 1.75rem);
  --fs-h2:      1.3125rem;
  --fs-h3:      1.0625rem;
  --fs-body:    1rem;       /* 16px floor — never smaller for prose */
  --fs-small:   0.875rem;
  --fs-label:   0.75rem;
  --fs-micro:   0.6875rem;  /* units and footnotes only, never sentences */

  /* composed shorthands: font: var(--t-h2) */
  --t-display: var(--w-display) var(--fs-display)/var(--lh-display) var(--font-display);
  --t-h1:      var(--w-display) var(--fs-h1)/var(--lh-heading) var(--font-display);
  --t-h2:      var(--w-display) var(--fs-h2)/var(--lh-heading) var(--font-display);
  --t-h3:      var(--w-semi) var(--fs-h3)/var(--lh-tight) var(--font-body);
  --t-body:    var(--w-normal) var(--fs-body)/var(--lh-body) var(--font-body);
  --t-body-strong: var(--w-semi) var(--fs-body)/var(--lh-body) var(--font-body);
  --t-small:   var(--w-normal) var(--fs-small)/1.55 var(--font-body);
  --t-label:   var(--w-bold) var(--fs-label)/var(--lh-tight) var(--font-body);
  --t-mono:    var(--w-normal) var(--fs-small)/var(--lh-tight) var(--font-mono);
  --t-quantity: var(--w-medium) var(--fs-body)/var(--lh-tight) var(--font-mono);

  /* tracking: near-neutral, not tightened — negative tracking is what
     makes a headline feel engineered instead of written */
  --tr-display: -0.006em;
  --tr-heading: 0em;
  --tr-body:    0em;
  --tr-label:   0.06em;   /* uppercase labels still need a little air */

  /* ---------- motion: read by CSS and by motion.js alike ---------- */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);       /* UI arriving or leaving */
  --ease-move: cubic-bezier(0.4, 0, 0.2, 1);   /* an object travelling inside a simulation */
  --dur-fast: 120ms;    /* hover, press */
  --dur: 220ms;         /* state changes, and anything leaving */
  --dur-slow: 420ms;    /* anything entering the page */
  --stagger: 90ms;      /* gap between items that arrive one after another */
}

/* =============================================================
   dark mode — the ramps invert roles: tints become the ink,
   the 900 step becomes the room. Same token names throughout.
   ============================================================= */
[data-theme="dark"] {
  color-scheme: dark;
  --link:  var(--primary);
  --title: var(--ink);

  --ink:   #ebe0ff;   /* ✓ 14.8 on --bg */
  --ink-2: #dac7ff;
  --muted: #a79fc0;   /* ✓ 7.4 */
  --faint: #7c7496;
  --line:  #2a2140;
  --line-strong: #3d3157;

  --bg:      #151021;
  --bg-tint: #1d1630;
  --card:    #1d1630;
  --card-2:  #2a2140;
  --overlay: rgba(10, 6, 20, .66);

  --primary:        var(--lav-300);
  --primary-hover:  var(--lav-200);
  --primary-ink:    #1c1725;          /* dark text on a light lavender fill */
  --primary-soft:   #2a2140;
  --primary-soft-ink: var(--lav-100); /* ✓ 9.8 */

  --accent:         var(--grn-300);
  --accent-hover:   var(--grn-200);
  --accent-ink:     #10240f;
  --accent-soft:    #1f3320;
  --accent-soft-ink: var(--grn-200);

  --success:      var(--grn-300);
  --success-soft: #1f3320;
  --danger:       #f0a3b0;
  --danger-soft:  #3a1a22;
  --warn:         #f0c274;
  --warn-ink:     #f0c274;
  --warn-soft:    #33260f;

  --focus-ring: 0 0 0 3px rgba(172, 139, 238, .45);

  --shadow-1: 0 1px 2px rgba(0, 0, 0, .5);
  --shadow-2: 0 2px 4px rgba(0, 0, 0, .4), 0 10px 28px rgba(0, 0, 0, .45);
  --shadow-3: 0 8px 20px rgba(0, 0, 0, .5), 0 24px 60px rgba(0, 0, 0, .55);
}

/* Follow the OS when no explicit choice has been stored. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --link: var(--primary); --title: var(--ink);
    --ink: #ebe0ff; --ink-2: #dac7ff; --muted: #a79fc0; --faint: #7c7496;
    --line: #2a2140; --line-strong: #3d3157;
    --bg: #151021; --bg-tint: #1d1630; --card: #1d1630; --card-2: #2a2140;
    --overlay: rgba(10, 6, 20, .66);
    --primary: var(--lav-300); --primary-hover: var(--lav-200);
    --primary-ink: #1c1725; --primary-soft: #2a2140; --primary-soft-ink: var(--lav-100);
    --accent: var(--grn-300); --accent-hover: var(--grn-200);
    --accent-ink: #10240f; --accent-soft: #1f3320; --accent-soft-ink: var(--grn-200);
    --success: var(--grn-300); --success-soft: #1f3320;
    --danger: #f0a3b0; --danger-soft: #3a1a22;
    --warn: #f0c274; --warn-ink: #f0c274; --warn-soft: #33260f;
    --focus-ring: 0 0 0 3px rgba(172, 139, 238, .45);
    --shadow-1: 0 1px 2px rgba(0,0,0,.5);
    --shadow-2: 0 2px 4px rgba(0,0,0,.4), 0 10px 28px rgba(0,0,0,.45);
    --shadow-3: 0 8px 20px rgba(0,0,0,.5), 0 24px 60px rgba(0,0,0,.55);
  }
}

/* =============================================================
   component primitives — thin, opt-in, all token-driven
   ============================================================= */

/* ---------- base type wiring ----------
   These apply the tokens above so headings, running text, and
   quantities look right by default, not only inside .ds-* wrappers. */
h1, h2, h3, h4 { margin: 0; text-wrap: balance; color: var(--ink-2); }
h1 { font: var(--t-display); letter-spacing: var(--tr-display); color: var(--title); }
h2 { font: var(--t-h1); letter-spacing: var(--tr-heading); }
h3 { font: var(--t-h2); letter-spacing: var(--tr-heading); }
h4 { font: var(--t-h3); }

p, li { font: var(--t-body); color: var(--ink); max-width: var(--measure); }
p.lede { font: var(--w-normal) 1.125rem/var(--lh-body) var(--font-body); color: var(--muted); }

small, .ds-caption { font: var(--t-small); color: var(--muted); }

.ds-eyebrow, .ds-label-inline {
  font: var(--t-label);
  text-transform: uppercase;
  letter-spacing: var(--tr-label);
  color: var(--muted);
}

/* quantities, units, calc lines — tabular figures so columns line up */
.ds-quantity, code, kbd, samp {
  font: var(--t-quantity);
  font-variant-numeric: tabular-nums;
}

.ds-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--sp-5);
  box-shadow: var(--shadow-2);
}

.ds-btn {
  font: var(--t-small);
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 10px 18px;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease), color var(--dur) var(--ease);
}
.ds-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ds-btn:active { transform: translateY(1px); }
.ds-btn[disabled] { opacity: .5; cursor: not-allowed; transform: none; }

.ds-btn--primary   { background: var(--primary); color: var(--primary-ink); }
.ds-btn--primary:hover:not([disabled])   { background: var(--primary-hover); }

.ds-btn--accent    { background: var(--accent); color: var(--accent-ink); }
.ds-btn--accent:hover:not([disabled])    { background: var(--accent-hover); }

.ds-btn--soft      { background: var(--primary-soft); color: var(--primary-soft-ink); }
.ds-btn--soft:hover:not([disabled])      { background: var(--lav-100); }

.ds-btn--ghost     { background: transparent; color: var(--primary-soft-ink);
                     border-color: var(--line-strong); }
.ds-btn--ghost:hover:not([disabled])     { background: var(--bg-tint); }

.ds-btn--danger    { background: var(--danger); color: #fff; }

.ds-label {
  font: var(--t-label);
  text-transform: uppercase;
  letter-spacing: var(--tr-label);
  color: var(--muted);
}

.ds-field {
  font: var(--t-body);
  width: 100%;
  padding: 10px 14px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.ds-field::placeholder { color: var(--faint); }
.ds-field:focus { outline: none; border-color: var(--primary); box-shadow: var(--focus-ring); }
.ds-field[aria-invalid="true"] { border-color: var(--danger); }

.ds-chip {
  font: var(--t-label);
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: var(--r-pill);
  background: var(--primary-soft);
  color: var(--primary-soft-ink);
}
.ds-chip--accent  { background: var(--accent-soft); color: var(--accent-soft-ink); }
.ds-chip--danger  { background: var(--danger-soft); color: var(--danger); }
.ds-chip--warn    { background: var(--warn-soft);   color: var(--warn-ink); }

/* Callouts get a 3px leading edge in the role colour — the one place
   the saturated 400-step swatches carry meaning on their own. */
.ds-note {
  border-left: 3px solid var(--primary);
  background: var(--primary-soft);
  color: var(--ink);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  padding: var(--sp-3) var(--sp-4);
}
.ds-note--accent { border-left-color: var(--accent); background: var(--accent-soft); }
.ds-note--danger { border-left-color: var(--danger); background: var(--danger-soft); }
.ds-note--warn   { border-left-color: var(--warn);   background: var(--warn-soft); }

/* =============================================================
   suite shell — the parts every Chemculator app shares.

   These use the class names the apps already carry in their markup
   (.theme-toggle, .btn, .seg, .choice-card ...), so an app gets them
   by linking this file and NOT redefining them. An app's own
   styles.css should hold only what is specific to that app: its
   layout, its data colours, its simulation.

   This file is copied into each repo. Edit the canonical copy and
   run design-system/sync.js — never edit a copy.
   ============================================================= */

/* ---------- base ---------- */
* { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  font: var(--t-body);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

/* focus: the ring token plus a solid outline, so it holds 3:1 on any surface */
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; box-shadow: var(--focus-ring); }

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- icons (icons.js): take the text colour, scale with the type ---------- */
.icon {
  width: 1.25em; height: 1.25em; flex: none; vertical-align: -0.22em;
  fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
}
[data-icon] { display: inline-flex; }

/* ---------- theme toggle: fixed, top-right, in every app ---------- */
.theme-toggle {
  position: fixed; top: var(--sp-4); right: var(--sp-4); z-index: 50;
  width: var(--control-h); height: var(--control-h); padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong); border-radius: var(--r-pill);
  background: var(--card); color: var(--ink);
  font-size: 1.15rem; line-height: 1; cursor: pointer;
  box-shadow: var(--shadow-1);
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.theme-toggle:hover { background: var(--primary-soft); border-color: var(--primary); transform: translateY(-1px); }
.theme-toggle:active { transform: none; transition-duration: var(--dur-fast); }
.theme-toggle:focus-visible { box-shadow: var(--shadow-1), var(--focus-ring); }

/* ---------- header: home link, brand mark, eyebrow, title ---------- */
.top-links { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-5); margin-bottom: var(--sp-4); }
@media (max-width: 1040px) { .top-links { padding-right: 60px; } }   /* keep the fixed theme toggle clear */

.home-link, .back-link {
  display: inline-block; color: var(--link); text-decoration: none;
  font: var(--t-body-strong); border-radius: var(--r-sm);
}
.home-link:hover, .back-link:hover { text-decoration: underline; text-underline-offset: 3px; }
/* .back-link is usually a <button> that steps back inside the app */
.back-link { background: none; border: 0; cursor: pointer; padding: var(--sp-2) 0; margin: var(--sp-1) 0 var(--sp-4); }

.brand-mark { display: block; width: fit-content; margin: 0 0 var(--sp-2); line-height: 0; }
.brand-mark img { height: 48px; width: auto; }
.brand-mark__img--light { display: block; }
.brand-mark__img--dark { display: none; }
:root[data-theme="dark"] .brand-mark__img--light { display: none; }
:root[data-theme="dark"] .brand-mark__img--dark { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-mark__img--light { display: none; }
  :root:not([data-theme="light"]) .brand-mark__img--dark { display: block; }
}

.eyebrow {
  display: inline-block; margin: 0; max-width: none;
  font: var(--t-label); text-transform: uppercase; letter-spacing: var(--tr-label);
  color: var(--link);
}

/* ---------- panels ---------- */
.card, .prompt-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--sp-5);
  box-shadow: var(--shadow-2);
}

/* ---------- buttons: ghost by default, one primary per view ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: var(--control-h); padding: 10px 20px;
  font: var(--t-body-strong); line-height: 1.3;
  border: 1px solid var(--line-strong); border-radius: var(--r-pill);
  background: transparent; color: var(--link);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.btn:hover { background: var(--bg-tint); }
.btn:active { transform: translateY(1px); transition-duration: var(--dur-fast); }

.btn--primary { background: var(--primary); border-color: transparent; color: var(--primary-ink); }
.btn--primary:hover { background: var(--primary-hover); }
.btn--accent { background: var(--accent); border-color: transparent; color: var(--accent-ink); }
.btn--accent:hover { background: var(--accent-hover); }
.btn--soft { background: var(--primary-soft); border-color: transparent; color: var(--primary-soft-ink); }
.btn--soft:hover { background: var(--card-2); border-color: var(--primary); }

.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; transform: none; }

/* ---------- fields ---------- */
.select, .num-input, .text-input {
  min-height: var(--control-h); padding: 10px 14px; max-width: 100%;
  font: var(--t-body); color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.select { cursor: pointer; }
.num-input { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.select:hover, .num-input:hover, .text-input:hover { border-color: var(--primary); }
.select:focus, .num-input:focus, .text-input:focus {
  outline: none; border-color: var(--primary); box-shadow: var(--focus-ring);
}
.num-input::placeholder, .text-input::placeholder { color: var(--faint); }
.select option, .select optgroup { background: var(--card); color: var(--ink); }
.select:disabled, .num-input:disabled, .text-input:disabled { opacity: .5; cursor: not-allowed; }

.form-error {
  margin: var(--sp-3) 0 0; padding: var(--sp-3) var(--sp-4); max-width: none;
  font: var(--t-body); color: var(--danger);
  background: var(--danger-soft);
  border-left: 3px solid var(--danger); border-radius: 0 var(--r-md) var(--r-md) 0;
}

/* ---------- segmented control ----------
   A recessed tray; the chosen segment is raised in soft lavender with a
   1px --primary ring, so state is never carried by colour alone.
   Children are either <button>s (mark the chosen one .active or
   aria-pressed="true") or <label>s wrapping a radio input.
   .seg--strong fills the chosen segment — use it for the ONE control
   that drives the view. .seg--wide stretches to the container. */
.seg {
  display: inline-flex; flex-wrap: wrap; gap: 3px; padding: 3px;
  border: 1px solid var(--line-strong);
  border-radius: calc(var(--control-h) / 2);
  background: var(--bg-tint);
}
.seg > button, .seg > label {
  position: relative; flex: 0 1 auto;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: calc(var(--control-h) - 8px); padding: 6px var(--sp-4);
  border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--muted);
  font: var(--t-body-strong); line-height: 1.3; text-align: center;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.seg > button:hover, .seg > label:hover { color: var(--ink); }
.seg > button.active, .seg > button[aria-pressed="true"], .seg > label:has(input:checked) {
  background: var(--primary-soft); color: var(--primary-soft-ink);
  box-shadow: inset 0 0 0 1px var(--primary);
}
.seg--strong > button.active, .seg--strong > button[aria-pressed="true"], .seg--strong > label:has(input:checked) {
  background: var(--primary); color: var(--primary-ink); box-shadow: none;
}
/* the native radio stays focusable and accessible, but is visually hidden */
.seg > label > input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.seg > label > input:focus-visible { outline: none; box-shadow: none; }
.seg > label:focus-within { outline: 2px solid var(--primary); outline-offset: 2px; }
.seg--wide { display: flex; width: 100%; }
.seg--wide > button, .seg--wide > label { flex: 1 1 auto; }

/* ---------- choice cards: soft surfaces, role shown by the leading edge ---------- */
.choice-card {
  --edge: var(--primary);
  --wash: var(--primary-soft);
  --wash-ink: var(--primary-soft-ink);
  position: relative; z-index: 0;
  display: flex; flex-direction: column; gap: var(--sp-2);
  appearance: none; text-align: left; cursor: pointer;
  padding: var(--sp-5);
  border: 1px solid var(--line-strong);
  border-left: 4px solid var(--edge);
  border-radius: var(--r-lg);
  background: var(--wash); color: var(--ink);
  font: inherit;
  box-shadow: var(--shadow-2);
  -webkit-tap-highlight-color: transparent;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background-color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.choice-card--lav   { --edge: var(--primary); --wash: var(--primary-soft); --wash-ink: var(--primary-soft-ink); }
.choice-card--grn   { --edge: var(--accent);  --wash: var(--accent-soft);  --wash-ink: var(--accent-soft-ink); }
.choice-card--plain { --edge: var(--line-strong); --wash: var(--card); --wash-ink: var(--primary-soft-ink); }
.choice-card:focus-visible { box-shadow: var(--shadow-2), var(--focus-ring); z-index: 5; }
@media (hover: hover) {
  .choice-card:hover { z-index: 5; transform: translateY(-3px); box-shadow: var(--shadow-3); }
}
.choice-card:active { transform: translateY(0); transition-duration: var(--dur-fast); }
.choice-card.active { z-index: 2; box-shadow: var(--shadow-2), 0 0 0 2px var(--primary); }
.choice-verb { font: var(--t-h2); letter-spacing: var(--tr-heading); color: var(--wash-ink); }
.choice-desc { font: var(--t-body); color: var(--ink); }

/* ---------- entrances ----------
   Content that appears from CSS alone fades up with this. Step changes,
   staggered entrances and anything else driven from JS go through
   motion.js, which reads the same tokens. */
@keyframes fade { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
