/* ════════════════════════════════════════════════════════════════════
   SimRecap · "Grandstand" design system (Direction A)
   Shared tokens, chrome and primitives. Loaded by every page.
   Light-first editorial: warm paper, hairline rules, Archivo display,
   Inter body/data, one rosso accent.
   ════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Grandstand core tokens (light) ── */
  --paper:     #f7f5f0;
  --surface:   #fefdfb;
  --ink:       #1b1812;
  --sub:       #6e6759;
  --faint:     #7e776a;
  --hero-sub:  #9a9a9a; /* on-dark hero subtext: neutral grey, constant in both themes */
  --line:      #e4dfd3;
  --line-soft: #ede9df;
  --red:       #c22d20;
  --red-dark:  #9c2318;
  --green:     #1e7a3c;
  --pit-bg:    #efe7cf;
  --pit-text:  #7a5f12;

  /* ── Class identity colors (data, not decoration) ── */
  --gtp:  #b87900;
  --lmp2: #2768d4;
  --gt3:  #d42757;
  --lmp3:  #16a34a;
  --cup:   #7c3aed;
  --sport: #c2410c;
  --tcr:   #0d9488;
  --m2:    #be185d;
  --fastest-lap: #a012c9; /* kept by decision: purple = fastest, motorsport convention */

  /* Derived tints (backgrounds on paper) */
  --gtp-light:  color-mix(in srgb, var(--gtp) 13%, var(--paper));
  --gtp-mid:    color-mix(in srgb, var(--gtp) 30%, var(--paper));
  --lmp2-light: color-mix(in srgb, var(--lmp2) 11%, var(--paper));
  --lmp2-mid:   color-mix(in srgb, var(--lmp2) 28%, var(--paper));
  --gt3-light:  color-mix(in srgb, var(--gt3) 11%, var(--paper));
  --gt3-mid:    color-mix(in srgb, var(--gt3) 28%, var(--paper));
  --lmp3-light: color-mix(in srgb, var(--lmp3) 11%, var(--paper));
  --cup-light:  color-mix(in srgb, var(--cup) 11%, var(--paper));
  --sport-light:color-mix(in srgb, var(--sport) 11%, var(--paper));
  --tcr-light:  color-mix(in srgb, var(--tcr) 11%, var(--paper));
  --m2-light:   color-mix(in srgb, var(--m2) 11%, var(--paper));
  --gold:       #b87900;
  --gold-light: var(--gtp-light);

  /* ── Type ── */
  --font-display: 'Archivo', system-ui, sans-serif;
  --font-body:    'Inter', system-ui, sans-serif;
  --font-serif:   'Newsreader', Georgia, serif;   /* story prose (race stories) */

  /* ── Legacy variable bridge ──
     Pre-Grandstand pages and JS-generated inline styles reference these.
     They resolve to Grandstand tokens so old selectors recolor correctly. */
  --white:         var(--surface);
  --off-white:     var(--paper);
  --border:        var(--line);
  --border-strong: var(--ink);
  --text:          var(--ink);
  --text-2:        var(--sub);
  --text-3:        var(--faint);
  --sans:          var(--font-body);
  --mono:          var(--font-body);
  --radius: 4px;
  --shadow: none;
  --shadow-md: none;
}

[data-theme="dark"] {
  /* Neutral dark grey inversion */
  --paper:     #26262b;
  --surface:   #313136;
  --ink:       #e9e9ee;
  --sub:       #a2a2aa;
  --faint:     #8e8e97;
  --line:      #3a3a40;
  --line-soft: #36363b;
  --red:       #e04a36;
  --red-dark:  #c2382a;
  --green:     #4caf77;
  --pit-bg:    #2e2810;
  --pit-text:  #cdb462;

  --gtp:  #d9a013;
  --lmp2: #5c92e8;
  --gt3:  #ef6292;
  --lmp3:  #4ade80;
  --cup:   #c084fc;
  --sport: #fb923c;
  --tcr:   #2dd4bf;
  --m2:    #f472b6;
  --fastest-lap: #e879f9;
  --gold: #d9a013;
}

/* ════════ Base ════════ */
*, *::before, *::after { box-sizing: border-box; }
/* The root carries the paper tone so the iOS/iPadOS overscroll and canvas region
   (the area the body box never covers) paints paper rather than the WebView's
   default white. body sets the same tone for the content box; html governs the
   strip above and below. */
html {
  scroll-behavior: smooth; background: var(--paper);
  /* Hold text at the size the viewport meta asks for. Without this, iOS Safari
     inflates body text when the device is turned into landscape, which reads as
     the whole page suddenly zooming in. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* Clip any horizontal overflow at the viewport. A purely decorative element
     that reaches past the right edge (for instance a Performance distribution
     tooltip, which is never shown on a touch device) otherwise makes the
     document wider than the screen on iOS Safari. Safari then shrinks the whole
     page to fit, which is the slight zoom out and rightward shift seen on first
     load and on the Performance tab. clip pins the page to the viewport width
     without the overflow-y side effect that overflow-x: hidden would force, and
     inner horizontal scrollers keep their own overflow: auto. */
  overflow-x: clip;
  /* Always reserve the scrollbar gutter so the content width is identical on
     every page, whether or not it scrolls. Without this, a page with no
     scrollbar is a scrollbar-width wider, which re-centres the fixed-width top
     bar and shifts the brand a few pixels; it also showed as a jump across a
     page transition, and as a jump when a page grows tall enough to scroll. */
  scrollbar-gutter: stable;
}
body {
  margin: 0; padding: 0;
  font-family: var(--font-body);
  background: var(--paper);
  color: var(--ink);
  font-size: 14.5px;
  line-height: 1.55;
  /* Belt and braces with the clip on html: keep the content box itself from
     ever forcing a horizontal scroll past the viewport. */
  overflow-x: clip;
  min-height: 100vh;   /* fallback for browsers without svh */
  min-height: 100svh;  /* iPad/iOS: small viewport height, never taller than the visible area — stops the footer overshoot */
  /* Sticky footer via a grid, NOT a flex column. The three shell children map to
     the three rows: header (auto), #view-root (1fr, absorbs the free space) and
     footer (auto). A flex column distributed that free space with the footer's
     margin-top:auto, but iOS WebKit caches a flex container's used height and does
     not always shrink it when the view's content shrinks (navigating from a tall
     page, e.g. Home or a many-race driver, to a shorter one). The footer was then
     pushed to the bottom of a stale, too-tall body, below the fold — the recurring
     "massive footer" on iPad. A grid recomputes the 1fr track from the current
     layout every time, so a shrink takes effect and the footer cannot strand. */
  display: grid; grid-template-rows: auto 1fr auto;
  font-variant-numeric: tabular-nums lining-nums;
  -webkit-font-smoothing: antialiased;
}

/* Content container — the responsive ladder:
   <720 compact (18px) · 720–1199 (32px) · ≥1200 (56px) · cap 1360 */
.page, .gs-wide {
  width: 100%; max-width: 1360px;
  margin: 0 auto; padding-left: 18px; padding-right: 18px;
}
@media (min-width: 720px)  { .page, .gs-wide { padding-left: 32px; padding-right: 32px; } }
@media (min-width: 1200px) { .page, .gs-wide { padding-left: 56px; padding-right: 56px; } }

/* ════════ Type primitives ════════ */
.gs-display {
  font-family: var(--font-display); font-weight: 800;
  letter-spacing: -0.015em; line-height: 1.04; color: var(--ink);
}
.gs-overline {
  font-family: var(--font-body); font-size: 11px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--faint);
}
.gs-num { font-variant-numeric: tabular-nums lining-nums; letter-spacing: 0.01em; }

/* Section head: overline + trailing hairline (+ optional right meta) */
.gs-section-head { display: flex; align-items: center; gap: 16px; }
.gs-section-head::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.gs-section-head .gs-section-meta { order: 3; font-size: 12px; color: var(--faint); white-space: nowrap; }

/* ════════ Top bar ════════ */
.gs-topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding-top: 16px; padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
  background: var(--paper);
}
.brand { display: inline-flex; align-items: center; gap: 7px; text-decoration: none; }
.brand .wm {
  font-family: var(--font-display); font-weight: 800; font-size: 20px;
  letter-spacing: -0.01em; color: var(--ink); line-height: 1;
}
.brand .wm span { color: var(--red); }
.brand .wm-slash {
  width: 8px; height: 8px; background: var(--red);
  transform: skewX(-12deg); display: inline-block;
}
.gs-nav { display: flex; align-items: center; gap: 28px; }
.gs-nav a {
  font-size: 13.5px; font-weight: 500; color: var(--sub); text-decoration: none;
  border-bottom: 2px solid transparent; padding-bottom: 2px; transition: color .12s;
}
.gs-nav a:hover { color: var(--ink); }
.gs-nav a.active { font-weight: 700; color: var(--ink); border-bottom-color: var(--red); }
.dark-toggle {
  width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--line); background: none; color: var(--sub);
  font-size: 15px; line-height: 1; cursor: pointer; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  transition: border-color .12s;
}
.dark-toggle:hover { border-color: var(--faint); }
/* The dark toggle and the share button sit as a tight pair at the right of the nav. */
.topbar-tools { display: inline-flex; align-items: center; gap: 10px; }
.share-btn {
  width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--line); background: none; color: var(--sub);
  cursor: pointer; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  transition: border-color .12s, color .12s;
}
.share-btn:hover { border-color: var(--faint); color: var(--ink); }
.share-btn svg { width: 15px; height: 15px; display: block; }
@media (max-width: 719.9px) {
  .gs-nav { gap: 18px; }
  .gs-nav a { font-size: 13px; }
  /* The share button has tightened the nav on the phone. Drop the Majors 24
     link here only; it stays in the nav on tablet and desktop, and Majors 24
     remains reachable on the phone through the coverage banner on the home
     page. */
  .gs-nav a[data-nav="majors24"] { display: none; }
}

/* ════════ Share popover ════════ */
.share-pop {
  /* Above the race story report modal (z-index 1200) so the popover is not
     trapped behind it when the report's own share button is used. */
  position: fixed; z-index: 1300;
  width: 320px; max-width: calc(100vw - 24px);
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .16);
  padding: 16px;
  font-family: var(--font-body);
}
.share-pop[hidden] { display: none; }
.share-pop-head {
  font-family: var(--font-display); font-weight: 700; font-size: 14px;
  letter-spacing: -0.01em; color: var(--ink); margin-bottom: 10px;
}
.share-url {
  width: 100%; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--line-soft); color: var(--ink);
  font-family: var(--font-body); font-size: 12.5px;
  padding: 8px 10px; margin-bottom: 10px;
}
.share-url:focus { outline: none; border-color: var(--faint); }
.share-copy {
  width: 100%; border: none; border-radius: 6px; cursor: pointer;
  background: var(--red); color: #fff;
  font-family: var(--font-body); font-weight: 700; font-size: 13px; letter-spacing: .02em;
  padding: 9px 14px; transition: background .12s;
}
.share-copy:hover { background: var(--red-dark); }
.share-copy.is-copied { background: var(--ink); color: var(--paper); }

/* ════════ Footer ════════ */
footer {
  /* The body grid (grid-template-rows: auto 1fr auto) keeps the footer at the
     bottom: it is the last, auto-sized row, sitting below the 1fr view row. No
     margin-top:auto or flex sizing is needed, and neither would survive the iOS
     stale-flex-height bug the grid was adopted to avoid (see the body note). */
  border-top: 1px solid var(--line);
  padding: 20px 18px;
  font-size: 12.5px; color: var(--faint);
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 8px;
}
@media (min-width: 720px)  { footer { padding-left: 32px; padding-right: 32px; } }
@media (min-width: 1200px) { footer { padding-left: 56px; padding-right: 56px; } }
footer strong { color: var(--sub); font-weight: 700; }
footer a { color: var(--red); text-decoration: none; }
footer a:hover { color: var(--red-dark); }

/* ════════ Buttons ════════ */
.gs-btn {
  display: inline-block; background: var(--red); color: #fff;
  font-family: var(--font-body); font-weight: 700; font-size: 13.5px;
  padding: 10px 20px; border-radius: 4px; border: none;
  text-decoration: none; cursor: pointer; transition: background .12s;
}
.gs-btn:hover { background: var(--red-dark); }
.gs-btn-outline {
  display: inline-block; background: none; color: var(--ink);
  border: 1px solid var(--ink); font-weight: 700; font-size: 13.5px;
  padding: 9px 20px; border-radius: 4px; text-decoration: none; cursor: pointer;
}

/* ════════ Class chips — colored text labels, data not decoration ════════ */
.cls-pill {
  font-family: var(--font-body);
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.1em;
  text-transform: uppercase; padding: 0; border-radius: 0;
  background: none !important;
  display: inline-block; line-height: 1.3; min-width: 0; text-align: left;
}
.cls-gtp, .cls-p919      { color: var(--gtp); }
.cls-lmp2, .cls-hpd      { color: var(--lmp2); }
.cls-gt3, .cls-gte, .cls-gt3pro { color: var(--gt3); }
.cls-lmp3  { color: var(--lmp3); }
.cls-cup   { color: var(--cup); }
.cls-sport { color: var(--sport); }
.cls-tcr   { color: var(--tcr); }
.cls-m2    { color: var(--m2); }

/* ════════ Search (shared component) ════════ */
/* z-index: the driver page names this element for the view transition, which
   makes it a stacking context; the dropdown's own z-index then only counts
   inside it, so the wrap itself must sit above later positioned content
   (the score rings) or the results panel paints underneath. */
.search-wrap { position: relative; z-index: 30; }
.search-box {
  width: 100%; padding: 14px 16px 14px 44px;
  font-size: 15px; font-family: var(--font-body);
  background: var(--surface); border: none; border-radius: 0;
  color: var(--ink); outline: none;
  box-shadow: 7px 7px 0 var(--red); /* signature move — once per page */
  transition: box-shadow .12s;
}
.search-box:focus { box-shadow: 7px 7px 0 var(--red-dark); }
.search-box::placeholder { color: var(--faint); }
.search-icon { position: absolute; left: 16px; top: 50%; transform: translateY(-50%); color: var(--faint); pointer-events: none; }
.search-results {
  position: absolute; top: calc(100% + 10px); left: 0; right: 0;
  background: var(--paper); border: 1px solid var(--line);
  box-shadow: 0 10px 28px rgba(27,24,18,0.16);
  z-index: 200; overflow: hidden; display: none;
}
.search-results.open { display: block; }
.search-group-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--faint); padding: 10px 14px 6px;
  background: var(--paper); border-bottom: 1px solid var(--line);
}
.search-item {
  display: flex; align-items: center; gap: 12px; padding: 10px 14px;
  text-decoration: none; color: inherit;
  border-bottom: 1px solid var(--line-soft); transition: background .1s; cursor: pointer;
}
.search-item:last-child { border-bottom: none; }
.search-item:hover, .search-item.active { background: var(--surface); }
.search-item-icon { display: none; }
.search-item-main { flex: 1; min-width: 0; }
.search-item-name { font-size: 13.5px; font-weight: 700; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.search-item-sub  { font-size: 11.5px; color: var(--faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
.search-item-meta { font-size: 11.5px; color: var(--faint); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.search-empty { padding: 20px 14px; text-align: center; font-size: 13px; color: var(--faint); }
.search-show-more {
  padding: 9px 14px; font-size: 12.5px; color: var(--red); cursor: pointer;
  border-top: 1px solid var(--line); font-weight: 700; transition: background .1s;
}
.search-show-more:hover { background: var(--surface); }

/* ════════ Stat strip — hairline columns, no boxes ════════
   (driver profile career stats; same pattern reused by race.html car panel) */
.stat-row {
  display: grid; grid-template-columns: repeat(8, 1fr);
  border-top: 1px solid var(--line);
}
.stat-card {
  border-left: 1px solid var(--line-soft);
  padding: 14px 16px 12px 16px;
  display: flex; flex-direction: column; align-items: flex-start;
  background: none; border-radius: 0; box-shadow: none;
}
.stat-card:first-child { border-left: none; padding-left: 0; }
.stat-lbl {
  order: 1;
  font-size: 10px; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--faint);
  line-height: 1.2; margin: 0 0 6px;
}
.stat-val {
  order: 2;
  font-family: var(--font-display); font-weight: 800; font-size: 24px;
  letter-spacing: -0.01em; color: var(--ink); line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.stat-icon { display: none; }
.stat-rate { order: 3; font-size: 11.5px; color: var(--sub); line-height: 1.35; margin-top: 6px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.stat-rate .soft-bad { color: var(--red); }
@media (max-width: 1023.9px) {
  .stat-row { grid-template-columns: repeat(4, 1fr); }
  .stat-card { padding: 12px 14px 10px; }
  .stat-card:nth-child(4n+1) { border-left: none; padding-left: 0; }
  .stat-card:nth-child(n+5) { border-top: 1px solid var(--line-soft); }
}
@media (max-width: 719.9px) {
  .stat-row { grid-template-columns: repeat(2, 1fr); }
  .stat-card:nth-child(4n+1) { border-left: 1px solid var(--line-soft); padding-left: 14px; }
  .stat-card:nth-child(2n+1) { border-left: none; padding-left: 0; }
  .stat-card:nth-child(n+3) { border-top: 1px solid var(--line-soft); }
  .stat-val { font-size: 21px; }
}

/* ════════ Utility ════════ */
.loading, .error { text-align: center; padding: 80px 32px; color: var(--faint); font-size: 14px; }
::selection { background: color-mix(in srgb, var(--red) 22%, transparent); }

/* ════════════════════════════════════════════════════════════════════
   Page transitions · expand from centre
   The SPA router animates same-document view swaps with
   document.startViewTransition(); these ::view-transition(root) rules style that
   swap, growing the incoming view up from the centre. A fixed origin keeps the
   motion symmetric and independent of scroll. A progressive enhancement:
   browsers without View Transitions, and readers who prefer reduced motion,
   simply navigate with no animation. (The cross-document @view-transition opt-in
   was dropped with the SPA merge: the router intercepts every in-app link, so a
   cross-document navigation between views no longer happens.)
   ════════════════════════════════════════════════════════════════════ */

:root {
  --pt-dur:  480ms;
  --pt-ease: cubic-bezier(.22, .61, .36, 1);   /* the house easing */
}

@keyframes ptExpandIn  { from { opacity: 0; transform: scale(.90); } to { opacity: 1; transform: none; } }
@keyframes ptExpandOut { from { opacity: 1; transform: none; }       to { opacity: 0; transform: scale(1.03); } }

/* The incoming view grows from the point that was clicked: the router sets
   --pt-ox / --pt-oy (viewport px) from the clicked card/row before the
   transition. Without them (top-bar nav, Back/Forward, direct load) it falls back
   to centre. The outgoing view always settles toward centre. */
::view-transition-old(root) { transform-origin: 50% 42%; animation: ptExpandOut calc(var(--pt-dur) * 0.7) var(--pt-ease) both; }
::view-transition-new(root) { transform-origin: var(--pt-ox, 50%) var(--pt-oy, 42%); animation: ptExpandIn var(--pt-dur) var(--pt-ease) both; }

/* Hold the top bar still. Giving it its own transition name lifts it out of the
   root snapshot, so only the body expands beneath a fixed header rather than the
   whole page, nav included, zooming up. Freezing the group stops the bar sliding
   when the outgoing page was scrolled (its bar is captured off-screen) and the
   incoming page sits at the top; its contents, the active tab, still cross-fade. */
.gs-topbar { view-transition-name: gs-topbar; }
::view-transition-group(gs-topbar) { animation: none; }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}

/* ════════════════════════════════════════════════════════════════════
   Data-view loader · spinner
   Race and Driver fetch multi-MB JSON and cannot paint content on the first
   frame, so a small spinner shows while the data is acquired, then the content
   dissolves in. transform: rotate is composited, so it keeps turning even while
   the page parses its data on the main thread. Race centres it in a full-viewport
   fixed overlay; Driver centres it in the content flow.
   ════════════════════════════════════════════════════════════════════ */
.sr-loader {
  position: fixed; inset: 0; pointer-events: none;
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.sr-spinner {
  width: 30px; height: 30px; border-radius: 50%;
  border: 3px solid var(--line); border-top-color: var(--red);
  will-change: transform; animation: srSpin .7s linear infinite;
}
@keyframes srSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .sr-spinner { animation: none; } }
