  /* Instrument deck over a schematic. Paper/ink reverse for light;
     hierarchy comes from type weight and hairlines, never fills. */
  :root {
    /* kyfram palette — warm-olive monochrome, sat <8%. */
    --bg: #0d0d0c;
    --surface: #171816;
    --surface-2: #232421;
    --line: #343531;
    --line-strong: #4b4c46;
    --text: #f5f5f4;
    --muted: #8f8f86;
    --muted-2: #8a8a80;
    --scrim: rgba(13, 13, 12, 0.62);
    --toast-shadow: 0 12px 32px rgba(0, 0, 0, 0.42);
    --mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
    --mission: "Geist Mono", ui-monospace, monospace;
    --sans: "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
    --r: 14px;
    --r-sm: 10px;
    /* derived: glass over the canvas + grid alphas */
    --panel: rgba(23, 24, 22, 0.8);
    --grid-faint: rgba(245, 245, 244, 0.055);
    --grid-strong: rgba(245, 245, 244, 0.11);
  }
  html.light {
    /* inverse: same warm family, swapped ends */
    --bg: #f5f5f4;
    --surface: #eae9e5;
    --surface-2: #deddd8;
    --line: #c9c8c1;
    --line-strong: #9b9a92;
    --text: #0d0d0c;
    --muted: #5a5a52;
    --muted-2: #5f5f56;
    --scrim: rgba(245, 245, 244, 0.66);
    --toast-shadow: 0 8px 22px rgba(13, 13, 12, 0.13);
    --panel: rgba(234, 233, 229, 0.85);
    --grid-faint: rgba(13, 13, 12, 0.06);
    --grid-strong: rgba(13, 13, 12, 0.12);
  }
  * { box-sizing: border-box; }
  html, body { height: 100%; margin: 0; min-width: 320px; }
  html { scrollbar-gutter: stable; }
  body {
    background: var(--bg);
    color: var(--text);
    overflow: hidden;
    overflow-x: auto;
    font-family: var(--sans);
    font-size: 14px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
  }
  #board { position: fixed; inset: 0; display: block; }
  #well { position: relative; }
  .mono {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
  }
  button {
    background: transparent; color: var(--text);
    border: 0; font: inherit; cursor: pointer;
    min-height: 44px;
  }
  button:focus-visible, [tabindex]:focus-visible {
    outline: 2px solid var(--text); outline-offset: 2px;
  }
  :focus:not(:focus-visible) { outline: none; }

  /* Component vocabulary: one base per kind, modifiers do the rest.
     Future DOM rendering (loadout from sim data) calls these classes,
     it never restyles them. */
  .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    min-height: 36px; min-width: 0; padding: 0 10px;
    background: transparent; color: var(--text); border: 0; border-radius: var(--r-sm);
    font-size: 12.5px;
  }
  .btn svg { width: 19px; height: 19px; }
  /* Icon-only stays a fat touch target; text buttons may breathe. */
  .btn--icon { min-width: 44px; min-height: 44px; width: 44px; padding: 0; color: var(--muted); }
  .btn--icon:hover { color: var(--text); }
  .btn--ghost { border: 1px solid var(--line); }
  .btn--ghost:hover { border-color: var(--text); }
  .btn--primary { background: var(--text); color: var(--bg); border: 1px solid var(--text); }
  .btn--primary svg { width: 22px; height: 22px; }
  .btn--primary:hover { background: var(--bg); color: var(--text); }
  .btn--dashed { width: 100%; margin-top: 12px; border: 1px dashed var(--muted); color: var(--muted); font-size: 11.5px; min-height: 0; padding: 8px 10px; }
  .btn--dashed:hover { color: var(--text); border-color: var(--text); border-style: solid; }
  /* Composer size chips: dense price rows, not fat buttons. */
  .pick .sizes .btn.size {
    min-height: 0; justify-content: flex-start;
    padding: 7px 10px; font-size: 12px;
  }

  /* Deck: the whole chrome is one fused frame, glass over grid. */
  #deck {
    position: fixed; inset: 0;
    display: grid;
    grid-template-rows: 58px minmax(0, 1fr) auto;
    grid-template-columns: 224px 1fr 212px;
    grid-template-areas:
      "bar  bar  bar"
      "l    well r"
      "rep  rep  rep";
    pointer-events: none;
  }
  #deck > * { pointer-events: auto; }
  #deck > #well { pointer-events: none; }
  #bar, #rail-l, #rail-r, #rep {
    background: var(--panel);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
  }

  /* Top bar: brand + wave hero left, telemetry right. */
  #bar {
    grid-area: bar;
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 0 16px 0 20px;
    border-bottom: 1px solid var(--line);
  }
  #bar-left { flex: 0 0 auto; }
  #bar-actions { flex: 1; display: flex; align-items: center; justify-content: center; justify-content: safe center; gap: 8px; position: relative; min-width: 0; overflow-x: auto; }
  /* Section dividers: modes | telemetry | theme read as groups, not a list. */
  #bar-actions::after {
    content: ""; position: absolute; right: -8px; top: 22%; bottom: 22%;
    width: 1px; background: var(--line);
  }
  #bar-right { flex: 0 0 auto; display: flex; align-items: center; }
  #telemetry { display: flex; gap: 18px; padding: 0 4px; }
  #theme { flex: 0 0 auto; }
  #bar-actions .btn { min-height: 32px; padding: 0 12px; font-size: 11.5px; font-family: var(--mono); letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; flex: none; }
  #bar-actions .btn[aria-pressed="true"] { background: var(--text); color: var(--bg); border-color: var(--text); }
  #bar .bar-left {
    align-self: stretch;
    display: flex; align-items: center;
    min-width: 0;
  }
  #brand {
    align-self: stretch;
    display: flex; align-items: center; gap: 10px;
    font-family: var(--mono);
    font-size: 11px; letter-spacing: 0.22em;
    color: var(--muted);
    text-transform: uppercase;
    padding-right: 22px;
    margin-right: 22px;
    border-right: 1px solid var(--line);
    white-space: nowrap;
  }
  #station { display: flex; align-items: center; gap: 14px; min-width: 0; }
  #wavenum {
    width: 40px; height: 28px; flex: none;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--line-strong);
    background: var(--surface-2);
    border-radius: var(--r-sm);
    font-size: 13px; font-weight: 600;
  }
  #wave-title { min-width: 0; }
  #wave-title h1 {
    font-size: 19px; font-weight: 700; letter-spacing: 0.01em;
    margin: 0; line-height: 1.2;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #wave-title .meta {
    font-family: var(--mono);
    font-size: 10.5px; letter-spacing: 0.14em;
    color: var(--muted); line-height: 1;
    display: block;
  }
  #bar .bar-right {
    align-self: stretch;
    display: flex; align-items: center;
  }
  #telemetry {
    align-self: stretch;
    display: flex; align-items: center;
  }
  .readout {
    align-self: stretch;
    display: flex; flex-direction: column;
    align-items: flex-end; justify-content: center;
    gap: 2px;
    padding: 0 24px;
  }
  .readout + .readout { border-left: 1px solid var(--line); }
  .readout .label {
    font-family: var(--mono);
    font-size: 9.5px; letter-spacing: 0.18em;
    color: var(--muted);
  }
  .readout .value { font-size: 16px; font-weight: 600; line-height: 1; white-space: nowrap; }
  .readout .den { font-size: 12px; font-weight: 400; color: var(--muted); }
  #theme { align-self: center; }
  #theme svg { width: 19px; height: 19px; }
  #theme .icon-moon { display: none; }
  html.light #theme .icon-moon { display: block; }
  html.light #theme .icon-sun { display: none; }

  /* Side rails: flush to the seam with the report bar. */
  #rail-l { grid-area: l; border-right: 1px solid var(--line); }
  #rail-r { grid-area: r; border-left: 1px solid var(--line); }
  .rail { padding: 16px 18px 14px; overflow-y: auto; }
  /* Rail sections keep their labels while long loadouts scroll. */
  .rail .instr {
    position: sticky; top: 0; z-index: 3;
    background: var(--surface);
    margin: 0 -18px 10px; padding: 12px 18px 8px;
  }
  .instr {
    font-family: var(--mono);
    font-size: 10px; letter-spacing: 0.22em;
    color: var(--muted);
    margin: 0 0 10px;
    display: flex; align-items: center; gap: 8px;
    text-transform: uppercase;
  }
  .instr::after {
    content: ""; flex: 1; height: 1px; background: var(--line);
    margin-top: 1px;
  }

  /* Loadout: rows with glyph chips, dividers, flooded hover. */
  [hidden] { display: none !important; }
  .comp {
    position: relative;
    display: grid;
    grid-template-columns: 34px minmax(0,1fr) auto;
    grid-template-areas: "chip main cost";
    align-items: start;
    column-gap: 10px; row-gap: 1px;
    width: 100%; max-width: 100%; text-align: left;
    padding: 10px 50px 10px 6px;
    border-bottom: 1px solid var(--line);
    min-height: 52px;
    overflow: hidden;
  }
  .comp:first-of-type { border-top: 1px solid var(--line); }
  .comp:hover { background: var(--line); }
  /* Brick tones: one hue per component, shared by rail chips and the
     canvas signal ladder. Chips read as logos in their brick color. */
  .tone-gateway { --brick-h: 42; } .tone-cdn { --brick-h: 188; }
  .tone-limiter { --brick-h: 8; } .tone-cache { --brick-h: 354; }
  .tone-cache-lfu { --brick-h: 30; } .tone-memcached { --brick-h: 104; }
  .tone-db { --brick-h: 216; } .tone-indexed-db { --brick-h: 258; }
  .tone-replica { --brick-h: 174; } .tone-nosql { --brick-h: 308; }
  .tone-s3 { --brick-h: 54; } .tone-queue { --brick-h: 136; }
  .tone-kafka { --brick-h: 276; } .tone-worker { --brick-h: 82; }
  .tone-container { --brick-h: 14; } .tone-vm { --brick-h: 332; }
  .tone-lb { --brick-h: 66; } .tone-shard { --brick-h: 292; }
  .tone-breaker { --brick-h: 20; } .tone-fork { --brick-h: 160; }
  .tone-serverless { --brick-h: 202; } .tone-autoscale { --brick-h: 120; }
  .tone-provisioned-db { --brick-h: 320; }
  .chip {
    --brick-h: 220;
    width: 32px; height: 32px;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid hsl(var(--brick-h), 70%, 62%);
    background: hsl(var(--brick-h), 70%, 62%, 0.12);
    border-radius: var(--r-sm);
    color: hsl(var(--brick-h), 74%, 68%);
  }
  html.light .chip {
    border-color: hsl(var(--brick-h), 62%, 38%);
    background: hsl(var(--brick-h), 62%, 38%, 0.1);
    color: hsl(var(--brick-h), 64%, 34%);
  }
  .chip svg { width: 18px; height: 18px; display: block; }
  .comp:hover .chip { border-color: var(--text); }
  .comp-main { grid-area: main; min-width: 0; max-width: 100%; display: flex; flex-direction: column; gap: 4px; overflow: hidden; }
  .knobs {
    font-family: var(--mono); font-size: 10.5px; color: var(--muted);
    display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    min-width: 0;
  }
  /* Tune rides alone under the card's knobs; berth moved into the
     tune dialog so the card row stays one thin line. */
  .comp-main .tunebtn {
    align-self: start; font-family: var(--mono); font-size: 10.5px; color: var(--muted);
    border: 1px dashed var(--line); border-radius: 6px;
    min-height: 0; padding: 2px 8px; white-space: nowrap;
  }
  .comp-main .tunebtn:hover { color: var(--text); border-color: var(--text); }
  /* Hosts: declared boxes, clickable size and region. */
  #hosts { margin-bottom: 2px; }
  .hostrow {
    display: grid; grid-template-columns: 1fr auto auto auto;
    align-items: center; column-gap: 6px;
    padding: 7px 2px; border-bottom: 1px solid var(--line);
  }
  .hostrow:first-of-type { border-top: 1px solid var(--line); }
  .hostname { font-size: 12px; font-weight: 600; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .hostbtn {
    font-family: var(--mono); font-size: 11px; color: var(--muted);
    border: 1px solid var(--line); border-radius: 6px;
    min-height: 0; padding: 3px 8px;
  }
  .hostbtn:hover { color: var(--text); border-color: var(--text); }
  .hostbtn.on { color: var(--text); border-color: var(--line-strong); }
  /* Tune popup: compact dialog over the board. */
  #tune-backdrop {
    position: fixed; inset: 0; z-index: 50;
    background: var(--scrim);
  }
  #tune {
    position: fixed; z-index: 51;
    left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: min(340px, 92vw); max-height: 60vh;
    display: flex; flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--r);
    overflow: hidden;
  }
  #tune header {
    display: flex; align-items: center; gap: 12px;
    padding: 14px 14px 12px 18px;
    border-bottom: 1px solid var(--line);
  }
  #tune header h2 { font-size: 16px; font-weight: 700; margin: 0; flex: 1; }
  #tune-list { padding: 14px 18px; overflow-y: auto; flex: 1 1 0%; }
  #tune-list .pick.knobrow {
    grid-template-columns: 1fr; grid-template-areas: "main" "sizes";
    padding: 8px 0; border-bottom: 1px solid var(--line);
  }
  #tune-list .pick.knobrow:last-child { border-bottom: 0; }
  #tune-list .hostpick { border-bottom: 1px solid var(--line-strong); margin-bottom: 4px; }
  #tune-list select {
    font-family: var(--mono); font-size: 12px;
    background: var(--bg); color: var(--text); border: 1px solid var(--line); border-radius: 6px;
    padding: 6px 8px; width: 100%; appearance: none; -webkit-appearance: none; cursor: pointer;
  }
  #tune-list select:focus { outline: none; border-color: var(--text); }
  #tune footer {
    border-top: 1px solid var(--line);
    padding: 10px 18px;
    display: flex; align-items: center; gap: 10px;
  }
  #tune footer .tune-actions { margin-left: auto; display: flex; gap: 8px; }
  #tune footer .tune-actions .btn { min-height: 32px; }
  #tune-note { font-size: 11px; color: var(--muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .hostrow .rm { margin: 0; }
  .hostrow .rm {
    width: 32px; height: 32px;
    display: flex; align-items: center; justify-content: center;
    color: var(--muted); font-size: 15px; line-height: 1;
  }
  .hostrow .rm:hover { color: var(--text); background: var(--line); }
  /* Observed work: what the brick actually ate last run. */
  .obs {
    font-family: var(--mono); font-size: 10.5px; color: var(--text);
    display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    min-width: 0;
  }
  .comp .chip { grid-area: chip; align-self: center; }
  .comp .rm {
    position: absolute; top: 2px; right: 2px;
    width: 44px; height: 44px;
    display: flex; align-items: center; justify-content: center;
    color: var(--muted); font-size: 16px; line-height: 1;
  }
  .comp .rm:hover { color: var(--text); background: var(--line); }
  .comp .name {
    font-size: 13px; font-weight: 600; text-transform: uppercase;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
    display: block;
  }
  .comp .cost { grid-area: cost; font-size: 12px; color: var(--muted); align-self: start; padding-top: 6px; white-space: nowrap; }
  .comp .desc { grid-area: desc; font-size: 11.5px; color: var(--muted); }

  /* Picker sheet: the shop floats over the board. */
  #sheet-backdrop {
    position: fixed; inset: 0; z-index: 50;
    background: var(--scrim);
  }
  #sheet {
    position: fixed; z-index: 51;
    left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: min(620px, 94vw); max-height: 78vh;
    display: flex; flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--r);
    overflow: hidden;
  }
  #sheet header {
    display: flex; align-items: center; gap: 12px;
    padding: 14px 14px 12px 18px;
    border-bottom: 1px solid var(--line);
  }
  #sheet header .instr { margin: 0; }
  #sheet header h2 { font-size: 16px; font-weight: 700; margin: 0; flex: 1; }
  #sheet-searchwrap { padding: 12px 18px 2px; flex-shrink: 0; }
  #sheet-search {
    width: 100%; min-height: 44px;
    background: transparent; color: var(--text);
    border: 1px solid var(--line); border-radius: var(--r-sm);
    padding: 0 14px; font: inherit;
    font-family: var(--mono); font-size: 13px;
  }
  #sheet-search::placeholder { color: var(--muted); }
  #sheet-search:focus { outline: none; border-color: var(--text); }
  #sheet-list { flex: 1; min-height: 0; overflow-y: auto; padding: 0 16px 16px; }
  .sheet-group {
    position: sticky; top: 0; z-index: 1;
    background: var(--surface);
    font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.18em;
    color: var(--muted); margin: 0; padding: 14px 2px 8px;
    display: flex; align-items: center; gap: 10px;
  }
  .sheet-group::after { content: ""; flex: 1; height: 1px; background: var(--line); }
  .pick {
    display: grid;
    grid-template-columns: 34px 1fr;
    grid-template-areas: "chip main" "chip sizes";
    column-gap: 10px; row-gap: 10px;
    padding: 12px 2px;
    border-bottom: 1px solid var(--line);
  }
  .pick .chip { grid-area: chip; align-self: start; margin-top: 2px; }
  .pick .pick-main { grid-area: main; }
  .pick .name { font-size: 13px; font-weight: 600; display: block; }
  .pick .tag { font-size: 11.5px; color: var(--muted); display: block; margin-top: 1px; }
  .pick .sizes { grid-area: sizes; display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: 8px; }
  .btn.size { font-family: var(--mono); font-size: 12px; }
  .btn.size .arr { color: var(--muted); margin-right: 4px; display: inline-flex; }
  .btn.size .arr svg { width: 12px; height: 12px; display: block; }
  /* micro icons: phosphor only, never text glyphs */
  #add svg { width: 14px; height: 14px; display: block; }
  #sheet-close svg { width: 16px; height: 16px; display: block; }
  .comp .rm svg { width: 14px; height: 14px; display: block; }
  .btn.size .verdict { display: inline-flex; margin-left: 4px; }
  .btn.size .verdict svg { width: 12px; height: 12px; display: block; }
  #next svg { width: 12px; height: 12px; display: inline-block; vertical-align: -1px; margin: 0 2px; }
  .pick:hover { background: var(--line); }
  #sheet-foot {
    border-top: 1px solid var(--line);
    padding: 12px 18px;
    font-size: 12px; color: var(--muted);
    display: flex; justify-content: space-between; gap: 10px;
  }
  #sheet-foot .mono { color: var(--text); }
  #sheet-error { padding: 18px 4px; color: var(--muted); font-size: 13px; }

  /* Import: paste TOML, same floating panel language. Snapshot
     reuses it: board + last run as text, worth pasting to an AI.
     Debrief reuses it too: the full report lives in a popup so the
     footer strip never grows over the board. */
  #import-backdrop, #snapview-backdrop, #debrief-backdrop, #design-backdrop { position: fixed; inset: 0; z-index: 50; background: var(--scrim); }
  #import, #snapview, #debriefdlg, #design {
    position: fixed; z-index: 51;
    left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: min(560px, 94vw); max-height: 78vh;
    display: flex; flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--r);
    overflow: hidden;
  }
  #import header, #snapview header, #debriefdlg header, #design header {
    display: flex; align-items: center; gap: 12px;
    padding: 14px 14px 12px 18px;
    border-bottom: 1px solid var(--line);
  }
  #import header .instr, #snapview header .instr, #debriefdlg header .instr, #design header .instr { margin: 0; }
  #import header h2, #snapview header h2, #debriefdlg header h2, #design header h2 { font-size: 16px; font-weight: 700; margin: 0; flex: 1; }
  #import-close svg, #snapview-close svg, #debrief-close svg, #design-close svg { width: 16px; height: 16px; display: block; }
  #import-text:focus, #snapview-text:focus { outline: none; border-color: var(--text); }
  #import-error { margin: 0; padding: 0 18px 12px; font-family: var(--mono); font-size: 12px; color: #ff453a; }

  /* Quiz: eight questions out loud, same floating panel language. */
  #quiz-backdrop { position: fixed; inset: 0; z-index: 50; background: var(--scrim); }
  #quiz {
    position: fixed; z-index: 51;
    left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: min(560px, 94vw); max-height: 78vh;
    display: flex; flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--r);
    overflow: hidden;
  }
  #quiz header {
    display: flex; align-items: center; gap: 12px;
    padding: 14px 14px 12px 18px;
    border-bottom: 1px solid var(--line);
  }
  #quiz header .instr { margin: 0; }
  #quiz header h2 { font-size: 16px; font-weight: 700; margin: 0; flex: 1; }
  #quiz-close svg { width: 16px; height: 16px; display: block; }
  #quiz-body { padding: 14px 18px; overflow-y: auto; flex: 1 1 auto; min-height: 0; }
  .quiz-q { font-size: 14px; font-weight: 600; margin: 0 0 10px; }
  .quiz-tag { font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); margin: 0 0 8px; }
  .quiz-dots { display: flex; gap: 6px; margin: 0 0 12px; }
  .quiz-dots i { width: 26px; height: 3px; border-radius: 2px; background: var(--line-strong); }
  .quiz-dots i.done { background: var(--text); }
  .quiz-dots i.now { background: transparent; border: 1px solid var(--text); }
  .quiz-opt {
    display: block; width: 100%; text-align: left;
    min-height: 44px; margin: 0 0 8px; padding: 10px 14px;
    background: transparent; color: var(--text);
    border: 1px solid var(--line); border-radius: var(--r-sm);
    font-size: 13px;
  }
  .quiz-opt:hover:not(:disabled) { border-color: var(--text); }
  .quiz-opt:disabled { cursor: default; opacity: 0.7; }
  .quiz-opt.right { border-color: #30d158; color: #30d158; }
  .quiz-opt.wrong { border-color: #ff453a; color: #ff453a; }
  .quiz-why { font-size: 12.5px; color: var(--muted); margin: 10px 0 0; }
  #quiz-foot {
    border-top: 1px solid var(--line);
    padding: 12px 18px;
    display: flex; align-items: center; gap: 10px;
  }
  #quiz-foot .spacer { flex: 1; }
  #quiz-score { font-size: 12px; color: var(--muted); }

  /* Wave rail: one numeral, one meter, paired stats, transport. */
  #tick { font-size: 40px; font-weight: 600; line-height: 1; margin: 0 0 10px; }
  #tick small { font-size: 15px; font-weight: 400; color: var(--muted); }
  .meter {
    height: 2px; background: var(--line);
    margin: 0 0 14px; border-radius: 1px; overflow: hidden;
  }
  .meter i { display: block; height: 100%; width: 30%; background: var(--text); }
  .stats { margin: 0 0 14px; }
  /* Signal: the lane's latest word, as UI text — never canvas text. */
  /* Signal toasts: lane news that waits to be dismissed, never
     canvas text and never auto-expiring. */
  /* Floating signal toasts: regular notifications over the canvas,
     never rail content — the rail must not shift under them. */
  #toasts {
    /* margin-centered, no transform: a fixed mission toast must anchor to the viewport. */
    position: fixed; bottom: 118px; left: 0; right: 0; margin: 0 auto;
    z-index: 60; width: min(420px, 92vw);
    display: flex; flex-direction: column; gap: 8px;
    pointer-events: none;
    /* the stack scrolls inside itself: six toasts can never push
       past the canvas or shove the report bar around. */
    max-height: 40vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }
  #toasts:empty { display: none; }
  #toasts .toast { pointer-events: auto; box-shadow: var(--toast-shadow); }
  .toast {
    display: flex; align-items: flex-start; gap: 8px; flex: none;
    background: var(--surface); color: var(--text);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-sm); padding: 9px 6px 9px 12px;
    font-family: var(--mono); font-size: 11.5px; line-height: 1.5;
    animation: toastin 0.28s ease both;
  }
  @keyframes toastin { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
  .toast.leaving { animation: toastout 0.24s ease both; }
  @keyframes toastout { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(28px); } }
  .toast-tick {
    flex: none; margin-top: 4px;
    font-size: 10px; font-weight: 600; letter-spacing: 0.08em;
    color: var(--muted); border: 1px solid var(--line-strong);
    border-radius: 6px; padding: 2px 7px; white-space: nowrap;
  }
  .toast-tick.toast-bad { color: #ff453a; border-color: #ff453a; }
  .toast-text { flex: 1; min-width: 0; padding-top: 5px; overflow-wrap: anywhere; }
  .toast-text svg { width: 11px; height: 11px; display: inline-block; vertical-align: -2px; margin: 0 4px; color: var(--muted); }
  .toast-x {
    flex: none; width: 32px; height: 32px;
    display: flex; align-items: center; justify-content: center;
    color: var(--muted); border-radius: 6px; min-height: 0;
  }
  .toast-x:hover { color: var(--text); background: var(--line); }
  .toast-x svg { width: 13px; height: 13px; display: block; }
  /* Mission toast: the wave's orders, posted once on wave load.
     Bigger than lane notes and pinned to the top so it reads as
     the brief, not the chatter. Same 6s lifetime as lane notes. */
  .toast.mission {
    position: fixed; top: 66px; left: 0; right: 0; margin: 0 auto;
    width: min(560px, 92vw);
    padding: 12px 8px 12px 16px;
  }
  .toast.mission .toast-text { font-size: 15px; line-height: 1.55; }
  .statline {
    display: flex; justify-content: space-between;
    font-size: 12.5px; padding: 4px 0;
    border-bottom: 1px solid var(--line);
  }
  .statline span:first-child { color: var(--muted); }
  .transport { display: flex; gap: 8px; }
  .transport .btn--primary { flex: 1; }
  .transport .btn--ghost { min-width: 44px; padding: 0; }

  /* Intro page: the beginner loader. Full-bleed landing, the whole
     mechanic on one screen: traffic legend, chain, money, goal. The
     lane behind the boxes is pure CSS dots drifting right — traffic. */
  body.intro-page {
    overflow-y: auto;
    overflow-x: hidden;
    background: var(--bg);
    min-width: 320px;
  }
  .intro-screen {
    width: min(720px, calc(100vw - 32px)); max-width: 720px; margin: 0 auto;
    padding: clamp(32px, 6vw, 56px) clamp(16px, 4vw, 24px) 48px;
    box-sizing: border-box;
    animation: introin .25s ease both;
  }
  @keyframes introin { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
  .intro-eyebrow { font-size: 10px; color: var(--muted); letter-spacing: .06em; text-transform: uppercase; margin: 0; }
  .intro-mark { width: 40px; height: 40px; display: block; margin-bottom: 14px; }
  .intro-name { font-size: 12.5px; color: var(--muted); margin: 10px 0 0; }
  .intro-name b { color: var(--text); }
  .brand-mark { width: 22px; height: 22px; display: block; }
  .intro-screen h1 { font-family: var(--mission); font-size: clamp(30px, 6vw, 44px); line-height: 1.15; font-weight: 400; margin: 10px 0 0; }
  .intro-sub { font-size: 14.5px; line-height: 1.6; color: var(--muted); max-width: 62ch; margin: 12px 0 0; }
  .intro-lane {
    position: relative; overflow: hidden;
    display: flex; gap: clamp(6px, 2vw, 14px); align-items: center; justify-content: center;
    border: 1px dashed var(--line); border-radius: 10px;
    margin: 22px 0; padding: 16px 12px;
    background-image: radial-gradient(circle, var(--text) 1.5px, transparent 1.7px);
    background-size: 22px 12px; background-repeat: repeat-x; background-position: 0 center;
  }
  .intro-box {
    position: relative; z-index: 1; flex: none;
    background: var(--bg); border: 1px solid var(--line-strong);
    border-radius: 8px; padding: 8px 14px;
    font-family: var(--mono); font-size: 12px; color: var(--text);
  }
  /* Flow: the lane speaks the board's chevron language. Each gap marches
     its own token — junk (hollow) walks into the edge, reads (green) run
     to the cache, writes (amber) cut to the db. Same pace, three stories. */
  .intro-flow { position: relative; flex: none; width: clamp(30px, 9vw, 60px); height: 16px; }
  .intro-flow i {
    position: absolute; top: 50%; margin-top: -4px;
    width: 0; height: 0; opacity: 0;
    animation: flowrun 1.5s linear infinite;
  }
  .intro-flow i.fl-read { border-left: 6px solid #30d158; border-top: 4px solid transparent; border-bottom: 4px solid transparent; }
  .intro-flow i.fl-write { border-left: 6px solid #ffb340; border-top: 4px solid transparent; border-bottom: 4px solid transparent; }
  .intro-flow i.fl-junk { border-left: 6px solid var(--muted); border-top: 4px solid transparent; border-bottom: 4px solid transparent; }
  .intro-flow i.fl-gen { border-left: 6px solid var(--line-strong); border-top: 4px solid transparent; border-bottom: 4px solid transparent; }
  .intro-flow i:nth-child(2) { animation-delay: .5s; }
  .intro-flow i:nth-child(3) { animation-delay: 1s; }
  @keyframes flowrun { 0% { opacity: 0; left: -8px; } 12% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; left: 100%; } }
   /* Deck: one card revealed at a time, sliding in from the travel
     direction. Dots jump, arrows walk, Next wraps on the last card. */
  .deck { position: relative; margin: 6px 0 4px; min-height: 296px; max-width: 100%; overflow: hidden; }
  .dcard {
    display: none;
    background: var(--surface); border: 1px solid var(--line-strong);
    border-radius: var(--r); padding: clamp(18px, 3vw, 22px) clamp(16px, 3vw, 24px);
    box-shadow: 0 12px 40px rgba(0,0,0,.35);
    overflow-wrap: anywhere; word-break: break-word;
  }
  .dcard.on { display: block; }
  .dcard.on.fwd { animation: cardfwd .28s ease both; }
  .dcard.on.back { animation: cardback .28s ease both; }
  @keyframes cardfwd { from { opacity: 0; transform: translateX(26px); } to { opacity: 1; transform: none; } }
  @keyframes cardback { from { opacity: 0; transform: translateX(-26px); } to { opacity: 1; transform: none; } }
  .dcard h2 { font-family: var(--mono); font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--text); margin: 0 0 12px; font-weight: 600; }
  .dcard p { font-size: 13.5px; line-height: 1.65; margin: 0 0 12px; }
  .dcard p:last-child { margin-bottom: 0; }
  .dcard p b { color: var(--text); }
  .deck-nav { display: flex; align-items: center; gap: 12px; margin: 14px 0 4px; flex-wrap: wrap; }
  .deck-nav .btn { min-height: 40px; }
  .deck-nav #deck-next { margin-left: auto; min-width: 96px; }
  .deck-dots { display: flex; gap: 8px; }
  .deck-dot {
    width: 22px; height: 22px; min-height: 0; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .deck-dot::before {
    content: ""; width: 7px; height: 7px; border-radius: 50%;
    background: var(--line-strong); transition: background .15s ease;
  }
  .deck-dot.on::before { background: var(--text); }
  .intro-legend { list-style: none; margin: 0; padding: 0; font-size: 13.5px; line-height: 1.6; }
  .intro-legend li { display: flex; gap: 12px; align-items: baseline; margin-bottom: 10px; }
  .intro-legend li:last-child { margin-bottom: 0; }
  /* Signal dots: the same three tokens the lane speaks. */
  .sig { flex: none; width: 10px; height: 10px; border-radius: 50%; align-self: center; }
  .sig-read { background: #30d158; }
  .sig-write { background: #ffb340; }
  .sig-junk { border: 1.5px solid var(--muted); background: transparent; }
  .intro-start { width: 100%; min-height: 52px; font-size: 16px; text-decoration: none; margin-top: 22px; }
  .intro-note { text-align: center; font-size: 11px; color: var(--muted); margin: 12px 0 0; }
  @media (max-width: 640px) { .intro-screen { padding: 36px 16px 32px; } .deck { min-height: 0; } .dcard { padding: 18px; } }
  @media (max-width: 360px) {
    .intro-screen { width: calc(100vw - 16px); padding: 24px 12px 32px; }
    .intro-lane { gap: 4px; flex-wrap: nowrap; }
    .intro-box { padding: 6px 8px; font-size: 11px; }
    .intro-flow { width: 22px; }
    .deck-nav { gap: 8px; }
    .deck-nav #deck-next { min-width: 0; flex: 1 1 auto; }
  }
  @media (prefers-reduced-motion: reduce) { .intro-screen, .intro-lane, .dcard.on.fwd, .dcard.on.back { animation: none; } .intro-flow i { animation: none; opacity: 1; left: 35%; } }

  /* Tour: the first-run walkthrough. One pinned bubble, same paper
     and ink as the panels, above everything but the tooltip. */
  #tour {
    position: fixed; left: 0; top: 0; z-index: 70;
    width: min(300px, 86vw);
    background: var(--surface); border: 1px solid var(--line-strong);
    border-radius: var(--r); box-shadow: 0 8px 32px rgba(0,0,0,.42);
    padding: 12px 14px;
    animation: tourin .2s ease both;
  }
  #tour[hidden] { display: none; }
  @keyframes tourin { from { opacity: 0; } to { opacity: 1; } }
  .tour-step { font-size: 10px; color: var(--muted); margin: 0 0 6px; letter-spacing: .06em; text-transform: uppercase; }
  #tour-text { font-size: 12.5px; line-height: 1.55; margin: 0 0 12px; }
  .tour-actions { display: flex; gap: 8px; }
  .tour-actions .btn { min-height: 32px; font-size: 12px; }
  .tour-actions #tour-done { margin-left: auto; }
  .tour-hl { outline: 2px solid var(--text); outline-offset: 3px; border-radius: 6px; }
  @media (prefers-reduced-motion: reduce) { #tour { animation: none; } }

  /* Small-screen gate: below desktop widths the board is replaced by
     a plain instruction to come back on a PC. No mobile layout, no
     compromises — the instrument needs the room. */
  #smallscreen { display: none; }
  @media (max-width: 900px) {
    #smallscreen {
      display: flex; flex-direction: column; justify-content: center;
      position: fixed; inset: 0; z-index: 200;
      background: var(--bg); padding: 32px 28px;
    }
    #smallscreen .intro-eyebrow { margin-bottom: 10px; }
    #smallscreen h1 {
      font-family: var(--mission); font-weight: 400;
      font-size: clamp(30px, 9vw, 44px); line-height: 1.15; margin: 0;
    }
    #smallscreen p:last-child { color: var(--muted); font-size: 14px; line-height: 1.6; max-width: 34ch; margin: 14px 0 0; }
  }

  /* Report: grade stamp + teaching line + next action. */
  #rep {
    grid-area: rep;
    display: flex; align-items: center; gap: 16px;
    min-height: 92px; padding: 14px 20px;
    flex-wrap: wrap; row-gap: 8px;
    border-top: 1px solid var(--line);
  }
  #rep .instr { margin: 0; width: 74px; flex: none; }
  #rep .instr::after { display: none; }
  /* Report grades: a washing backdrop per verdict, drifting slow.
     F red, C amber, B neutral ink, A green, S gold.
     Tutorial has its own held/broke wash so check/X reads as lesson
     verdict, not a rank — same entrance language, own hue. */
  #rep[class*="grade-"] { background-size: 220% 100%; animation: repdrift 9s linear infinite; }
  #rep.grade-F { background-image: linear-gradient(100deg, transparent 20%, color-mix(in srgb, #ff453a 16%, transparent) 50%, transparent 80%); }
  #rep.grade-C { background-image: linear-gradient(100deg, transparent 20%, color-mix(in srgb, #ffb340 15%, transparent) 50%, transparent 80%); }
  #rep.grade-B { background-image: linear-gradient(100deg, transparent 20%, color-mix(in srgb, var(--text) 9%, transparent) 50%, transparent 80%); }
  #rep.grade-A { background-image: linear-gradient(100deg, transparent 20%, color-mix(in srgb, #30d158 14%, transparent) 50%, transparent 80%); }
  #rep.grade-S { background-image: linear-gradient(100deg, transparent 20%, color-mix(in srgb, #e5b93f 18%, transparent) 50%, transparent 80%); }
  #rep.grade-tut-held { background-image: linear-gradient(100deg, transparent 20%, color-mix(in srgb, #30d158 13%, transparent) 50%, transparent 80%); }
  #rep.grade-tut-broke { background-image: linear-gradient(100deg, transparent 20%, color-mix(in srgb, #ff453a 13%, transparent) 50%, transparent 80%); }
  /* Report verdicts read across the room: grade color on the stamp
     and a matching top rule on the strip. */
  #rep.grade-F { border-top: 2px solid #ff453a; }
  #rep.grade-C { border-top: 2px solid #ffb340; }
  #rep.grade-B { border-top: 2px solid var(--line-strong); }
  #rep.grade-A { border-top: 2px solid #30d158; }
  #rep.grade-S { border-top: 2px solid #e5b93f; }
  #rep.grade-tut-held { border-top: 2px solid #30d158; }
  #rep.grade-tut-broke { border-top: 2px solid #ff453a; }
  #rep.grade-F #stamp { color: #ff453a; border-color: #ff453a; }
  #rep.grade-C #stamp { color: #ffb340; border-color: #ffb340; }
  #rep.grade-A #stamp { color: #30d158; border-color: #30d158; }
  #rep.grade-S #stamp { color: #e5b93f; border-color: #e5b93f; }
  #rep.grade-tut-held #stamp { color: #30d158; border-color: #30d158; }
  #rep.grade-tut-broke #stamp { color: #ff453a; border-color: #ff453a; }
  @keyframes repdrift { from { background-position: 0% 0; } to { background-position: -220% 0; } }
  /* entrance: stamp pops, teaching lines rise in stagger.
     Tutorial gets its own pop: held does a tiny bounce, broke does a
     quick shake — same family as the rank pop, never competing. */
  #rep.landed #stamp { animation: stamppop 0.45s cubic-bezier(0.2, 1.4, 0.4, 1); }
  #rep.grade-tut-held.landed #stamp { animation: tutheldpop 0.55s cubic-bezier(0.2, 1.5, 0.4, 1); }
  #rep.grade-tut-broke.landed #stamp { animation: tutbrokepop 0.5s ease; }
  #rep.landed #report-text p { animation: repriserise 0.5s ease both; }
  #rep.landed #report-text .hint { animation-delay: 0.09s; }
  #rep.landed #next { animation: repriserise 0.5s ease 0.16s both; }
  @keyframes stamppop { 0% { transform: scale(0.6); } 100% { transform: scale(1); } }
  @keyframes tutheldpop { 0% { transform: scale(0.5); } 55% { transform: scale(1.08); } 100% { transform: scale(1); } }
  @keyframes tutbrokepop { 0% { transform: translateX(0) scale(0.85); } 25% { transform: translateX(-3px) scale(1); } 50% { transform: translateX(3px) scale(1); } 75% { transform: translateX(-2px) scale(1); } 100% { transform: translateX(0) scale(1); } }
  @keyframes repriserise { 0% { opacity: 0; transform: translateY(8px); } 100% { opacity: 1; transform: none; } }
  @media (prefers-reduced-motion: reduce) {
    #rep.landed #stamp, #rep.grade-tut-held.landed #stamp, #rep.grade-tut-broke.landed #stamp, #rep.landed #report-text p, #rep.landed #next { animation: none; }
  }
  #stamp {
    width: 56px; height: 48px; flex: none;
    display: flex; align-items: center; justify-content: center;
    border: 1.5px solid var(--text);
    border-radius: var(--r-sm);
    font-family: var(--mono);
    font-size: 25px; font-weight: 600;
  }
  #stamp svg { width: 22px; height: 22px; display: block; }
  #rep .spacer { flex: 1 0 auto; }
  #report-text { min-width: 0; flex: 1 1 280px; display: flex; flex-direction: column; gap: 4px; min-height: 0; }
  /* The strip never grows over the board: verdict clamps to two lines,
     the hint to one — the rest lives in the Details popup. */
  #report-text p { margin: 0; font-size: 13.5px; max-width: 68ch; overflow-wrap: anywhere; word-break: break-word; white-space: normal; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  #report-text .hint {
    font-family: var(--mono);
    font-size: 11px; letter-spacing: 0.06em; line-height: 1.5;
    color: var(--muted); margin-top: 0; overflow-wrap: anywhere; word-break: break-word; white-space: normal;
    display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
  }
  /* Design: same floating panel, polished tick cards. */
  #design { width: min(720px, 94vw); max-height: 84vh; }
  #design-body { padding: 16px 18px; overflow-y: auto; flex: 1 1 auto; min-height: 0; }
  #design-meta { display: grid; grid-template-columns: 1fr 160px; gap: 14px; margin-bottom: 16px; }
  #design-meta label { font-size: 10px; letter-spacing: 0.14em; color: var(--muted); text-transform: uppercase; margin-bottom: 6px; display: block; }
  #design-meta .knobinput { min-height: 40px; }
  .design-head { display: grid; grid-template-columns: 1fr 62px 62px 62px 62px 42px 42px 28px; gap: 6px; padding: 0 4px 6px; font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; color: var(--muted); text-transform: uppercase; }
  #design-ticks { display: flex; flex-direction: column; gap: 8px; max-height: 42vh; overflow-y: auto; padding-right: 2px; }
  .design-row { display: grid; grid-template-columns: 1fr 62px 62px 62px 62px 42px 42px 28px; gap: 6px; align-items: center; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 8px 6px 8px 8px; }
  .design-row .knobinput { min-height: 36px; padding: 0 8px; font-size: 12px; background: var(--surface); }
  .design-row .rm { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; color: var(--muted); border-radius: 6px; }
  .design-row .rm:hover { color: var(--text); background: var(--line); }
  .design-chk { width: 18px; height: 18px; accent-color: var(--text); justify-self: center; }
  #design-actions { display: flex; gap: 8px; margin-top: 14px; }
  #design-err { color: #ff453a; font-size: 11px; margin: 8px 0 0; }
  #design footer { border-top: 1px solid var(--line); padding: 10px 18px; display: flex; align-items: center; gap: 10px; }
  #design footer .tune-actions { margin-left: auto; display: flex; gap: 8px; }
  @media (max-width: 640px) { .design-head { grid-template-columns: 1fr 46px 46px 46px 46px 30px 30px 24px; font-size: 9px; } .design-row { grid-template-columns: 1fr 46px 46px 46px 46px 30px 30px 24px; } .design-row .knobinput { font-size: 10px; min-height: 32px; } }
  /* Full debrief: same floating panel language, scrolling inside itself. */
  #debrief-body { padding: 14px 18px; overflow-y: auto; flex: 1 1 auto; min-height: 0; font-size: 13.5px; line-height: 1.6; }
  #debrief-body .debrief-verdict { margin: 0 0 10px; font-weight: 600; }
  #debrief-body .debrief-pat { margin: 0 0 10px; color: var(--muted); font-size: 12.5px; }
  #debrief-body ul { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 8px; }
  #rep-detail { flex: none; min-height: 44px; }
  #next {
    cursor: pointer;
    flex: none;
    display: inline-flex; align-items: center; gap: 8px;
    min-height: 44px; padding: 0 18px;
    background: var(--text); color: var(--bg);
    border: 1px solid var(--text);
    border-radius: var(--r-sm);
    font-family: var(--mono); font-size: 13px; font-weight: 600;
  }
  #next:hover { background: transparent; color: var(--text); }
  #next svg { width: 14px; height: 14px; display: block; }

  /* Register marks: drafting crop ticks at frame corners + seams. */
  .reg { position: fixed; width: 12px; height: 12px; pointer-events: none; }
  #deck > .reg { z-index: 2; }
  .reg.tl { top: 0; left: 0; border-top: 1.5px solid var(--line); border-left: 1.5px solid var(--line); }
  .reg.tr { top: 0; right: 0; border-top: 1.5px solid var(--line); border-right: 1.5px solid var(--line); }
  .reg.bl { bottom: 0; left: 0; border-bottom: 1.5px solid var(--line); border-left: 1.5px solid var(--line); }
  .reg.br { bottom: 0; right: 0; border-bottom: 1.5px solid var(--line); border-right: 1.5px solid var(--line); }

  @media (max-width: 1220px) {
    #deck { grid-template-columns: 200px 1fr 190px; }
    .rail { padding: 14px 14px 12px; }
    .rail .instr { margin: 0 -14px 10px; padding: 12px 14px 8px; }
    .readout { padding: 0 16px; }
  }
  @media (max-width: 1100px) {
    /* brand goes first: chrome yields to content, not the reverse */
    #brand { display: none; }
  }
  @media (max-width: 900px) {
    /* the canvas stays fixed fullscreen behind; chrome stacks over it */
    body { overflow: auto; }
    #deck { position: static; display: block; }
    #bar { position: sticky; top: 0; z-index: 5; column-gap: 14px; padding: 8px 12px; flex-wrap: wrap; row-gap: 8px; }
    #brand { display: none; }
    /* telemetry gets its own scroll row: three full-width rows
       (title, telemetry, modes) never paint over each other */
    #bar-right { order: 2; flex: 1 1 100%; overflow-x: auto; }
    #bar-actions { order: 3; flex: 1 1 100%; justify-content: flex-start; overflow-x: auto; }
    #wave-title h1 { font-size: 16px; }
    .readout { padding: 0 12px; }
    .readout:first-child { padding-left: 0; }
    #rail-l, #rail-r, #rep { border: 0; border-bottom: 1px solid var(--line); }
    /* solid rails: translucent glass over the lane reads as broken */
    #rail-l, #rail-r { background: var(--surface); backdrop-filter: none; -webkit-backdrop-filter: none; }
    .rail { overflow: visible; }
    #well { display: none; }
    #rep { flex-wrap: wrap; padding: 14px 18px; row-gap: 10px; }
    #rep .spacer { display: none; }
    #sheet { width: 94vw; max-height: 86vh; }
    /* zoom dock is a desktop pointer convenience; touch drag-pans.
       hiding beats floating over the wrapped bar. (Specificity beats
       the base rule below regardless of source order.) */
    body #zoom { display: none; }
    #toasts { bottom: 106px; }
    #bar-actions { gap: 6px; }
    #bar-actions .btn { padding: 0 8px; font-size: 10px; }
  }
  @media (max-width: 640px) {
    .readout .value { font-size: 13px; }
    #wave-title h1 { font-size: 15px; }
    #rep { padding: 12px 14px; gap: 12px; }
  }
  @media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
  }
  #board { touch-action: none; cursor: grab; }
  /* Zoom dock: lives inside the well, always 16px from its corner —
     never fixed to the viewport, so it can never drift out of the
     canvas as rails or rep change size. */
  #zoom { position: absolute; right: 16px; bottom: 16px; z-index: 5; display: flex; flex-direction: column; gap: 8px; pointer-events: auto; }
  #zoom .btn { width: 44px; background: var(--panel); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); border: 1px solid var(--line); }
  #zoom .btn:hover { border-color: var(--text); }
  #zoom svg { width: 16px; height: 16px; display: block; }
  .btn:disabled { opacity: 0.35; cursor: default; }
  /* Juice: press physics, the RUN invitation, stat bumps, answer pops.
     All of it dies under prefers-reduced-motion with everything else. */
  .btn { transition: transform 0.08s ease, background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease; }
  .btn:active { transform: scale(0.95); }
  /* Ready pulse: the run button breathes when a wave can go. */
  #play:not(:disabled) { animation: playready 2.2s ease-in-out infinite; }
  #play:disabled { animation: none; }
  @keyframes playready {
    0%, 100% { box-shadow: 0 0 0 0 transparent; }
    50% { box-shadow: 0 0 0 7px var(--line); }
  }
  .statline .mono { display: inline-block; }
  .statline .mono.bump { animation: statbump 0.3s ease; }
  @keyframes statbump { 30% { transform: scale(1.35); } }
  .quiz-opt.right, .quiz-opt.wrong { animation: optpop 0.25s ease; }
  @keyframes optpop { from { transform: scale(0.97); } }
  /* Composer knobs: real number inputs. Typeable, native spinners,
     no rebuild under the finger. */
  .pick.knobrow { grid-template-columns: 1fr; grid-template-areas: "main" "sizes"; }
  .knobinput {
    width: 100%; min-height: 44px;
    background: transparent; color: var(--text);
    border: 1px solid var(--line); border-radius: var(--r-sm);
    padding: 0 14px; font: inherit;
    font-family: var(--mono); font-size: 13px;
  }
  .knobinput:focus { outline: none; border-color: var(--text); }
  /* Juice II: the whole chrome. Dialogs land, theme crossfades, the
     meter glides, waves slide in, spending flashes. Same
     prefers-reduced-motion kill-switch covers all of it. */
  #sheet, #import, #quiz, #snapview, #debriefdlg, #design { animation: panelin 0.3s cubic-bezier(0.2, 1.2, 0.4, 1); }
  @keyframes panelin { from { opacity: 0; transform: translate(-50%, -48%) scale(0.97); } }
  #sheet-backdrop, #import-backdrop, #quiz-backdrop, #snapview-backdrop, #debrief-backdrop, #design-backdrop { animation: fadein 0.25s ease; }
  @keyframes fadein { from { opacity: 0; } }
  body { transition: background-color 0.25s ease, color 0.25s ease; }
  #bar, #rail-l, #rail-r, #rep { transition: background-color 0.25s ease, border-color 0.25s ease; }
  /* Rail tools: one button + dropdown for infrequent actions. */
  .rail-tools { position: relative; display: flex; flex-direction: column; align-items: stretch; }
  #tools-menu {
    position: absolute; top: 100%; left: 0; right: 0; z-index: 10;
    margin-top: 4px; padding: 4px;
    background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--r-sm);
    display: flex; flex-direction: column; gap: 2px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.25);
  }
  .tools-item {
    display: block; width: 100%; padding: 8px 10px; border: 0; border-radius: 6px;
    background: transparent; color: var(--text); font: inherit;
    font-family: var(--mono); font-size: 12px; text-align: left; white-space: nowrap;
  }
  .tools-item:hover { background: var(--line); }
  /* Brick stack shadow: a subtle depth cue for count > 1. */
  .comp { transition: background-color 0.12s ease, border-color 0.12s ease, transform 0.12s ease; }
  .comp:hover { border-color: var(--line-strong); transform: translateY(-1px); }
  .comp .chip { transition: border-color 0.12s ease; }
  .meter i { transition: width 0.18s linear; }
  #next svg { transition: transform 0.15s ease; }
  #next:hover svg { transform: translateX(3px); }
  #station.swap { animation: swapin 0.35s ease; }
  @keyframes swapin { from { opacity: 0; transform: translateX(12px); } }
  #budget.spent { animation: spentflash 0.5s ease; }
  @keyframes spentflash { 25% { color: #ff453a; } }
  /* Wave dots: every level's best mark, always in sight. */
  #wavedots { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }
  #wavedots:empty { display: none; }
  #wavedots .wdot {
    flex: 1 1 26px; min-width: 26px; min-height: 38px; padding: 3px 2px;
    font-family: var(--mono); font-size: 10px;
    background: transparent; color: var(--muted);
    border: 1px solid var(--line); border-radius: 8px;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 0; line-height: 1.35;
  }
  #wavedots .wdot b { font-size: 12px; font-weight: 600; color: var(--text); }
  #wavedots .wdot .g-S { color: #e5b93f; }
  #wavedots .wdot .g-A { color: #30d158; }
  #wavedots .wdot .g-C { color: #ffb340; }
  #wavedots .wdot .g-F { color: #ff453a; }
  #wavedots .wdot:hover { border-color: var(--text); color: var(--text); }
  #wavedots .wdot.cur { border-color: var(--text); color: var(--text); }
  #wavedots .wdot.locked { opacity: 0.35; }
  #wavedots .stagerow { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; flex: 1 1 100%; }
  #wavedots .stagerow .wdot { border-style: double; }
  /* Orders: the wave's own words, persistent DOM — the canvas brief
     is scenery, this is the instruction you can re-read mid-build. */
  #rail-r .instr { margin-top: 2px; }
  #waveobj { font-size: 12.5px; line-height: 1.55; margin: 0 0 14px; max-width: 32ch; overflow-wrap: anywhere; word-break: break-word; white-space: normal; }
  .btn[aria-disabled="true"] { opacity: 0.35; cursor: not-allowed; }
  /* Tip: the one tooltip. Opt in with data-tip; native titles suppressed. */
  #tip {
    position: fixed; left: 0; top: 0; z-index: 99;
    max-width: 250px; padding: 8px 12px;
    background: var(--surface); color: var(--text);
    border: 1px solid var(--line-strong); border-radius: var(--r-sm);
    font-family: var(--mono); font-size: 11.5px; line-height: 1.5;
    pointer-events: none;
  }
  .btn--ghost[aria-pressed="true"] { border-color: var(--text); color: var(--text); }
