/* formula-watchers: pit wall timing terminal.
   Carbon blacks, steel grays, F1 red accent. Serif display type over mono data,
   Exo for the paddock-wire headlines; the brand, nav rail, and countdown clock
   keep the original condensed face. */

@font-face {
  font-family: "Barlow Condensed";
  src: url("/static/fonts/barlow-condensed-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Barlow Condensed";
  src: url("/static/fonts/barlow-condensed-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Crimson Text";
  src: url("/static/fonts/crimson-text-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Crimson Text";
  src: url("/static/fonts/crimson-text-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Crimson Text";
  src: url("/static/fonts/crimson-text-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
/* Exo ships from Google Fonts as one variable file covering wght 100-900. */
@font-face {
  font-family: "Exo";
  src: url("/static/fonts/exo-variable.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/ibm-plex-mono-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/ibm-plex-mono-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}

:root {
  --bg: #0b0b0d;
  --bg-deep: #070708;
  --panel: #131316;
  --panel-2: #17171b;
  --grid: #232329;
  --grid-soft: #1b1b20;
  --text: #ecedef;
  --muted: #8f909a;
  --faint: #5a5b64;
  --accent: #e10600;
  --accent-glow: rgba(225, 6, 0, 0.35);
  --up: #27f07c;
  --down: #ff4d5a;
  --warn: #f5c518;
  --display: "Crimson Text", Georgia, serif;
  --condensed: "Barlow Condensed", "Arial Narrow", sans-serif;
  --wire: "Exo", system-ui, sans-serif;
  --mono: "IBM Plex Mono", "Consolas", monospace;
  --rail-w: 176px;
  --mark-h: 0.62em;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { color-scheme: dark; }

body {
  font-family: var(--mono);
  font-size: 13px;
  background:
    radial-gradient(1200px 500px at 85% -10%, rgba(225, 6, 0, 0.05), transparent 60%),
    repeating-linear-gradient(45deg, rgba(255,255,255,0.012) 0 2px, transparent 2px 6px),
    var(--bg);
  color: var(--text);
  min-height: 100vh;
}

/* ---------- header ---------- */
header {
  display: flex; align-items: center; gap: 1rem;
  height: 52px; padding: 0 1.1rem;
  background: linear-gradient(180deg, #121215, #0d0d10);
  border-bottom: 1px solid var(--grid);
  position: sticky; top: 0; z-index: 50;
}
header h1 {
  font-family: var(--condensed);
  font-weight: 700; font-size: 1.35rem; letter-spacing: 0.22em;
  white-space: nowrap;
}
/* the mark: car silhouette painted in --accent via mask, so it stays on-theme.
   Height matches the square it replaced; width follows the art's 3.543 aspect. */
header h1::before {
  content: ""; display: inline-block;
  height: var(--mark-h); width: calc(var(--mark-h) * 3.543);
  margin-right: 0.55em;
  background: var(--accent);
  -webkit-mask: url("/static/img/f1-car.svg") no-repeat center / contain;
  mask: url("/static/img/f1-car.svg") no-repeat center / contain;
  filter: drop-shadow(0 0 7px var(--accent-glow));
}
#mode-badge {
  font-size: 10px; letter-spacing: 0.12em; padding: 2px 7px;
  border: 1px solid var(--warn); color: var(--warn); border-radius: 2px;
  display: none;
}
#mode-badge.on { display: inline-block; }
#site-dots { display: flex; gap: 0.55rem; margin-left: auto; flex: 0 0 auto; }
.dot { display: flex; align-items: center; gap: 0.32rem; color: var(--faint); font-size: 10px; letter-spacing: 0.08em; }
.dot i {
  width: 8px; height: 8px; border-radius: 50%; background: #3a3a42; display: inline-block;
}
.dot.ok i { background: var(--up); box-shadow: 0 0 6px rgba(39, 240, 124, 0.6); }
.dot.stale i { background: var(--warn); }
.dot.err i { background: var(--down); }
.dot.ok.live i { animation: pulse 2.2s infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
/* the note yields first when the header runs tight: it shrinks and ellipsizes
   instead of pushing the page wide (serif brand is wider than the old condensed) */
#boot-note {
  color: var(--faint); font-size: 10.5px; white-space: nowrap;
  flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
}

/* ---------- shell ---------- */
#shell { display: flex; min-height: calc(100vh - 52px); }

nav#rail {
  width: var(--rail-w); flex: 0 0 auto;
  border-right: 1px solid var(--grid);
  padding: 1rem 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.015), transparent 30%);
}
nav#rail button {
  display: flex; align-items: center; gap: 0.7rem;
  width: 100%; padding: 0.62rem 1rem;
  background: none; border: none; border-left: 3px solid transparent;
  color: var(--muted); font-family: var(--condensed);
  font-size: 1.02rem; font-weight: 600; letter-spacing: 0.14em;
  text-transform: uppercase; cursor: pointer; transition: all 0.15s;
}
nav#rail button .pos {
  font-family: var(--mono); font-size: 10px; color: var(--faint);
  width: 1.5em; text-align: right;
}
nav#rail button:hover { color: var(--text); background: rgba(255,255,255,0.03); }
nav#rail button.active {
  color: var(--text); border-left-color: var(--accent);
  background: linear-gradient(90deg, rgba(225,6,0,0.10), transparent 70%);
}
nav#rail button.active .pos { color: var(--accent); }

main { flex: 1 1 auto; padding: 1.1rem 1.4rem 3rem; min-width: 0; }

.view { display: none; }
.view.active { display: block; }

/* staggered row reveal on view activation */
.view.active .reveal { animation: rise 0.35s both; }
.view.active .reveal:nth-child(2) { animation-delay: 0.04s; }
.view.active .reveal:nth-child(3) { animation-delay: 0.08s; }
.view.active .reveal:nth-child(4) { animation-delay: 0.12s; }
.view.active .reveal:nth-child(5) { animation-delay: 0.16s; }
@keyframes rise { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }

/* ---------- shared components ---------- */
.panel {
  background: var(--panel); border: 1px solid var(--grid); border-radius: 6px;
  /* wide tables scroll INSIDE their panel; the page itself never overflows */
  overflow-x: auto; overflow-y: hidden;
}
.panel > h2 {
  font-family: var(--display); font-weight: 600; font-size: 1rem;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted);
  padding: 0.55rem 0.9rem; border-bottom: 1px solid var(--grid-soft);
  display: flex; align-items: center; gap: 0.6rem;
}
.panel > h2 .spacer { margin-left: auto; }

.grid2 { display: grid; grid-template-columns: 2fr 1fr; gap: 1rem; }
.mt { margin-top: 1rem; }

table.tt { width: 100%; border-collapse: collapse; }
table.tt th {
  font-family: var(--display); font-weight: 600; font-size: 0.82rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint);
  text-align: left; padding: 0.45rem 0.7rem; border-bottom: 1px solid var(--grid);
  white-space: nowrap;
}
table.tt td { padding: 0.42rem 0.7rem; border-bottom: 1px solid var(--grid-soft); white-space: nowrap; }
table.tt tr.row { transition: background 0.12s; }
table.tt tr.row:hover { background: rgba(225, 6, 0, 0.05); }
table.tt td.num { font-weight: 600; text-align: right; }
table.tt th.th-info { color: var(--muted); }
.tnote { color: var(--muted); font-size: 0.78rem; margin-top: 8px; line-height: 1.5; }

.poschip {
  font-family: var(--display); font-weight: 700; font-size: 0.92rem;
  display: inline-flex; justify-content: center; align-items: center;
  min-width: 26px; height: 22px; padding: 0 4px;
  background: #202027; border-radius: 3px; color: var(--text);
}
.teambar { display: inline-block; width: 4px; height: 16px; border-radius: 1px; vertical-align: -3px; margin-right: 8px; background: var(--faint); }
.teamname { color: var(--muted); font-size: 11px; }

.badge {
  display: inline-block; font-size: 10px; letter-spacing: 0.08em;
  padding: 1px 6px; border-radius: 2px; border: 1px solid var(--grid);
  color: var(--muted); text-transform: uppercase; white-space: nowrap;
}
.badge.red { border-color: var(--accent); color: #ff6b66; }
.badge.warn { border-color: var(--warn); color: var(--warn); }
.badge.dim { opacity: 0.75; }
.badge.unverified { color: #ff6b66; border-color: var(--accent); }
.badge.lang { text-transform: uppercase; letter-spacing: .04em; }

/* segmented mode toggle (ratings: driver/team) - same border/mono language as
   the badges and the chart-close button, with a nav-rail-style accent tint
   marking the active side. Text-transform:uppercase is inherited from h2. */
.seg { display: inline-flex; border: 1px solid var(--grid); border-radius: 3px; overflow: hidden; }
.seg-btn {
  background: none; border: none; border-left: 1px solid var(--grid);
  color: var(--muted); font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.08em; padding: 3px 10px; cursor: pointer; transition: all 0.15s;
}
.seg-btn:first-child { border-left: none; }
.seg-btn:hover { color: var(--text); }
.seg-btn.active { color: var(--text); background: rgba(225, 6, 0, 0.18); }

.edge { font-weight: 600; }
.edge.pos { color: var(--up); }
.edge.neg { color: var(--down); }

.confmeter {
  display: inline-block; width: 64px; height: 7px; background: #202027;
  border-radius: 2px; overflow: hidden; vertical-align: 1px;
}
.confmeter i { display: block; height: 100%; background: linear-gradient(90deg, #7a1512, var(--accent)); }
.confnum { color: var(--muted); font-size: 11px; margin-left: 6px; }

.probbar {
  position: relative; background: #1d1d23; border-radius: 2px; height: 16px;
  min-width: 120px; overflow: hidden;
}
.probbar i {
  position: absolute; inset: 0 auto 0 0;
  background: linear-gradient(90deg, rgba(225,6,0,0.75), rgba(225,6,0,0.35));
}
.probbar b {
  position: relative; z-index: 1; font-weight: 600; font-size: 11px;
  padding-left: 6px; line-height: 16px;
}

.quote-chip {
  display: inline-flex; flex-direction: column; align-items: center; gap: 1px;
  min-width: 74px; padding: 4px 8px; margin: 2px 4px 2px 0;
  background: var(--panel-2); border: 1px solid var(--grid); border-radius: 4px;
}
.quote-chip .site { font-size: 9px; letter-spacing: 0.1em; color: var(--faint); text-transform: uppercase; }
.quote-chip .price { font-weight: 600; font-size: 12.5px; }
.quote-chip .qedge { font-size: 10.5px; }
.quote-chip.stale { border-style: dashed; opacity: 0.65; }
.quote-chip .flags { font-size: 8.5px; color: var(--warn); }
/* the whole chip - not just the site word - doubles as the outbound
   bookmaker/exchange link when the adapter resolved one, so it carries its
   own hover affordance: pointer cursor + the same accent border/brightness
   lift used elsewhere (e.g. the chart-close button) for outbound controls */
a.quote-chip { text-decoration: none; color: inherit; cursor: pointer; transition: border-color 120ms ease, filter 120ms ease; }
a.quote-chip:hover, a.quote-chip:focus-visible { border-color: var(--accent); filter: brightness(1.2); }
a.quote-chip:hover .site, a.quote-chip:focus-visible .site { color: var(--accent); }

/* ---------- pit wall ---------- */
#nextrace {
  display: flex; align-items: stretch; gap: 1.4rem;
  background:
    radial-gradient(600px 200px at 15% 0%, rgba(225,6,0,0.14), transparent 55%),
    var(--panel);
  border: 1px solid var(--grid); border-radius: 6px; padding: 1.1rem 1.3rem;
}
#nextrace .what .k { font-family: var(--display); font-size: 0.84rem; font-weight: 600; letter-spacing: 0.15em; color: var(--accent); text-transform: uppercase; }
#nextrace .what h3 { font-family: var(--display); font-size: 2.1rem; font-weight: 700; letter-spacing: 0.06em; line-height: 1.05; text-transform: uppercase; }
#nextrace .what .sub { color: var(--muted); margin-top: 2px; }
#countdown { margin-left: auto; text-align: right; }
/* the clock keeps the condensed face: Barlow honors the tabular-nums feature
   below, so ticking digits hold their width (Crimson ignores it and drifts) */
#countdown .clock {
  font-family: var(--condensed); font-weight: 700; font-size: 2.5rem;
  letter-spacing: 0.08em; font-variant-numeric: tabular-nums;
  text-shadow: 0 0 24px rgba(225, 6, 0, 0.25);
}
#countdown .lbl { color: var(--faint); font-size: 10px; letter-spacing: 0.24em; text-transform: uppercase; }

#standings-strip { display: flex; gap: 0.5rem; overflow-x: auto; padding: 0.7rem 0.9rem; }
/* Team colour tags the top-left corner only, as a crop-mark bracket: a short
   solid arm down the left, and a top arm that holds then dissolves to the
   right. Deliberately NOT a full-width header rule. The top-left radius is
   squared off so the bracket sits flush in the corner; --team comes from app.js.
   Both arms are fixed px, not %, so the mark is identical on every card
   whatever the driver's name length. */
.stand-card {
  position: relative;
  flex: 0 0 auto; min-width: 108px; padding: 0.5rem 0.65rem;
  background: var(--panel-2); border: 1px solid var(--grid-soft);
  border-radius: 0 4px 4px 4px;
}
.stand-card::before,
.stand-card::after { content: ""; position: absolute; left: 0; top: 0; pointer-events: none; }
.stand-card::before { width: 2px; height: 14px; background: var(--team, var(--faint)); }
.stand-card::after {
  height: 2px; width: 44px;
  background: linear-gradient(90deg, var(--team, var(--faint)) 0 35%, transparent);
}
.stand-card .p { font-family: var(--display); font-weight: 700; color: var(--faint); font-size: 0.8rem; }
.stand-card .n { font-family: var(--display); font-weight: 600; font-size: 1.05rem; letter-spacing: 0.04em; }
.stand-card .pts { color: var(--muted); font-size: 11px; }
.stand-card .pts b { color: var(--text); }

.newsitem { padding: 0.55rem 0.9rem; border-bottom: 1px solid var(--grid-soft); }
/* wire headlines get their own face (Exo); the meta line below stays mono */
.newsitem a {
  font-family: var(--wire); font-weight: 500; font-size: 13.5px; line-height: 1.35;
  color: var(--text); text-decoration: none;
}
.newsitem a:hover { color: #ff8a86; }
.newsitem .meta { color: var(--faint); font-size: 10.5px; margin-top: 2px; display: flex; gap: 0.5rem; flex-wrap: wrap; }

.edgeitem { display: flex; align-items: center; gap: 0.7rem; padding: 0.5rem 0.9rem; border-bottom: 1px solid var(--grid-soft); }
/* edge titles carry the display face: driver name semibold, question regular */
.edgeitem .q {
  font-family: var(--display); font-weight: 600; font-size: 1.08rem; line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.edgeitem .q .teamname { font-weight: 400; font-size: 0.92rem; }
.edgeitem .scope { color: var(--faint); font-size: 10.5px; }

/* ---------- bets ---------- */
#filterbar {
  display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap;
  padding: 0.65rem 0.9rem; background: var(--panel); border: 1px solid var(--grid);
  border-radius: 6px;
}
#filterbar label { color: var(--faint); font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase; display: flex; align-items: center; gap: 0.45rem; }
#filterbar select, #filterbar input[type="number"] {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--grid);
  border-radius: 3px; padding: 0.28rem 0.5rem; font-family: var(--mono); font-size: 12px;
}
#filterbar input[type="checkbox"] { accent-color: var(--accent); }
#bets-count { margin-left: auto; color: var(--faint); font-size: 11px; }

/* row-end outbound link to place the bet - same quiet treatment as the
   ratings table's "chart >" cell until hovered, then picks up the accent */
.place-link { color: var(--muted); font-size: 11px; text-decoration: none; white-space: nowrap; }
.place-link:hover { color: var(--accent); text-decoration: underline; }

/* ---------- engine ---------- */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.8rem; }
.stat {
  background: var(--panel); border: 1px solid var(--grid); border-radius: 6px;
  padding: 0.7rem 0.9rem;
}
.stat .k { color: var(--faint); font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; }
.stat .v { font-family: var(--display); font-weight: 700; font-size: 1.7rem; letter-spacing: 0.04em; }
.stat .v small { font-size: 0.95rem; color: var(--muted); }

.sharebar { display: inline-block; width: 90px; height: 7px; background: #1d1d23; border-radius: 2px; overflow: hidden; vertical-align: 1px; }
.sharebar i { display: block; height: 100%; background: var(--team, var(--muted)); }

/* model-competition leaderboard: winning candidate's row picks up the same
   up/positive accent used for edges and status dots elsewhere */
#compete-table tr.winner td { color: var(--up); }
/* de-abbreviation: full-word column headers ("2025 walk-forward log-loss")
   and registry labels would otherwise push the compete table's tail columns
   into sideways scroll at 1280 - let headers and the label column wrap */
#compete-table th { white-space: normal; }
#compete-table td:first-child { white-space: normal; }
/* same pressure on the bets table: the wider full-word badges + Confidence
   header clipped the row-end place link, so the scope column wraps instead;
   the floor keeps "Round 12 - Dutch Grand Prix" at two lines, not five */
#bets-table td:nth-child(2) { white-space: normal; min-width: 120px; }
/* and the longest book name ("place at draftkings") folds to two lines
   rather than clipping its tail at 1280 */
#bets-table td:last-child { white-space: normal; min-width: 90px; }
#bets-table .place-link { white-space: normal; }

/* ---------- predictions ---------- */
#pred-controls {
  display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap;
  padding: 0.65rem 0.9rem; background: var(--panel); border: 1px solid var(--grid);
  border-radius: 6px;
}
#pred-controls label { color: var(--faint); font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase; display: flex; align-items: center; gap: 0.45rem; }
#pred-controls select {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--grid);
  border-radius: 3px; padding: 0.28rem 0.5rem; font-family: var(--mono); font-size: 12px;
  min-width: 240px;
}

/* full-grid heatmap: every cell shaded by its own probability (see
   heatCellStyle in app.js), driver column pinned so a 22 x 23 grid still
   scrolls sanely on a phone. border-collapse:separate is deliberate - sticky
   positioning on td/th is unreliable under border-collapse:collapse. */
table.tt.heat { border-collapse: separate; border-spacing: 0; }
table.tt.heat th, table.tt.heat td { text-align: center; padding: 0.32rem 0.4rem; }
table.tt.heat td { font-weight: 600; font-size: 11px; color: var(--text); }
table.tt.heat td.sticky-col, table.tt.heat th.sticky-col {
  position: sticky; left: 0; z-index: 2;
  background: var(--panel); text-align: left; min-width: 160px;
}
table.tt.heat th.sticky-col { z-index: 3; }
table.tt.heat .predexp { display: block; color: var(--faint); font-size: 9.5px; margin-left: 12px; }
table.tt.heat td.heat-cell { min-width: 32px; }
/* top-3 highlight: the row itself is the distribution, this just marks
   which buckets in it matter most */
table.tt.heat td.heat-cell.top1 { box-shadow: inset 0 0 0 2px rgba(255,255,255,0.85); }
table.tt.heat td.heat-cell.top3:not(.top1) { box-shadow: inset 0 0 0 1px rgba(255,255,255,0.4); }
/* negligible cells (<0.5%, see heatCellLabel in app.js) render a dimmed dash
   instead of vanishing outright - a blank cell reads as "no data", a dim
   one reads as "basically none" */
table.tt.heat td.heat-cell.dim { color: var(--faint); font-weight: 400; }

/* ---------- predictions: retrospective (finished rounds) ---------- */
/* retrospective: where the driver actually finished - the one cell per row
   the whole feature exists to compare against. Gold, not white: the top-1/
   top-3 rings already own the white inset band on these exact pixels, and a
   correct prediction (actual cell = top pick) must stay visible, not vanish
   into the ring it confirms (T5 review) */
table.tt.heat td.heat-cell.retro-actual {
  outline: 2px solid var(--warn); outline-offset: -2px; position: relative;
}
.outcome { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  padding: 1px 6px; border-radius: 2px; border: 1px solid var(--grid); }
.outcome.win { color: var(--up); border-color: var(--up); }
.outcome.lose { color: var(--accent); border-color: var(--accent); }
.outcome.void { color: var(--faint); }

.promo-action { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  padding: 1px 6px; border-radius: 2px; border: 1px solid var(--grid); }
.promo-action.promote { color: var(--up); border-color: var(--up); }
.promo-action.hold { color: var(--faint); }

/* ---------- predictions: how-to-read explainer ---------- */
.pred-explainer { padding: 0.6rem 0.9rem 0; border-bottom: 1px solid var(--grid-soft); }
.pred-explainer[open] { padding-bottom: 0.65rem; }
.pred-explainer summary {
  cursor: pointer; color: var(--faint); font-family: var(--display); font-weight: 600;
  font-size: 0.78rem; letter-spacing: 0.1em; text-transform: uppercase;
}
.pred-explainer summary:hover { color: var(--text); }
.pred-explainer summary::marker { color: var(--faint); }
.pred-explainer p { color: var(--muted); font-size: 0.78rem; line-height: 1.6; margin-top: 0.5rem; white-space: normal; }

/* ---------- 24-0 v2: four-reel team builder ---------- */
/* #t240-explainer reuses .pred-explainer as-is (see above) - same collapsible
   how-to-read treatment, no new rules needed for it. */
#t240-mode-row { padding: 0.7rem 0.9rem 0; }
#t240-mode-row label {
  color: var(--faint); font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase;
  display: inline-flex; align-items: center; gap: 0.5rem;
}
#t240-mode-row select {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--grid);
  border-radius: 3px; padding: 0.28rem 0.5rem; font-family: var(--mono); font-size: 12px;
}

/* the reel rig: four fixed-height clipping windows over tall vertical
   strips (app.js builds a bounded windowed strip per reel, never the full
   pool) - overflow:hidden on the WINDOW is what makes the strip's own
   transform-transition read as a slot-machine scroll rather than a list. */
#t240-rig { display: flex; flex-wrap: wrap; gap: 0.7rem; padding: 0.9rem; }
.t240-reel-card {
  flex: 1 1 150px; min-width: 130px; max-width: 220px;
  background: var(--panel-2); border: 1px solid var(--grid); border-radius: 6px;
  padding: 0.5rem 0.6rem 0.6rem; text-align: center;
}
.t240-reel-label {
  color: var(--faint); font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase;
  margin-bottom: 4px;
}
.t240-reel-window {
  height: 40px; overflow: hidden; position: relative;
  background: var(--bg-deep); border-radius: 3px; border: 1px solid var(--grid-soft);
}
.t240-reel-strip { display: flex; flex-direction: column; will-change: transform; }
.t240-reel-cell {
  height: 40px; min-height: 40px; display: flex; align-items: center; justify-content: center;
  gap: 5px; padding: 0 8px;
  font-family: var(--display); font-weight: 600; font-size: 0.92rem;
}
/* min-width:0 is required for a flex item to shrink below its content's
   natural size at all - without it, text-overflow:ellipsis never triggers
   inside a flex container (see t240CellHtml's own comment in app.js). */
.t240-reel-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* motion blur while a reel's transform-transition is in flight, cleared the
   instant THAT reel's own transition ends (app.js listens per-strip, not
   globally) - a flat filter, no per-frame trail effects needed. */
.reel-blur { filter: blur(2px); }
/* landing bounce lives on the CARD, never the strip: the strip already owns
   an inline translateY transform for the scroll itself, and animating
   `transform` again on that same element would replace it mid-keyframe. */
@keyframes reel-land { 0% { transform: scale(1); } 36% { transform: scale(1.09); } 100% { transform: scale(1); } }
.t240-reel-card.reel-land { animation: reel-land 380ms ease; }

/* the collapsed result: four compact pills replacing the big rig once every
   reel has landed - team pill in constructor livery (the --team custom
   property, same convention .stand-card/.sharebar already use), driver
   pills neutral, era pill on the app accent. */
#t240-pills { display: flex; flex-wrap: wrap; gap: 0.6rem; padding: 0 0.9rem 0.9rem; }
.t240-pill {
  padding: 0.4rem 0.8rem; border-radius: 999px; background: var(--panel-2);
  border: 1px solid var(--grid); font-family: var(--display); font-weight: 600; font-size: 0.85rem;
}
.t240-pill.team { border-color: var(--team, var(--grid)); color: var(--team, var(--text)); }
.t240-pill.era { border-color: var(--accent); color: var(--accent); }
@keyframes spin-result-in {
  0% { opacity: 0; transform: scale(0.62); }
  56% { opacity: 1; transform: scale(1.08); }
  100% { opacity: 1; transform: scale(1); }
}
#t240-pills.spin-result-in { animation: spin-result-in 420ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }

/* idle "come tap me" breathe on SPIN, present before any interaction and
   restored between spins (decision 10: free re-spins) - removed only while
   a spin is actually in flight (app.js). */
@keyframes spin-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.055); } }
.t240-btn.spin-pulse { animation: spin-pulse 1.8s ease-in-out infinite; }

#t240-controls { display: flex; gap: 0.6rem; flex-wrap: wrap; padding: 0.2rem 0.9rem 0.9rem; }
.t240-btn {
  background: var(--panel-2); border: 1px solid var(--grid); color: var(--text);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  padding: 0.55rem 0.9rem; border-radius: 4px; cursor: pointer; transition: all 0.15s;
}
.t240-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.t240-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.t240-btn.primary { border-color: var(--accent); background: rgba(225, 6, 0, 0.14); }
.t240-btn.primary:hover:not(:disabled) { background: rgba(225, 6, 0, 0.24); }

/* driver pick panel (24-0 v2.1 staged flow): appears once era + team land
   and stays until the NEXT era+team spin, so the pick can be changed at any
   point; the selected chip mirrors the primary-button accent treatment. */
#t240-pick { padding: 0.2rem 0.9rem 0.9rem; }
#t240-pick h3 {
  font-family: var(--display); font-weight: 700; font-size: 0.95rem;
  text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 0.5rem;
}
#t240-pick-list { display: flex; flex-wrap: wrap; gap: 0.5rem; max-height: 300px; overflow-y: auto; }
.t240-pick-chip {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  background: var(--panel-2); border: 1px solid var(--grid); color: var(--text);
  border-radius: 4px; padding: 0.45rem 0.7rem; cursor: pointer; text-align: left;
  transition: all 0.15s;
}
.t240-pick-chip:hover { border-color: var(--accent); }
.t240-pick-chip .nm { font-weight: 600; font-size: 0.85rem; }
.t240-pick-chip .meta { font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.05em; color: var(--muted); text-transform: uppercase; }
.t240-pick-chip.selected { border-color: var(--accent); background: rgba(225, 6, 0, 0.14); }
.t240-pick-chip.selected .nm { color: var(--accent); }

/* pre-landing hint text inside the driver / co-driver reel windows */
.t240-reel-hint { color: var(--faint); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; }

/* the assembled TeamSheet: two driver tiles + the shared .cards/.stat grid
   (also used by the engine view) for team/era/multiplier/DNF rate. */
.t240-sheet-drivers { display: flex; flex-wrap: wrap; gap: 0.7rem; padding: 0.9rem 0.9rem 0; }
.t240-sheet-driver {
  flex: 1 1 200px; background: var(--panel-2); border: 1px solid var(--grid-soft);
  border-radius: 6px; padding: 0.6rem 0.8rem;
}
.t240-sheet-driver h3 { font-family: var(--display); font-weight: 700; font-size: 1.15rem; text-transform: uppercase; letter-spacing: 0.02em; }
.t240-sheet-driver .sub { color: var(--muted); font-size: 0.82rem; margin-top: 2px; }
#t240-sheet .cards { padding: 0.9rem; }

#t240-record { padding: 0.9rem; }
.t240-record-main {
  font-family: var(--display); font-weight: 700; font-size: 1.35rem; letter-spacing: 0.02em;
}
.t240-record-wl { color: var(--muted); font-size: 0.8rem; margin-top: 2px; letter-spacing: 0.08em; text-transform: uppercase; }
/* perfect season: gold, the same --warn token the win chips below use, so a
   24-0 record visually pays off every win chip that built it */
#t240-record.t240-perfect .t240-record-main { color: var(--warn); text-shadow: 0 0 18px rgba(245, 197, 24, 0.45); }
#t240-record.t240-perfect .t240-record-wl { color: var(--warn); }
.badge.tier-perfect { border-color: var(--warn); color: var(--warn); }

.t240-focus-team {
  padding: 0.9rem 0.9rem 0.4rem; font-family: var(--display); font-weight: 700;
  font-size: 1.05rem; text-transform: uppercase; letter-spacing: 0.02em;
}
.t240-focus-driver { padding: 0.3rem 0.9rem 0.7rem; }
.t240-focus-driver h3 {
  font-family: var(--display); font-weight: 600; font-size: 0.95rem;
  text-transform: uppercase; letter-spacing: 0.02em; margin-bottom: 4px;
}

/* the round strip: one chip per calendar round, background-shaded by that
   round's win probability via the same heatCellStyle() the predictions
   heatmap cells use (app.js) - "heat-cell-like chips" taken literally, v1's
   own chip language reused verbatim. A class now (not a single #id): v2
   renders one strip per driver, in both the custom-team focus block and
   every expandable standings row, not just one strip for the whole page. */
.t240-rounds { display: flex; flex-wrap: wrap; gap: 6px; }
.t240-chip {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 52px; padding: 5px 7px; border-radius: 4px;
  background: var(--panel-2); border: 1px solid var(--grid);
}
.t240-chip .rnd { font-family: var(--mono); font-size: 8.5px; letter-spacing: 0.06em; color: var(--faint); text-transform: uppercase; }
.t240-chip .pos { font-family: var(--display); font-weight: 700; font-size: 0.95rem; }
.t240-chip .wp { font-family: var(--mono); font-size: 9.5px; color: var(--muted); }
.t240-chip.t240-dnf { border-style: dashed; }
.t240-chip.t240-dnf .pos { color: var(--down); }
.t240-chip.t240-win { border-color: var(--warn); box-shadow: inset 0 0 0 1px var(--warn); }
.t240-chip.t240-win .pos { color: var(--warn); }

/* full-grid standings: every team in the simulation, expandable per-team
   round strips (t240-standings-row toggles its sibling t240-detail-row) */
.t240-standings-row td { white-space: normal; }
.t240-detail-row td { background: rgba(255, 255, 255, 0.015); padding: 0; }

/* celebration, PERFECT seasons only: a CSS-only particle burst + flash
   (82-0's own primitives) - fixed overlay, pointer-events:none so it never
   blocks the page underneath, self-clearing after its animation window. */
/* ---------- Podium Chasers public mode (body[data-site="pc"]) ----------
   One template serves both sites (app.render_index); these rules shape the
   public page: no nav rail (the #shell flex row lets main fill the width),
   no fixture badge / odds dots, and the pc-only footer. The footer element
   is always in the DOM so Charlie can style it in place; dev simply never
   displays it. */
[data-site="dev"] #pc-footer { display: none; }
#pc-footer { padding: 1.6rem 0.2rem 0.6rem; color: var(--muted); font-size: 0.78rem; line-height: 1.5; }
#pc-footer a { color: var(--muted); text-decoration: underline; }
[data-site="pc"] nav#rail, [data-site="pc"] #mode-badge, [data-site="pc"] #site-dots { display: none; }

#t240-celebrate { position: fixed; inset: 0; z-index: 90; pointer-events: none; opacity: 0; overflow: hidden; }
#t240-celebrate.on { opacity: 1; }
.t240-flash { position: absolute; inset: 0; background: var(--warn); opacity: 0; animation: t240-flash-anim 480ms ease-out; }
@keyframes t240-flash-anim { 0% { opacity: 0; } 12% { opacity: 0.5; } 100% { opacity: 0; } }
.t240-particle { position: absolute; width: 8px; height: 8px; border-radius: 50%; animation: t240-burst 1100ms cubic-bezier(0.2, 0.7, 0.4, 1) forwards; }
@keyframes t240-burst {
  0% { transform: translate3d(0, 0, 0) scale(1); opacity: 1; }
  100% { transform: translate3d(var(--dx), var(--dy), 0) scale(0.3); opacity: 0; }
}

/* ---------- chart overlay ---------- */
#chart-overlay {
  position: fixed; inset: 0; background: rgba(5, 5, 6, 0.82);
  display: none; align-items: center; justify-content: center; z-index: 100;
  backdrop-filter: blur(3px);
}
#chart-overlay.open { display: flex; }
#chart-panel {
  width: min(940px, 94vw); background: var(--panel); border: 1px solid var(--grid);
  border-radius: 8px; box-shadow: 0 20px 80px rgba(0,0,0,0.6);
}
#chart-box { width: 100%; height: 420px; }
#chart-panel h2 button { margin-left: auto; background: none; border: 1px solid var(--grid); color: var(--muted); border-radius: 3px; padding: 2px 10px; cursor: pointer; font-family: var(--mono); }
#chart-panel h2 button:hover { color: var(--text); border-color: var(--accent); }

.empty { color: var(--faint); padding: 1rem; text-align: center; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: #26262d; border-radius: 5px; }
::-webkit-scrollbar-track { background: transparent; }

/* inner scroll containers get thin, dark-theme bars */
.panel, nav#rail, #standings-strip, .view {
  scrollbar-width: thin; scrollbar-color: #2e2e36 transparent;
}
.panel::-webkit-scrollbar, nav#rail::-webkit-scrollbar,
#standings-strip::-webkit-scrollbar, .view::-webkit-scrollbar { width: 8px; height: 8px; }
.panel::-webkit-scrollbar-thumb, nav#rail::-webkit-scrollbar-thumb,
#standings-strip::-webkit-scrollbar-thumb, .view::-webkit-scrollbar-thumb {
  background: #2e2e36; border-radius: 4px;
  border: 2px solid transparent; background-clip: padding-box;
}
.panel::-webkit-scrollbar-thumb:hover, nav#rail::-webkit-scrollbar-thumb:hover,
#standings-strip::-webkit-scrollbar-thumb:hover, .view::-webkit-scrollbar-thumb:hover {
  background: #3c3c46; background-clip: padding-box;
}

/* ---------- responsive ---------- */
@media (max-width: 860px) {
  #boot-note { display: none; }
  header { gap: 0.6rem; }
  header h1 { font-size: 1.1rem; letter-spacing: 0.14em; }
  #shell { flex-direction: column; }
  nav#rail {
    width: 100%; display: flex; padding: 0; border-right: none;
    border-bottom: 1px solid var(--grid); overflow-x: auto;
  }
  nav#rail button { width: auto; flex: 1 0 auto; justify-content: center; border-left: none; border-bottom: 3px solid transparent; padding: 0.55rem 0.8rem; }
  nav#rail button.active { border-left-color: transparent; border-bottom-color: var(--accent); }
  .grid2 { grid-template-columns: 1fr; }
  main { padding: 0.8rem 0.8rem 2.5rem; }
  #nextrace { flex-direction: column; gap: 0.6rem; }
  #countdown { margin-left: 0; text-align: left; }
  #site-dots .dot span { display: none; }
  table.tt th:nth-child(n+5), table.tt td:nth-child(n+5) { display: none; }
  table.tt.keep-cols th, table.tt.keep-cols td { display: table-cell; }
  /* ratings header carries a toggle + two dropdowns now - wrap instead of
     forcing the panel to scroll sideways to reach them */
  #view-ratings .panel > h2 { flex-wrap: wrap; row-gap: 6px; }
  /* full-word round options (de-abbreviation) made the round select - which
     sizes itself to its longest option - and the race badge wider than the
     viewport; cap both to the row so they clip instead of dragging the page
     sideways */
  #pred-controls label { flex: 1 1 auto; min-width: 0; max-width: 100%; }
  #pred-controls select { flex: 1 1 auto; min-width: 0; max-width: 100%; }
  #pred-panel > h2 { flex-wrap: wrap; row-gap: 6px; }
  #pred-race-badge { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
  /* full-word elo model labels would force the A/B table into sideways panel
     scroll on a phone - wrap the label column instead */
  #elo-ab-table td:first-child { white-space: normal; min-width: 140px; }
  /* the competition-result header carries a tier badge that can run long
     ("TITLE FIGHT" etc) - same wrap treatment as every other header above */
  #view-twentyfour .panel > h2 { flex-wrap: wrap; row-gap: 6px; }
  /* force exactly two reels per row rather than trust flex-wrap's own
     min-width arithmetic at the narrowest phones - four 130px-min cards
     cannot fit one row under ~375px regardless, but pinning the basis
     removes any doubt and keeps cell text comfortably legible */
  .t240-reel-card { flex: 1 1 45%; min-width: 0; }
}

/* narrow phones (<=400px): the brand steps down once more so
   brand + badge + status dots clear a 360px viewport */
@media (max-width: 400px) {
  header h1 { font-size: 1rem; letter-spacing: 0.1em; }
}

/* ---------- desktop: the shell fills the viewport, every panel scrolls itself.
   Mobile keeps the stacked page-scroll flow above. ---------- */
@media (min-width: 861px) {
  body { height: 100vh; height: 100dvh; overflow: hidden; }
  #shell { height: calc(100vh - 52px); height: calc(100dvh - 52px); min-height: 0; }
  nav#rail { overflow-y: auto; }
  main {
    display: flex; flex-direction: column;
    min-height: 0; overflow: hidden; padding: 1.1rem 1.4rem;
  }
  /* the view distributes height; if the fixed rows alone overflow a very short
     window it degrades to scrolling itself, so nothing is ever unreachable */
  .view.active { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow-y: auto; }
  .panel { overflow-y: auto; }
  .panel > h2 { position: sticky; top: 0; left: 0; z-index: 5; background: var(--panel); }
  /* natural-height rows */
  #nextrace, #view-pitwall > .panel, #filterbar, #pred-controls, .cards { flex: 0 0 auto; }
  /* workhorse rows absorb the leftover height; the panels inside them scroll.
     basis 0 (not auto) so a tall table inside never drags shrink math: the row
     simply takes whatever is left over, floored at a useful height */
  .grid2 { flex: 1 1 0; min-height: 220px; grid-template-rows: minmax(0, 1fr); }
  .grid2 > .panel { min-height: 0; }
  #view-ratings > .panel, #view-bets > .panel, #view-predictions > .panel,
  #view-twentyfour > .panel { flex: 0 1 auto; min-height: 0; }
  /* the A/B panel keeps its natural height while it fits, then gives way to the
     grid row's floor and scrolls itself - the view only scrolls as a last resort */
  #view-engine > .panel { flex: 0 1 auto; min-height: 150px; }
  #chart-panel { max-height: 90vh; }
}
