:root {
  --bg: #101308;
  --panel: #1a1e10;
  --ink: #eef3d8;
  --dim: #a8b08a;
  --line: #3a4226;
  --good: #7ddf64;
  --bad: #ff5a5a;
  --safe: #6fc3ff;
  --player: #ffd75e;
  /* In-frame overlays sit on the battlefield, so they take its colours: the
     night sky (#00000b) nudged toward EGA blue, edged in EGA blue, with EGA
     light grey text, and key caps in the theme's light accent. */
  --wash: rgba(0, 0, 24, 0.72);
  --wash-solid: rgba(0, 0, 24, 0.88);
  --wash-card: rgba(4, 4, 32, 0.95);
  --wash-edge: rgba(85, 85, 255, 0.55);
  --wash-ink: #aaaaaa;
  --wash-key: var(--accent-hover);
  --wash-head: #0e0e40;
}

/* Themes: the accent palette every panel, button and status-bar highlight
   wears (the battlefield keeps its own colours). <html data-theme> picks one;
   index.html ships the default there and swaps in the saved choice before the
   first paint, and Settings changes it (src/theme.ts). --accent-ink is the text
   on an accent fill, --accent-rgb the accent for translucent tints, --focus the
   focus ring. test/theme.test.ts holds every pair to WCAG AA. Custom has no block
   here: it sets the same five as inline properties on <html>, derived from the
   player's one colour (src/theme.ts). Orange, the default, comes first so any
   other theme's block, equal in specificity to :root, wins by coming after it. */
:root, [data-theme="orange"] { --accent: #ff9f43; --accent-hover: #ffb873; --accent-ink: #111111; --accent-rgb: 255, 159, 67; --focus: #ffd0a1; }
[data-theme="yellow"] { --accent: #ffc93c; --accent-hover: #ffd96e; --accent-ink: #111111; --accent-rgb: 255, 201, 60; --focus: #ffe08a; }
[data-theme="lime"] { --accent: #a3e635; --accent-hover: #bef264; --accent-ink: #111111; --accent-rgb: 163, 230, 53; --focus: #d9f99d; }
[data-theme="cyan"] { --accent: #22d3ee; --accent-hover: #67e8f9; --accent-ink: #111111; --accent-rgb: 34, 211, 238; --focus: #a5f3fc; }
[data-theme="magenta"] { --accent: #f472d0; --accent-hover: #f9a8e4; --accent-ink: #111111; --accent-rgb: 244, 114, 208; --focus: #fbcfe8; }

* { box-sizing: border-box; }

/* Present for screen readers, not drawn (the battlefield shows whose turn). */
.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 1rem/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
}

.topbar {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: end;
  justify-content: space-between;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--line);
}

h1 { margin: 0; font-size: 1.5rem; letter-spacing: 0.02em; }
.tagline { margin: 0.15rem 0 0; color: var(--dim); }

.seedbox { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.seedbox label { color: var(--dim); }

input[type="text"] {
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.4rem 0.6rem;
  max-width: 11rem;
}

/* Secondary buttons (the default) wear the navbar style; .btn-primary and the
   aim pad wear gold, one primary per panel. */
button {
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.45rem 0.8rem;
  font-weight: 700;
  cursor: pointer;
}
button:hover { border-color: var(--accent); }
button.btn-primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
button.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
/* Ready, once pressed, reads as held down until it is pressed again. */
button.btn-primary[aria-pressed="true"] { background: var(--panel); color: var(--accent); box-shadow: inset 0 0 0 2px var(--accent); }
button:focus-visible, input:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
button:disabled { opacity: 0.45; cursor: default; }

/* Key tabs: the look is the kit's .kit-key-tab (a dark keycap, 15px tall,
   label centred). Tankity keeps them in flow inside their buttons, and only a
   mouse or trackpad means a keyboard is at hand, so only then do they show. */
.key {
  --kit-key-tab-position: static;
  display: none;
}
@media (hover: hover) and (pointer: fine) {
  .key { display: inline-flex; }
}
.key:empty { display: none; }

.bark[hidden] { display: none; }

.veil {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 11, 0.82);
  display: grid;
  place-items: center;
  padding: 1rem;
  z-index: 10;
  overflow: auto;
}
.veil[hidden] { display: none; }

.card {
  background: var(--panel);
  border: 1px solid var(--accent);
  border-radius: 12px;
  max-width: 34rem;
  width: 100%;
  padding: 1.25rem 1.4rem;
}
.kicker { color: var(--accent); text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.8rem; margin: 0; }
.card h2 { margin: 0.2rem 0 0.5rem; }

#frame button { font-size: 0.75rem; padding: 0.3rem 0.35rem; white-space: nowrap; }
/* Game menu: a compact centred card. Seed and New Game share a row, the
   unit picker sits under them, and the rest fill equal three-across rows. */
.menu-card {
  inset: 0;
  margin: auto;
  width: min(27rem, 92%);
  height: fit-content;
  max-height: 88%;
  padding: 0.8rem 0.9rem;
}
.menu-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.35rem; }
.menu-grid button { width: 100%; }
.menu-grid > .hint { grid-column: 1 / -1; margin: 0; font-size: 0.8rem; }
.seed-row, .unit-row { grid-column: 1 / -1; display: flex; align-items: center; gap: 0.4rem; }
.seed-row label, .unit-label { font-size: 0.8rem; color: var(--wash-ink); flex: none; }
/* The picker rows share one label column, so their tiles line up. */
.unit-row .unit-label { width: 3.6rem; }
.seed-row input {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.3rem 0.45rem;
}
.seed-row button { width: auto; flex: none; }
.unit-picker { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.3rem; flex: 1; }
.unit-picker .unit-choice { display: grid; justify-items: center; gap: 0.1rem; padding: 0.25rem 0.2rem; }
.unit-picker .text-choice { display: grid; justify-items: center; align-content: end; gap: 0.1rem; padding: 0.25rem 0.2rem; min-height: 3.2rem; }
.text-glyph { font-weight: 800; line-height: 1; }
.unit-choice canvas, .tile-icon { width: 48px; height: 34px; }
.tile-icon { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.tile-toggle[aria-pressed="true"] .off-only, .tile-toggle[aria-pressed="false"] .on-only { display: none; }
#btn-sound[aria-pressed="false"], #btn-music[aria-pressed="false"] { color: var(--dim); }
/* The Sound and Music rows: word, small mute toggle, slider, percent. The toggle and
   the slider's thumb are touch-sized (44 px); the percent has a fixed width so the
   slider does not move as the number gains digits. */
.vol-row { gap: 0.5rem; }
.menu-grid .vol-toggle { display: grid; justify-items: center; align-content: center; gap: 0.1rem; width: 3.4rem; min-width: 44px; min-height: 44px; flex: none; padding: 0.15rem 0; }
.vol-toggle .tile-icon { width: 1.5rem; height: 1.5rem; }
.vol-toggle .key { font-size: 0.6rem; }
.vol-range { flex: 1 1 6rem; min-width: 0; min-height: 44px; margin: 0; accent-color: var(--accent); }
.vol-range:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.vol-range::-webkit-slider-thumb { width: 28px; height: 28px; }
.vol-range::-moz-range-thumb { width: 28px; height: 28px; }
@media (max-width: 600px) {
  .vol-row { gap: 0.3rem; }
  .menu-grid .vol-toggle { width: 44px; }
}
.vol-out { flex: none; width: 2.7rem; text-align: right; font-weight: bold; font-size: 0.85rem; color: var(--accent); font-variant-numeric: tabular-nums; }
.tile-toggle > span { display: grid; justify-items: center; line-height: 1.15; text-align: center; }
.map-label { flex-basis: 100%; color: var(--dim); font-size: 0.9rem; }
.map-picker { flex: 1 1 100%; grid-template-columns: repeat(auto-fill, minmax(5.4rem, 1fr)); }
.map-choice canvas { width: 80px; height: 52px; }
.map-choice { cursor: pointer; }
.unit-choice span { font-size: 0.7rem; }
/* Narrow screens: a tile's word and the Next song button stay inside their borders. */
.unit-picker .m-track { grid-column: span 2; white-space: nowrap; }
@media (max-width: 600px) {
  .tile-toggle > span, .theme-choice > span { font-size: 0.62rem; }
  .unit-picker .tile-toggle { padding-inline: 0.1rem; }
  .unit-picker .theme-choice { padding-inline: 0; }
  /* Five names need the card's whole width: the Theme label sits above them. */
  .unit-row:has(> .theme-picker) { flex-wrap: wrap; row-gap: 0.2rem; }
  .unit-row > .theme-picker { flex-basis: 100%; }
}
.unit-picker button[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); background: rgba(var(--accent-rgb), 0.1); }
/* Theme tiles: five across, each swatch in its own theme's accent (its
   data-theme scopes the palette to the swatch). */
.unit-picker.theme-picker { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0.2rem; }
/* Walls: six picks in two rows of three, so Wraparound fits its tile. */
.unit-picker.walls-picker { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.unit-picker.walls-picker .unit-choice span { overflow-wrap: anywhere; }
.theme-choice { align-content: center; min-height: 3.2rem; }
.theme-swatch { display: block; width: 1.3rem; height: 1.3rem; border-radius: 50%; background: var(--accent); border: 2px solid rgba(255, 255, 255, 0.3); }
.theme-choice[aria-pressed="true"] .theme-swatch { border-color: var(--ink); }
/* Custom: its tile and the colour picker share one line under the five. */
.theme-custom { grid-column: 1 / -1; display: flex; align-items: center; gap: 0.5rem; }
.theme-custom > .theme-choice { flex: 0 0 5.2rem; }
.theme-custom-pick { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 0.5rem; color: var(--dim); font-size: 0.8rem; white-space: nowrap; }
.theme-custom-pick > span { overflow: hidden; text-overflow: ellipsis; }
.theme-custom-pick input[type="color"] { flex: 0 0 auto; width: 2.6rem; height: 2.2rem; padding: 0; border: 2px solid rgba(255, 255, 255, 0.3); border-radius: 8px; background: none; cursor: pointer; }
.theme-custom-pick input[type="color"]:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

.hint { color: var(--dim); font-size: 0.9rem; }
/* Room-server connection dot: red until a ping answers, green while live. */
.dot { display: inline-block; width: 0.7em; height: 0.7em; border-radius: 50%; background: #e5484d; vertical-align: baseline; }
.dot.on { background: #46c26a; }
.invite-row { display: flex; gap: 0.4rem; align-items: center; }
.invite-row input {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.3rem 0.5rem;
  font-size: 0.85rem;
}
.invite-row button { display: inline-flex; gap: 0.35rem; align-items: center; }
.invite-row button svg { width: 1em; height: 1em; }

/* In-frame panels: help, report, and the radio log ride over the battle and
never pause it. The log is a transparent whisper, emoji plus text only. */
.frame-overlay[hidden] { display: none; }
.log-overlay {
  position: absolute;
  top: 6.4rem; /* placeLogBelowStatus() sets the measured value */
  right: 0.5rem;
  width: min(20rem, 42%);
  max-height: 55%;
  overflow-y: auto;
  z-index: 6;
  pointer-events: none;
  /* One panel behind every line, so the battlefield does not show through
     between rows. */
  background: var(--wash-card);
  border: 1px solid var(--wash-edge);
  border-radius: 10px;
  padding: 0.4rem;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
}
.log-transparent {
  max-height: none;
  overflow: visible;
  gap: 0.15rem;
}
.log-transparent li {
  list-style: none;
  background: rgba(85, 85, 255, 0.08);
  border: none;
  border-left: 3px solid var(--wash-edge);
  border-radius: 6px;
  padding: 0.1rem 0.45rem 0.1rem 0.35rem;
  font-size: 0.82rem;
  color: var(--ink);
  text-shadow: 0 1px 2px #000;
}
.log-transparent li.good::before { content: '\2705  '; }
.log-transparent li.bad::before { content: '\1F4A5  '; }
.log-transparent li.info::before { content: '\1F4FB  '; }
.card-overlay {
  position: absolute;
  inset: 8% 6%;
  z-index: 6;
  overflow-y: auto;
  background: var(--wash-card);
  border: 1px solid var(--accent);
  border-radius: 12px;
  padding: 1rem 1.2rem;
}
.card-overlay h2 { margin: 0 0 0.5rem; font-size: 1.05rem; }
.card-overlay button { margin-top: 0.6rem; }
/* Navigation footers: always visible; the scroll keys only show while there
   is something to scroll (aria-disabled="true" means everything fits). */
.nav-hint { color: #ffffff; font-size: 0.8rem; margin: 0.6rem 0 0; text-shadow: 0 1px 2px #000; }
.nav-hint [data-keyhint] { color: var(--wash-key); font-weight: 700; }
/* A panel only scrolls once it has reached its full size, so showing the
   keys then reflows inside it and never resizes it. */
.nav-hint[aria-disabled="true"] .scroll-keys { display: none; }
.nav-hint[data-scroll-only][aria-disabled="true"] { display: none; }
.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0.8rem 1rem;
}
.panel h2 { margin: 0 0 0.5rem; font-size: 1.05rem; }

.runstats { color: var(--dim); font-size: 0.9rem; }

/* This match's scoreboard (src/ui/standings.tsx). */
.board { margin: 0 0 10px; }
.board .kicker { font-size: 0.7rem; letter-spacing: 0.14em; color: var(--dim); text-transform: uppercase; }
.board-title { margin: 2px 0 8px; font-size: 1.1rem; color: var(--accent); }
.board-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
.board-table th { text-align: left; font-size: 0.62rem; letter-spacing: 0.1em; color: var(--dim); font-weight: 600; padding: 3px 4px; border-bottom: 1px solid #3a3fb0; }
.board-table td { padding: 5px 4px; border-bottom: 1px solid #1b2050; white-space: nowrap; }
.board-table .n { text-align: right; }
.board-table tr.me td { background: #141a46; }
.board-table tr.out td { color: #7d84a8; }
.board-table .pl { font-weight: 800; }
.board-table .you { font-size: 0.6rem; color: var(--accent-ink); background: var(--accent); border-radius: 4px; padding: 1px 4px; margin-left: 4px; }
.board-table .delta { color: #7f7; font-size: 0.66rem; margin-left: 3px; }
.board-table .crown { color: var(--accent); }
.board-table tfoot td { font-weight: 800; border-bottom: 0; }
/* In the shop the scoreboard must not squeeze the list or push the page sideways:
 * it keeps to its own band and the longest cell (a room's last column) wraps. */
#shop-veil .board { flex: 0 1 auto; min-height: 0; max-height: 34dvh; overflow-y: auto; min-width: 0; }
#shop-veil .board-table td.last { white-space: normal; }

.help { margin: 0; padding-left: 1.1rem; }
.help li { margin-bottom: 0.35rem; }

.scores { margin: 0.5rem 0 0; padding-left: 1.4rem; display: grid; gap: 0.2rem; }
.scores li { font-variant-numeric: tabular-nums; }
/* min-width: 0 all the way down: a grid or flex child never grows past what
   the screen gives it just to fit its content. */
#shop-veil { grid-template-columns: minmax(0, 1fr); }
/* The card is a column that never outgrows the screen: the list takes what is
   left and scrolls, and Start (and Leave room) stay in a footer below it. */
#shop-veil .card { max-width: 44rem; min-width: 0; display: flex; flex-direction: column; max-height: calc(100dvh - 2rem); overflow-y: auto; }
/* Start sits below the list, never over it: the list gives up the room. */
.shop-foot { flex: none; padding-top: 0.3rem; display: flex; flex-wrap: wrap; align-items: center; gap: 0 0.5rem; }
/* The ready line takes its own row; Start and Leave room sit side by side under it. */
.shop-foot .runstats { flex: 1 0 100%; }
/* The list gives up room first (shrink weight 100); only at its one-row minimum does the board shrink. */
#shop-list { flex: 1 100 auto; min-height: 7.5rem; overflow-y: auto; min-width: 0; padding-left: 0; margin-bottom: 0.7rem; }
/* Two columns: the icon, then the text with Preview and Buy under it. */
#shop-list li { display: grid; grid-template-columns: 72px minmax(0, 1fr); column-gap: 0.75rem; align-items: start; padding: 0.35rem 0.4rem; }
.shop-item { min-width: 0; display: grid; gap: 0.1rem; }
.shop-name { font-weight: 700; }
.shop-vals { display: inline-block; color: var(--wash-key); font-weight: 600; }
.shop-sub { color: var(--dim); font-size: 0.85rem; }
.shop-cat { font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.8rem; color: var(--dim); margin-top: 0.4rem; }
#shop-list li.shop-cat { display: block; }
#shop-list li.sel { background: rgba(255, 255, 255, 0.07); border-radius: 0.4rem; }
#shop-list li .shop-icon { width: 72px; height: 47px; align-self: center; }
#shop-list li .acts { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.35rem 0 0; justify-content: flex-start; }
#shop-list li .acts button { min-width: 0; margin-top: 0; }
/* A short screen (a phone on its side) gives the board a compact strip. */
@media (max-height: 480px) {
  #shop-veil .board { min-height: 3.4rem; max-height: 4.5rem; margin-bottom: 0.3rem; }
  #shop-cash { margin: 0.3rem 0; }
  #shop-list { margin-bottom: 0.3rem; }
  /* The key hints give way, so the list keeps a full row and Start stays in the card. */
  #shop-veil #nav-shop { display: none; }
  .shop-foot .runstats { margin: 0 0 0.2rem; }
  .shop-foot button { margin-top: 0; }
}
/* Wherever the screen is wide enough, the shop is two columns: the board, war
   chest and Start on the left, the list filling the right, so the list shows
   several rows instead of one card's width of them. That is any screen 760 px
   wide, and also a phone on its side (the way most play): under about 520 px
   tall one column cannot stack the board's rows, a full shop row and Start,
   and 4:3 or wider leaves each column room. Portrait phones stay one column.
   The left column stacks from the top; the board gives up height first. */
@media (min-width: 760px), (max-height: 520px) and (min-aspect-ratio: 4/3) {
  #shop-veil .card {
    max-width: 70rem; height: min(calc(100dvh - 2rem), 52rem); max-height: none; overflow: hidden;
    display: grid; column-gap: 1.25rem;
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    grid-template-rows: auto minmax(0, auto) auto 1fr;
    grid-template-areas: "head head" "board list" "cash list" "foot list";
  }
  #shop-veil .ov-head { grid-area: head; }
  #shop-veil .board { grid-area: board; min-height: 0; max-height: none; margin: 0; }
  #shop-cash { grid-area: cash; margin: 0.6rem 0; }
  #shop-list { grid-area: list; min-height: 0; margin: 0; }
  .shop-foot { grid-area: foot; align-self: start; }
}
/* A phone on its side: a one-line header and a tighter board. */
@media (max-height: 520px) and (min-aspect-ratio: 4/3) {
  #shop-veil { padding: 0.5rem; }
  #shop-veil .card { max-width: 60rem; height: calc(100dvh - 1rem); padding-bottom: 0.6rem; column-gap: 1rem; }
  #shop-veil .ov-head { padding-top: 0.4rem; padding-bottom: 0.35rem; margin-bottom: 0.5rem; }
  #shop-veil .ov-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.75rem; }
  #shop-veil .ov-head .kicker { order: 1; margin: 0; }
  #shop-veil .ov-head h2 { font-size: 1.15rem; }
  #shop-veil .board-title { margin-bottom: 4px; }
  #shop-veil .board-table { font-size: 0.75rem; }
  #shop-veil .board-table th, #shop-veil .board-table td { padding-left: 3px; padding-right: 3px; }
  #shop-veil #nav-shop { display: none; }
  #shop-cash { margin: 0.4rem 0; }
}
/* The end card is a column that never outgrows the screen: the scoreboard takes
   what is left and scrolls on its own, and the score line, the filed line and
   the buttons stay in a footer below it. */
#end-veil .card { max-width: 40rem; min-width: 0; display: flex; flex-direction: column; max-height: calc(100dvh - 2rem); overflow: hidden; }
#end-veil .end-board { flex: 1 1 auto; min-height: 4.5rem; overflow-y: auto; min-width: 0; }
#end-veil .end-board .board { margin-bottom: 0.4rem; }
#end-veil .board-table td.last { white-space: normal; }
.end-foot { flex: none; padding-top: 0.3rem; display: flex; flex-direction: column; }
.end-foot p { margin: 0.2rem 0; }
.end-acts { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.3rem; }
.end-acts button { margin-top: 0; }
@media (max-height: 480px) {
  #end-veil .card { padding-top: 0; padding-bottom: 0.6rem; }
  #end-veil #nav-end { display: none; }
  #end-veil #end-text { margin: 0.2rem 0; }
}
/* Phones: the buttons share the text column's width in equal halves (a lone
   Preview takes all of it), so nothing sets the card wider than the screen. */
@media (max-width: 600px) {
  #shop-list li .acts button { flex: 1 1 0; }
}
/* One line, always: the hit text never resizes the firing range. */
#preview-result { min-height: 1.5em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#preview-stage { width: 100%; height: auto; border-radius: 6px; background: #10131c; }

.banner { position: absolute; top: 50%; left: 0; right: 0; text-align: center;
  transform: translateY(-50%);
  pointer-events: none; z-index: 5; }
.banner[hidden] { display: none; }
.banner span { display: inline-block; font-size: 1.6rem; font-weight: 800; color: #fff;
  background: var(--wash-solid); border: 1px solid var(--accent); border-radius: 10px;
  padding: 0.5rem 1.2rem; animation: bannerpop 1.5s ease-out; }
@keyframes bannerpop {
  0% { transform: scale(0.7); opacity: 0; }
  15% { transform: scale(1.05); opacity: 1; }
  30% { transform: scale(1); }
  80% { opacity: 1; }
  100% { opacity: 0; }
}

.lobby-rows { display: grid; gap: 0.8rem; margin: 0.6rem 0; }
.lobby-rows[hidden] { display: none; }
.lobby-form { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: 8px; padding: 0.6rem 0.7rem; }
.lobby-form label { color: var(--dim); font-size: 0.9rem; }
.lobby-form input { max-width: 6rem; text-transform: none; }
.lobby-form select {
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.4rem 0.6rem;
  max-width: 10rem;
}
#join-code { max-width: 7rem; text-transform: uppercase; }
.room-code { font-size: 2rem; font-weight: 800; letter-spacing: 0.4em; margin: 0.4rem 0 0;
  color: var(--accent); }
/* A six-character code in two halves, K7Q 2MX: the gap is drawn, so the text stays one code. */
.room-code .code-half + .code-half { margin-left: 0.5em; }
/* Lobby seats: the unit-picker tile look, initials large, one line under. */
.seat-grid { margin: 0.5rem 0; }
.seat-tile { display: grid; justify-items: center; align-content: center; gap: 0.15rem; min-height: 3.6rem; }
.seat-tile .seat-name { font-size: 1.15rem; font-weight: 800; letter-spacing: 0.08em; line-height: 1.1; }
.seat-tile .seat-cap { font-size: 0.68rem; color: var(--dim); }
.seat-tile[data-mode="human"] { border-color: var(--accent); color: var(--accent); background: rgba(var(--accent-rgb), 0.1); }
.seat-tile.seat-open { color: var(--dim); border-style: dashed; }
.seat-tile.seat-fixed { cursor: default; }
.seat-tile.seat-fixed:hover { border-color: var(--line); }
.seat-tile[data-mode="human"].seat-fixed:hover { border-color: var(--accent); }
/* Leaving is the one red way out: never gold, so it is never the easy tap. */
button.btn-leave { border-color: var(--bad); color: var(--bad); }
button.btn-leave:hover { background: rgba(255, 80, 80, 0.12); border-color: var(--bad); }
button.btn-leave[hidden] { display: none; }
.card .acts { display: flex; gap: 0.4rem; margin-left: auto; justify-content: flex-end; margin-top: 0.6rem; }

.log {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 16rem;
  overflow-y: auto;
  display: grid;
  gap: 0.35rem;
}
.log li {
  border-left: 3px solid var(--line);
  padding-left: 0.55rem;
}
.log li.good { border-color: var(--good); }
.log li.bad { border-color: var(--bad); }
.log li.info { border-color: var(--safe); }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* Touch screens have no keyboard: no key caps, key footers or key prose. */
.touch-only { display: none; }
.touch .touch-only { display: revert; }
.touch .key, .touch .keys-only, .touch .nav-hint { display: none; }

/* Overlay title bars: title and close on top, the panel's keys in a grid
   below. They stay pinned while the panel scrolls. Each container sets its
   side padding in --px so the bar can run edge to edge. */
.card { --px: 1.4rem; padding-top: 0; }
.card-overlay { --px: 1.2rem; padding-top: 0; }
.log-overlay { --px: 0.4rem; padding-top: 0; }
.ov-head {
  position: sticky;
  top: 0;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.35rem 0.6rem;
  margin: 0 calc(-1 * var(--px)) 0.7rem;
  padding: 0.7rem var(--px) 0.5rem;
  background: var(--wash-head);
  border-bottom: 1px solid var(--wash-edge);
  border-radius: 11px 11px 0 0;
}
.ov-head.has-tools { grid-template-columns: minmax(0, 1fr) auto auto; }
.ov-tools { display: flex; align-items: center; gap: 0.4rem; }
.ov-title { min-width: 0; }
.ov-head h2, .card .ov-head h2, .card-overlay .ov-head h2 { margin: 0; }
.ov-head .kicker { margin-bottom: 0.1rem; }
.ov-head .ov-x, .card-overlay .ov-head .ov-x {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.2rem 0.5rem;
  font-size: 1.25rem;
  line-height: 1;
  pointer-events: auto;
}
.ov-x .x-glyph { font-size: 1.35rem; line-height: 0.8; font-weight: 400; }
.log-overlay .ov-x .x-glyph { font-size: 1.1rem; }
.ov-keys {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.15rem 0.6rem;
  margin: 0;
  font-size: 0.75rem;
}
/* A hint that does not fit its cell wraps between its words, and a chip wider than the cell (wider fonts) wraps rather than spilling out. */
.ov-keys > span { text-align: center; min-width: 0; overflow-wrap: anywhere; }
.log-overlay .ov-head { margin-bottom: 0.3rem; padding-top: 0.35rem; border-radius: 9px 9px 0 0; }
.log-overlay .ov-head h2 { font-size: 0.85rem; }
.log-overlay .ov-keys { font-size: 0.68rem; }
.log-overlay .ov-x { font-size: 1rem; padding: 0.1rem 0.4rem; }

/* Weapon picker: the rack as tiles, four across. */
.gun-card { inset: 0; margin: auto; width: min(34rem, 92%); height: fit-content; max-height: 84%; padding-bottom: 0.9rem; }
.gun-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.4rem; }
.gun-choice { display: grid; justify-items: center; gap: 0.1rem; padding: 0.35rem 0.25rem; margin: 0; }
.card-overlay .gun-choice { margin-top: 0; }
.gun-choice canvas { width: 48px; height: 31px; }
.gun-choice .gun-count { color: var(--wash-ink); font-size: 0.75rem; }
.gun-choice[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); background: rgba(var(--accent-rgb), 0.1); }
.gun-choice.cursor { outline: 2px solid var(--wash-key); outline-offset: 1px; }
/* None in stock: greyed, but still a button the cursor and pointer reach. */
.gun-choice[aria-disabled="true"] { color: var(--wash-ink); border-style: dashed; }
.gun-choice[aria-disabled="true"] canvas { opacity: 0.35; filter: grayscale(1); }
/* All guns or only those in stock: a 44 px target in the title bar. */
.card-overlay .ov-tools .gun-stock { margin: 0; min-height: 44px; padding: 0.3rem 0.8rem; white-space: nowrap; }

.touch .gun-choice.cursor { outline: none; }

/* Help's key list: each key as a cap (always shown, unlike the button chips:
   the whole list is keyboard-only), its job beside it. */
.help-keys h3 { margin: 0.8rem 0 0.3rem; font-size: 0.85rem; color: var(--wash-key); }
.help-keys dl { display: grid; grid-template-columns: max-content 1fr; gap: 0.25rem 0.7rem; margin: 0; }
.help-keys dl > div { display: contents; }
.help-keys dt { white-space: nowrap; }
.help-keys dd { margin: 0; }
.hk {
  display: inline-flex; align-items: center; justify-content: center; height: 1.15rem; padding: 0 0.35rem;
  font: 700 0.72rem/1 system-ui, sans-serif; color: #eef0ff; background: #14183a;
  border: 1px solid #3a3f78; border-bottom: 2px solid #000; border-radius: 4px;
}

/* The title card's mount point adds no box of its own. */
#title-root { display: contents; }
/* The title card over the dimmed demo. It covers the battlefield only, so the
   bars stay usable, and sits under the in-frame panels: the menu opens over it. */
.title-veil {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 0.5rem;
  background: rgba(5, 6, 15, 0.55);
  border-radius: 6px;
  z-index: 3;
  overflow: auto;
}
.title-veil[hidden] { display: none; }
.title-card {
  width: min(78%, 20rem);
  padding: 0.9rem 1rem;
  text-align: center;
  color: #eef;
  background: #0c0f2e;
  border: 1px solid var(--accent);
  border-radius: 12px;
}
.title-card h2 { margin: 0 0 0.25rem; font-size: 1.15rem; letter-spacing: 0.04em; color: var(--accent); text-transform: uppercase; }
.title-tag { margin: 0 0 0.6rem; font-size: 0.75rem; color: #9aa3c7; }
/* Play and Share share one row that never wraps: Play takes what Share leaves, Share is a square as tall as Play. */
.title-primary { display: flex; gap: 0.4rem; margin-bottom: 0.45rem; }
#frame .title-play {
  display: flex; align-items: center; justify-content: center; gap: 0.35rem;
  flex: 1 1 0; min-width: 0; min-height: 44px; padding: 0.65rem; font-size: 1rem; font-weight: 800; border-radius: 9px;
}
/* Share: the secondary accent outline (as Tutorial), so it follows every theme. */
#frame .title-share {
  flex: none; display: grid; place-items: center; width: 44px; min-width: 44px; min-height: 44px; padding: 0;
  background: rgba(var(--accent-rgb), 0.12); border: 1.5px solid var(--accent); color: var(--accent); border-radius: 9px;
}
#frame .title-share:hover { background: rgba(var(--accent-rgb), 0.22); }
/* "Link copied" shows in the card; empty, it stays in the page for a screen reader and takes no room. */
.title-share-status:empty { position: absolute; width: 1px; height: 1px; margin: 0; overflow: hidden; clip-path: inset(50%); }
.title-share-status:not(:empty) { margin: -0.2rem 0 0.4rem; color: var(--accent); }
.title-share-url { box-sizing: border-box; width: 100%; margin: -0.2rem 0 0.4rem; padding: 0.35rem 0.5rem; font: 500 0.85rem/1.2 ui-monospace, monospace; }
.title-row { display: flex; gap: 0.4rem; margin-bottom: 0.5rem; }
#frame .title-row button, #frame .title-settings { flex: 1; padding: 0.45rem; background: #11163a; border-color: #3a3fb0; border-radius: 9px; }
#frame .title-settings { display: block; width: 100%; margin-top: 0.1rem; }
/* Tutorial: secondary to Play, but the one that says "start here": an accent
   outline and tint with a cap, never Play's solid fill. */
#frame .title-row .title-tutorial { background: rgba(var(--accent-rgb), 0.12); border: 1.5px solid var(--accent); color: var(--accent); }
#frame .title-row .title-tutorial:hover { background: rgba(var(--accent-rgb), 0.22); }
.title-tutorial-icon { margin-right: 0.3rem; }
.initials { display: flex; justify-content: center; align-items: center; gap: 0.3rem; border: 0; margin: 0 0 0.2rem; padding: 0; }
.initials legend { float: left; margin-right: 0.4rem; font-size: 0.75rem; color: #9aa3c7; }
input.initial { width: 2rem; height: 2rem; max-width: none; padding: 0; text-align: center; font-size: 1rem; font-weight: 800; text-transform: uppercase; }
/* An installed app that could not close itself says how, on the card. */
.title-hint { margin: 0 0 0.3rem; font-size: 0.8rem; font-weight: 600; color: #cdd3f0; }
.title-note { min-height: 1em; margin: 0 0 0.3rem; font-size: 0.72rem; color: var(--bad); }
/* The demo's own "press Play" banner would sit over the card. */
#title-root:has(.title-veil:not([hidden])) ~ .banner { display: none; }
/* Phones, portrait or landscape: the card fills the whole battlefield instead
   of the canvas-shaped box, so every control is in reach without an inner
   scroll; the bars and Menu stay usable around it. */
@media (max-width: 600px), (max-height: 480px) {
  .title-veil {
    z-index: 5; /* over the deck (4) inside the battlefield; the panels (6, 10) open above it */
    aspect-ratio: auto;
    border-radius: 0;
    padding: 0.4rem;
    background: rgba(5, 6, 15, 0.85);
  }
  .title-card { width: min(100%, 24rem); padding: 0.7rem 0.8rem; }
  #frame .title-play { padding: 0.9rem; }
}
@media (max-height: 480px) {
  .title-card { padding: 0.4rem 0.8rem; }
  .title-card h2 { font-size: 1rem; margin-bottom: 0.1rem; }
  .title-tag { margin-bottom: 0.3rem; }
  #frame .title-play { padding: 0.5rem; }
  .title-primary { margin-bottom: 0.3rem; }
  .title-row { margin-bottom: 0.3rem; }
  .title-note { margin-bottom: 0; }
}
/* Thumb-sized on touch screens. */
@media (pointer: coarse) {
  #frame .title-play, #frame .title-row button, #frame .title-settings { min-height: 44px; }
  input.initial { width: 44px; height: 44px; }
}

/* ---------- the frame: status bar, battlefield, control deck ----------
   The page is one screen tall: the header, then the frame's three parts, the
   battlefield taking what is left, edge to edge and touching both bars, so no
   band of page shows between them. The bars size in px so the text-size
   setting (which scales the panels) never pushes them over; their
   breakpoints follow the frame's own width. */
body { height: 100dvh; display: flex; flex-direction: column; }
.topbar { flex: none; padding: 0.5rem 1.25rem; }
.layout { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1120px); justify-content: center; padding: 0.5rem; }
#frame { container-type: inline-size; height: 100%; min-height: 0; }
.canvas-holder {
  position: relative; display: flex; flex-direction: column; gap: 0; height: 100%; width: 100%; margin: 0;
  padding: 6px; background: #05060a; border: 1px solid var(--line); border-radius: 10px; user-select: none;
}
.field { position: relative; flex: 1; min-height: 0; margin: 0 -6px; display: grid; grid-template: minmax(0, 1fr) / minmax(0, 1fr); place-items: center; }
#stage { display: block; width: 100%; height: 100%; justify-self: stretch; align-self: stretch; }
#frame:fullscreen { background: var(--bg); padding: 0.5rem; width: 100%; height: 100%; overflow: hidden; }
#frame:fullscreen .canvas-holder { max-width: 1600px; margin: 0 auto; }

/* Status bar: Menu, angle, power, fuel, the AMMO, ARMOR, lives and WIND
   pills, and the match badge at the far end. */
#hud-bar { flex: none; }
#hud-bar .runstats { display: none; }
.hud {
  display: flex; align-items: center; gap: 10px; min-width: 0; padding: 5px 8px;
  background: #0c0f2e; border: 1px solid #3a3fb0; border-radius: 9px; color: #eef;
  font: 13px/1.2 system-ui, -apple-system, "Segoe UI", sans-serif; white-space: nowrap;
}
.hud-row { display: contents; }
.hud .k { color: #9aa3c7; font-size: 0.78em; letter-spacing: 0.06em; }
.hud .v { color: #7f7; font-weight: 800; font-variant-numeric: tabular-nums; }
.hud .stat { flex: none; }
.hud .short { display: none; }
#frame .menu-btn {
  display: inline-flex; align-items: center; gap: 6px; flex: none; height: 26px; padding: 0 9px;
  font: 800 13px/1 system-ui, sans-serif; color: var(--accent-ink); background: var(--accent); border: 1px solid var(--accent); border-radius: 6px;
}
.menu-icon { width: 14px; height: 14px; }
.pill { display: inline-flex; align-items: center; gap: 5px; flex: none; padding: 2px 9px; background: #11163a; border: 1px solid #5a63e0; border-radius: 999px; }
.pill.ammo { border-color: #ffb13c; }
.pill.ammo .v { color: #ffb13c; }
.pill.armor { border-color: #7ddf64; }
.pill.lives { border-color: #ff5c8a; }
.pill.lives .v, .pill.lives .hearts { color: #ff5c8a; }
.seg { display: inline-flex; align-items: stretch; flex: none; margin-left: auto; border: 1px solid #3a3fb0; border-radius: 8px; overflow: hidden; }
.seg > span { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; }
.seg > span + span { border-left: 1px solid #3a3fb0; }
.seg .cash .v { color: var(--accent); }
.seg .dot { margin-left: 4px; }

/* Control deck: Aim, Drive, More, Weapon and a big FIRE, each labelled. Chips
   sit at the foot of their button, so chips in a row line up. */
#deck {
  --chip: 4px;
  flex: none; display: flex; align-items: flex-end; justify-content: space-between; gap: 10px;
  padding: 8px; background: #0c0f2e; border: 1px solid #3a3fb0; border-radius: 10px;
}
@media (hover: hover) and (pointer: fine) { #deck { --chip: 18px; } }
.touch #deck { --chip: 4px; }
.grp { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.gl { font: 9px/1.2 system-ui, sans-serif; letter-spacing: 0.12em; color: #9aa3c7; text-transform: uppercase; }
#deck .row { display: flex; gap: 5px; }
.aim-pad { display: grid; grid-template-columns: repeat(3, auto); gap: 4px; }
#frame #deck .btn {
  position: relative; display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  min-width: 48px; height: 55px; padding: 4px 8px var(--chip); border: 1.5px solid var(--c, #667); border-radius: 9px;
  background: #0a0d26; color: #eef; font: 700 11px/1.15 system-ui, sans-serif; white-space: nowrap;
}
#deck .btn .ic { font-size: 14px; line-height: 1; color: var(--c); }
#frame #deck .btn.gold { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
#deck .btn.gold .ic { color: var(--accent-ink); }
#frame .aim-pad .btn { height: 54px; }
#deck .w-narrow { display: none; }
#deck .key { --kit-key-tab-position: absolute; --kit-key-tab-top: auto; --kit-key-tab-right: auto; left: 50%; bottom: 3px; transform: translateX(-50%); }
#frame #deck .weap { min-width: 96px; }
#frame #deck .grp-drive .btn { min-width: 76px; }
#deck .gun { display: flex; flex-direction: column; align-items: center; gap: 2px; }
#deck .gun-top { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 800; }
#deck .gun-icon { width: 28px; height: 18px; }
#deck .gun-line { font-size: 10px; font-weight: 700; color: #ffb13c; }
#frame #deck .fire {
  position: relative; display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  width: 120px; height: 55px; padding: 0 0 var(--chip); border: 0; border-radius: 12px; background: #c42222; color: #fff;
  font: 900 16px/1 system-ui, sans-serif; box-shadow: 0 0 0 4px rgba(238, 51, 51, 0.3);
}
#deck [aria-expanded="true"] { box-shadow: 0 0 0 2px var(--c, var(--accent)); }
.phone-extras { display: none; }
/* Touch screens: no chips, thumb-sized targets. */
.touch #frame #deck .btn { height: 46px; min-width: 46px; font-size: 10px; padding: 2px 5px; }
.touch #frame .aim-pad .btn { height: 44px; }
.touch #frame #deck .fire { height: 46px; }
.touch #frame .menu-btn { height: 44px; min-width: 44px; }

/* Chatter: a one-line toast at the top of the battlefield. */
#dialogue {
  position: absolute; top: 8px; left: 50%; transform: translateX(-50%); z-index: 2;
  display: flex; align-items: center; max-width: calc(100% - 16px); padding: 3px 9px;
  background: rgba(12, 15, 46, 0.88); border: 1px solid #3a3fb0; border-radius: 7px;
  font-size: 0.72rem; line-height: 1.3; white-space: nowrap; pointer-events: none;
}
#dialogue[hidden] { display: none; }
#dialogue > canvas { display: none; }
#dialogue > div { display: flex; gap: 0.4rem; min-width: 0; }
#dialogue span + span { overflow: hidden; text-overflow: ellipsis; }
#dialogue span:first-child { font-weight: 800; letter-spacing: 0.04em; }

/* The FF button (the game speed): the battlefield's top right corner, just
   under the status bar, over the hills (z 3: under the deck, the title card
   and the panels). The chatter and the Next song toast are centred, so they
   stop --ff-room short of both sides and never run under it; the sky marks
   leave it clear too (render.ts, view.ts skyInset). */
.field { --ff-room: 92px; }
.touch .field { --ff-room: 76px; }
#frame .speed-btn {
  position: absolute; top: 8px; right: 8px; z-index: 3;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  height: 32px; min-width: 56px; padding: 0 8px;
  background: rgba(10, 13, 38, 0.9); color: #eef; border: 1.5px solid #6fe4ff; border-radius: 9px;
  font: 800 14px/1 system-ui, -apple-system, "Segoe UI", sans-serif; font-variant-numeric: tabular-nums; white-space: nowrap;
}
#frame .speed-btn[hidden] { display: none; }
.speed-btn .ic { color: #6fe4ff; font-size: 9px; letter-spacing: -2px; }
#frame .speed-btn[aria-disabled="true"] { border-color: #5a63a0; cursor: default; }
#frame .speed-btn[aria-disabled="true"] .ic { color: #9aa3c7; }
.touch #frame .speed-btn { height: 44px; min-width: 60px; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* The Next song announcement: one line inside the battlefield, under the
   chatter toast (#dialogue sits at top: 8px and is under 32 px tall), clipped
   with an ellipsis rather than wrapped. It shows over the title card (5) and
   the menu (6), since a phone's Next song is a menu row that leaves the menu
   open; it never takes a tap. */
.track-toast {
  position: absolute; top: 44px; left: 50%; transform: translateX(-50%); z-index: 7;
  max-width: calc(100% - 16px); padding: 3px 10px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  background: rgba(12, 15, 46, 0.88); border: 1px solid var(--accent); border-radius: 999px;
  color: #fff; font-weight: 700; font-size: 0.72rem; line-height: 1.3;
  pointer-events: none;
}
.track-toast[hidden] { display: none; }
/* Both stop short of the FF button on either side (see .speed-btn). */
#dialogue, .track-toast { max-width: calc(100% - 2 * var(--ff-room)); }

/* "Turn sideways": a small chip at the bottom of the battlefield, in portrait only. */
#rotate-hint-root { display: contents; }
.rotate-hint {
  position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); z-index: 3; /* at the foot, clear of the chatter toast at the top */
  display: flex; align-items: center; gap: 6px; padding: 2px 4px 2px 12px;
  background: rgba(12, 15, 46, 0.92); border: 1px solid #3a3fb0; border-radius: 999px;
  color: #eef; font: 600 12px/1.2 system-ui, sans-serif; white-space: nowrap;
}
#frame .rotate-x { min-width: 44px; min-height: 44px; padding: 0; background: none; border: 0; color: #9aa3c7; font-size: 18px; }
@media (orientation: landscape) { .rotate-hint { display: none; } }

/* The frame's own width decides: short labels, then an 11 px bar, then no chips. */
@container (max-width: 1100px) {
  .hud { font-size: 12px; gap: 7px; }
  .hud .full { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .hud .short { display: inline; }
}
@container (max-width: 860px) {
  .hud { font-size: 11px; gap: 6px; padding: 4px 6px; }
  .pill { padding: 1px 7px; }
  .seg > span { padding: 1px 6px; }
}
@container (max-width: 760px) {
  .hud { gap: 4px; padding: 3px 4px; }
  .pill { padding: 1px 5px; gap: 3px; }
  .seg > span { padding: 1px 4px; gap: 3px; }
  #frame .menu-btn { height: 24px; padding: 0 7px; }
  .key { display: none !important; }
  #deck { --chip: 4px; }
}

/* Portrait phone: no page header; the status bar in three rows (Menu and the
   aim numbers, the four pills, the badge across); the deck without headings,
   Weapon on FIRE beside the arrows (its top level with ▲), Drive, Radio and
   Help along the foot; Next song moves to the Menu. */
@media (orientation: portrait) and (max-width: 600px) {
  .topbar { display: none; }
  .layout { padding: 4px; }
  .hud { flex-direction: column; align-items: stretch; gap: 4px; }
  .hud-row { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
  .seg { flex: 1; margin-left: 0; justify-content: space-around; }
  #deck { display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "aim weapon" "aim fire" "drive more"; gap: 6px; align-items: stretch; }
  .grp-aim { grid-area: aim; }
  .grp-weapon { grid-area: weapon; align-items: stretch; }
  .grp-fire { grid-area: fire; align-items: stretch; }
  .grp-drive { grid-area: drive; align-items: flex-start; }
  .grp-more { grid-area: more; align-items: flex-end; }
  .gl { display: none; }
  .grp { gap: 0; }
  #frame #deck .weap { width: 100%; height: 44px; }
  #frame #deck .fire { width: 100%; height: auto; min-height: 44px; }
  #frame #deck #btn-track { display: none; }
  #deck .w-wide { display: none; }
  #deck .w-narrow { display: inline; }
  .phone-extras { display: flex; }
  #frame .phone-extras .m-radio, #frame .phone-extras .m-help { display: none; }
}

/* Landscape phone: no page header; the controls float over the battlefield's
   lower corners (arrows left, Drive centre, Weapon above FIRE right) and the
   arrow keys turn translucent so the hills show through; Radio, Help and
   Next song move to the Menu. */
@media (orientation: landscape) and (max-height: 500px) {
  .topbar { display: none; }
  .layout { padding: 4px; }
  #deck {
    position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 4;
    display: grid; grid-template-columns: auto 1fr auto; grid-template-areas: "aim drive weapon" "aim drive fire";
    align-items: end; align-content: end; row-gap: 8px; padding: 0; background: none; border: 0; pointer-events: none;
  }
  #deck > * { pointer-events: auto; }
  .gl, .grp-more { display: none; }
  .grp-aim { grid-area: aim; }
  .grp-drive { grid-area: drive; justify-self: center; align-self: end; }
  .grp-aim { align-self: end; }
  .grp-weapon { grid-area: weapon; }
  .grp-fire { grid-area: fire; }
  #frame #deck .weap { width: 96px; height: 44px; }
  #frame #deck .fire { width: 96px; height: 46px; }
  #frame #deck .btn.gold { background: rgba(var(--accent-rgb), 0.55); border-color: rgba(var(--accent-rgb), 0.9); color: #fff; text-shadow: 0 0 2px #000, 0 1px 2px #000; }
  #deck .btn.gold .ic { color: #fff; }
  #deck .w-wide { display: none; }
  #deck .w-narrow { display: inline; }
  .phone-extras { display: flex; }
}

/* The Scores overlay: the player's own rows in gold, and a board switcher with full-size touch targets. */
.scores li.mine { color: var(--accent); font-weight: 700; }
.scores-h { margin: 0.8rem 0 0.2rem; font-size: 0.95rem; }
.scores-levels { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 8px; }
.scores-levels button { min-height: 44px; min-width: 44px; padding: 0 14px; }
.scores-levels button[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); }

/* The turn-time slider (src/ui/turn-time.tsx): label, range and its value on
   one line that wraps on a phone. */
.turn-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.5rem 0;
}
.turn-range {
  flex: 1 1 9rem;
  min-width: 0;
  accent-color: var(--accent);
}
.turn-range:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.turn-out {
  min-width: 8.5em;
  font-weight: bold;
  color: var(--accent);
}

/* Your games (src/ui/games.tsx): one row per room, its words and Open. */
.your-games {
  margin: 0.75rem 0;
  text-align: left;
}
.your-games h3 {
  margin: 0 0 0.35rem;
  font-size: 1rem;
}
.games-list {
  list-style: none;
  margin: 0 0 0.5rem;
  padding: 0;
  display: grid;
  gap: 0.35rem;
}
.game-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}
.game-row.your-turn .game-text { color: var(--accent); }
.game-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}
.game-open { flex: 0 0 auto; }

/* The turn toasts (src/ui/toast.tsx), stacked at the bottom, above the veils. */
.toasts {
  position: fixed;
  left: 50%;
  bottom: 1rem;
  transform: translateX(-50%);
  width: min(28rem, calc(100% - 2rem));
  display: grid;
  gap: 0.5rem;
  z-index: 20;
  pointer-events: none;
}
.toast {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.75rem;
  background: var(--wash-card);
  border: 1px solid var(--accent);
  border-radius: 6px;
  color: var(--ink);
  pointer-events: auto;
}
.toast-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}
.toast-go, .toast-x { flex: 0 0 auto; }

/* The tutorial's coach marks (src/ui/tutorial.tsx): a layer over the whole
   frame, veils included, that never takes a tap itself. The spotlight's
   shadow dims everything but the target; the bubble beside it is the one
   thing that takes taps. While the target is off screen the marks wait,
   hidden, and the game shows undimmed. */
.coach { position: fixed; inset: 0; z-index: 15; pointer-events: none; overflow: hidden; }
.coach[hidden] { display: none; }
.coach-spot {
  position: absolute; border-radius: 10px; pointer-events: none;
  box-shadow: 0 0 0 200vmax rgba(0, 0, 8, 0.55);
}
[data-coach-target] { outline: 3px solid var(--focus) !important; outline-offset: 2px; }
.coach-bubble {
  position: absolute; left: 8px; top: 8px; width: min(17rem, calc(100% - 16px)); pointer-events: auto;
  padding: 0.55rem 0.7rem 0.6rem; background: var(--wash-card); color: var(--ink);
  border: 2px solid var(--accent); border-radius: 10px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55);
  font-size: 0.85rem; line-height: 1.35; text-align: left;
}
.coach-bubble[data-waiting] { visibility: hidden; }
.coach-bubble:focus { outline: none; }
.coach-bubble:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
/* The arrow: a rotated square on the edge that faces the target. */
.coach-bubble::before {
  content: ''; position: absolute; width: 12px; height: 12px; background: var(--wash-card);
  border: 2px solid var(--accent); border-width: 2px 0 0 2px;
}
.coach-bubble[data-side="below"]::before { top: -8px; left: calc(var(--arrow, 50%) - 7px); transform: rotate(45deg); }
.coach-bubble[data-side="above"]::before { bottom: -8px; left: calc(var(--arrow, 50%) - 7px); transform: rotate(225deg); }
.coach-bubble[data-side="right"]::before { left: -8px; top: calc(var(--arrow, 50%) - 7px); transform: rotate(-45deg); }
.coach-bubble[data-side="left"]::before { right: -8px; top: calc(var(--arrow, 50%) - 7px); transform: rotate(135deg); }
.coach-bubble[data-side="none"]::before { display: none; }
.coach-count { margin: 0 0 0.2rem; font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent); font-weight: 700; }
.coach-text { margin: 0; font-weight: 600; }
.coach-keys { margin: 0.3rem 0 0; font-size: 0.78rem; color: var(--dim); }
.coach-keys .hk { margin: 0 0.1rem; }
.coach-acts { display: flex; justify-content: flex-end; gap: 0.4rem; margin-top: 0.5rem; }
#frame .coach-acts button { margin: 0; min-height: 36px; padding: 0.3rem 0.8rem; font-size: 0.8rem; display: inline-flex; align-items: center; gap: 0.35rem; }
.touch #frame .coach-acts button { min-height: 44px; }
