/* Strike ecosystem world: HUD, touch controls and sheets over the 3D canvas. Uses the BR kit tokens. */

html, body { height: 100%; margin: 0; }
body { overflow: hidden; overscroll-behavior: none; }

#world {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

/* A game, not a document: no double-tap zoom anywhere (a second tap just off a driving button zoomed the page on
   iOS, with no way back short of a reload). The canvas and the driving controls take touch-action: none, so pinch
   does nothing over the world either; a sheet can still be pinched, which is what WCAG 1.4.4 asks (the viewport meta
   no longer says user-scalable=no, which only ever bound Android anyway). */
html, body { touch-action: manipulation; }
/* Labels in the world sit at 12 px (the kit's token is 11.2 px, which read as ten on a phone in the blind re-score) */
:root { --label-size: 0.75rem; }
/* ── HUD ─────────────────────────────────────────────────────────────── */
.hud { position: fixed; z-index: 10; touch-action: manipulation; }
.hud p { margin: 0; }

.hud-top {
  top: max(var(--space-sm), env(safe-area-inset-top));
  left: max(var(--space-sm), env(safe-area-inset-left));
  right: max(var(--space-sm), env(safe-area-inset-right));
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-sm);
  pointer-events: none;
}
.hud-title,
.hud-actions { pointer-events: auto; }
.hud-title {
  min-height: 44px; /* the chips' height, so the row reads as one */
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--space-2xs) var(--space-sm);
  border-radius: 0.75rem;
  background: color-mix(in srgb, var(--bg-surface) 88%, transparent);
  border: 1px solid var(--border-color);
  backdrop-filter: blur(6px);
}
.hud-district {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.125rem;
  line-height: 1.2;
}
.hud-actions { display: flex; gap: var(--space-2xs); margin-left: auto; }
/* During a lap the race panel takes the title's corner: the district name is noise while you're driving */
body:has(#race-hud:not([hidden])) .hud-title { display: none; }

.chip {
  min-height: 44px;
  padding: 0 var(--space-sm);
  border-radius: 10rem;
  border: 1px solid var(--border-color);
  background: color-mix(in srgb, var(--bg-surface) 88%, transparent);
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.05rem;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  backdrop-filter: blur(6px);
}
.chip:hover { border-color: var(--text-primary); }
#theme { min-width: 4.5rem; } /* "Light" is wider than "Dark": the same width in both themes, so the title never wraps in one of them */

.hud-prompt {
  left: 50%;
  bottom: 3.5rem;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3xs);
}
.hud-prompt[hidden], .hud-hint[hidden] { display: none; }
.hud-hint {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--text-primary);
  text-shadow: 0 0 6px var(--bg-page);
}

/* Who's driving: the chip carries a coloured dot per live visitor state; the note under the top bar says who arrived */
.chip-peers::before { content: ""; display: inline-block; width: 0.5rem; height: 0.5rem; margin-right: 0.45rem; border-radius: 50%; background: var(--peers-dot, var(--text-secondary)); vertical-align: 0.05rem; }
.chip-peers[data-status="on"] { --peers-dot: #16a34a; }
.chip-peers[data-status="offline"] { --peers-dot: #dc2626; }
.chip-short { display: none; }
@media (max-width: 480px) { /* three chips beside a two-line title: short labels keep them on one row */
  .hud-actions .chip-long { display: none; }
  .hud-actions .chip-short { display: inline; }
}
.peers-note { position: absolute; right: var(--space-sm); top: calc(100% + 0.25rem); margin: 0; pointer-events: none; }
.peers-note[hidden] { display: none; }
.peers-list { list-style: none; padding: 0 !important; margin: 0; }
.peers-item { display: flex; align-items: baseline; gap: var(--space-2xs); font-size: 1rem; line-height: 1.5; }
.peers-item + .peers-item { margin-top: var(--space-3xs); }
.peers-dot { flex: 0 0 auto; width: 0.7rem; height: 0.7rem; border-radius: 50%; background: var(--c); align-self: center; }
.peers-item span { color: var(--text-secondary); font-size: 0.875rem; }
.peers-item strong { font-family: var(--font-body); font-weight: 600; }

.hud-foot {
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100vw - 2rem);
  bottom: max(var(--space-2xs), env(safe-area-inset-bottom));
  padding: 0.2rem var(--space-sm);
  border: 1px solid var(--border-color);
  border-radius: 10rem;
  background: color-mix(in srgb, var(--bg-surface) 88%, transparent);
  backdrop-filter: blur(6px);
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-3xs) var(--space-sm);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--text-secondary);
  pointer-events: none;
}
.hud-foot a { color: inherit; pointer-events: auto; }
/* Light theme: HUD panels go opaque. At 88% the grey labels on them dropped to ~3.9:1 over
   dark scenery; on solid white they are 4.8:1 whatever is behind. */
.light :is(.hud-title, .chip, .race-hud, .prompt-card, .hud-foot) { background: var(--bg-surface); }
.light :is(.hud-title, .chip, .hud-foot) { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); } /* white pills dissolved into the clouds */
/* While a sheet is open the HUD goes: the footer and driving buttons would only crowd its edges, and the corner
   panels read as live controls behind the backdrop (below ~1140px a 34rem sheet cut them mid-word as well). The
   sheet's own eyebrow names the district. */
body:has(dialog[open]) :is(.hud-foot, .touch, .hud-top, .race-hud, .hud-prompt, .emote-row) { visibility: hidden; } /* the pad prompt too: at 1001 px it peeked out under the sheet's edge */
/* The phone tip in the intro only matters on touch screens; on a phone the intro keeps to the tip, Map view and the links */
@media (pointer: fine) { .touch-tip { display: none; } }
@media (max-width: 600px) { .intro-more { display: none; } }
/* The district name wraps the same way in both themes */
.hud-district { text-wrap: balance; }

/* ── Touch controls ──────────────────────────────────────────────────── */
.touch {
  position: fixed;
  z-index: 10;
  touch-action: manipulation;
  left: max(var(--space-sm), env(safe-area-inset-left));
  right: max(var(--space-sm), env(safe-area-inset-right));
  bottom: calc(max(var(--space-2xs), env(safe-area-inset-bottom)) + 1.75rem);
  display: flex;
  justify-content: space-between;
  pointer-events: none;
}
.touch[hidden] { display: none; }
.touch-group { display: flex; gap: var(--space-sm); pointer-events: auto; }
.pad-btn {
  width: 4.5rem;
  height: 4.5rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--border-color);
  background: color-mix(in srgb, var(--bg-surface) 80%, transparent);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.pad-btn.is-down { background: var(--text-primary); }
.pad-btn.is-down .tri { border-color: transparent; }
.pad-btn.is-down .tri-left { border-right-color: var(--bg-page); }
.pad-btn.is-down .tri-right { border-left-color: var(--bg-page); }
.pad-btn.is-down .tri-up { border-bottom-color: var(--bg-page); }
.pad-btn.is-down .tri-down { border-top-color: var(--bg-page); }
.pad-gas { width: 5.25rem; height: 5.25rem; }

/* The steering stick (stick.js): a pill with a knob that follows the thumb; where the thumb lands is neutral */
.stick {
  position: relative;
  width: 9rem; /* about the two old buttons and their gap, as on a tablet; narrower where a phone cannot fit it (below) */
  height: 4.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 0.7rem;
  border-radius: 10rem;
  border: 1px solid var(--border-color);
  background: color-mix(in srgb, var(--bg-surface) 80%, transparent);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.stick.is-down { background: color-mix(in srgb, var(--bg-surface) 95%, transparent); }
.stick-knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: var(--text-primary);
  transform: translate(calc(-50% + var(--stick-x, 0px)), -50%);
  transition: transform 90ms ease; /* the snap back to centre on release; while held the knob tracks the thumb directly */
  pointer-events: none;
}
.stick.is-down .stick-knob { transition: none; }

.tri { width: 0; height: 0; border: 0.7rem solid transparent; }
.tri-left { border-right: 1rem solid var(--text-primary); border-left-width: 0; }
.tri-right { border-left: 1rem solid var(--text-primary); border-right-width: 0; }
.tri-up { border-bottom: 1rem solid var(--text-primary); border-top-width: 0; }
.tri-down { border-top: 1rem solid var(--text-primary); border-bottom-width: 0; }

/* ── Sheets (dialogs) ────────────────────────────────────────────────── */
.sheet {
  margin: auto;
  inset: 0;
  width: min(34rem, calc(100vw - 2rem));
  max-height: calc(100dvh - 2rem);
  overflow: auto;
  padding: var(--space-xl);
  border: 1px solid var(--border-color);
  border-radius: 1rem;
  background: var(--bg-surface);
  color: var(--text-primary);
  box-shadow: 0 12px 40px var(--shadow-heavy);
}
.sheet::backdrop { background: rgba(0, 0, 0, 0.45); }
.light .sheet::backdrop { background: rgba(255, 255, 255, 0.45); } /* a black scrim turned the daylight scene muddy behind every white sheet */
.sheet > * { margin: 0; }
.sheet > * + * { margin-top: var(--space-md); }
.sheet h1 { font-size: 2.25rem; }
.sheet h2 { font-size: 2rem; }
.sheet p { font-size: 1.0625rem; max-width: var(--measure); text-wrap: pretty; }
.sheet ul { padding-left: 1.1rem; }
.sheet li { font-size: 1rem; line-height: 1.5; text-wrap: pretty; }
.sheet li + li { margin-top: var(--space-2xs); }
.sheet .muted { color: var(--text-secondary); font-size: 0.95rem; }
.sheet .muted a { color: inherit; text-decoration: underline; text-underline-offset: 0.15em; } /* the kit's link colour fails contrast on the dark sheet */
.sheet-actions { display: flex; flex-wrap: wrap; gap: var(--space-xs); }
/* A sheet's own action row stays in view while a long sheet scrolls (on a phone the way out sat below the fold); it
   carries the sheet's bottom padding. A guide mounted inside the sheet keeps its page's row in flow. */
.sheet > .sheet-actions { position: sticky; bottom: calc(-1 * var(--space-xl)); z-index: 1; margin: var(--space-md) calc(-1 * var(--space-xl)) calc(-1 * var(--space-xl)); padding: var(--space-sm) var(--space-xl) var(--space-xl); background: var(--bg-surface); } /* bottom reaches past the sheet's padding, which the sticky constraint otherwise excludes */
@media (max-width: 1000px) { .sheet > .sheet-actions { bottom: calc(-1 * var(--space-lg)); margin-left: calc(-1 * var(--space-lg)); margin-right: calc(-1 * var(--space-lg)); margin-bottom: calc(-1 * var(--space-lg)); padding: var(--space-sm) var(--space-lg) var(--space-lg); } }
/* A soft edge above the pinned row: content scrolling under it fades over the row's top margin instead of being cut mid-line */
.sheet > .sheet-actions::before { content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: var(--space-md); background: linear-gradient(to bottom, transparent, var(--bg-surface)); pointer-events: none; }
/* A sheet opens with its heading focused (main.js show); the ring belongs on controls, not on the title a shared link lands on */
.sheet :is(h1, h2)[tabindex="-1"]:focus { outline: none; }
/* Phones: the intro's primary pill on its own row and the two secondaries side by side (wrapping left "Map view" alone on a third row) */
@media (max-width: 480px) {
  #intro .sheet-actions { display: grid; grid-template-columns: repeat(2, max-content); }
  #intro .sheet-actions .br-button:first-child { grid-column: 1 / -1; }
}
/* Without JavaScript: one box pointing at the text companion (noscript content, never shown otherwise) */
.noscript { position: fixed; inset: 0; z-index: 60; /* above the loader (50) */ display: grid; place-content: center; padding: var(--space-lg); background: var(--bg-page); color: var(--text-primary); text-align: center; }
.noscript p { max-width: var(--measure); font-size: 1.1rem; line-height: 1.5; }
.sheet-actions .br-button { text-decoration: none; }
/* Copy link's fallback when the clipboard is unavailable: a read-only field with the URL, selected */
.sheet-actions .stop-link-url { flex: 1 1 100%; min-width: 0; font-family: var(--font-mono); font-size: 0.85rem; }
.sheet-actions .stop-link-url[hidden] { display: none; }
@media (pointer: coarse) { .sheet-actions .stop-link-url { font-size: 1rem; } } /* iOS zooms the page into a focused field under 16 px now that zoom is allowed */

/* A guide (or the stops page) mounted inside the world: a wider sheet, Back to the pad at the top, the page's own
   article rules from guides.css (loaded when the sheet first opens) */
.sheet--guide { width: min(44rem, calc(100vw - 2rem)); max-height: calc(100dvh - 2rem); padding: var(--space-lg); }
.sheet--guide > * + * { margin-top: var(--space-sm); }
.guide-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-sm); } /* on a narrow phone the pill drops under the eyebrow rather than squeezing it */
.guide-head .br-button { flex: none; }
.sheet--guide .guide-sheet, .sheet--guide main { position: static; margin: 0; width: auto; max-width: none; border: 0; box-shadow: none; padding: 0; background: transparent; }
.sheet--guide :is(.stops-head > .wrap, .stops-body) { width: auto; margin: 0; padding: 0; background: transparent; border: 0; box-shadow: none; }
.sheet--guide .stops-head { padding: 0; }
.sheet--guide .stops-body { display: block; margin-top: var(--space-md); }
.sheet--guide .stops-nav { position: static; }
.sheet--guide .topbar { padding: 0; }
.stop-guides { display: flex; flex-wrap: wrap; gap: var(--space-xs); }
.stop-guides[hidden] { display: none; }
.stop-guides .br-button { text-decoration: none; }
@media (max-width: 600px) { .sheet--guide { padding: var(--space-md); } }

/* The arcade cabinet's sheet: the game in a frame, Keep driving above it so it stays reachable on a phone */
.sheet--arcade { width: min(40rem, calc(100vw - 2rem)); padding: var(--space-md); }
.sheet--arcade > * + * { margin-top: var(--space-sm); }
.arcade-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-sm); }
.arcade-head h2 { font-size: 1.5rem; }
.arcade-head .br-button { flex: none; }
.arcade-credit { font-size: 0.9rem !important; }
.arcade-frame { height: clamp(240px, 68dvh, 640px); border-radius: 0.75rem; overflow: hidden; background: #170f38; }
.arcade-frame iframe { display: block; width: 100%; height: 100%; border: 0; }
.arcade-board h3 { margin: 0; font-size: 1rem; }
@media (max-width: 480px) { .sheet--arcade { width: calc(100vw - 1rem); padding: var(--space-sm); } .arcade-head h2 { font-size: 1.25rem; } }
.arcade-frame:focus { outline: none; }
/* A phone on its side: the sheet takes the height and the frame takes what the header leaves */
@media (max-height: 520px) {
  .sheet--arcade[open] { display: flex; flex-direction: column; height: calc(100dvh - 1rem); max-height: none; width: min(40rem, calc(100vw - 1rem)); padding: var(--space-xs) var(--space-sm); }
  .sheet--arcade > * + * { margin-top: var(--space-2xs); }
  .sheet--arcade .arcade-credit, .sheet--arcade .arcade-board { display: none; }
  .arcade-frame { flex: 1; min-height: 0; height: auto; }
}

/* Emotes: the row of five above the controls, and the smiley on the touch bar */
.emote-row {
  left: 50%; transform: translateX(-50%);
  bottom: calc(max(var(--space-2xs), env(safe-area-inset-bottom)) + 2.5rem);
  display: flex; gap: var(--space-3xs); padding: var(--space-3xs);
  border-radius: 999px; border: 1px solid var(--border-color);
  background: color-mix(in srgb, var(--bg-surface) 90%, transparent); backdrop-filter: blur(6px);
}
.emote-row[hidden] { display: none; }
.emote-row button {
  width: 3rem; height: 3rem; border-radius: 50%; border: 1px solid transparent; background: transparent;
  font-size: 1.5rem; line-height: 1; display: grid; place-items: center; cursor: pointer;
}
.emote-row button.is-selected { border-color: var(--text-primary); background: color-mix(in srgb, var(--text-primary) 12%, transparent); }
body:has(#emote-row:not([hidden])) #prompt { visibility: hidden; } /* the row takes the prompt's spot while it is open */
body:has(#touch:not([hidden])) .emote-row { bottom: calc(max(var(--space-2xs), env(safe-area-inset-bottom)) + 8rem); } /* above the touch controls */
.touch-mid { align-self: center; }
.emote-btn {
  width: 3rem; height: 3rem; border-radius: 50%; border: 1px solid var(--border-color);
  background: color-mix(in srgb, var(--bg-surface) 80%, transparent);
  font-size: 1.3rem; line-height: 1; display: grid; place-items: center; touch-action: manipulation;
}

.keys { list-style: none; padding: 0 !important; display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2xs); }
.keys li + li { margin-top: 0; }
.keys li { display: grid; grid-template-columns: 5.5rem 1fr; align-items: baseline; justify-items: start; } /* the descriptions line up in one column; a keycap keeps its own width */
.key {
  display: inline-block;
  margin-right: var(--space-3xs);
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--border-color);
  border-radius: 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
}

.stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr); /* four figures: 2x2, never 3 + 1 */
  gap: var(--space-2xs);
}
.stats[hidden], .br-button[hidden] { display: none; }
.stats div {
  display: flex; /* a label that wraps pushes its own value down, not out of line with its neighbour's */
  flex-direction: column;
  justify-content: space-between;
  padding: var(--space-xs) var(--space-sm);
  border: 1px solid var(--border-color);
  border-radius: 0.5rem;
  background: var(--bg-page);
}
.stats dt {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--text-secondary);
}
.stats dd {
  margin: var(--space-3xs) 0 0;
  font-family: var(--font-mono);
  font-size: 1.25rem;
  font-variant-numeric: tabular-nums;
}
.stats div:last-child:nth-child(odd) { grid-column: 1 / -1; } /* an odd last tile takes the row, instead of sitting beside an empty cell */

.map-list { list-style: none; padding: 0 !important; }
.map-item { display: flex; gap: var(--space-2xs); align-items: stretch; }
.map-read {
  flex: none;
  align-self: center;
  min-width: 4.5rem;
  min-height: 44px;
  padding: 0 var(--space-sm);
  border: 1px solid var(--border-color);
  border-radius: 10rem;
  white-space: nowrap;
  background: transparent;
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.05rem;
  text-transform: uppercase;
  cursor: pointer;
}
.map-read:hover { border-color: var(--text-primary); }
.map-go {
  flex: 1;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  padding: var(--space-xs) var(--space-sm);
  border: 1px solid var(--border-color);
  border-radius: 0.5rem;
  background: var(--bg-page);
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
}
.map-go:hover { border-color: var(--text-primary); }
/* The card is the drive-to button: a chevron at its edge says so (READ beside it looked like the only control) */
.map-go { position: relative; padding-right: 2.25rem; }
.map-go::after { content: "›"; position: absolute; right: var(--space-sm); top: 50%; transform: translateY(-50%); font-family: var(--font-mono); font-size: 1.5rem; line-height: 1; color: var(--text-secondary); }
.map-go:hover::after { color: var(--text-primary); }
.map-list strong { font-family: var(--font-body); font-size: 1rem; }
.map-list span { font-size: 0.875rem; color: var(--text-secondary); line-height: 1.4; }

:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }

@media (max-width: 1000px) {
  .sheet { padding: var(--space-lg); }
  .sheet h1 { font-size: 1.875rem; }
  .sheet h2 { font-size: 1.625rem; }
}
/* Below 1000px the full footer no longer fits one line at 12 px (an 834 px iPad in portrait wrapped it under the
   driving buttons; a 768 tablet did so at 11 px with the three.js credit): drop the live-data note, forbid wrapping,
   and sit the driving buttons clear above it */
@media (max-width: 1000px), (max-height: 500px) {
  .foot-live { display: none; }
  .hud-foot { flex-wrap: nowrap; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; gap: var(--space-xs); max-width: calc(100vw - 1rem); }
  .touch { bottom: calc(max(var(--space-2xs), env(safe-area-inset-bottom)) + 2.5rem); }
}
@media (max-width: 600px), (max-height: 500px) {
  .hud-title .br-label { display: none; }
  .foot-credit { display: none; } /* phones: the disclosure and the credit link are what fit */
  body:not(.guide-page) .hud-foot a[href="/stops/"] { display: none; } /* the stops page link lives on the intro and in Map view; at 11 px the line has no room for it on a 360 px phone */
  .hud-foot { font-size: 0.7rem; }
  .pad-btn { width: 4rem; height: 4rem; }
  .pad-gas { width: 4.75rem; height: 4.75rem; }
  .stick { width: 7.5rem; height: 4rem; }
}
.foot-short { display: none; }
@media (max-width: 400px) { /* the smallest phones: the shorter disclosure keeps the credit on screen */
  .stick { width: 6.5rem; } /* and the stick leaves room for the emote button and the two driving buttons */
  .foot-long { display: none; }
  .foot-short { display: inline; }
}
@media (max-height: 500px) { /* a phone on its side: less height to spend */
  .pad-btn { width: 3.5rem; height: 3.5rem; }
  .pad-gas { width: 4rem; height: 4rem; }
  .stick { width: 7.5rem; height: 3.5rem; }
  .hud-prompt { bottom: 7rem; }
}

@media (pointer: coarse) {
  .keys { display: none; }
  /* A 44px tap height for the credit link without moving the text */
  .hud-foot a { display: inline-block; padding-block: 17px; margin-block: -17px; }
  .sheet .muted a { display: inline-block; padding-block: 13px; margin-block: -13px; } /* the sheet's inline links too */
}

/* ── Graphics setting (in Map view) ─────────────────────────────────── */
.quality { border: 0; padding: 0; margin-left: 0; margin-right: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2xs); }
.quality legend {
  float: left;
  margin-right: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--text-secondary);
}
.quality button { min-height: 44px; }
.quality button[aria-pressed="true"] { background: var(--text-primary); color: var(--bg-page); border-color: var(--text-primary); }
.chip-sound { min-width: 44px; justify-content: center; } /* the short "♪" label alone is narrower than a tap target */
@media (max-width: 400px) { .chip-sound { display: none; } } /* the smallest phones: four chips do not fit beside the title; mute lives in Map view too */
/* The smallest phones with the longest district name (Community & Channels) and the who's-here chip: the title gives way, breaking a word only when it must */
@media (max-width: 480px) { .hud-title { min-width: 0; } .hud-district { hyphens: auto; } }
@media (max-width: 400px) { .hud-district { font-size: 1rem; } }
.chip-sound[aria-pressed="false"] { text-decoration: line-through; color: var(--text-secondary); }
.map-group { font-family: var(--font-mono); font-size: var(--label-size); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--text-secondary); }
.map-group-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); }
.map-list + .map-group-row { margin-top: var(--space-lg); }
.map-group-row + .map-list { margin-top: var(--space-2xs); }
.map-track > .map-best, .map-track + .map-list { margin-top: var(--space-xs); } /* Post my best sits under its track's top 3; race control's card under the track group */
.map-best p { margin: 0; font-size: 0.9rem; }
#map-groups > * + .map-track { margin-top: var(--space-lg); }
/* Phones: READ beside each card squeezed the description to a narrow column; put it underneath */
@media (max-width: 480px) {
  .map-item { flex-direction: column; }
  .map-read { align-self: flex-end; }
  .map-item + .map-item { margin-top: var(--space-xs); }
}

/* ── Open prompt: one panel, district-coloured edge, Enter keycap ──── */
.prompt-card {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-height: 56px;
  padding: var(--space-2xs) var(--space-2xs) var(--space-2xs) var(--space-md);
  border: 1px solid var(--border-color);
  border-left: 6px solid var(--prompt-colour, var(--text-primary));
  border-radius: 0.9rem;
  background: color-mix(in srgb, var(--bg-surface) 92%, transparent);
  color: var(--text-primary);
  box-shadow: 0 8px 24px var(--shadow-heavy);
  backdrop-filter: blur(8px);
  cursor: pointer;
  text-align: left;
}
.prompt-card:hover { border-color: var(--text-primary); border-left-color: var(--prompt-colour, var(--text-primary)); }
.prompt-text { display: flex; flex-direction: column; gap: 0.1rem; }
.prompt-eyebrow { font-family: var(--font-mono); font-size: var(--label-size); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--text-secondary); white-space: nowrap; }
.prompt-name { font-family: var(--font-display); font-weight: 600; font-size: 1.125rem; line-height: 1.2; }
.prompt-key {
  padding: 0.45rem 0.7rem;
  border-radius: 0.55rem;
  background: var(--text-primary);
  color: var(--bg-page);
  font-family: var(--font-mono);
  font-size: 0.8rem;
}
.prompt-key[hidden] { display: none; }

/* On touch screens the prompt sits above the driving buttons */
@media (pointer: coarse) { .hud-prompt { bottom: 10.5rem; } }

/* ── Loading screen: Strike's mark turning, like the one on HQ ───────── */
.loader {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--space-lg);
  background: var(--bg-page);
  transition: opacity 400ms ease;
  perspective: 600px;
}
.loader.is-done { opacity: 0; pointer-events: none; }
.loader-bar { width: min(16rem, 60vw); height: 2px; border-radius: 1px; background: var(--border-color); overflow: hidden; }
.loader-bar::after { content: ""; display: block; height: 100%; background: var(--text-primary); transform: scaleX(var(--p, 0)); transform-origin: left; transition: transform 350ms ease; }

/* ── The arrival: title card over the opening flight; the HUD waits until the car has landed ──────── */
.arrive {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  align-content: end;
  justify-items: center;
  text-align: center;
  padding: 0 var(--space-md) max(16vh, env(safe-area-inset-bottom));
  pointer-events: none;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 900ms ease, transform 900ms ease;
}
.arrive.is-in { opacity: 1; transform: none; }
.arrive p { margin: 0; text-shadow: 0 0 10px var(--bg-page), 0 0 2px var(--bg-page); }
/* The card's eyebrow and hint take the title's ink and halo: the grey measured about 2:1 over grass and road */
.arrive .br-label { color: var(--text-primary); font-size: 0.8125rem; margin-bottom: var(--space-xs); }
.arrive-title { font-family: var(--font-display); font-weight: 600; font-size: clamp(2.25rem, 7vw, 5rem); line-height: 1; letter-spacing: -0.02em; color: var(--text-primary); text-shadow: 0 2px 28px var(--bg-page), 0 0 2px var(--bg-page); }
.arrive-hint { margin-top: var(--space-lg); font-family: var(--font-mono); font-size: 0.8125rem; letter-spacing: 0.08rem; text-transform: uppercase; color: var(--text-primary); }
.arrive-tap { display: none; }
body:has(#touch:not([hidden])) .arrive-tap { display: inline; }
body:has(#touch:not([hidden])) .arrive-key { display: none; }
.hud, .touch { transition: opacity 700ms ease; }
/* The footer fades while driving (hud-math.js sets body.is-driving): out in 0.4 s with a small slide, back in 0.6 s once the car has been still a moment */
.hud-foot { transition: opacity 600ms ease, transform 600ms ease; }
body.is-driving .hud-foot { opacity: 0; transform: translate(-50%, 0.5rem); transition-duration: 400ms; }
body.is-driving .hud-foot a { pointer-events: none; }
body.is-arriving :is(.hud, .touch) { opacity: 0; pointer-events: none; transition: none; } /* gone at once; they fade back in */
@media (prefers-reduced-motion: reduce) { .arrive, .hud, .touch, .stick-knob { transition: none; } }
/* The mark turns like the coin on HQ: two faces back to back, each hiding its reverse, so whichever face comes
   round shows the mark the right way (one flat image turned in 3D showed it mirrored for half of every turn) */
.loader-coin { position: relative; width: 7.5rem; height: 7.5rem; transform-style: preserve-3d; animation: loader-turn 2.4s linear infinite; }
.loader-mark { position: absolute; inset: 0; width: 100%; height: 100%; -webkit-backface-visibility: hidden; backface-visibility: hidden; }
.loader-mark--back { transform: rotateY(180deg); }
.loader-text { margin: 0; font-family: var(--font-mono); font-size: var(--label-size); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--text-secondary); }
@keyframes loader-turn { from { transform: rotateY(0deg); } to { transform: rotateY(360deg); } }
@media (prefers-reduced-motion: reduce) { .loader-coin { animation: none; } }

/* ── RealFi Raceway: lap clock and finish sheet ─────────────────────── */
.race-hud {
  top: max(var(--space-sm), env(safe-area-inset-top));
  left: max(var(--space-sm), env(safe-area-inset-left));
  min-width: 12rem;
  padding: var(--space-2xs) var(--space-sm);
  border-radius: 0.75rem;
  border: 1px solid var(--border-color);
  border-top: 4px solid #0fb89c;
  background: color-mix(in srgb, var(--bg-surface) 90%, transparent);
  backdrop-filter: blur(6px);
  pointer-events: none;
}
.race-hud[hidden], .race-note[hidden], .race-form[hidden] { display: none; }
.race-time { font-family: var(--font-mono); font-size: 1.75rem; line-height: 1.2; font-variant-numeric: tabular-nums; }
.race-sub, .race-note { font-family: var(--font-mono); font-size: 0.75rem; color: var(--text-secondary); }
.race-note { margin-top: var(--space-3xs) !important; color: var(--text-primary); }
.race-result { font-family: var(--font-mono); font-size: 2.5rem !important; line-height: 1.1; font-variant-numeric: tabular-nums; }
.race-form { display: flex; flex-direction: column; gap: var(--space-2xs); }
.race-best-note { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-xs); }
.race-best-note[hidden] { display: none; }
.race-best-note p { margin: 0; }
/* The name field keeps at least 12rem; on a phone the button wraps under it rather than squeezing it */
.race-row { display: flex; flex-wrap: wrap; gap: var(--space-2xs); }
.race-row .br-input { flex: 1 1 12rem; min-width: 0; min-height: 44px; }
.race-row .br-button { flex: 0 0 auto; }
.race-top { margin: var(--space-2xs) 0 0; padding-left: 2rem !important; } /* room for "10." */
#map-groups > * + .map-group-row { margin-top: var(--space-lg); } /* the next district's row keeps its distance from the top 10 as well as from a list */
.race-top li { font-size: 0.95rem; }
.race-top li::marker { font-family: var(--font-mono); color: var(--text-secondary); }
.race-top li span:first-child { overflow-wrap: anywhere; }
.race-top-ms { float: right; margin-left: var(--space-sm); font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.race-top-empty { margin-top: var(--space-2xs) !important; }
/* Phones (portrait up to the Pro Max at 430 px): a compact strip beside the chips, and the theme chip steps aside while
   racing so the row fits a 360 px screen */
@media (max-width: 600px) {
  .race-hud { min-width: 0; padding: 0.3rem 0.7rem; border-top-width: 3px; }
  .race-time { font-size: 1.25rem; line-height: 1.15; }
  .race-sub { font-size: 0.65rem; }
  .race-result { font-size: 2rem !important; }
  body:has(#race-hud:not([hidden])) :is(#theme, #sound-chip) { display: none; } /* the timer panel needs the room; sound lives in Map view too */
}

/* ── Live races ─────────────────────────────────────────────────────── */
.race-go { margin-top: var(--space-2xs); pointer-events: auto; }
.race-go[hidden] { display: none; }
.race-invite .prompt-card { --prompt-colour: #0fb89c; cursor: default; pointer-events: auto; gap: var(--space-sm); flex-wrap: wrap; } /* the Raceway's teal, as on the lap clock */
.chip.chip--fill { background: var(--text-primary); color: var(--bg-page); border-color: var(--text-primary); } /* the invite's Join: the two chips read as one otherwise (doubled so it outranks the light theme's opaque-chip rule) */
.chip.chip--fill:hover { border-color: var(--text-primary); opacity: 0.9; }
.race-invite-actions { display: flex; gap: var(--space-2xs); }
.hud-prompt { max-width: calc(100vw - 1rem); }
@media (max-width: 480px) { .race-invite-actions { flex: 1 1 100%; justify-content: flex-end; } } /* the chips under the message, which they had squeezed to a word a line */

/* The board zoom (main.js focusBoard): the HUD and the driving controls go, a bar with Save the board and Back stays */
.focus-bar { left: 50%; bottom: max(var(--space-sm), env(safe-area-inset-bottom)); transform: translateX(-50%); display: flex; gap: var(--space-2xs); pointer-events: auto; }
.focus-bar[hidden] { display: none; }
body.is-focus :is(.hud:not(.focus-bar), .touch) { visibility: hidden; }
.race-live-line { margin: 0 0 var(--space-2xs); font-family: var(--font-mono); font-size: 0.875rem; letter-spacing: 0.04em; color: var(--text-secondary); }
.race-live-line[hidden] { display: none; }
.race-actions { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; margin: var(--space-sm) 0; }
.race-actions-hint { font-size: 0.875rem; }

/* ── ?fps=1 frame-time readout (dev only, fps.js) ───────────────────── */
.fps { position: fixed; left: var(--space-2xs); top: 42%; z-index: 20; margin: 0; padding: var(--space-2xs); font: 0.75rem/1.45 var(--font-mono); white-space: pre; color: #f9fafb; background: rgb(13 13 13 / 0.78); border-radius: 4px; pointer-events: none; }

