/* Boost Lab Turbo Run. Industrial, clean, styled like a dyno sheet. */

:root {
  --bl-orange: #d61e3b;
  --bl-orange-dark: #a3122b;
  --bl-black: #101216;
  --bl-ink: #1a1d23;
  --bl-panel: #20242b;
  --bl-panel-2: #2a2f37;
  --bl-line: #3a3f47;
  --bl-text: #f2f2f2;
  --bl-muted: #9aa3ad;
  --bl-warn: #e02828;
  --bl-ok: #34c759;
  --bl-paper: #f4f1ea;
  --bl-paper-ink: #1b1d22;
  --safe-top: env(safe-area-inset-top, 0px);
  /* The music button is pinned to the top right corner of every screen. This is
     the room a header leaves it: the button, plus a gap you can see. It was
     forty six, which cleared the button by four pixels and read as touching. */
  --bl-corner: 58px;
  /* How much of the garage the car gets. One height for the whole garage: it
     is one window, and a panel that moved as you went from tab to tab was
     something to keep up with rather than a layout. Dragged from the bar at the
     top of the panel, and this is only where it starts. */
  --garage-stage: 32vh;
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; overflow: hidden; background: var(--bl-black); color: var(--bl-text); font-family: var(--font); overscroll-behavior: none; touch-action: none; }
body { position: fixed; inset: 0; -webkit-user-select: none; user-select: none; -webkit-text-size-adjust: 100%; }
button { font: inherit; color: inherit; }
a { color: var(--bl-orange); }
b, strong { font-weight: 700; }
[hidden] { display: none !important; }

#app { position: fixed; inset: 0; }
#gl { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
#shimmer {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(ellipse at 50% 100%, rgba(255,120,40,0.18), transparent 60%);
  transition: opacity 200ms linear;
  animation: shimmer 1.1s ease-in-out infinite alternate;
}
@keyframes shimmer { from { transform: translateY(0) scaleX(1); } to { transform: translateY(-4px) scaleX(1.015); } }
/* The top end. The edges of the picture close in and go cold as the speed
   comes up, so a trap at two hundred does not look like a run to the shops.
   Opacity is driven per frame from the camera, so nothing animates here. */
#rush {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background:
    radial-gradient(ellipse 62% 52% at 50% 50%, transparent 38%, rgba(6,8,14,0.55) 100%),
    radial-gradient(ellipse 120% 40% at 50% 50%, transparent 55%, rgba(90,150,255,0.10) 100%);
}

/* Screens

   Screens toggle hidden, so every move between them was a hard cut. A short
   fade, and a small rise on the things inside a sheet, is enough to read as one
   screen replacing another rather than the page being swapped underneath you.

   Opacity only on the screen itself: a transform there would make a containing
   block, and the pads and the music button are positioned against the window.
   The strip gets none of it, because a pass starting with an animation is an
   animation over the tree. */
@keyframes bl-sheet-rise { from { opacity: 0; transform: translate3d(0, 12px, 0); } to { opacity: 1; transform: none; } }
/* The screen itself never fades. Fading it made its own background see through
   for the length of the fade, and what is behind every screen is the garage,
   still on the last car: leaving the garage flashed it for a sixth of a second
   on the way to wherever you were going. The contents arrive instead, over a
   background that is opaque from the first frame. */
.screen.sheet:not([hidden]) > * { animation: bl-sheet-rise 240ms cubic-bezier(0.2, 0.7, 0.3, 1) both; }
/* The head arrives first and the body just behind it. */
.screen.sheet:not([hidden]) > .sheet-head { animation-duration: 180ms; }
.screen.sheet:not([hidden]) > *:not(.sheet-head) { animation-delay: 40ms; }
@media (prefers-reduced-motion: reduce) {
  .screen.sheet:not([hidden]) > * { animation: none; }
  .turntable, .garage-panel { transition: none; }
}

/* Screens */
.screen { position: absolute; inset: 0; display: flex; flex-direction: column; padding: calc(var(--safe-top) + 10px) calc(var(--safe-right) + 14px) calc(var(--safe-bottom) + 14px) calc(var(--safe-left) + 14px); overflow: hidden; }
.screen.sheet { background: linear-gradient(180deg, #14171c 0%, #0f1115 100%); overflow-y: auto; touch-action: pan-y; -webkit-overflow-scrolling: touch; }
.screen.sheet::before { content: ""; position: fixed; left: 0; right: 0; top: 0; height: 4px; background: var(--bl-orange); }
/* A sheet is a scrolling column. Its panels keep their own height: as flex
   items they used to shrink to fit the screen instead, and a tall one (the
   results slip after a long pass) had its foot cut off with nothing to
   scroll, because the panel had shrunk rather than the sheet overflowed. */
.screen.sheet > * { flex: none; }
/* The music button is pinned to this corner on every screen, so a header runs
   its last thing, usually the credit balance, straight underneath it. The room
   it needs is reserved here rather than being found out one screen at a time. */
.sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 0 12px; border-bottom: 1px solid var(--bl-line); margin-bottom: 12px; min-height: 52px; }
.sheet-head.overlay { border: 0; margin: 0; position: absolute; left: calc(var(--safe-left) + 14px); right: calc(var(--safe-right) + 14px); top: calc(var(--safe-top) + 10px); z-index: 3; }
.sheet-brand { display: flex; align-items: center; gap: 10px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; font-size: 14px; }
.sheet-brand img { border-radius: 8px; }
.credits { font-size: 13px; color: var(--bl-muted); display: flex; align-items: center; gap: 6px; white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.credits b { color: var(--bl-text); font-family: var(--mono); }
.source-tag { font-size: 11px; color: var(--bl-muted); border: 1px solid var(--bl-line); padding: 3px 8px; border-radius: 999px; text-transform: uppercase; letter-spacing: 0.06em; }
.fine { font-size: 12px; color: var(--bl-muted); line-height: 1.45; }
.fine.center { text-align: center; margin-top: auto; padding-top: 14px; }
.fine.warn { color: var(--bl-warn); }
.loadout { margin-bottom: 12px; }
/* The car on the line, as a card rather than a sentence. */
.loadout-card { display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; grid-template-areas: "paint body garage" "paint chips chips" "paint note note"; gap: 6px 12px; align-items: center; padding: 10px 12px 10px 10px; border: 1px solid var(--bl-line); border-radius: 12px; background: linear-gradient(180deg, #1b1f26, #14171c); }
.loadout-card .lo-paint { grid-area: paint; align-self: stretch; width: 6px; border-radius: 3px; box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset; }
.loadout-card .lo-body { grid-area: body; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.loadout-card .lo-body small { font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--bl-orange); font-weight: 700; }
.loadout-card .lo-body b { font-size: 16px; font-weight: 800; letter-spacing: 0.01em; line-height: 1.15; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.loadout-card .lo-body span { font-size: 12px; color: var(--bl-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.loadout-card .lo-garage { grid-area: garage; min-height: 32px; padding: 4px 12px; font-size: 12px; background: transparent; border-color: var(--bl-line); color: var(--bl-muted); }
.loadout-card .lo-chips { grid-area: chips; display: flex; flex-wrap: wrap; gap: 5px; }
.loadout-card .lo-chips em { font-style: normal; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; padding: 2px 7px; border-radius: 999px; background: #22262e; color: var(--bl-muted); }
.loadout-card .lo-chips em.cls { background: rgba(214, 30, 59, 0.16); color: #ff8595; }
.loadout-card .lo-note { grid-area: note; margin: 0; font-size: 11px; color: var(--bl-muted); }
.loadout-card .lo-chips:empty, .loadout-card .lo-note:empty { display: none; }
.sheet-head .info-btn { margin-left: 0; }

/* Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 46px; padding: 10px 18px; border-radius: 10px; border: 1px solid var(--bl-line);
  background: var(--bl-panel); color: var(--bl-text); font-weight: 700; letter-spacing: 0.04em;
  text-decoration: none; cursor: pointer; touch-action: manipulation; transition: transform 90ms ease, background 120ms ease;
}
.btn:active { transform: scale(0.97); background: var(--bl-panel-2); }
.btn.primary { background: linear-gradient(180deg, var(--bl-orange) 0%, var(--bl-orange-dark) 100%); border-color: transparent; color: #fff; }
.btn.big { font-size: 18px; min-height: 58px; padding: 14px 40px; }
.btn.small { min-height: 36px; padding: 6px 12px; font-size: 13px; }
.btn.icon { width: 44px; min-height: 44px; padding: 0; }
.btn.icon.round { border-radius: 50%; background: rgba(16,18,22,0.7); }
.btn.locked { opacity: 0.55; }
/* Something that cannot be taken back: read before tapping. */
.btn.danger, .btn.primary.danger { background: linear-gradient(180deg, #8f1420 0%, #5d0c15 100%); border-color: #b3202f; color: #fff; }
.btn-row { display: flex; flex-wrap: wrap; gap: 8px; }
.btn:disabled { opacity: 0.45; pointer-events: none; }

/* Title */
#screen-title { justify-content: flex-end; align-items: center; text-align: center; background: #0f1115; overflow: hidden; padding-bottom: calc(var(--safe-bottom) + 34px); }
/* The hero: two cars leaving the line, slowly pushing in behind the title. */
.title-hero { position: absolute; inset: 0; z-index: 0; }
.title-hero img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%; animation: hero-push 18s ease-in-out infinite alternate; }
/* The reel: eight passes stacked on each other, one lit at a time. Only the
   first has a src in the page, so the front screen still paints on one image
   and the rest arrive as their turn comes round. */
.title-shot { position: absolute; inset: 0; opacity: 0; transition: opacity 1.8s ease-in-out; }
.title-shot.on { opacity: 1; }
.title-hero::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(15,17,21,0.15) 0%, rgba(15,17,21,0) 30%, rgba(15,17,21,0.55) 62%, rgba(15,17,21,0.96) 100%); }
@keyframes hero-push { from { transform: scale(1.02); } to { transform: scale(1.1); } }
.title-wrap { position: relative; z-index: 1; }
.title-wrap { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.logo { width: 120px; height: 120px; border-radius: 24px; box-shadow: 0 16px 40px rgba(0,0,0,0.5); }
.wordmark { width: min(86vw, 360px); height: auto; filter: drop-shadow(0 10px 24px rgba(0,0,0,0.6)); }
.sheet-brand img { border-radius: 8px; }
.title { margin: 0; line-height: 0; position: relative; display: inline-block; }
/* No filter on this image, at any point, animated or still. An iPhone rasterises
   a filtered layer of this size badly and what it draws instead is a white
   panel exactly where the logo goes: the game's own name, gone, on the first
   screen anybody sees. The glow behind it does the same job and costs nothing. */
.title-logo { display: block; width: min(86vw, 460px); height: auto; }

/* ------------------------------------------------------------- The intro
   The logo arrives rather than simply being there: it drops in as a glow blooms
   out behind it, and the line and the button follow it up. It runs for a second
   and a half and never blocks the button, which is live from the first frame.
   Opacity and transform only: those are the two things a phone can animate
   without redrawing the picture, and every attempt at anything richer here has
   ended with an iPhone painting a white box where the logo should be. */
@keyframes title-land {
  0%   { opacity: 0; transform: scale(1.24) translateY(-12px); }
  55%  { opacity: 1; transform: scale(0.982) translateY(0); }
  76%  { transform: scale(1.011); }
  100% { transform: scale(1); }
}
@keyframes title-bloom { 0% { opacity: 0; transform: scale(0.45); } 22% { opacity: 0.9; } 100% { opacity: 0; transform: scale(2); } }
@keyframes title-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

.title-logo { animation: title-land 900ms cubic-bezier(0.16, 0.9, 0.28, 1) both; }
.title-bloom {
  position: absolute; left: 50%; top: 50%; width: 120%; aspect-ratio: 1; translate: -50% -50%;
  border-radius: 50%; pointer-events: none; z-index: -1;
  background: radial-gradient(circle, rgba(214,30,59,0.55) 0%, rgba(214,30,59,0.14) 42%, rgba(214,30,59,0) 68%);
  animation: title-bloom 1100ms ease-out 120ms both;
}
#app.intro #screen-title .powered { animation: title-rise 600ms ease-out 620ms both; }
#app.intro #screen-title #btn-start { animation: title-rise 600ms ease-out 780ms both; }
#app.intro #screen-title #title-version { animation: title-rise 600ms ease-out 900ms both; }
.powered { color: var(--bl-muted); font-size: 14px; letter-spacing: 0.08em; text-transform: uppercase; }

/* Menu */
.menu-grid { display: grid; grid-template-columns: 1fr; gap: 10px; }
.menu-links { display: flex; justify-content: flex-end; margin: 6px 0 0; }
.menu-links .btn { color: var(--bl-muted); }
.btn.menu { flex-direction: column; align-items: flex-start; gap: 2px; min-height: 64px; padding: 12px 16px; text-align: left; overflow: hidden; }
.btn.menu > * { max-width: 100%; }
.menu-title { font-size: 17px; }
/* One line, whatever is in it. A long car and a long setup name together ran
   to three lines under each event and took the bottom of the menu off the
   screen; the panel says which car and which setup, and the garage says the
   rest. */
.menu-sub { font-size: 12px; color: var(--bl-muted); font-weight: 500; letter-spacing: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.btn.menu.primary .menu-sub { color: rgba(255,255,255,0.8); }

/* ---------------------------------------------------------------- Menu
   A hero band with the car that is in the garage, then the two events as
   big tiles, then everything else. The hero breaks out of the screen
   padding so the picture runs to the edges of the phone. */
.screen.menu { padding-top: 0; padding-left: 0; padding-right: 0; }
.screen.menu > *:not(.menu-hero) { margin-left: calc(var(--safe-left) + 14px); margin-right: calc(var(--safe-right) + 14px); }
.menu-hero { flex: none; position: relative; overflow: hidden; background: radial-gradient(115% 95% at 80% 12%, rgba(214,30,59,0.4) 0%, rgba(214,30,59,0.06) 52%, rgba(214,30,59,0) 72%), linear-gradient(158deg, #1e232b 0%, #12161c 56%, #0d0f13 100%); padding: calc(var(--safe-top) + 20px) calc(var(--safe-right) + 16px) 20px calc(var(--safe-left) + 16px); margin-bottom: 14px; border-bottom: 3px solid var(--bl-orange); border-radius: 0 0 20px 20px; min-height: 248px; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; gap: 16px; }
/* The mark, oversized and low, as a watermark. It drifts a little so the band is not dead still. */
.menu-hero-img { position: absolute; left: 50%; top: 52%; width: 62%; height: auto; opacity: 0.09; transform: translate(-50%, -50%) rotate(-9deg); animation: menu-drift 26s ease-in-out infinite alternate; }
/* Fine diagonal lines, the way a workshop floor or a race livery is scored. */
.menu-hero::before { content: ''; position: absolute; inset: 0; opacity: 0.5; background: repeating-linear-gradient(118deg, rgba(255,255,255,0.035) 0 2px, rgba(255,255,255,0) 2px 13px); }
.menu-hero::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(13,15,19,0) 46%, rgba(13,15,19,0.55) 100%); }
.menu-hero > *:not(.menu-hero-img) { position: relative; z-index: 1; }
/* The logo and the credits share a row in the markup. The row dissolves so
   both become items of the band itself: the logo centered on the screen rather
   than on whatever space the credits leave it, and the credits out of the flow
   in the corner. It reads the same on a phone and on a monitor. */
.menu-hero-top { display: contents; }
/* Same picture, same rule as the title: no filter on it. */
.menu-logo { order: -1; width: min(64vw, 300px); height: auto; }
/* The purse goes in the top left corner of the band, and only the number: on
   the right it was under the music button, in the middle of the band it was
   across the greeting, and spelled out it was across the logo. */
.menu-hero .credits { position: absolute; top: calc(var(--safe-top) + 12px); left: calc(var(--safe-left) + 16px); right: auto; z-index: 2; color: rgba(255,255,255,0.72); font-size: 0; gap: 5px; }
.menu-hero .credits b { font-size: 13px; }
.menu-hero .credits svg { width: 14px; height: 14px; }
.menu-hero-car { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.menu-kicker { font-size: 10px; font-weight: 800; letter-spacing: 0.18em; text-transform: uppercase; color: var(--bl-orange); }
/* A car with a long name and a supercharger kit with a longer one used to
   take four lines between them and push the bottom row of the menu off the
   screen. The name gets two lines at most and the setup gets one, so the band
   is the same height whatever is parked in it. */
.menu-car-name { font-size: 27px; line-height: 1.04; font-weight: 900; letter-spacing: 0.02em; text-transform: uppercase; text-shadow: 0 3px 14px rgba(0,0,0,0.6); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.menu-car-spec { font-family: var(--mono); font-size: 12.5px; color: rgba(255,255,255,0.82); letter-spacing: 0.02em; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.menu-greeting { margin: 6px 0 0; font-size: 12px; color: rgba(255,255,255,0.6); }
/* The greeting is a button: face, name, and the way to your own profile. */
button.menu-greeting { display: inline-flex; align-items: center; gap: 7px; background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.14); border-radius: 999px; padding: 2px 10px 2px 2px; font: inherit; font-size: 12px; line-height: 1; color: rgba(255,255,255,0.8); cursor: pointer; max-width: 100%; }
.menu-greeting .avatar.greet { width: 22px; height: 22px; margin: 0; }
.menu-greeting small { color: var(--bl-orange); font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; }
@keyframes menu-drift { from { transform: translate(-50%, -50%) rotate(-9deg) scale(1); } to { transform: translate(-50%, -52%) rotate(-6deg) scale(1.07); } }

/* A phone is not as tall as a desk monitor and the menu has to be one screen:
   everything on it is reachable without scrolling, so the band, the event
   panels and the tiles all give ground as the screen gets shorter. */
@media (max-height: 900px) {
  .menu-hero { min-height: 196px; gap: 10px; padding-top: calc(var(--safe-top) + 14px); padding-bottom: 16px; margin-bottom: 10px; }
  .menu-logo { width: min(58vw, 258px); }
  .menu-car-name { font-size: 22px; }
  .screen.menu .btn.menu.primary { min-height: 76px; padding: 12px 16px; }
  .screen.menu .btn.menu.primary .menu-title { font-size: 23px; }
  .btn.tile { min-height: 84px; }
  .menu-tiles { margin-top: 8px; gap: 8px; }
  .menu-grid { gap: 8px; }
}
@media (max-height: 740px) {
  .menu-hero { min-height: 128px; gap: 4px; padding-top: calc(var(--safe-top) + 10px); padding-bottom: 10px; margin-bottom: 8px; }
  .menu-logo { width: min(44vw, 190px); }
  .menu-car-name { font-size: 18px; }
  .menu-car-spec { font-size: 11.5px; }
  .menu-greeting { display: none; }
  .screen.menu .btn.menu.primary { min-height: 58px; padding: 9px 14px; }
  .screen.menu .btn.menu.primary .menu-title { font-size: 19px; }
  .btn.tile { min-height: 62px; padding: 10px 12px; }
  .btn.tile svg { width: 20px; height: 20px; }
  .btn.tile.small { min-height: 52px; }
  .btn.tile.wide { min-height: 48px; }
  .menu-tiles, .menu-grid { gap: 7px; }
  .menu-tiles { margin-top: 7px; }
  .screen.menu > p.fine.center { display: none; }
}
/* The smallest phone still in use. The band keeps the logo and the name of the
   car and gives up everything else, and nothing drops below a thumb sized
   target on the way. */
@media (max-height: 690px) {
  .menu-hero { min-height: 80px; }
  .menu-logo { width: min(36vw, 150px); }
  .menu-car-spec, .menu-hero .menu-kicker { display: none; }
  .screen.menu .btn.menu.primary { min-height: 50px; }
  .btn.tile { min-height: 50px; }
  .btn.tile.small { min-height: 44px; }
  .btn.tile.wide { min-height: 44px; }
  .menu-tiles, .menu-grid { gap: 5px; }
  .menu-tiles { margin-top: 5px; }
  .screen.menu { padding-bottom: calc(var(--safe-bottom) + 4px); }
  .menu-hero { min-height: 72px; margin-bottom: 6px; padding-top: calc(var(--safe-top) + 8px); padding-bottom: 8px; }
  .menu-car-name { font-size: 17px; -webkit-line-clamp: 1; }
}

/* The two events. A red panel with a sheen that crosses it now and then. */
.screen.menu .btn.menu.primary { position: relative; overflow: hidden; min-height: 86px; padding: 14px 18px; gap: 3px; background: linear-gradient(118deg, #e0263f 0%, #b31732 46%, #6f0f22 100%); border-color: rgba(255,255,255,0.16); box-shadow: 0 10px 26px rgba(160,18,40,0.3); }
.screen.menu .btn.menu.primary .menu-kicker { color: rgba(255,255,255,0.82); }
.screen.menu .btn.menu.primary .menu-title { font-size: 25px; font-weight: 900; text-transform: uppercase; letter-spacing: 0.03em; line-height: 1.05; }
.screen.menu .btn.menu.primary::after { content: ''; position: absolute; top: -60%; bottom: -60%; width: 40%; left: -55%; background: linear-gradient(100deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.16) 50%, rgba(255,255,255,0) 100%); transform: skewX(-18deg); animation: menu-sheen 7s ease-in-out infinite; }
.screen.menu .btn.menu.primary:nth-child(2)::after { animation-delay: 3.5s; }
@keyframes menu-sheen { 0%, 62% { left: -55%; } 88%, 100% { left: 125%; } }

/* Everything else: tiles with an icon, two across, three for the small ones. */
.menu-tiles { flex: none; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 10px; }
.screen.menu .menu-grid { flex: none; }
.menu-tiles.three { grid-template-columns: repeat(3, 1fr); }
.menu-tiles.four { grid-template-columns: repeat(4, 1fr); }
.menu-tiles.four .btn.tile.small { padding: 12px 4px; }
.menu-tiles.four .btn.tile.small .tile-title { font-size: 11.5px; }
.btn.tile { flex-direction: column; align-items: flex-start; gap: 4px; text-align: left; padding: 13px 14px; min-height: 96px; background: linear-gradient(160deg, #1c2028 0%, #14171c 100%); border-color: var(--bl-line); }
.btn.tile svg { width: 24px; height: 24px; color: var(--bl-orange); margin-bottom: 2px; }
.tile-title { font-size: 15px; font-weight: 800; letter-spacing: 0.02em; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Daily or weekly, on the title of every event tile, so the home screen
   says at a glance what turns over at midnight and what runs to Monday. */
.tile-when { margin-left: auto; font-size: 9.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; padding: 2px 7px; border-radius: 999px; border: 1px solid var(--bl-line); color: var(--bl-muted); font-style: normal; line-height: 1.3; }
.tile-when.daily { border-color: rgba(214, 30, 59, 0.45); color: #ff8595; }
.tile-when.weekly { border-color: rgba(120, 160, 255, 0.45); color: #9db7ff; }
.tile-sub { font-size: 11.5px; color: var(--bl-muted); font-weight: 500; letter-spacing: 0; line-height: 1.3; }
#menu-index b { color: var(--bl-ok); font-weight: 700; }
.tile-sub.on { color: #6ee89b; font-weight: 700; }
.tile-sub.on::before { content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--bl-ok); box-shadow: 0 0 6px var(--bl-ok); margin-right: 5px; vertical-align: 1px; }
.tile-sub:empty { display: none; }
/* The wide tile: the icon beside the title, the sub under the title. As a
   wrapping flex row the title centered itself on line one and the sub sat left
   on line two, which read as a mistake rather than a layout. */
.btn.tile.wide { grid-column: 1 / -1; display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "icon title" "icon sub"; align-content: center; justify-content: start; gap: 1px 12px; min-height: 68px; }
.btn.tile.wide svg { grid-area: icon; align-self: center; margin: 0; }
.btn.tile.wide .tile-title { grid-area: title; align-self: end; }
.btn.tile.wide .tile-sub { grid-area: sub; align-self: start; margin: 0; }
.btn.tile.small { min-height: 74px; align-items: center; text-align: center; justify-content: center; gap: 6px; padding: 12px 6px; }
.btn.tile.small .tile-title { font-size: 13px; }
.screen.menu .fine.center { margin-top: auto; padding-top: 16px; margin-bottom: 4px; }
@media (prefers-reduced-motion: reduce) {
  .menu-hero-img { animation: none; }
  .screen.menu .btn.menu.primary::after { animation: none; opacity: 0; }
  /* The intro is the first thing anybody sees, so it is also the first thing
     to go for somebody who has asked for less movement. */
  .title-logo, .title-bloom,
  #screen-title .powered, #screen-title #btn-start, #screen-title #title-version { animation: none; }
  .title-bloom { opacity: 0; }
}

/* Garage */
.screen.garage { padding: 0; }
/* No transition on this one. It is an invisible region the camera measures
   rather than anything anybody sees, and animating its height made a run of
   quick changes stall part way, leaving the split reading one number and
   measuring another. The panel below is what is actually seen to move. */
.turntable { position: absolute; left: 0; right: 0; top: calc(var(--safe-top) + 70px); height: var(--garage-stage); display: flex; align-items: center; justify-content: space-between; padding: 0 14px; pointer-events: auto; touch-action: none; cursor: grab; }
.turntable .btn { pointer-events: auto; }
.garage-panel { position: absolute; left: 0; right: 0; bottom: 0; top: calc(var(--safe-top) + 70px + var(--garage-stage)); transition: top 220ms ease; background: var(--bl-ink); border-top: 3px solid var(--bl-orange); border-radius: 18px 18px 0 0; display: flex; flex-direction: column; overflow: hidden; }
/* The lip of the panel is a handle: drag it and the split moves, and where it
   is left is remembered for that tab. How much of the garage the car is worth
   is a matter of taste and it changes with what you are doing, so it is set
   rather than decided here. */
.panel-grip { display: block; width: 100%; height: 22px; padding: 0; margin: 0; border: 0; background: transparent; cursor: ns-resize; touch-action: none; flex: none; }
.panel-grip span { display: block; width: 44px; height: 4px; margin: 9px auto; border-radius: 2px; background: var(--bl-line); transition: background 120ms ease; }
.panel-grip:active span, .panel-grip:hover span { background: var(--bl-orange); }
#app[data-gripping="1"] .turntable, #app[data-gripping="1"] .garage-panel { transition: none; }

.tabs { display: flex; border-bottom: 1px solid var(--bl-line); }
.tab { flex: 1; min-height: 44px; background: transparent; border: 0; color: var(--bl-muted); font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; font-size: 13px; }
.tab.active { color: var(--bl-text); box-shadow: inset 0 -3px 0 var(--bl-orange); }
.tab-body { flex: 1; overflow-y: auto; touch-action: pan-y; -webkit-overflow-scrolling: touch; padding: 12px 14px 14px; }
.garage-actions { padding: 10px 14px calc(var(--safe-bottom) + 10px); border-top: 1px solid var(--bl-line); display: flex; gap: 8px; }
.garage-actions .btn { flex: 1; }
/* Each strip's button with a test and tune under it: a solo pass that posts
   nothing, for setting a car up before an index or a race. */
.garage-go { flex: 1; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.garage-go .btn { flex: none; width: 100%; }
.garage-go .btn.garage-test { min-height: 30px; padding: 4px 8px; font-size: 12px; background: transparent; border-color: var(--bl-line); color: var(--bl-muted); }
.garage-go .btn.garage-test:hover { color: var(--bl-text); border-color: var(--bl-muted); }
.garage-go .btn.garage-test[hidden] { display: none; }

/* Spec sheets */
.spec { background: var(--bl-paper); color: var(--bl-paper-ink); border-radius: 10px; padding: 12px 14px; margin-bottom: 10px; box-shadow: 0 6px 18px rgba(0,0,0,0.35); position: relative; overflow: hidden; }
.spec::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 6px; background: var(--bl-orange); }
.spec.oem::before { background: #6b7280; }
.spec.locked { opacity: 0.8; }
.spec.selected { outline: 3px solid var(--bl-orange); }
.spec-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; margin-bottom: 6px; }
.spec-title { font-weight: 900; font-size: 16px; letter-spacing: 0.02em; text-transform: uppercase; }
.spec-brand { font-size: 11px; color: #5b616b; text-transform: uppercase; letter-spacing: 0.1em; }
.spec-sku { font-family: var(--mono); font-size: 11px; background: #1b1d22; color: #fff; padding: 3px 7px; border-radius: 4px; white-space: nowrap; }
.spec-desc { font-size: 12.5px; line-height: 1.4; color: #3a3f47; margin: 4px 0 8px; }
/* What a wheel figure on the card above means, said once under it. */
.spec-foot { font-size: 11px; line-height: 1.35; color: #6b7178; margin: 6px 0 0; }
.spec-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px 10px; font-size: 12px; }
.spec-grid div { border-top: 1px solid #d5d0c4; padding-top: 4px; }
.spec-grid span { display: block; color: #6b7280; font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; }
.spec-grid b { font-family: var(--mono); font-size: 13px; }
.spec-graph { width: 100%; height: 110px; display: block; margin-top: 8px; border-radius: 6px; background: #ebe6db; }
.spec-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; align-items: center; }
.spec-actions .btn { min-height: 38px; padding: 6px 12px; font-size: 13px; }
/* The link to the real unit. It sits at the far end of the row from the buy
   button on purpose: one of those spends credits in a game and the other one
   leaves for a shop, and they should not look like a pair. */
.spec-link { font-size: 12px; font-weight: 700; color: var(--bl-orange-dark); margin-left: auto; text-decoration: underline; text-underline-offset: 3px; }
/* What a unit is for, worked out from its own curve. Set apart from the maker's
   description above it, because one is a blurb and the other is an opinion. */
.spec-advice { border-left: 3px solid var(--bl-orange); padding: 2px 0 2px 10px; margin: 8px 0 10px; }
.spec-advice h4 { margin: 0 0 3px; font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bl-orange-dark); }
.spec-advice p { margin: 0 0 4px; font-size: 12.5px; line-height: 1.45; color: #3a3f47; }
.spec-advice p:last-child { margin-bottom: 0; }
.difficulty { display: inline-flex; gap: 2px; }
.difficulty i { width: 8px; height: 8px; border-radius: 2px; background: #cfc9bc; }
.difficulty i.on { background: var(--bl-orange); }
.car-spec .spec-title { font-size: 20px; }
/* Wear and tear, as a bar. Green while it is fresh, amber once it is costing
   power, red when it wants a rebuild. */
/* Moving a game to another browser: two halves, one for each end of it. */
.move-half { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--bl-line); text-align: left; }
.move-half:first-of-type { border-top: 0; padding-top: 0; }
.move-half h3 { font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--bl-orange); }
.move-half .fine { margin: 4px 0 10px; }
.move-half .row { display: flex; gap: 8px; }
.move-half input { flex: 1; min-width: 0; padding: 11px 12px; border-radius: 10px; border: 1px solid var(--bl-line); background: #0e1116; color: var(--bl-text); font: inherit; font-family: var(--mono); font-size: 18px; letter-spacing: 0.18em; text-transform: uppercase; }
/* A line of text that is a button: asking where the code comes from should
   not look like another thing to press before the code arrives. */
.btn.link { display: inline; min-height: 0; padding: 0; border: 0; background: none; font: inherit; font-weight: 700; color: var(--bl-orange); text-decoration: underline; letter-spacing: inherit; }
.btn.link:active { transform: none; background: none; }
/* The drawing on a how to card: a screen with the thing to press marked. */
.howto-art { margin: 2px 0 4px; }
.howto-art svg { display: block; width: 100%; height: auto; }
/* The shop's own small print: ids and counts, where the shape matters. */
.fine.mono { font-family: var(--mono); font-size: 11px; letter-spacing: 0; color: var(--bl-muted); }
/* Picking between two saved games: two buttons, each saying what it holds. */
.garage-pick { display: flex; flex-direction: column; gap: 8px; }
.garage-pick .btn { flex-direction: column; align-items: flex-start; gap: 2px; min-height: 62px; text-align: left; }
.garage-pick .btn small { font-weight: 600; letter-spacing: 0; color: var(--bl-muted); font-size: 12px; }
.move-code { margin-top: 10px; font-family: var(--mono); font-size: 30px; font-weight: 800; letter-spacing: 0.22em; color: var(--bl-text); text-align: center; }
#modal-move .btn-row { margin-top: 14px; }
/* A short card of steps, for the things a browser will not do for us. */
#howto-steps { margin: 12px 0 4px; padding-left: 22px; display: flex; flex-direction: column; gap: 8px; }
#howto-steps li { font-size: 14px; line-height: 1.45; }
/* About: the model credits, folded away until somebody wants them. */
.credits-block { margin-top: 16px; border-top: 1px solid rgba(0,0,0,0.12); padding-top: 10px; }
.credits-block summary { cursor: pointer; font-size: 13px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; list-style: none; display: flex; align-items: center; gap: 8px; }
.credits-block summary::-webkit-details-marker { display: none; }
.credits-block summary::after { content: '+'; margin-left: auto; font-size: 16px; font-weight: 700; opacity: 0.6; }
.credits-block[open] summary::after { content: '\2013'; }
.credit-list { margin: 8px 0 2px; padding-left: 18px; }
.credit-list li { font-size: 11.5px; line-height: 1.5; color: #55606d; }
/* A pass somebody ran against your garage, in the card that greets you. */
.bout { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 12px; padding: 9px 0; border-top: 1px solid var(--bl-line); text-align: left; }
.bout:first-child { border-top: 0; }
/* Name and verdict on the first line, the car and the two times under it. */
.bout b { grid-area: 1 / 1; font-size: 14px; font-weight: 800; }
.bout em { grid-area: 1 / 2; font-style: normal; font-size: 12px; font-weight: 800; color: #d61e3b; text-align: right; white-space: nowrap; }
.bout.held em { color: #4ec06a; }
.bout span { grid-area: 2 / 1; font-size: 12px; color: var(--bl-muted); }
.bout i { grid-area: 2 / 2; font-style: normal; font-size: 12px; color: var(--bl-muted); text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
#bouts-list { margin: 10px 0 4px; }
/* The card behind this is paper white, so the panel says what its own colors
   are rather than inheriting ink meant for a light background. */
.health { margin-top: 10px; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--bl-line); background: #14171c; color: #f2f2f3; }
.health-head { display: flex; align-items: baseline; gap: 8px; }
.health-head b { font-size: 11.5px; letter-spacing: 0.08em; text-transform: uppercase; color: #f2f2f3; }
.health-head span { flex: 1; font-size: 12px; color: #9aa3ad; }
.health-head em { font-style: normal; font-size: 13px; font-weight: 800; color: #f2f2f3; }
.health .fine { color: #9aa3ad; }
.meter { height: 7px; margin-top: 7px; border-radius: 4px; background: #23272e; overflow: hidden; }
.meter i { display: block; height: 100%; border-radius: 4px; background: #f2b64c; transition: width 200ms ease; }
.health.good .meter i { background: #4ec06a; }
.health.warn .meter i { background: #d61e3b; }
.health .fine { margin-top: 6px; }
.health .btn { margin-top: 8px; }
.car-note { font-size: 11px; color: #6b7280; margin-top: 6px; font-style: italic; }
/* A turbo maker's own artwork on the spec card, in place of their name. */
.spec-brand .brand-logo { display: block; height: 22px; width: auto; max-width: 190px; object-fit: contain; margin-bottom: 3px; }
.spec-brand .spec-housing { display: block; font-size: 10px; opacity: 0.75; }
.car-gate { width: 100%; border: 1px solid var(--bl-line); border-radius: 8px; padding: 9px 11px; background: var(--bl-ink); }
.car-gate .gate-head { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: #f2b64c; }
.car-gate ul { margin: 7px 0 0; padding-left: 16px; }
.car-gate li { font-size: 11px; color: var(--bl-muted); line-height: 1.5; }
/* Boost past what the unit is rated for: said on the slider, not in the bill. */
.tune-warn { grid-column: 1 / -1; margin: 6px 0 0; font-size: 11px; line-height: 1.45; color: #f2b64c; }

.car-note.warn, .estimate-warn { color: #f2b64c; font-style: normal; font-size: 11px; margin-top: 6px; grid-column: 1 / -1; }

/* Tune sliders */
.tune-row { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--bl-line); }
.tune-row label { font-size: 13px; font-weight: 700; }
.tune-row small { display: block; color: var(--bl-muted); font-weight: 400; font-size: 11px; margin-top: 2px; }
.tune-row output { font-family: var(--mono); font-size: 13px; color: var(--bl-orange); min-width: 64px; text-align: right; }
.tune-row input[type="range"] { grid-column: 1 / -1; width: 100%; accent-color: var(--bl-orange); height: 32px; }
/* A vertical swipe over a slider scrolls the sheet; only a sideways drag moves it. */
.tune-row input[type="range"], .gear-row input[type="range"], .field.inline input[type="range"] { touch-action: pan-y; }
/* The Tune tab keeps a clear lane down its right edge to scroll by, dotted like a grip. */
#garage-tune { position: relative; padding-right: 62px; }
#garage-tune::after { content: ''; position: absolute; top: 0; right: 8px; bottom: 0; width: 40px; border-radius: 8px; background: radial-gradient(circle, rgba(255,255,255,0.22) 1.6px, transparent 2.2px) 50% 0 / 12px 12px repeat-y; pointer-events: none; }
.tune-row .switch { justify-self: end; }
.switch { position: relative; width: 48px; height: 28px; border-radius: 14px; background: var(--bl-line); border: 0; }
.switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: #fff; transition: transform 120ms ease; }
.switch.on { background: var(--bl-orange); }
.switch.on::after { transform: translateX(20px); }
.presets { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0 4px; }
.presets .btn { min-height: 34px; padding: 4px 12px; font-size: 12px; }
/* Setups kept by name: the tune on the page can be filed, and any filed one
   loaded back over it. A row is the name, what it was built on and how it
   simulated, then Load and a small remove. */
.saved-tunes { display: flex; flex-direction: column; gap: 6px; margin: 6px 0 4px; }
.saved-tune { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid var(--bl-line); border-radius: 10px; background: rgba(255, 255, 255, 0.03); }
.saved-tune .saved-name { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.saved-tune .saved-name b { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.saved-tune .saved-name small { color: var(--bl-muted); font-size: 11px; }
.saved-tune .btn.small { min-height: 30px; padding: 2px 10px; }
.saved-tune .saved-x { min-height: 30px; min-width: 30px; padding: 0 8px; font-size: 16px; line-height: 1; opacity: 0.7; }
.saved-empty { color: var(--bl-muted); font-size: 12px; margin: 2px 0 6px; }
#tunename-input { font-family: var(--font, system-ui, sans-serif); font-size: 18px; font-weight: 700; text-align: center; }
.tune-graph { width: 100%; height: 120px; background: var(--bl-panel); border-radius: 8px; margin-top: 10px; display: block; }
.section-title { font-size: 11px; text-transform: uppercase; letter-spacing: 0.12em; color: var(--bl-muted); margin: 12px 0 6px; }

/* Track list */
.track-list { display: flex; flex-direction: column; gap: 10px; }
.track-card { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 12px; padding: 12px 14px; text-align: left; align-items: center; }
.track-card.locked { opacity: 0.6; }
.track-card h3 { font-size: 16px; text-transform: uppercase; letter-spacing: 0.04em; }
.track-card p { font-size: 12px; color: var(--bl-muted); grid-column: 1 / -1; line-height: 1.4; }
.track-card .meta { font-size: 11px; color: var(--bl-muted); font-family: var(--mono); text-align: right; }
.track-card .best { grid-column: 1 / -1; font-size: 12px; font-family: var(--mono); color: var(--bl-orange); }
.track-card .env { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--bl-muted); }

/* Race HUD */
.screen.race { padding: 0; pointer-events: none; }
.hud { position: absolute; inset: 0; pointer-events: none; }
.hud-top { position: absolute; left: calc(var(--safe-left) + 10px); right: calc(var(--safe-right) + 10px); top: calc(var(--safe-top) + 8px); display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
.hud-block { background: rgba(12,14,18,0.72); border: 1px solid var(--bl-line); border-radius: 8px; padding: 6px 10px; min-width: 88px; }
.hud-block.center { text-align: center; flex: 1; max-width: 190px; }
.hud-label { display: block; font-size: 10px; letter-spacing: 0.12em; color: var(--bl-muted); }
.hud-block b { font-family: var(--mono); font-size: 18px; display: block; white-space: nowrap; }
.hud-block b.long { font-size: 14px; letter-spacing: -0.02em; }
.hud-best { font-size: 10px; color: var(--bl-muted); letter-spacing: 0.08em; }
.hud-best i { font-style: normal; font-family: var(--mono); color: var(--bl-orange); }
#minimap { width: 96px; height: 96px; background: rgba(12,14,18,0.6); border: 1px solid var(--bl-line); border-radius: 8px; }
/* Above the tree, under the lane card, and painted over every gauge and bar
   whatever the order they come in: the status banner sat early in the HUD
   and the tires bar drawn after it covered COMPRESSOR SURGE. Kirk. */
.hud-status { position: absolute; left: 50%; top: calc(27% - 41px); z-index: 6; transform: translate(-50%, 0); background: rgba(12,14,18,0.8); border: 1px solid var(--bl-line); color: var(--bl-text); padding: 6px 14px; border-radius: 6px; font-weight: 800; letter-spacing: 0.1em; font-size: 14px; opacity: 0; transition: opacity 150ms; white-space: nowrap; }
.hud-status.show { opacity: 1; }
.hud-status.warn { border-color: var(--bl-warn); color: #ff6b6b; }
.hud-status.good { border-color: var(--bl-ok); color: #6ee89b; }
.hud-drift { position: absolute; right: 16px; top: 34%; font-family: var(--mono); font-weight: 800; font-size: 20px; color: var(--bl-orange); opacity: 0; transition: opacity 120ms; text-shadow: 0 2px 8px rgba(0,0,0,0.6); }
.hud-drift.show { opacity: 1; }
.hud-egt { position: absolute; left: 50%; transform: translateX(-50%); top: calc(var(--safe-top) + 78px); display: flex; align-items: center; gap: 8px; font-size: 10px; letter-spacing: 0.12em; color: var(--bl-muted); }
.egt-track { position: relative; width: 120px; height: 8px; background: rgba(12,14,18,0.7); border: 1px solid var(--bl-line); border-radius: 4px; overflow: hidden; }
/* The window the compound wants to be in, drawn on the track so a burnout is
   something to judge rather than something to hold until the bar stops. */
.egt-band { position: absolute; top: 0; bottom: 0; background: rgba(52,199,89,0.28); box-shadow: inset 1px 0 0 rgba(52,199,89,0.9), inset -1px 0 0 rgba(52,199,89,0.9); pointer-events: none; }
.egt-bar { height: 100%; width: 0; background: #ffb020; transition: width 100ms linear; }
.egt-bar.on { background: #ff8a1f; }
.egt-bar.hot { background: var(--bl-warn); }
.hud-egt.tires { top: calc(var(--safe-top) + 100px); }
/* In the burnout the tire gauge is the whole game, so it gets big: the window
   to hit and the needle to hold in it, readable with a thumb over the pad. */
.hud-egt.tires, .hud-egt.tires .egt-track { transition: width 220ms ease, height 220ms ease, font-size 220ms ease; }
/* Anchored between the left gutter and the track map rather than centered on
   the screen: centered, a wide bar reaches under the map, and the map is 96px
   hard against the right edge. Bounded by the map's own gutter, it cannot
   touch it at any width. */
.hud-egt.tires.burnout { left: calc(var(--safe-left) + 10px); right: calc(var(--safe-right) + 112px); transform: none; font-size: 14px; letter-spacing: 0.16em; gap: 12px; }
.hud-egt.tires.burnout .egt-track { width: auto; flex: 1; max-width: 320px; height: 18px; border-radius: 9px; border-color: rgba(255,255,255,0.35); }
.egt-bar.tires { background: #8fd0ff; }
.egt-bar.tires.on { background: #34c759; }
/* Past the window: going off, and on a soft compound going off hard. */
.egt-bar.tires.cooked { background: var(--bl-warn); }
.tune-row .seg { justify-self: end; }
.hud-gauges { position: absolute; left: 0; right: 0; bottom: calc(var(--safe-bottom) + 182px); display: flex; justify-content: space-between; align-items: flex-end; padding: 0 8px; }
.gauge { width: calc(118px * var(--gauge-scale, 1)); height: calc(118px * var(--gauge-scale, 1)); }
.hud-speed { text-align: center; padding-bottom: 6px; }
.hud-speed b { font-family: var(--mono); font-size: calc(44px * var(--gauge-scale, 1)); line-height: 1; text-shadow: 0 2px 10px rgba(0,0,0,0.7); display: block; }
.hud-speed span { font-size: 11px; letter-spacing: 0.2em; color: var(--bl-muted); }
.hud-speed em { display: block; font-style: normal; font-family: var(--mono); font-size: calc(20px * var(--gauge-scale, 1)); color: var(--bl-orange); margin-top: 2px; }
.debug-panel { position: absolute; left: 10px; top: calc(var(--safe-top) + 110px); background: rgba(12,14,18,0.85); border: 1px solid var(--bl-orange); border-radius: 8px; padding: 6px 8px; font-family: var(--mono); font-size: 11px; width: 190px; }
.debug-panel div { display: flex; justify-content: space-between; gap: 6px; }
.debug-panel span { color: var(--bl-muted); }
.countdown { position: absolute; left: 50%; top: 40%; transform: translate(-50%, -50%); font-size: 96px; font-weight: 900; font-family: var(--mono); color: var(--bl-orange); text-shadow: 0 4px 24px rgba(0,0,0,0.8); }
.countdown.go { color: var(--bl-ok); }
/* The card that says what to do on the line. It was nowrap with no width, so
   the sentence under BURNOUT ran off both edges of a phone and off both edges
   harder on a small one. The title is short; the sentence wraps. */
/* Who is in the other lane, for the whole pass: under the distance chip. */
.lane-card { position: absolute; left: 50%; z-index: 5; transform: translateX(-50%); top: calc(var(--safe-top) + 172px); display: flex; gap: 6px; align-items: center; background: rgba(12,14,18,0.7); border: 1px solid var(--bl-line); border-radius: 999px; padding: 3px 10px 3px 4px; font-size: 11px; color: var(--bl-muted); white-space: nowrap; max-width: calc(100vw - 32px); overflow: hidden; text-overflow: ellipsis; }
.lane-card #lane-card-face:empty { display: none; }
.lane-card #lane-card-face:empty + b { margin-left: 6px; }
.lane-card .avatar.lane { width: 20px; height: 20px; margin: 0; }
.lane-intro .avatar.intro { width: 64px; height: 64px; margin: 2px 0 4px; border-color: var(--bl-orange); }
.lane-card b { color: var(--bl-text); font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; }
.lane-card em { font-style: normal; font-family: var(--mono); }
/* The lower third under the opening sweep. */
.lane-intro { position: absolute; left: calc(var(--safe-left) + 16px); top: 50%; transform: translateY(-50%); display: flex; flex-direction: column; gap: 2px; padding: 12px 16px; border-left: 3px solid var(--bl-orange); background: linear-gradient(90deg, rgba(12,14,18,0.9), rgba(12,14,18,0.4)); max-width: 78vw; animation: lane-in 260ms ease-out; }
.lane-intro small { font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--bl-orange); font-weight: 700; }
.lane-intro b { font-size: 26px; line-height: 1.05; text-transform: uppercase; letter-spacing: 0.02em; }
.lane-intro span { font-size: 14px; color: var(--bl-text); }
.lane-intro em { font-style: normal; font-family: var(--mono); font-size: 12px; color: var(--bl-muted); }
.lane-intro i { font-style: normal; font-size: 10px; color: var(--bl-muted); margin-top: 6px; letter-spacing: 0.08em; text-transform: uppercase; }
@keyframes lane-in { from { transform: translate(-16px, -50%); } to { transform: translate(0, -50%); } }
/* The burnout and stage instructions: a bar under the tree, never over it.
   The card they used to be sat at mid screen, which is where the tree's
   green lamps are. The tree is 148px tall from 27% down; the gauges and the
   pads take the bottom 300px, so on a short phone the bar tucks up to
   clear them instead. */
.race-msg { position: absolute; left: 50%; top: min(calc(27% + 154px), calc(100% - 348px)); z-index: 6; transform: translateX(-50%); display: flex; gap: 10px; align-items: center; background: rgba(12,14,18,0.85); border: 1px solid var(--bl-line); padding: 6px 12px; border-radius: 8px; font-size: 13px; font-weight: 900; letter-spacing: 0.06em; text-align: left; white-space: normal; width: min(92vw, 420px); box-sizing: border-box; }
.race-msg small { display: block; flex: 1; font-size: 11px; color: var(--bl-muted); font-weight: 600; letter-spacing: 0.02em; line-height: 1.3; text-wrap: pretty; }
.drag-tree { position: absolute; left: 50%; top: 27%; transform: translateX(-50%) scale(0.72); transform-origin: top center; opacity: 0.95; transition: opacity 0.6s; display: flex; flex-direction: column; gap: 6px; background: rgba(12,14,18,0.85); padding: 8px; border-radius: 10px; border: 1px solid var(--bl-line); }
.drag-tree.fade { opacity: 0; }
.drag-tree i { width: 26px; height: 26px; border-radius: 50%; background: #2a2e35; display: block; }
.drag-tree i.on[data-light="stage"] { background: #f2f2f2; box-shadow: 0 0 12px #fff; }
.drag-tree i.on[data-light^="amber"] { background: #ffb020; box-shadow: 0 0 12px #ffb020; }
.drag-tree i.on[data-light="green"] { background: #30ff60; box-shadow: 0 0 14px #30ff60; }
.drag-tree i.on[data-light="red"] { background: #ff2020; box-shadow: 0 0 14px #ff2020; }
.btn.pause { position: absolute; right: calc(var(--safe-right) + 10px); top: calc(var(--safe-top) + 112px); pointer-events: auto; background: rgba(12,14,18,0.7); }

/* Touch controls */
.controls { position: absolute; left: 0; right: 0; bottom: 0; height: calc(var(--safe-bottom) + 176px); pointer-events: none; }
.steer-zones { position: absolute; left: calc(var(--safe-left) + 8px); bottom: calc(var(--safe-bottom) + 10px); display: flex; gap: 8px; pointer-events: auto; }
.zone { width: 78px; height: 150px; border-radius: 14px; background: rgba(32,36,43,0.72); border: 1px solid var(--bl-line); display: flex; align-items: center; justify-content: center; color: var(--bl-muted); touch-action: none; }
.zone.active { background: rgba(255,90,31,0.5); color: #fff; }
.steer-slider { position: absolute; left: calc(var(--safe-left) + 10px); bottom: calc(var(--safe-bottom) + 10px); width: 40%; height: 64px; pointer-events: auto; display: none; touch-action: none; }
.slider-track { position: absolute; left: 0; right: 0; top: 22px; height: 20px; border-radius: 10px; background: rgba(32,36,43,0.8); border: 1px solid var(--bl-line); }
.slider-track i { position: absolute; left: 50%; top: -8px; width: 36px; height: 36px; margin-left: -18px; border-radius: 50%; background: var(--bl-orange); }
#app[data-steer-mode="slider"] .steer-slider { display: block; }
#app[data-steer-mode="slider"] .steer-zones, #app[data-steer-mode="tilt"] .steer-zones { display: none; }
.pedals { position: absolute; right: calc(var(--safe-right) + 8px); bottom: calc(var(--safe-bottom) + 10px); display: flex; gap: 8px; align-items: flex-end; pointer-events: auto; }
.pedal { border-radius: 14px; border: 1px solid var(--bl-line); background: rgba(32,36,43,0.78); color: var(--bl-text); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; touch-action: none; font-weight: 800; letter-spacing: 0.06em; }
.pedal span { font-size: 9px; color: var(--bl-muted); letter-spacing: 0.14em; }
.pedal b { font-size: 12px; }
.pedal.throttle { width: 86px; height: 150px; background: rgba(255,90,31,0.28); border-color: rgba(255,90,31,0.6); }
.pedal.brake { width: 64px; height: 110px; }
.pedal.kick { width: 60px; height: 84px; }
.pedal.active { background: rgba(255,90,31,0.75); color: #fff; }
/* The key on a pad, for anybody with a keyboard. Hidden on a phone: the page
   is marked keyboard=yes by a fine pointer with hover, or by a real keypress. */
.pedal kbd { display: none; margin-top: 3px; font: 700 9px var(--mono); letter-spacing: 0.08em; border: 1px solid currentColor; border-radius: 4px; padding: 1px 5px; opacity: 0.75; }
[data-keyboard="yes"] .pedal kbd { display: inline-block; }
.keylist { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; align-items: center; font-size: 12px; }
.keylist kbd { font: 700 11px var(--mono); border: 1px solid var(--bl-line); border-radius: 4px; padding: 1px 6px; margin-right: 4px; color: var(--bl-text); }
.keylist small { display: block; color: var(--bl-muted); }
.keylist .keys { white-space: nowrap; }
.pedal.active span { color: #fff; }
.shift-col { display: none; flex-direction: column; gap: 6px; }
#app[data-manual="1"] .shift-col { display: flex; }
.pedal.small { width: 46px; height: 46px; font-size: 11px; }
.pause-menu { position: absolute; inset: 0; background: rgba(8,10,14,0.78); display: flex; align-items: center; justify-content: center; pointer-events: auto; }
.pause-card { background: var(--bl-ink); border: 1px solid var(--bl-line); border-radius: 14px; padding: 20px; display: flex; flex-direction: column; gap: 10px; width: min(300px, 86vw); }
.pause-card h2 { text-align: center; text-transform: uppercase; letter-spacing: 0.1em; font-size: 18px; margin-bottom: 4px; }

/* Results */
.results-card { background: var(--bl-paper); color: var(--bl-paper-ink); border-radius: 12px; padding: 16px; box-shadow: 0 8px 26px rgba(0,0,0,0.4); position: relative; overflow: hidden; }
.results-card::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 8px; background: repeating-linear-gradient(90deg, var(--bl-orange) 0 20px, var(--bl-black) 20px 40px); }
.results-card h2 { font-size: 22px; text-transform: uppercase; letter-spacing: 0.06em; margin: 0; }
/* Who won and by how much, once, across the top. A slip is read for that one
   thing first and the card used to say it three times in three weights. */
.verdict { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: 4px 12px;
  margin: 10px 0 2px; padding: 12px 14px; border-radius: 10px; border-left: 6px solid #9aa3ad; background: #ece8df; }
/* The one word the slip is read for, set big enough to be that. It was the
   same size as the track name above it, and the card read as a form. */
.verdict h2 { font-size: 30px; letter-spacing: 0.08em; line-height: 1; }
.verdict span { font-family: var(--mono); font-size: 15px; font-weight: 700; color: #4a5059; }
.verdict.win { border-left-color: #1f9d4d; background: #e6f3ea; }
.verdict.win h2 { color: #14612f; }
.verdict.lose { border-left-color: var(--bl-orange); background: #f7e6e8; }
.verdict.lose h2 { color: var(--bl-orange-dark); }
/* The header of a printed slip: the strip, the car and the unit set in a
   black band the way a real one carries the track's name, not a gray line. */
.results-card .sub { font-size: 11px; color: #d9d4c8; background: var(--bl-black); text-transform: uppercase; letter-spacing: 0.12em; padding: 9px 12px; margin: 2px -16px 0; font-weight: 700; }
.results-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 14px; margin-top: 12px; }
.results-grid div { border-top: 1px solid #d5d0c4; padding-top: 6px; }
.results-grid span { display: block; font-size: 10px; color: #6b7280; text-transform: uppercase; letter-spacing: 0.1em; }
.results-grid b { font-family: var(--mono); font-size: 20px; }
/* One tone, one meaning. hl is the number the card is about, warn is what the
   pass cost you, good is what went your way. */
.results-grid b.hl { color: var(--bl-paper-ink); }
.results-grid b.warn { color: var(--bl-orange-dark); }
.results-grid b.good { color: #14612f; }
/* A heading inside the grid, so the block under the slip reads as how the pass
   went rather than as more result fields in the same weight. */
.results-head { border-top: none !important; padding-top: 10px !important; margin-top: 2px;
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: #6b7280; font-weight: 800; }
/* A second line under a figure, for the cells where the number on its own does
   not say what it means. Kept off the mono face so it does not read as data. */
.results-grid b small { display: block; margin-top: 1px; font-family: var(--font); font-size: 11px; font-weight: 600; line-height: 1.35; color: #6b7280; letter-spacing: 0; }
.results-grid .wide { grid-column: 1 / -1; }
.slip { width: 100%; border-collapse: collapse; margin-top: 6px; font-family: var(--mono); font-size: 14px; }
.slip th { text-align: left; font-weight: 600; color: #6b7280; font-size: 11px; letter-spacing: 0.08em; padding: 3px 0; width: 22%; }
.slip td { text-align: right; padding: 4px 0 4px 8px; border-bottom: 1px dashed #d5d0c4; }
/* Every other row tinted, so the eye runs across a row and not down a column
   of near identical numbers, and the finish row set off with a solid rule. */
.slip tbody tr:nth-child(even) th, .slip tbody tr:nth-child(even) td { background: rgba(0,0,0,0.03); }
.slip tbody tr:has(b) th, .slip tbody tr:has(b) td { border-top: 2px solid #b9b3a6; border-bottom: 2px solid #b9b3a6; padding: 7px 0 7px 8px; }
.slip tbody tr:has(b) td { font-size: 22px; font-weight: 800; }
.slip .slip-car { display: block; font-size: 9px; letter-spacing: 0.04em; color: var(--bl-muted); text-transform: none; }
.slip thead td { font-size: 10px; letter-spacing: 0.1em; color: #6b7280; border-bottom: 2px solid #d5d0c4; }
.slip b.hl { color: var(--bl-orange-dark); }
/* The lane that won, marked on the column rather than on the numbers. Coloring
   numbers put the same red on the time you ran and the time that beat it. */
.slip td.lane-win { background: rgba(31, 157, 77, 0.10); }
.slip thead td.lane-win { color: #14612f; }
.slip tbody td.lane-win { font-weight: 700; }
.slip .lane-flag { display: block; font-size: 9px; letter-spacing: 0.12em; color: #1f9d4d; font-weight: 800; line-height: 1.2; }
.slip thead td { vertical-align: bottom; }
.results-card .earned { margin-top: 12px; font-weight: 800; color: var(--bl-orange-dark); font-family: var(--mono); }
.results-card .rank { margin-top: 6px; font-size: 13px; }
.results-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px; }
.results-actions .btn:first-child { grid-column: 1 / -1; }
.results-actions.with-tune .btn:last-child { grid-column: 1 / -1; }
#garage-race.rerun { background: var(--bl-orange); }

/* Leaderboard */
.filters { display: flex; gap: 8px; margin-bottom: 10px; }
.filters label { flex: 1; font-size: 11px; color: var(--bl-muted); text-transform: uppercase; letter-spacing: 0.08em; display: flex; flex-direction: column; gap: 4px; }
select, input[type="text"], input[type="number"], textarea, input:not([type]) { width: 100%; background: var(--bl-panel); color: var(--bl-text); border: 1px solid var(--bl-line); border-radius: 8px; padding: 9px 10px; font: inherit; font-size: 14px; }
.lb-table { display: flex; flex-direction: column; gap: 4px; }
.lb-row { display: grid; grid-template-columns: 30px minmax(70px, 1.1fr) 1.6fr auto; gap: 8px; align-items: center; background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 8px; padding: 8px 10px; font-size: 13px; }
.lb-note { margin: 0 0 8px; }
.lb-row.head { background: transparent; border: 0; color: var(--bl-muted); font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em; }
.lb-row.me { border-color: var(--bl-orange); }
.lb-row .rank { font-family: var(--mono); color: var(--bl-muted); }
.lb-row .name { font-family: var(--mono); font-weight: 800; letter-spacing: 0.1em; }
.lb-row .setup { font-size: 11px; color: var(--bl-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-row .time { font-family: var(--mono); text-align: right; }
.lb-row .time small, .lb-mine .time small { display: block; font-size: 10px; color: var(--bl-muted); font-family: var(--font); }
.lb-empty { color: var(--bl-muted); font-size: 13px; padding: 20px 0; text-align: center; }

/* About */
.about-card { background: var(--bl-paper); color: var(--bl-paper-ink); border-radius: 12px; padding: 18px; box-shadow: 0 8px 26px rgba(0,0,0,0.4); }
.about-card h2 { font-size: 22px; text-transform: uppercase; letter-spacing: 0.06em; }
.about-card p { font-size: 14px; line-height: 1.5; margin-top: 10px; }
.about-card .addr { font-family: var(--mono); font-size: 14px; line-height: 1.6; margin-top: 12px; border-left: 4px solid var(--bl-orange); padding-left: 12px; }
.about-card .addr a { color: var(--bl-orange-dark); text-decoration: none; font-weight: 700; }
.about-card .btn { margin-top: 14px; width: 100%; }

/* Settings */
.settings { display: flex; flex-direction: column; gap: 6px; }
.setting { display: flex; justify-content: space-between; align-items: center; gap: 10px; background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 10px; padding: 10px 12px; min-height: 54px; }
.setting label { font-size: 14px; font-weight: 700; }
.setting small { display: block; font-size: 11px; color: var(--bl-muted); font-weight: 400; margin-top: 2px; }
.setting .seg { display: flex; gap: 4px; }
.seg .btn { min-height: 34px; padding: 4px 10px; font-size: 12px; }
.seg .btn.on { background: var(--bl-orange); border-color: transparent; color: #fff; }

/* Editor */
.screen.editor { background: #0f1115; overflow-y: auto; touch-action: pan-y; }
.editor-body { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 900px) { .editor-body { grid-template-columns: 1.2fr 1fr; } }
.editor-graph-wrap { background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 10px; padding: 8px; }
#editor-graph { width: 100%; height: 280px; display: block; touch-action: none; border-radius: 6px; background: #14171c; }
.editor-estimates { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin: 10px 0; }
.editor-estimates div { background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 8px; padding: 6px 8px; }
.editor-estimates span { display: block; font-size: 9px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--bl-muted); }
.editor-estimates b { font-family: var(--mono); font-size: 15px; }
.editor-tools { display: flex; flex-direction: column; gap: 8px; }
.field { display: flex; flex-direction: column; gap: 4px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--bl-muted); }
.field.inline { flex-direction: row; align-items: center; justify-content: space-between; text-transform: none; letter-spacing: 0; font-size: 13px; color: var(--bl-text); padding: 6px 0; border-bottom: 1px solid var(--bl-line); gap: 10px; }
.field.inline input, .field.inline select { width: 50%; }
.field.inline input[type="range"] { width: 45%; accent-color: var(--bl-orange); }
.field.inline output { font-family: var(--mono); font-size: 12px; color: var(--bl-orange); min-width: 44px; text-align: right; }
.field.inline small { display: block; font-size: 10px; color: var(--bl-muted); }
.editor-right { background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 10px; padding: 10px 12px; }
.editor-right h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.12em; color: var(--bl-orange); margin: 14px 0 2px; }
.editor-right h3:first-child { margin-top: 0; }
/* What a group of numbers decides, under its heading. */
.editor-about { margin: 0 0 6px; font-size: 11.5px; line-height: 1.4; }
/* A field is labeled the way you would say it; the key it carries in the file
   sits under it in small type for whoever is writing one. */
.field.inline span { flex: 1 1 auto; min-width: 0; }
.field.inline i { font-style: normal; color: var(--bl-muted); font-size: 11px; font-family: var(--mono); }
.field.inline code { display: block; font-family: var(--mono); font-size: 9.5px; color: #5c626b; letter-spacing: 0; margin-top: 1px; }
/* What the bench is, and what it is not, before anything is dragged. */
.editor-note { font-size: 12.5px; line-height: 1.5; color: var(--bl-muted); background: #14171c; border: 1px solid var(--bl-line); border-left: 3px solid var(--bl-orange); border-radius: 0 10px 10px 0; padding: 10px 14px; margin-bottom: 12px; }
.editor-note code { font-family: var(--mono); font-size: 11.5px; color: var(--bl-text); }
.editor-compare-list { display: flex; gap: 6px; flex-wrap: wrap; }
.editor-compare-list .chip { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; padding: 4px 10px; border-radius: 999px; border: 1px solid; background: rgba(0,0,0,0.3); }
.editor-compare-list .chip button { background: none; border: 0; color: inherit; font-weight: 800; }
.editor-head-actions { display: flex; gap: 6px; }
.error-list { color: var(--bl-warn); font-size: 12px; }

/* The eye on a password field. A password typed blind on a phone keyboard that
   has already autocapitalized the first letter is a password nobody can tell
   is wrong, so every one of them can be looked at. The button sits inside the
   field's own box rather than beside it, so the row does not grow a column. */
.pw { position: relative; display: block; }
.pw > input { width: 100%; padding-right: 44px; }
.pw > .eye { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; padding: 0; border: 0; border-radius: 8px; background: none; color: var(--bl-muted); }
.pw > .eye:active { color: var(--bl-orange); }
.pw > .eye[aria-pressed="true"] { color: var(--bl-orange); }
.pw > .eye svg { width: 20px; height: 20px; display: block; }

/* Modal and toast */
.modal { position: absolute; inset: 0; background: rgba(8,10,14,0.8); display: flex; align-items: center; justify-content: center; z-index: 20; padding: 20px; }
/* The face picker opens from the profile as well as from Settings, so it sits
   above every other card: it came before the profile in the markup and opened
   behind it, out of sight. */
#modal-avatar { z-index: 21; }
.modal-card { background: var(--bl-ink); border: 1px solid var(--bl-line); border-radius: 14px; padding: 20px; width: min(340px, 92vw); display: flex; flex-direction: column; gap: 10px; }
.modal-card h2 { font-size: 18px; text-transform: uppercase; letter-spacing: 0.08em; }
#name-input { font-family: var(--font, system-ui, sans-serif); font-size: 22px; font-weight: 700; text-align: center; letter-spacing: 0.02em; }
/* The email and password sit under the name as one block, so setting up a
   racer reads as one thing to do rather than three. */
#name-account { display: flex; flex-direction: column; gap: 8px; }
#name-account input { padding: 11px 12px; border-radius: 10px; border: 1px solid var(--bl-line); background: #0e1116; color: var(--bl-text); font: inherit; font-size: 16px; }
/* Under the header, where the eye is. It used to sit at the bottom, over
   the buttons, and a message about a motor that had let go went unread. */
.toast { position: absolute; left: 50%; top: calc(var(--safe-top) + 74px); transform: translateX(-50%); animation: toast-in 180ms ease-out; background: var(--bl-ink); border: 1px solid var(--bl-orange); color: var(--bl-text); padding: 10px 16px; border-radius: 10px; font-size: 13px; font-weight: 700; z-index: 30; max-width: 90vw; text-align: center; }
/* A slide only, no fade: a phone that is busy drawing the garage can sit
   on an animation's first frame for a while, and the first frame of a fade
   is nothing. */
@keyframes toast-in { from { transform: translate(-50%, -8px); } to { transform: translate(-50%, 0); } }
@keyframes toast-in-left { from { transform: translate(0, -8px); } to { transform: translate(0, 0); } }
/* On the race screen a toast drops into the gap under the tree's message,
   clear of the clocks, the bars and the gauges. */
.toast.race { top: calc(27% + 230px); }
.toast.tappable { cursor: pointer; pointer-events: auto; background: var(--bl-orange); color: #101216; border-color: var(--bl-orange); }
.loading { position: absolute; inset: 0; background: var(--bl-black); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; z-index: 40; color: var(--bl-muted); font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; }
.spinner { width: 40px; height: 40px; border-radius: 50%; border: 4px solid var(--bl-line); border-top-color: var(--bl-orange); animation: spin 0.9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Landscape phones: tighten the vertical budget. */
@media (max-height: 460px) {
  .gauge { width: calc(84px * var(--gauge-scale, 1)); height: calc(84px * var(--gauge-scale, 1)); }
  .hud-gauges { bottom: calc(var(--safe-bottom) + 120px); }
  .controls { height: calc(var(--safe-bottom) + 118px); }
  .zone { height: 100px; width: 70px; }
  .pedal.throttle { height: 100px; }
  .pedal.brake { height: 80px; }
  .pedal.kick { height: 64px; }
  #app { --garage-stage: 24vh; }
}

/* Landscape: the garage panel becomes a side sheet so the turntable keeps the left half. */
@media (orientation: landscape) and (min-width: 640px) {
  .turntable { right: 54%; top: calc(var(--safe-top) + 60px); height: auto; bottom: 0; }
  .garage-panel { left: 46%; top: calc(var(--safe-top) + 60px); border-radius: 18px 0 0 0; border-left: 1px solid var(--bl-line); }
  .menu-grid { grid-template-columns: 1fr 1fr; max-width: 900px; margin: 0 auto; width: 100%; }
  .screen.sheet > .sheet-head, .track-list, .results-card, .results-actions, .about-card, .settings, .filters, .lb-table, .loadout { max-width: 900px; margin-left: auto; margin-right: auto; width: 100%; }
  .screen.sheet > .sheet-head { margin-bottom: 12px; }
}

/* Drag strip layout: LAUNCH and SHIFT replace steering and pedals. */
.drag-controls { position: absolute; left: calc(var(--safe-left) + 10px); right: calc(var(--safe-right) + 10px); bottom: calc(var(--safe-bottom) + 12px); display: none; gap: 12px; pointer-events: auto; }
#app[data-layout="drag"] .drag-controls { display: flex; }
#app[data-layout="drag"] .steer-zones, #app[data-layout="drag"] .steer-slider, #app[data-layout="drag"] .pedals { display: none; }
/* A piece the player has placed: pinned to the window where they put it, and
   out of whatever row or centering the stylesheet had it in. */
.placed { position: absolute !important; right: auto !important; bottom: auto !important; margin: 0 !important; flex: none !important; z-index: 3; }
/* Placed pieces live in a layer of their own over the whole screen, so no
   container's own transform or row has a say in where they land. The pads
   keep taking touches there, and keep to the strip and stay out of a replay. */
#hud-placed { position: absolute; inset: 0; pointer-events: none; }
#hud-placed .pedal { pointer-events: auto; }
#app:not([data-layout="drag"]) #hud-placed .pedal { display: none !important; }
#app[data-replay="on"] #hud-placed { display: none; }
.arr-guide { position: fixed; background: var(--bl-orange); pointer-events: none; z-index: 22; box-shadow: 0 0 6px rgba(214,30,59,0.8); }
.arr-guide.v { width: 2px; top: 0; height: 100vh; }
.arr-guide.h { height: 2px; left: 0; width: 100vw; }
.hud-egt.tires.placed, .hud-egt.tires.burnout.placed { max-width: none; }
/* The arrange screen: the strip as it is, the pads switched off, a box round every piece. */
.arranging [data-control] { pointer-events: none !important; }
/* No pulsing on the arrange screen: a pad that breathes cannot be measured or placed. */
.arranging .pulse { animation: none !important; transform: none !important; }
.arranging .pause, .arranging .race-msg, .arranging .drag-info, .arranging .lane-card { display: none !important; }
.arrange { position: absolute; inset: 0; pointer-events: none; z-index: 20; }
.arrange-bar { position: absolute; left: 50%; top: calc(var(--safe-top) + 150px); transform: translateX(-50%); display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; background: rgba(12,14,18,0.92); border: 1px solid var(--bl-orange); border-radius: 12px; padding: 10px 14px; pointer-events: auto; width: max-content; max-width: min(720px, calc(100vw - 24px)); z-index: 22; }
/* The words take the row and the buttons drop under them on a phone: side
   by side, three buttons left the words a column one word wide, and the
   card ran most of the way down the screen. */
.arrange-bar > div:first-child { flex: 1 1 240px; min-width: 0; }
.arrange-acts { margin-left: auto; }
.arrange-bar b { display: block; font-size: 14px; }
.arrange-bar small { display: block; font-size: 11px; color: var(--bl-muted); line-height: 1.35; }
.arrange-acts { display: flex; gap: 6px; flex: none; }
.arr-box { position: fixed; border: 2px dashed rgba(255,255,255,0.7); border-radius: 8px; box-sizing: border-box; pointer-events: auto; cursor: move; touch-action: none; z-index: 21; background: rgba(214,30,59,0.06); }
.arr-box:hover, .arr-box:active { border-color: var(--bl-orange); background: rgba(214,30,59,0.14); }
.arr-box span { position: absolute; left: 0; top: -18px; font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: #fff; background: var(--bl-orange); border-radius: 4px; padding: 1px 6px; pointer-events: none; }
.arr-knob { position: absolute; right: -9px; bottom: -9px; width: 22px; height: 22px; border-radius: 50%; background: var(--bl-orange); border: 2px solid #fff; cursor: nwse-resize; touch-action: none; }
/* Index racing: three cards, and the ladder. */
.index-card { background: var(--bl-ink); border: 1px solid var(--bl-line); border-radius: 10px; padding: 10px 12px; margin-top: 8px; }
.index-head { display: flex; align-items: baseline; gap: 8px; }
.index-head b { font-family: var(--mono); font-size: 22px; font-weight: 800; }
.index-head span { font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bl-muted); }
.index-head em { margin-left: auto; font-style: normal; font-weight: 800; color: var(--bl-orange); font-family: var(--mono); }
.index-card.done { border-color: rgba(52, 199, 89, 0.55); }
.index-card.in { border-color: rgba(214, 30, 59, 0.55); }
/* The state strip under the index: open, so many runs in, or done with a
   check. The pips are the three runs, filled as they go in. */
.index-strip { display: flex; align-items: center; gap: 8px; margin: 6px 0 2px; min-height: 20px; }
.index-state { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; letter-spacing: 0.02em; }
.index-state.open { color: var(--bl-muted); font-weight: 600; }
.index-state.off { color: var(--bl-muted); font-weight: 600; }
.index-state.in { color: var(--bl-text); }
.index-state.done { color: var(--bl-ok); }
.index-state.done svg { width: 16px; height: 16px; }
.index-pips { display: inline-flex; gap: 4px; }
.index-pips i { width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--bl-orange); box-sizing: border-box; }
.index-pips i.on { background: var(--bl-orange); }
.index-facts { font-size: 12px; color: var(--bl-muted); margin: 4px 0 8px; line-height: 1.4; }
/* The action on top, full width; the two boards as an even pair under it. */
.mode-card .row.index-actions { display: grid; grid-template-columns: 1fr; gap: 6px; }
.index-actions .btn { min-height: 38px; padding: 6px 10px; font-size: 13px; width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.index-boards { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.index-boards .btn { font-size: 12px; padding: 6px 6px; }
.index-facts b { color: var(--bl-text); }
.index-list { display: flex; flex-direction: column; gap: 4px; margin: 8px 0; }
.index-row { display: grid; grid-template-columns: 28px 1fr auto; gap: 8px; align-items: center; background: var(--bl-ink); border: 1px solid var(--bl-line); border-radius: 8px; padding: 6px 10px; font-size: 12px; }
.index-row.mine { border-color: var(--bl-orange); }
.index-row .place { font-family: var(--mono); font-weight: 800; color: var(--bl-muted); }
.index-row .place.top { color: var(--bl-orange); }
.index-row small { display: block; color: var(--bl-muted); font-size: 10px; }
.index-row .entry { font-family: var(--mono); text-align: right; }
.index-row .entry.bad { color: #ff8a8a; }
.index-ladder { display: flex; gap: 10px; overflow-x: auto; padding: 4px 0; }
.index-round { display: flex; flex-direction: column; justify-content: space-around; gap: 6px; min-width: 130px; }
.index-round h4 { margin: 0; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bl-muted); }
.index-pair { background: var(--bl-ink); border: 1px solid var(--bl-line); border-radius: 6px; font-size: 11px; }
.index-pair span { display: block; padding: 3px 8px; color: var(--bl-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 150px; }
.index-pair span.win { color: var(--bl-text); font-weight: 700; }
.index-pair span + span { border-top: 1px solid var(--bl-line); }
/* The latest races between friends. */
.match-list { display: flex; flex-direction: column; gap: 6px; }
.match-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 8px; background: var(--bl-ink); border: 1px solid var(--bl-line); border-radius: 8px; padding: 6px 10px; }
.match-lane { display: flex; flex-direction: column; min-width: 0; }
.match-lane:last-child { text-align: right; }
.match-lane b { font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.match-lane small { font-size: 10px; color: var(--bl-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.match-lane i { font-style: normal; font-family: var(--mono); font-size: 12px; color: var(--bl-muted); }
.match-lane.won b { color: var(--bl-orange); }
.match-lane.won i { color: var(--bl-text); }
.match-vs { display: flex; flex-direction: column; align-items: center; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--bl-muted); }
.match-vs small { font-size: 9px; letter-spacing: 0; text-transform: none; }
/* Replay: the towers get a clean picture, so everything but the strip bar goes. */
#app[data-replay="on"] .hud-top, #app[data-replay="on"] .hud-gauges, #app[data-replay="on"] .hud-egt,
#app[data-replay="on"] .controls, #app[data-replay="on"] .drag-info, #app[data-replay="on"] .pause,
#app[data-replay="on"] .hud-status, #app[data-replay="on"] .drag-tree, #app[data-replay="on"] .drag-controls { display: none; }
.replay-bar { position: absolute; left: calc(var(--safe-left) + 10px); right: calc(var(--safe-right) + 10px); bottom: calc(var(--safe-bottom) + 14px); display: flex; align-items: center; gap: 10px; background: rgba(12,14,18,0.82); border: 1px solid var(--bl-line); border-radius: 10px; padding: 8px 10px; pointer-events: auto; }
.replay-bar b { font-size: 12px; letter-spacing: 0.1em; flex: 1; }
.replay-tag { font-size: 10px; font-weight: 800; letter-spacing: 0.16em; color: #fff; background: var(--bl-orange); border-radius: 4px; padding: 3px 6px; }
.replay-read { display: flex; flex-direction: column; align-items: flex-end; font-family: var(--mono); font-size: 12px; }
.replay-read i { font-style: normal; }
.replay-read i:last-child { color: var(--bl-muted); font-size: 10px; }
.replay-bar .btn { padding: 6px 12px; }
.pedal.launch, .pedal.shift { flex: 1; height: 150px; font-size: 22px; }
.pedal.launch { background: rgba(214,30,59,0.32); border-color: rgba(214,30,59,0.75); }
.pedal.shift { background: rgba(52,199,89,0.22); border-color: rgba(52,199,89,0.6); }
.pedal.launch b, .pedal.shift b { font-size: 24px; }
/* Pressed.
   A thumb covers the middle of the pad, so a signal put on the label is a
   signal nobody sees: only the letters lit up, and on the launch and shift pads
   not even that, because their own color was declared after the pressed one
   and quietly won. The whole pad lights instead, from the edges in, and shrinks
   under the finger the way a real button does. */
.pedal.active { background: rgba(255,90,31,0.9); border-color: rgba(255,170,120,0.95); color: #fff; transform: scale(0.965); box-shadow: inset 0 0 0 2px rgba(255,255,255,0.8), 0 0 22px rgba(255,120,50,0.6); }
.pedal.active span, .pedal.active b { color: #fff; }
.pedal.launch.active { background: rgba(214,30,59,0.95); border-color: rgba(255,150,170,0.95); box-shadow: inset 0 0 0 2px rgba(255,255,255,0.85), 0 0 26px rgba(214,30,59,0.75); }
.pedal.shift.active { background: rgba(52,199,89,0.92); border-color: rgba(170,255,195,0.95); box-shadow: inset 0 0 0 2px rgba(255,255,255,0.85), 0 0 26px rgba(52,199,89,0.7); }
.pedal.brake.active { background: rgba(214,30,59,0.85); border-color: rgba(255,150,170,0.9); box-shadow: inset 0 0 0 2px rgba(255,255,255,0.8), 0 0 22px rgba(214,30,59,0.6); }
.drag-tree b { display: flex; gap: 4px; justify-content: center; }
.drag-tree b i { width: 11px; height: 11px; }
.drag-tree i.on[data-light="prestage"], .drag-tree i.on[data-light="stage"] { background: #ffd020; box-shadow: 0 0 8px #ffd020; }
/* Kept clear of the pause button in the corner, and allowed to wrap rather than
   run out under it: a career event name and a rival's name together are longer
   than a phone is wide. */
.drag-info { position: absolute; left: 50%; transform: translateX(-50%); top: calc(var(--safe-top) + 128px); background: rgba(12,14,18,0.8); border: 1px solid var(--bl-line); border-radius: 8px; padding: 6px 12px; font-family: var(--mono); font-size: 12px; color: var(--bl-muted); white-space: normal; text-align: center; line-height: 1.4; max-width: calc(100vw - var(--bl-corner) * 2 - 16px); box-sizing: border-box; }
.drag-info b { color: var(--bl-text); }
.drag-modes { display: flex; flex-direction: column; gap: 10px; }
/* The mode tabs: one row that scrolls sideways rather than wrapping, so six
   of them fit a phone without stacking. */
.drag-tabs { flex: none; overflow-x: auto; scrollbar-width: none; margin-bottom: 2px; }
.drag-tabs::-webkit-scrollbar { display: none; }
.drag-tabs .tab { flex: none; padding: 0 13px; white-space: nowrap; }
.mode-card { background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 12px; padding: 12px 14px; }
.mode-card h3 { font-size: 16px; text-transform: uppercase; letter-spacing: 0.04em; display: flex; justify-content: space-between; align-items: center; }
.mode-card h3 span { font-size: 11px; color: var(--bl-muted); font-family: var(--mono); letter-spacing: 0; text-transform: none; }
.mode-card p { font-size: 12px; color: var(--bl-muted); line-height: 1.4; margin: 4px 0 8px; }
.mode-card .row { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.mode-card .row .btn { min-height: 36px; padding: 6px 12px; font-size: 13px; }
.mode-card .row .btn.on { background: var(--bl-orange); border-color: transparent; color: #fff; }
.mode-card input[type="number"] { width: 110px; font-family: var(--mono); }
.ladder { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; }
.ladder div { display: grid; grid-template-columns: 24px 1fr auto; gap: 8px; font-size: 12px; align-items: center; padding: 4px 0; border-bottom: 1px solid var(--bl-line); }
.ladder .avatar.rung { width: 18px; height: 18px; margin-right: 4px; }
.ladder div.done { color: var(--bl-muted); }
/* A rung already won is run again for the time: it reads as a button. */
.ladder div.done[data-rerun] { cursor: pointer; }
.ladder div.done[data-rerun]:active { color: var(--bl-text); }
.ladder div.done[data-rerun] small { color: var(--bl-orange); font-family: var(--mono); }
.ladder div.next { color: var(--bl-orange); font-weight: 700; }
.ladder div.locked { opacity: 0.45; }
.ladder span:first-child { font-family: var(--mono); }
.gear-row { display: grid; grid-template-columns: 18px 34px 1fr 34px 104px; gap: 6px; align-items: center; padding: 4px 0; font-size: 12px; }
/* A thumb cannot find one hundredth of a ratio on a slider. These can. */
.nudge {
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0; flex: none;
  border: 1px solid var(--bl-line); border-radius: 8px;
  background: var(--bl-panel); color: var(--bl-text);
  font-size: 18px; font-weight: 700; line-height: 1;
  cursor: pointer; touch-action: manipulation; user-select: none;
}
.nudge:active { background: var(--bl-panel-2); transform: scale(0.94); }
/* The final drive keeps its own row, so its pair sits either side of the track. */
.slider-nudge { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; }
.slider-nudge input[type="range"] { flex: 1; min-width: 0; }
.gear-row input[type="range"] { accent-color: var(--bl-orange); height: 28px; }
.gear-row output { font-family: var(--mono); color: var(--bl-orange); text-align: right; font-size: 11px; white-space: nowrap; }
.gear-row span { font-family: var(--mono); color: var(--bl-muted); }
.dyno-sheet { background: var(--bl-paper); color: var(--bl-paper-ink); border-radius: 10px; padding: 12px 14px; }
.dyno-sheet canvas { width: 100%; height: 190px; display: block; background: #ebe6db; border-radius: 6px; }
.dyno-sheet .spec-grid { margin-top: 8px; }
.dyno-sheet h3 { font-size: 16px; text-transform: uppercase; letter-spacing: 0.04em; }
.dyno-sheet .sub { font-size: 11px; color: #5b616b; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 8px; }

/* Paint shop */
.swatches { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 10px; }
.swatch { width: 40px; height: 40px; border-radius: 50%; border: 2px solid var(--bl-line); cursor: pointer; padding: 0; }
.swatch.on { border-color: #fff; box-shadow: 0 0 0 2px var(--bl-orange); }
.swatch.custom { background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red); position: relative; overflow: hidden; }
.swatch.custom input { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; }
.seg.wrap { flex-wrap: wrap; }
.paint-preview { font-size: 12px; color: var(--bl-muted); }

.garage-loading { position: absolute; left: 50%; top: 42%; transform: translate(-50%, -50%); display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-radius: 999px; background: rgba(12,14,18,0.8); border: 1px solid var(--bl-line); font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--bl-text); z-index: 3; pointer-events: none; }
.garage-loading span { width: 14px; height: 14px; border-radius: 50%; border: 2px solid rgba(255,255,255,0.25); border-top-color: var(--bl-orange); animation: spin 0.9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }


.lb-row .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Leaderboard rows open on a tap to show the setup and offer to race it. */
.lb-row { color: inherit; font: inherit; text-align: left; width: 100%; cursor: pointer; }
.lb-row:not(.head):hover { border-color: var(--bl-muted); }
.lb-row .lb-detail { display: none; grid-column: 1 / -1; grid-template-columns: 1fr 1fr; gap: 6px 10px; padding-top: 8px; margin-top: 6px; border-top: 1px solid var(--bl-line); font-size: 12px; }
.lb-row.open .lb-detail { display: grid; }
.lb-row .lb-detail i { display: block; font-style: normal; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bl-muted); }
.lb-row .lb-actions { grid-column: 1 / -1; }
/* inline-block here dropped the centering every other button gets from .btn,
   so the label sat at the top of a box kept 36px tall by its own min-height. */
.lb-row .btn.small { display: inline-flex; align-items: center; justify-content: center; padding: 6px 14px; font-size: 12px; background: var(--bl-orange); color: #fff; border-radius: 8px; font-weight: 800; }
/* This week's rule on the daily. It goes first and it is the loudest thing on
   the tile, because it is the only part that changes what to do. */
.rule-chip { display: inline-block; background: var(--bl-orange); color: #fff; font-size: 10px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; padding: 2px 7px; border-radius: 4px; margin-right: 2px; vertical-align: 1px; }
/* That the daily's car is lent, under the car it is lending. */
.daily-lent { display: block; margin-top: 3px; font-size: 11px; line-height: 1.35; color: var(--bl-muted); }
.daily-next { display: inline-flex; align-items: center; gap: 7px; margin-top: 8px; padding: 6px 10px; border-radius: 8px; border: 1px solid rgba(214,30,59,0.55); background: rgba(214,30,59,0.14); color: #fff; font-size: 12px; font-weight: 600; letter-spacing: 0.01em; line-height: 1.3; }
.daily-next svg { flex: none; color: var(--bl-orange); }
.daily-next b { font-weight: 800; font-size: 14px; color: #fff; }

/* Why half the other lane's column is dashes. */
.slip-note { margin: 6px 0 0; line-height: 1.4; }

/* What the pass cost, on the slip. The rest of it is numbers; this is the one
   part that says what to do differently, so it reads as a sentence. */
.coach { margin-top: 12px; padding-top: 10px; border-top: 1px solid #d5d0c4; }
.coach b { display: block; font-size: 13px; font-weight: 800; }
.coach ul { margin: 6px 0 0; padding: 0; list-style: none; }
.coach li { position: relative; padding-left: 14px; margin-top: 4px; font-size: 12px; line-height: 1.45; color: #4b5563; }
.coach li::before { content: ''; position: absolute; left: 0; top: 7px; width: 5px; height: 5px; border-radius: 50%; background: var(--bl-orange); }

/* This week, above the all time order. A board that only ever shows an all
   time order stops being somewhere to look once the top of it is settled. */
.week-card { border: 1px solid var(--bl-line); border-radius: 10px; background: var(--bl-panel); margin: 0 0 10px; overflow: hidden; }
.week-card summary { display: flex; align-items: baseline; gap: 8px; padding: 10px 12px; cursor: pointer; list-style: none; font-size: 13px; }
.week-card summary::-webkit-details-marker { display: none; }
.week-card summary b { letter-spacing: 0.06em; text-transform: uppercase; font-size: 11px; color: var(--bl-orange); }
.week-card summary span { color: var(--bl-muted); font-size: 11px; }
.week-card summary::after { content: '+'; margin-left: auto; font-size: 16px; color: var(--bl-muted); }
.week-card[open] summary::after { content: '\2212'; }
.week-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4px 14px; padding: 0 12px 10px; }
/* The faces made the two lists wider than the card on a phone: the number
   columns ran off its edge. Small faces, columns that can shrink, and on a
   phone the two lists stack. */
.week-grid li b .avatar { width: 20px; height: 20px; margin-right: 4px; }
@media (max-width: 520px) { .week-grid { grid-template-columns: minmax(0, 1fr); } }
.week-grid h4 { margin: 0 0 4px; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bl-muted); font-weight: 800; }
.week-grid ol { margin: 0; padding: 0; list-style: none; }
.week-grid li { display: flex; align-items: baseline; gap: 6px; font-size: 12px; padding: 3px 0; border-top: 1px solid var(--bl-line); }
.week-grid li:first-child { border-top: 0; }
.week-grid li b { flex: 1; min-width: 0; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.week-grid li i { font-style: normal; font-family: var(--mono); color: var(--bl-orange); white-space: nowrap; }
/* Which board the quickest column is reading, and the trap beside the clock.
   A time on its own does not say whether it was an eighth or a half. */
.week-grid h4 small { font-weight: 700; letter-spacing: 0.04em; text-transform: none; color: var(--bl-dim, #6b7280); }
.week-grid li i em { font-style: normal; color: var(--bl-muted); font-size: 10.5px; margin-left: 5px; }
.week-grid li.me b { color: var(--bl-orange); }
.week-grid .none { color: var(--bl-muted); font-size: 12px; padding: 3px 0; }

.lb-mine { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; padding: 8px 10px; border: 1px solid var(--bl-orange); border-radius: 8px; font-size: 13px; }
.lb-mine .chip { font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; background: var(--bl-orange); color: #fff; padding: 2px 6px; border-radius: 4px; }
.lb-mine b { font-family: var(--mono); }
/* What it would take to move up: the row in front, and the top of the board.
   It wraps to its own line on a phone rather than squeezing the time. */
.lb-mine { flex-wrap: wrap; }
.lb-mine .lb-gap { flex: 1 0 100%; font-size: 11px; color: #f2b64c; font-variant-numeric: tabular-nums; }
.lb-mine .lb-gap.top { color: #4ec06a; }
.lb-mine .lb-gap s { text-decoration: none; opacity: 0.5; }

/* Build section: engine and drivetrain swaps. */
.swap-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.swap-card { display: flex; align-items: center; justify-content: space-between; gap: 10px; background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 8px; padding: 8px 10px; }
.swap-card.fitted { border-color: var(--bl-orange); }
.swap-card b { display: block; font-size: 13px; }
/* A maker's mark on a part they build. Capped by height so a wide wordmark and
   a square badge sit the same, and never wider than the card on a phone. */
.swap-card .swap-logo { display: block; height: 15px; width: auto; max-width: 60%; margin: 0 0 4px; object-fit: contain; }
.swap-card .meta { display: block; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--bl-muted); margin-top: 2px; }
.swap-card p { font-size: 11px; color: var(--bl-muted); margin: 4px 0 0; }
.swap-card .btn.small { padding: 6px 10px; font-size: 12px; white-space: nowrap; }
.swap-card .chip.on { font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; background: var(--bl-orange); color: #fff; padding: 3px 7px; border-radius: 4px; white-space: nowrap; }

.replay-fade { position: absolute; inset: 0; background: #000; opacity: 0; pointer-events: none; transition: opacity 0.6s ease; }
.replay-fade.on { opacity: 1; }

.setting .chip.on { font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; background: var(--bl-orange); color: #fff; padding: 3px 7px; border-radius: 4px; white-space: nowrap; }

.ladder small { display: block; font-size: 10px; color: var(--bl-muted); font-weight: 400; }

/* Coach: the pad to press pulses on the first passes. */
.pedal.pulse { animation: pad-pulse 0.7s ease-in-out infinite; }
@keyframes pad-pulse { 0%, 100% { transform: scale(1); filter: brightness(1); } 50% { transform: scale(1.035); filter: brightness(1.35); } }

/* Landscape phones and tablets: gauges in the middle, the pads in the corners, the tree small and high. */
@media (orientation: landscape) and (max-height: 560px) {
  .hud-gauges { bottom: calc(var(--safe-bottom) + 6px); padding: 0 calc(var(--safe-left) + 178px) 0 calc(var(--safe-right) + 178px); }
  .gauge { width: calc(92px * var(--gauge-scale, 1)); height: calc(92px * var(--gauge-scale, 1)); }
  .hud-speed b { font-size: calc(32px * var(--gauge-scale, 1)); }
  .hud-speed em { font-size: calc(15px * var(--gauge-scale, 1)); }
  .drag-controls { justify-content: space-between; bottom: calc(var(--safe-bottom) + 8px); }
  .pedal.launch, .pedal.shift { flex: 0 0 160px; height: 92px; font-size: 15px; }
  .pedal.launch b, .pedal.shift b { font-size: 18px; }
  .drag-tree { top: 22%; transform: translateX(-50%) scale(0.5); }
  /* The distance chip goes up beside the time box, off the top of the tree. */
  .drag-info { top: calc(var(--safe-top) + 8px); left: calc(50% + 180px); }
  .hud-egt { top: calc(var(--safe-top) + 46px); }
  .hud-egt.tires { top: calc(var(--safe-top) + 64px); }
  /* Sideways the tree sits at 22% and is half size, so the messages line up
     under it, in the band between the tree and the gauges. */
  .hud-status { top: calc(22% + 109px); }
  .race-msg { top: calc(22% + 145px); width: min(92vw, 560px); }
  /* The lane card goes up beside the distance box, off the tree; a toast
     takes the empty left column over the launch pad. */
  .lane-card { left: calc(var(--safe-left) + 108px); transform: none; top: calc(var(--safe-top) + 12px); max-width: 240px; }
  .toast.race { left: calc(var(--safe-left) + 12px); transform: none; animation-name: toast-in-left; top: calc(var(--safe-top) + 150px); max-width: 30vw; text-align: left; }
  .controls { height: calc(var(--safe-bottom) + 120px); }
  .pedals { bottom: calc(var(--safe-bottom) + 8px); }
  .pedal.throttle { height: 100px; }
  .replay-bar { bottom: calc(var(--safe-bottom) + 6px); }
  #screen-title { padding-bottom: calc(var(--safe-bottom) + 12px); }
  .title-wrap { gap: 6px; }
  .title-wrap .wordmark { width: 200px; height: auto; }
  .title { font-size: 24px; }
}

/* Race a friend: the room code big enough to read across a room. */
.online { display: flex; flex-direction: column; gap: 10px; }
.online .mode-card .row { display: flex; gap: 8px; align-items: center; }
.online .code { font-family: var(--mono); font-size: 44px; letter-spacing: 0.3em; font-weight: 800; text-align: center; padding: 12px 0 6px; color: var(--bl-orange); }
.online input.code-input { font-family: var(--mono); font-size: 28px; letter-spacing: 0.25em; text-transform: uppercase; text-align: center; width: 100%; padding: 10px; border-radius: 10px; border: 1px solid var(--bl-line); background: var(--bl-panel); color: var(--bl-text); }
.online .peer { display: flex; justify-content: space-between; align-items: center; gap: 10px; background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 8px; padding: 8px 10px; font-size: 13px; }
.online .peer.me { border-color: var(--bl-orange); }
/* How far down the track somebody watching a race can see each car is. */
.online .watch-bar { display: block; height: 5px; margin-top: 6px; border-radius: 3px; background: #2a2e35; overflow: hidden; }
.online .watch-bar i { display: block; height: 100%; background: var(--bl-orange); transition: width 120ms linear; }
.online .peer .chip { font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; padding: 3px 7px; border-radius: 4px; background: #2a2e35; color: var(--bl-muted); }
.online .peer .chip.on { background: var(--bl-ok, #2e8b57); color: #fff; }
.online .peer .class-chip { font-style: normal; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; padding: 2px 6px; border-radius: 4px; background: #2a2e35; color: #dfe3e8; margin-left: 6px; vertical-align: 1px; }
.online .peer.far .class-chip { background: rgba(214,30,59,0.25); color: #ff9aa8; }
.lobby-filter { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; }
.lobby-filter input { width: 18px; height: 18px; accent-color: var(--bl-orange); }

/* A unit the current block cannot run: listed, dimmed, with the build it needs. */
.spec.needs-build { opacity: 0.78; }
.spec.needs-build .spec-graph { display: none; }
.spec-need { margin: 6px 0 2px; font-size: 13px; font-weight: 700; color: var(--bl-orange); display: flex; gap: 6px; align-items: center; }
.spec-need svg { flex: none; width: 14px; height: 14px; }
.swap-need { margin: 6px 0 0; font-size: 12px; font-weight: 700; line-height: 1.35; color: var(--bl-orange); display: flex; gap: 6px; align-items: flex-start; }
.swap-need svg { flex: none; width: 13px; height: 13px; margin-top: 1px; }
.swap-card.blocked { opacity: 0.72; }
.swap-card.blocked .chip { display: flex; gap: 5px; align-items: center; }

/* The Lanes: everybody's garage, open to everybody. */
.lane-list { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
/* A row is a name and when it was last seen on one line, the numbers under it,
   and whatever needs flagging under that: the same four things in the same
   four places on every row, so forty of them still read down the page. */
.lane {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 10px; width: 100%;
  padding: 11px 13px 11px 14px; border-radius: 12px; border: 1px solid var(--bl-line);
  background: linear-gradient(180deg, #171a20, #13161b); color: inherit; text-align: left; align-items: center;
  cursor: pointer; font: inherit; box-sizing: border-box; box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03) inset;
}
.lane > b, .lane > em { align-self: baseline; }
.lane > span { align-self: center; }
.lane.live { border-color: rgba(61, 220, 132, 0.35); }
.lane .lane-cars { background: transparent; border-color: var(--bl-line); color: var(--bl-muted); min-height: 30px; padding: 3px 12px; font-size: 12px; }
.lane .lane-cars:active { color: var(--bl-text); }
/* The row is the profile; the cars are behind their own button, so a tap on
   a name no longer drops forty cars into the list. */
.lane:has(.lane-cars) > span { grid-column: 1; }
.lane > em { grid-column: 2; grid-row: 1; justify-self: end; }
.lane .lane-cars { grid-column: 2; grid-row: 2; align-self: center; justify-self: end; }
.lane .flags { grid-column: 1 / -1; grid-row: 3; }
.lane b { font-size: 15px; font-weight: 800; letter-spacing: 0.02em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lane em { font-style: normal; font-size: 11px; color: var(--bl-muted); white-space: nowrap; }
.lane span { grid-column: 1 / -1; font-size: 11.5px; color: var(--bl-muted); font-variant-numeric: tabular-nums; }
.lane span s { text-decoration: none; opacity: 0.45; padding: 0 2px; }
.lane .flags { display: flex; flex-wrap: wrap; gap: 5px; }
.lane .flags:empty { display: none; }
.lane .flags i { font-style: normal; font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; padding: 2px 6px; border-radius: 5px; background: #22262e; color: var(--bl-muted); }
.lane .flags i.tag { background: rgba(214,30,59,0.18); color: #f0a3ae; }
.lane .flags i.warn { background: rgba(214,30,59,0.9); color: #fff; }
/* Search and sort, one row, both reachable with a thumb. */
.lane-tools { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.lane-tools input, .lane-tools select { flex: 1; min-width: 0; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--bl-line); background: #0e1116; color: var(--bl-text); font: inherit; font-size: 14px; }
.lane-tools select { flex: 0 0 38%; }
/* The On now switch: the same green as the dot on a live row, a pill that
   fills when it is filtering. The whole top row of tools is one line. */
.lane-tools .lane-live { flex: 1 1 100%; margin: 0; justify-content: center; min-height: 40px; padding: 8px 14px; border-radius: 999px; border: 1px solid var(--bl-line); background: #0e1116; color: var(--bl-text); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; touch-action: manipulation; }
.lane-tools .lane-live.on { background: rgba(61, 220, 132, 0.14); border-color: rgba(61, 220, 132, 0.5); color: #8ff0b8; }
.lane-tools .lane-live i.off { background: var(--bl-muted); box-shadow: none; }
.lane-count { margin: 8px 2px 0; }
#lane-count { margin: 8px 2px 0; }
.lane-live { margin: 10px 2px 0; display: flex; align-items: center; gap: 8px; }
.lane-live i, .lane.live b::before { content: ''; display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #3ddc84; flex: 0 0 auto; }
.lane-live i { box-shadow: 0 0 6px rgba(61, 220, 132, 0.7); }
/* The name cell clips its overflow for the ellipsis, which was taking the
   left edge off the dot: a little padding gives the dot room inside it. */
.lane.live b { padding-left: 2px; margin-left: -2px; }
.lane.live b::before { margin-right: 6px; vertical-align: middle; }
.lane-note { margin-top: 4px; }
.lane-note summary { cursor: pointer; font-size: 12px; color: var(--bl-muted); letter-spacing: 0.04em; text-transform: uppercase; }
.lane-note p { margin-top: 6px; }
.lane-garage { padding: 4px 6px 10px; display: flex; flex-direction: column; gap: 4px; }
/* A color chip, the car over what is fitted, and the button to race it. The
   cells are named rather than left to auto placement, which put the setup line
   in the button's column and pushed the button onto a row of its own. */
.lane-car { display: grid; grid-template-columns: 14px minmax(0, 1fr) auto; grid-template-areas: "chip name race" "chip spec race"; gap: 2px 10px; align-items: center; padding: 9px 11px; border-radius: 10px; background: #101318; }
.lane-car i { grid-area: chip; align-self: center; width: 14px; height: 14px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.25); }
.lane-car b { grid-area: name; font-size: 13.5px; font-weight: 700; line-height: 1.25; }
.lane-car span { grid-area: spec; font-size: 11.5px; color: var(--bl-muted); line-height: 1.3; }
.lane-car .btn { grid-area: race; align-self: center; white-space: nowrap; }
.lane-gift { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; margin-top: 6px; border-radius: 12px; border: 1px solid var(--bl-line); background: #14171c; }
.lane-gift h3 { margin: 0; font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--bl-muted); }
.lane-gift .row { display: flex; gap: 8px; }
.lane-gift .row .btn { flex: none; }
.lane-gift input, .lane-gift select { flex: 1; min-width: 0; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--bl-line); background: #0e1116; color: var(--bl-text); font: inherit; font-size: 14px; }
/* One job per block, each with its heading and its explanation above the
   buttons it is about. The panel grew a section at a time and read like it. */
.lane-gift .gift-part { display: flex; flex-direction: column; gap: 8px; padding-top: 10px; border-top: 1px solid var(--bl-line); }
.lane-gift .gift-part h4 { margin: 0; font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--bl-muted); font-weight: 700; }
.lane-gift .gift-part .fine { margin: 0; }
/* The address an account signs in with. Monospaced because the whole point of
   showing it is reading it back to somebody character by character, and a
   lowercase l next to a one in the body font is how that goes wrong. */
/* A shop event on the tile: the name of the thing, before the rule. */
.rule-chip.event { background: #f2f2f2; color: #101216; }
/* The same box the signup log sits in, so it reads as a thing to open rather
   than a heading: it was a bare line and nobody would have tapped it. */
.lane-events { border: 1px solid var(--bl-line); border-radius: 12px; padding: 10px 12px; margin-bottom: 10px; background: rgba(214,30,59,0.06); }
.lane-events > summary { display: flex; justify-content: space-between; align-items: center; gap: 8px; cursor: pointer; font-size: 12px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: var(--bl-muted); list-style: none; }
.lane-events > summary::-webkit-details-marker { display: none; }
.lane-events > summary b { color: var(--bl-orange); }
.lane-events > summary span { color: var(--bl-muted); font-size: 12px; text-transform: none; letter-spacing: 0; font-weight: 400; }
.lane-events > summary::after { content: ''; width: 8px; height: 8px; border-right: 2px solid var(--bl-muted); border-bottom: 2px solid var(--bl-muted); transform: rotate(45deg); margin-left: 6px; flex: none; transition: transform 120ms; }
.lane-events[open] > summary::after { transform: rotate(-135deg); }
.lane-everyone > p.fine { margin-top: 8px; }
.lane-everyone-form { margin-top: 8px; }
.lane-everyone-form .row { display: flex; gap: 8px; align-items: center; }
.lane-everyone-form .row input, .lane-everyone-form .row select { flex: 1; min-width: 0; }
.lane-everyone-form .row button { flex: 1; }
.lane-event { display: flex; flex-direction: column; gap: 2px; padding: 8px 0; border-bottom: 1px solid var(--bl-line); font-size: 13px; }
.lane-event span { color: var(--bl-muted); font-size: 12px; }
.lane-event small { color: var(--bl-muted); }
.lane-event.on b { color: var(--bl-orange); }
.lane-event.past { opacity: 0.6; }
.lane-event .btn { align-self: flex-start; margin-top: 4px; }
.lane-event-form { display: flex; flex-direction: column; gap: 8px; padding-top: 10px; }
.lane-event-form h4 { margin: 0; font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--bl-muted); }
.lane-event-form .row { display: flex; gap: 8px; flex-wrap: wrap; }
.lane-event-form .row > * { flex: 1 1 auto; min-width: 0; }
.lane-event-form label.fine { display: flex; align-items: center; gap: 6px; }
.lane-event-form label.fine input { flex: 1 1 auto; min-width: 0; }
.lane-gift .signin-email { font-family: var(--mono); font-size: 12px; color: var(--bl-text); word-break: break-all; }
.lane-gift .row input { flex: 1 1 auto; min-width: 0; }
/* The car list beside the credits box. Flexing from nothing next to an input
   that flexes from its own width left it a chevron with no name in it. */
.lane-gift .row .gift-credits { flex: 1 1 0; }
.lane-gift .row .gift-car { flex: 1.4 1 0; min-width: 45%; }
/* The one block that takes something away is marked as such before it is read. */
.lane-gift .danger-part { border-top-color: rgba(214, 40, 57, 0.35); }
.lane-gift .danger-part h4 { color: #d97782; }
/* Two account ids and a couple of counts: worth having, not worth the top of
   the panel, so they sit under the sentence that says the same thing in words. */
.gift-facts summary { cursor: pointer; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--bl-muted); }
.gift-facts .mono { margin: 6px 0 0; }

/* About: what the shop does, and where to find it. */
.about-h { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bl-muted); margin: 16px 0 6px; }
/* The BL8685R at the top of About: the shop's own artwork, cut off the black
   it was drawn on so it sits on the card rather than in a box on it. */
.about-hero { display: flex; justify-content: center; margin: -8px 0 2px; }
.about-hero img { width: min(300px, 64%); height: auto; filter: drop-shadow(0 16px 30px rgba(214,30,59,0.3)); }
@media (max-width: 420px) { .about-hero img { width: 70%; } }
.about-list { margin: 0 0 4px; padding-left: 18px; }
.about-list li { font-size: 13.5px; line-height: 1.5; margin-bottom: 5px; }
.about-card .row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
/* The links sit side by side; the full width rule above is for a lone button. */
.about-card .row .btn { margin-top: 0; width: auto; flex: 1 1 auto; min-width: 108px; }
a.btn { text-decoration: none; }

/* Setup: the ladder as a list, least power first, any rung opened in place. */
.setup-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
/* The same row above the car card, choosing what the arrows walk through. */
.setup-head.car-view { margin-bottom: 10px; }
.setup-item { margin-bottom: 8px; }
.setup-row { display: grid; grid-template-columns: 1fr auto; gap: 2px 12px; width: 100%; text-align: left; padding: 10px 14px; border-radius: 10px; border: 1px solid var(--bl-line); background: #14171c; color: inherit; cursor: pointer; }
.setup-row b { font-size: 14.5px; font-weight: 700; }
.setup-row em { font-style: normal; font-family: var(--mono); font-size: 14px; font-weight: 700; text-align: right; }
.setup-row span { font-size: 11.5px; color: var(--bl-muted); }
.setup-row i { font-style: normal; font-size: 11.5px; color: var(--bl-muted); text-align: right; white-space: nowrap; }
.setup-row.on { border-color: var(--bl-orange); }
.setup-row.on i { color: var(--bl-orange); }
.setup-row.blocked { opacity: 0.72; }
.setup-row.open { border-bottom-left-radius: 0; border-bottom-right-radius: 0; border-bottom-color: transparent; }
.setup-row.open + .spec { border-top-left-radius: 0; border-top-right-radius: 0; margin-bottom: 0; }

/* ------------------------------------------------------- The music button
   Pinned to the corner and above every screen, because wanting the music off
   is a thing that happens where you are, not in Settings. It moves out of the
   way of whatever else lives in that corner, and it is not there at all on the
   strip, where the music is not playing anyway. */
.music-toggle {
  position: fixed; z-index: 25;
  top: calc(var(--safe-top) + 10px); right: calc(var(--safe-right) + 12px);
  width: 40px; min-height: 40px; padding: 0;
  /* Deliberately no backdrop-filter: on a fixed element above every screen it
     is a known way to blow up compositing on some phone GPUs, and a solid
     panel looks the same. */
  background: rgba(16,18,22,0.86); border-color: rgba(255,255,255,0.14); color: var(--bl-text);
}
.music-toggle .music-off { display: none; }
.music-toggle[aria-pressed="false"] { color: var(--bl-muted); }
.music-toggle[aria-pressed="false"] .music-on { display: none; }
.music-toggle[aria-pressed="false"] .music-off { display: block; }
#app[data-music="hide"] .music-toggle { display: none; }
/* Whatever else sits in that corner steps aside for it. */
#app:not([data-music="hide"]) .sheet-head { padding-right: var(--bl-corner); }
/* In the garage the panel's tab strip runs under the corner, so the last tab
   steps aside too. */
#app:not([data-music="hide"]) .garage-panel .tabs { padding-right: 44px; }
@media (min-width: 1024px) {
  .music-toggle { top: calc(var(--safe-top) + 16px); right: calc(var(--safe-right) + 20px); }
  #app:not([data-music="hide"]) .screen.garage .sheet-head.overlay { padding-right: var(--bl-corner); }
  #app:not([data-music="hide"]) .garage-panel .tabs { padding-right: 52px; }
}

/* The account card: two fields and the two things you can do with them. */
#modal-account .field { margin-top: 2px; }
#modal-account input { padding: 10px 12px; border-radius: 10px; border: 1px solid var(--bl-line); background: #0e1116; color: var(--bl-text); font: inherit; font-size: 15px; text-transform: none; letter-spacing: 0; }
/* One primary and one way out on the same line, and the two things you can do
   to the account you are already in kept apart under a rule of their own. They
   were five buttons in a stack: a red one, a gray one, an underlined red link
   and two more full width buttons, in no order that said which was the point. */
/* The setup sheet in front of a race. Tall enough to hold the rows that change
   a pass and scrolled rather than squeezed, because a phone is not tall. */
/* The tree on its own, for practice. It reuses the strip's own bulbs and its
   own timing, so a light cut in here is worth exactly what it is worth out
   there; only the car is missing. */
.rt-card { align-items: center; text-align: center; }
.rt-card .rt-tree { position: static; transform: none; opacity: 1; margin: 2px 0; }
.rt-read { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.rt-read b { font-family: var(--mono); font-size: 40px; line-height: 1; }
.rt-read span { font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--bl-muted); }
.rt-read.good b { color: #6ee89b; }
.rt-read.foul b { color: var(--bl-warn); }
.rt-pad { width: 100%; min-height: 64px; font-size: 16px; letter-spacing: 0.08em; touch-action: none; user-select: none; -webkit-user-select: none; }
.rt-pad.held { background: var(--bl-orange); color: #fff; }
.rt-kind { display: flex; gap: 6px; justify-content: center; }
.rt-rollout { display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 12px; color: var(--bl-muted); flex-wrap: wrap; }
/* The select takes the row's own size, not the form default's full width, and
   the two-step switch stays one line: it was three lines tall beside a select
   that ran the width of the card. */
.rt-rollout select { width: auto; flex: 0 0 auto; min-height: 36px; padding: 6px 8px; font-size: 13px; font-family: var(--mono); }
.rt-rollout .btn.small { white-space: nowrap; flex: none; }
.rt-rollout .btn.small.on { border-color: var(--bl-orange); color: var(--bl-text); }
.rt-kind .btn.on { border-color: var(--bl-orange); color: var(--bl-text); }
.avatar { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; vertical-align: middle; margin-right: 6px; background: #14171c; border: 1px solid var(--bl-line); flex: none; }
.lb-row .name { display: flex; align-items: center; min-width: 0; }
.lb-row .name .avatar { width: 24px; height: 24px; }
.lb-week li b .avatar { width: 20px; height: 20px; margin-right: 4px; }
.lane b .avatar { width: 22px; height: 22px; }
.profile-head { display: flex; align-items: center; gap: 12px; }
.profile-head .avatar { width: 56px; height: 56px; margin: 0; }
/* Your own profile is a portrait: the face big and centered, the name under it. */
.profile-head.own { flex-direction: column; gap: 6px; text-align: center; }
.profile-head.own .avatar { width: 120px; height: 120px; }
.profile-head.own h2 { margin: 0; }
.face-btn { background: none; border: 0; padding: 0; cursor: pointer; border-radius: 50%; display: block; }
#profile-hint { margin: 0; }
.setting .avatar.own { width: 32px; height: 32px; margin: 0 8px 0 0; }
.modal-card.avatar-card { width: min(420px, 94vw); max-height: 88vh; overflow-y: auto; }
.avatar-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.avatar-grid button { background: var(--bl-panel); border: 2px solid var(--bl-line); border-radius: 10px; padding: 6px 4px; display: flex; flex-direction: column; align-items: center; gap: 4px; color: var(--bl-muted); font-size: 10px; cursor: pointer; }
.avatar-grid button img { width: 100%; height: auto; aspect-ratio: 1; border-radius: 8px; margin: 0; border: 0; }
.avatar-grid button.on { border-color: var(--bl-orange); color: var(--bl-text); }
.avatar-grid button.shop { box-shadow: inset 0 0 0 1px var(--bl-orange); }
.modal-card.profile-card { width: min(400px, 94vw); max-height: 88vh; overflow-y: auto; }
.profile-stats { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.profile-stats .profile-note { grid-column: 1 / -1; margin: 0; }
.profile-stats div { background: var(--bl-panel); border: 1px solid var(--bl-line); border-radius: 8px; padding: 8px; }
.profile-stats i { display: block; font-style: normal; font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--bl-muted); }
.profile-stats b { display: block; font-family: var(--mono); font-size: 16px; margin-top: 2px; }
.profile-bests h4, .profile-cars h4 { margin: 6px 0 4px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--bl-muted); }
.profile-bests div { display: grid; grid-template-columns: 1fr auto; gap: 6px; padding: 5px 0; border-bottom: 1px solid var(--bl-line); font-size: 12px; }
.profile-bests div small { display: block; color: var(--bl-muted); }
.profile-bests div b { font-family: var(--mono); font-size: 14px; text-align: right; }
.profile-bests div b small { font-size: 10px; }
.profile-cars p { font-size: 12px; color: var(--bl-muted); margin: 0; line-height: 1.5; }
.lb-row .name[data-profile], .lb-week li b[data-profile] { text-decoration: underline dotted; text-underline-offset: 3px; cursor: pointer; }
.modal-card.pretune { width: min(420px, 94vw); }
.pretune-tabs { display: flex; gap: 6px; margin-top: 4px; }
.pretune-tabs .btn { flex: 1 1 0; font-size: 12px; padding: 8px 6px; }
/* The tab you are on. These two carried the class all along and nothing here
   drew it, so both tabs looked the same and the only way to tell which one was
   open was to read the rows under it. Same treatment a picked segment gets
   everywhere else in the game, so it reads the way the rest of it does. */
.pretune-tabs .btn.on { background: var(--bl-orange); border-color: transparent; color: #fff; }
/* Room on the right for the scrollbar. A phone draws it over the content
   rather than beside it, and it landed on the value column: 3.90 read 3.9,
   154 mph lost its h. The padding keeps the numbers clear of it. */
.pretune-rows { max-height: min(48vh, 400px); overflow-y: auto; scrollbar-gutter: stable; padding-right: 14px; display: flex; flex-direction: column; gap: 2px; margin: 2px 0; }
/* The same minus and plus the Tune tab has, either side of each slider: a
   ratio is a two decimal number and a thumb on a phone is not that precise. */
.pretune-rows .gear-row { display: grid; grid-template-columns: 20px auto 1fr auto auto; align-items: center; gap: 6px; padding: 5px 0; }
.pretune-rows .gear-row input[type="range"] { min-width: 0; }
.pretune-rows .tune-row .slider-nudge { grid-column: 1 / -1; }
.pretune-rows .gear-row > span { font-size: 11px; font-weight: 800; color: var(--bl-muted); }
.pretune-rows .gear-row output { font-family: var(--mono); font-size: 12px; color: var(--bl-orange); text-align: right; min-width: 92px; }
.pretune-rows .tune-row { padding: 8px 0; }
.pretune-rows .tune-row.locked { opacity: 0.55; }
.pretune-rows .tune-row.locked input, .pretune-rows .tune-row.locked .seg { pointer-events: none; }
.pretune-rows .lock-why { display: block; font-size: 10px; text-transform: none; letter-spacing: 0; color: var(--bl-warn); margin-top: 2px; }
/* The shop's signup log on The Lanes: who claimed a name, and on what day.
   Scrolled, because the useful shape of it is a long list of quiet days with
   the odd good one in it. */
.lane-signups { border: 1px solid var(--bl-line); border-radius: 12px; padding: 10px 12px; margin-bottom: 10px; background: rgba(214,30,59,0.06); }
.lane-signups > summary { cursor: pointer; font-size: 12px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: var(--bl-muted); list-style: none; }
.lane-signups > summary::-webkit-details-marker { display: none; }
.lane-signups > summary b { color: var(--bl-orange); font-size: 15px; font-family: var(--mono); }
.signup-days { max-height: 220px; overflow-y: auto; margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.signup-day { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; border-top: 1px solid var(--bl-line); padding-top: 6px; }
.signup-day span { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--bl-text); }
.signup-day b { font-family: var(--mono); font-size: 13px; color: var(--bl-orange); text-align: right; }
.signup-day p { grid-column: 1 / -1; margin: 0; font-size: 11px; color: var(--bl-muted); word-break: break-word; }
#modal-account .btn-row { gap: 8px; }
#modal-account .btn-row .btn { flex: 1 1 0; min-width: 0; font-size: 14px; padding: 12px 8px; white-space: nowrap; }
#modal-account #account-forgot { display: inline-block; align-self: flex-end; margin: -4px 2px 0; font-size: 12px; font-weight: 700; letter-spacing: 0; text-transform: none; color: var(--bl-muted); text-decoration: none; border-bottom: 1px solid rgba(255,255,255,0.22); }
#modal-account #account-forgot:active { color: var(--bl-text); }
#modal-account .account-more { margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--bl-line); display: flex; flex-direction: column; gap: 8px; }
#modal-account .account-more > span { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.1em; color: var(--bl-muted); }

/* Turbo bench: our units side by side on a car of the customer's choosing. */
.bench-pickers { display: grid; grid-template-columns: 1fr; gap: 8px; margin-bottom: 4px; }
@media (min-width: 560px) { .bench-pickers { grid-template-columns: 1fr 1fr; } }
.bench-pickers select { width: 100%; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--bl-line); background: #0e1116; color: var(--bl-text); font: inherit; font-size: 14px; }
.section-title small { text-transform: none; letter-spacing: 0; font-size: 11px; color: var(--bl-line); margin-left: 6px; }
.bench-lanes { display: grid; grid-template-columns: 1fr; gap: 6px; margin-bottom: 10px; }
@media (min-width: 560px) { .bench-lanes { grid-template-columns: repeat(3, 1fr); } }
.bench-lane { display: flex; align-items: center; gap: 9px; width: 100%; min-height: 42px; padding: 8px 12px; border-radius: 10px; border: 1px solid var(--bl-line); background: #14171c; color: var(--bl-muted); text-align: left; font: inherit; }
.bench-lane i { flex: none; width: 12px; height: 12px; border-radius: 3px; background: var(--bench); }
.bench-lane b { flex: 1; min-width: 0; font-size: 12.5px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bench-lane.filled b { color: var(--bl-text); }
.bench-lane em { flex: none; font-size: 11px; font-style: normal; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--bl-muted); padding: 3px 6px; border-radius: 6px; border: 1px solid var(--bl-line); }
.bench-lane.on { border-color: var(--bench); box-shadow: inset 0 0 0 1px var(--bench); }
.bench-units .btn { min-height: 38px; padding: 6px 12px; font-size: 12.5px; }
.bench-graph { width: 100%; height: 200px; display: block; border-radius: 8px; background: #ebe6db; }
@media (min-width: 1024px) { .bench-graph { height: 260px; } }
.bench-cards { display: grid; grid-template-columns: 1fr; gap: 10px; margin-top: 14px; }
@media (min-width: 760px) { .bench-cards { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); } }
/* The stripe down the card is the color that unit carries on the graphs. */
.bench-cards .spec { margin-bottom: 0; }
.bench-cards .spec::before { background: var(--bench, var(--bl-orange)); }

/* A delivery from the shop: it stays on screen until it is read. */
/* A podium paid: the place big and colored for the step, the event named
   above it, the credits under. A payout used to come as a parcel slip. */
.gift-card.podium { border-color: var(--bl-orange); box-shadow: 0 0 0 1px rgba(255, 106, 0, 0.25), 0 18px 48px rgba(0, 0, 0, 0.6); }
.gift-card.podium h2 { font-size: 22px; }
.podium-place { display: flex; align-items: baseline; gap: 8px; margin: 2px 0 0; color: var(--bl-orange); }
.podium-place svg { align-self: center; }
.podium-place b { font-family: var(--mono); font-size: 44px; font-weight: 800; line-height: 1; letter-spacing: -0.02em; }
.podium-place small { font-size: 13px; color: var(--bl-muted); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }
.gift-card.podium.gold .podium-place { color: #ffc23d; }
.gift-card.podium.silver .podium-place { color: #d8dde6; }
.gift-card.podium.bronze .podium-place { color: #d58a52; }
.gift-card .gift-from { font-size: 11px; font-weight: 800; letter-spacing: 0.16em; text-transform: uppercase; color: var(--bl-orange); }
.gift-card h2 { margin: 0; }
.gift-card p { font-size: 14px; line-height: 1.5; }
.gift-card blockquote { margin: 2px 0 0; padding: 10px 12px; border-left: 3px solid var(--bl-orange); background: #14171c; border-radius: 0 8px 8px 0; font-size: 14px; line-height: 1.5; font-style: italic; }

/* What changed since this garage was last opened: shown once, then remembered. */
.news-card .gift-from { font-size: 11px; font-weight: 800; letter-spacing: 0.16em; text-transform: uppercase; color: var(--bl-orange); }
.news-card h2 { margin: 0; }
.news-card .news-rel { margin-top: 12px; }
.news-card .news-rel:first-child { margin-top: 4px; }
.news-card .news-ver { display: block; font-size: 11px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bl-muted); }
.news-card .news-head { margin: 1px 0 6px; font-size: 15px; font-weight: 800; }
.news-card ul { margin: 0; padding: 0; list-style: none; }
.news-card li { position: relative; padding: 0 0 0 16px; margin-bottom: 6px; font-size: 14px; line-height: 1.45; text-align: left; }
.news-card li::before { content: ''; position: absolute; left: 0; top: 8px; width: 6px; height: 6px; border-radius: 50%; background: var(--bl-orange); }
.news-card .news-cars { color: var(--bl-orange); font-weight: 800; }
.news-card #news-body { max-height: 46vh; overflow-y: auto; }
/* A crew of eight over a board of many, or a long rule card, runs past a
   phone: the body scrolls and the buttons stay in reach. */
.modal-card.news-card { max-height: 90vh; }
#crews-body, #index-body { max-height: 60vh; overflow-y: auto; overscroll-behavior: contain; }

/* A worn motor: the note carries its own repair button. */
.car-note .btn { margin-top: 8px; }

/* ------------------------------------------------------------- Desktop
   The game is built for a phone held upright, and on a wide monitor that
   layout came apart: menu rows ran the full 1920 with the wordmark small in
   a corner, the garage gave half the screen to a spec sheet, and every sheet
   stretched its text to the width of the glass.
   
   So above a laptop's width the whole thing becomes a centered column with the
   proportions it has on a phone, the menu gets a proper title stage with the
   logo big in the middle, and the garage keeps the car large on the left with
   the panel a fixed column on the right. Nothing is added or taken away: it
   is the same game, laid out for the screen it is on. */
@media (min-width: 1024px) {
  :root { --sheet-max: 940px; --menu-max: 1160px; }

  /* Every sheet screen: one centered column instead of full bleed text. */
  .screen.sheet { align-items: center; padding-left: calc(var(--safe-left) + 24px); padding-right: calc(var(--safe-right) + 24px); }
  .screen.sheet > * { width: 100%; max-width: var(--sheet-max); }
  .screen.sheet > .title-hero { max-width: none; }

  /* Title: the logo carries the screen. */
  .title-logo { width: min(58vw, 720px); }
  .title-wrap { gap: 20px; }
  #screen-title { padding-bottom: calc(var(--safe-bottom) + 64px); }

  /* ------------------------------------------------------------ Menu
     The band runs the full width of the glass, like the title card of a game;
     everything under it is a centered column. */
  .screen.menu { align-items: center; padding-left: 0; padding-right: 0; }
  .screen.menu > *:not(.menu-hero) { max-width: var(--menu-max); margin-left: auto; margin-right: auto; }
  .screen.menu > .menu-hero { max-width: none; width: 100%; min-height: 340px; border-radius: 0 0 28px 28px; padding: calc(var(--safe-top) + 30px) 32px 34px; margin-bottom: 20px; justify-content: center; align-items: center; text-align: center; gap: 26px; }
  /* The watermark grows with the band. */
  .menu-hero-img { width: 460px; opacity: 0.07; }
  /* The same centered lockup, scaled up for the room. */
  .menu-hero .credits { top: calc(var(--safe-top) + 20px); left: 32px; right: auto; }
  .menu-hero .credits b { font-size: 15px; }
  .menu-hero .credits svg { width: 16px; height: 16px; }
  .menu-logo { width: min(46vw, 560px); filter: drop-shadow(0 8px 26px rgba(0,0,0,0.7)); }
  .menu-hero-car { gap: 5px; }
  .menu-car-name { font-size: 40px; }
  .menu-car-spec { font-size: 14px; }
  .menu-greeting { font-size: 13px; }
  .menu-grid { grid-template-columns: 1fr 1fr; gap: 14px; }
  .screen.menu .btn.menu.primary { min-height: 108px; padding: 18px 24px; }
  .screen.menu .btn.menu.primary .menu-title { font-size: 30px; }
  .menu-tiles { gap: 14px; margin-top: 14px; }
  .btn.tile { min-height: 108px; padding: 16px 18px; }
  .btn.tile svg { width: 26px; height: 26px; }
  .btn.tile.wide { min-height: 78px; }
  .btn.tile.small { min-height: 84px; }
  /* Hover: a mouse expects something to happen under it. */
  .btn:hover { background: var(--bl-panel-2); }
  .btn.primary:hover { filter: brightness(1.08); }
  .btn.tile:hover { border-color: var(--bl-orange); }
  .lane:hover, .tab:hover { border-color: var(--bl-orange); color: var(--bl-text); }

  /* ---------------------------------------------------------- Garage
     The car gets the room; the panel is a column of a readable width. */
  .turntable { right: 560px; top: calc(var(--safe-top) + 74px); height: auto; bottom: 0; padding: 0 34px; }
  .garage-panel { left: auto; width: 560px; right: 0; top: 0; bottom: 0; border-radius: 0; border-top: 0; border-left: 3px solid var(--bl-orange); }
  .garage-panel .tabs { padding-top: calc(var(--safe-top) + 4px); }
  .tab-body { padding: 16px 20px 18px; }
  .garage-actions { padding: 12px 20px calc(var(--safe-bottom) + 12px); }
  /* The head sits over the car, not over the panel. */
  .screen.garage .sheet-head.overlay { right: calc(560px + 20px); }
  .garage-loading { left: calc(50% - 280px); }
  .dyno-sheet canvas { height: 230px; }

  /* Race: the pads belong under a thumb on a phone. On a monitor they are a
     keyboard's job, so they shrink out of the way rather than filling a
     quarter of a 1080 screen. */
  .drag-controls { left: 50%; right: auto; transform: translateX(-50%); width: min(720px, 70vw); }
}

/* Very wide monitors: stop the garage from putting the car a meter from the panel. */
@media (min-width: 1700px) {
  .turntable { right: 620px; }
  .garage-panel { width: 620px; }
  .screen.garage .sheet-head.overlay { right: calc(620px + 20px); }
  .garage-loading { left: calc(50% - 310px); }
}

/* Grudge Night: the week's card on the strip and its tile on the menu. The
   card borrows the index card's bones; the grid is the week at a glance. */
#menu-night b { color: var(--bl-ok); font-weight: 700; }
.night-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin: 6px 0 8px; }
.night-grid > div { background: rgba(255, 255, 255, 0.03); border: 1px solid var(--bl-line); border-radius: 8px; padding: 7px 8px; min-width: 0; }
.night-grid span { display: block; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bl-muted); }
.night-grid b { display: block; font-family: var(--mono); font-size: 15px; margin-top: 2px; overflow-wrap: anywhere; line-height: 1.2; }
.night-grid small { display: block; font-size: 10.5px; color: var(--bl-muted); margin-top: 2px; overflow-wrap: anywhere; line-height: 1.25; }
.night-grid .muted { color: var(--bl-muted); font-family: var(--font); font-size: 12px; }
.night-match { background: var(--bl-ink); border: 1px solid var(--bl-orange); border-radius: 10px; padding: 10px 12px; margin: 2px 0 6px; }
.night-match b { font-size: 15px; }
.night-match .fine { margin-top: 4px; }
.info-btn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; margin-left: 8px; padding: 0; border-radius: 50%; border: 1px solid var(--bl-line); background: var(--bl-panel); color: var(--bl-muted); cursor: pointer; vertical-align: middle; flex: none; }
.info-btn:active { background: var(--bl-panel-2); transform: scale(0.94); }
.mode-card h3 .info-btn { margin-left: 8px; }
.index-pair.won span:first-child, .index-pair span.won { color: var(--bl-ok); font-weight: 700; }
.index-pair span.mine { color: var(--bl-text); }

/* Crews: the team rivalry. The modal, the board rows, the code and the chip by a name. */
#menu-crews b { color: var(--bl-ok); font-weight: 700; }
.crew-chip { display: inline-block; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; padding: 1px 6px; border-radius: 4px; background: rgba(214, 30, 59, 0.16); color: #ff8595; margin-left: 6px; vertical-align: 1px; font-style: normal; font-weight: 700; }
.crew-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.crew-head b { font-size: 18px; }
.crew-head .chip { margin-left: 0; }
.crew-code { display: flex; align-items: center; gap: 10px; margin: 8px 0; }
.crew-code .code { font-family: var(--mono); font-size: 26px; font-weight: 800; letter-spacing: 0.18em; }
.crew-code .fine { flex: 1; }
.crew-list { display: flex; flex-direction: column; gap: 4px; margin: 8px 0; }
.crew-row { display: grid; grid-template-columns: 24px 1fr auto; gap: 8px; align-items: center; background: var(--bl-ink); border: 1px solid var(--bl-line); border-radius: 8px; padding: 6px 10px; font-size: 12px; }
.crew-row.mine { border-color: var(--bl-orange); }
.crew-row.member { grid-template-columns: 1fr auto; }
.crew-row .place { font-family: var(--mono); font-weight: 800; color: var(--bl-muted); }
.crew-chip.you { background: rgba(255, 255, 255, 0.08); color: var(--bl-muted); }
.crew-standing { margin-bottom: 2px; }
.crew-standing b { color: var(--bl-text); }
.crew-row .place.top { color: var(--bl-orange); }
.crew-row small { display: block; color: var(--bl-muted); font-size: 10px; }
.crew-row .score { font-family: var(--mono); text-align: right; }
.crew-row .score.short { color: var(--bl-muted); font-family: var(--font); font-size: 11px; }
.crew-row .btn.small { min-height: 26px; padding: 2px 8px; font-size: 11px; }
.crew-forms { display: flex; flex-direction: column; gap: 10px; margin: 8px 0; }
.crew-forms .row { display: flex; gap: 6px; align-items: center; }
.crew-forms input { flex: 1; min-width: 0; }
.crew-forms .code-input { max-width: 120px; }
.crew-section { margin-top: 12px; }
.crew-section h3 { margin: 0 0 6px; }
#lb-crews-body .crew-list { margin: 6px 0 2px; }

.index-row .entry small { display: block; font-family: var(--font); font-size: 10px; color: var(--bl-muted); text-align: right; }
.night-actions .btn.on, .index-actions .btn.on { border-color: rgba(52, 199, 89, 0.5); color: #6ee89b; }
