  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
  /* ── Design tokens ────────────────────────────────────────────────────────
     "Training Floor": graphite base, layered surfaces for depth, amber as the
     brand mark, an electric cyan for performance/progress, and oversized
     tabular numerals under wide-tracked micro-labels. Every size, duration and
     easing below used to be a literal scattered through the sheet. */
  :root {
    /* ══ BROADSHEET, APP-WIDE ══════════════════════════════════════════════
       These token NAMES are the dark theme's; their VALUES are now Broadsheet.
       Retargeting here rather than renaming is deliberate: ~700 rules already
       reference --bg/--card/--text, so one mapping converts every screen at
       once instead of touching all of them. Names that no longer describe
       their value (--gold is ultramarine, --volt is not volt) are kept as
       semantic ROLES — brand mark, performance accent — and the mapping below
       is the single place that decides what a role looks like.
       Previous dark values are in git (see the commit that introduced this).

       The press has TWO inks plus a pen. Black, ultramarine, and red for
       marginalia only. --teal/--purple existed as extra hues and are folded
       into that discipline rather than kept as a third and fourth colour.
       ══════════════════════════════════════════════════════════════════════ */
    /* Newsprint tokens, defined at the root so every screen can reach them
       (they were scoped to .bs, which is why only two screens could use them). */
    --bs-stock: #e6e9e0; --bs-stock-2: #dadfd0; --bs-sheet: #f8faf4;
    --bs-ink: #0c0f0b; --bs-ink-2: #41483d; --bs-ink-3: #616858;
    --bs-rule: #c3c9ba;
    --bs-blue: #1524d8;
    --bs-pen: #c2261f;
    --bs-graphite: #7d8478;
    --bs-ok: #0f6b3c; --bs-miss: #c62222;
    --bs-ed: 'Fraunces', Georgia, serif;
    --bs-ui: 'Archivo', system-ui, sans-serif;
    --bs-mono: 'IBM Plex Mono', ui-monospace, Menlo, monospace;
    --bs-hand: 'Caveat', ui-rounded, cursive;

    /* Surfaces — on paper "lifted" means whiter, so the dark stack inverts:
       the base sheet is the darkest plane and a raised card is the brightest. */
    --bg: var(--bs-stock); --surface: #eef1e9; --card: var(--bs-sheet); --card-hi: #ffffff;
    --border: var(--bs-rule); --border-hi: #a4ac98;
    /* Brand mark — the accent ink. */
    --gold: var(--bs-blue); --gold-dim: #0f1a9e; --gold-bg: #e0e3f8;
    /* Performance accent — progress, pace, session state. Same ink as the
       brand on purpose: a second hue here is what made the old theme read as
       a generic dashboard. Emphasis comes from weight and rule, not colour. */
    --volt: var(--bs-blue); --volt-dim: #5560c9; --volt-bg: #e4e7f9;
    /* Text. --ink was referenced by six rules but never defined, so the
       feedback stem and choices silently fell back to inherit. */
    --text: var(--bs-ink); --ink: var(--bs-ink); --muted: var(--bs-ink-3); --subtle: var(--bs-rule);
    /* Semantics — kept distinct from the accent so state never reads as brand. */
    --green: var(--bs-ok); --green-bg: #dfeee4; --green-line: #9dc3ab;
    --red: var(--bs-miss); --red-bg: #f7e2e1; --red-line: #d9a5a2;
    /* Folded into the two-ink discipline rather than kept as extra hues. */
    --teal: var(--bs-ink-2); --teal-dim: var(--bs-ink-3); --teal-bg: #e7eae2;
    --purple: var(--bs-blue); --purple-dim: var(--bs-ink-2); --purple-bg: #e4e7f9;
    /* Radius rhythm. Print has hard edges — the rounded-card look was the
       single biggest "generic web app" tell, so the scale collapses to near-0
       while keeping the token so nothing has to be hunted down. */
    --radius: 2px; --radius-sm: 1px; --radius-lg: 3px; --radius-pill: 999px;
    /* Spacing scale */
    --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px;
    --sp-6: 32px; --sp-7: 48px;
    /* Type scale */
    --fs-micro: 10px; --fs-label: 11px; --fs-sm: 13px; --fs-body: 16px;
    --fs-stem: clamp(17px, 16px + 0.3vw, 20px);
    --fs-num: clamp(20px, 17px + 0.9vw, 30px);
    --fs-num-hero: clamp(38px, 28px + 3vw, 64px);
    --track-label: 0.14em;
    --font-mono: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, monospace;
    /* Motion */
    --dur-fast: 120ms; --dur: 200ms; --dur-slow: 380ms;
    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    --ease-snap: cubic-bezier(0.16, 1, 0.3, 1);
  }
  html, body { height: 100%; background: var(--bg); color: var(--text);
    font-family: var(--bs-ui); font-size: 16px; line-height: 1.6;
    -webkit-font-smoothing: antialiased; }
  /* Paper tooth. The static radial-gradient version this replaces was a 4px
     dot pattern painted on the body; #paper-tooth draws the same grain on a
     canvas so the dots can part around the cursor. Grid is 14px there rather
     than 4px — at 4px the displacement is too small to read as motion. */
  #paper-tooth { position: fixed; inset: 0; width: 100vw; height: 100vh;
    pointer-events: none; z-index: 0; display: block; }
  /* Every screen sits above the grain. .screen is the app's only top-level
     content wrapper, so one rule covers all of them. */
  .screen { position: relative; z-index: 1; }
  #app { height: 100%; display: flex; flex-direction: column; }
  /* Reserve the scrollbar gutter always, so the content column does not shift
     sideways when a screen grows past one viewport. */
  .screen { scrollbar-gutter: stable; }
  /* The running head is a sibling of the screens, so it spans the full viewport
     while a scrolling screen's content box is narrower by its scrollbar. Both
     centre a 1080px column, so on any platform with CLASSIC scrollbars — which
     includes the school Chromebooks this ships to — the masthead sat ~7px off
     the story column beneath it. --sbw is measured in JS (see setScrollbarVar)
     because no CSS expression can report scrollbar width. It is 0 on macOS
     overlay scrollbars, where this rule then does nothing. */
  #global-bar { padding-right: var(--sbw, 0px); }
  .screen { display: none; flex-direction: column; height: 100%; }
  .screen.active { display: flex; }

