*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  font-family: Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--fg);
}

/* --- theme tokens ---------------------------------------------------------
 * Order matters. :root carries light, the prefers-color-scheme block flips it
 * for the first paint before JS runs, and body[data-theme] wins over both once
 * the player has an explicit preference.
 * ------------------------------------------------------------------------ */

:root {
  --hud-h: 48px;
  /* 200ms was ambiguous with "the click didn't register" at click speed. */
  --settle-ms: 450ms;

  --bg: #f3f3f1;
  --fg: #111;
  --hud-bg: rgba(255, 255, 255, 0.92);
  --hud-border: #ddd;
  --tile-bg: #fff;
  --tile-border: #8a8a8a;
  --tile-fg: #111;
  --armed: #7c3aed;
  --dev: #ea580c;
  --done: #2563eb;
  --done-fill: #dbeafe;
  --btn-bg: #f5f5f5;
  --btn-border: #bbb;
  --mm-bg: #e8e8e8;
  --mm-border: #bbb;
  --tip-bg: rgba(255, 255, 255, 0.96);
  --tip-border: #ccc;
  --shadow: rgba(0, 0, 0, 0.18);
  /* Settle: ink, not a fourth hue. The Three Signals Rule holds. */
  --settle: rgba(17, 17, 17, 0.72);
  /* Stacked-paper edges: nearest edge darkest, receding edges lighter. */
  --stack-1: rgba(0, 0, 0, 0.3);
  --stack-2: rgba(0, 0, 0, 0.255);
  --stack-3: rgba(0, 0, 0, 0.215);
  --stack-4: rgba(0, 0, 0, 0.18);
  --stack-5: rgba(0, 0, 0, 0.15);
  --stack-6: rgba(0, 0, 0, 0.125);
  --stack-7: rgba(0, 0, 0, 0.105);
  --done-1: rgba(37, 99, 235, 0.6);
  --done-2: rgba(37, 99, 235, 0.52);
  --done-3: rgba(37, 99, 235, 0.45);
  --done-4: rgba(37, 99, 235, 0.38);
  --done-5: rgba(37, 99, 235, 0.31);
  --done-6: rgba(37, 99, 235, 0.25);
  --done-7: rgba(37, 99, 235, 0.19);
  --done-ambient: rgba(37, 99, 235, 0.24);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #121212;
    --fg: #eee;
    --hud-bg: rgba(20, 20, 20, 0.92);
    --hud-border: #333;
    --tile-bg: #333;
    --tile-border: #7a7a7a;
    --tile-fg: #eee;
    --armed: #a78bfa;
    --dev: #fb923c;
    --done: #3b82f6;
    --done-fill: #1e3a5f;
    --btn-bg: #2a2a2a;
    --btn-border: #555;
    --mm-bg: #111;
    --mm-border: #444;
    --tip-bg: rgba(20, 20, 20, 0.96);
    --tip-border: #555;
    --shadow: rgba(0, 0, 0, 0.4);
    --settle: rgba(238, 238, 238, 0.72);
    --stack-1: rgba(255, 255, 255, 0.24);
    --stack-2: rgba(255, 255, 255, 0.205);
    --stack-3: rgba(255, 255, 255, 0.175);
    --stack-4: rgba(255, 255, 255, 0.148);
    --stack-5: rgba(255, 255, 255, 0.125);
    --stack-6: rgba(255, 255, 255, 0.105);
    --stack-7: rgba(255, 255, 255, 0.088);
    --done-1: rgba(59, 130, 246, 0.58);
    --done-2: rgba(59, 130, 246, 0.5);
    --done-3: rgba(59, 130, 246, 0.43);
    --done-4: rgba(59, 130, 246, 0.36);
    --done-5: rgba(59, 130, 246, 0.3);
    --done-6: rgba(59, 130, 246, 0.24);
    --done-7: rgba(59, 130, 246, 0.19);
    --done-ambient: rgba(59, 130, 246, 0.3);
  }
}

body[data-theme='light'] {
  --bg: #f3f3f1;
  --fg: #111;
  --hud-bg: rgba(255, 255, 255, 0.92);
  --hud-border: #ddd;
  --tile-bg: #fff;
  --tile-border: #8a8a8a;
  --tile-fg: #111;
  --armed: #7c3aed;
  --dev: #ea580c;
  --done: #2563eb;
  --done-fill: #dbeafe;
  --btn-bg: #f5f5f5;
  --btn-border: #bbb;
  --mm-bg: #e8e8e8;
  --mm-border: #bbb;
  --tip-bg: rgba(255, 255, 255, 0.96);
  --tip-border: #ccc;
  --shadow: rgba(0, 0, 0, 0.18);
  --settle: rgba(17, 17, 17, 0.72);
  --stack-1: rgba(0, 0, 0, 0.3);
  --stack-2: rgba(0, 0, 0, 0.255);
  --stack-3: rgba(0, 0, 0, 0.215);
  --stack-4: rgba(0, 0, 0, 0.18);
  --stack-5: rgba(0, 0, 0, 0.15);
  --stack-6: rgba(0, 0, 0, 0.125);
  --stack-7: rgba(0, 0, 0, 0.105);
  --done-1: rgba(37, 99, 235, 0.6);
  --done-2: rgba(37, 99, 235, 0.52);
  --done-3: rgba(37, 99, 235, 0.45);
  --done-4: rgba(37, 99, 235, 0.38);
  --done-5: rgba(37, 99, 235, 0.31);
  --done-6: rgba(37, 99, 235, 0.25);
  --done-7: rgba(37, 99, 235, 0.19);
  --done-ambient: rgba(37, 99, 235, 0.24);
}

body[data-theme='dark'] {
  --bg: #121212;
  --fg: #eee;
  --hud-bg: rgba(20, 20, 20, 0.92);
  --hud-border: #333;
  --tile-bg: #333;
  --tile-border: #7a7a7a;
  --tile-fg: #eee;
  --armed: #a78bfa;
  --dev: #fb923c;
  --done: #3b82f6;
  --done-fill: #1e3a5f;
  --btn-bg: #2a2a2a;
  --btn-border: #555;
  --mm-bg: #111;
  --mm-border: #444;
  --tip-bg: rgba(20, 20, 20, 0.96);
  --tip-border: #555;
  --shadow: rgba(0, 0, 0, 0.4);
  --settle: rgba(238, 238, 238, 0.72);
  /* Dark: edges are card-material, so they lighten rather than darken. */
  --stack-1: rgba(255, 255, 255, 0.24);
  --stack-2: rgba(255, 255, 255, 0.205);
  --stack-3: rgba(255, 255, 255, 0.175);
  --stack-4: rgba(255, 255, 255, 0.148);
  --stack-5: rgba(255, 255, 255, 0.125);
  --stack-6: rgba(255, 255, 255, 0.105);
  --stack-7: rgba(255, 255, 255, 0.088);
  --done-1: rgba(59, 130, 246, 0.58);
  --done-2: rgba(59, 130, 246, 0.5);
  --done-3: rgba(59, 130, 246, 0.43);
  --done-4: rgba(59, 130, 246, 0.36);
  --done-5: rgba(59, 130, 246, 0.3);
  --done-6: rgba(59, 130, 246, 0.24);
  --done-7: rgba(59, 130, 246, 0.19);
  --done-ambient: rgba(59, 130, 246, 0.3);
}

/* --- a11y utilities ------------------------------------------------------ */

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

.skip-link {
  position: fixed;
  top: 6px;
  left: 6px;
  z-index: 200;
  padding: 10px 14px;
  border: 1px solid var(--btn-border);
  border-radius: 4px;
  background: var(--btn-bg);
  color: var(--fg);
  font-size: 13px;
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: translateY(0);
}

/* --- HUD ----------------------------------------------------------------- */

#hud {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 40;
  height: var(--hud-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 14px;
  background: var(--hud-bg);
  border-bottom: 1px solid var(--hud-border);
  backdrop-filter: blur(6px);
  user-select: none;
}

/* The value speaks in the label's old uppercase voice, so the readout still
   reads as status, not as a search field. (The "In hand:" prefix survives
   sr-only for screen readers.) */
.armed-readout {
  flex: 1;
  min-width: 0;
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 14px;
}

.readout-value {
  min-width: 0;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Mismatch acknowledgement, at the element the driver is already watching.
   Ink at full strength — no new hue, no motion, nothing that scolds. */
.armed-readout.is-flash .readout-value {
  font-weight: 600;
  opacity: 1;
}

.armed-readout.is-idle .readout-value {
  font-weight: 400;
  /* 0.62 clears 4.5:1 against the chrome surface; 0.55 measured 4.16:1. */
  opacity: 0.62;
}

.hud-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

.stats {
  font-size: 13px;
  white-space: nowrap;
}

.stats--short,
.btn-label--short {
  display: none;
}

/* --- filed disclosure ----------------------------------------------------
 * The count is a summary; the names are behind it. Styled as chrome, not as a
 * control — it must not read as more important than the board.
 * ------------------------------------------------------------------------ */

.filed {
  position: relative;
  flex-shrink: 0;
}

.filed__summary {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 4px;
  border-radius: 4px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.filed__summary::-webkit-details-marker {
  display: none;
}

.filed__summary:focus-visible {
  outline: 2px solid var(--armed);
  outline-offset: 2px;
}

/* A caret rather than a glyph: the system has no icon set. */
.filed__caret {
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: 0.62;
}

.filed[open] .filed__caret {
  transform: rotate(180deg);
}

.filed__panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 60;
  width: max-content;
  max-width: min(420px, calc(100vw - 24px));
  max-height: min(60vh, 420px);
  overflow: auto;
  overscroll-behavior: contain;
  padding: 8px;
  /* Card stock, opaque — not the translucent Chrome Surface. Twenty-two
     names have to be readable over whatever board sits behind them, and a
     drawer's index card is the right object for a list of filed drawers. */
  background: var(--tile-bg);
  border: 1px solid var(--tip-border);
  border-radius: 6px;
  box-shadow: 0 8px 24px var(--shadow);
}

/* A closed <details> still reports a layout box in Chrome; take it out. */
.filed:not([open]) .filed__panel {
  display: none;
}

.filed__empty {
  margin: 0;
  padding: 4px 6px;
  font-size: 13px;
  opacity: 0.62;
}

/* The mistake tally, with the word the compressed bar has no room for. */
.filed__misses {
  margin: 0 0 6px;
  padding: 4px 6px;
  border-bottom: 1px solid var(--hud-border);
  font-size: 13px;
  opacity: 0.62;
}

.filed__empty[hidden] {
  display: none;
}

.filed__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px 8px;
}

.filed__item {
  display: block;
  width: 100%;
  padding: 5px 6px;
  border: 0;
  border-radius: 3px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}

.filed__item:hover {
  background: var(--btn-bg);
}

.filed__item:focus-visible {
  outline: 2px solid var(--armed);
  outline-offset: -2px;
}

.btn {
  font-family: inherit;
  font-size: 13px;
  padding: 6px 12px;
  border: 1px solid var(--btn-border);
  border-radius: 4px;
  background: var(--btn-bg);
  color: var(--fg);
  cursor: pointer;
}

.btn--quiet {
  font-size: 12px;
  padding: 4px 8px;
  background: transparent;
  opacity: 0.75;
}

/* 36, not 32: the `?` was the smallest fine-pointer target in the product and
   the only glyph-only control. 44 under a coarse pointer, below. */
.btn--icon {
  width: 36px;
  height: 36px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-weight: 600;
  line-height: 1;
}

/* `opacity: 1` alone only did anything for .btn--quiet; every other control
   had no hover state at all. The outline sharpens to Ink — no fill shift, no
   lift, no colour change, so The Flat Rest Rule is untouched. */
.btn:hover {
  opacity: 1;
  border-color: var(--fg);
}

/* Chrome controls had no focus rule at all and fell back to the UA ring —
   which is blue, the hue this system reserves for "filed". */
.btn:focus-visible,
.skip-link:focus-visible {
  outline: 2px solid var(--armed);
  outline-offset: 2px;
}

/* --- board --------------------------------------------------------------- */

/* The scroll position IS the camera. One mechanism, so keyboard focus,
   touch drag, wheel and the minimap can never disagree.
   The field runs to the bottom of the window; the minimap floats over it and
   the board carries the panel's footprint as scroll padding (see syncBoardSize)
   so anything it covers can always be scrolled clear. */
#viewport {
  position: fixed;
  inset: var(--hud-h) 0 0 0;
  overflow: auto;
  overscroll-behavior: contain;
  touch-action: pan-x pan-y;
  cursor: default;
}

#board {
  position: relative;
  outline: none;
}

.tile {
  position: absolute;
  /* Resolved once at boot from the content's longest unbroken token; app.js
     also writes it per tile, so this is the pre-script value. */
  width: var(--col-w, 140px);
  margin: 0;
  padding: 12px;
  border: 1.5px solid var(--tile-border);
  border-radius: 2px;
  background: var(--tile-bg);
  color: var(--tile-fg);
  font: inherit;
  font-size: 13px;
  line-height: 1.35;
  text-align: center;
  overflow: hidden;
  cursor: pointer;
  user-select: none;
  appearance: none;
  /* Short tiles top-align in taller row bands via absolute y = row top. */
  display: flex;
  align-items: center;
  justify-content: center;
  transition:
    box-shadow 200ms ease-out,
    border-color var(--settle-ms) ease-out,
    /* Vertical band collapse, played as a FLIP from app.js. Transform only:
       400 cards can move at once and none of them may touch layout. */
    transform 180ms ease-out;
}

/*
 * Stack depth reads as physical paper thickness: hard, unblurred, stepped
 * offsets on both axes, so a pile reads as a stack of cards fanned down and
 * right rather than as a rule beneath a single card. Buckets, not per-member
 * steps — the point is reading "roughly how deep" across the board.
 */
.tile--d2 {
  box-shadow: 2px 2px 0 var(--stack-1);
}

.tile--d3 {
  box-shadow:
    2px 2px 0 var(--stack-1),
    4px 4px 0 var(--stack-2);
}

.tile--d4 {
  box-shadow:
    2px 2px 0 var(--stack-1),
    4px 4px 0 var(--stack-2),
    6px 6px 0 var(--stack-3);
}

.tile--d5 {
  box-shadow:
    2px 2px 0 var(--stack-1),
    4px 4px 0 var(--stack-2),
    6px 6px 0 var(--stack-3),
    8px 8px 0 var(--stack-4);
}

.tile--d6 {
  box-shadow:
    2px 2px 0 var(--stack-1),
    4px 4px 0 var(--stack-2),
    6px 6px 0 var(--stack-3),
    8px 8px 0 var(--stack-4),
    10px 10px 0 var(--stack-5);
}

.tile--d7 {
  box-shadow:
    2px 2px 0 var(--stack-1),
    4px 4px 0 var(--stack-2),
    6px 6px 0 var(--stack-3),
    8px 8px 0 var(--stack-4),
    10px 10px 0 var(--stack-5),
    12px 12px 0 var(--stack-6);
}

/*
 * Pre-completion (20–21 of 22). The deepest stack the board can carry, plus
 * the one non-shadow cue: the card's own hairline thickens to 2px — the same
 * weight a filed card sits at, in the card's own edge colour rather than a
 * fourth hue. "One or two away" without printing a number.
 */
.tile--d8 {
  border-width: 2px;
  box-shadow:
    2px 2px 0 var(--stack-1),
    4px 4px 0 var(--stack-2),
    6px 6px 0 var(--stack-3),
    8px 8px 0 var(--stack-4),
    10px 10px 0 var(--stack-5),
    12px 12px 0 var(--stack-6),
    14px 14px 0 var(--stack-7);
}

.tile:focus-visible {
  outline: 2px solid var(--armed);
  outline-offset: 2px;
}

.tile__label {
  display: block;
  width: 100%;
  overflow: hidden;
  /* Wrap at spaces only — never split an unbroken token. */
  word-break: keep-all;
  overflow-wrap: normal;
  hyphens: none;
}

.tile--armed {
  border-color: var(--armed);
  border-width: 2.5px;
  outline: 1px solid var(--armed);
}

/* Registered, not a match. Neutral ink, no motion on the card, no new hue —
   this is response, never punishment. */
.tile--mismatch {
  border-color: var(--settle);
  border-width: 2.5px;
}

.tile--dev {
  border-color: var(--dev);
  border-width: 2.5px;
  outline: 1px solid var(--dev);
}

.tile--completed {
  background: var(--done-fill);
  border-color: var(--done);
  border-width: 2px;
  /* Terminal state: the deepest stack, tinted, plus the one soft shadow
     the board permits. Same seven-step ramp as .tile--d8, in blue. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    2px 2px 0 var(--done-1),
    4px 4px 0 var(--done-2),
    6px 6px 0 var(--done-3),
    8px 8px 0 var(--done-4),
    10px 10px 0 var(--done-5),
    12px 12px 0 var(--done-6),
    14px 14px 0 var(--done-7),
    8px 14px 20px var(--done-ambient);
  cursor: default;
  animation: done-in 280ms ease-out;
}

@keyframes done-in {
  from {
    transform: scale(0.96);
  }
  to {
    transform: scale(1);
  }
}

.tile--just-merged .tile__label {
  animation: merge-pop 180ms ease-out;
}

@keyframes merge-pop {
  from {
    opacity: 0.35;
    transform: scale(0.97);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* --- minimap ------------------------------------------------------------- */

/* One bounded Chrome Surface holding both the controls and the canvas, so the
   instrument is a single opaque object rather than loose labels over the field.
   It does float over live tiles; the board reserves its footprint as scroll
   padding so anything under it can be scrolled clear. */
#minimap-wrap {
  position: fixed;
  right: 12px;
  bottom: 12px;
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  padding: 6px;
  background: var(--hud-bg);
  border: 1px solid var(--hud-border);
  border-radius: 6px;
  backdrop-filter: blur(6px);
}

.minimap-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
}

#minimap {
  display: block;
  border: 1px solid var(--mm-border);
  border-radius: 4px;
  cursor: pointer;
  background: var(--mm-bg);
}

#minimap:focus-visible {
  outline: 2px solid var(--armed);
  outline-offset: 2px;
}

#minimap[hidden] {
  display: none;
}

/* --- pan hint ------------------------------------------------------------ */

/* Present before the first pan, gone the moment one lands. */
.pan-hint {
  position: fixed;
  left: 50%;
  bottom: 20px;
  z-index: 35;
  transform: translateX(-50%);
  padding: 8px 14px;
  max-width: calc(100vw - 24px);
  background: var(--hud-bg);
  border: 1px solid var(--hud-border);
  border-radius: 6px;
  backdrop-filter: blur(6px);
  font-size: 13px;
  white-space: nowrap;
  pointer-events: none;
}

.pan-hint[hidden] {
  display: none;
}

/* --- tooltip ------------------------------------------------------------- */

#tooltip {
  position: fixed;
  z-index: 80;
  max-width: 320px;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--tip-bg);
  color: var(--fg);
  border: 1px solid var(--tip-border);
  box-shadow: 0 8px 24px var(--shadow);
  font-size: 13px;
  line-height: 1.35;
  pointer-events: none;
  white-space: normal;
  word-break: break-word;
}

#tooltip[hidden] {
  display: none;
}

/* --- modals -------------------------------------------------------------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.modal[hidden] {
  display: none;
}

.modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
}

.modal__panel {
  position: relative;
  z-index: 1;
  width: min(640px, 100%);
  max-height: min(90vh, 640px);
  display: flex;
  flex-direction: column;
  background: var(--hud-bg);
  color: var(--fg);
  border: 1px solid var(--hud-border);
  border-radius: 6px;
  box-shadow: 0 16px 48px var(--shadow);
}

.modal__panel--intro,
.modal__panel--confirm {
  width: min(420px, 100%);
}

.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px 0;
  flex-shrink: 0;
}

.modal__header h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
}

.modal__body {
  padding: 12px 16px 8px;
  overflow: auto;
  font-size: 14px;
  line-height: 1.45;
}

.modal__body h2 {
  margin: 4px 0 10px;
  font-size: 18px;
  font-weight: 700;
}

.modal__body p {
  margin: 0 0 12px;
}

/* The one rule that unlocks everything. Set at Title size, not Body — it is
   the only thing on a cold arrival that has to be read. */
.intro-rule {
  font-size: 18px;
  font-weight: 700;
  line-height: 1.3;
}

.intro-sub {
  opacity: 0.7;
}

.modal__body h3 {
  margin: 14px 0 6px;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.7;
}

.modal__body ul {
  margin: 0;
  padding-left: 1.15em;
}

.modal__body li {
  margin: 0 0 6px;
}

.modal__body li:last-child {
  margin-bottom: 0;
}

.modal__body kbd {
  font-family: inherit;
  font-size: 0.92em;
  padding: 1px 5px;
  border: 1px solid var(--btn-border);
  border-radius: 3px;
  background: var(--btn-bg);
}

.modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 8px 16px 14px;
  flex-shrink: 0;
}

body.is-panning #viewport {
  cursor: grabbing;
}

body.modal-open {
  overflow: hidden;
}

/* --- reach --------------------------------------------------------------- */

/* Coarse pointers and narrow windows get real hit areas. Nothing in the
   product previously reached 44×44 in either dimension. */
@media (pointer: coarse), (max-width: 720px) {
  :root {
    --hud-h: 56px;
  }

  .btn {
    min-height: 44px;
    min-width: 44px;
    padding: 6px 14px;
  }

  .btn--quiet {
    padding: 6px 10px;
  }

  .btn--icon {
    width: 44px;
    height: 44px;
  }

  .minimap-actions {
    gap: 8px;
  }

  .filed__summary,
  .filed__item {
    min-height: 44px;
  }

  .filed__summary {
    padding: 6px 8px;
  }

  .filed__item {
    display: flex;
    align-items: center;
  }
}

/* Narrow HUD: compress the labels, keep the readout, keep theme access. */
@media (max-width: 720px) {
  #hud {
    gap: 8px;
    padding: 0 10px;
  }

  .hud-actions {
    gap: 6px;
  }

  .stats--full {
    display: none;
  }

  .stats--short {
    display: inline;
  }

  .btn-label--full {
    display: none;
  }

  .btn-label--short {
    display: inline;
  }

  /* The summary sits mid-bar, so a right-anchored popover runs off the left
     edge below ~420px. Pin it to the window instead. */
  .filed__panel {
    position: fixed;
    top: calc(var(--hud-h) + 6px);
    left: 10px;
    right: 10px;
    width: auto;
    max-width: none;
  }

  .filed__list {
    grid-template-columns: minmax(0, 1fr);
  }

  /* The hint shares the chrome band with the minimap panel, which is
     right-aligned; centred, it landed on the panel's controls at 390px. */
  .pan-hint {
    left: 10px;
    right: auto;
    transform: none;
    max-width: calc(100vw - 170px);
    white-space: normal;
    text-align: left;
  }
}

/* Stack depth is information, so the shadows stay; only the motion goes.
   The mismatch settle also stays — it is acknowledgement, not decoration. */
@media (prefers-reduced-motion: reduce) {
  /* Depth and the settle survive; only the motion goes. `playShifts()` also
     bails on this query, so a row collapse lands instantly rather than
     part-way through a transform. */
  .tile {
    transition: none;
    transform: none;
  }

  .tile--completed {
    animation: none;
  }

  .tile--just-merged .tile__label {
    animation: none;
  }

  .skip-link {
    transition: none;
  }
}

@media (max-width: 380px) {
  .btn {
    padding: 6px 10px;
  }

  .btn--quiet {
    font-size: 12px;
    padding: 6px 8px;
  }
}
