/* One stylesheet for the whole arena (design brief, scenarios.md section 5).
 *
 * The palette is three groups and the boundary between them is the point.
 * The board is the data: --felt, --disc-b, --disc-w and the line and rim that
 * go with them hold one value in every theme, because a physical board does
 * not change colour when the lights go on.  The felt sits between the discs
 * in luminance -- 4.4:1 to white, 4.1:1 to black -- so neither reads stronger
 * in a benchmark that measures which of them covered more of it.  The page is
 * only the surface a board is set down on, so --bg, the surfaces and the inks
 * are themed: dark by default, light for a lecture-room projector, written
 * twice because CSS cannot share a declaration block between a media query
 * and a plain selector.  --brass is the only interface colour, chosen because
 * no board carries it: nothing the page does can be mistaken for data.
 * Hierarchy is weight and space -- no tracked capitals, no monospace label;
 * mono is for a value someone copies.  A status chip always spells its word.
 */

:root {
  color-scheme: dark light;

  /* -- type: three voices ------------------------------------------- */
  /* No web fonts: the server may be on a LAN with no route out, so a font
     that is not on the machine is a font that never arrives. */
  --font-sans: "Century Gothic", "URW Gothic", "Avant Garde", Futura,
               "Trebuchet MS", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "DejaVu Sans Mono",
               "Liberation Mono", "Courier New", monospace;
  --fs-xs: 11px; --fs-sm: 12px; --fs-md: 13px; --fs-base: 15px;
  --fs-lg: 18px; --fs-xl: 24px; --fs-2xl: 32px;
  --fs-display: clamp(1.5rem, 7vw, 4rem);
  --lh-body: 1.6; --lh-tight: 1.1; --lh-snug: 1.4;
  --fw-normal: 400; --fw-semibold: 600; --fw-bold: 700;

  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 40px; --sp-8: 64px;
  --max-width: 1200px; --narrow: 800px; --prose: 72ch;
  --gutter: 24px; --board-size: 448px;

  --radius-xs: 3px; --radius-sm: 4px; --radius-input: 6px;
  --radius-panel: 10px; --radius-flyout: 14px;
  --radius-bezel-in: 16px; --radius-bezel-out: 20px; --radius-pill: 999px;

  --ease-pill: cubic-bezier(.22, 1, .36, 1);
  --dur-fast: .15s;

  /* -- the board's own colours --------------------------------------- */
  /* A physical board does not change colour when the lights go on, and
     neither does this one: --felt and the two discs are the same in every
     theme, because they are the data.  The felt sits between the discs in
     luminance on purpose -- 4.4:1 to white and 4.1:1 to black -- so neither
     colour reads stronger than the other in a benchmark that measures which
     of them covered more of the board. */
  --felt: #527a6b; --felt-line: #3f6255; --felt-dead: #35524a;
  --brass: #e0a03f; --brass-deep: #8a580c;
  /* Series colours for the curves.  Not board colours: a line on a chart is
     never a disc, so it may take a hue the board cannot. */
  --s-brass: #e0a03f; --s-teal: #3fb6a8; --s-indigo: #8c9af2;
  --s-clay: #e08b73; --s-moss: #a8cf5f; --s-plum: #d08ade;

  /* -- dark page (default) ------------------------------------------- */
  /* The page is the surface a board is set down on, not the board. */
  --bg: #16241f;
  --surface-1: #1d2f28;
  --surface-2: #24382f;
  --surface-3: #2d443a;
  --card: #1d2f28;
  --ink: #e9efe9; --ink-strong: #ffffff; --ink-2: #adbdb4;
  --ink-dim: #9ab0a6; --ink-faint: #859890;
  --rule: #24382f; --rule-soft: rgba(233, 239, 233, .16); --rule-strong: #3e5249;
  --hover: rgba(233, 239, 233, .06);
  --glass: rgba(22, 36, 31, .62);

  /* Brass is the only interface colour, and it is the one colour that never
     appears on a board -- so nothing the page does can be mistaken for data. */
  --accent: var(--brass);
  --accent-hover: #f0b661;
  --accent-soft: color-mix(in srgb, var(--brass) 16%, var(--bg));
  --accent-ink: #16241f;
  --attention: var(--brass); --attention-ink: var(--brass);
  --link: var(--ink); --link-hover: var(--brass);
  --ok: #63c98a; --warn: var(--brass); --bad: #f07a6a; --info: #6fb6f0;
  --host: var(--brass); --ta: #6fb6f0; --student: var(--ink-dim);

  --rank-1: var(--s-brass); --rank-2: var(--s-teal); --rank-3: var(--s-indigo);
  --rank-4: var(--s-clay); --rank-5: var(--s-moss); --rank-6: var(--s-plum);
  --rank-rest: #8fa29a;

  --axis: #6d817a; --grid: #2a4038;
  --tooltip-bg: rgba(10, 18, 15, .94); --tooltip-border: #3e5249;

  --screen: var(--felt); --screen-glow: rgba(0, 0, 0, .55);
  --board-line: var(--felt-line); --board-block: var(--felt-dead);
  --disc-b: #0a0a0a; --disc-w: #f4f4f1; --disc-rim: rgba(0, 0, 0, .45);
  --last-move: var(--brass); --flipped: rgba(224, 160, 63, .32);
  --shell-public: #3e5249; --shell-host: #6b4a12;
  --shell-base: var(--shell-public);
  --shell-hi: color-mix(in srgb, var(--shell-base) 75%, #fff 25%);
  --shell-lo: color-mix(in srgb, var(--shell-base) 70%, #000 30%);
  --shell-bezel: color-mix(in srgb, var(--shell-base) 55%, #000 45%);

  --chip-pass: #63c98a; --chip-fail: #f07a6a; --chip-queued: var(--brass);
  --chip-running: #6fb6f0; --chip-done: #63c98a; --chip-cancelled: var(--ink-dim);
}

/* -- light theme, for the OS preference ------------------------------- */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    /* The page only.  --felt, --disc-b, --disc-w, --board-line and --screen are
       deliberately absent: the board keeps its colours in both themes. */
    --bg: #e9eee9; --surface-1: #f6f8f5; --surface-2: #dfe6e0; --surface-3: #ced8d0;
    --card: #f6f8f5;
    --ink: #0f1d18; --ink-strong: #000000; --ink-2: #3a4d45; --ink-dim: #475a52;
    --ink-faint: #5c6f67; --rule: #ced8d0; --rule-soft: rgba(15, 29, 24, .18);
    --rule-strong: #b4c0b8; --hover: rgba(15, 29, 24, .05); --glass: rgba(233, 238, 233, .62);
    --accent: var(--brass-deep); --accent-hover: #6d4408;
    --accent-soft: color-mix(in srgb, var(--brass-deep) 12%, var(--bg));
    --accent-ink: #ffffff; --attention: var(--brass); --attention-ink: var(--brass-deep);
    --link: var(--ink); --link-hover: var(--brass-deep);
    --ok: #1d7a46; --warn: var(--brass-deep); --bad: #b02a1c; --info: #15629f;
    --host: var(--brass-deep); --ta: #15629f;
    --rank-1: #8a580c; --rank-2: #12726a; --rank-3: #3b4bb8; --rank-4: #a8402a;
    --rank-5: #4d6b14; --rank-6: #8a3a9c; --rank-rest: #55685f;
    --axis: #7d9189; --grid: #ced8d0;
    --tooltip-bg: rgba(246, 248, 245, .97); --tooltip-border: #b4c0b8;
    --screen-glow: rgba(15, 29, 24, .18);
    --last-move: var(--brass-deep); --flipped: rgba(138, 88, 12, .28);
    --shell-public: #b4c0b8; --shell-host: #d8bd8a;
    --chip-pass: #1d7a46; --chip-fail: #b02a1c; --chip-queued: var(--brass-deep);
    --chip-running: #15629f; --chip-done: #1d7a46;
  }
}

/* -- light theme, chosen in the page (overrides the OS) --------------- */
:root[data-theme="light"] {
  /* The page only.  --felt, --disc-b, --disc-w, --board-line and --screen are
     deliberately absent: the board keeps its colours in both themes. */
  --bg: #e9eee9; --surface-1: #f6f8f5; --surface-2: #dfe6e0; --surface-3: #ced8d0;
  --card: #f6f8f5;
  --ink: #0f1d18; --ink-strong: #000000; --ink-2: #3a4d45; --ink-dim: #475a52;
  --ink-faint: #5c6f67; --rule: #ced8d0; --rule-soft: rgba(15, 29, 24, .18);
  --rule-strong: #b4c0b8; --hover: rgba(15, 29, 24, .05); --glass: rgba(233, 238, 233, .62);
  --accent: var(--brass-deep); --accent-hover: #6d4408;
  --accent-soft: color-mix(in srgb, var(--brass-deep) 12%, var(--bg));
  --accent-ink: #ffffff; --attention: var(--brass); --attention-ink: var(--brass-deep);
  --link: var(--ink); --link-hover: var(--brass-deep);
  --ok: #1d7a46; --warn: var(--brass-deep); --bad: #b02a1c; --info: #15629f;
  --host: var(--brass-deep); --ta: #15629f;
  --rank-1: #8a580c; --rank-2: #12726a; --rank-3: #3b4bb8; --rank-4: #a8402a;
  --rank-5: #4d6b14; --rank-6: #8a3a9c; --rank-rest: #55685f;
  --axis: #7d9189; --grid: #ced8d0;
  --tooltip-bg: rgba(246, 248, 245, .97); --tooltip-border: #b4c0b8;
  --screen-glow: rgba(15, 29, 24, .18);
  --last-move: var(--brass-deep); --flipped: rgba(138, 88, 12, .28);
  --shell-public: #b4c0b8; --shell-host: #d8bd8a;
  --chip-pass: #1d7a46; --chip-fail: #b02a1c; --chip-queued: var(--brass-deep);
  --chip-running: #15629f; --chip-done: #1d7a46;
}
:root[data-theme="dark"] { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* -- base -------------------------------------------------------------- */

* { box-sizing: border-box; }
/* Several controls are laid out with flex, whose display would otherwise beat
   the UA rule for [hidden]; scripts reveal them by clearing the attribute. */
[hidden] { display: none !important; }

body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: var(--fw-normal) var(--fs-base)/var(--lh-body) var(--font-sans);
  -webkit-text-size-adjust: 100%; overflow-wrap: break-word;
}

main { max-width: var(--max-width); margin: 0 auto; padding: var(--sp-6) var(--gutter) var(--sp-8); }
section.narrow { max-width: var(--narrow); }

h1 { font-size: var(--fs-2xl); line-height: var(--lh-tight); margin: 0 0 var(--sp-6); font-weight: var(--fw-bold); }
h2 { font-size: var(--fs-lg); font-weight: var(--fw-bold); margin: var(--sp-7) 0 var(--sp-4); }
h3 { font-size: var(--fs-base); font-weight: var(--fw-bold); margin: var(--sp-6) 0 var(--sp-3); }
h4 { font-size: var(--fs-base); font-weight: var(--fw-semibold); margin: var(--sp-5) 0 var(--sp-2); }
.label, .panel-title {
  font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  color: var(--ink-2); margin: var(--sp-5) 0 var(--sp-2);
}
p { margin: var(--sp-2) 0; }

a { color: var(--link); text-decoration: underline; text-underline-offset: 2px; }
a:hover { color: var(--link-hover); text-decoration: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

code, .hash, .filename, kbd { font-family: var(--font-mono); }
code {
  font-size: var(--fs-sm); background: var(--surface-2);
  padding: 2px 5px; margin-right: -3px; border-radius: var(--radius-sm);
}
pre code, .prose pre code { background: none; padding: 0; }

.lede { font-size: var(--fs-lg); color: var(--ink-2); max-width: 62ch; line-height: var(--lh-snug); }
.meta { color: var(--ink-2); font-size: var(--fs-sm); }
.fine { color: var(--ink-dim); font-size: var(--fs-sm); max-width: 78ch; margin-top: var(--sp-3); }
.hint { color: var(--ink-dim); font-size: var(--fs-sm); }
.empty { color: var(--ink-dim); font-style: italic; }
.dim { color: var(--ink-dim); }
.strong { font-weight: var(--fw-bold); }
.ok { color: var(--ok); }
.bad, .why { color: var(--bad); }
.warn { color: var(--warn); }
.host-only { color: var(--host); }
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 30;
  background: var(--accent); color: var(--accent-ink); padding: var(--sp-2) var(--sp-4);
}
.skip:focus { left: var(--sp-4); top: var(--sp-2); }

/* -- header ------------------------------------------------------------ */

.bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-4) var(--gutter);
  background: var(--glass); backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--rule);
}
.bar > * { min-width: 0; }
.brand {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-base); font-weight: var(--fw-semibold);
  color: var(--ink); text-decoration: none; white-space: nowrap;
}
.brand svg { width: 16px; height: 16px; flex: none; }

.bar nav, .menu nav {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1);
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius-pill);
}
.bar nav a, .menu nav a {
  font-size: var(--fs-md); color: var(--ink-dim); text-decoration: none;
  padding: 6px 12px; border-radius: var(--radius-pill);
  transition: background var(--dur-fast), color var(--dur-fast);
}
.bar nav a:hover, .menu nav a:hover { color: var(--ink); background: var(--hover); }
.bar nav a.here, .menu nav a.here { background: var(--surface-3); color: var(--ink); }

.bar .who {
  margin-left: auto;
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-md);
}
.bar .who a { color: var(--ink-dim); text-decoration: none; }
.bar .who a:hover { color: var(--ink); }
.bar .handle { color: var(--ink-2); display: inline-flex; align-items: center; gap: var(--sp-1); }
.bar form { display: inline; }

.theme-toggle {
  font: var(--fw-semibold) var(--fs-md)/1 var(--font-sans);
  color: var(--ink-dim); background: var(--surface-2); padding: 6px 10px;
  border: 1px solid var(--rule-soft); border-radius: var(--radius-input); cursor: pointer;
}
.theme-toggle:hover { color: var(--ink); }

/* The mobile menu is a <details>: a disclosure the browser owns, so the nav
   still opens with JavaScript switched off. */
.menu { display: none; margin-left: auto; }
.menu > summary {
  list-style: none; cursor: pointer; padding: 6px 10px;
  border: 1px solid var(--rule-soft); border-radius: var(--radius-input);
  font: var(--fw-semibold) var(--fs-md)/1 var(--font-sans); color: var(--ink-dim);
}
.menu > summary::-webkit-details-marker { display: none; }
.menu[open] > summary { color: var(--ink); background: var(--surface-2); }
.menu nav {
  position: absolute; right: var(--sp-4); margin-top: var(--sp-2);
  flex-direction: column; align-items: stretch; min-width: 200px;
  background: var(--surface-1); border-radius: var(--radius-flyout);
  border: 1px solid var(--rule); padding: var(--sp-2); z-index: 25;
}

footer {
  max-width: var(--max-width); margin: 0 auto; border-top: 1px solid var(--rule);
  padding: var(--sp-5) var(--gutter) var(--sp-6);
  display: flex; flex-direction: column; gap: var(--sp-1);
  color: var(--ink-dim); font-size: var(--fs-sm);
}
footer .policy { color: var(--ink-faint); }

/* -- notices ----------------------------------------------------------- */

.notice, .error, .callout {
  background: var(--surface-2); border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm); padding: var(--sp-3) var(--sp-4);
}
.notice, .error { max-width: var(--max-width); margin: var(--sp-3) auto 0; font-size: var(--fs-sm); }
.callout { margin: var(--sp-4) 0; }
.error { border-left-color: var(--bad); color: var(--bad); }
main .notice, main .error { margin-left: 0; margin-right: 0; }
.callout.bad { border-left-color: var(--bad); }
.callout.warn { border-left-color: var(--warn); }
.callout > :first-child { margin-top: 0; }
.callout > :last-child { margin-bottom: 0; }

/* -- buttons, tags, chips, pills --------------------------------------- */

button, .button, .btn {
  display: inline-block; cursor: pointer; text-decoration: none;
  font-family: var(--font-sans); font-size: var(--fs-base);
  border: 1px solid transparent; border-radius: var(--radius-sm); padding: 8px 20px;
  background: color-mix(in srgb, var(--ink) 20%, var(--bg)); color: var(--ink);
  transition: background var(--dur-fast), color var(--dur-fast);
}
button:hover, .button:hover, .btn:hover {
  background: color-mix(in srgb, var(--ink) 30%, var(--bg));
  text-decoration: none;
}
button:active, .button:active { background: var(--surface-3); color: var(--ink-strong); }
button[type="submit"], .button.primary {
  background: var(--accent); color: var(--accent-ink); font-weight: var(--fw-semibold);
}
button[type="submit"]:hover, .button.primary:hover { background: var(--accent-hover); color: var(--accent-ink); }
.button.secondary { background: var(--attention); color: #0e0c0c; font-weight: var(--fw-semibold); }
.button.secondary:hover { background: var(--attention); filter: brightness(1.1); }
.btn {
  background: var(--surface-2); color: var(--ink);
  border: 1px solid var(--rule-soft); border-radius: var(--radius-input);
  padding: 8px 14px; font-size: var(--fs-md);
}
button:disabled, .btn:disabled { opacity: .5; cursor: not-allowed; }

button.linkish {
  background: none; border: none; padding: 0; color: var(--link);
  text-decoration: underline; font-size: inherit; font-family: inherit;
}
button.linkish:hover { background: none; color: var(--link-hover); }
button.danger, .danger, button.linkish.danger { color: var(--bad); }
button.danger, .danger {
  background: none; border: 1px solid color-mix(in srgb, var(--bad) 40%, transparent);
  border-radius: var(--radius-input); padding: 6px 12px; font-size: var(--fs-md);
}
button.linkish.danger { border: none; padding: 0; text-decoration: underline; background: none; }
button.danger:hover, .danger:hover { background: color-mix(in srgb, var(--bad) 15%, transparent); }

.tag, .chip { font-size: var(--fs-xs); font-weight: var(--fw-semibold); white-space: nowrap; }
.tag {
  padding: 1px 6px; border-radius: var(--radius-xs);
  background: var(--accent-soft); color: var(--accent);
}
.tag.bad { background: color-mix(in srgb, var(--bad) 16%, var(--bg)); color: var(--bad); }
.tag.role-host, .tag.host { background: color-mix(in srgb, var(--host) 16%, var(--bg)); color: var(--host); }
.tag.role-ta, .tag.ta { background: color-mix(in srgb, var(--ta) 16%, var(--bg)); color: var(--ta); }

.chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: 2px 8px; border-radius: var(--radius-pill);
  border: 1px solid currentColor; color: var(--ink-dim);
}
.chip.pass, .chip.ok, .chip.done, .chip.finished { color: var(--chip-pass); }
.chip.fail, .chip.failed, .chip.error { color: var(--chip-fail); }
.chip.queued, .chip.pending, .chip.held { color: var(--chip-queued); }
.chip.running { color: var(--chip-running); }
.chip.cancelled, .chip.superseded, .chip.none { color: var(--chip-cancelled); }

.pill-toggle {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  /* The options keep a slot floor, so the row cannot shrink below one slot.
     It wraps instead: five console pills in a 360px viewport become three
     lines, not 260px of horizontal page scroll (constraint 9). */
  flex-wrap: wrap; max-width: 100%;
  padding: var(--sp-1); margin: 0;
  border: 1px solid var(--rule-soft); border-radius: 25px;
}
.pill-option {
  font-size: var(--fs-md); font-weight: var(--fw-semibold);
  min-width: 120px; padding: 6px 16px; text-align: center;
  color: var(--ink-dim); text-decoration: none;
  border-radius: var(--radius-pill);
  transition: background var(--dur-fast) var(--ease-pill), color var(--dur-fast);
}
.pill-option:hover { color: var(--ink); text-decoration: none; }
.pill-option[aria-current], .pill-option.here {
  background: var(--surface-3); color: var(--ink);
}
/* The :target pills (envs.html): the first option is current until the second
   fragment is asked for.  Without :has() both sections show and the first pill
   stays lit, which is the same honest fallback the sections take. */
.target-pills a:first-of-type { background: var(--surface-3); color: var(--ink); }
:root:has(#scored:target) .target-pills a:first-of-type { background: none; color: var(--ink-dim); }
:root:has(#scored:target) .target-pills a:last-of-type { background: var(--surface-3); color: var(--ink); }

.tabs { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin: var(--sp-2) 0 var(--sp-5); padding: 0; }
.tabs a { color: var(--ink-dim); text-decoration: none; font-size: var(--fs-md); }
.tabs a.here { color: var(--ink); font-weight: var(--fw-bold); }

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

.table-scroll { overflow-x: auto; margin: var(--sp-4) 0; }
table { border-collapse: collapse; width: 100%; }
table.board, table.data-table, .prose table {
  font-size: var(--fs-xs);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
table.board th, table.board td, table.data-table th, table.data-table td,
.prose table th, .prose table td {
  border: 1px solid var(--rule);
  padding: var(--sp-2);
  text-align: left;
  vertical-align: top;
}
table.board thead th, table.data-table thead th, .prose table thead th {
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  color: var(--ink-faint); background: var(--surface-1);
  position: relative;
}
th[data-sort] { cursor: pointer; user-select: none; }
th[data-sort]:hover { color: var(--ink); }
th[aria-sort="ascending"]::after { content: " \25B2"; }
th[aria-sort="descending"]::after { content: " \25BC"; }
table.board tbody tr:hover td, table.data-table tbody tr:hover td { background: var(--hover); }
.sub-table tbody td { color: var(--ink-dim); }

.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.rank { color: var(--ink-dim); font-weight: var(--fw-bold); }
/* The rank colour rides on the row, so the rank cell's markup stays exactly
   what it was: a leaderboard test reads that cell as a literal string. */
.rank-1, [data-rank="1"] .rank { color: var(--rank-1); }
.rank-2, [data-rank="2"] .rank { color: var(--rank-2); }
.rank-3, [data-rank="3"] .rank { color: var(--rank-3); }
.rank-4, [data-rank="4"] .rank { color: var(--rank-4); }
.rank-5, [data-rank="5"] .rank { color: var(--rank-5); }
.rank-6, [data-rank="6"] .rank { color: var(--rank-6); }
.draw { color: var(--ink-2); }
.hash, .detail { font-size: var(--fs-xs); color: var(--ink-dim); word-break: break-all; white-space: normal; }
.filename, .agent { white-space: normal; word-break: break-word; }
.why { font-size: var(--fs-xs); white-space: normal; }
.actions { white-space: nowrap; }
.actions form { display: inline; }
.struck td { opacity: .55; text-decoration: line-through; }
.is-active td, tr.is-active > td { background: var(--accent-soft); }

/* An (i) marker whose explanation is in the title attribute, so a browser
   without our script still shows it on hover. */
.info-mark {
  display: inline-block; width: 13px; height: 13px; line-height: 13px;
  text-align: center; border-radius: var(--radius-pill);
  border: 1px solid var(--rule-strong); color: var(--ink-faint);
  font-size: 9px; cursor: help; margin-left: 4px;
}
.tip {
  position: fixed; z-index: 40; max-width: 280px;
  background: var(--tooltip-bg); border: 1px solid var(--tooltip-border);
  border-radius: var(--radius-input); padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-sm); line-height: var(--lh-snug);
  color: var(--ink); white-space: normal; pointer-events: none;
}

table.facts, .narrow-table { width: auto; min-width: min(100%, 26rem); max-width: 100%; }
table.facts th, table.facts td { border: 1px solid var(--rule); padding: var(--sp-2); text-align: left; }
table.facts th {
  font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  color: var(--ink-2); width: 14rem;
}

.status-pending, .status-queued { color: var(--chip-queued); }
.status-running { color: var(--chip-running); }
.status-finished, .status-done { color: var(--chip-done); }
.status-failed, .status-cancelled { color: var(--chip-fail); }

/* -- panels, cards, stats ---------------------------------------------- */

.panel {
  background: var(--surface-1); border: 1px solid var(--rule);
  border-radius: var(--radius-panel); padding: var(--sp-5);
}
.panel > :first-child { margin-top: 0; }
.panel > :last-child { margin-bottom: 0; }
.cards {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sp-4); margin: var(--sp-5) 0;
}
.card {
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--radius-panel); padding: var(--sp-4);
  display: flex; flex-direction: column;
}
.card h2, .card h4 {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-base); font-weight: var(--fw-semibold); color: var(--ink);
}
.card p { font-size: var(--fs-md); }
.card .card-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin-top: auto; padding-top: var(--sp-3); }

.stat-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--sp-3); margin: var(--sp-6) 0;
}
.stat {
  background: var(--surface-2); border-radius: var(--radius-panel); padding: var(--sp-4);
}
.stat-label {
  display: block; font-size: var(--fs-sm); color: var(--ink-2); margin-bottom: var(--sp-1);
}
.stat-value {
  display: block; font-size: var(--fs-xl); line-height: var(--lh-tight);
  font-variant-numeric: tabular-nums; font-weight: var(--fw-bold);
}
.stat-note { display: block; font-size: var(--fs-xs); color: var(--ink-dim); margin-top: var(--sp-1); }
.stat.bad .stat-value { color: var(--bad); }
.stat.wide .stat-value { font-size: var(--fs-lg); }

.chip-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--sp-2); margin: var(--sp-4) 0;
}
.chip-cell { background: var(--surface-2); border-radius: var(--radius-input); padding: var(--sp-2) var(--sp-3); }
.chip-cell .value { font-size: var(--fs-md); }

.log-panel {
  background: var(--surface-1); border: 1px solid var(--rule);
  border-radius: var(--radius-panel); padding: var(--sp-4); margin: var(--sp-4) 0;
}
.log-panel .panel-title { margin: 0 0 var(--sp-2); }
.log-panel .log-body, pre.log, pre {
  font: var(--fw-normal) var(--fs-xs)/var(--lh-snug) var(--font-mono);
  background: var(--surface-1); color: var(--ink-2);
  border: 1px solid var(--rule); border-radius: var(--radius-input);
  padding: var(--sp-3); margin: 0;
  max-height: 60vh; overflow: auto; scrollbar-width: thin;
  white-space: pre-wrap; word-break: break-word;
}
.log-filter {
  width: 100%; max-width: 22rem; margin-bottom: var(--sp-2);
  font-size: var(--fs-sm);
}
.log-count { font-size: var(--fs-sm); color: var(--ink-dim); }

/* -- forms ------------------------------------------------------------- */

form.narrow { max-width: 34rem; margin: var(--sp-4) 0; }
label { display: block; font-size: var(--fs-sm); color: var(--ink-dim); margin-top: var(--sp-3); }
label.checkbox, label.inline { display: block; color: var(--ink-2); }
label.checkbox input, label.inline input { width: auto; margin-right: var(--sp-2); }

input[type="text"], input[type="password"], input[type="number"], input[type="search"],
input[type="email"], select, textarea, input[type="file"] {
  font-family: var(--font-mono); font-size: var(--fs-md);
  width: 100%; max-width: 34rem; padding: 8px 10px; line-height: 1.5;
  background: var(--surface-2); color: var(--ink);
  border: 1px solid var(--rule-strong); border-radius: var(--radius-input);
}
textarea, input[type="search"] { font-family: var(--font-sans); }
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
input[aria-invalid="true"] { border-color: var(--bad); }

.inline-form { display: inline-flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; margin-left: var(--sp-2); }
.inline-form input[type="text"] { width: auto; max-width: 100%; margin: 0; }
.grid-form {
  display: grid; grid-template-columns: 14rem minmax(10rem, 24rem);
  gap: var(--sp-2) var(--sp-4); align-items: center; margin: var(--sp-4) 0;
}
.grid-form label { margin: 0; }
.report { margin: var(--sp-2) 0; padding-left: var(--sp-5); font-size: var(--fs-md); }
.report.bad li { color: var(--bad); }
.report.warn li { color: var(--warn); }

.signin-panel {
  max-width: 420px; margin: 10vh auto 0;
  background: var(--surface-1); border: 1px solid var(--rule);
  border-radius: var(--radius-panel); padding: var(--sp-6);
}
.signin-panel h1 { font-size: var(--fs-xl); margin-bottom: var(--sp-3); }
.signin-panel input[type="password"] { max-width: none; }
.signin-panel button { width: 100%; margin-top: var(--sp-4); }
.signin-note { max-width: 62ch; margin: var(--sp-5) auto 0; }

.drop-area {
  border: 1px dashed var(--rule-strong); border-radius: var(--radius-panel);
  padding: var(--sp-6); text-align: center; margin: var(--sp-3) 0;
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
.drop-area.over { border-color: var(--accent); background: var(--accent-soft); }
.drop-area input[type="file"] { max-width: 100%; }

.pipeline { list-style: none; margin: 0; padding: 0; }
.pipeline li {
  display: grid; grid-template-columns: 10px 1fr; gap: var(--sp-3);
  padding: var(--sp-2) 0; border-bottom: 1px solid var(--rule);
}
.pipeline li:last-child { border-bottom: none; }
.pipeline .dot {
  width: 8px; height: 8px; border-radius: var(--radius-pill);
  background: var(--ink-faint); margin-top: 6px;
}
.pipeline .dot.pass { background: var(--ok); }
.pipeline .dot.fail { background: var(--bad); }
.pipeline .dot.queued { background: var(--warn); }
.pipeline .dot.running { background: var(--info); }
.pipeline .step { font-size: var(--fs-sm); color: var(--ink-dim); display: block; }
.pipeline .label { display: block; margin: 0; color: var(--ink); }
.copy-inline { padding: 0 6px; font-size: 10px; margin-left: var(--sp-2); }
.host-panel { border-left: 3px solid var(--host); margin-top: var(--sp-6); }
details.danger-zone > summary { color: var(--bad); }
.docs-aside { display: none; }
@media (min-width: 1024px) { .docs-aside { display: block; } }

/* -- hero and mini leaderboard ----------------------------------------- */

.hero { display: grid; gap: var(--sp-6); align-items: start; margin-bottom: var(--sp-6); }
.hero .cta { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }
.hero-board { position: relative; max-width: var(--board-size); }
/* The hero's round tag, on the board's top-right corner.  Taken out of flow
   on purpose: a round id is `tier-YYYYMMDD-HHMMSS`, and in the label voice
   that is a ~360px box which would otherwise set the width of the hero's
   grid column and scroll a 320px phone sideways.  It wraps rather than
   overflowing, which is why this one tag opts out of the .tag nowrap. */
.tag.corner {
  position: absolute; top: calc(-1 * var(--sp-3)); right: var(--sp-3); z-index: 2;
  background: var(--attention); color: #0e0c0c; max-width: calc(100% - var(--sp-5));
  white-space: normal; text-align: right; text-decoration: none;
}
.mini-board { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-6); }
.mini-leaderboard { width: 100%; font-size: var(--fs-md); border-collapse: collapse; }
.mini-leaderboard th {
  color: var(--ink-faint); font-weight: var(--fw-semibold); font-size: var(--fs-sm);
  text-align: left; padding: var(--sp-1) var(--sp-2);
}
.mini-leaderboard td {
  padding: var(--sp-1) var(--sp-2); border-top: 1px solid var(--rule);
  font-variant-numeric: tabular-nums;
}

/* -- the share mark: the one loud thing on the leaderboard ------------- */
/* The board is what this benchmark measures, so the headline number is drawn
   in the board's own material rather than in a bar: ten cells of felt, filled
   from the left with black and from the right with white, cut where the
   agent's share of won games falls.  Two background layers and no element per
   cell -- the lower layer is the two-tone fill, the upper one is the felt with
   a round hole punched in each cell, so what separates the discs is felt and
   the mark reads as a board.  --won is the only thing the row supplies.
   The number stays beside the mark: the mark is the shape of the result and
   the number is the result, and with no stylesheet the number is all of it. */

.share-mark {
  display: inline-block; vertical-align: middle;
  --cell: 13px; width: calc(10 * var(--cell)); height: var(--cell);
  border-radius: var(--radius-xs);
  background:
    radial-gradient(circle closest-side at center, transparent 72%, var(--felt-line) 76%,
                    var(--felt) 84%) 0 0 / var(--cell) var(--cell) repeat-x,
    linear-gradient(90deg, var(--disc-b) var(--won, 0%), var(--disc-w) 0);
}
.share-num {
  margin-left: var(--sp-3); vertical-align: middle;
  font-size: var(--fs-md); font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}

/* -- the leaderboard chart --------------------------------------------- */

.title-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-4); }
.board-title { margin: 0; }
.round-chip { display: inline-block; background: var(--surface-2); border-radius: var(--radius-input);
  padding: var(--sp-2) var(--sp-3); }
.chart-block { margin: var(--sp-5) 0; }
.curve-chart { width: 100%; height: auto; font: var(--fs-xs) var(--font-sans); }
/* No grid: the vertical rule a reader wants is the one at the checkpoint
   under the pointer, which chart.js draws.  Horizontal value rules stay --
   nothing on demand says where 50% is, and 50% is the coin flip. */
.curve-chart .axis, .curve-chart .tick { stroke: var(--axis); stroke-width: 1; fill: none; }
.curve-chart .rule { stroke: var(--grid); stroke-width: 1; } .curve-chart .rule.even { stroke: var(--rule-strong); } .curve-chart .axis-label { fill: var(--ink-dim); font-size: var(--fs-xs); }
/* One rank -> token mapping: curve, dots and end label all paint from
   currentColor, so a dot cannot differ from its own line.  Your curve takes
   the page's ink, not a seventh series colour: hue here means rank. */
.curve-chart .r1 { color: var(--rank-1); } .curve-chart .r2 { color: var(--rank-2); }
.curve-chart .r3 { color: var(--rank-3); } .curve-chart .r4 { color: var(--rank-4); }
.curve-chart .r5 { color: var(--rank-5); } .curve-chart .r6 { color: var(--rank-6); }
.curve-chart .rest, .curve-chart .band, .curve-chart .band-label { color: var(--rank-rest); }
.curve-chart .you { color: var(--ink); } .curve-chart .end-label.mine { font-weight: var(--fw-semibold); }
.curve-chart .halo { fill: none; stroke: var(--bg); stroke-width: 6; stroke-linejoin: round; } .curve-chart .leader { stroke: currentColor; stroke-width: 1; opacity: .4; }
.curve-chart .curve { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; }
.curve-chart .curve.rest { stroke-width: 1; opacity: .5; } .curve-chart .curve.on { stroke-width: 3.4; } .curve-chart .dot { fill: currentColor; stroke: none; }
/* The field, once there is too much of it to draw a row at a time: two shapes
   in one ink, because the contrast is rising against flat, not hue against hue.
   A flat dashed median is what "no signal" looks like. */
.curve-chart .band { fill: currentColor; stroke: none; opacity: .09; } .curve-chart .band.up { opacity: .3; }
.curve-chart .band-mid { fill: none; stroke: var(--rank-rest); stroke-width: 2; } .curve-chart .band-mid.flat { stroke-dasharray: 5 4; }
.curve-chart .end-label, .curve-chart .band-label { fill: currentColor; font-size: var(--fs-xs); stroke: var(--bg); stroke-width: 3px; paint-order: stroke; }
.chart-note { margin-top: var(--sp-2); max-width: var(--prose); } .spark { white-space: nowrap; }
.sparkline { display: block; overflow: visible; } .spark-line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.spark-end { fill: var(--accent); } .spark-base { stroke: var(--rule-strong); stroke-width: 1; }
/* The cell's one reading: in the markup for a screen reader and a stylesheet-less page, a 1px box otherwise. */
.checkpoints { display: inline-block; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

/* -- replay: the handheld console -------------------------------------- */

.replay { display: grid; gap: var(--sp-5); align-items: start; margin-top: var(--sp-4); }
.badge-row {
  display: inline-block; font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  border: 2px solid var(--shell-base); color: var(--ink-2);
  border-radius: var(--radius-sm); padding: 4px 10px; margin-bottom: var(--sp-3);
}
.board-pane { max-width: var(--board-size); width: 100%; }
.host-tier { --shell-base: var(--shell-host); }
.bezel {
  border-radius: var(--radius-bezel-out);
  border-style: solid; border-width: 5px 6px 6px 5px; border-color: var(--shell-bezel);
  background: linear-gradient(160deg, var(--shell-hi), var(--shell-lo));
  box-shadow: inset 1px 1px 0 rgba(255, 255, 255, .2);
  padding: var(--sp-2);
}
.bezel-inner { border-radius: var(--radius-bezel-in); padding: var(--sp-2); }
#board, #hero-board, .geometry-tile svg {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius-input);
  background: var(--screen);
  box-shadow: inset 0 0 20px var(--screen-glow);
}
.cell { fill: none; stroke: var(--board-line); stroke-width: 0.02; }
.blocked { fill: var(--board-block); }
.flip { fill: var(--flipped); stroke: none; }
svg .black { fill: var(--disc-b); stroke: var(--disc-rim); stroke-width: 0.03; }
svg .white { fill: var(--disc-w); stroke: var(--disc-rim); stroke-width: 0.03; }
.last { fill: none; stroke: var(--last-move); stroke-width: 0.08; }

.controls, .transport { display: flex; gap: var(--sp-2); align-items: center; margin-top: var(--sp-3); flex-wrap: wrap; }
.transport a, .transport button {
  width: 36px; height: 36px; padding: 0; border-radius: var(--radius-pill); display: inline-flex;
  align-items: center; justify-content: center; background: var(--surface-3); color: var(--ink-strong); border: 1px solid var(--rule-soft); text-decoration: none;
}
.transport a:hover, .transport button:hover { background: var(--accent); color: var(--accent-ink); }
.transport a[aria-disabled="true"] { opacity: .4; pointer-events: none; }
.transport svg { width: 16px; height: 16px; fill: currentColor; }
.transport .frame-link { width: auto; padding: 0 12px; border-radius: var(--radius-input); font: var(--fw-semibold) var(--fs-md)/1 var(--font-sans); }
.deck input[type="range"] { display: block; width: 100%; accent-color: var(--accent); margin: 0; }
/* Five speeds as one control: a cycle is a dead end for somebody at 8x who wants 2x. */
.speeds { display: inline-flex; border: 1px solid var(--rule-soft); border-radius: var(--radius-input); overflow: hidden; }
.speeds button { width: auto; height: 34px; padding: 0 9px; border: 0; border-radius: 0; font: var(--fw-semibold) var(--fs-sm)/1 var(--font-sans); font-variant-numeric: tabular-nums; }
.speeds button[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); }
/* The disc-share curve: a second screen on the same console, set on the board's
   felt and filled with the board's discs -- which is what they are, and the felt
   sits between the two in luminance so neither side reads stronger.  --brass is
   still the chart's only interface colour, on the threshold and the marker, as it
   is the last-move ring.  A stretched viewBox needs every stroke out of the scale. */
.replay-stats { grid-template-columns: repeat(auto-fit, minmax(116px, 1fr)); gap: var(--sp-2); margin: 0 0 var(--sp-4); }
.replay-stats .stat { padding: var(--sp-3); } .replay-stats .stat-value { font-size: var(--fs-lg); }
.share-curve { display: block; width: 100%; height: 128px; background: var(--screen); border-radius: var(--radius-input); box-shadow: inset 0 0 20px var(--screen-glow); cursor: crosshair; }
.share-curve line, .share-curve polyline { vector-effect: non-scaling-stroke; }
.share-curve .area { stroke: none; } .share-curve .area.b { fill: var(--disc-b); opacity: .85; } .share-curve .area.w { fill: var(--disc-w); opacity: .8; }
.share-curve .line { fill: none; stroke: var(--disc-rim); stroke-width: 2; stroke-linejoin: round; }
.share-curve .mid { stroke: var(--board-line); } .share-curve .k { stroke: var(--attention); stroke-dasharray: 6 4; } .share-curve .marker { stroke: var(--accent); stroke-width: 2; }
/* Event pips: a tick for a big flip, a full mark for the rarer things. */
.deck { margin-top: var(--sp-4); } .pips { position: relative; height: 13px; margin-bottom: var(--sp-1); }
.pip { position: absolute; top: 6px; width: 3px; height: 7px; margin-left: -1px; border-radius: 1px; background: var(--ink-faint); }
.pip.pass, .pip.corner, .pip.penalty { top: 0; height: 13px; background: var(--accent); } .pip.penalty { background: var(--bad); }
.game-chips { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin: var(--sp-3) 0; }
.game-chips a {
  font-family: var(--font-mono); font-size: var(--fs-xs); text-decoration: none;
  padding: 2px 6px; border: 1px solid var(--rule); border-radius: var(--radius-xs);
  color: var(--ink-dim);
}
.game-chips a.here { border-color: var(--accent); color: var(--ink); }
.game-chips a.win { color: var(--ok); } .game-chips a.loss { color: var(--bad); }
.log-panel .plies { list-style: none; margin: 0; padding: 0; max-height: 60vh; overflow: auto; white-space: normal; }
.plies li { font: var(--fs-xs)/1.7 var(--font-mono); }
.plies a { display: block; padding: 1px var(--sp-2); color: var(--ink-2); text-decoration: none; }
.plies a:hover { background: var(--hover); }
.plies li.at a { background: var(--surface-3); color: var(--ink); }
.plies li.pass { color: var(--ink-dim); }
.plies.hide-passes li.pass { display: none; }

/* Two tier sections, switched by :target.  Without :has() both stay visible,
   which is the honest fallback: nothing is hidden that the page promised. */
#practice:target ~ #scored { display: none; }
.tier-sections:has(#scored:target) #practice { display: none; }
.geometry-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-3); }
.geometry-tile { background: var(--surface-2); border-radius: var(--radius-input); padding: var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-xs); }
.geometry-tile svg { max-width: 132px; margin-top: var(--sp-1); }
details.geometry-tile { display: block; } /* a flex container on <details> has leaked its shut contents */
/* One disc mark, two jobs: which side an objective rewards on /envs, and
   which colour an agent played in a replay.  Four classes became two plus a
   ring, because "majority" and "black" are the same disc drawn for the same
   reason -- the board's own colours, which are data and stay theme-independent. */
.disc-mark { display: inline-block; width: 9px; height: 9px; border-radius: var(--radius-pill);
  margin-right: 6px; background: var(--ink-faint); box-shadow: 0 0 0 1px var(--rule-strong); }
.disc-mark.b { background: var(--disc-b); } .disc-mark.w { background: var(--disc-w); }
.disc-mark.capped { box-shadow: 0 0 0 2px var(--brass); }

/* -- prose and the docs layout ----------------------------------------- */

.docs-layout { display: grid; gap: var(--sp-6); align-items: start; }
/* A grid item's automatic minimum is its min-content: without this a wide
   spec table widens the column past the page instead of scrolling itself. */
.docs-layout > * { min-width: 0; }
.docs-side { position: sticky; top: 80px; }
.doc-switch { display: flex; flex-direction: column; gap: var(--sp-1); }
.doc-switch .pill-option { min-width: 0; text-align: left; }
.toc { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); }
.toc ul { list-style: none; margin: 0; padding: 0; }
.toc a { color: var(--ink-dim); text-decoration: none; display: block; padding: 2px 0; }
.toc a:hover, .toc a.at { color: var(--ink); }
.toc .h3 { padding-left: var(--sp-3); }
/* The copy button rides in the corner of the code block it copies. */
.copy-code { position: absolute; top: var(--sp-2); right: var(--sp-2); padding: 2px 8px; font-size: 10px; }

.prose { max-width: var(--prose); font-size: var(--fs-base); line-height: var(--lh-body); }
.prose h1 { font-size: var(--fs-2xl); margin: 0 0 var(--sp-5); }
.prose h2 {
  font-size: var(--fs-lg); margin: var(--sp-7) 0 var(--sp-4);
  padding-bottom: var(--sp-2); border-bottom: 1px solid var(--rule);
}
.prose h3, .prose h4 {
  font-size: var(--fs-base); font-weight: var(--fw-semibold);
  color: var(--ink); margin: var(--sp-5) 0 var(--sp-2);
}
.prose blockquote {
  margin: var(--sp-4) 0; padding-left: var(--sp-4);
  border-left: 3px solid var(--rule-strong); color: var(--ink-2);
}
.prose pre {
  background: var(--surface-1); border: 1px solid var(--rule); border-radius: var(--radius-panel);
  padding: var(--sp-4); font-size: var(--fs-sm); max-height: none; position: relative;
}
.prose table { white-space: normal; }
.prose hr { border: none; border-top: 1px solid var(--rule); margin: var(--sp-6) 0; }
.prose li { margin: var(--sp-1) 0; }
/* -- the error page ---------------------------------------------------- */

.error-page { min-height: 60vh; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center; gap: var(--sp-4); }
h1.code {
  font-size: var(--fs-display); font-weight: var(--fw-bold);
  color: var(--attention-ink); margin: 0;
}

/* -- host console ------------------------------------------------------ */

.console-nav { position: sticky; top: 64px; z-index: 10; background: var(--glass);
  backdrop-filter: blur(16px); padding: var(--sp-2) 0; margin: var(--sp-4) 0; }
.two-column { display: grid; gap: var(--sp-5); align-items: start; }
/* A grid item's automatic minimum size is its content's, so a .table-scroll
   inside a panel pushed the whole console sideways at 320px instead of
   scrolling inside itself. */
.two-column > * { min-width: 0; }
.entry-status { margin: var(--sp-4) 0; }
details.explain, details.limits, details > summary { font-size: var(--fs-md); }
details > summary { cursor: pointer; color: var(--ink-2); }
details.explain { margin: var(--sp-5) 0; }

/* -- breakpoints ------------------------------------------------------- */

@media (min-width: 900px) {
  .hero { grid-template-columns: 1fr minmax(320px, var(--board-size)); }
  .two-column { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1024px) {
  :root { --board-size: 488px; }
  .replay { grid-template-columns: minmax(0, var(--board-size)) minmax(0, 1fr); }
  /* Column 1 is the console: board, then transport.  The deck used to span
     both columns on row 2, so the scrubber sat under the whole info pane --
     past the curve and the placements log -- although source order had always
     put it straight after the board, which is why only desktop was wrong. */
  .replay > .board-pane { grid-area: 1 / 1; } .replay > .deck { grid-area: 2 / 1; }
  .replay > .info-pane { grid-area: 1 / 2 / span 2; }
  .docs-layout { grid-template-columns: 220px minmax(0, var(--prose)) 200px; }
  /* disputes.py injects the rules note before .prose: both go in track 2. */
  .docs-layout > .meta, .docs-layout > .prose { grid-column: 2; } .docs-layout > .docs-side { grid-row: 1 / span 2; }
}
@media (max-width: 767px) {
  :root { --gutter: 16px; }
  .bar { gap: var(--sp-2); padding: var(--sp-3) var(--gutter); }
  .bar > nav, .bar .who { display: none; }
  .menu { display: block; }
  .menu nav .who-menu { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2); }
  .mini-board, .grid-form { grid-template-columns: 1fr; }
  /* A dense nowrap table would otherwise push the page sideways.  Every data
     table becomes its own scroll box on a phone, wrapper or not, so the page
     itself never scrolls horizontally. */
  table.board, table.facts, .narrow-table, table.data-table, .prose table {
    display: block; max-width: 100%; min-width: 0; overflow-x: auto; scrollbar-width: thin;
  }
  /* The chart's labels are drawn inside it, so it scrolls rather than shrinks. */
  .chart-block { overflow-x: auto; } .curve-chart { min-width: 760px; }
  .docs-side { position: static; }
  .stat-strip { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
}
@media (max-width: 480px) {
  .pill-option { min-width: 96px; padding: 6px 10px; }
  .share-mark { --cell: 9px; }
  .share-num { margin-left: var(--sp-2); }
  table.board, table.data-table { font-size: 10px; }
  table.board th, table.board td { padding: 6px; }
}
/* Replays index (server/templates/replays.html).  Win/draw/loss are the
   chip colours every status already uses; the board's own colours stay data. */
.replay-filters { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-end; margin: var(--sp-4) 0; }
.replay-filters label { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 9rem; }
.replay-filters select { max-width: 16rem; }
.replay-filters .label { margin: 0; }
.rx-panel { margin: var(--sp-6) 0; }
.rx-panel h2 { font-size: var(--fs-lg); margin-bottom: var(--sp-2); }
.rx-matrix { width: auto; border-collapse: separate; border-spacing: 2px; font-size: var(--fs-sm); }
.rx-matrix th { font-weight: var(--fw-semibold); text-align: left; white-space: nowrap; padding: 2px 6px; }
.rx-matrix th.rx-col { height: 7.5rem; vertical-align: bottom; padding: 0; width: 2.4rem; }
.rx-matrix th.rx-col span { display: inline-block; writing-mode: vertical-rl; transform: rotate(180deg); padding: 4px 0; }
.rx-matrix td { width: 2.4rem; height: 2rem; text-align: center; border-radius: var(--radius-xs); padding: 0; }
.rx-cell { background: color-mix(in srgb, color-mix(in srgb, var(--chip-pass) calc(var(--p) * 1%), var(--chip-fail)) 55%, var(--bg)); }
.rx-cell a { display: block; line-height: 2rem; color: var(--ink); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; text-decoration: none; }
.rx-cell a:hover, .rx-cell a:focus-visible { outline: 2px solid var(--brass); outline-offset: 1px; }
.rx-self { background: repeating-linear-gradient(45deg, var(--surface-2) 0 4px, var(--surface-3) 4px 8px); }
.rx-none { background: var(--surface-1); }
.rx-legend { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.rx-swatch { display: inline-block; width: 1.2rem; height: .8rem; border-radius: 2px;
  background: color-mix(in srgb, var(--chip-pass) calc(var(--p) * 1%), var(--chip-fail)); }
.rx-bars { list-style: none; padding: 0; margin: 0; display: grid; gap: 4px; }
.rx-bars li { display: grid; grid-template-columns: minmax(6rem, 10rem) 1fr 7rem; gap: var(--sp-3); align-items: center; }
.rx-bars .num { font-size: var(--fs-sm); }
.rx-bars a.here code { color: var(--attention-ink); }
.rx-bar { display: flex; height: .9rem; border-radius: var(--radius-xs); overflow: hidden; background: var(--surface-2); }
/* Widths come as a unitless --w (0..100): a literal "NN%" beside an environment id
   reads as a per-environment rate to the disclosure sweep (tests/test_integrity_scan.py). */
.rx-bar > span { width: calc(var(--w, 0) * 1%); }
.rx-bar .w, .rx-key.w { background: var(--chip-pass); }
.rx-bar .d, .rx-key.d { background: var(--ink-faint); }
.rx-bar .l, .rx-key.l { background: var(--chip-fail); }
.rx-key { display: inline-block; width: .8rem; height: .8rem; border-radius: 2px; }
/* Leaderboard overview (leaderboard.html). */
.board-overview { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); gap: var(--sp-6); }
.board-overview .rx-panel { margin: var(--sp-4) 0; }
.field-bars li { grid-template-columns: minmax(8rem, 11rem) 1fr 5.5rem; }
.field-bars .agent { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-sm); }
.field-bars li.mine .agent, .field-bars li.focus .agent { color: var(--attention-ink); font-weight: var(--fw-semibold); }
.field-bars li.struck { opacity: .5; }
.rx-bar.mini { display: flex; width: 7rem; height: .45rem; margin: 3px 0 2px auto; }
table.board tr.mine td { background: color-mix(in srgb, var(--brass) 10%, transparent); }
.scatter { width: 100%; height: auto; }
.scatter .rule { stroke: var(--rule-soft); stroke-width: 1; }
.scatter .median { stroke: var(--ink-faint); stroke-dasharray: 4 4; stroke-width: 1; }
.scatter .axis-label { fill: var(--ink-dim); font-size: 11px; }
.scatter .pt circle { fill: var(--ink-2); stroke: var(--bg); stroke-width: 1.5; }
.scatter .pt text { fill: var(--ink-2); font-size: 11px; }
.scatter .pt.top circle { fill: var(--s-teal); }
.scatter .pt.focus circle, .scatter .pt.mine circle { fill: var(--brass); }
.scatter .pt.focus text, .scatter .pt.mine text { fill: var(--attention-ink); font-weight: 600; }
/* Player page (_profile.html): a header card, a side column, a match list. */
.pf-head { display: flex; gap: var(--sp-4); align-items: center; padding: var(--sp-4); background: var(--surface-1); border-radius: var(--radius-panel); margin: var(--sp-4) 0; }
.pf-avatar { width: 64px; height: 64px; border-radius: var(--radius-panel); background: var(--felt); display: grid; grid-template-columns: 1fr 1fr; place-items: center; padding: 10px; flex: none; }
.pf-avatar .disc-mark { width: 20px; height: 20px; margin: 0; }
.pf-name { margin: 0; font-size: var(--fs-xl); }
.pf-badges { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin: 0 0 var(--sp-1); }
.pf-badge { font-size: var(--fs-xs); padding: 1px 6px; border-radius: var(--radius-xs); background: var(--accent-soft); color: var(--attention-ink); text-decoration: none; }
.pf-grid { display: grid; grid-template-columns: minmax(260px, 320px) 1fr; gap: var(--sp-4); align-items: start; }
.pf-side, .pf-main { display: grid; gap: var(--sp-4); min-width: 0; }
.pf-card { background: var(--surface-1); border-radius: var(--radius-panel); padding: var(--sp-4); }
.pf-card h2, .pf-matches h2 { font-size: var(--fs-md); margin: 0 0 var(--sp-3); }
.pf-rank { margin: 0; }
.pf-rank-n { font-size: var(--fs-2xl); font-weight: var(--fw-bold); color: var(--attention-ink); }
.pf-trail { width: 100%; height: 48px; }
.pf-trail polyline { fill: none; stroke: var(--accent); stroke-width: 2; }
.pf-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 6px; }
.pf-list li { display: grid; grid-template-columns: 5.5rem 1fr 5.5rem; gap: var(--sp-2); align-items: center; font-size: var(--fs-sm); }
.pf-opp { font-size: var(--fs-sm); margin: 0; }
.good { color: var(--chip-pass); }
.pf-summary { display: grid; grid-template-columns: 96px 1fr; gap: var(--sp-4); align-items: center; }
.pf-summary .fine { grid-column: 1 / -1; margin: 0; }
.pf-donut { width: 96px; height: 96px; transform: rotate(0deg); }
.pf-donut circle { fill: none; stroke-width: 5; }
.pf-donut .track { stroke: var(--chip-fail); opacity: .55; }
.pf-donut .won { stroke: var(--chip-pass); }
.pf-donut text { fill: var(--ink); font-size: 10px; font-weight: 700; }
.pf-big { font-size: var(--fs-lg); font-weight: var(--fw-semibold); margin: 0; }
.pf-matches { display: grid; gap: 6px; }
.pf-match { display: grid; grid-template-columns: 7rem 8rem 7rem 1fr auto; gap: var(--sp-3); align-items: center; padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-input); border-left: 5px solid var(--ink-faint); background: var(--surface-1); font-size: var(--fs-sm); }
.pf-match.win { border-left-color: var(--chip-pass); background: color-mix(in srgb, var(--chip-pass) 12%, var(--surface-1)); }
.pf-match.loss { border-left-color: var(--chip-fail); background: color-mix(in srgb, var(--chip-fail) 12%, var(--surface-1)); }
.pf-match > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pf-m-score { flex-direction: row !important; align-items: center; gap: 6px !important; font-size: var(--fs-base); }
.pf-settings { margin-top: var(--sp-7); }
.pf-settings > summary { cursor: pointer; }
.pf-settings > summary h2 { display: inline; }
@media (max-width: 800px) {
  .pf-grid { grid-template-columns: 1fr; }
  .pf-match { grid-template-columns: 1fr 1fr; }
  .pf-m-go { grid-column: 1 / -1; }
}
/* Play (index.html, play.html).  The board keeps the board group's colours;
   the move hint is --brass, the one interface accent. */
.play-home { display: grid; grid-template-columns: 1fr minmax(200px, 260px); gap: var(--sp-6); align-items: start; }
.play-form fieldset { border: 0; padding: 0; margin: 0 0 var(--sp-4); }
.agent-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--sp-2); }
.agent-card { display: grid; grid-template-columns: 36px 1fr; grid-template-rows: auto auto; column-gap: var(--sp-2); align-items: center; padding: var(--sp-2) var(--sp-3); border: 1px solid var(--rule-strong); border-radius: var(--radius-input); background: var(--surface-1); cursor: pointer; }
.agent-card input { position: absolute; opacity: 0; }
.agent-card:has(input:checked) { border-color: var(--brass); background: var(--accent-soft); }
.agent-card:has(input:focus-visible) { outline: 2px solid var(--brass); outline-offset: 2px; }
.agent-face { grid-row: 1 / 3; width: 36px; height: 36px; border-radius: 50%; background: var(--surface-3); color: var(--ink); display: grid; place-items: center; font-weight: var(--fw-bold); }
.agent-name { font-weight: var(--fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.play-options { display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: flex-end; }
.colour-pick { display: flex; gap: var(--sp-3); align-items: center; border: 0; padding: 0; margin: 0; }
.play-recent ul { list-style: none; padding: 0; }
.play-status { display: flex; gap: var(--sp-4); align-items: center; flex-wrap: wrap; }
.play-score { font-size: var(--fs-lg); font-weight: var(--fw-bold); }
.play-verdict { font-size: var(--fs-xl); font-weight: var(--fw-bold); }
.play-verdict.win { color: var(--chip-pass); } .play-verdict.loss { color: var(--chip-fail); }
.play-board-form .bezel { max-width: min(92vw, 520px); }
.play-board { display: grid; grid-template-columns: repeat(var(--cols), 1fr); background: var(--felt-line); gap: 1px; }
.play-board .sq { aspect-ratio: 1; background: var(--felt); display: grid; place-items: center; border: 0; padding: 0; margin: 0; }
.play-board .sq.blocked { background: var(--felt-dead); }
.play-board .disc { width: 78%; height: 78%; border-radius: 50%; display: block; }
.play-board .disc.b { background: var(--disc-b); } .play-board .disc.w { background: var(--disc-w); }
.play-board button.legal { cursor: pointer; }
.play-board button.legal::after { content: ""; width: 26%; height: 26%; border-radius: 50%; border: 2px solid var(--brass); }
.play-board button.legal:hover::after, .play-board button.legal:focus-visible::after { background: var(--brass); }
.play-actions { display: flex; gap: var(--sp-3); align-items: center; margin-top: var(--sp-4); }
@media (max-width: 800px) { .play-home { grid-template-columns: 1fr; } }
/* Submit quest (submit.html, server/onboarding.py). */
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.quest { margin: var(--sp-5) 0; }
.quest-head { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-2) var(--sp-4); align-items: center; padding: var(--sp-4); background: var(--surface-1); border-radius: var(--radius-panel); }
.quest-head .meta { grid-column: 1 / -1; margin: 0; }
.quest-lv { font-size: var(--fs-2xl); font-weight: var(--fw-bold); color: var(--attention-ink); margin-right: 4px; }
.quest-bar { height: 12px; border-radius: var(--radius-pill); background: var(--surface-3); overflow: hidden; }
.quest-bar > span { display: block; height: 100%; width: calc(var(--w, 0) * 1%); background: var(--brass); border-radius: inherit; transition: width .6s var(--ease-pill); }
.quest-steps { list-style: none; padding: 0; margin: var(--sp-4) 0 0; display: grid; gap: var(--sp-2); position: relative; }
.quest-step, .quest-side { display: grid; grid-template-columns: 40px 1fr; gap: var(--sp-3); align-items: start; padding: var(--sp-3); border-radius: var(--radius-input); background: var(--surface-1); border: 1px solid transparent; }
.quest-step h3, .quest-side h3 { margin: 0; font-size: var(--fs-base); }
.quest-step p, .quest-side p { margin: 2px 0 0; }
.quest-badge { width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; font-weight: var(--fw-bold); background: var(--surface-3); color: var(--ink-dim); }
.quest-step.done .quest-badge, .quest-side.done .quest-badge { background: var(--surface-3); color: var(--chip-pass); box-shadow: inset 0 0 0 2px var(--chip-pass); }
.quest-step.current { border-color: var(--brass); background: var(--accent-soft); }
.quest-step.current .quest-badge { background: var(--brass); color: var(--accent-ink); }
.quest-step.failed { border-color: var(--bad); }
.quest-step.failed .quest-badge { background: var(--surface-3); color: var(--bad); box-shadow: inset 0 0 0 2px var(--bad); }
.quest-step.locked { opacity: .6; }
.quest-upload { margin-top: var(--sp-2); }
.quest-side { margin-top: var(--sp-3); border: 1px dashed var(--rule-strong); }
.lang-switch { white-space: nowrap; font-size: var(--fs-sm); padding: 2px 8px; border: 1px solid var(--rule-strong); border-radius: var(--radius-pill); text-decoration: none; }
.pager { display: flex; gap: var(--sp-4); align-items: center; justify-content: center; margin: var(--sp-4) 0; }
@media (max-width: 640px) {
  .rx-bars li { grid-template-columns: 5.5rem 1fr 5.5rem; gap: var(--sp-2); }
  .rx-bars.field-bars li { grid-template-columns: 8.5rem 1fr 3.2rem; }
  .replay-filters label { min-width: 0; flex: 1 1 40%; }
}
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0s !important; animation: none !important; }
}
