:root {
  --bg: #16131f;
  --panel: rgba(22, 19, 34, 0.86);
  --edge: rgba(255, 255, 255, 0.12);
  --text: #f1eef8;
  --muted: #a9a3bb;
  --accent: #ff4d2e;
  --accent-2: #ffb300;
  --focus: #00e5ff;
  --display: 'Chakra Petch', system-ui, sans-serif;
  --body: 'Inter', system-ui, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--body);
  overflow: hidden;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

#game-root {
  position: fixed;
  inset: 0;
}

/* The race's end: the track and the HUD fade out, then the results fade in
   (see `onOver` in main.ts). The next race fades back in the same way. */
#game-root, .screen.hud { transition: opacity 1s ease; }
body.race-out #game-root, body.race-out .screen.hud { opacity: 0; }
@media (prefers-reduced-motion: reduce) { #game-root, .screen.hud { transition: none; } }

.game-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.ui-root {
  position: fixed;
  inset: 0;
  pointer-events: none;
}

/* A `hidden` screen must really be gone: an author `display` rule beats the
   attribute, and an invisible full-screen overlay swallows every click. */
.screen[hidden] { display: none !important; }

.screen {
  position: absolute;
  inset: 0;
}

/* ------------------------------------------------------------------ menus */

.screen.menu {
  display: grid;
  /* "safe": a card taller than the window starts at the top and scrolls,
     rather than being centred off both ends with its buttons unreachable
     (the lobby at 640x400, or any phone held landscape). */
  place-items: safe center;
  overflow-y: auto;
  pointer-events: auto;
  background:
    radial-gradient(ellipse at 30% 20%, rgba(255, 77, 46, 0.18), transparent 60%),
    radial-gradient(ellipse at 80% 90%, rgba(0, 229, 255, 0.12), transparent 55%),
    var(--bg);
  padding: 16px;
}

.menu-card {
  width: min(440px, 100%);
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: 14px;
  padding: 28px 24px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
}

.title {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(34px, 9vw, 52px);
  line-height: 0.95;
  letter-spacing: 0.02em;
  margin: 0 0 8px;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-style: italic;
}

h2 {
  font-family: var(--display);
  margin: 0 0 16px;
}

.tagline { color: var(--muted); margin: 0 0 24px; }
.menu-note { color: var(--muted); font-size: 13px; margin: 16px 0 0; }
.version { color: var(--muted); font-size: 12px; margin: 12px 0 0; opacity: 0.7; }
/* The version on the left, a link to the changelog on the right, one line. */
.version-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin: 12px 0 0; }
.version-row .version { margin: 0; }
.changelog-link { text-decoration: none; }
.changelog-link:hover, .changelog-link:focus-visible, .changelog-link.nav-focus { text-decoration: underline; opacity: 1; }

.menu-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 8px;
}

.btn {
  font: 600 16px var(--display);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--edge);
  border-radius: 10px;
  padding: 13px 18px;
  cursor: pointer;
  pointer-events: auto;
}

.btn:hover { background: rgba(255, 255, 255, 0.12); }
/* Join before the code is whole: plainly not ready, and skipped by the focus ring. */
.btn:disabled { opacity: 0.45; cursor: default; }
.btn.primary { background: linear-gradient(90deg, var(--accent), #e8336a); border-color: transparent; }
.btn.small { font-size: 12px; padding: 8px 12px; }

.btn:focus-visible, select:focus-visible, input:focus-visible, .nav-focus {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 12px;
}

.field.check { justify-content: flex-start; }
/* Big enough to read across a room: the browser's own box is 13px. */
.field.check input { width: 20px; height: 20px; margin: 0; accent-color: var(--accent); }
/* A row's display: flex would otherwise beat the hidden attribute. */
.field[hidden], .seed-row[hidden] { display: none; }

/* The seed and its dice on one line: the dice is only a glyph, so it sits at the end of the box. */
.seed-row { display: flex; align-items: stretch; gap: 8px; margin: 0 0 12px; }
.seed-row .field { flex: 1 1 auto; min-width: 0; margin: 0; }
.seed-row input { min-width: 0; }
/* As tall as the seed box beside it (44 px), and as wide, with the dice filling it (#15). */
.btn.dice { flex: none; align-self: stretch; width: 44px; display: grid; place-items: center; font-size: 28px; line-height: 1; padding: 0; }

/* The track chooser's star (#14): a favourite is a gold one. */
.btn.fav { flex: none; align-self: stretch; width: 44px; display: grid; place-items: center; font-size: 24px; line-height: 1; padding: 0; }
.btn.fav.on { color: #ffc93c; }
/* The Track of the Day has no second choice: its row keeps its place, empty, so nothing below jumps. */
.pick-row.blank { visibility: hidden; }
.track-pick { min-width: 0; }
.track-pick .seed-row { margin: 0 0 12px; }

select {
  font: 15px var(--body);
  color: var(--text);
  background: #241f33;
  border: 1px solid var(--edge);
  border-radius: 8px;
  padding: 8px 10px;
}

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

/* The HUD's scale, set from the window's size (main.ts): 1 up to a laptop's
   window, up to about 1.8 on a QHD desktop. The TV layout zooms the overlay instead. */
:root { --hud: 1; --hud-big: 1; }
body.tv { --hud: 1; --hud-big: 1; }
.hud-top, .hud-race, .hud-bottom, .hud-feed { zoom: var(--hud); }

.hud-top, .hud-bottom {
  position: absolute;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: max(12px, env(safe-area-inset-top)) 16px 12px;
}

.hud-top { top: 0; }
.hud-bottom { bottom: 0; padding-bottom: max(14px, env(safe-area-inset-bottom)); }

.hud-track {
  font: 700 14px var(--display);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  text-shadow: 0 1px 3px #000;
}

.speedo {
  font: 700 38px var(--display);
  font-size: calc(38px * var(--hud-big));
  font-style: italic;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.8);
}

.speedo small { font-size: 14px; margin-left: 4px; color: var(--muted); }
/* A fixed box for three digits, right-aligned: sized to its text, the number
   pushed the turbo bar and everything after it about as the speed changed. */
#hud-speed { display: inline-block; width: 3ch; text-align: right; font-variant-numeric: tabular-nums; }

.turbo[hidden] { display: none; }
.turbo {
  width: 140px;
  height: 10px;
  border-radius: 5px;
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid var(--edge);
  overflow: hidden;
}

.turbo-fill {
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, var(--focus), #6af0ff);
  transform-origin: left;
}

.hud-arms[hidden] { display: none; }

.hud-arms {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
}

/* Ten segments, one per 10 health: a hit is visibly two or three of them going. */
.health {
  width: 170px;
  height: 12px;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid var(--edge);
  overflow: hidden;
  position: relative;
}

.health::after {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(90deg, transparent 0 15px, rgba(0, 0, 0, 0.6) 15px 17px);
}

.health-fill {
  height: 100%;
  width: 100%;
  background: #4be08a;
  transform-origin: left;
  transition: transform 0.12s;
}

.health-fill.low { background: #ffb020; }
.health-fill.critical { background: #ff3b3b; animation: hp-blink 0.5s steps(2) infinite; }

@keyframes hp-blink { 50% { opacity: 0.4; } }

.ammo {
  display: flex;
  gap: 12px;
  font: 700 13px var(--display);
  color: var(--muted);
  text-shadow: 0 1px 3px #000;
}

.ammo b { color: var(--text); font-size: 16px; }
.ammo b.empty { color: #ff5a5a; }

.hud-help {
  position: absolute;
  left: 50%;
  top: 58px;
  transform: translateX(-50%);
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: 10px;
  font-size: 13px;
  color: var(--muted);
  text-align: center;
  transition: opacity 0.8s;
  max-width: calc(100% - 32px);
}

.hud-help b { color: var(--text); }
.hud-help.gone { opacity: 0; }

.hud-debug {
  position: absolute;
  right: 12px;
  top: 12px;
  font: 11px ui-monospace, monospace;
  color: var(--muted);
  text-align: right;
  white-space: pre;
  text-shadow: 0 1px 2px #000;
}

/* ------------------------------------------------------------------ touch */

.touch-layer {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 5;
}

.touch-layer[hidden] { display: none !important; }

/* The left half is the steering thumb's, below the top bar: over it, the
   steering zone covered the ☰ Menu button, and a phone could not pause. */
.touch-steer {
  position: absolute;
  left: 0;
  top: 64px;
  bottom: 0;
  width: 48%;
  pointer-events: auto;
}

/* Steering by buttons (#26): a left and a right under the left thumb, apart enough to rock between. */
.touch-steer-buttons {
  position: absolute;
  left: max(14px, env(safe-area-inset-left));
  bottom: max(14px, env(safe-area-inset-bottom));
  display: flex;
  gap: 18px;
  pointer-events: auto;
}
.touch-steer-buttons[hidden], .touch-steer[hidden] { display: none; }
.touch-btn.steer { width: 78px; height: 78px; font-size: 26px; }

.touch-steer-base {
  position: fixed;
  left: 22%;
  top: 72%;
  width: 180px;
  height: 56px;
  transform: translate(-50%, -50%);
  border-radius: 28px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.25);
  opacity: 0.55;
}

.touch-steer-base.active { opacity: 1; }

.touch-steer-knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.35);
  transform: translate(-50%, -50%);
}

.touch-pad {
  position: absolute;
  right: max(14px, env(safe-area-inset-right));
  bottom: max(14px, env(safe-area-inset-bottom));
  display: grid;
  grid-template-columns: repeat(3, 64px);
  grid-template-rows: repeat(2, 64px);
  gap: 10px;
  pointer-events: auto;
}

.touch-btn {
  width: 100%;
  height: 100%;
  min-width: 0;
  padding: 0;
  overflow: hidden;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.3);
  background: rgba(255, 255, 255, 0.1);
  color: var(--text);
  font: 700 18px var(--display);
  touch-action: none;
}

/* Glass buttons, lit from above, each in its own colour, with a picture rather than a letter (#24). */
.touch-btn {
  display: grid;
  place-items: center;
  background: radial-gradient(circle at 50% 30%, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.05) 70%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 3px 10px rgba(0, 0, 0, 0.35);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  transition: transform 60ms, background 60ms;
}
.touch-btn svg { width: 56%; height: 56%; display: block; pointer-events: none; filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.5)); }
.touch-btn.down { transform: scale(0.93); background: radial-gradient(circle at 50% 30%, rgba(255, 255, 255, 0.45), rgba(255, 255, 255, 0.15) 70%); }
.touch-btn.weapon { color: #ffd23c; border-color: rgba(255, 210, 60, 0.5); }
/* Where each button sits: weapons top left, the handbrake above the accelerator
   (under the same thumb, a short reach up), the brake beside it. */
.touch-btn[data-drive="front"] { grid-area: 1 / 1; }
.touch-btn[data-drive="rear"] { grid-area: 1 / 2; }
.touch-btn[data-drive="handbrake"] { grid-area: 1 / 3; }
.touch-btn[data-drive="turbo"] { grid-area: 2 / 1; }
.touch-btn[data-drive="brake"] { grid-area: 2 / 2; }
.touch-btn[data-drive="throttle"] { grid-area: 2 / 3; }
.touch-pad .touch-gap { display: none; }
/* No weapons in this race: their buttons go; the handbrake stays over the accelerator. */
.touch-pad.no-weapons .touch-btn.weapon { display: none; }
/* Always-on throttle: no accelerator button, and the handbrake drops into its place beside the brake. */
.touch-pad.auto-throttle .touch-btn[data-drive="throttle"] { display: none; }
.touch-pad.auto-throttle .touch-btn[data-drive="handbrake"] { grid-area: 2 / 3; }
.touch-btn.hb { color: #ffb13c; border-color: rgba(255, 177, 60, 0.5); }
.touch-btn.steer { color: #3ee6ff; border-color: rgba(62, 230, 255, 0.5); }
.touch-btn.pedal.gas { color: #7dffb5; border-color: rgba(0, 220, 130, 0.7); background: radial-gradient(circle at 50% 30%, rgba(0, 230, 140, 0.55), rgba(0, 150, 90, 0.2) 70%); }
.touch-btn.pedal.brake { color: #ffb3a3; border-color: rgba(255, 77, 46, 0.7); background: radial-gradient(circle at 50% 30%, rgba(255, 90, 60, 0.55), rgba(180, 40, 20, 0.2) 70%); }
.touch-btn.pedal.gas.down, .touch-btn.pedal.brake.down { filter: brightness(1.3); }

/* Touch devices: the controls hint is about keys nobody has, and the bottom of
   the screen belongs to thumbs, so the speedo moves up under the top bar. */
@media (pointer: coarse) {
  .hud-help { display: none; }
  .hud-bottom { bottom: auto; top: 44px; padding-top: 4px; }
  .speedo { font-size: 28px; }
}

.touch-btn.turbo { font-size: 11px; letter-spacing: 0.04em; }
.touch-btn.hb { font-size: 14px; }

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

.hud-race {
  position: absolute;
  left: 16px;
  top: 64px;
  display: flex;
  gap: 14px;
  align-items: flex-start;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.8);
}

.hud-pos b {
  font: 700 54px/0.9 var(--display);
  font-style: italic;
}

.hud-pos small, .hud-lap small {
  font: 700 18px var(--display);
  color: var(--muted);
}

.hud-lap { font: 700 16px var(--display); letter-spacing: 0.08em; color: var(--muted); }
.hud-lap b { color: var(--text); font-size: 22px; }
.hud-time { font: 700 22px var(--display); font-variant-numeric: tabular-nums; }
.hud-splits { font: 12px var(--body); color: var(--muted); font-variant-numeric: tabular-nums; }

.hud-minimap {
  position: absolute;
  right: 14px;
  bottom: 14px;
  width: calc(150px * var(--hud-big));
  height: calc(150px * var(--hud-big));
  border-radius: 12px;
  background: rgba(10, 8, 18, 0.45);
  border: 1px solid var(--edge);
}

.hud-countdown {
  position: absolute;
  left: 50%;
  top: 30%;
  transform: translate(-50%, -50%);
  font: 700 120px var(--display);
  font-style: italic;
  color: var(--accent-2);
  text-shadow: 0 6px 24px rgba(0, 0, 0, 0.8);
  pointer-events: none;
}

.hud-countdown.go { color: #5cff8a; }
.hud-countdown.pop { animation: count-pop 0.9s ease-out both; }
.hud-countdown.go.pop { animation-duration: 1.4s; }
@keyframes count-pop {
  0% { transform: translate(-50%, -50%) scale(2.2); opacity: 0; }
  18% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  80% { opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(0.9); opacity: 0.2; }
}
@media (prefers-reduced-motion: reduce) { .hud-countdown.pop { animation: none; } }

.hud-banner {
  position: absolute;
  left: 50%;
  top: 24%;
  transform: translateX(-50%);
  font: 700 30px var(--display);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-shadow: 0 3px 12px rgba(0, 0, 0, 0.9);
  white-space: nowrap;
  pointer-events: none;
  transition: opacity 0.4s;
  font-size: calc(30px * var(--hud));
}

.hud-banner.warn { color: #ff5a4a; }
/* RACE OVER: across the middle of the screen, over half its width. */
.hud-banner.over { top: 30%; transform: translate(-50%, -50%); font-size: 8vw; font-style: italic; color: var(--accent-2); }
body.tv .hud-banner.over { font-size: 5.7vw; }
/* Where you finished, under RACE OVER, until the fade. */
/* Centred under it; its own letter spacing, not the big one's; never smaller than 16px, on a phone held upright. */
.hud-banner.over { text-align: center; }
.hud-banner .banner-sub { display: block; font-size: max(0.3em, 16px); letter-spacing: 0.08em; font-style: normal; color: var(--text); margin-top: 0.15em; }
/* A phone held sideways has the lap box where RACE OVER would be: lower, clear of it. */
@media (pointer: coarse) { .hud-banner.over { top: 50%; } }
.hud-banner:empty { opacity: 0; }

.hud-auto {
  font: 700 11px var(--display);
  letter-spacing: 0.12em;
  color: var(--focus);
  border: 1px solid var(--focus);
  border-radius: 6px;
  padding: 3px 7px;
}

.hud-arrows { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.hud-names { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }

/* A driver's name over their car: their colour on a dark chip, readable over road and grass. */
.name-tag {
  position: absolute;
  left: 0;
  top: 0;
  font: 700 12px var(--display);
  letter-spacing: 0.06em;
  white-space: nowrap;
  color: #fff;
  background: rgba(10, 10, 16, 0.62);
  border-bottom: 2px solid var(--c, #fff);
  border-radius: 4px;
  padding: 1px 6px;
}
.name-tag.you { color: var(--accent-2); }

.rival-arrow {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  margin: -9px 0 0 -9px;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
  border-left: 18px solid var(--c, #fff);
  filter: drop-shadow(0 0 2px #000);
}

.menu-card.wide { width: min(560px, 100%); }

/* An animation restarts whenever `hidden` comes off, and only a race's end shows the results. */
.screen.results { animation: results-in 1s ease both; }
@keyframes results-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .screen.results { animation: none; } }

.results-table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 18px;
  font-variant-numeric: tabular-nums;
}

.results-table th {
  text-align: left;
  font: 600 12px var(--body);
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 6px 8px;
}

.results-table td { padding: 8px; border-top: 1px solid var(--edge); }
.results-table tr.you td { background: rgba(255, 255, 255, 0.06); font-weight: 600; }
.results-table .fastest-lap { margin-left: 6px; font-size: 0.85em; vertical-align: 1px; }
.results-table .swatch { display: inline-block; width: 12px; height: 12px; border-radius: 3px; margin-right: 8px; vertical-align: -1px; }

/* The podium: the first three turning on their plinths, names underneath. */
.podium { position: relative; width: min(560px, 100%); height: clamp(110px, 17vh, 190px); margin: -6px auto 6px; }
.podium-canvas { width: 100%; height: 100%; display: block; }
/* Landscape: the whole card's width, so the three stand well apart, each over its name. */
@media (orientation: landscape) and (min-width: 720px) { .podium { width: 100%; } }
.podium-names {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  text-align: center;
  font: 700 13px var(--display);
  letter-spacing: 0.06em;
  text-shadow: 0 1px 4px #000;
}
.podium-names span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 6px; }
#podium-1 { font-size: 15px; }

/* The race's awards: a coloured bar for whoever won each, the title, then the line. */
.awards { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 6px; }
.awards li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 7px 12px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.04);
  border-left: 4px solid var(--c, var(--accent-2));
}
.awards b { font: 700 13px var(--display); letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-2); flex: none; }
.awards span { font-size: 14px; }

/* Tonight's standings sit beside the race's results where there is room, under them where not. */
.results-grid { display: grid; gap: 0 22px; }
.tonight h3 { font: 700 14px var(--display); letter-spacing: 0.1em; text-transform: uppercase; margin: 0 0 4px; }
.tonight h3 small { color: var(--muted); font-weight: 600; letter-spacing: 0.04em; text-transform: none; }
.tonight .menu-note { margin: -10px 0 14px; }
.results-grid > * { min-width: 0; }
.tonight .results-table th { padding: 6px; }
.tonight .results-table td { padding: 8px 6px; white-space: nowrap; }
.tonight .results-table td:nth-child(2) { max-width: 130px; overflow: hidden; text-overflow: ellipsis; }
@media (min-width: 960px) {
  .results-grid.with-tonight { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
}
/* Rematch, lobby and leave in one row: three stacked buttons pushed the results off a short screen. */
@media (min-width: 720px) {
  .results .menu-actions { flex-direction: row; }
  .results .menu-actions > .btn { flex: 1; }
}

/* The kill feed: every wreck in the race, newest on top, under the top right corner. */
.hud-feed {
  position: absolute;
  right: 16px;
  top: 64px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  pointer-events: none;
}
.feed-line {
  font: 700 14px var(--display);
  letter-spacing: 0.04em;
  white-space: nowrap;
  padding: 3px 10px;
  border-radius: 6px;
  background: rgba(10, 10, 16, 0.62);
  transition: opacity 0.5s;
  animation: feed-in 0.25s ease-out;
}
.feed-line.you { background: rgba(255, 77, 46, 0.35); }
.feed-line.gone { opacity: 0; }
.feed-icon { color: var(--accent-2); margin: 0 8px; }
@keyframes feed-in { from { transform: translateX(24px); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .feed-line { animation: none; } }

@media (pointer: coarse) {
  .hud-race { top: 86px; }
  .hud-pos b { font-size: 40px; }
  .hud-minimap { top: 56px; bottom: auto; width: 110px; height: 110px; }
  .hud-feed { top: 176px; }
}

@media (max-width: 520px) {
  .hud-minimap { width: 110px; height: 110px; }
  .hud-countdown { font-size: 88px; }
  .hud-banner { font-size: 22px; }
}

.menu-note.keys b { color: var(--text); font-weight: 600; }
@media (pointer: coarse) { .menu-note.keys { display: none; } }

/* ------------------------------------------------------- lobby and rooms */

.field.stacked { flex-direction: column; align-items: stretch; gap: 6px; }

input[type='text'] {
  font: 600 18px var(--display);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text);
  background: #241f33;
  border: 1px solid var(--edge);
  border-radius: 8px;
  padding: 10px 12px;
}

.btn-row { display: flex; gap: 10px; }
.btn-row > .btn { flex: 1; }

.lobby-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.room-code { font-family: var(--display); letter-spacing: 0.18em; color: var(--accent-2); }
.menu-note.share { margin: 0 0 12px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.menu-note .link { color: var(--text); word-break: break-all; }

.pill {
  font: 600 11px var(--body);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 4px 9px;
  border-radius: 99px;
  border: 1px solid var(--edge);
  color: var(--muted);
}
.pill.online { color: #5cff8a; border-color: rgba(92, 255, 138, 0.4); }
.pill.offline, .pill.error { color: #ff5a4a; border-color: rgba(255, 90, 74, 0.4); }

.roster { list-style: none; margin: 0 0 16px; padding: 0; display: grid; gap: 6px; }
.roster li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 10px 4px 4px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--edge);
}
.roster .swatch { width: 14px; height: 14px; border-radius: 4px; flex: none; }
.roster .name { font: 600 15px var(--display); letter-spacing: 0.04em; flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* The car they are in, under the name: the portrait shows it, this says it. */
.roster .name small { font: 500 11px var(--body); letter-spacing: 0.04em; color: var(--muted); text-transform: uppercase; }
.roster .car-portrait { flex: none; }
.roster .badge { font: 700 10px var(--body); letter-spacing: 0.08em; color: var(--muted); border: 1px solid var(--edge); border-radius: 5px; padding: 2px 6px; }
.roster .badge.host { color: var(--accent-2); border-color: rgba(255, 179, 0, 0.5); }
.roster .badge.direct { color: var(--focus); border-color: rgba(0, 229, 255, 0.5); }
.roster .badge.warn, .menu-note.warn { color: var(--accent); border-color: currentColor; }
.roster li.bot { opacity: 0.6; }
.roster .badge.score { color: var(--text); border-color: rgba(255, 255, 255, 0.3); font-variant-numeric: tabular-nums; }

.lobby-grid { display: grid; gap: 4px; margin-bottom: 6px; }

/* Wide screens (the Deck's 1280x800 included): settings in two columns, so the
   lobby's six rows and its buttons fit on the screen without scrolling. */
@media (min-width: 720px) {
  .menu-card.wide { width: min(720px, 100%); }
  /* minmax(0, 1fr): a plain 1fr column grows to its widest control, and
     "6 (fill with bots)" and the seed box pushed past the card's edge. */
  .lobby-grid:not(.one-column) { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 22px; }
}
@media (min-width: 960px) {
  .menu-card.wide { width: min(860px, 100%); }
}
.lobby-grid > * { min-width: 0; }
/* The lobby: who is here on the left, every control in one column on the right. */
.lobby-layout { display: grid; gap: 14px; }
.lobby-layout > * { min-width: 0; }
.lobby-people .roster { margin-bottom: 10px; }
.lobby-controls { display: flex; flex-direction: column; gap: 8px; }
.lobby-controls .lobby-grid { margin-bottom: 0; }
@media (min-width: 720px) {
  .lobby-layout { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 22px; align-items: start; }
}
body.is-host .guest-only { display: none !important; }
/* The room's track as a card: its map and what it is, the whole card one stop for the ring. */
.track-card {
  display: flex; align-items: center; gap: 12px; width: 100%; padding: 8px 10px; text-align: left;
  font: inherit; text-transform: none; letter-spacing: normal;
  background: rgba(255, 255, 255, 0.04); border: 1px solid var(--edge); border-radius: 10px;
}
.track-card .track-map { width: 72px; height: 72px; }
.track-card .track-info { display: block; font-size: 12px; }
button.track-card::after { content: '›'; margin-left: auto; padding-left: 6px; font: 600 24px var(--display); color: var(--muted); }
/* A colour somebody else has: still pickable (the room sorts clashes out), but marked. */
.picker.taken .picker-value { opacity: 0.55; }
.swatch.taken { opacity: 0.35; background-image: linear-gradient(135deg, transparent 45%, rgba(0, 0, 0, 0.7) 45%, rgba(0, 0, 0, 0.7) 55%, transparent 55%); }
.lobby-grid .field select, .lobby-grid .field input { min-width: 0; max-width: 62%; }
.lobby-grid .seed-row .field input { max-width: none; flex: 1 1 auto; }
.lobby-grid .pick-row .field select { max-width: none; flex: 1 1 auto; }
body:not(.is-host) .host-only { display: none !important; }
/* A setting the room has fixed for now: the championship's track while it runs. */
.lobby-grid .field:has(select:disabled), .seed-row:has(input:disabled) { opacity: 0.45; }

/* The championship: its tracks as a row of chips, the next one lit, on one line that scrolls. */
.cup-box { flex: 0 1 62%; max-width: 62%; min-width: 0; display: flex; align-items: center; gap: 6px; }
.cup-box .btn { flex: none; }
.cup-box .btn[hidden] { display: none; }
#btn-cup-add { font-size: 16px; line-height: 1; padding: 6px 11px; }
.cup-list {
  list-style: none; margin: 0; padding: 2px; flex: 1 1 auto; min-width: 0;
  display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; counter-reset: cup;
}
.cup-list::-webkit-scrollbar { display: none; }
.cup-list li { counter-increment: cup; flex: none; }
.cup-list li.empty { color: var(--muted); font-size: 13px; counter-increment: none; }
.cup-chip {
  font: 600 12px var(--body);
  color: var(--text);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--edge);
  border-radius: 6px;
  padding: 4px 8px;
  max-width: 130px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
}
.cup-chip::before { content: counter(cup) '. '; color: var(--muted); }
button.cup-chip { cursor: pointer; }
button.cup-chip::after { content: ' ✕'; color: var(--muted); }
.cup-chip.done { opacity: 0.45; text-decoration: line-through; }
.cup-chip.next { border-color: var(--accent-2); color: var(--accent-2); }
/* A phone scrolls the page anyway: there the chips wrap, all in view. */
@media (max-width: 719px) {
  .cup-list { flex-wrap: wrap; overflow: visible; }
}

.console-banner {
  margin-top: 16px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid rgba(0, 229, 255, 0.35);
  background: rgba(0, 229, 255, 0.07);
  font-size: 13px;
  color: var(--muted);
}
.console-banner b { color: var(--text); }
.console-sub { display: block; margin-top: 4px; }
.glyph { color: var(--focus); font-weight: 700; }
.console-banner[hidden] { display: none; }

.notice {
  position: fixed;
  left: 50%;
  bottom: max(24px, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  max-width: calc(100vw - 32px);
  margin: 0;
  padding: 10px 16px;
  border-radius: 10px;
  border: 1px solid var(--edge);
  background: var(--panel);
  color: var(--text);
  font-size: 14px;
  text-align: center;
  z-index: 50;
  pointer-events: none;
}
.notice[hidden] { display: none; }

/* ----------------------------------------------------- overlays */

.pause-veil, .keyboard-veil {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgba(10, 8, 18, 0.72);
  pointer-events: auto;
  z-index: 20;
}
.pause-veil[hidden], .keyboard-veil[hidden] { display: none !important; }

.keyboard-preview {
  font: 700 26px var(--display);
  letter-spacing: 0.12em;
  text-align: center;
  padding: 10px;
  margin-bottom: 12px;
  border-radius: 8px;
  background: #241f33;
  min-height: 1.6em;
}

.keyboard-grid {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 6px;
  margin-bottom: 14px;
}

.keyboard-grid .key {
  font: 700 16px var(--display);
  color: var(--text);
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid var(--edge);
  border-radius: 8px;
  padding: 10px 0;
  min-width: 0;
}

/* A dropdown's options as a list, for a controller (ChoiceList). Two columns
   where there's room, so twenty-odd tracks are a few presses apart. */
.choice-veil .menu-card { width: min(640px, 100%); }
.choice-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 6px;
  max-height: min(62vh, 560px);
  overflow-y: auto;
  padding: 4px;
  margin-bottom: 14px;
}
.choice-list h3 {
  grid-column: 1 / -1;
  margin: 8px 0 0;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.choice-list h3:first-child { margin-top: 0; }
.choice {
  font: 600 15px var(--body, inherit);
  color: var(--text);
  text-align: left;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid var(--edge);
  border-radius: 8px;
  padding: 9px 12px;
  min-width: 0;
  cursor: pointer;
}
.choice:hover { background: rgba(255, 255, 255, 0.13); }
.choice.current { border-color: var(--accent, #3ee6ff); }
.choice.current::after { content: ' ✓'; color: var(--accent, #3ee6ff); }

/* Steam Deck and other 1280x800 screens: everything fits without scrolling. */
/* The TV layout (at the end) repeats these: it zooms a 1080p screen to lay out
   like 1370x770, but media queries still see 1920x1080 and never fire. */
@media (max-height: 820px) and (min-width: 1000px) {
  .menu-card { padding: 20px 22px; }
  .title { font-size: 44px; }
  .tagline { margin-bottom: 14px; }
  .btn { padding: 11px 16px; }
}

/* ------------------------------------------------------------------ garage */

.garage-view {
  width: 100%;
  height: clamp(150px, 30vh, 260px);
  border-radius: 12px;
  background: radial-gradient(ellipse at 50% 60%, #3a3552, #1a1726 70%);
  overflow: hidden;
  margin-bottom: 8px;
}

.garage-canvas { width: 100%; height: 100%; display: block; }

/* Landscape: the turntable on the left, the pickers on the right (still one
   column of them), so the Garage fits a TV or a Deck without scrolling. */
@media (min-width: 720px) {
  .garage-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 22px; align-items: stretch; }
  .garage-layout .garage-view { height: auto; min-height: 240px; margin-bottom: 0; }
  /* Eleven colour squares need the row's width: the label goes above them. */
  .garage-layout .swatch-row { flex-direction: column; align-items: stretch; gap: 6px; }
  .garage-layout .swatch-row .picker.swatches { justify-content: flex-start; }
}
.menu-card.garage > .menu-note { margin: 10px 0 8px; }

/* The question before leaving a room. */
.confirm-veil .menu-card { width: min(460px, 100%); }
.confirm-veil .menu-note { margin: 0 0 18px; }

/* Pickers: ‹ arrows › and colour squares, in place of dropdowns. */
.picker { display: flex; align-items: center; outline-offset: 2px; border-radius: 8px; }
.picker:focus-visible, .picker.nav-focus { outline: 3px solid var(--focus); }
.picker.stepper {
  font: 15px var(--body);
  background: #241f33;
  border: 1px solid var(--edge);
  min-width: 190px;
  justify-content: space-between;
}
.picker .step {
  font: 700 20px var(--display);
  line-height: 1;
  padding: 6px 12px;
  cursor: pointer;
  color: var(--accent);
  user-select: none;
}
.picker .step:hover { background: rgba(255, 255, 255, 0.08); }
.picker-value { flex: 1; text-align: center; padding: 8px 0; white-space: nowrap; }
/* A dropdown under arrows: kept in the page for its value, out of sight and reach. */
select.stepped { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.field:has(> select.stepped) { position: relative; }
.select-stepper { flex: 0 1 auto; min-width: 150px; }
.select-stepper .picker-value { overflow: hidden; text-overflow: ellipsis; }
/* In two columns there is half the room: the arrows take what the dropdown had. */
.lobby-grid .select-stepper { min-width: 0; max-width: 62%; flex-basis: 62%; }
/* One column (the Garage): the race number as wide as the pickers above it. */
.garage .lobby-grid.one-column .select-stepper { flex: 0 1 auto; min-width: 190px; }
.picker.swatches { gap: 6px; flex-wrap: wrap; justify-content: flex-end; padding: 3px; }
.swatch {
  width: 26px;
  height: 26px;
  border-radius: 6px;
  border: 2px solid rgba(255, 255, 255, 0.18);
  cursor: pointer;
}
.swatch.on { border-color: var(--text); box-shadow: 0 0 0 2px var(--accent); }

body[data-pad="none"] .pad-only { display: none; }

.car-icon { flex: none; margin-right: 2px; }

/* ------------------------------------------------------------------ hotlap */

.hud-split {
  font: 700 22px var(--display);
  font-style: italic;
  min-height: 26px;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.8);
}

.hud-split.up { color: #4be08a; }
.hud-split.down { color: #ff5a5a; }

/* ------------------------------------------------------------ track preview */

.track-preview {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 2px 0 4px;
}

.track-map {
  flex: none;
  width: 92px;
  height: 92px;
  border-radius: 10px;
  border: 1px solid var(--edge);
}

.track-preview.big .track-map { width: 150px; height: 150px; }
/* A phone on its side: the room's map at the menu's size, so Done stays on the screen under the chooser (#18). */
@media (max-height: 500px) {
  .track-preview.big .track-map { width: 92px; height: 92px; }
}

.track-info { margin: 0; font-size: 13px; line-height: 1.45; color: var(--muted); }
.track-info b { color: var(--text); font-family: var(--display); letter-spacing: 0.04em; }

/* ------------------------------------------------------------ photo mode */

/* Photo mode (main.ts, ui/PhotoMode.ts): the race HUD goes, leaving the
   photo bar along the bottom; Hide UI takes that too, for a clean screen. */
body.photo .screen.hud > :not(#photo-bar, #photo-ring) { visibility: hidden; }
body.photo-clean #photo-bar, body.photo-clean .notice { visibility: hidden; }
.photo-bar {
  position: absolute;
  left: 50%;
  bottom: max(12px, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 24px);
  padding: 8px 12px;
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: 10px;
  pointer-events: auto;
  touch-action: none;
}
.photo-bar[hidden] { display: none; }
/* Where a click focused: a ring that fades. Shown with the UI hidden too, as the click was meant;
   HTML, so never in a saved photo. Fixed, so in the window's own pixels, as the click reports them. */
.photo-ring {
  position: fixed;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  border: 2px solid var(--focus);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
}
.photo-ring[hidden] { display: none; }
.photo-ring.on { animation: photo-ring 0.7s ease-out; }
@keyframes photo-ring {
  from { opacity: 1; transform: scale(1.5); }
  30% { opacity: 1; transform: scale(1); }
  to { opacity: 0; transform: scale(1); }
}
body.photo .screen.hud > #photo-ring { visibility: visible; }
.photo-keys { margin: 0 0 6px; font-size: 12px; line-height: 1.4; color: var(--muted); text-align: center; }
.photo-keys b { color: var(--text); font-weight: 600; }
.photo-controls { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px 10px; }
.photo-field { display: flex; align-items: center; gap: 6px; font: 600 12px var(--display); letter-spacing: 0.04em; text-transform: uppercase; }
.photo-field input[type='range'] { width: 110px; accent-color: var(--accent); }
.photo-field output { min-width: 3.6em; color: var(--muted); font-variant-numeric: tabular-nums; }
/* A phone: room for the sliders, and no keys line, which is about keys nobody has. */
@media (pointer: coarse) {
  .photo-keys { font-size: 11px; }
}
@media (max-width: 560px) {
  .photo-field input[type='range'] { width: 84px; }
}

/* ------------------------------------------------------------- TV layout */

/* A TV across the room (on by default on a console): the whole overlay is
   zoomed so a 1080p screen lays out like a 1370x770 one, the size every
   screen is already checked at, and held in from the edges a TV may crop.
   The HUD maps car positions into the zoomed overlay itself. */
body.tv .ui-root { zoom: 1.4; }
body.tv .screen.hud { inset: 3vh 3vw; }
body.tv .screen.menu { padding: 3vh 3vw; }
body.tv .name-tag { font-size: 14px; }
/* The Deck's fitting rules, which the zoom keeps from firing (see above). */
body.tv .menu-card { padding: 20px 22px; }
body.tv .title { font-size: 44px; }
body.tv .tagline { margin-bottom: 14px; }
/* :where() keeps this at .btn's weight, so .btn.small, the dice and the car keep their own. */
body.tv :where(.btn) { padding: 11px 16px; }
/* The small print, read from the sofa: nothing under about 21px on the screen. */
body.tv .menu-note, body.tv .track-info, body.tv .version, body.tv .console-banner { font-size: 15px; }
body.tv .roster .badge { font-size: 12px; }
body.tv .hud-splits { font-size: 15px; }
body.tv .ammo { font-size: 15px; }

/* The settings list is long: its rows sit closer, so it fits a phone, a Deck or a TV without scrolling.
   One column, so down and up on a pad or the arrow keys visit every row in turn. */
#screen-settings .field { margin-bottom: 7px; }
/* The name beside its label like every other setting: a box for twelve letters, not the row's width. */
#screen-settings .field input[type='text'] { width: 11em; min-width: 0; padding: 7px 10px; font-size: 16px; }
#screen-settings h2 { margin-bottom: 10px; }
/* Experimental… beside Back, so the long list gets no taller. */
.menu-actions.row { flex-direction: row; }
.menu-actions.row > .btn { flex: 1; }
/* The Custom camera's sliders, with each value beside its name. */
#screen-experimental .field output { color: var(--muted); font-variant-numeric: tabular-nums; margin-left: 6px; }
#screen-experimental .menu-note.warn { margin: 0 0 14px; }
/* Photo mode's bar on a TV: held in from the edges with the rest of the HUD, and readable from the sofa. */
body.tv .photo-keys { font-size: 14px; }
body.tv .photo-field input[type='range'] { width: 130px; }
