/* ==========================================================================
   HOLD MY BEER — DRIVER HUB
   Design tokens
   ========================================================================== */
:root {
  /* Core palette */
  --ink: #0a0b0d;
  --surface: #16181c;
  --surface-raised: #1d2024;
  --border: #2a2d33;
  --teal: #00d6c9;
  --teal-dim: #00d6c933;
  --mist: #9ba0a8;
  --paper: #f5f6f7;

  /* Semantic (used only on deltas / status, never on identity or position) */
  --green: #3dd68c;
  --green-dim: #3dd68c22;
  --red: #e8615d;
  --red-dim: #e8615d22;
  --purple: #a78bfa;
  --purple-dim: #a78bfa22;
  --gold: #f2c94c;
  --gold-dim: #f2c94c22;

  /* Type scale */
  --fs-display: 2.75rem;   /* big position numbers */
  --fs-h1: 1.375rem;
  --fs-h2: 1.125rem;
  --fs-body: 1rem;
  --fs-small: 0.875rem;
  --fs-eyebrow: 0.6875rem;

  /* Spacing scale */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;

  --radius: 14px;
  --radius-sm: 10px;
  --tap-min: 44px;
  --content-max: 720px;

  --font-stack: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
    Roboto, Helvetica, Arial, sans-serif;
}

/* ==========================================================================
   Reset / base
   ========================================================================== */
* {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

html,
body {
  margin: 0;
  padding: 0;
  overflow-x: hidden;
  width: 100%;
  background: var(--ink);
}

body {
  font-family: var(--font-stack);
  color: var(--paper);
  font-size: var(--fs-body);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  padding-bottom: env(safe-area-inset-bottom, 0);
}

img,
svg {
  max-width: 100%;
  display: block;
}

button {
  font-family: inherit;
  color: inherit;
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration: none;
}

.tabular {
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* ==========================================================================
   App shell
   ========================================================================== */
#app {
  min-height: 100vh;
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  position: relative;
}

.screen {
  width: 100%;
  padding: 0 var(--sp-4) var(--sp-7);
  animation: fadein 180ms ease-out;
}

.screen[hidden] {
  display: none;
}

@keyframes fadein {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ==========================================================================
   Top bar
   ========================================================================== */
.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  /* Reserves the unsafe area (status bar / Dynamic Island / notch) as
     real padding rather than letting content sit under it — the dark
     background+blur still extends up under that area (so there's no
     visible gap/seam), but every tappable control sits below it. */
  padding-top: env(safe-area-inset-top, 0px);
  background: rgba(10, 11, 13, 0.86);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  max-width: var(--content-max);
  margin: 0 auto;
}

.topbar-row {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 56px;
  padding: 0 var(--sp-4);
}

.topbar-left {
  display: flex;
  align-items: center;
  gap: 2px;
  position: relative;
  z-index: 1;
}

.topbar-btn {
  width: var(--tap-min);
  height: var(--tap-min);
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--paper);
  flex-shrink: 0;
}

.topbar-btn svg {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  color: var(--paper);
}

.topbar-btn:active {
  background: var(--surface);
}

.topbar-title {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-size: var(--fs-h2);
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  pointer-events: none;
  /* v0.5.3 §1: ROOT CAUSE (measured with a real headless-Chromium render at
     320/375/390/393/430px, not guessed) — this box has no explicit width,
     so the browser uses shrink-to-fit sizing for it. With overflow:hidden
     set (needed for the old ellipsis fallback) PLUS min-width:0 on the
     nested flex item down in .topbar-title-brand/.tt-text (added in
     v0.5.2 specifically to let the old clamp() shrink work), Chromium's
     shrink-to-fit preferred-width calculation for THIS box collapsed to
     something well under the text's actual single-line width — e.g. on a
     375px screen "Hold My Beer Challenges" measured a 216px natural width
     but this box was only computing itself at 200px, ~16px short, with
     nothing beyond that box catching the overflow. That's what was
     clipping — not insufficient physical screen width. On every width
     tested (320–430px) the real content only ever needed 200–240px
     against 300–400px of available room, so the fix is to stop asking
     the browser to guess this box's width at all: `width: max-content`
     makes it exactly as wide as its content needs, full stop, with
     max-width kept only as a generous hard ceiling real content never
     actually reaches. No text shrinking, no ellipsis, no wrap — confirmed
     scrollWidth === clientWidth (zero overflow) for all four branded
     headings at all five widths tested. */
  width: max-content;
  max-width: calc(100% - 16px);
  overflow: visible;
}

/* Wordmark: "HOLD MY" stacked over "BEER" with the beer-glass mark */
.wordmark {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.wordmark svg {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}

.wordmark-text {
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: 0.01em;
  line-height: 1;
}

.wordmark-text .accent {
  color: var(--teal);
}

/* Brand mark (§1) — one real artwork file (assets/branding/beer-mug.png),
   sized per context via these classes. Height-only sizing (width:auto)
   preserves the source aspect ratio instead of squashing it. */
.beer-mark {
  display: inline-block;
  width: auto;
  object-fit: contain;
  flex-shrink: 0;
  vertical-align: middle;
}
.beer-mark-xs { height: 18px; }
.beer-mark-sm { height: 22px; }
.beer-mark-md { height: 30px; }
.beer-mark-lg { height: 72px; }
/* Hub UX pass (post-2J) Part C: larger brand mark for the global masthead,
   vertically centred against the combined two-line title block (see
   .masthead below) rather than sitting inline with just the top line. */
.beer-mark-header { height: 40px; }

/* v0.7.12 §1: .topbar-title-brand (the old small inline beer-mark-xs +
   text treatment used only on Challenges/My HMB/Standings/Stats) is
   removed here — screenTitleHTML() no longer emits it now that those
   four screens (plus More) share the .masthead treatment below instead. */

/* Masthead (v0.7.12 §1; restructured Hub UX pass post-2J §C) — the ONE
   reusable "🍺 HOLD MY BEER / PAGE" header shared across all five root
   bottom-nav screens, living in the sticky topbar instead of the screen
   body. The brand mark sits to the LEFT, vertically centred against the
   full two-line text block (brand line + page subtitle stacked directly
   beneath it) rather than only alongside the brand line — a single
   change here updates every page since every root screen calls the same
   mastheadTopbarHTML(). */
.masthead-row {
  flex-direction: column;
  justify-content: center;
  align-items: center;
  min-height: 0;
  padding-top: var(--sp-2);
  padding-bottom: var(--sp-2);
}
.masthead {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
}
.masthead-text {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}
.masthead-brand-text {
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: 0.01em;
  line-height: 1;
  color: var(--paper);
}
.masthead-brand-text .accent {
  color: var(--teal);
}
.masthead-page {
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--mist);
  line-height: 1;
  text-transform: uppercase;
  text-align: center;
}

/* ==========================================================================
   Bottom navigation (replaces the old hamburger drawer)
   ========================================================================== */
.bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 45;
  display: flex;
  background: rgba(10, 11, 13, 0.92);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  max-width: var(--content-max);
  margin: 0 auto;
  /* iOS Safari bug fix (§18): position:fixed elements that also use
     backdrop-filter can lose their fixed layer during momentum/rubber-band
     scrolling — WebKit occasionally fails to keep the compositor layer
     pinned to the viewport and the bar visibly rides up with the content
     until something forces a repaint (exactly Anthony's "scrolled up,
     fixed again after reopening" report). Forcing this element onto its
     own stable GPU compositing layer up front — rather than letting
     scroll/backdrop-filter recomposite it on the fly — is the standard,
     documented workaround. Do not remove the transform/will-change pair;
     removing either re-exposes the bug. */
  transform: translateZ(0);
  -webkit-transform: translateZ(0);
  will-change: transform;
}
.bottom-nav-tab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-height: 56px;
  background: none;
  border: none;
  color: var(--mist);
  font-size: 0.64rem;
  font-weight: 700;
  padding: 6px 2px;
}
.bottom-nav-tab svg {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  color: var(--mist);
}
.bottom-nav-tab.active,
.bottom-nav-tab.active svg {
  color: var(--teal);
}
.bottom-nav-tab:active { background: var(--surface); }

/* Reserve space so page content never sits under the fixed bottom nav */
#app {
  padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
}

/* ==========================================================================
   Menu screen (bottom-nav tab 5) — a normal scrollable page, not a drawer
   ========================================================================== */
.menu-screen-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}
/* §19: primary destinations (Round Highlights, Handicap) — roughly double
   the visual weight of a normal secondary row, side by side, with the
   secondary list starting a clear gap below (margin handled at the call
   site via .section-style spacing on the following list). */
.menu-primary-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
}
.menu-primary-tile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 104px;
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-align: left;
  position: relative;
}
.menu-primary-tile:active { background: var(--surface-raised); }
.menu-primary-tile svg { width: 26px; height: 26px; color: var(--teal); }
.menu-primary-tile-label {
  font-size: 1.05rem;
  font-weight: 800;
  line-height: 1.2;
}
.menu-primary-tile .beta-badge { position: absolute; top: var(--sp-3); right: var(--sp-3); margin-left: 0; }

.menu-screen-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: 52px;
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--paper);
  text-align: left;
}
.menu-screen-item:active { background: var(--surface-raised); }
.menu-screen-item svg {
  width: 20px;
  height: 20px;
  color: var(--mist);
  flex-shrink: 0;
}
.menu-screen-item-label { flex: 1; }
.menu-screen-item-chevron {
  color: var(--mist);
  font-size: 1.1rem;
  font-weight: 700;
}

/* ==========================================================================
   Freshness bar
   ========================================================================== */
.freshness {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  margin-top: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-small);
  color: var(--mist);
}

.freshness-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--teal);
  flex-shrink: 0;
}

.freshness.updating .freshness-dot {
  background: var(--mist);
  animation: pulse 1.1s ease-in-out infinite;
}

.freshness.delayed .freshness-dot {
  background: var(--gold);
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}

.freshness strong {
  color: var(--paper);
  font-weight: 600;
}

/* ==========================================================================
   Round status pill
   ========================================================================== */
.round-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: var(--sp-4);
}

/* §5: "2026 SEASON" (small, muted) stacked over "Round 1" (still the
   visually dominant line) — calendar-year season label only, no separate
   scoring system implied. */
.round-season-line {
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mist);
  margin-bottom: 1px;
}
.round-label {
  font-size: 1.75rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.08;
  margin-top: 1px;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--teal-dim);
  color: var(--teal);
}

.status-pill.archived {
  background: var(--surface-raised);
  color: var(--mist);
}

/* Round countdown (v0.7.12 §2) — same pill shape/size as the existing
   status pill (it sits right next to it), just its own two colour
   treatments. Deliberately calm/neutral for the everyday "N DAYS TO GO"
   case; FINAL HOURS borrows the app's existing warning/gold tone so it
   reads as more urgent without introducing a brand-new colour. */
.status-pill.days-to-go {
  background: var(--surface-raised);
  color: var(--paper);
  margin-left: 6px;
}
.status-pill.final-hours {
  background: var(--gold-dim);
  color: var(--gold);
  margin-left: 6px;
}

.status-pill .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.round-dates {
  font-size: var(--fs-small);
  color: var(--mist);
  margin-top: 2px;
}

/* ==========================================================================
   Section headers / eyebrows
   ========================================================================== */
.eyebrow {
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mist);
  margin: 0 0 var(--sp-2);
}

.section {
  margin-top: var(--sp-6);
}

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--sp-3);
}

.section-head h2 {
  font-size: var(--fs-h1);
  font-weight: 800;
  margin: 0;
  letter-spacing: -0.01em;
}

.view-all {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--teal);
  background: none;
  border: none;
  padding: var(--sp-1) 0;
  min-height: var(--tap-min);
  display: flex;
  align-items: center;
}

/* ==========================================================================
   Cards — generic
   ========================================================================== */
.card {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-4);
}

/* ==========================================================================
   MY HOLD MY BEER — identity + standing card
   ========================================================================== */
.me-card {
  margin-top: var(--sp-4);
  background: linear-gradient(160deg, var(--surface) 0%, var(--surface-raised) 100%);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-4);
}

.me-identity {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.avatar {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--surface-raised);
  border: 1.5px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
}

.avatar.sm {
  width: 28px;
  height: 28px;
}

.avatar img,
.avatar svg {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.avatar-initials {
  font-weight: 800;
  font-size: 1.1rem;
  color: var(--teal);
}

.avatar.sm .avatar-initials {
  font-size: 0.8rem;
}

/* Fallback shown in place of a helmet <img> that fails to load (bad path,
   flaky network, etc.) — see handleHelmetImgError in icons.js. .sm sits
   inside the existing .avatar circle (same treatment as .avatar-initials
   above); .lg needs its own box since the My Driver picker stage isn't a
   circle. */
.helmet-illustration-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  color: var(--teal);
  width: 100%;
  height: 100%;
}
.helmet-illustration-fallback.sm {
  font-size: 0.8rem;
}
.helmet-illustration-fallback.lg {
  aspect-ratio: 4 / 3;
  max-width: 260px;
  margin: 0 auto;
  background: var(--surface-raised);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  font-size: 2rem;
}

.me-name-block {
  min-width: 0;
  flex: 1;
}

.me-name {
  font-size: var(--fs-h2);
  font-weight: 800;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.me-subline {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-small);
  color: var(--mist);
  margin-top: 2px;
}

.flag {
  font-size: 1rem;
  line-height: 1;
}

.me-standings {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
}

.standing-block {
  min-width: 0;
  background: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  text-align: center;
}

.standing-block .eyebrow {
  margin-bottom: var(--sp-1);
}

.standing-block.handicap {
  border-color: var(--purple-dim);
}

.standing-pos {
  font-size: var(--fs-display);
  font-weight: 800;
  line-height: 1;
  color: var(--paper);
}

.standing-block .standing-pos {
  color: var(--teal);
}

.standing-block.handicap .standing-pos {
  color: var(--purple);
}

.standing-pts {
  font-size: var(--fs-small);
  color: var(--mist);
  margin-top: var(--sp-1);
}

.me-stats-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

.mini-stat {
  min-width: 0;
  text-align: center;
  padding: var(--sp-2) 4px;
}

.mini-stat-value {
  font-size: 1.15rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.mini-stat-label {
  font-size: 0.6875rem;
  color: var(--mist);
  margin-top: 2px;
}

/* ==========================================================================
   Signature element — the Gap Bar
   Used on: Home "Your Next Target", Challenge Detail "Compare To"
   Visualises the gap-to-catch as a shrinking physical distance rather than
   just a number, so a driver feels how close they are, not just reads it.
   ========================================================================== */
.gap-card {
  margin-top: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--teal-dim);
  border-radius: var(--radius);
  padding: var(--sp-4);
  box-shadow: 0 0 0 1px transparent, 0 8px 24px -12px var(--teal-dim);
}

.gap-card .eyebrow {
  color: var(--teal);
}

.gap-copy {
  font-size: var(--fs-body);
  line-height: 1.5;
  margin: 0 0 var(--sp-3);
}

.gap-copy strong {
  color: var(--paper);
}

.gap-bar-track {
  position: relative;
  height: 6px;
  background: var(--border);
  border-radius: 999px;
  margin: var(--sp-4) 0 var(--sp-2);
  overflow: visible;
}

.gap-bar-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--teal), var(--green));
  transition: width 500ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.gap-bar-dot {
  position: absolute;
  top: 50%;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--paper);
  border: 3px solid var(--teal);
  transform: translate(-50%, -50%);
  transition: left 500ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.gap-bar-labels {
  display: flex;
  justify-content: space-between;
  font-size: var(--fs-eyebrow);
  color: var(--mist);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.gap-amount {
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--teal);
  margin-top: var(--sp-3);
}

.gap-amount.tied {
  color: var(--gold);
}

.gap-amount .unit {
  font-size: 1rem;
  font-weight: 600;
  color: var(--mist);
  margin-left: 4px;
}

/* ==========================================================================
   Highlights strip (Home preview)
   ========================================================================== */
.highlight-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}

.highlight-tile {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  text-align: left;
  width: 100%;
  color: inherit;
  font: inherit;
  position: relative;
}
.highlight-tile.tappable { padding-right: 26px; }
.highlight-tile.tappable::after {
  content: "\203a";
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--mist);
  font-size: 1.1rem;
  font-weight: 700;
}
.highlight-tile.tappable:active { background: var(--surface-raised); }

.highlight-tile .eyebrow {
  margin-bottom: 6px;
}

.highlight-value {
  font-size: 1.35rem;
  font-weight: 800;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.highlight-value.gold {
  color: var(--gold);
}

.highlight-value.purple {
  color: var(--purple);
}

/* ==========================================================================
   Challenge cards (compact — Home + Challenges screen)
   ========================================================================== */
.challenge-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}

/* v0.5.3 (found during §2 investigation): this was named .challenge-card
   until now, but that name collided with the unrelated Challenge Card
   image-frame component added in v0.5.2 (both are legitimately named
   from their own component's perspective, but CSS classes are global) \u2014
   the newer rule's aspect-ratio/gradient were bleeding into this compact
   My Hold My Beer list card, visibly denting it. Renamed to keep the
   Challenge Tile / Challenge Card terminology unambiguous at the CSS
   level too, not just in prose \u2014 this component is otherwise unchanged. */
.my-challenge-card {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-4);
  position: relative;
  overflow: hidden;
}

.my-challenge-card:active {
  background: var(--surface-raised);
}

.challenge-track-motif {
  position: absolute;
  right: -18px;
  top: -18px;
  width: 110px;
  height: 110px;
  opacity: 0.35;
  color: var(--teal);
  pointer-events: none;
}

.challenge-track-motif svg {
  width: 100%;
  height: 100%;
}

.challenge-top {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--sp-2);
  position: relative;
}

.challenge-top > *:last-child {
  margin-left: auto;
}

.challenge-id {
  font-size: var(--fs-eyebrow);
  font-weight: 800;
  letter-spacing: 0.06em;
  color: var(--teal);
  background: var(--teal-dim);
  padding: 3px 8px;
  border-radius: 6px;
}

.challenge-position {
  font-size: 1.5rem;
  font-weight: 800;
}

.challenge-names {
  margin-top: var(--sp-2);
  position: relative;
}

.challenge-track {
  font-weight: 700;
  font-size: 1.02rem;
}

.challenge-car {
  font-size: 0.88rem;
  color: var(--mist);
  margin-top: 2px;
}

.revealable {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.text-reveal-toast {
  position: fixed;
  left: 50%;
  bottom: calc(64px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  max-width: calc(100% - 32px);
  z-index: 60;
  background: var(--surface-raised);
  border: 1px solid var(--teal);
  color: var(--paper);
  font-size: 0.85rem;
  font-weight: 600;
  padding: 10px 16px;
  border-radius: 999px;
  box-shadow: 0 8px 24px -8px rgba(0, 0, 0, 0.6);
  text-align: center;
}
.text-reveal-toast[hidden] { display: none; }

.challenge-foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  margin-top: var(--sp-3);
  position: relative;
}

.challenge-pb {
  font-size: var(--fs-small);
  color: var(--mist);
}

.challenge-pb strong {
  color: var(--paper);
  font-weight: 700;
  font-size: var(--fs-body);
}

.challenge-target {
  font-size: var(--fs-small);
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 6px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.challenge-target.behind {
  color: var(--red);
  background: var(--red-dim);
}

.challenge-target.ahead {
  color: var(--green);
  background: var(--green-dim);
}

.challenge-target.leader {
  color: var(--gold);
  background: var(--gold-dim);
}

/* Hub UX pass (post-2J, follow-up) §7 — Challenge Awards 3-driver gate.
   Subtle, restrained — the Challenge page must not feel busy while
   waiting for the comparison pool to fill. */
.challenge-awards-locked {
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  text-align: center;
}
.cal-title {
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--paper);
  margin: 0;
}
.cal-progress {
  font-size: var(--fs-eyebrow);
  color: var(--mist);
  margin: 4px 0 0;
}

.challenge-empty {
  font-size: var(--fs-small);
  color: var(--mist);
  margin-top: var(--sp-2);
  font-style: normal;
}

/* Part K (Hub UX pass, post-2J): compact qualification-progress nudge —
   deliberately understated (small, teal accent, no border/background)
   since it's an encouragement, not a warning. */
.award-qualification-line {
  font-size: var(--fs-eyebrow);
  color: var(--teal);
  margin-top: 4px;
}

/* ==========================================================================
   Standings screen
   ========================================================================== */
.segmented {
  display: flex;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 3px;
  margin-top: var(--sp-3);
}

.segmented button {
  flex: 1;
  min-height: 38px;
  background: none;
  border: none;
  border-radius: 8px;
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--mist);
}

.segmented button.active {
  background: var(--teal);
  color: var(--ink);
}

.segmented button.active.handicap-active {
  background: var(--purple);
  color: var(--ink);
}

.standings-list {
  margin-top: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.standing-row {
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  color: inherit;
  margin: 0;
  cursor: pointer;
  display: grid;
  grid-template-columns: 34px 1fr auto 46px;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.standing-row.leader {
  border-color: var(--gold);
  box-shadow: inset 3px 0 0 var(--gold);
}

.standing-row.me {
  background: var(--teal-dim);
  border-color: var(--teal);
}

.standing-row-pos {
  font-weight: 800;
  font-size: var(--fs-body);
  text-align: center;
}

.standing-row-pos .t {
  color: var(--mist);
  font-weight: 600;
  font-size: 0.8em;
}

.standing-row-driver {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.standing-row-name {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Part E (Hub UX pass, post-2J): the shared "Name #NN" identity
   treatment — subdued, smaller, lighter weight, clearly secondary to
   the driver's name. One rule, applied everywhere driverIdentityHTML()
   is used (ladders, award recipients, History ladders/awards, the
   Handicap Leader highlight tile). */
.driver-race-number {
  font-weight: 400;
  font-size: 0.85em;
  color: var(--mist);
  margin-left: 5px;
}

.standing-row-pts {
  font-weight: 700;
  text-align: right;
}

.standing-row-behind {
  font-size: var(--fs-small);
  color: var(--mist);
  text-align: right;
  min-width: 0;
}

.show-all-btn {
  width: 100%;
  min-height: var(--tap-min);
  margin-top: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--paper);
}

.standings-note {
  font-size: var(--fs-small);
  color: var(--mist);
  margin-top: var(--sp-3);
  line-height: 1.5;
}

/* v0.7.0 §5: link from Standings → Handicap straight to the More →
   Handicap explainer page. Back navigation returns here automatically —
   it's pushed via the normal navigate()/history stack, same as every
   other in-app link, nothing bespoke needed for the return trip. */
/* v0.7.1 §10: explicit reset here — the shared `button` rule (near the
   top of this file) only sets font-family/color/cursor, so without this
   a <button> falls back to the browser's default white/grey button
   chrome (background, border, padding) instead of just teal text. That
   default chrome is exactly what made this look like a solid white
   pill before. */
.standings-handicap-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: var(--sp-2);
  padding: 0;
  background: none;
  border: none;
  box-shadow: none;
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--teal);
}
.standings-handicap-link:active { opacity: 0.7; }

/* ==========================================================================
   Challenge Detail
   ========================================================================== */
.detail-hero {
  margin-top: var(--sp-3);
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  position: relative;
  overflow: hidden;
}
.detail-hero.compact {
  padding: var(--sp-3) var(--sp-4);
  /* v0.5.2 §9/§10: two-column layout replacing the removed squiggle motif
     — identity on the left, Your Position using that freed space on the
     right (only rendered when the selected driver has a result). */
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
}
.detail-hero.compact .detail-hero-track {
  font-size: 1.1rem;
}
.detail-hero-left { min-width: 0; }
.detail-hero-right {
  flex-shrink: 0;
  text-align: right;
}
.detail-hero-position {
  font-size: 1.4rem;
  font-weight: 800;
  margin-top: 2px;
}

.detail-hero-id {
  font-size: var(--fs-eyebrow);
  font-weight: 800;
  letter-spacing: 0.06em;
  color: var(--teal);
}

.detail-hero-track {
  font-size: 1.4rem;
  font-weight: 800;
  margin-top: var(--sp-1);
  position: relative;
}

.detail-hero-car {
  font-size: var(--fs-body);
  color: var(--mist);
  margin-top: 2px;
  position: relative;
}

.about-toggle {
  margin-top: var(--sp-3);
  background: none;
  border: none;
  color: var(--teal);
  font-weight: 700;
  font-size: var(--fs-small);
  min-height: var(--tap-min);
  display: flex;
  align-items: center;
  gap: 6px;
  position: relative;
}

.about-body {
  font-size: var(--fs-small);
  color: var(--mist);
  line-height: 1.6;
  padding-bottom: var(--sp-2);
}

.perf-card {
  margin-top: var(--sp-5);
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.perf-top {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.perf-pos {
  font-size: var(--fs-display);
  font-weight: 800;
  color: var(--teal);
  line-height: 1;
}

.perf-lap {
  font-size: 1.05rem;
  font-weight: 700;
  margin-top: 2px;
}

.perf-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}

/* Compare To card reuses .gap-card styles from the signature element,
   with a driver-vs-driver row above the bar */
.compare-select {
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
  margin-bottom: var(--sp-4);
  overflow-x: auto;
  scrollbar-width: none;
}

.compare-select::-webkit-scrollbar {
  display: none;
}

.compare-chip {
  flex-shrink: 0;
  padding: 6px 12px;
  min-height: 36px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--ink);
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--mist);
}

.compare-chip.active {
  background: var(--teal);
  border-color: var(--teal);
  color: var(--ink);
}

.compare-vs {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-3);
}

.compare-side {
  min-width: 0;
  text-align: center;
}

.compare-side .who {
  font-size: var(--fs-small);
  color: var(--mist);
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.compare-side .lap {
  font-size: 1.15rem;
  font-weight: 800;
  margin-top: 2px;
}

.compare-side .pos {
  font-size: var(--fs-small);
  color: var(--mist);
  margin-top: 1px;
}

.compare-vs-divider {
  font-size: var(--fs-eyebrow);
  color: var(--mist);
  font-weight: 700;
}

.sector-grid {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

.sector-row {
  display: grid;
  grid-template-columns: 40px 1fr auto;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  background: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.sector-label {
  font-weight: 800;
  color: var(--mist);
  font-size: var(--fs-small);
}

.sector-bar-track {
  height: 6px;
  background: var(--surface-raised);
  border-radius: 999px;
  overflow: hidden;
}

.sector-bar-fill {
  height: 100%;
  border-radius: 999px;
}

.sector-delta {
  font-weight: 700;
  font-size: var(--fs-small);
  min-width: 62px;
  text-align: right;
}

.sector-delta.behind {
  color: var(--red);
}

.sector-delta.ahead {
  color: var(--green);
}

.accordion {
  margin-top: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.accordion-head {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border: none;
  min-height: var(--tap-min);
  font-weight: 700;
  font-size: var(--fs-body);
}

/* Safety net: any reused icon carrying the .chev class gets a fixed size
   wherever it appears (accordion headers, the About-Challenge toggle),
   so it never falls back to the browser's oversized default SVG box. */
.chev {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  transition: transform 180ms ease;
  color: var(--mist);
}

.accordion-head .chev {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  transition: transform 180ms ease;
  color: var(--mist);
}

.accordion.open .accordion-head .chev {
  transform: rotate(180deg);
}

.accordion-body {
  padding: 0 var(--sp-4) var(--sp-4);
  background: var(--surface);
  border-top: 1px solid var(--border);
}

.accordion-body[hidden] {
  display: none;
}

/* Part K (Hub UX pass, post-2J) — Round-level qualification breakdown.
   Reuses .accordion/.accordion-head/.accordion-body wholesale (the
   .hc-round-progress head still gets the standard chevron-rotation
   treatment via .accordion.open, since .hc-round-progress-arrow is
   given the same rotate transition here). */
.round-qualification-accordion .hc-round-progress {
  margin-bottom: 0;
  border: none;
  border-radius: 0;
}
.round-qualification-accordion .hc-round-progress-arrow {
  transition: transform 180ms ease;
  display: inline-block;
}
.round-qualification-accordion.open .hc-round-progress-arrow {
  transform: rotate(90deg);
}
.round-qualification-caption {
  color: var(--mist);
  font-size: var(--fs-eyebrow);
  margin: 0 0 var(--sp-2);
}
.round-qualification-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 0;
  font-size: var(--fs-small);
  border-top: 1px solid var(--border);
}
.round-qualification-row:first-of-type { border-top: none; }
.round-qualification-row .qualified {
  color: var(--green);
  font-weight: 600;
}

/* ==========================================================================
   Highlights screen
   ========================================================================== */
.hl-hero-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}

.hl-hero-tile {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-4);
}

.hl-hero-tile .eyebrow {
  margin-bottom: var(--sp-2);
}

.hl-hero-name {
  font-size: 1.15rem;
  font-weight: 800;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.battle-card {
  margin-top: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--gold);
  border-radius: var(--radius);
  padding: var(--sp-4);
}

.battle-card .eyebrow {
  color: var(--gold);
}

.ch-leader-list {
  margin-top: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.ch-leader-row {
  display: grid;
  grid-template-columns: 44px 1fr auto;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
/* v0.7.5 \u00a74: Challenge Detail Top 5 specifically (not the award-ranking
   lists that also use .ch-leader-row, which can show up to "P50" and need
   the wider default column) \u2014 tightens the gap between the position and
   the helmet+name group, matching the same fix applied to the Challenge
   card's mini-top5-row. */
.ch-leader-row.top5 {
  grid-template-columns: 22px 1fr auto;
  gap: var(--sp-2);
}

.ch-leader-row .id {
  font-weight: 800;
  color: var(--teal);
  font-size: var(--fs-small);
}

.ch-leader-row .name {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Helmet + name pairing inside the "name" grid cell, mirroring the same
   avatar+name treatment already used in Standings (.standing-row-driver) */
.ch-leader-driver {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.ch-leader-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* .ch-leader-row is now a <button> (was a <div>) so these rows can be
   tapped through to that driver's read-only profile, same as Standings \u2014
   reset default button chrome so it still looks exactly like a plain row. */
button.ch-leader-row {
  width: 100%;
  text-align: left;
  cursor: pointer;
  font: inherit;
}
button.ch-leader-row:active { opacity: 0.7; }

.ch-leader-row .lap {
  font-size: var(--fs-small);
  color: var(--mist);
  font-weight: 600;
}

/* v0.6.0: Challenge Award ladder \u2014 ineligible entries (e.g. Squeaky Clean
   under the minimum-attempts threshold) are visually de-emphasised and
   never carry a position number. */
.ch-leader-row.not-eligible {
  opacity: 0.55;
}
.ch-leader-row.not-eligible .id {
  color: var(--mist);
}
.ch-leader-row.not-eligible .lap {
  color: var(--red);
}

/* ==========================================================================
   History
   ========================================================================== */
.round-card {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-4);
  padding-right: calc(var(--sp-4) + 18px);
  margin-top: var(--sp-3);
  position: relative;
}

/* v0.7.0 §11: makes it visually obvious the whole card is tappable,
   without redesigning the card itself. */
.round-card-chevron {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-4);
  color: var(--mist);
  font-size: 1.2rem;
  font-weight: 700;
  line-height: 1;
}

.round-card-label {
  font-weight: 800;
  font-size: var(--fs-h2);
}

.round-card-dates {
  font-size: var(--fs-small);
  color: var(--mist);
  margin-top: 2px;
}

.round-card-winners {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}

.round-card-winners > div {
  min-width: 0;
}

.round-card-winners .eyebrow {
  margin-bottom: 4px;
}

.round-card-winner-name {
  font-weight: 700;
  font-size: var(--fs-small);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.round-card-foot {
  display: flex;
  gap: var(--sp-4);
  margin-top: var(--sp-3);
  font-size: var(--fs-small);
  color: var(--mist);
}

.archived-banner {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--mist);
  font-size: var(--fs-small);
  font-weight: 600;
  margin-top: var(--sp-3);
}

/* Hub UX pass (post-2J follow-up) §16 — History Round Detail jump-nav.
   Compact, 3 buttons, scrolls the page to the matching section
   (bindHistoryDetail in app.js). Sticky-on-mobile, positioned exactly
   below .topbar's REAL measured height (its device-dependent height —
   env(safe-area-inset-top) + content — is read live via
   getBoundingClientRect() in bindHistoryDetail(), never guessed as a
   fixed pixel value here). */
.history-jumpnav {
  display: flex;
  gap: var(--sp-2);
  margin: var(--sp-3) 0;
  position: sticky;
  /* top is set inline by bindHistoryDetail() in app.js, measured live
     from the actual .topbar height (varies by device/safe-area) rather
     than guessed here. */
  top: 0;
  z-index: 30; /* below .topbar's z-index:40, above ordinary content */
  background: var(--ink);
  padding-top: 2px;
  padding-bottom: 2px;
}
.history-jumpnav button {
  flex: 1;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-1);
  color: var(--paper);
  font-size: var(--fs-small);
  font-weight: 600;
  text-align: center;
}
.history-jumpnav button:active { background: var(--surface-raised); }

.archived-banner .icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* Phase 2H §Part A: the Beer Trophy slot — an empty, ready-for-artwork
   element that sits to the LEFT of every Round Award tile's name/icon.
   Challenge Award tiles (challengeAwardsHTML in app.js) never get this
   modifier class, so they render completely unchanged. Deliberately no
   background image / emoji placeholder here (prompt: "Do not generate
   fake artwork" — only prepare the location/contract) — a future
   transparent PNG drops into this exact slot via a single background-
   image rule with no markup change required. */
.award-card--round {
  position: relative;
  padding-top: calc(var(--sp-4) + 14px);
}
.round-award-trophy-slot {
  position: absolute;
  top: var(--sp-2);
  left: var(--sp-2);
  width: 18px;
  height: 18px;
  /* intentionally empty — no background/content until real artwork
     is supplied; the reserved space is the whole point of this slot */
}

/* Phase 2H §Part C: compact archived Challenge card for Round History
   Detail — deliberately NOT the full live challenge-tile (no hero
   image, no mini-top5, no sector grid). Alien benchmark renders as
   clearly SECONDARY text under the Scratch leader line, never as a
   headline value. */
.history-challenge-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
}
.history-challenge-card-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.history-challenge-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--border);
  font-size: var(--fs-small);
}
.history-benchmark-secondary {
  color: var(--mist);
  font-size: 0.72rem;
}

/* ==========================================================================
   Rules
   ========================================================================== */
.rule-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.rule-list li {
  display: flex;
  gap: var(--sp-2);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.rule-list li:last-child {
  border-bottom: none;
}

.rule-list .bullet {
  color: var(--teal);
  flex-shrink: 0;
}

/* ==========================================================================
   Driver picker (first-run + view-as)
   ========================================================================== */
.picker-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}

/* v0.7.0 §8: search box for the Country picker — reuses the same
   .picker-list/.picker-row pattern below it, just adds a text input on
   top so the list is filterable. */
.country-search-input {
  display: block;
  width: 100%;
  min-height: var(--tap-min);
  margin-top: var(--sp-4);
  padding: 0 var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--paper);
  font-size: var(--fs-body);
  font-family: inherit;
}
.country-search-input::placeholder {
  color: var(--mist);
}
.country-search-input:focus {
  outline: none;
  border-color: var(--teal);
}

.picker-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  text-align: left;
}

/* v0.7.1 §2: name-search first-time driver selection — generously
   spaced result rows (bigger tap target + more gap between rows) so a
   fat-finger tap can't land on the wrong driver. */
.picker-list.roomy {
  gap: var(--sp-3);
}
.picker-row.roomy {
  padding: var(--sp-4) var(--sp-4);
  min-height: 60px;
}
.picker-row.roomy .name {
  font-size: 1.05rem;
  font-weight: 800;
}

.picker-row:active {
  background: var(--surface-raised);
}

.picker-row .name {
  font-weight: 700;
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.back-to-me-bar {
  position: sticky;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  background: var(--surface-raised);
  border: 1px solid var(--teal);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  margin-top: var(--sp-4);
}

.back-to-me-bar span {
  font-size: var(--fs-small);
  font-weight: 600;
}

.back-to-me-btn {
  background: var(--teal);
  color: var(--ink);
  border: none;
  border-radius: 8px;
  font-weight: 800;
  font-size: var(--fs-small);
  padding: var(--sp-2) var(--sp-3);
  min-height: 36px;
}

/* ==========================================================================
   Empty / loading / error states
   ========================================================================== */
.empty-state {
  text-align: center;
  padding: var(--sp-6) var(--sp-4);
  color: var(--mist);
}

.empty-state svg {
  width: 40px;
  height: 40px;
  margin: 0 auto var(--sp-3);
  color: var(--border);
}

.empty-state p {
  font-size: var(--fs-small);
  margin: 0;
  line-height: 1.5;
}

.skeleton {
  background: linear-gradient(
    100deg,
    var(--surface) 30%,
    var(--surface-raised) 50%,
    var(--surface) 70%
  );
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
  border-radius: var(--radius-sm);
}

@keyframes shimmer {
  0% {
    background-position: 200% 0;
  }
  100% {
    background-position: -200% 0;
  }
}

.load-screen {
  min-height: 60vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
  padding: var(--sp-5);
}

.load-screen .wordmark svg {
  width: 40px;
  height: 40px;
}

.load-screen p {
  color: var(--mist);
  font-size: var(--fs-small);
}

.error-screen {
  min-height: 60vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--sp-3);
  padding: var(--sp-5);
}

.error-screen svg {
  width: 36px;
  height: 36px;
  color: var(--gold);
}

.error-screen h2 {
  font-size: var(--fs-h1);
  margin: 0;
}

.error-screen p {
  color: var(--mist);
  font-size: var(--fs-small);
  max-width: 32ch;
  line-height: 1.5;
}

.retry-btn {
  margin-top: var(--sp-2);
  background: var(--teal);
  color: var(--ink);
  border: none;
  border-radius: var(--radius-sm);
  font-weight: 800;
  font-size: var(--fs-small);
  padding: var(--sp-3) var(--sp-5);
  min-height: var(--tap-min);
}

/* ==========================================================================
   Settings screen
   ========================================================================== */
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-top: var(--sp-3);
}

.settings-row-label {
  font-weight: 700;
}

.settings-row-sub {
  font-size: var(--fs-small);
  color: var(--mist);
  margin-top: 2px;
}

.settings-btn {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  color: var(--paper);
  font-weight: 700;
  font-size: var(--fs-small);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  min-height: 40px;
}

/* Per-screen footer removed in v0.5.1 — the single global #buildFingerprint
   element in index.html (styled inline there) now serves as the one
   "Powered by Chipperten" footer for every screen; see index.html header
   comment. */

/* ==========================================================================
   Desktop reflow (single breakpoint)
   ========================================================================== */
@media (min-width: 768px) {
  .me-stats-row {
    grid-template-columns: repeat(4, 1fr);
  }

  .highlight-grid {
    grid-template-columns: repeat(4, 1fr);
  }

  .challenge-list {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }

  .hl-hero-grid {
    grid-template-columns: repeat(4, 1fr);
  }

  .compare-vs {
    max-width: 420px;
    margin: 0 auto;
  }
}

/* ==========================================================================
   PASS 2 ADDITIONS
   ========================================================================== */

/* Compact header — round info left, freshness right */
.hmb-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: var(--sp-2);
}
.hmb-header-left { min-width: 0; }
.hmb-header-right { text-align: right; flex-shrink: 0; }
.status-pill.sm { padding: 3px 8px; margin-top: 4px; display: inline-flex; }
.freshness-compact {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-eyebrow);
  color: var(--mist);
  font-weight: 600;
}
.freshness-compact .freshness-dot { width: 6px; height: 6px; }
.freshness-compact.delayed .freshness-dot { background: var(--gold); }
.freshness-compact.updating .freshness-dot { background: var(--mist); animation: pulse 1.1s ease-in-out infinite; }
.freshness-next { font-size: 0.65rem; color: var(--mist); margin-top: 2px; }

/* Compact "Refresh latest data" control (Hub UX pass, post-2J follow-up
   §1) — lives INSIDE .hmb-header-right, directly beneath Updated/Next
   update, sized to its content (never width:100%) so it reads as part
   of the update-status area rather than a full-width banner/major
   content card. Still only ever rendered once Next Update has passed
   (see isRefreshDue()). Tasteful, not a loud CTA: teal-tinted outline
   rather than a filled button. */
.refresh-row {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  margin-top: 6px;
  padding: 5px 10px;
  background: var(--teal-dim);
  border: 1px solid var(--teal-dim);
  border-radius: var(--radius-sm);
  color: var(--teal);
  font-size: 0.7rem;
  font-weight: 700;
  min-height: 0;
}
.refresh-row .icon { width: 13px; height: 13px; flex-shrink: 0; }
.refresh-row .refresh-hint { display: none; } /* compact form has no room for the hint line */
.refresh-row.checking { color: var(--mist); opacity: 0.8; }
.refresh-row.checking .icon { animation: spin 900ms linear infinite; }
.refresh-row.noted {
  background: transparent;
  border-style: dashed;
  color: var(--mist);
  font-weight: 600;
}
.refresh-row.noted.updated { color: var(--teal); border-color: var(--teal-dim); }
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

.wordmark-sub {
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.1em;
  color: var(--mist);
  margin: 2px 0 var(--sp-5) 0;
  padding-left: 30px;
}

.beta-badge {
  display: inline-block;
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: var(--ink);
  background: var(--purple);
  padding: 1px 6px;
  border-radius: 5px;
  vertical-align: middle;
  margin-left: 4px;
}
.beta-badge.sm { font-size: 0.55rem; padding: 1px 5px; }

/* Round Snapshot strip */
.snapshot-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1.4fr;
  gap: var(--sp-2);
}
.snapshot-item {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-3);
  display: flex;
  flex-direction: column;
}
.snapshot-value {
  font-weight: 800;
  font-size: 1.2rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.snapshot-value.gold { color: var(--gold); }
.snapshot-label { font-size: 0.65rem; color: var(--mist); text-transform: uppercase; letter-spacing: 0.04em; margin-top: 2px; }

.standing-pos-ord { font-size: 1.9rem; font-weight: 800; line-height: 1; }
.standing-block .standing-pos-ord { color: var(--teal); }
.standing-block.handicap .standing-pos-ord { color: var(--purple); }

/* mini-stat icons */
.mini-stat .icon { width: 16px; height: 16px; color: var(--mist); margin: 0 auto 4px; display: block; }

/* Avatar xs (frozen table rows) */
.avatar.xs { width: 20px; height: 20px; margin-right: 6px; flex-shrink: 0; }

/* Picker compact row (desktop-safe width) */
.picker-row.compact { max-width: 420px; margin: 0 auto; }

/* Back to top */
.back-to-top {
  position: fixed;
  bottom: 20px;
  right: 16px;
  z-index: 30;
  background: var(--teal);
  color: var(--ink);
  border: none;
  border-radius: 999px;
  font-weight: 800;
  font-size: 13px;
  padding: 8px 14px;
  box-shadow: 0 8px 20px -8px rgba(0, 214, 201, 0.5);
}
.back-to-top[hidden] { display: none; }

/* v0.7.1 §8: Add to Home Screen first-arrival banner — sits fixed just
   above the bottom nav (nav min-height 56px + its own safe-area inset),
   dismissible, never modal/blocking. */
.a2hs-banner {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(56px + env(safe-area-inset-bottom, 0px) + 12px);
  z-index: 40;
  max-width: calc(var(--content-max) - 24px);
  margin: 0 auto;
  background: var(--surface-raised);
  border: 1px solid var(--teal-dim);
  border-radius: var(--radius);
  padding: var(--sp-4);
  box-shadow: 0 12px 32px -12px rgba(0, 0, 0, 0.6);
}
.a2hs-close {
  position: absolute;
  top: var(--sp-2);
  right: var(--sp-2);
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: none;
  border: none;
  color: var(--mist);
  display: flex;
  align-items: center;
  justify-content: center;
}
.a2hs-close svg { width: 16px; height: 16px; }
.a2hs-banner-title {
  font-weight: 800;
  font-size: 0.95rem;
  margin: 0 24px 4px 0;
}
.a2hs-banner-body {
  color: var(--mist);
  font-size: 0.82rem;
  line-height: 1.5;
  margin: 0 0 var(--sp-3);
}
.a2hs-banner-steps {
  color: var(--paper);
  font-size: 0.82rem;
  line-height: 1.5;
  margin: 0;
}
.a2hs-install-btn {
  width: 100%;
  min-height: var(--tap-min);
  background: var(--teal);
  color: var(--ink);
  border: none;
  border-radius: var(--radius-sm);
  font-weight: 800;
  font-size: 0.9rem;
}

/* Challenge hero card (Challenges page) — fixed visual-zone height so
   swapping artwork between rounds can never break the page layout. */
/* v0.5.2 §3: "Challenge Tile" = this whole button (artwork + all live
   data). "Challenge Card" = .challenge-card below, the pure image frame
   only \u2014 nothing app-generated renders inside it. */
.challenge-tile {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: var(--sp-4);
  position: relative;
}
.challenge-tile:active { background: var(--surface-raised); }
.challenge-tile.community-choice { border-color: var(--gold); }

/* v0.5.2 §4: poster-like landscape frame, sized by aspect-ratio (not a
   fixed pixel height) so it scales cleanly across phone widths instead
   of needing per-breakpoint tuning. At the padded content widths of
   common iPhones (~343\u2013398px) 3:2 lands right in the ~220\u2013240px range
   Anthony asked for; max-height keeps it sane on the widest supported
   layout (720px desktop content cap). See assets/challenges/README.md
   for the exact source-artwork size this implies. */
.challenge-card {
  position: relative;
  aspect-ratio: 3 / 2;
  max-height: 320px;
  background: linear-gradient(160deg, #1a2f2c 0%, #0a0b0d 70%);
  overflow: hidden;
}
.challenge-card-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: 2;
}
/* v0.5.2 §5: deliberately faint, internal-only helper \u2014 explicit z-index
   (not DOM order) keeps it UNDER the image, so a successfully-loaded
   photo covers it with no JS toggling, and an onerror-hidden broken
   image reveals it automatically too. */
.challenge-card-placeholder {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 28px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.16);
  pointer-events: none;
}

/* v0.7.1 §1: identity now gets the FULL width of the tile — number +
   car/track on one row (no more squeezed-in PB/Position column), with
   the personal-data row moved BELOW so long track/layout names never
   have to compete with it for space. */
.challenge-tile-identity {
  display: flex;
  flex-direction: column;
  padding: var(--sp-4);
  gap: var(--sp-3);
}
.cti-identity-row {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--sp-3);
}
/* Huge, bold, teal — a visual identity element, not a text label.
   Zero-padded (01/02/.../05) per spec. tabular-nums keeps two-digit
   numbers from jittering in width against each other. */
.cti-number {
  font-size: 2.75rem;
  font-weight: 800;
  color: var(--teal);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.cti-middle {
  /* min-width:0 is required here, not decorative — without it this grid
     item refuses to shrink below its content's natural min-content width
     (the same box-sizing behaviour responsible for the §1 bug above, just
     the opposite failure mode: here we WANT this column to be able to
     shrink so long track names wrap instead of forcing the whole tile
     wider than the card). */
  min-width: 0;
}
.cti-track-name {
  font-size: 1.2rem;
  font-weight: 800;
  color: var(--paper);
  line-height: 1.2;
  /* §2 track-name rule: no truncation, no forced single line — long
     names wrap naturally onto a second line and the tile (which has no
     fixed height anywhere in this component) simply grows to fit. */
  white-space: normal;
  overflow-wrap: break-word;
}
.cti-car-name {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--mist);
  margin-top: 2px;
  white-space: normal;
  overflow-wrap: break-word;
}
.cti-cc { margin-top: var(--sp-2); }
/* v0.7.1 §1: My PB / My Position, now a dedicated row below identity —
   two equal centred blocks, label centred over value. */
.cti-stats-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--border);
  padding-top: var(--sp-3);
}
.cti-stat-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.cti-stat-block .eyebrow { margin-bottom: 0; }
.cti-stat-val {
  font-size: 1.05rem;
  font-weight: 800;
  margin: 2px 0 0;
}

.challenge-hero-data {
  padding: var(--sp-4);
  padding-top: 0;
}
.mini-car-used {
  font-size: 0.62rem;
  color: var(--mist);
  font-weight: 600;
}

.tap-for-more {
  margin: var(--sp-3) 0 0;
  font-size: 0.68rem;
  color: var(--mist);
  position: relative;
}
.mini-top5-row.p1 { font-weight: 700; }
.mini-top5-row.p1 span:nth-child(2) { color: var(--gold); }

/* §13/v0.5.2: fastest/leading sector values only — never a whole-table
   treatment. */
.fastest-sector { color: var(--purple) !important; font-weight: 800; }

.community-choice-badge {
  display: inline-flex;
  align-items: center;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink);
  background: linear-gradient(90deg, var(--gold), var(--teal));
  padding: 3px 8px;
  border-radius: 999px;
  height: fit-content;
}
.my-challenge-card.community-choice {
  border-color: var(--gold);
}
.mini-top5 { margin-top: 0; display: flex; flex-direction: column; gap: 4px; }
.mini-top5-row {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-small);
  padding: 4px 0;
}
.mini-top5-row span:first-child { color: var(--mist); font-weight: 700; }
.mini-top5-driver {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.mini-top5-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* v0.5.3 §4: three sectors across, driven by a real CSS grid (not flex-
   wrap) so "sector 4 sits directly under sector 1" etc. falls out of
   normal grid auto-flow for free — no JS row-breaking logic needed, and
   it's correct for any sector count (3/4/6/9/…) automatically. No fixed
   height anywhere in this block; it grows with however many rows of
   sectors exist. */
.sector-grid-3col {
  margin-top: var(--sp-3);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-3) var(--sp-2);
}
.sector-cell {
  text-align: center;
  min-width: 0;
}
.sector-cell-label {
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mist);
  margin: 0;
}
.sector-cell-time {
  font-size: 1.05rem;
  font-weight: 800;
  margin: 2px 0 0;
}
.sector-cell-name {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--paper);
  margin: 1px 0 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Challenge Detail: leader + sector kings */
.leader-card {
  background: var(--surface);
  border: 1px solid var(--gold);
  border-radius: var(--radius);
  padding: var(--sp-4);
}
.leader-row { display: flex; justify-content: space-between; align-items: baseline; margin-top: 6px; }
.leader-name { font-weight: 800; font-size: 1.1rem; }
.leader-time { color: var(--gold); font-weight: 700; }
.sector-kings-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}
.sector-king-tile {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3) var(--sp-2);
  text-align: center;
}
.sk-name { font-weight: 700; font-size: var(--fs-small); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sk-time { color: var(--mist); font-size: 0.75rem; margin-top: 2px; }

/* v0.6.0: Challenge Snapshot \u2014 3 compact participation-facts tiles.
   Deliberately smaller/lighter than .stat-card: no tap target, no
   section heading, just a quick sense of Challenge activity. */
.snapshot-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}
.snap-tile {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-2);
  text-align: center;
}
.snap-value {
  font-weight: 800;
  font-size: 1.1rem;
  margin: 2px 0 0;
  color: var(--teal);
}

/* Challenge Highlights stat cards (tappable) */
.stat-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
}
.stat-card {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  text-align: left;
  font: inherit;
  color: inherit;
}
button.stat-card { cursor: pointer; }
button.stat-card:active { background: var(--surface-raised); }
.stat-name { font-weight: 800; font-size: 1.05rem; margin-top: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat-value { color: var(--teal); font-weight: 700; font-size: 0.82rem; margin-top: 2px; }

.segmented.sm button { min-height: 32px; font-size: 0.8rem; }

/* Frozen-column horizontal data table */
.hint-swipe {
  font-size: 0.7rem;
  color: var(--mist);
  text-align: right;
  margin: var(--sp-2) 0 4px;
  transition: opacity 300ms ease;
}
.rotate-hint {
  font-size: 0.72rem;
  color: var(--mist);
  margin: var(--sp-3) 0 0;
}
@media (min-width: 700px) and (orientation: landscape) {
  .rotate-hint { display: none; }
}
.htable-wrap {
  display: flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface);
  max-width: 100%;
}
.htable-frozen {
  flex-shrink: 0;
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--surface);
  border-right: 1px solid var(--border);
}
.htable-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  flex: 1;
  min-width: 0;
}
.htable-inner { display: inline-block; min-width: 100%; }
.htable-row {
  box-sizing: border-box;
  display: grid;
  grid-auto-flow: column;
  /* v0.5.2 §16: was a flat 52px, too tight for longer header labels once
     you factor in that headers previously inherited nowrap from this
     same rule with nowhere to overflow to — "AVG OPT GAP" (and several
     others across both this table and the Challenge full-data table,
     which shares this exact CSS) would spill into the next column
     rather than wrap. Widened slightly and — see .htable-head below —
     headers now wrap onto two lines instead of overflowing. Kept as a
     single fixed value (not auto/minmax) deliberately: each .htable-row
     is its own independent CSS grid, so header and data rows only stay
     visually aligned into columns if they all use the identical fixed
     track size. */
  grid-auto-columns: 64px;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 var(--sp-3);
  font-size: 0.72rem;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.htable-frozen .htable-row {
  grid-auto-columns: unset;
  grid-template-columns: 22px 96px;
}
.htable-row:last-child { border-bottom: none; }
.htable-row.htable-head {
  font-weight: 700;
  color: var(--mist);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 0.6rem;
  background: var(--surface-raised);
  /* Headers get to wrap to a second line (e.g. "AVG OPT" / "GAP")
     instead of the fixed 38px single-line height every data row uses —
     checked against every column label in both tables that use this
     component, not just the one string that was reported. */
  height: auto;
  min-height: 38px;
  align-items: center;
  padding-top: 6px;
  padding-bottom: 6px;
  white-space: normal;
  line-height: 1.15;
}
.htable-row.me { background: var(--teal-dim); }
.htable-row .drv { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }

/* Standings — wide row w/ Challenges Completed column, tappable */
.standing-row.wide {
  grid-template-columns: 30px 1fr 44px 40px 40px;
}
.standing-row-cc { font-size: 0.7rem; color: var(--mist); text-align: center; }
.view-all-inline {
  width: 100%;
  margin-top: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--teal);
  font-weight: 700;
  font-size: var(--fs-body);
  padding: var(--sp-4);
  border-radius: var(--radius-sm);
  min-height: 52px;
}

/* Highlights: close battles + awards */
.battle-list { display: flex; flex-direction: column; gap: var(--sp-2); }
.battle-card {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
}
/* Hub UX pass (post-2J, follow-up) §3/4/5 — Round Awards page
   qualification/progress area. Compact rows, restrained green
   "COMPLETE" treatment (not gaudy), stays visible even once qualified
   so the driver sees their five rows fill in over the Round. */
.award-progress-area {
  margin-bottom: var(--sp-4);
}
.award-progress-explainer {
  color: var(--mist);
  font-size: var(--fs-eyebrow);
  margin: 0 0 var(--sp-3);
  line-height: 1.4;
}
.award-progress-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.award-progress-row {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-3);
}
.award-progress-row.qualified {
  border-color: var(--green-dim);
  background: var(--green-dim);
}
.apr-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.apr-number {
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--mist);
}
.award-progress-row.qualified .apr-number { color: var(--green); }
.apr-check {
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  color: var(--green);
}
.apr-names {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--paper);
  margin-top: 2px;
}
.apr-progress {
  font-size: var(--fs-small);
  color: var(--paper);
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
.apr-remaining {
  font-size: var(--fs-eyebrow);
  color: var(--teal);
  margin-top: 1px;
}
.award-progress-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--mist);
}
.award-progress-summary.all-complete {
  border-style: solid;
  border-color: var(--green-dim);
  color: var(--green);
}

.award-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
}
.award-card {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-4) var(--sp-3);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}
/* v0.7.11 §3: redesigned hierarchy \u2014 the driver's name is now the
   loudest thing on the tile (that's who won), the award name is a quiet
   uppercase eyebrow (what it was), and the value is a small teal accent
   (the number that proves it). Previously all three competed at nearly
   the same weight. Icon variety fixed in icons.js/mockData.js, not here. */
.award-icon { width: 20px; height: 20px; color: var(--gold); margin: 0 auto; }
.award-icon svg { width: 100%; height: 100%; }
.award-icon.lg { width: 44px; height: 44px; margin: 0 auto var(--sp-3); }
.award-label {
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--mist);
  margin-top: var(--sp-2);
  width: 100%;
}
.award-winner {
  color: var(--paper);
  font-size: 0.95rem;
  font-weight: 800;
  margin-top: 3px;
  width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.award-value { color: var(--teal); font-size: 0.72rem; font-weight: 600; margin-top: 2px; width: 100%; }
.award-hero { text-align: center; padding: var(--sp-5) 0; }
.award-hero-label { font-weight: 800; font-size: 1.2rem; margin-top: var(--sp-2); }
.award-hero-winner { color: var(--gold); font-weight: 700; margin-top: 4px; }

/* Handicap section */
.beta-notice {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  background: var(--purple-dim);
  border: 1px solid var(--purple);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  margin-top: var(--sp-4);
  font-size: var(--fs-small);
  color: var(--paper);
}
.handicap-intro { margin-top: var(--sp-4); font-size: var(--fs-small); line-height: 1.6; color: var(--paper); }
.handicap-intro p { margin: 0 0 var(--sp-2); }
.handicap-intro p:last-child { margin-bottom: 0; }
/* v0.7.10 \u00a72: trimmed landing intro \u2014 "Scratch is king" and the
   Handicap question both read as short, bold statements rather than
   a paragraph of explanatory copy. */
.handicap-intro-lead p { font-size: 0.95rem; }
.handicap-intro-strong { color: var(--paper); font-weight: 800; }

/* v0.7.10 \u00a73: consistent breathing room between the tab bar and the
   first piece of content on all four Handicap tabs. Padding (not
   margin) on the wrapper so it can't be swallowed by margin collapse
   with whatever each tab renders as its first child. */
.handicap-tab-body { padding-top: var(--sp-5); }

/* v0.7.10 \u00a74: "My Performance" \u2014 one polished summary card (styled
   after the My Round card) instead of four floating numbers.
   v0.7.11 \u00a75: now carries the driver identity row too (avatar, name,
   flag/number) so it matches My Round's structure, not just its card
   chrome \u2014 the small all-caps "MY PERFORMANCE" eyebrow that used to sit
   inside the card is gone; the page-level heading above it does that job
   now. */
/* Hub UX pass (post-2J): "My Round Performance" clarity (Part H/I) — a
   short explainer plus a tappable X/5 Challenges completed progress
   pill, both sitting above the existing performance card unchanged. */
.hc-perf-explainer {
  color: var(--mist);
  font-size: var(--fs-small);
  margin: 2px 0 var(--sp-3);
}
.hc-round-progress {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  margin-bottom: var(--sp-3);
  color: var(--paper);
  font-weight: 600;
  font-size: 0.9rem;
  text-align: left;
}
.hc-round-progress:active { background: var(--surface-raised); }
.hc-round-progress-arrow { color: var(--mist); font-size: 1.1rem; }

.hc-performance-card {
  background: linear-gradient(160deg, var(--surface) 0%, var(--surface-raised) 100%);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-4);
}
.hc-performance-card .me-identity { margin-bottom: var(--sp-3); }
.hc-expectation-banner {
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--paper);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  margin-bottom: var(--sp-3);
  text-align: center;
}
.hc-expectation-banner.ahead { color: var(--green); border-color: var(--green-dim); background: var(--green-dim); }
.hc-expectation-banner.behind { color: var(--red); border-color: var(--red-dim); background: var(--red-dim); }
.hc-perf-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3) var(--sp-3);
  margin-top: var(--sp-2);
}
.hc-perf-item { min-width: 0; }
.hc-perf-divider { grid-column: 1 / -1; height: 1px; background: var(--border); margin: 2px 0; }
.hc-perf-value {
  font-size: 1.4rem;
  font-weight: 800;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hc-perf-position { color: var(--purple); }
.hc-perf-label {
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mist);
  margin-top: 4px;
}

/* v0.7.11 \u00a78: very short key under the Handicap tabs \u2014 explains "Gap %"
   / "Closed %" in one line each, not a wall of text (the full model lives
   in How It Works \u2192 Handicap System). */
.hc-legend {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: var(--sp-3);
  font-size: 0.72rem;
  color: var(--mist);
  line-height: 1.4;
}
.hc-legend strong { color: var(--paper); font-weight: 700; }

/* Inline text-link used inside prose (e.g. "\u2192 See Handicap System in How
   It Works") \u2014 looks like a link, not a button, but is one. */
.handicap-inline-link {
  background: none;
  border: none;
  padding: 0;
  color: var(--teal);
  font-weight: 700;
  font-size: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* v0.7.10 \u00a75: "By Challenge" cards restyled on the My Challenges card
   base (.my-challenge-card) with Handicap-specific content \u2014 position
   promoted to the top-right, pace kept quiet/secondary, Vs Expected
   given the visual weight instead of the raw points total.
   v0.7.11 \u00a78: raw-seconds pace line demoted further to a single quiet
   footnote; the primary content is now the 3-up gap-percentage grid plus
   the dynamic expectation sentence. */
.hc-challenge-card { display: block; cursor: default; }
.hc-position-accent { color: var(--purple); }
.hc-gap-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  text-align: center;
}
.hc-gap-item { min-width: 0; }
.hc-gap-value { font-size: 1.05rem; font-weight: 800; }
.hc-gap-label {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--mist);
  margin-top: 2px;
}
.hc-pace-footnote {
  font-size: 0.7rem;
  color: var(--mist);
  margin: var(--sp-2) 0 0;
}
.hc-result-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--border);
}
.hc-result-delta { font-size: 1.05rem; font-weight: 800; }
.hc-result-points { font-size: var(--fs-small); color: var(--mist); }
.tabular.ahead { color: var(--green); }
.tabular.behind { color: var(--red); }

/* v0.7.2 — My Driver helmet picker: one large finished-artwork helmet,
   swipe/arrow carousel between the (currently 5) catalogue entries,
   compact windowed pagination dots, position counter, then the
   driver/country/era identity line. No colour customisation — every
   helmet is a supplied image, never generated or recoloured. */
.helmet-designer-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-4);
}
.helmet-preview-stage {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-3) 52px;
  touch-action: pan-y;
  box-sizing: border-box;
  overflow: hidden; /* Part M (Hub UX pass, post-2J): per-asset visualScale
    can mildly upscale an image (max 1.08x, see icons.js helmetImageHTML) to
    normalise display size across the 12 helmets — this guarantees that
    never bleeds past the stage's own padding into the carousel buttons. */
}
/* Fixed-aspect box so every helmet — regardless of its own silhouette
   proportions or which way it's facing — gets the same consistent
   breathing room. object-fit: contain guarantees the full helmet is
   always visible, never cropped or stretched. The stage's own 52px
   side padding (above) keeps the image clear of the carousel buttons. */
.helmet-illustration.lg {
  width: 100%;
  aspect-ratio: 4 / 3;
  max-width: 260px;
  object-fit: contain;
}
.helmet-illustration.sm {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.helmet-carousel-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--teal-dim);
  background: rgba(0, 214, 201, 0.08);
  color: var(--teal);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.helmet-carousel-btn.prev { left: 0; }
.helmet-carousel-btn.next { right: 0; }
.helmet-carousel-btn svg { width: 20px; height: 20px; }
.helmet-dots {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: var(--sp-2);
}
.helmet-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--border);
}
.helmet-dot.active {
  background: var(--teal);
  width: 8px;
  height: 8px;
}
.helmet-design-counter {
  text-align: center;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--mist);
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
/* v0.7.2 — driver identity beneath the picker. Name carries the visual
   weight (half the fun is knowing whose helmet this is); country/era is
   deliberately smaller/secondary, same relationship as .me-name/.me-subline
   above, just centred here since the helmet stage above it is centred. */
.helmet-driver-id {
  text-align: center;
  margin-top: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}
.helmet-driver-name {
  font-size: var(--fs-h2);
  font-weight: 800;
  letter-spacing: 0.02em;
}
.helmet-driver-sub {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: var(--fs-small);
  color: var(--mist);
  margin-top: 2px;
}
.race-number-display { font-size: 1.4rem; font-weight: 800; }

.rg-card {
  background: linear-gradient(160deg, var(--surface) 0%, var(--surface-raised) 100%);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-5) var(--sp-4);
  text-align: center;
}
.rg-instruction {
  font-size: var(--fs-small);
  color: var(--mist);
  margin: 0 0 var(--sp-4);
  min-height: 2.6em;
}
.rg-instruction.rg-armed { color: var(--gold); font-weight: 700; }
/* §20/22: the lights going dark ARE the cue — no green anywhere, including
   this instruction label, so there's no second color-based "go" signal
   competing with (or surviving after) the actual lights-out moment. */
.rg-instruction.rg-go { color: var(--paper); font-weight: 800; font-size: 1.1rem; }

.lights-row {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin: 0 0 var(--sp-5);
}
.light-bulb {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--ink);
  border: 3px solid var(--border);
  flex-shrink: 0;
}
.light-bulb.lit {
  animation: rgLightOn 0.15s ease forwards;
}
@keyframes rgLightOn {
  to {
    background: var(--red);
    border-color: var(--red);
    box-shadow: 0 0 18px 3px rgba(232, 97, 93, 0.55);
  }
}

.rg-tap-btn {
  width: 100%;
  min-height: 56px;
  border-radius: var(--radius-sm);
  border: none;
  background: var(--teal);
  color: var(--ink);
  font-weight: 800;
  font-size: 1rem;
}
.rg-tap-btn.rg-tap-zone {
  background: var(--surface-raised);
  color: var(--paper);
  border: 2px dashed var(--border);
  min-height: 112px;
  font-size: 1.2rem;
}
/* §20/22: "go" state deliberately looks IDENTICAL to the armed tap-zone —
   grey/dark, no color change, no pulse. Lights-out is the only cue. */
.rg-tap-btn.rg-go-btn {
  font-size: 1.4rem;
  font-weight: 800;
}

.rg-reveal { text-align: center; }
.rg-reveal-result {
  font-size: 3rem;
  font-weight: 800;
  color: var(--teal);
  margin: var(--sp-3) 0;
  font-variant-numeric: tabular-nums;
}
.rg-reveal-result.rg-reveal-fail { color: var(--red); font-size: 2rem; }

.rg-attempt-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: var(--sp-3) 0;
}
.rg-attempt-row {
  display: flex;
  justify-content: space-between;
  padding: var(--sp-2) var(--sp-3);
  background: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
}
.rg-jump { color: var(--red); font-weight: 700; }

.rg-progress { display: flex; flex-wrap: wrap; gap: 6px; }
.rg-dot { width: 14px; height: 14px; border-radius: 50%; background: var(--surface-raised); border: 1px solid var(--border); }
.rg-dot.done { background: var(--teal); border-color: var(--teal); }
.rg-dot.false-start { background: var(--red); border-color: var(--red); }
.rg-dot.no-react { background: var(--gold); border-color: var(--gold); }

.rg-results-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-3);
  margin: var(--sp-4) 0;
}
.rg-results-grid > div { text-align: center; }
.rg-results-grid span { display: block; font-weight: 800; font-size: 1.3rem; }
.rg-results-grid label { display: block; font-size: 0.62rem; color: var(--mist); text-transform: uppercase; margin-top: 2px; }
.rg-note { font-size: 0.75rem; color: var(--mist); line-height: 1.5; margin: 0 0 var(--sp-4); }
.rg-share-btn {
  width: 100%;
  min-height: var(--tap-min);
  border-radius: var(--radius-sm);
  border: none;
  background: var(--teal);
  color: var(--ink);
  font-weight: 800;
}

/* Compare Drivers */
.compare-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: var(--sp-3);
  margin-bottom: var(--sp-4);
}
.compare-pick-chip {
  padding: 6px 12px;
  min-height: 36px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--mist);
}
.compare-pick-chip.active { background: var(--teal); border-color: var(--teal); color: var(--ink); }
.compare-table { border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.compare-table-head, .compare-table-row {
  display: grid;
  grid-template-columns: 1fr repeat(3, minmax(0, 1fr));
  gap: 4px;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.compare-table-head { background: var(--surface-raised); font-weight: 700; font-size: 0.65rem; color: var(--mist); text-transform: uppercase; }
.compare-head-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.compare-row-label { font-size: 0.72rem; color: var(--mist); font-weight: 600; }
.compare-cell { font-size: 0.8rem; text-align: center; }
.compare-cell.best { color: var(--green); font-weight: 800; }

@media (min-width: 768px) {
  .award-grid { grid-template-columns: repeat(4, 1fr); }
  .stat-grid { grid-template-columns: repeat(4, 1fr); }
}
