/* Buttons, fields, tables, banners, panels. Tokens only — no literal colours
   below the token block. Retheme by editing css/tokens.css, never this file. */

/* ---------------------------------------------------------------------- *
 * App-level tokens.
 *
 * The physics vocabulary needs more colours than the six brand ones, because
 * a learner has to tell a friction arrow from a drag arrow at a glance. They
 * are defined here rather than in tokens.css — that file is copied verbatim
 * between Detronics apps and belongs to the brand, not to this app.
 *
 * Every one is chosen to sit at 3:1 or better against --panel in both themes,
 * because these carry lines and arrowheads, not just fills. Light is the base;
 * dark is redefined twice, once behind prefers-color-scheme for viewers who
 * never touch the toggle and once behind [data-theme] so the toggle wins.
 * ---------------------------------------------------------------------- */

:root {
  --force-weight:   #b45309;
  --force-normal:   #0f766e;
  --force-friction: #7e22ce;
  --force-drag:     #0369a1;
  --force-applied:  #2f6e94;
  --force-spring:   #9d174d;
  --force-tension:  #4d7c0f;
  --force-buoyancy: #0e7490;
  --force-control:  #a1621b;
  --force-net:      #a32020;

  --vec-velocity:     #1f7a3d;
  --vec-acceleration: #be185d;
  --vec-momentum:     #4338ca;

  --body-0: #7fabc7;
  --body-1: #e0a458;
  --body-2: #82b28a;
  --body-3: #b08ec4;
  --body-ink: #1f2d3d;

  --ground: #9aa4ad;
  --grid: #dfe3e7;
  --trail: #94a2b1;
  --wall: #6b7d8f;
  --cannon: #8a5a00;

  /* The four kinds of statement the app must keep apart. */
  --kind-reality: #1f7a3d;
  --kind-model: #2f6e94;
  --kind-assumption: #8a5a00;
  --kind-approximation: #a32020;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --force-weight:   #f0b45c;
    --force-normal:   #5eead4;
    --force-friction: #c9a2ee;
    --force-drag:     #7dd3fc;
    --force-applied:  #9cc4dc;
    --force-spring:   #f9a8d4;
    --force-tension:  #bef264;
    --force-buoyancy: #67e8f9;
    --force-control:  #f0c078;
    --force-net:      #f08a8a;

    --vec-velocity:     #6ed08c;
    --vec-acceleration: #f9a8d4;
    --vec-momentum:     #a5b4fc;

    --body-0: #7fabc7;
    --body-1: #e0a458;
    --body-2: #82b28a;
    --body-3: #b08ec4;
    --body-ink: #12202c;

    --ground: #5b6b7c;
    --grid: #2a3949;
    --trail: #6b7d8f;
    --wall: #8ca0b4;
    --cannon: #e8b45c;

    --kind-reality: #6ed08c;
    --kind-model: #9cc4dc;
    --kind-assumption: #e8b45c;
    --kind-approximation: #f08a8a;
  }
}

:root[data-theme="dark"] {
  --force-weight:   #f0b45c;
  --force-normal:   #5eead4;
  --force-friction: #c9a2ee;
  --force-drag:     #7dd3fc;
  --force-applied:  #9cc4dc;
  --force-spring:   #f9a8d4;
  --force-tension:  #bef264;
  --force-buoyancy: #67e8f9;
  --force-control:  #f0c078;
  --force-net:      #f08a8a;

  --vec-velocity:     #6ed08c;
  --vec-acceleration: #f9a8d4;
  --vec-momentum:     #a5b4fc;

  --body-0: #7fabc7;
  --body-1: #e0a458;
  --body-2: #82b28a;
  --body-3: #b08ec4;
  --body-ink: #12202c;

  --ground: #5b6b7c;
  --grid: #2a3949;
  --trail: #6b7d8f;
  --wall: #8ca0b4;
  --cannon: #e8b45c;

  --kind-reality: #6ed08c;
  --kind-model: #9cc4dc;
  --kind-assumption: #e8b45c;
  --kind-approximation: #f08a8a;
}

/* --- surfaces ---------------------------------------------------------- */

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: var(--space-4);
}

.section { border-bottom: 1px solid var(--border); }
.section:last-child { border-bottom: none; }

/*
 * A section heading has to look like a heading, not like the quietest thing in
 * the panel.
 *
 * It used to be 11px faint grey above a body of full-size dark labels, which
 * made it less prominent than its own contents: with several sections open at
 * once there was nothing to tell you where one ended and the next began. A
 * filled band fixes that without adding weight - the heading is still small and
 * still quiet, but it is now obviously a different kind of thing from the
 * inputs underneath it.
 */
.section__title {
  display: flex; align-items: center; gap: var(--space-2);
  margin: 0;
  padding: var(--space-3) var(--space-4);
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-dim);
  background: var(--panel-2);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
/* Open, it also needs a line under it: the band alone reads as a lid on a
 * closed box, and as a label for the wrong thing once the box is open. */
.section[open] > .section__title { border-bottom: 1px solid var(--border); }
.section__title::-webkit-details-marker { display: none; }
.section__title::after {
  content: '';
  margin-left: auto;
  width: 6px; height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg) translate(-1px, 1px);
  transition: transform 0.12s ease;
}
.section[open] > .section__title::after { transform: rotate(45deg) translate(-1px, -1px); }
.section__title:hover { color: var(--text); background: var(--panel-3); }
.section__body { padding: var(--space-3) var(--space-4) var(--space-4); }

.muted { color: var(--text-faint); }
.value { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }

/* --- buttons ----------------------------------------------------------- */

.btn {
  font: inherit;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  min-height: 32px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--panel-2);
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  /* Two of these are anchors — the home link and the coffee cup — and without
     this the browser underlines the glyph inside the disc. */
  text-decoration: none;
}
.btn:hover { background: var(--panel-3); }
.btn:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 1px; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* --accent is ~2.3:1 on white: it fills and outlines, it never carries text.
   Accent-coloured text uses --accent-strong. */
.btn-primary {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
  color: var(--accent-ink);
}
.btn-primary:hover { filter: brightness(1.08); background: var(--accent-strong); }
.btn-sm { min-height: 26px; padding: 3px var(--space-2); font-size: 12px; }
.btn-danger { color: var(--danger); border-color: var(--danger); background: var(--danger-soft); }
.btn[aria-pressed="true"] {
  background: var(--accent-soft); border-color: var(--accent-strong); color: var(--accent-strong);
  font-weight: 600;
}
.btn-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* --- tabs and mode switch ---------------------------------------------- */

.segmented {
  display: flex; gap: var(--space-1);
  padding: var(--space-1);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow-x: auto;
  /* Firefox and iOS keep the bar from shrinking its own box to nothing. */
  scrollbar-width: thin;
}

/*
 * Grow to fill the bar, never shrink below the label.
 *
 * `flex-shrink: 1` is the default, and with thirteen experiments it squashes
 * every tab until the words sit on top of each other — which looks like a font
 * problem and is a flex problem. Shrink 0 makes the bar scroll instead, which
 * is what its `overflow-x` was always for.  pitfalls.md #2, in miniature.
 */
.segmented__btn {
  flex: 1 0 auto;
  font: inherit; font-weight: 600;
  padding: 7px var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  white-space: nowrap;
}
.segmented__btn:hover { background: var(--panel-3); }
.segmented__btn[aria-selected="true"] {
  background: var(--panel);
  border-color: var(--border);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}
.segmented--modes { flex: 0 0 auto; }
.segmented--modes .segmented__btn { flex: 0 0 auto; padding: 5px var(--space-3); font-size: 12px; }

/* --- fields ------------------------------------------------------------ */

.field { margin-bottom: var(--space-3); }
.field:last-child { margin-bottom: 0; }
.field__label {
  display: flex; align-items: center; gap: var(--space-2);
  margin-bottom: var(--space-1);
  font-size: 12px; font-weight: 600; color: var(--text-dim);
}
.field__hint { margin-top: var(--space-1); font-size: 11px; color: var(--text-faint); }
.field__spacer { flex: 1 1 auto; }

.input, .select {
  font: inherit; width: 100%;
  padding: var(--space-2) var(--space-3);
  min-height: 34px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--panel);
  color: var(--text);
}
.input { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.input:focus, .select:focus { outline: 2px solid var(--accent-strong); outline-offset: -1px; border-color: var(--accent-strong); }
.input--invalid { border-color: var(--danger); background: var(--danger-soft); }

.field-row { display: flex; gap: var(--space-2); }
.field-row > * { flex: 1 1 0; min-width: 0; }

.field--toggle { display: flex; align-items: center; gap: var(--space-2); cursor: pointer; }
.field__label--inline { margin: 0; }

input[type="range"] { width: 100%; accent-color: var(--accent-strong); }
input[type="checkbox"] { accent-color: var(--accent-strong); }

/* --- chips ------------------------------------------------------------- */

.chipset { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.chip {
  font: inherit; font-size: 12px;
  padding: 5px var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--panel);
  color: var(--text-dim);
  cursor: pointer;
}
.chip:hover { background: var(--panel-2); }
.chip[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: var(--accent-strong);
  color: var(--accent-strong);
  font-weight: 600;
}

/* --- info icon --------------------------------------------------------- */

.info {
  flex: 0 0 auto;
  width: 15px; height: 15px; padding: 0;
  font: 700 10px/1 var(--font);
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: var(--panel-2);
  color: var(--text-faint);
  cursor: help;
}
.info:hover { border-color: var(--accent-strong); color: var(--accent-strong); }

/*
 * The gear beside a section title.
 *
 * An SVG with a viewBox and no size fills whatever holds it, which is how this
 * first appeared: one 700-pixel cog above the settings it belonged to. Sized
 * in em so it tracks the title it sits next to.
 */
.gear {
  flex: 0 0 auto;
  width: 1.05em; height: 1.05em;
  color: var(--text-faint);
}
summary:hover .gear { color: var(--accent-strong); }

/* --- banners ----------------------------------------------------------- */

.banners { display: flex; flex-direction: column; gap: var(--space-2); }
.banner {
  display: flex; align-items: flex-start; gap: var(--space-2);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  border: 1px solid;
  font-size: 13px;
}
.banner__mark { font-weight: 700; flex: 0 0 auto; }
.banner-ok     { color: var(--ok);     background: var(--ok-soft);     border-color: var(--ok); }
.banner-warn   { color: var(--warn);   background: var(--warn-soft);   border-color: var(--warn); }
.banner-danger { color: var(--danger); background: var(--danger-soft); border-color: var(--danger); }
.banner-info   { color: var(--text-dim); background: var(--panel-2);   border-color: var(--border); }

/* --- readouts ---------------------------------------------------------- */

.readout {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--space-3);
}
.stat {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-3);
  min-width: 0;
}
.stat__label {
  display: flex; align-items: center; gap: var(--space-2);
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-faint);
}
.stat__value {
  margin-top: var(--space-1);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 20px; font-weight: 600; color: var(--text);
  overflow-wrap: anywhere;
}
.stat__note { margin-top: 2px; font-size: 11px; color: var(--text-faint); }
.stat--accent .stat__value { color: var(--accent-strong); }

/* A stat tied to a coloured arrow on the drawing. The swatch is what connects
   the number to the thing pointing at the object. */
.stat__swatch {
  flex: 0 0 auto; width: 10px; height: 10px; border-radius: 2px;
  background: var(--swatch, var(--accent));
}
.stat--vector .stat__value { font-size: 17px; }
.stat__sub { margin-top: 2px; font-size: 11px; color: var(--text-dim); font-family: var(--font-mono); }

.stat--editable { border-color: var(--accent-strong); }
.stat__field { display: flex; align-items: baseline; gap: var(--space-2); margin-top: var(--space-1); }
.stat__input {
  flex: 1 1 auto; min-width: 0;
  padding: 2px var(--space-2); min-height: 30px;
  font-size: 19px; font-weight: 600;
  background: var(--panel-2);
}
.stat__unit { flex: 0 0 auto; font-size: 12px; color: var(--text-faint); }

/* --- the physics inspector --------------------------------------------- */

.inspector { display: flex; flex-direction: column; gap: var(--space-2); }
.inspector__row {
  display: grid;
  /* Every column is allowed to shrink below its content. A bare `auto` on the
     value column plus `white-space: nowrap` made the row wider than its parent
     rather than wrapping, which only stayed invisible while the inspector lived
     inside the sidebar's own scroll container. Moved into the viewport, the
     same row pushed the whole page sideways at 375px. */
  grid-template-columns: 12px minmax(0, 1fr) minmax(0, auto);
  align-items: baseline;
  gap: var(--space-2);
  padding: 3px 0;
  border-bottom: 1px dotted var(--border);
  font-size: 12.5px;
}
.inspector__row:last-child { border-bottom: none; }
.inspector__key { color: var(--text-dim); min-width: 0; overflow-wrap: anywhere; }
.inspector__val {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--text); text-align: right;
  min-width: 0;
  /* Wrapping a number is ugly; overflowing the page is worse, and on a phone
     one of the two has to happen. */
  overflow-wrap: anywhere;
}
.inspector__swatch { width: 10px; height: 10px; border-radius: 2px; align-self: center; }
.inspector__row--total { border-top: 1px solid var(--border-strong); border-bottom: none; padding-top: var(--space-2); font-weight: 600; }
.inspector__note { grid-column: 2 / -1; font-size: 11px; color: var(--text-faint); font-family: var(--font); text-align: left; }
.inspector__group {
  font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-faint); margin-top: var(--space-2);
}

/* --- transport --------------------------------------------------------- */

.transport {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  padding: var(--space-2) var(--space-3);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.transport__spacer { flex: 1 1 auto; }
.transport__clock {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 13px; color: var(--text-dim); white-space: nowrap;
}
.transport__speed { display: flex; align-items: center; gap: var(--space-1); }
.transport__speed .chip { padding: 3px var(--space-2); }
.transport__scrub { flex: 1 1 160px; min-width: 120px; }
.transport__btn { min-width: 38px; }

/* --- the model disclosure ---------------------------------------------- */

.disclosure {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
  overflow: hidden;
}
.disclosure > summary {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  padding: var(--space-3) var(--space-4);
  cursor: pointer; font-weight: 600; list-style: none;
}
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary::before { content: '▸'; color: var(--text-faint); }
.disclosure[open] > summary::before { content: '▾'; }
.disclosure__summary { font-size: 11px; color: var(--text-faint); font-weight: 400; margin-left: auto; }
.disclosure__body { padding: 0 var(--space-4) var(--space-4); }

.kind {
  border-left: 3px solid var(--kind-colour, var(--border));
  padding: var(--space-2) 0 var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
}
.kind:last-child { margin-bottom: 0; }
.kind--reality { --kind-colour: var(--kind-reality); }
.kind--model { --kind-colour: var(--kind-model); }
.kind--assumption { --kind-colour: var(--kind-assumption); }
.kind--approximation { --kind-colour: var(--kind-approximation); }

.kind__label {
  font-size: 10px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--kind-colour, var(--text-faint));
}
.kind__item { margin-top: var(--space-2); }
.kind__item:first-of-type { margin-top: var(--space-1); }
.kind__name { font-weight: 600; font-size: 13px; }
.kind__text { font-size: 12.5px; color: var(--text-dim); margin: 2px 0 0; max-width: 70ch; }
.kind__if { font-size: 12px; color: var(--text-faint); margin: 3px 0 0; max-width: 70ch; }
.kind__if b { color: var(--text-dim); font-weight: 600; }

/* An approximation that is switched on is not a footnote — it is a banner. */
.approx-flag {
  display: flex; align-items: flex-start; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--kind-approximation);
  border-radius: var(--radius-sm);
  background: var(--danger-soft);
  color: var(--kind-approximation);
  font-size: 12.5px;
}

.numbers { display: grid; grid-template-columns: 1fr; gap: var(--space-2); margin-top: var(--space-3); }
.numbers__row {
  padding: var(--space-2) var(--space-3);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.numbers__head { display: flex; gap: var(--space-3); align-items: baseline; justify-content: space-between; }
.numbers__label { font-size: 12px; font-weight: 600; color: var(--text-dim); }
.numbers__value { font-family: var(--font-mono); font-size: 13px; color: var(--text); text-align: right; }
.numbers__note { font-size: 11.5px; color: var(--text-faint); margin-top: 3px; max-width: 70ch; }

/* --- the teaching panel ------------------------------------------------ */

.explain-host { display: flex; flex-direction: column; gap: var(--space-3); }

.explain {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
}
.explain > summary {
  padding: var(--space-3) var(--space-4);
  cursor: pointer; font-weight: 600; list-style: none;
  display: flex; align-items: center; gap: var(--space-2);
}
.explain > summary::-webkit-details-marker { display: none; }
.explain > summary::before { content: '▸'; color: var(--text-faint); }
.explain[open] > summary::before { content: '▾'; }
.explain__body { padding: 0 var(--space-4) var(--space-4); }
.explain__body p { margin: 0 0 var(--space-3); max-width: 70ch; }
.explain__body p:last-child { margin-bottom: 0; }

.explain__formula, .explain__worked {
  margin: 0 0 var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--panel-2);
  font-family: var(--font-mono); font-size: 12.5px; line-height: 1.7;
  overflow-x: auto;
  white-space: pre;
}
.explain__worked { background: var(--accent-soft); border-color: var(--accent); color: var(--text); }
.explain__caption {
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 var(--space-1);
}
.explain__valid {
  font-size: 12px; color: var(--text-dim);
  border-left: 3px solid var(--kind-model);
  padding-left: var(--space-3);
  margin: 0 0 var(--space-3);
  max-width: 70ch;
}

/* --- the discovery prompt ---------------------------------------------- */

.prompt {
  border: 1px solid var(--accent);
  background: var(--accent-soft);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
}
.prompt__ask { font-size: 15px; font-weight: 600; color: var(--text); margin: 0; max-width: 60ch; }
.prompt__meta { font-size: 11px; color: var(--text-dim); margin: 0 0 var(--space-1); text-transform: uppercase; letter-spacing: 0.07em; font-weight: 700; }
.prompt__body { font-size: 13px; color: var(--text-dim); margin: var(--space-2) 0 0; max-width: 70ch; }

.misconception {
  margin-top: var(--space-3);
  border-top: 1px solid var(--accent);
  padding-top: var(--space-2);
  font-size: 12.5px;
}
.misconception dt { font-weight: 600; color: var(--text-dim); margin-top: var(--space-2); }
.misconception dd { margin: 2px 0 0; color: var(--text-dim); max-width: 70ch; }

/* --- graphs ------------------------------------------------------------ */

.graph { display: flex; flex-direction: column; gap: var(--space-2); }
.graph__head { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.graph__canvas {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.graph__canvas svg { width: 100%; height: auto; display: block; max-width: none !important; }
.graph__legend { display: flex; flex-wrap: wrap; gap: var(--space-3); font-size: 11px; color: var(--text-faint); }
.graph__key { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }
.graph__empty { padding: var(--space-5); text-align: center; color: var(--text-faint); font-size: 13px; }

/* --- the legend under the drawing -------------------------------------- */

.legend { display: flex; flex-wrap: wrap; gap: var(--space-3); font-size: 11px; color: var(--text-faint); }
.legend__item { display: flex; align-items: center; gap: var(--space-1); }
.legend__key { width: 16px; height: 3px; border-radius: 2px; }

.stage-tools { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.stage-tools__spacer { flex: 1 1 auto; }

/* --- comparison -------------------------------------------------------- */

.compare { display: flex; flex-direction: column; gap: var(--space-3); }
.compare__head { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.compare__change { font-weight: 600; }
.compare-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: var(--space-3); }
.compare-row {
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
}
.compare-row--headline { border-color: var(--accent-strong); }
.compare-row__label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-faint);
}
.compare-row__pair { display: flex; align-items: baseline; gap: var(--space-2); margin-top: var(--space-1); font-family: var(--font-mono); }
.compare-row__a { color: var(--text-dim); }
.compare-row__b { color: var(--accent-strong); font-weight: 600; }
.compare-row__arrow { color: var(--text-faint); }
.compare-row__ratio { font-size: 12px; color: var(--text-dim); margin-top: 3px; }

/* --- tables ------------------------------------------------------------ */

.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: 13px; }
.table th, .table td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
}
.table th {
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-faint);
}
.table td.num, .table th.num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.table tbody tr:hover { background: var(--panel-2); }
.table tbody tr[aria-selected="true"] { background: var(--accent-soft); }
.table tbody tr.is-clickable { cursor: pointer; }
.table tfoot td { font-weight: 600; border-top: 1px solid var(--border-strong); }

/* --- the body picker --------------------------------------------------- */

.body-list { display: flex; flex-direction: column; gap: var(--space-1); }
.body-pick {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel);
  font: inherit; color: var(--text); text-align: left; cursor: pointer; width: 100%;
}
.body-pick:hover { background: var(--panel-2); }
.body-pick[aria-pressed="true"] { border-color: var(--accent-strong); box-shadow: 0 0 0 1px var(--accent-strong) inset; }
.body-pick__swatch { flex: 0 0 auto; width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--border-strong); }
.body-pick__name { flex: 1 1 auto; font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.body-pick__meta { flex: 0 0 auto; font-family: var(--font-mono); font-size: 12px; color: var(--text-faint); }

/* --- challenge --------------------------------------------------------- */

.challenge { display: flex; flex-direction: column; gap: var(--space-3); }
.challenge__brief { font-size: 14px; max-width: 68ch; margin: 0; }
.challenge__predict { display: flex; gap: var(--space-2); align-items: flex-end; flex-wrap: wrap; }
.challenge__predict .field { flex: 1 1 200px; margin: 0; }
.challenge__verdict { display: flex; flex-direction: column; gap: var(--space-2); }

/* --- toast ------------------------------------------------------------- */

.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  z-index: 400;
  padding: var(--space-2) var(--space-4);
  border-radius: 999px;
  background: var(--text);
  color: var(--bg);
  box-shadow: var(--shadow-lg);
  font-size: 13px;
  max-width: calc(100vw - 32px);
  text-align: center;
}

/* --- modal ------------------------------------------------------------- */

.modal-backdrop {
  position: fixed; inset: 0; z-index: 350;
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4);
  background: rgb(0 0 0 / 45%);
}
.modal {
  width: min(620px, 100%);
  max-height: min(84vh, 720px);
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-5);
}
.modal__title { margin: 0 0 var(--space-3); font-size: 17px; }
.modal__row { display: flex; gap: var(--space-2); margin-top: var(--space-4); flex-wrap: wrap; }

/* --- the mode bar ------------------------------------------------------ *
 * Its own row, directly under the wordmark and directly above the steps it
 * governs. Sharing a row with the steps made it read as a filter on them.
 *
 * The sentence beside the chips is the *current* level's, not a description
 * of the control: a reader wants to know what they are looking at.        */

.modebar-host {
  display: flex; align-items: center; gap: var(--space-3);
  flex-wrap: wrap;
}
.modebar { display: flex; gap: var(--space-1); flex: 0 0 auto; }
.modebar__chip { font-size: 12px; padding: 4px var(--space-3); }
.modebar__hint {
  flex: 1 1 240px; min-width: 0;
  font-size: 12px; line-height: 1.4;
  color: var(--text-faint);
}

/* On a phone the sentence drops under the chips rather than squeezing them. */
@media (max-width: 640px) {
  .modebar { flex: 1 1 100%; }
  .modebar__chip { flex: 1 1 0; }
  .modebar__hint { flex: 1 1 100%; }
}

/* --- the section lock -------------------------------------------------- *
 * One panel open at a time is right almost always and wrong exactly when
 * somebody is comparing two things. Rather than weaken the default, let a
 * reader pin the panel they want kept in view.                            */

.section__name { flex: 0 1 auto; min-width: 0; }

.section__lock {
  flex: 0 0 auto;
  margin-left: auto;
  width: 24px; height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
}
.section__lock:hover { color: var(--text); background: var(--panel-3); }
.section__lock:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 1px; }
.section__lock[aria-pressed="true"] { color: var(--accent-strong); }

/* The chevron is drawn by `.section__title::after` and has `margin-left:auto`
   to push itself right. With a lock beside it, the lock takes that job. */
.section__title:has(.section__lock)::after { margin-left: var(--space-2); }

/* --- the stepper ------------------------------------------------------- *
 * Eight steps, all of them reachable at any time. Nothing here is unlocked
 * and nothing is a reward — going back to look at the push again with the
 * friction still set up is a reasonable thing to want.                     */

.stepper {
  display: flex; gap: var(--space-1);
  padding: var(--space-1);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow-x: auto;
  scrollbar-width: thin;
}

/* Grow to fill, never shrink below the label: eight labels squashed onto one
   row sit on top of each other, which looks like a font problem and is a flex
   problem.                                              pitfalls.md #2       */
.stepper__step {
  flex: 1 0 auto;
  display: flex; align-items: center; gap: var(--space-2);
  min-height: 36px;
  padding: 6px var(--space-3);
  font: inherit; font-weight: 600;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  white-space: nowrap;
}
.stepper__step:hover { background: var(--panel-3); color: var(--text-dim); }
.stepper__step.is-done { color: var(--text-dim); }
.stepper__step.is-current {
  background: var(--panel);
  border-color: var(--border);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}

.stepper__n {
  flex: 0 0 auto;
  width: 19px; height: 19px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--panel-3);
  color: var(--text-faint);
  font-size: 11px; font-weight: 700;
}
.stepper__step.is-current .stepper__n { background: var(--accent-strong); color: var(--accent-ink); }
.stepper__step.is-done .stepper__n { background: var(--accent-soft); color: var(--accent-strong); }

.prompt__nav { display: flex; gap: var(--space-2); margin-top: var(--space-3); flex-wrap: wrap; }

/* --- the arrow picker -------------------------------------------------- *
 * Sits directly above the drawing, because it is a way of looking at the
 * drawing rather than a setting.                                           */

.vectors {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-3);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.vectors__head { display: flex; align-items: center; gap: var(--space-2); }
.vectors__title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-faint);
}
.vectors__group { display: flex; align-items: flex-start; gap: var(--space-3); flex-wrap: wrap; }
.vectors__label {
  flex: 0 0 52px;
  font-size: 11px; font-weight: 600; color: var(--text-faint);
  padding-top: 5px;
}
.vectors__chips { display: flex; flex-wrap: wrap; gap: var(--space-1); flex: 1 1 auto; }

/* A chip that carries the arrow's own colour, so the picker and the drawing
   cannot end up describing different things. */
.vchip {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font: inherit; font-size: 12px;
  padding: 4px var(--space-3) 4px var(--space-2);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--panel);
  color: var(--text-faint);
  cursor: pointer;
}
.vchip:hover { background: var(--panel-2); }
.vchip__key {
  width: 12px; height: 3px; border-radius: 2px;
  background: var(--vchip, var(--accent));
  opacity: 0.35;
}
.vchip[aria-pressed="true"] {
  border-color: var(--vchip, var(--accent-strong));
  color: var(--text);
  font-weight: 600;
}
.vchip[aria-pressed="true"] .vchip__key { opacity: 1; height: 4px; }

@media (max-width: 640px) {
  .vectors__label { flex-basis: 100%; padding-top: 0; }
}


/* ------------------------------------------------------------------------
 * The object list, the drawing tools and the driving controls.
 *
 * These are the parts of the sidebar that hold a variable number of things,
 * which is where a layout usually gives way: twenty rows of controls has to
 * stay as readable as one, and on a 320px phone as on a desktop.
 * ---------------------------------------------------------------------- */

.objects {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.object-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel-2);
}

.object-row.is-selected {
  border-color: var(--accent-strong);
  box-shadow: inset 0 0 0 1px var(--accent-strong);
}

.object-row__swatch {
  width: 14px;
  height: 14px;
  border-radius: 4px;
  border: 1px solid var(--body-ink);
  flex: 0 0 auto;
}

.object-row__name {
  font-size: 12px;
  font-weight: 600;
  /* The name is the flexible column, and it is the one that must be allowed to
     shrink — otherwise the delete button is pushed off the edge on a phone. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.object-row__meta {
  display: block;
  font-weight: 400;
  color: var(--text-dim);
  font-size: 11px;
}

/* The full editor for whichever object is selected. */
.object-edit {
  padding: var(--space-2) 0 0;
  border-top: 1px dashed var(--border);
  margin-top: var(--space-2);
}

.tool-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}

.tool-row .btn {
  /* Never shrink below the label: a flex row of buttons compresses instead of
     wrapping unless each one is told not to. pitfalls.md #2. */
  flex: 0 1 auto;
}

.btn.is-armed {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
  color: var(--accent-ink);
}

/* While a wall is being drawn the canvas is a drawing surface, and it should
   say so with the cursor rather than only in a hint nobody reads. */
.viewport__stage.is-drawing svg { cursor: crosshair; }
.viewport__stage.is-driving svg { cursor: grab; }

.scene__walls line { pointer-events: none; }

.wall-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  font-size: 11px;
  color: var(--text-dim);
}

.wall-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 6px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel-2);
}

/* A button that reads as text: used where the control is the label itself, as
   in the object list, where a full button per row would be a wall of chrome. */
.link-btn {
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.link-btn:hover { color: var(--accent-strong); }

.link-btn:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Two controls side by side where they are a pair — an x and a y. Collapses to
   one column early, because two sliders at 160px each are two unusable sliders. */
.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-2);
}


/* ------------------------------------------------------------------------
 * Measurements: everything the experiment tells you back.
 *
 * It lives in the viewport rather than the sidebar because the sidebar is for
 * things you change. A readout at the top of a column of controls means going
 * past a control to read a number, and past a number to reach a control.
 * ---------------------------------------------------------------------- */

.measurements {
  margin-top: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
}

.measurements__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
}

.measurements__title {
  margin: 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.measurements__note {
  /* Allowed to shrink and wrap rather than push the title out of the row. */
  flex: 1 1 260px;
  min-width: 0;
  font-size: 11px;
  color: var(--text-faint);
}

.measurements__detail { margin-top: var(--space-3); }

/* ------------------------------------------------------------------------
 * A slider's value, which is also a field you can type into.
 *
 * It has to read as a number and behave as a control, so it is bare until it
 * is hovered or focused. Sized in ch so it does not jump width as the digits
 * change under a dragging thumb.
 * ---------------------------------------------------------------------- */

.value--typed {
  width: 11ch;
  min-width: 0;
  padding: 1px 4px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: 12px;
  text-align: right;
  cursor: text;
}

.value--typed:hover {
  border-color: var(--border);
  background: var(--panel-2);
}

.value--typed:focus {
  outline: none;
  border-color: var(--accent-strong);
  background: var(--panel);
  color: var(--text);
}

.value--typed.input--invalid { border-color: var(--danger); color: var(--danger); }

/* ------------------------------------------------------------------------
 * The drawing as something you can select.
 *
 * At the last step the arrow keys have to belong either to the page or to the
 * object, and there is no way to guess which. Selecting the drawing is how you
 * say — so it has to be obvious that it is selected.
 * ---------------------------------------------------------------------- */

.viewport__stage { border-radius: var(--radius); }

.viewport__stage:focus { outline: none; }

.viewport__stage.is-engaged {
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--accent-soft);
}

.viewport__stage[tabindex="0"]:not(.is-engaged) {
  cursor: pointer;
}

/* Panning: the drawing becomes something you grab. */
.viewport__stage.is-panning svg { cursor: grab; }
.viewport__stage.is-panning:active svg { cursor: grabbing; }

/* ------------------------------------------------------------------------
 * An icon button: a disc with one glyph in it.
 *
 * For controls whose meaning is carried by the title and the accessible name
 * rather than by a word on the face — the theme cycle is the only one so far.
 * Sized from the same minimum as the other header buttons so the row stays on
 * one baseline.
 * ---------------------------------------------------------------------- */
.btn--icon {
  width: 32px;
  min-width: 32px;
  height: 32px;
  min-height: 32px;
  padding: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

.btn--icon .btn__glyph {
  font-size: 15px;
  line-height: 1;
  /* The glyphs are ◐ ○ ● — centring them optically needs no nudge, but they
     must not inherit the letter-spacing the button text uses. */
  letter-spacing: 0;
}

/*
 * The arrow filter and the view controls share one row: filter left, view
 * right. They stack on a narrow screen rather than squeezing, because four
 * buttons and a long label do not fit across a phone.
 */
.vectors__foot {
  margin-top: var(--space-2);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.vectors__view {
  margin-left: auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
@media (max-width: 640px) {
  .vectors__view { margin-left: 0; }
}

/* The curve slider sits inside the wall chip, short enough to keep one row. */
.wall-chip__curve {
  width: 84px;
  margin: 0 var(--space-1);
  accent-color: var(--wall);
}

/*
 * A fold inside a panel. Deliberately quieter than `.section`: no border along
 * the bottom, a smaller label, and indented just enough to read as belonging to
 * the panel above it rather than as another panel.
 */
.subsection {
  margin-top: var(--space-3);
  border-top: 1px solid var(--border);
}
.subsection__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-faint);
  cursor: pointer;
  list-style: none;
}
.subsection__title::-webkit-details-marker { display: none; }
.subsection__title::after {
  content: '';
  width: 6px;
  height: 6px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--motion-fast, 120ms) ease;
}
.subsection[open] > .subsection__title::after { transform: rotate(45deg) translate(-1px, -1px); }
.subsection__title:hover { color: var(--text-dim); }
.subsection__body { padding-bottom: var(--space-2); }

/* ------------------------------------------------ prepared experiments -- */

/*
 * The shelf. A card is a picture of an experiment and three lines about it, so
 * the still is given the room and the text is kept to what fits under it.
 */
.gallery { display: flex; flex-direction: column; gap: var(--space-4); }
.gallery__note {
  margin: 0;
  max-width: 62ch;
  color: var(--text-dim);
  font-size: 0.92rem;
  line-height: 1.5;
}
.gallery__grid {
  display: grid;
  /* As many as fit, never narrower than a still can be read at. */
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-4);
}
.gallery__card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.gallery__still {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) - 2px);
  overflow: hidden;
  /* The scene draws at a fixed viewBox, so it scales to whatever the card is. */
  aspect-ratio: 880 / 460;
}
.gallery__still svg { display: block; width: 100%; height: 100%; }
.gallery__missing {
  display: grid;
  place-items: center;
  height: 100%;
  color: var(--text-faint);
  font-size: 0.85rem;
}
.gallery__text { display: flex; flex-direction: column; gap: var(--space-1); }
.gallery__name { margin: 0; font-size: 1rem; font-weight: 650; }
.gallery__blurb { margin: 0; color: var(--text-dim); font-size: 0.9rem; line-height: 1.45; }
.gallery__where {
  margin: 0;
  color: var(--text-faint);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.gallery__go { margin-top: auto; }

/*
 * The shelf's own tab: at the end of the row, and unnumbered, which is what
 * says it is not another step to walk through.
 */
.stepper__step--aside { margin-left: var(--space-3); }
.stepper__step--aside::before {
  content: '';
  align-self: stretch;
  width: 1px;
  margin-right: var(--space-3);
  background: var(--border);
}

/* The rule marks a change of kind — steps, then the things that are not steps
   — so it is drawn once, before the first of them. A bar with a rule between
   every tab has said nothing. */
.stepper__step--aside + .stepper__step--aside { margin-left: 0; }
.stepper__step--aside + .stepper__step--aside::before { display: none; }

/*
 * On a whole-page view, the bench is not merely empty — it is not there.
 *
 * Clearing the regions leaves their boxes behind: the drawing keeps its 300 px
 * and its border with nothing in it, which put a large white rectangle under
 * the cards. The stepper and the prompt stay, because they are how a reader
 * gets back.
 *
 * Written as "not the bench" rather than as a list of page names, so a page
 * added later is hidden correctly without anyone remembering this block.
 */
html:not([data-page='bench']) #vectors,
html:not([data-page='bench']) #stage,
html:not([data-page='bench']) #legend,
html:not([data-page='bench']) #transport,
html:not([data-page='bench']) #banners,
html:not([data-page='bench']) .viewport--more,
html:not([data-page='bench']) .sidebar { display: none; }

/*
 * The level chips govern the bench. On the shelf or in the guide there is
 * nothing for them to govern, and a dead control is worse than no control.
 *
 * `visibility`, not `display`: taking their box away hands the step bar their
 * width, which changes how far it can scroll — so a reader who had scrolled
 * right to reach "How to use" had their position clamped on the way in and
 * did not get it back on the way out. Hidden is enough; it also takes them out
 * of the tab order. A control disappearing must not move anything.
 */
html:not([data-page='bench']) .modebar-host { visibility: hidden; }

/* -------------------------------------------------- equation triangles -- */

.equation { padding: var(--space-3) 0; border-top: 1px solid var(--border); }
.equation:first-child { border-top: none; padding-top: 0; }
.equation__name { margin: 0 0 var(--space-1); font-size: 0.95rem; font-weight: 650; }
.equation__formula {
  margin: 0 0 var(--space-2);
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 0.9rem;
  color: var(--accent-strong);
}
.equation__plain { margin: var(--space-2) 0 0; line-height: 1.5; }
.equation__means { margin: var(--space-2) 0 0; padding-left: 1.1rem; line-height: 1.5; }
.equation__means li { margin-bottom: var(--space-1); }
.equation__misread { margin: var(--space-2) 0 0; color: var(--text-dim); line-height: 1.5; }

/*
 * The triangle is drawn once at 340×190 and scaled here, so its geometry is
 * arithmetic rather than guesswork at every size.
 */
.triangle { display: block; width: 100%; max-width: 340px; height: auto; margin: var(--space-2) 0; }
.triangle__outline { fill: none; stroke: var(--accent); stroke-width: 1.5; }
.triangle__divider { stroke: var(--accent); stroke-width: 1.5; }
.triangle__leader { stroke: var(--text-faint); stroke-width: 1; stroke-dasharray: 2 2; }
.triangle__symbol {
  fill: var(--accent-strong);
  font-size: 26px;
  font-weight: 700;
  font-family: var(--mono, ui-monospace, monospace);
}
.triangle__times { fill: var(--text-dim); font-size: 15px; }
.triangle__label { fill: var(--text); font-size: 12px; }
.triangle__unit { fill: var(--text-faint); font-size: 11px; }

/* --- the guide --------------------------------------------------------- *
 * One search over everything, then the three things a stuck reader wants:
 * the steps for a task, the answer to a question, and the features they would
 * never have found from a label.                                           */

.guide { display: flex; flex-direction: column; gap: var(--space-5); }

.guide__searchbar { display: flex; flex-direction: column; gap: var(--space-2); }
.guide__search { font-size: 15px; padding: var(--space-3); }
.guide__count { margin: 0; font-size: 12px; color: var(--text-faint); }

.guide__block { display: flex; flex-direction: column; gap: var(--space-3); }
.guide__heading {
  margin: 0;
  font-size: 13px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--text-dim);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border);
}
.guide__note { margin: 0; max-width: 62ch; font-size: 0.92rem; color: var(--text-dim); }

/* Numbered, because a task is an order and a bullet does not say so. */
.guide__steps {
  margin: 0;
  padding-left: var(--space-5);
  display: flex; flex-direction: column; gap: var(--space-2);
  max-width: 68ch;
  line-height: 1.5;
}

.guide__faqs { display: flex; flex-direction: column; gap: var(--space-4); }
.faq { max-width: 70ch; }
.faq__q { font-weight: 600; margin-bottom: var(--space-1); }
.faq__a { margin: 0; color: var(--text-dim); line-height: 1.55; }

.guide__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-3);
}
.guide__tile {
  padding: var(--space-3);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.guide__tile-name { font-weight: 600; }
.guide__tile-where {
  margin-top: 2px;
  font-size: 11px; letter-spacing: 0.02em;
  color: var(--accent-strong);
}
.guide__tile-what {
  margin: var(--space-2) 0 0;
  font-size: 0.9rem; line-height: 1.5;
  color: var(--text-dim);
}

/* --- the welcome ------------------------------------------------------- *
 * Shown once, on the very first open, over a bench that already has a worked
 * example on it — so the first numbered action is a real try on a populated
 * screen rather than a blank form.                                         */

.welcome {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4);
  background: rgb(31 45 61 / 55%);
  overflow-y: auto;
}
.welcome__card {
  width: min(560px, 100%);
  max-height: 100%;
  overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--space-4);
  padding: var(--space-5);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.welcome__card:focus { outline: none; }
.welcome__title { margin: 0; font-size: 1.25rem; }
.welcome__lede { margin: 0; color: var(--text-dim); line-height: 1.55; }

.welcome__steps {
  margin: 0;
  padding-left: var(--space-5);
  display: flex; flex-direction: column; gap: var(--space-4);
}
.welcome__step { padding-left: var(--space-1); }
.welcome__step-title { font-weight: 600; }
.welcome__step-what {
  margin: var(--space-1) 0 var(--space-2);
  font-size: 0.92rem; line-height: 1.5;
  color: var(--text-dim);
}

.welcome__foot {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
}
.welcome__foot p { margin: 0; flex: 1 1 200px; font-size: 12px; }

@media (max-width: 640px) {
  .welcome { padding: var(--space-2); align-items: flex-start; }
  .welcome__card { padding: var(--space-4); gap: var(--space-3); }
}

/* --- the footer panels ------------------------------------------------- *
 * What's new, the licence, the imprint. The same card as the welcome,
 * because they are the same kind of thing: a short read that interrupts,
 * and gets out of the way on a click, the backdrop or Escape.            */

.panel__head {
  display: flex; align-items: flex-start; gap: var(--space-3);
}
.panel__head .welcome__title { flex: 1 1 auto; }
.panel__head .btn--icon { flex: 0 0 auto; }
.panel__head .btn__glyph { font-size: 18px; }

.panel__item + .panel__item { margin-top: var(--space-3); }
.panel__item-title { font-weight: 600; }
.panel__item-text {
  margin: var(--space-1) 0 0;
  color: var(--text-dim);
  line-height: 1.55;
}

/* --- what Simple leaves out -------------------------------------------- *
 * The explanatory line under a control. A newcomer needs the control and its
 * name; a paragraph under every one of a dozen fields is what makes a panel
 * look like a manual, and it is the first thing that stops being read. The
 * sentences are unchanged at Advanced, where somebody is asking *why*.
 *
 * Done here rather than at thirty call sites, and it keeps them on the
 * printed sheet, which is where a reader does want the prose.             */

html[data-level='simple'] .field__hint { display: none; }

/* Printing is not the screen: a sheet is read away from the app, so it
   carries the explanations whatever the level was on screen. */
@media print {
  html[data-level='simple'] .field__hint { display: block; }
}

/* --- dismissing a banner ----------------------------------------------- *
 * A message with no way to close it is furniture: it sits above the drawing
 * for the rest of the session whether or not it has been read, and on a step
 * with two of them it is most of the screen.                              */

/*
 * One line until asked.
 *
 * Every banner is a sentence that says the thing, then a paragraph explaining
 * it. On a step with two of them the paragraphs were most of the screen above
 * the drawing, which is the wrong way round: the drawing is the app.
 */
.banner__text {
  flex: 1 1 auto; min-width: 0;
  font: inherit; color: inherit; text-align: left;
  padding: 0; border: none; background: transparent;
  cursor: pointer;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  overflow: hidden;
}
.banner__text[aria-expanded='true'] { -webkit-line-clamp: unset; overflow: visible; }
.banner__text:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* Paper has no clicks and plenty of room. */
@media print {
  .banner__text { -webkit-line-clamp: unset; overflow: visible; }
}
.banner__close {
  flex: 0 0 auto;
  width: 20px; height: 20px;
  margin: -2px -4px 0 0;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  font: inherit; font-size: 15px; line-height: 1;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  /* Inherits the banner's own colour, so it is never louder than the message
     it belongs to and needs no rule per severity. */
  color: inherit;
  opacity: 0.6;
  cursor: pointer;
}
.banner__close:hover { opacity: 1; background: rgb(0 0 0 / 8%); }
.banner__close:focus-visible { opacity: 1; outline: 2px solid currentColor; outline-offset: 1px; }

/* Nothing to press on paper. */
@media print { .banner__close { display: none; } }

/* --- what you have found ----------------------------------------------- *
 * The card that says you found something, and the list of what is left.
 *
 * The card is not a modal on purpose: whatever the reader was doing when they
 * found it is the thing that found it, and stopping the bench to hand out a
 * badge takes them out of the moment the badge is about.                   */

.unlock {
  position: fixed;
  left: var(--space-4); bottom: var(--space-4);
  z-index: 55;
  width: min(360px, calc(100vw - var(--space-5)));
  display: flex; align-items: flex-start; gap: var(--space-2);
  padding: var(--space-3);
  background: var(--panel);
  border: 1px solid var(--accent-strong);
  border-left-width: 3px;
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.unlock__body {
  flex: 1 1 auto; min-width: 0;
  font: inherit; color: inherit; text-align: left;
  padding: 0; border: none; background: transparent; cursor: pointer;
}
.unlock__eyebrow {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--accent-strong);
}
.unlock__name { margin-top: 2px; font-weight: 600; }
.unlock__what {
  margin: var(--space-1) 0 0;
  font-size: 0.9rem; line-height: 1.5;
  color: var(--text-dim);
}
.unlock__close {
  flex: 0 0 auto;
  width: 20px; height: 20px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0; font-size: 15px; line-height: 1;
  border: none; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-faint);
  cursor: pointer;
}
.unlock__close:hover { color: var(--text); background: var(--panel-3); }

@media (max-width: 640px) {
  .unlock { left: var(--space-2); right: var(--space-2); bottom: var(--space-2); width: auto; }
}
@media print { .unlock { display: none; } }

.found { display: flex; flex-direction: column; gap: var(--space-4); }
.found__count { margin: 0; font-size: 12px; color: var(--text-faint); }
.found__bar {
  height: 6px;
  background: var(--panel-3);
  border-radius: 999px;
  overflow: hidden;
}
.found__bar-fill { height: 100%; background: var(--accent-strong); }

.found__group { display: flex; flex-direction: column; gap: var(--space-3); }
.found__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-3);
}
.found__item {
  padding: var(--space-3);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  /* Unfound ones are quiet rather than hidden: the hint is the invitation. */
  opacity: 0.6;
}
.found__item.is-found { opacity: 1; border-color: var(--accent-strong); }
.found__name { font-weight: 600; }
.found__item:not(.is-found) .found__name { color: var(--text-faint); font-weight: 400; font-style: italic; }
.found__text {
  margin: var(--space-2) 0 0;
  font-size: 0.9rem; line-height: 1.5;
  color: var(--text-dim);
}

/* --- the questions ----------------------------------------------------- *
 * Guess first, then read. The options are live until one is pressed and the
 * reasoning only appears afterwards, because a reader handed the explanation
 * has no reason to go and look — and looking is the whole point.          */

.quiz__q + .quiz__q { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--border); }
.quiz__ask { margin: 0 0 var(--space-2); font-weight: 600; }

.quiz__options { display: flex; flex-direction: column; gap: var(--space-2); align-items: flex-start; }
.quiz__option {
  font: inherit; text-align: left;
  max-width: 62ch;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--panel-2);
  color: var(--text);
  cursor: pointer;
}
.quiz__option:hover:not(:disabled) { background: var(--panel-3); }
.quiz__option:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 1px; }
.quiz__option:disabled { cursor: default; }

/* Once answered: the right one is marked whether or not it was chosen, so a
   wrong guess still ends up looking at the right answer. */
.quiz__option.is-right { border-color: var(--ok); background: var(--ok-soft); color: var(--ok); font-weight: 600; }
.quiz__option.is-wrong { border-color: var(--danger); background: var(--danger-soft); color: var(--danger); }
.quiz__option:disabled:not(.is-right):not(.is-wrong) { opacity: 0.55; }

.quiz__why {
  display: none;
  margin: var(--space-3) 0 0;
  max-width: 68ch;
  line-height: 1.55;
  color: var(--text-dim);
}
.quiz__why.is-shown { display: block; }
