@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@500;700;900&family=Rajdhani:wght@500;600;700&display=swap');

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

html, body {
  height: 100%;
  background: #0a0a0a;
  font-family: 'Rajdhani', sans-serif;
  overflow: hidden;
  /* pan-x/pan-y (not "manipulation") — this app should never zoom at all,
     on any page: "manipulation" still lets a two-finger pinch zoom the
     page even with double-tap-zoom disabled, so it's not enough on its
     own. Combined with each page's own viewport meta tag
     (user-scalable=no) as a second layer, since some mobile browsers
     don't fully honor that meta tag by itself. */
  touch-action: pan-x pan-y;
  -webkit-tap-highlight-color: transparent;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
}

a { text-decoration: none; }

/* ============== SITE-WIDE ANNOUNCEMENT BANNER (all pages) ==============
   Admin-triggered site-wide message (see admin_dashboard.html's SITE-WIDE
   ANNOUNCEMENT BANNER card and static/js/maintenance-banner.js) — the JS
   builds this element itself and appends it to <body>, so there's no
   markup to add to any individual template. No close button on purpose:
   it stays up until the admin turns it off, not until a driver dismisses
   it. See .phone's margin-top/height rules above for how the rest of the
   page shifts down to stay clear of it instead of being covered.
   Severity (see .sev-* below) picks the color; red is the base/default so
   an unset or unrecognized severity still reads as a real warning. */
.maintenance-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 10000;
  display: none;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 9px 4vw;
  padding-top: calc(9px + env(safe-area-inset-top));
  background: linear-gradient(90deg, #200606, #3d0f0c 50%, #200606);
  background-size: 200% 100%;
  color: #9dff3f;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: clamp(13px, 3vw, 16px);
  letter-spacing: 0.4px;
  text-align: center;
  text-shadow: 0 0 10px rgba(157,255,63,0.55);
  box-shadow: 0 2px 14px rgba(0,0,0,0.6);
  animation: maintenance-banner-sheen 3.2s linear infinite, maintenance-banner-slide-down 0.4s ease both;
}
.maintenance-banner.sev-orange { background: linear-gradient(90deg, #241505, #3f230a 50%, #241505); background-size: 200% 100%; }
.maintenance-banner.sev-yellow { background: linear-gradient(90deg, #211d04, #3a3308 50%, #211d04); background-size: 200% 100%; }
.maintenance-banner.sev-green { background: linear-gradient(90deg, #06170c, #0f2b18 50%, #06170c); background-size: 200% 100%; }
.maintenance-banner.is-blinking { animation: maintenance-banner-sheen 3.2s linear infinite, maintenance-banner-slide-down 0.4s ease both, maintenance-banner-blink 1s ease-in-out infinite; }
@keyframes maintenance-banner-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
.maintenance-banner-icon {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  animation: maintenance-banner-pulse 1.4s ease-in-out infinite;
}
.maintenance-banner-icon svg { width: 100%; height: 100%; }
@keyframes maintenance-banner-sheen {
  0% { background-position: 0% 0; }
  100% { background-position: 200% 0; }
}
@keyframes maintenance-banner-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.55; transform: scale(0.85); }
}
@keyframes maintenance-banner-slide-down {
  0% { opacity: 0; transform: translateY(-100%); }
  100% { opacity: 1; transform: translateY(0); }
}

/* Full-screen version of the same warning, used only on the main menu
   (see dashboard.html's window.MAINTENANCE_BANNER_FULLSCREEN flag and
   maintenance-banner.js) — everywhere else stays the slim top strip
   above. Closable for the current view only (small × button); it comes
   back on the next visit, or the moment the admin actually changes the
   message, since either counts as a genuinely new state to show. */
.maintenance-fullscreen-overlay {
  position: fixed;
  inset: 0;
  z-index: 10001;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
  padding: 8vw;
  background: radial-gradient(circle at 50% 40%, rgba(120,30,20,0.16), rgba(2,2,2,0.99) 68%);
  animation: maintenance-fullscreen-fade 0.35s ease both;
}
.maintenance-fullscreen-overlay.sev-orange { background: radial-gradient(circle at 50% 40%, rgba(140,75,10,0.18), rgba(2,2,2,0.99) 68%); }
.maintenance-fullscreen-overlay.sev-yellow { background: radial-gradient(circle at 50% 40%, rgba(140,125,10,0.18), rgba(2,2,2,0.99) 68%); }
.maintenance-fullscreen-overlay.sev-green { background: radial-gradient(circle at 50% 40%, rgba(20,100,45,0.2), rgba(2,2,2,0.99) 68%); }
.maintenance-fullscreen-overlay.sev-orange .maintenance-fullscreen-icon { color: #ff9d4a; }
.maintenance-fullscreen-overlay.sev-orange .maintenance-fullscreen-title { color: #ffb877; }
.maintenance-fullscreen-overlay.sev-yellow .maintenance-fullscreen-icon { color: #f0d43a; }
.maintenance-fullscreen-overlay.sev-yellow .maintenance-fullscreen-title { color: #f5e185; }
.maintenance-fullscreen-overlay.sev-green .maintenance-fullscreen-icon { color: #5ee87f; }
.maintenance-fullscreen-overlay.sev-green .maintenance-fullscreen-title { color: #9dff3f; }
.maintenance-fullscreen-overlay.is-blinking { animation: maintenance-fullscreen-fade 0.35s ease both, maintenance-banner-blink 1s ease-in-out infinite; }
.maintenance-fullscreen-close {
  position: absolute;
  top: max(16px, env(safe-area-inset-top));
  right: max(16px, env(safe-area-inset-right));
  width: 38px;
  height: 38px;
  padding: 0;
  border-radius: 50%;
  border: 1.5px solid rgba(255,255,255,0.3);
  background: rgba(255,255,255,0.06);
  color: #fff;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.maintenance-fullscreen-close:hover { background: rgba(255,255,255,0.14); border-color: rgba(255,255,255,0.5); }
.maintenance-fullscreen-icon {
  width: clamp(52px, 13vw, 84px);
  height: clamp(52px, 13vw, 84px);
  color: #ff6b5a;
  animation: maintenance-banner-pulse 1.6s ease-in-out infinite;
}
.maintenance-fullscreen-icon svg { width: 100%; height: 100%; }
.maintenance-fullscreen-title {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  letter-spacing: 2px;
  font-size: clamp(17px, 5vw, 27px);
  color: #ff8a75;
}
.maintenance-fullscreen-text {
  max-width: 46ch;
  font-size: clamp(16px, 4vw, 21px);
  font-weight: 600;
  color: #9dff3f;
  text-shadow: 0 0 10px rgba(157,255,63,0.4);
  line-height: 1.5;
}
@keyframes maintenance-fullscreen-fade {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

/* ============== ROTATE-TO-LANDSCAPE NOTICE ==============
   Shown on pages reached from the main menu when a mobile-sized screen is
   in portrait — those pages (timers, race data) need the extra width. The
   main menu itself and login/track-selection stay portrait-friendly. */
.rotate-notice {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: #0a0a0a;
  color: #f2f2f2;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 8vw;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: clamp(14px, 4.2vw, 20px);
  letter-spacing: 0.4px;
  line-height: 1.5;
}
.rotate-notice .icon {
  display: block;
  font-size: clamp(36px, 13vw, 58px);
  color: #9dff3f;
  margin-bottom: 4vw;
  animation: rotate-hint 1.6s ease-in-out infinite;
}
.rotate-notice-menu-btn {
  display: inline-block;
  margin-top: 6vw;
  padding: 0.7em 1.6em;
  border: 1.5px solid #9dff3f;
  border-radius: 8px;
  color: #9dff3f;
  font-weight: 700;
  letter-spacing: 1px;
  font-size: clamp(13px, 3.6vw, 17px);
  text-decoration: none;
  background: rgba(157,255,63,0.06);
}
.rotate-notice-menu-btn:active { transform: scale(0.97); }
.rotate-notice-lock-hint {
  margin-top: 4vw;
  font-size: clamp(11px, 3.2vw, 14px);
  color: #9a9a9a;
  font-weight: 500;
  max-width: 46ch;
}
@keyframes rotate-hint {
  0%, 100% { transform: rotate(0deg); }
  50% { transform: rotate(90deg); }
}
@media (orientation: portrait) and (max-width: 859px) {
  .rotate-notice { display: flex; }
  /* sibling selector: only hides .phone on pages that actually render a
     .rotate-notice element (it's always placed right before .phone in the
     markup) — pages without one, like login/tracks/dashboard, are
     untouched. Also more specific than the base .phone rule, so it wins
     regardless of stylesheet source order. */
  .rotate-notice ~ .phone { display: none; }
}

/* ============== MOBILE ADMIN: PORTRAIT-ONLY ==============
   The exact inverse of .rotate-notice above — the mobile admin panel
   (see mobile_admin_panel.html) must never be usable in landscape (too
   easy for someone else nearby to glance at on a busy show floor), so it
   blocks the opposite orientation instead. A separate class rather than
   reusing/modifying .rotate-notice, so the two never fight over the same
   selector under different media queries. */
.rotate-notice-portrait-only {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: #0a0a0a;
  color: #f2f2f2;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 8vw;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: clamp(14px, 4.2vw, 20px);
  letter-spacing: 0.4px;
  line-height: 1.5;
}
.rotate-notice-portrait-only .icon {
  display: block;
  font-size: clamp(36px, 13vw, 58px);
  color: #9dff3f;
  margin-bottom: 4vw;
  animation: rotate-hint 1.6s ease-in-out infinite;
}
/* max-width/max-height caps this to actual phone-sized landscape screens
   only — a real desktop browser window is also technically "landscape"
   (wider than tall), and without this it would get blocked here too,
   with no way to satisfy "rotate to portrait" on a monitor that can't
   rotate. Same desktop threshold this app already uses elsewhere (see
   the min-width:860px/min-height:500px breakpoint that switches .phone
   itself to the desktop card layout) — just inverted. */
@media (orientation: landscape) and (max-width: 859px), (orientation: landscape) and (max-height: 499px) {
  .rotate-notice-portrait-only { display: flex; }
  .rotate-notice-portrait-only ~ .phone { display: none; }
}

/* the mobile admin panel's severity picker (see mobile_admin_panel.html)
   — same 4 colors as the banner itself (.maintenance-banner.sev-*), just
   a plain radio-chip row styled with this app's normal design language
   instead of admin.css (which this page doesn't load). */
.mobile-admin-severity-row { display: flex; flex-wrap: wrap; gap: 0.8cqh 1.4cqw; }
.mobile-admin-severity-chip {
  display: flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.6em 1em;
  border-radius: 999px;
  border: 1.5px solid #333;
  background: rgba(255,255,255,0.02);
  cursor: pointer;
  font-size: clamp(12px, 2cqh, 15px);
  color: #d8d8d8;
}
.mobile-admin-severity-chip input { width: 15px; height: 15px; cursor: pointer; margin: 0; accent-color: #9dff3f; }
.mobile-admin-severity-chip:has(input:checked) { border-color: #9dff3f; background: rgba(157,255,63,0.08); color: #eafccf; }

/* small inline actions (RESET/DELETE next to a driver or PIN row) and a
   quiet caption line — mobile_admin_panel.html loads only this
   stylesheet, not admin.css, so it needs its own compact equivalents of
   admin.css's .admin-btn small / .admin-hint rather than pulling in a
   whole second stylesheet built for the full-width desktop layout. */
.mobile-admin-btn {
  padding: 0.5em 0.9em;
  border-radius: 8px;
  border: 1.5px solid rgba(157,255,63,0.4);
  background: rgba(157,255,63,0.04);
  color: #cfe9a8;
  font-weight: 700;
  font-size: clamp(11px, 1.9cqh, 13px);
  letter-spacing: 0.3px;
  cursor: pointer;
  white-space: nowrap;
}
.mobile-admin-btn:hover { background: rgba(157,255,63,0.12); border-color: #9dff3f; }
.mobile-admin-btn.danger {
  border-color: rgba(255,79,79,0.5);
  background: rgba(255,79,79,0.06);
  color: #ff8080;
}
.mobile-admin-btn.danger:hover { background: rgba(255,79,79,0.16); border-color: #ff4f4f; }
.mobile-admin-hint { color: #9a9a9a; font-size: clamp(11px, 1.8cqh, 13px); margin-top: 2px; }

/* ============== SHELL: fills the screen, scales with viewport ============== */
/* ============== SHELL: fills the screen, scales with viewport ============== */
/* container-type:size makes the cqw/cqh units used throughout this file
   scale to THIS element's own box, not the raw device viewport — so the
   exact same design works full-screen on a phone and in a smaller centered
   card on desktop. */
.phone {
  width: 100vw;
  height: 100dvh;
  max-height: 100vh;
  container-type: size;
  background: linear-gradient(135deg, #1a1a1a 0%, #0d0d0d 100%);
  background-image:
    linear-gradient(135deg, #1a1a1a 0%, #0d0d0d 100%),
    repeating-linear-gradient(45deg, rgba(255,255,255,0.015) 0px, rgba(255,255,255,0.015) 1px, transparent 1px, transparent 4px);
  display: flex;
  flex-direction: column;
  /* env(safe-area-inset-*) keeps content clear of notches / home indicators
     when the app is added to the home screen or run fullscreen on iOS */
  padding: max(2.2cqh, env(safe-area-inset-top)) max(3cqw, env(safe-area-inset-right)) max(2.2cqh, env(safe-area-inset-bottom)) max(3cqw, env(safe-area-inset-left));
  overflow: hidden;
  /* --maintenance-banner-h is 0px unless static/js/maintenance-banner.js
     has shown the site-wide warning banner, in which case it's kept in
     sync with that banner's real rendered height (which varies by device
     because of env(safe-area-inset-top)) — .phone shrinks and shifts down
     by exactly that much so the banner never covers page content on any
     of the app's pages, without needing per-page layout changes. */
  margin-top: var(--maintenance-banner-h, 0px);
  height: calc(100dvh - var(--maintenance-banner-h, 0px));
  max-height: calc(100vh - var(--maintenance-banner-h, 0px));
}

/* Most pages are built to fit exactly within .phone's fixed height, so the
   base rule above clips overflow on purpose (nothing should ever need to
   scroll there). MY STATISTICS has a lot of stacked content (summary
   cards + a COMPARE button + filter tabs + a table) that can add up to
   more than a short landscape phone's available height — rather than
   clipping the bottom off with no way to reach it, this page opts into
   normal vertical scrolling of the whole shell instead. */
.phone.is-scroll-page { overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; }
/* .drivers-table-shell is normally flex:1/min-height:0 so it eagerly
   shrinks to whatever's left over, which on a scrollable page would
   shrink it all the way to 0 instead of ever causing the page to actually
   overflow/scroll — give it back a real height here so the table stays
   usable and the rest of the page becomes what scrolls past it */
.phone.is-scroll-page .drivers-table-shell { flex: 0 0 auto; height: 42cqh; min-height: 240px; }

/* DESKTOP: show the app as a centered, framed card instead of stretching
   full width/height across a large monitor. Below this breakpoint (phones,
   tablets) it stays full-bleed as before. */
@media (min-width: 860px) and (min-height: 500px) {
  html, body { overflow: auto; }
  body { padding: 40px; background: #050505; }
  .phone {
    /* bigger than the original 900x620 card — every size in this file is
       driven by cqh/cqw units off .phone's own box, so a roomier desktop
       card makes text/icons/spacing read at a proper desktop scale
       without touching a single mobile rule (this whole block only
       matches above the 860px/500px mobile breakpoint) */
    width: min(92vw, 1180px);
    height: min(90vh, calc(780px - var(--maintenance-banner-h, 0px)));
    max-height: calc(90vh - var(--maintenance-banner-h, 0px));
    margin-top: var(--maintenance-banner-h, 0px);
    border-radius: 22px;
    border: 2px solid #2a2a2a;
    box-shadow: 0 24px 70px rgba(0,0,0,0.65);
  }
  /* the login screen is naturally narrower / portrait-shaped */
  body.login-body .phone {
    width: min(92vw, 520px);
    height: min(90vh, 860px);
  }
}

/* ============== LOGO ============== */
.logo { display: flex; align-items: center; gap: 1.2cqw; flex-shrink: 0; }

.logo-mark {
  width: clamp(26px, 5.2cqh, 40px);
  height: clamp(26px, 5.2cqh, 40px);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
  transform: skewX(-10deg);
  border-radius: 2px;
  overflow: hidden;
  flex-shrink: 0;
}
.logo-mark span { background: #e8e8e8; }
.logo-mark span:nth-child(odd) { background: #1a1a1a; }
.logo-mark span:nth-child(4n+1), .logo-mark span:nth-child(4n) { background: #9dff3f; }

.logo-text { font-family: 'Orbitron', sans-serif; font-weight: 700; line-height: 1.05; }
.logo-text .k1 { color: #ffffff; font-size: clamp(14px, 2.9cqh, 22px); letter-spacing: 1px; }
.logo-text .k2 { color: #9dff3f; font-size: clamp(14px, 2.9cqh, 22px); letter-spacing: 1px; display: block; }

/* ============== TOP HEADER (used on dashboard + sub-pages) ============== */
.top-header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2cqw;
  flex-shrink: 0;
  margin-bottom: 2cqh;
}

/* dashboard.html only: stacks the logo and the LEADERBOARD quick-link in
   the same top-left corner (button sits right under the logo) instead of
   .top-header's default align-items:center row, while .identity keeps its
   normal position on the right. */
.top-left-block {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6cqh;
}
/* LEADERBOARD + the kart quick-select button, side by side in one row
   under the logo — a slight gap between them so they read as two
   distinct actions, not a single wide button. */
.top-left-actions-row {
  display: flex;
  align-items: center;
  gap: 0.8cqw;
  flex-wrap: wrap;
}
.kart-select-group {
  display: flex;
  align-items: center;
  gap: 0.5em;
  flex-wrap: wrap;
}
.kart-select-btn {
  cursor: pointer;
  padding: 0.9cqh 1.8cqw;
  font-size: clamp(12px, 2.2cqh, 16px);
  min-height: 34px;
}
.kart-select-btn svg { width: 1em; height: 1em; flex-shrink: 0; }
.kart-select-hint {
  color: #f2f2f2;
  font-weight: 700;
  letter-spacing: 0.3px;
  font-size: clamp(10px, 1.7cqh, 13px);
  white-space: nowrap;
}

/* driver_view.html only: the ALL DRIVERS back button needs to be truly
   centered on the header regardless of how wide the logo/identity blocks
   next to it are (justify-content:space-between alone just puts it
   wherever space is left, which isn't necessarily center). Pulled out of
   the flex flow and centered absolutely against .top-header's own width —
   scoped to this one class so every other page's .top-actions (which can
   hold different buttons) keeps its normal in-flow layout. */
.dv-top-actions {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.8cqh 1cqw;
  max-width: 60cqw;
}

.top-header .identity {
  text-align: right;
  font-size: clamp(13px, 2.6cqh, 19px);
  line-height: 1.5;
}
.top-header .identity .track-line { color: #9dff3f; font-weight: 700; letter-spacing: 0.4px; font-size: 0.85em; }
.top-header .identity .driver-line { color: #d8d8d8; position: relative; }
.top-header .identity .driver-line .driver-label { font-size: 0.82em; color: #9a9a9a; }
.top-header .identity .driver-line b { color: #f2f2f2; font-size: 1.15em; }

/* dashboard.html only: a small HELP shortcut under the driver's name,
   straight to /help — sized to match .leaderboard-btn/.kart-select-btn's
   own (shorter) height rather than the taller .back-btn default, since it
   sits in this same small top-corner identity block, not the bottom
   button row. */
.identity-help-row { margin-top: 0.5cqh; }
.help-menu-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  border-radius: 999px;
  padding: 0.5cqh 1.8cqw;
  font-weight: 700;
  font-size: clamp(10px, 1.7cqh, 13px);
  letter-spacing: 0.6px;
  min-height: 34px;
  background: rgba(157,255,63,0.04);
  border: 1px solid rgba(157,255,63,0.35);
  color: #cfe9a8;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.help-menu-btn:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; color: #eafccf; }
.help-menu-btn svg { width: 1em; height: 1em; flex-shrink: 0; }

/* status badge right after the driver's name — three states:
   - registered (PIN) login: a green star, gently fading
   - Drop In guest who hasn't picked a kart yet: a slowly cycling
     green/yellow/red dot, nudging them to register or pick one
   - Drop In guest who HAS picked a kart: a calmer green checkmark
     (still fading, but no more color-cycling nag) since they've
     already done the thing the cycling dot was pushing them toward */
.driver-name-tag { cursor: pointer; }
.driver-badge {
  display: inline-block;
  margin-left: 0.35em;
  font-size: 1em;
  line-height: 1;
  vertical-align: middle;
}
.driver-badge.badge-star,
.driver-badge.badge-kart-ready {
  color: #9dff3f;
  text-shadow: 0 0 6px rgba(157,255,63,0.6);
  animation: driver-badge-fade 2s ease-in-out infinite;
}
@keyframes driver-badge-fade {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
.driver-badge.badge-guest {
  width: 0.55em;
  height: 0.55em;
  border-radius: 50%;
  animation: driver-badge-cycle 3s linear infinite;
}
@keyframes driver-badge-cycle {
  0%, 30%   { background: #9dff3f; box-shadow: 0 0 6px rgba(157,255,63,0.7); }
  33%, 63%  { background: #ffd23f; box-shadow: 0 0 6px rgba(255,210,63,0.7); }
  66%, 96%  { background: #ff4f4f; box-shadow: 0 0 6px rgba(255,79,79,0.7); }
  100%      { background: #9dff3f; box-shadow: 0 0 6px rgba(157,255,63,0.7); }
}

/* tap-to-reveal popup — a centered full-screen overlay (same visual
   language as .winner-overlay/.winner-card on the Live Leaderboard): a
   thank-you trophy for a registered driver, or a nag toward logging in /
   picking a kart for a guest. Tap anywhere, or wait a few seconds, to
   dismiss (see static/js/driver-badge.js). */
.driver-popup-overlay {
  position: fixed;
  inset: 0;
  z-index: 400;
  background: rgba(5,5,5,0.92);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 4cqh 4cqw;
  cursor: pointer;
}
.driver-popup-overlay.is-visible { display: flex; }
.driver-popup-card {
  position: relative;
  text-align: center;
  max-width: 420px;
  padding: 4cqh 5cqw;
  border: 2px solid #9dff3f;
  border-radius: 20px;
  background: linear-gradient(180deg, rgba(157,255,63,0.08), rgba(0,0,0,0.4));
  box-shadow: 0 0 60px rgba(157,255,63,0.25);
  animation: driver-popup-pop 0.5s cubic-bezier(0.2, 1.4, 0.4, 1) both;
}
@keyframes driver-popup-pop {
  0% { opacity: 0; transform: scale(0.6) translateY(20px); }
  70% { opacity: 1; transform: scale(1.05) translateY(0); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}
/* explicit close affordance, alongside the existing "tap anywhere on the
   overlay to close" behavior (see driver-badge.js's overlay click
   listener — this button doesn't need its own handler, the click just
   bubbles up to that same listener) */
.driver-popup-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 50%;
  border: 1.5px solid rgba(157,255,63,0.4);
  background: rgba(0,0,0,0.25);
  color: #cfe9a8;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.driver-popup-close:hover { border-color: #9dff3f; color: #9dff3f; }
.driver-popup-emoji {
  font-size: clamp(48px, 12cqh, 84px);
  line-height: 1;
  margin-bottom: 0.8cqh;
}
.driver-popup-card.is-registered .driver-popup-emoji { animation: driver-popup-bounce 1.4s ease-in-out infinite; }
.driver-popup-card.is-guest .driver-popup-emoji { animation: driver-popup-shake 1.4s ease-in-out infinite; }
@keyframes driver-popup-bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}
@keyframes driver-popup-shake {
  0%, 100% { transform: rotate(0deg); }
  20% { transform: rotate(-10deg); }
  40% { transform: rotate(9deg); }
  60% { transform: rotate(-6deg); }
  80% { transform: rotate(4deg); }
}
.driver-popup-title {
  color: #9dff3f;
  font-weight: 800;
  letter-spacing: 2px;
  font-size: clamp(14px, 2.6cqh, 19px);
  margin-bottom: 0.6cqh;
}
.driver-popup-text {
  color: #9dff3f;
  font-weight: 600;
  font-size: clamp(13px, 2.2cqh, 16px);
  line-height: 1.4;
}

/* main-menu LOG OUT button — sits in the bottom button row, in line with
   CHANGE TRACK (and MY ACCOUNT), as the last/right-most one. Reuses
   .back-btn's own sizing so all buttons in that row match; only the icon
   gets a green accent to keep it visually tied to the rest of the app. */
.logout-bottom-btn svg { width: 1.1em; height: 1.1em; flex-shrink: 0; color: #9dff3f; }

/* the main-menu LIVE LEADERBOARD button — sits inside .top-left-block,
   directly under the logo, filled/bright so it still reads as an inviting
   action rather than a plain nav link even at this small corner size. */
.leaderboard-btn {
  background: rgba(157,255,63,0.1);
  border-color: #9dff3f;
  color: #9dff3f;
  font-weight: 700;
  font-size: clamp(10px, 1.7cqh, 13px);
  padding: 0.5cqh 1.8cqw;
  gap: 0.35em;
}
.leaderboard-btn:hover { background: rgba(157,255,63,0.18); }
/* .back-btn is normally just a text arrow (&#8592;), never a real <svg> —
   without an explicit size here the icon rendered at an unconstrained,
   oversized default instead of matching the text next to it. Sized off
   the button's own font-size (em), not cqh — cqh scales off the .phone
   container's rendered height, which on a real phone is much shorter
   than a desktop browser window, so a cqh-based size can look right in
   one and oversized in the other; em keeps it locked to the text
   sitting right next to it everywhere. */
.leaderboard-btn svg {
  width: 0.65em;
  height: 0.65em;
  flex-shrink: 0;
}

.back-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5cqw;
  border-radius: 999px;
  padding: 1.1cqh 2.2cqw;
  font-weight: 600;
  letter-spacing: 0.6px;
  font-size: clamp(14px, 2.6cqh, 19px);
  cursor: pointer;
  min-height: 40px;
  background: rgba(157,255,63,0.04);
  border: 1px solid rgba(157,255,63,0.35);
  color: #cfe9a8;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
  flex-shrink: 0;
}
.back-btn:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; color: #eafccf; }
.back-btn:active { background: rgba(157,255,63,0.18); }
/* a compact, arrow-only variant — for spots like the driver login screen
   where the full "MAIN MENU" text crowds the page's own logo/title */
.back-btn.icon-only {
  padding: 0.6cqh 0.6cqh;
  min-width: 40px;
  min-height: 40px;
  justify-content: center;
  font-size: clamp(16px, 3cqh, 22px);
}

/* ============== GENERIC PILL BUTTON (top actions on live timer etc.) ============== */
.top-actions { display: flex; gap: 1cqw; }
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5cqw;
  border-radius: 999px;
  padding: 1.1cqh 2cqw;
  font-weight: 600;
  letter-spacing: 1px;
  font-size: clamp(14px, 2.4cqh, 18px);
  cursor: pointer;
  white-space: nowrap;
  min-height: 40px;
  background: rgba(157,255,63,0.04);
  border: 1px solid rgba(157,255,63,0.35);
  color: #cfe9a8;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn .btn-icon { font-size: 1.1em; line-height: 1; color: #9dff3f; }
.btn:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; color: #eafccf; }
.btn:active { background: rgba(157,255,63,0.18); }

/* ============== PAGE TITLE ============== */
.page-title {
  text-align: center;
  color: #f2f2f2;
  font-weight: 700;
  font-size: clamp(19px, 3.8cqh, 28px);
  letter-spacing: 2.5px;
  margin-bottom: 2cqh;
  flex-shrink: 0;
}
.page-title .sub { color: #9dff3f; }

/* ============== ALL DRIVERS: current heat / drop indicator ==============
   Single-heat case: a plain centered label ("DROPIN 9") right under the
   page title. Multi-heat case (rare — a venue reporting more than one
   live activity at once) swaps this for tappable tabs instead, one per
   heat, so switching heats never needs more than a single screen. */
.heat-name-line {
  text-align: left;
  flex-shrink: 0;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(19px, 3.9cqh, 29px);
  letter-spacing: 1px;
  color: #9dff3f;
  text-shadow: 0 0 10px rgba(157,255,63,0.35);
  margin-bottom: 0.7cqh;
}
.heat-tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 0.8cqh 1.4cqw;
  flex-shrink: 0;
  margin-bottom: 0.7cqh;
}
.heat-tab {
  border-radius: 999px;
  padding: 0.6cqh 2cqw;
  font-weight: 700;
  letter-spacing: 0.5px;
  font-size: clamp(13px, 2.2cqh, 17px);
  cursor: pointer;
  border: 1.5px solid rgba(157,255,63,0.35);
  background: rgba(157,255,63,0.04);
  color: #cfe9a8;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.heat-tab:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; }
.heat-tab.active { background: #9dff3f; border-color: #9dff3f; color: #10230a; }

/* short landscape phones (see the menu-grid/card-list rules using the same
   query) — the extra heat/filter rows this page adds need to shrink here
   too, or they eat into the room the table itself needs to stay usable. */
@media (orientation: landscape) and (max-height: 500px) {
  .heat-name-line { font-size: clamp(15px, 4.4cqh, 20px); margin-bottom: 0.4cqh; }
  .heat-tabs { gap: 0.35cqh 1cqw; margin-bottom: 0.4cqh; }
  .heat-tab { padding: 0.3cqh 1.6cqw; font-size: clamp(12px, 2.8cqh, 15px); }
  .filter-bar { gap: 0.3cqh 0.8cqw; margin-bottom: 0.4cqh; }
  .filter-btn { padding: 0.32cqh 1.6cqw; font-size: clamp(11px, 2.4cqh, 14px); min-height: 0; }
}

/* ============== ALL DRIVERS: filter / sort bar ============== */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.7cqh 1.2cqw;
  flex-shrink: 0;
  margin-bottom: 0.8cqh;
}
.filter-btn {
  border-radius: 999px;
  padding: 0.75cqh 2.4cqw;
  font-weight: 700;
  letter-spacing: 0.6px;
  font-size: clamp(13px, 2.3cqh, 17px);
  cursor: pointer;
  border: 1.5px solid #4b6b1f;
  background: rgba(255,255,255,0.02);
  color: #cfcfcf;
  min-height: 36px;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.filter-btn:hover { border-color: #9dff3f; color: #eafccf; }
a.filter-btn { display: inline-flex; align-items: center; justify-content: center; }
.filter-btn.active { background: rgba(157,255,63,0.16); border-color: #9dff3f; color: #9dff3f; }
.filter-btn.sort-btn { border-style: dashed; }
.filter-btn.sort-btn.active { border-style: solid; }

/* Live Leaderboard's PICK A DATE tab — a compact input+button row that
   fits inside the same stat-card the other period tabs use, so it never
   needs its own layout space or disturbs the existing grid. */
.date-pick-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.8cqw;
  flex-wrap: wrap;
}
.date-pick-row .text-input { max-width: 180px; flex: 1 1 auto; }

/* ============== MY STATISTICS BY TIME (Drop In only) ==============
   A separate page (see app.py's my_stats_by_time) reached by a button on
   MY STATISTICS, for narrowing down to just the FROM/TO window a Drop In
   guest personally drove on a kart/device others may have also used. */
.guest-filter-bar {
  flex-shrink: 0;
  margin-bottom: 1cqh;
  padding: 1.4cqh 2cqw;
  border: 1.5px solid #3a3a3a;
  border-radius: 12px;
  background: rgba(255,255,255,0.035);
}
.guest-filter-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1cqh 1.6cqw;
}
.guest-filter-label {
  color: #b9b9b9;
  font-size: clamp(12px, 2.2cqh, 15px);
  font-weight: 700;
  letter-spacing: 0.6px;
}
.guest-filter-time {
  position: relative;
  background: #1e1e1e;
  border: 1.5px solid #6b9a2f;
  border-radius: 8px;
  color: #f2f2f2;
  padding: 0.9cqh 2.6em 0.9cqh 1.4cqw;
  font-size: clamp(15px, 2.8cqh, 19px);
  font-family: inherit;
  min-height: 40px;
  /* without this, the browser assumes a light theme for the native time
     picker's own popup/spinner UI (not just this input box), rendering
     dark-on-dark and effectively invisible */
  color-scheme: dark;
  /* the browser's own clock icon (drawn below) can't be recolored
     reliably across browsers, so it's hidden entirely (see the
     ::-webkit-calendar-picker-indicator rule) and this is our own icon
     in the app's actual accent green, matching every other icon here */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239dff3f' stroke-width='1.8'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3.5 2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.7em center;
  background-size: 1.3em;
}
.guest-filter-time:focus {
  outline: none;
  border-color: #9dff3f;
}
/* the native icon is fully transparent but stretched over the whole
   input, so clicking anywhere (not just the tiny original icon spot)
   opens the picker — our own SVG above is what's actually seen */
.guest-filter-time::-webkit-calendar-picker-indicator {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.guest-filter-btn {
  border-radius: 999px;
  padding: 0.9cqh 2.2cqw;
  font-weight: 700;
  letter-spacing: 0.5px;
  font-size: clamp(13px, 2.3cqh, 16px);
  cursor: pointer;
  border: 1.5px solid #9dff3f;
  background: rgba(157,255,63,0.14);
  color: #9dff3f;
  min-height: 40px;
}
.guest-filter-btn.ghost {
  border-color: #4b6b1f;
  background: transparent;
  color: #cfcfcf;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}


/* ============== CURRENT TRACK BANNER (dashboard) ==============
   The small track-line in the top-right header is easy to miss — this is
   a big, unmissable "you are here" banner for the main menu specifically. */
.current-track-banner {
  text-align: center;
  flex-shrink: 0;
  margin-bottom: 0.6cqh;
}
.current-track-banner .ctb-label {
  font-size: clamp(12px, 2cqh, 16px);
  color: #f2f2f2;
  letter-spacing: 2px;
  margin-bottom: 0.3cqh;
}
.current-track-banner .ctb-name {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(14px, 2.8cqh, 20px);
  color: #9dff3f;
  text-shadow: 0 0 14px rgba(157,255,63,0.4);
  padding: 0 3cqw;
  line-height: 1.25;
  /* however long the track's name is, this must always read as a single
     line, never wrap to two — a long custom admin-added track name
     gracefully truncates with an ellipsis instead */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* live running/pit/finished glance-icon, now living inside
   .track-started-line (see below) rather than next to the track name —
   see static/js/track-status.js. Hidden by default until a poll resolves
   a status, so a track with no live session shows nothing extra. */
.track-status-icon {
  display: none;
  align-items: center;
  justify-content: center;
  width: clamp(24px, 4.6cqh, 34px);
  height: clamp(24px, 4.6cqh, 34px);
  vertical-align: middle;
  flex-shrink: 0;
}
.track-status-icon svg { width: 100%; height: 100%; }
.track-status-icon.status-running { color: #9dff3f; animation: live-pulse 1.4s ease-in-out infinite; }
.track-status-icon.status-pit { color: #f5a623; }
.track-status-icon.status-finished { color: #ef4444; }

/* the driver's OWN claimed kart status (see static/js/track-status.js's
   computeMyKartStatus/renderMyKartStatus) is shown directly on the Kart #N
   button itself and its hint text, not as a separate badge — a different
   question from .track-status-icon above (which is about whether the
   TRACK currently has a live session at all): green = this specific kart
   is free, yellow = ready/waiting, red = actively racing right now.
   Colors only apply once the first poll actually resolves a status —
   until then the button keeps its normal look and the hint keeps
   reading "Select/Change kart number". */
.kart-select-btn.status-free { border-color: rgba(157,255,63,0.5); background: rgba(157,255,63,0.07); color: #cfe9a8; }
.kart-select-btn.status-ready { border-color: rgba(245,166,35,0.55); background: rgba(245,166,35,0.08); color: #f5c77e; }
.kart-select-btn.status-ready svg { animation: live-pulse 1.4s ease-in-out infinite; }
.kart-select-btn.status-occupied { border-color: rgba(239,68,68,0.55); background: rgba(239,68,68,0.08); color: #ff9b9b; }
.kart-select-btn.status-occupied svg { animation: live-pulse 1.4s ease-in-out infinite; }
.kart-select-hint.status-free { color: #cfe9a8; }
.kart-select-hint.status-ready { color: #f5c77e; }
.kart-select-hint.status-occupied { color: #ff9b9b; }

/* "Started <date> <time>" line, placed ABOVE "YOU ARE AT" so it's the
   first thing seen — hidden entirely until a poll resolves a live heat's
   start time. Sized well above the old sub-15px text, which was
   effectively unreadable on an actual phone screen. Works unchanged in
   both portrait and landscape since the main menu (unlike most other
   pages) supports both orientations. */
.track-started-line {
  display: none;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.8cqh 3.5cqw;
  margin-bottom: 1cqh;
}
.tsl-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-size: clamp(16px, 3cqh, 23px);
  color: #cfcfcf;
  letter-spacing: 0.4px;
  font-weight: 600;
}
.tsl-item svg {
  width: clamp(18px, 3.6cqh, 26px);
  height: clamp(18px, 3.6cqh, 26px);
  color: #9dff3f;
  flex-shrink: 0;
}
.tsl-item span:last-child { color: #f2f2f2; font-weight: 700; }

@media (orientation: landscape) and (max-height: 500px) {
  .track-started-line { margin-bottom: 0.5cqh; gap: 0.4cqh 2.6cqw; }
  .track-status-icon { width: clamp(18px, 5cqh, 26px); height: clamp(18px, 5cqh, 26px); }
  .tsl-item { font-size: clamp(13px, 3.6cqh, 17px); }
  .tsl-item svg { width: clamp(14px, 3.8cqh, 19px); height: clamp(14px, 3.8cqh, 19px); }
}

/* ============== SELECT TRACK: QR CODE ============== */
.qr-mini {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4cqh;
  width: fit-content;
  margin: 0 auto 1.6cqh;
  cursor: pointer;
  flex-shrink: 0;
}
.qr-mini img {
  /* cqh-relative (not just a fixed px range) so this stays the same
     proportion of the available height in both orientations — a short
     landscape phone naturally gets a smaller code, a tall portrait phone
     a bigger one, without ever overflowing .phone's fixed-height shell */
  width: clamp(72px, 14cqh, 110px);
  height: clamp(72px, 14cqh, 110px);
  background: #fff;
  padding: 6px;
  border-radius: 8px;
  border: 1.5px solid #4b6b1f;
  transition: border-color 0.15s ease;
}
.qr-mini:hover img, .qr-mini:focus-visible img { border-color: #9dff3f; outline: none; }
.qr-mini-hint {
  font-size: clamp(12px, 2.1cqh, 15px);
  font-weight: 700;
  letter-spacing: 0.5px;
  color: #9a9a9a;
}
.qr-overlay-img {
  width: min(70cqw, 320px);
  height: min(70cqw, 320px);
  background: #fff;
  padding: 4vw;
  border-radius: 16px;
}

/* ============== WELCOME PAGE: LOGO ROW — SHARE + QR ============== */
/* a SHARE button on the left and the same site QR code as SELECT TRACK
   on the right (see .qr-mini above — same tap-to-enlarge overlay, shared
   static/js/qr-mini.js; QR only when the admin has actually set one),
   symmetric around the centered logo. A real 3-column grid (share | logo
   | QR), NOT absolute positioning — an earlier version of this let the QR
   overlap the logo text on narrower phones, because absolute positioning
   takes an element out of flow entirely, so the logo's own centering had
   no idea it needed to leave room. The two 1fr side columns are always
   equal width, so the logo (the grid's only auto-sized column) stays
   mathematically centered no matter which of share/QR are present, and
   neither can ever sit on top of it — each simply has its own reserved
   space. The helmet icon below keeps its own separate, fully-centered
   row, untouched by any of this. */
.welcome-logo-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  width: 100%;
  margin-bottom: 1.6cqh;
  flex-shrink: 0;
}
.welcome-logo-row .logo { grid-column: 2; }
.qr-mini.qr-mini-corner {
  grid-column: 3;
  justify-self: end;
  margin: 0;
}
.qr-mini.qr-mini-corner img {
  width: clamp(38px, 8cqh, 58px);
  height: clamp(38px, 8cqh, 58px);
  padding: 4px;
}
.share-mini-btn {
  grid-column: 1;
  justify-self: start;
  width: clamp(38px, 8cqh, 58px);
  height: clamp(38px, 8cqh, 58px);
  border: 1.5px solid #9dff3f;
  border-radius: 50%;
  background: rgba(157,255,63,0.05);
  color: #9dff3f;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.15s ease;
}
.share-mini-btn svg { width: 54%; height: 54%; }
.share-mini-btn:hover { background: rgba(157,255,63,0.14); }
.share-mini-btn:active { transform: scale(0.94); }

/* small floating confirmation ("Link copied!") for the SHARE button's
   fallback path on browsers with no native share sheet (see
   static/js/share-app.js) — built and appended to <body> on demand,
   never present in the page's own markup. */
.share-toast {
  position: fixed;
  left: 50%;
  bottom: max(6cqh, env(safe-area-inset-bottom) + 20px);
  transform: translateX(-50%) translateY(12px);
  z-index: 10002;
  background: #16180f;
  border: 1.5px solid #9dff3f;
  color: #cfe9a8;
  font-weight: 700;
  letter-spacing: 0.4px;
  font-size: clamp(12px, 2cqh, 15px);
  padding: 0.8em 1.4em;
  border-radius: 999px;
  box-shadow: 0 8px 30px rgba(0,0,0,0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  max-width: 84vw;
  text-align: center;
}
.share-toast.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* the SHARE button's fallback modal (see static/js/share-app.js) — shown
   whenever navigator.share isn't available, which in practice is most of
   the time for this app (the Web Share API requires a secure/https
   context, and this app is commonly reached over a plain http:// LAN
   address). Same fixed-overlay/centered-card language as the app's other
   popups (driver-popup-overlay, kart-select-overlay). Built and appended
   to <body> on demand, never present in any page's own markup. */
.share-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 10003;
  background: rgba(5,5,5,0.88);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 4cqh 4cqw;
}
.share-modal-overlay.is-visible { display: flex; }
.share-modal-card {
  width: 100%;
  max-width: 360px;
  border: 2px solid #9dff3f;
  border-radius: 18px;
  background: linear-gradient(180deg, rgba(157,255,63,0.07), #0e0e0e);
  box-shadow: 0 0 50px rgba(157,255,63,0.2);
  padding: 3cqh 4cqw;
  animation: kart-select-pop 0.3s cubic-bezier(0.2, 1.3, 0.4, 1) both;
}
.share-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1cqh;
  gap: 1cqw;
}
.share-modal-title {
  font-family: 'Orbitron', sans-serif;
  color: #9dff3f;
  font-size: clamp(13px, 2.4cqh, 16px);
  letter-spacing: 1px;
  font-weight: 700;
}
.share-modal-close {
  background: none;
  border: 1.5px solid rgba(157,255,63,0.4);
  color: #cfe9a8;
  border-radius: 8px;
  width: 30px;
  height: 30px;
  padding: 0;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.share-modal-close:hover { border-color: #9dff3f; color: #9dff3f; }
.share-modal-link {
  font-family: 'Orbitron', sans-serif;
  font-size: clamp(11px, 1.9cqh, 13px);
  color: #9a9a9a;
  word-break: break-all;
  margin-bottom: 1.6cqh;
  padding: 0.6em 0.8em;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  background: rgba(255,255,255,0.02);
}
.share-modal-apps {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1cqh 1.2cqw;
}
.share-app-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5cqh;
  padding: 1.4cqh 0.6cqw;
  border: 1.5px solid rgba(157,255,63,0.35);
  border-radius: 12px;
  background: rgba(157,255,63,0.04);
  color: #cfe9a8;
  font-weight: 700;
  font-size: clamp(11px, 1.9cqh, 13px);
  letter-spacing: 0.4px;
  cursor: pointer;
  text-align: center;
}
.share-app-btn:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; color: #eafccf; }
.share-app-icon { width: 22px; height: 22px; }
.share-app-icon svg { width: 100%; height: 100%; }

/* ============== WELCOME PAGE: ABOUT / HELP BUTTONS ==============
   Secondary utility buttons — noticeably a button (border, padding, icon),
   but deliberately smaller/quieter than the two main confirm-btn choices
   above them so they never compete for attention. HELP gets a bit more
   visual weight (brighter border, filled background, small pulse) since
   it's the one the user most needs to be able to spot at a glance. */
.welcome-util-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.8cqh;
  margin-top: 1.6cqh;
  flex-shrink: 0;
}
.welcome-util-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  border: 1.5px solid #4b6b1f;
  border-radius: 22px;
  padding: 0.75em 1.3em;
  font-size: clamp(14px, 2.5cqh, 18px);
  font-weight: 600;
  letter-spacing: 0.3px;
  color: #c7c7c7;
  background: rgba(157,255,63,0.03);
  text-decoration: none;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease, transform 0.1s ease;
  min-width: 38cqw;
}
.welcome-util-btn svg { width: 1.15em; height: 1.15em; stroke: #9dff3f; flex-shrink: 0; }
.welcome-util-btn:hover { border-color: #9dff3f; color: #eafccf; background: rgba(157,255,63,0.1); }
.welcome-util-btn:active { transform: scale(0.97); }
.welcome-util-btn.help {
  border-color: #9dff3f;
  background: rgba(157,255,63,0.1);
  color: #eafccf;
}
.welcome-util-btn.help:hover { background: rgba(157,255,63,0.18); }
.welcome-util-btn.help .help-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #9dff3f;
  box-shadow: 0 0 6px #9dff3f;
  animation: welcome-help-pulse 1.6s ease-in-out infinite;
  flex-shrink: 0;
}
@keyframes welcome-help-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}
.app-version-text {
  margin-top: 1.4cqh;
  color: #6b6b6b;
  font-size: clamp(10px, 1.6cqh, 12px);
  letter-spacing: 0.6px;
  text-align: center;
  flex-shrink: 0;
}

/* ============== ABOUT / CREDITS PAGE ============== */
@keyframes about-fade-up {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}
.about-wrap {
  width: 100%;
  max-width: 620px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1.6cqh;
  padding-bottom: 2cqh;
}
.about-intro {
  text-align: center;
  color: #c7c7c7;
  font-size: clamp(13px, 2.1cqh, 16px);
  line-height: 1.55;
  padding: 0 2cqw;
  animation: about-fade-up 0.55s ease both;
}
.info-steps {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.8cqh;
  padding: 0;
  margin: 0;
}
.info-steps li {
  display: flex;
  align-items: flex-start;
  gap: 2.4cqw;
  font-size: clamp(12.5px, 1.95cqh, 15px);
  color: #d0d0d0;
  line-height: 1.5;
}
.info-step-num {
  flex-shrink: 0;
  width: 1.7em;
  height: 1.7em;
  border-radius: 50%;
  border: 1.5px solid #9dff3f;
  color: #9dff3f;
  font-weight: 700;
  font-size: 0.85em;
  display: flex;
  align-items: center;
  justify-content: center;
}

.info-faq {
  display: flex;
  flex-direction: column;
  gap: 0.9cqh;
  animation: about-fade-up 0.55s ease both;
}
.info-faq-item {
  border: 1px solid rgba(157,255,63,0.14);
  border-radius: 10px;
  padding: 1.2cqh 3cqw;
  background: rgba(255,255,255,0.02);
}
.info-faq-q {
  font-weight: 700;
  color: #f2f2f2;
  font-size: clamp(13px, 2cqh, 16px);
  margin-bottom: 0.35cqh;
}
.info-faq-q::before { content: "Q. "; color: #9dff3f; }
.info-faq-a {
  font-size: clamp(12px, 1.85cqh, 14px);
  color: #b0b0b0;
  line-height: 1.5;
}

.info-section-title {
  font-weight: 700;
  letter-spacing: 0.6px;
  font-size: clamp(15px, 2.4cqh, 19px);
  color: #f2f2f2;
  margin: 0.4cqh 0 -0.4cqh;
  animation: about-fade-up 0.55s ease both;
}
.info-section-title .sub { color: #9dff3f; }

.about-features {
  display: flex;
  flex-direction: column;
  gap: 0.9cqh;
  animation: about-fade-up 0.55s ease both;
  animation-delay: 0.03s;
}
.about-feature-row {
  display: flex;
  align-items: flex-start;
  gap: 2.6cqw;
  border: 1px solid rgba(157,255,63,0.16);
  border-radius: 10px;
  padding: 1.2cqh 3cqw;
  background: rgba(157,255,63,0.03);
}
.about-feature-icon {
  flex-shrink: 0;
  width: clamp(26px, 4.6cqh, 34px);
  height: clamp(26px, 4.6cqh, 34px);
  border-radius: 50%;
  border: 1.5px solid #9dff3f;
  display: flex;
  align-items: center;
  justify-content: center;
}
.about-feature-icon svg { width: 55%; height: 55%; stroke: #9dff3f; }
.about-feature-text {
  font-size: clamp(12px, 1.9cqh, 15px);
  color: #d0d0d0;
  line-height: 1.45;
  padding-top: 0.2cqh;
}
.about-feature-text b { color: #f2f2f2; }

.about-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.5cqh;
  border: 1.5px solid #4b6b1f;
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(157,255,63,0.05), rgba(0,0,0,0.2));
  padding: 2.4cqh 4cqw;
  animation: about-fade-up 0.55s ease both;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.about-card:hover { border-color: #9dff3f; transform: translateY(-2px); }
.about-card:nth-of-type(1) { animation-delay: 0.08s; }
.about-card:nth-of-type(2) { animation-delay: 0.18s; }
.about-card-icon {
  width: clamp(44px, 8.6cqh, 60px);
  height: clamp(44px, 8.6cqh, 60px);
  border: 1.5px solid #9dff3f;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0.4cqh;
}
.about-card-icon svg { width: 50%; height: 50%; }
.about-card-name {
  font-weight: 700;
  letter-spacing: 0.6px;
  font-size: clamp(17px, 3cqh, 22px);
  color: #f2f2f2;
}
.about-card-role {
  font-size: clamp(11px, 1.8cqh, 14px);
  color: #9dff3f;
  letter-spacing: 0.6px;
  text-transform: uppercase;
}
.about-card-body {
  font-size: clamp(12px, 1.9cqh, 15px);
  color: #9a9a9a;
  line-height: 1.5;
  max-width: 42ch;
}
.about-card-email {
  margin-top: 0.4cqh;
  font-size: clamp(12px, 1.9cqh, 15px);
  color: #9dff3f;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ============== GET THE APP (get_app.html) ============== */
.ga-hero {
  text-align: center;
  margin-bottom: 2cqh;
  animation: about-fade-up 0.55s ease both;
}
.ga-hero-icon {
  width: clamp(56px, 11cqh, 78px);
  height: clamp(56px, 11cqh, 78px);
  margin: 0 auto 1cqh;
  border: 1.5px solid #9dff3f;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 24px rgba(157,255,63,0.25);
  animation: ga-hero-float 2.6s ease-in-out infinite;
}
.ga-hero-icon svg { width: 52%; height: 52%; }
@keyframes ga-hero-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}
.ga-hero-badge {
  display: inline-block;
  border: 1px solid rgba(157,255,63,0.5);
  border-radius: 999px;
  padding: 0.3em 1em;
  font-weight: 800;
  letter-spacing: 2px;
  font-size: clamp(11px, 1.9cqh, 14px);
  color: #9dff3f;
  animation: ga-badge-pulse 1.8s ease-in-out infinite;
}
@keyframes ga-badge-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 rgba(157,255,63,0); }
  50% { opacity: 0.75; box-shadow: 0 0 14px rgba(157,255,63,0.35); }
}
/* toggled by static/js/get-app.js once it detects which platform the
   visitor is actually on — a plain border/glow highlight, not a full
   restyle, since "coming soon" makes neither card actionable yet */
.about-card.is-your-device {
  border-color: #9dff3f;
  background: linear-gradient(180deg, rgba(157,255,63,0.1), rgba(0,0,0,0.2));
}
.about-card.is-your-device .about-card-role::after {
  content: " \2014 YOUR DEVICE";
}
.ga-device-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6em;
  margin: 1.4cqh auto 0;
  padding: 0.6em 1.2em;
  border: 1px solid rgba(157,255,63,0.4);
  border-radius: 999px;
  width: fit-content;
  max-width: 90%;
  color: #eafccf;
  font-weight: 700;
  letter-spacing: 0.4px;
  font-size: clamp(12px, 2cqh, 15px);
}
.ga-device-badge svg { width: 1.2em; height: 1.2em; stroke: #9dff3f; flex-shrink: 0; }
.ga-device-badge b { color: #9dff3f; }
.about-company {
  border: 1.5px solid #4b6b1f;
  border-radius: 14px;
  padding: 2.2cqh 5cqw;
  animation: about-fade-up 0.55s ease both;
  animation-delay: 0.28s;
}
.about-company-name {
  text-align: center;
  font-weight: 700;
  letter-spacing: 1px;
  font-size: clamp(18px, 3.2cqh, 24px);
  color: #f2f2f2;
  margin-bottom: 1.2cqh;
}
.about-company-row {
  display: flex;
  justify-content: space-between;
  gap: 3cqw;
  padding: 0.7cqh 0;
  border-top: 1px solid rgba(157,255,63,0.12);
  font-size: clamp(12px, 1.9cqh, 15px);
}
.about-company-row:first-of-type { border-top: none; }
.about-company-row .label { color: #7a7a7a; letter-spacing: 0.4px; flex-shrink: 0; }
.about-company-row .value { color: #e0e0e0; text-align: right; }
.about-company-row .value a { color: #9dff3f; text-decoration: underline; text-underline-offset: 2px; }
.about-contact-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  color: #9dff3f !important;
  text-decoration: none !important;
  transition: color 0.15s ease;
}
.about-contact-link:hover { color: #c9ffa0 !important; }
.about-contact-link svg { width: 1.1em; height: 1.1em; flex-shrink: 0; stroke: currentColor; }
.about-back-row { display: flex; justify-content: center; animation: about-fade-up 0.55s ease both; animation-delay: 0.38s; }
.about-copyright {
  text-align: center;
  color: #555;
  font-size: clamp(10px, 1.6cqh, 12px);
  letter-spacing: 0.4px;
  animation: about-fade-up 0.55s ease both;
  animation-delay: 0.45s;
}

/* ============== LOGIN PAGE ============== */
.login-body { align-items: center; justify-content: center; }
.login-content {
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.helmet-wrap { display: flex; justify-content: center; margin-bottom: 1.6cqh; flex-shrink: 0; }
/* shared by both index.html (welcome page) and login.html (driver login) —
   one set of rules here covers both. Shape/border unchanged; the glow-pulse
   is a plain CSS loop, but the drift/bob motion is driven by
   static/js/helmet-icon.js (two mismatched sine waves, not a simple back-
   and-forth loop — reads as organic drift rather than a repeating tick)
   since CSS keyframes alone can't do the "never quite the same twice" look
   that was asked for. Also click/tap-to-enlarge (admin-toggleable). */
.helmet-circle {
  width: clamp(46px, 9cqh, 68px);
  height: clamp(46px, 9cqh, 68px);
  border: 1.5px solid #9dff3f;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  cursor: pointer;
  animation: helmet-glow 2.8s ease-in-out infinite;
}
.helmet-circle svg { width: 52%; height: 52%; }
@keyframes helmet-glow {
  0%, 100% { box-shadow: 0 0 16px rgba(157,255,63,0.18); }
  50% { box-shadow: 0 0 30px rgba(157,255,63,0.4); }
}

/* the enlarged popup shown when the helmet icon is tapped/clicked — same
   circle+icon, just bigger, centered on screen; auto-dismisses itself, or
   dismisses early on another tap/click anywhere. */
.helmet-popup-overlay {
  position: fixed;
  inset: 0;
  z-index: 450;
  background: rgba(5,5,5,0.85);
  display: none;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.helmet-popup-overlay.is-visible { display: flex; }
.helmet-popup-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.6vh;
  animation: helmet-popup-pop 0.4s cubic-bezier(0.2, 1.4, 0.4, 1) both;
}
.helmet-popup-circle {
  width: clamp(140px, 30vh, 220px);
  height: clamp(140px, 30vh, 220px);
  border: 2.5px solid #9dff3f;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 60px rgba(157,255,63,0.45);
  animation: helmet-glow 2.8s ease-in-out infinite;
}
.helmet-popup-circle svg { width: 52%; height: 52%; stroke: #9dff3f; }
@keyframes helmet-popup-pop {
  0% { opacity: 0; transform: scale(0.4); }
  100% { opacity: 1; transform: scale(1); }
}
.helmet-popup-text-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6vh;
  padding: 1.6vh 3.4vh;
  border-radius: 14px;
  background: rgba(8,8,8,0.72);
  border: 1px solid rgba(157,255,63,0.3);
}
.helmet-popup-title {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(18px, 4vh, 28px);
  letter-spacing: 2px;
  color: #f2f2f2;
  animation: helmet-text-glow 2.2s ease-in-out infinite;
}
@keyframes helmet-text-glow {
  0%, 100% { text-shadow: 0 0 10px rgba(157,255,63,0.3); }
  50% { text-shadow: 0 0 22px rgba(157,255,63,0.7); }
}
.helmet-popup-version {
  color: #9dff3f;
  font-size: clamp(11px, 2vh, 14px);
  letter-spacing: 0.5px;
  opacity: 0.85;
}

.pin-box {
  border: 1.5px solid #4b6b1f;
  border-radius: 8px;
  background: linear-gradient(180deg, rgba(157,255,63,0.04), rgba(0,0,0,0.2));
  padding: 1.6cqh 4cqw 1.4cqh;
  text-align: center;
  margin-bottom: 2cqh;
  width: 100%;
  flex-shrink: 0;
  transition: border-color 0.2s ease;
  overflow: hidden;
}
.pin-box.error { border-color: #ff4f4f; }
.pin-label { font-size: clamp(12px, 2cqh, 15px); letter-spacing: 1.5px; color: #b9b9b9; margin-bottom: 1cqh; }
.pin-dots {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  width: 100%;
  max-width: 280px;
  margin: 0 auto;
}
.pin-dots .slot {
  flex: 1 1 0;
  min-width: 0;
  max-width: 38px;
  font-family: 'Orbitron', sans-serif;
  font-size: clamp(17px, 3.6cqh, 24px);
  font-weight: 700;
  color: #9dff3f;
  text-align: center;
  border-bottom: 2px solid #4b6b1f;
  padding-bottom: 0.6cqh;
  overflow: hidden;
}

.keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.2cqh 1.4cqw;
  margin-bottom: 1.6cqh;
  width: 100%;
}
.key {
  aspect-ratio: 1.6 / 1;
  border: 1.5px solid #4b6b1f;
  border-radius: 10px;
  background: rgba(255,255,255,0.02);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(19px, 3.9cqh, 28px);
  color: #ffffff;
  cursor: pointer;
  user-select: none;
  transition: background 0.12s ease, transform 0.08s ease;
}
.key:active { background: rgba(157,255,63,0.12); transform: scale(0.96); }
.key.clear { color: #e0e0e0; }
.key.ok { background: linear-gradient(180deg, #b6ff4f, #7fcc1f); border-color: #9dff3f; color: #10230a; }
.key.ok:active { filter: brightness(1.1); }

.footer-text { text-align: center; font-size: clamp(13px, 2.1cqh, 16px); color: #b9b9b9; flex-shrink: 0; }
.footer-text a { color: #9dff3f; text-decoration: underline; }

/* these query the .phone container's own shape (via container-type:size),
   not the physical device orientation — so a narrow desktop card still gets
   the stacked layout even though the browser window itself is landscape */
@container (min-aspect-ratio: 1/1) {
  .login-content { max-width: 620px; flex-direction: row; align-items: center; justify-content: center; gap: 4cqw; }
  .login-left { display: flex; flex-direction: column; align-items: center; flex: 0 0 auto; width: 40%; }
  .login-right { flex: 0 0 auto; width: 52%; }
  .login-left .helmet-wrap { margin-bottom: 1.4cqh; }
  .login-left .pin-box { margin-bottom: 0; }
  .login-left .footer-text { margin-top: 1.6cqh; }
}
@container (max-aspect-ratio: 1/1) {
  .login-left, .login-right { width: 100%; }
}

/* ============== IDENTITY CONFIRMATION (after PIN login) ============== */
.confirm-name {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(20px, 5cqh, 34px);
  color: #f2f2f2;
  text-align: center;
  line-height: 1.35;
  margin: 1cqh 0 3cqh;
  padding: 0 4cqw;
  text-shadow: 0 0 14px rgba(157,255,63,0.25);
  flex-shrink: 0;
}
.confirm-actions {
  display: flex;
  flex-direction: column;
  gap: 1.4cqh;
  width: 100%;
  max-width: 380px;
  margin: 0 auto;
  flex-shrink: 0;
}
.confirm-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.7em;
  text-align: center;
  border-radius: 12px;
  padding: 2cqh 3cqw;
  font-weight: 700;
  letter-spacing: 1px;
  font-size: clamp(16px, 3cqh, 22px);
  cursor: pointer;
  border: 1.5px solid;
  min-height: 56px;
  line-height: 1.6;
  transition: filter 0.15s ease, background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.confirm-btn.yes {
  background: linear-gradient(180deg, #b6ff4f, #7fcc1f);
  border-color: #9dff3f;
  color: #10230a;
}
.confirm-btn.yes:hover { filter: brightness(1.06); }
.confirm-btn.no {
  background: rgba(255,79,79,0.06);
  border-color: rgba(255,79,79,0.5);
  color: #ff8080;
}
.confirm-btn.no:hover { background: rgba(255,79,79,0.14); border-color: #ff4f4f; color: #ffb3b3; }
/* secondary choice that isn't "cancel/wrong" (unlike .no) — the welcome
   screen's DROP IN and the post-track-selection MAIN MENU option */
.confirm-btn.neutral {
  background: rgba(157,255,63,0.04);
  border-color: rgba(157,255,63,0.35);
  color: #cfe9a8;
}
.confirm-btn.neutral:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; color: #eafccf; }
.confirm-btn svg { width: 1.3em; height: 1.3em; flex-shrink: 0; }

/* ============== FORM FIELDS (register, account) ============== */
.reg-form {
  width: 100%;
  max-width: 420px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1.6cqh;
  flex: 1;
  justify-content: center;
  min-height: 0;
}

.field-label {
  font-size: clamp(12px, 1.9cqh, 15px);
  letter-spacing: 1.5px;
  color: #b9b9b9;
  margin-bottom: 0.7cqh;
  display: block;
}

.text-input {
  width: 100%;
  background: rgba(255,255,255,0.03);
  border: 1.5px solid #4b6b1f;
  border-radius: 8px;
  padding: 1.3cqh 3cqw;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: clamp(15px, 2.5cqh, 19px);
  color: #f2f2f2;
  outline: none;
  transition: border-color 0.15s ease;
}
.text-input:focus { border-color: #9dff3f; }
.text-input::placeholder { color: #6b6b6b; }
/* the native calendar-picker icon on <input type=date> renders dark by
   default, which is invisible against this app's dark background —
   same class of bug as the admin <select> white-on-white fix */
.text-input::-webkit-calendar-picker-indicator { filter: invert(1); cursor: pointer; }

.pin-generate-box {
  border: 1.5px solid #4b6b1f;
  border-radius: 8px;
  background: linear-gradient(180deg, rgba(157,255,63,0.04), rgba(0,0,0,0.2));
  padding: 1.4cqh 3cqw;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2cqw;
}
.pin-generate-box .pin-value {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(20px, 3.8cqh, 28px);
  color: #9dff3f;
  letter-spacing: 3px;
  text-shadow: 0 0 10px rgba(157,255,63,0.4);
}

/* editable version of .pin-value — same look, but a real input so the
   driver can type their own PIN instead of only accepting a generated one */
.pin-edit-input {
  flex: 1;
  min-width: 0;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(20px, 3.8cqh, 28px);
  color: #9dff3f;
  letter-spacing: 3px;
  text-shadow: 0 0 10px rgba(157,255,63,0.4);
  background: transparent;
  border: none;
  outline: none;
  padding: 0;
}
.pin-edit-input::placeholder { color: rgba(157,255,63,0.4); }

.regenerate-btn {
  flex-shrink: 0;
  border-radius: 999px;
  padding: 0.9cqh 1.8cqw;
  font-weight: 600;
  letter-spacing: 0.6px;
  font-size: clamp(12px, 1.8cqh, 15px);
  cursor: pointer;
  background: rgba(157,255,63,0.04);
  border: 1px solid rgba(157,255,63,0.35);
  color: #cfe9a8;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.regenerate-btn:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; }
.regenerate-btn:active { background: rgba(157,255,63,0.18); }

.form-msg {
  text-align: center;
  font-size: clamp(12px, 1.8cqh, 14px);
  letter-spacing: 0.5px;
  color: #ff8080;
  min-height: 1.6em;
}
.form-msg.success { color: #9dff3f; }

.register-submit {
  width: 100%;
  border-radius: 8px;
  padding: 1.6cqh 3cqw;
  text-align: center;
  font-weight: 700;
  letter-spacing: 1.5px;
  font-size: clamp(15px, 2.6cqh, 19px);
  cursor: pointer;
  background: linear-gradient(180deg, #b6ff4f, #7fcc1f);
  border: 1.5px solid #9dff3f;
  color: #10230a;
  transition: filter 0.15s ease;
}
.register-submit:hover { filter: brightness(1.06); }
.register-submit:active { filter: brightness(1.15); }
.register-submit:disabled {
  opacity: 0.4;
  cursor: default;
  pointer-events: none;
  filter: none;
}

.danger-btn {
  width: 100%;
  border-radius: 8px;
  padding: 1.4cqh 3cqw;
  text-align: center;
  font-weight: 700;
  letter-spacing: 1px;
  font-size: clamp(14px, 2.4cqh, 17px);
  cursor: pointer;
  background: rgba(255,79,79,0.06);
  border: 1.5px solid rgba(255,79,79,0.5);
  color: #ff8080;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.danger-btn:hover { background: rgba(255,79,79,0.14); border-color: #ff4f4f; color: #ffb3b3; }
.danger-btn:active { background: rgba(255,79,79,0.22); }

.account-section {
  width: 100%;
  max-width: 420px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1.2cqh;
}
.account-section-title {
  font-size: clamp(12px, 1.9cqh, 15px);
  letter-spacing: 1.5px;
  color: #9dff3f;
  font-weight: 700;
}
.account-divider {
  width: 100%;
  max-width: 420px;
  margin: 1.8cqh auto;
  border: none;
  border-top: 1px solid #2a2a2a;
  flex-shrink: 0;
}

/* ============== TRACK SELECTION + generic card list ============== */
.card-list {
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  /* plain `center` can push overflowing content past the container's own
     top edge and make it permanently unreachable by scroll (a well-known
     flexbox gotcha) — `safe` falls back to start-aligned once content
     doesn't fit, so the top card never gets clipped on short screens */
  justify-content: safe center;
  gap: 1.8cqh;
  overflow-y: auto;
  min-height: 0;
  flex: 1;
}

.card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2cqw;
  border: 1.5px solid #4b6b1f;
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(157,255,63,0.05), rgba(0,0,0,0.2));
  padding: 2.4cqh 3.2cqw;
  min-height: 11cqh;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.08s ease;
  flex-shrink: 0;
}
.card:hover { background: rgba(157,255,63,0.09); border-color: #9dff3f; }
.card:active { background: rgba(157,255,63,0.16); transform: scale(0.99); }

.card-info { display: flex; align-items: center; gap: 2.6cqw; min-width: 0; }

.card-icon {
  flex-shrink: 0;
  width: clamp(42px, 7.4cqh, 60px);
  height: clamp(42px, 7.4cqh, 60px);
  border: 1.5px solid #9dff3f;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.card-icon svg { width: 55%; height: 55%; }

.card-text { display: flex; flex-direction: column; gap: 0.3em; min-width: 0; }

.card-name {
  font-weight: 700;
  font-size: clamp(19px, 3.4cqh, 26px);
  color: #f2f2f2;
  letter-spacing: 0.3px;
  /* bigger text no longer reliably fits the longest real track names on
     one line — wrap instead of ellipsis-truncating, since losing part of
     the track's name is worse than a slightly taller card */
  line-height: 1.25;
}
.card-sub {
  font-size: clamp(11px, 1.8cqh, 14px);
  color: #9a9a9a;
  letter-spacing: 0.8px;
}

.card-arrow { flex-shrink: 0; color: #9dff3f; font-size: clamp(22px, 3.6cqh, 30px); }

/* short landscape phones — same reasoning as the main menu's compact mode:
   the full-size cards don't all fit in ~300-390px of height, which forced
   a scroll to see every track. Shrink padding/icon and drop the subtitle
   so all 3 tracks land on one screen with nothing to scroll past. */
@media (orientation: landscape) and (max-height: 500px) {
  .card-list { gap: 0.8cqh; }
  .card {
    padding: 1cqh 2.4cqw;
    min-height: 0;
  }
  .card-icon {
    width: clamp(28px, 6.4cqh, 40px);
    height: clamp(28px, 6.4cqh, 40px);
  }
  .card-name { font-size: clamp(15px, 3.2cqh, 20px); line-height: 1.2; }
  .card-sub { display: none; }
  .card-arrow { font-size: clamp(16px, 2.6cqh, 20px); }
  /* a short landscape phone doesn't have the spare height for the bigger
     portrait-sized QR code above the track list (see .qr-mini img) — keep
     it small here specifically rather than letting the track list get
     squeezed for room */
  .qr-mini { margin-bottom: 0.6cqh; }
  .qr-mini img { width: 44px; height: 44px; padding: 4px; }
  .qr-mini-hint { font-size: 10px; }
}

.logout-link {
  margin-top: 2cqh;
  text-align: center;
  font-size: clamp(14px, 2.4cqh, 18px);
  color: #cfcfcf;
  cursor: pointer;
  flex-shrink: 0;
}
.logout-link:hover { color: #9dff3f; }

/* ============== DASHBOARD MENU GRID ============== */
.menu-grid {
  width: 100%;
  max-width: 680px;
  margin: 0.8cqh auto 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.8cqh 2.2cqw;
  flex: 1;
  min-height: 0;
  align-content: center;
}

.menu-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.2cqh;
  border: 1.5px solid #4b6b1f;
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(157,255,63,0.05), rgba(0,0,0,0.2));
  padding: 2.8cqh 1.8cqw;
  min-height: 14.5cqh;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.08s ease;
  text-align: center;
  /* belt-and-suspenders: whatever the exact cause (a squeezed row height in
     landscape, a non-shrinking icon in a narrow column, ...), nothing
     should ever be able to visually poke past this button's own rounded
     border — this guarantees it regardless of the cause. */
  overflow: hidden;
}
.menu-btn:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; }
.menu-btn:active { transform: scale(0.98); }

.menu-btn-icon {
  width: clamp(36px, 7cqh, 56px);
  height: clamp(36px, 7cqh, 56px);
  border: 1.5px solid #9dff3f;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
}
.menu-btn-icon svg { width: 48%; height: 48%; flex-shrink: 0; }

.menu-btn-label {
  font-weight: 700;
  letter-spacing: 1px;
  font-size: clamp(14px, 2.8cqh, 19px);
  color: #f2f2f2;
}
.menu-btn-sub {
  font-size: clamp(11px, 2cqh, 16px);
  color: #9a9a9a;
  letter-spacing: 0.5px;
}

/* short landscape phones (the main menu is the one page that stays usable
   in EITHER orientation — no .rotate-notice here): with only ~300-390px
   of height to work with, the stacked icon/label/sub-label layout doesn't
   fit its own min-height and the row below visually collides with it.
   Switch every button to the compact horizontal layout .wide already
   used, so each row only needs single-line height. */
@media (orientation: landscape) and (max-height: 500px) {
  .menu-grid {
    max-width: 920px;
    gap: 1cqh 1.6cqw;
  }
  .menu-btn {
    flex-direction: row;
    justify-content: flex-start;
    gap: 1.8cqw;
    min-height: 0;
    padding: 1.6cqh 2.4cqw;
  }
  .menu-btn-icon {
    width: clamp(26px, 6.4cqh, 38px);
    height: clamp(26px, 6.4cqh, 38px);
  }
  .menu-btn-label {
    font-size: clamp(13px, 3.6cqh, 17px);
    text-align: left;
  }
  .menu-btn-sub { display: none; }
}

/* ============== LIVE / TEAM TIMER PAGE ============== */
.time-box {
  border: 1.5px solid #4b6b1f;
  border-radius: 8px;
  background: linear-gradient(180deg, rgba(157,255,63,0.04), rgba(0,0,0,0.2));
  padding: 1.6cqh 3cqw 1.2cqh;
  width: min(94%, 560px);
  margin: 0 auto;
  overflow: hidden;
  box-sizing: border-box;
}
.time-display {
  display: flex;
  justify-content: center;
  align-items: baseline;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  /* tabular-nums keeps every digit glyph the same width — without it, a
     changing "1" vs "8" etc. subtly shifts the whole (centered) block
     sideways every frame, which reads as flickering while the clock runs */
  font-variant-numeric: tabular-nums;
  /* sized off the SMALLER of a height-based and a width-based value, so the
     "00:00.000" string can never grow wider than the (narrow) phone screen —
     height-only sizing let this overflow past both edges on tall/narrow devices */
  font-size: clamp(26px, min(11cqh, 14cqw), 74px);
  letter-spacing: 2px;
  white-space: nowrap;
  max-width: 100%;
}
/* tabular-nums above only helps if the loaded font actually ships equal-
   width digit glyphs for that OpenType feature — not guaranteed, and this
   is a webfont loaded from Google Fonts. Forcing a fixed character width
   on each digit group is a font-independent backstop: the centered clock
   genuinely cannot shift sideways as digits change, no matter what. */
.time-display .min,
.time-display .sec { display: inline-block; min-width: 2ch; text-align: center; }
.time-display .ms { display: inline-block; min-width: 3ch; text-align: center; }
.time-display .min { color: #ffffff; }
.time-display .sep { color: #6b6b6b; margin: 0 0.4cqw; }
.time-display .sec { color: #9dff3f; text-shadow: 0 0 12px rgba(157,255,63,0.6); }
.time-display .dot { color: #6b6b6b; margin: 0 0.15cqw; }
.time-display .ms { color: #9dff3f; text-shadow: 0 0 12px rgba(157,255,63,0.6); }

.time-labels {
  display: flex;
  justify-content: space-between;
  padding: 0 1.5cqw;
  font-size: clamp(10px, 1.7cqh, 13px);
  color: #9a9a9a;
  letter-spacing: 1px;
  margin-top: 0.4cqh;
}
.time-labels span:nth-child(2) { transform: translateX(3cqw); }
.time-labels span:nth-child(3) { transform: translateX(-1.5cqw); }

.main-flex {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  min-height: 0;
}

.bottom-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 2cqw;
  flex-shrink: 0;
  flex-wrap: wrap;
}
.lld-title { font-size: clamp(11px, 1.8cqh, 14px); color: #cfcfcf; letter-spacing: 1px; margin-bottom: 0.6cqh; }
.lap-box {
  border: 1.5px solid #4b6b1f;
  border-radius: 8px;
  padding: 0.8cqh 1.6cqw;
  display: flex;
  gap: 2cqw;
  font-size: clamp(12px, 1.9cqh, 15px);
  color: #cfcfcf;
  letter-spacing: 0.5px;
  align-items: center;
  flex-wrap: wrap;
  row-gap: 4px;
}
.lap-box .val { font-family: 'Orbitron', sans-serif; color: #f2f2f2; font-size: clamp(14px, 2.6cqh, 22px); font-weight: 700; margin-left: 0.4cqw; }
.lap-box .val.green { color: #9dff3f; }

.live-timer-badge {
  border: 1.5px solid #4b6b1f;
  border-radius: 6px;
  padding: 0.7cqh 2.2cqw;
  text-align: center;
  background: rgba(157,255,63,0.03);
}
.live-timer-badge .lt-label { font-size: clamp(11px, 1.8cqh, 14px); color: #9a9a9a; letter-spacing: 1px; }
.live-timer-badge .lt-value {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(18px, 3.2cqh, 24px);
  color: #cfe9a8;
  font-variant-numeric: tabular-nums;
  letter-spacing: 1px;
}

/* ============== INDEPENDENT STOPWATCH (Live Timer page) ============== */
.stopwatch-top {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6cqh;
  flex-shrink: 0;
  margin: 0.5cqh 0 0.5cqh;
}

/* bigger than the standard .time-display — this page is landscape-only
   (see .rotate-notice) so there's height to spare for larger digits.
   Sized conservatively (wide margin below the box's actual inner width) —
   this box has overflow:hidden as a hard backstop either way. */
.stopwatch-top .time-box .time-display {
  font-size: clamp(32px, min(17cqh, 10cqw), 84px);
}

.last-lap-box {
  border: 1.5px solid #4b6b1f;
  border-radius: 8px;
  background: linear-gradient(180deg, rgba(157,255,63,0.04), rgba(0,0,0,0.2));
  padding: 0.5cqh 3cqw 0.4cqh;
  width: min(94%, 560px);
  margin: 0 auto;
  text-align: center;
  overflow: hidden;
  box-sizing: border-box;
}
.last-lap-box .lt-label {
  font-size: clamp(11px, 1.7cqh, 14px);
  color: #9a9a9a;
  letter-spacing: 1.5px;
  margin-bottom: 0.2cqh;
}
.time-display.small {
  font-size: clamp(18px, min(9cqh, 5.5cqw), 36px);
}

/* TEAM STOPWATCH, driver view: the last lap becomes the prominent
   display, moved above the now-much-smaller ticking clock, since a
   driver only needs to glance at their last lap. ID-anchored selectors
   here are deliberate: .stopwatch-top .time-box .time-display above
   (0,3,0 specificity) would otherwise beat a plain .time-display.small
   toggle (0,2,0) no matter what class gets added/removed — two IDs (2,_,0)
   always outrank any number of classes, so these overrides are guaranteed
   to win regardless of what order the rules appear in the file. */
#teamStopwatchTop.team-driver-mode #teamLastLapBox { order: 1; width: min(96%, 620px); }
/* width-based term is the tighter of the two here on purpose — the box's
   own padding otherwise let "00:00.000" run past its edge and get clipped
   (overflow:hidden on .last-lap-box was hiding it rather than showing it) */
#teamStopwatchTop.team-driver-mode #teamLastLapBox .time-display {
  font-size: clamp(30px, min(16cqh, 8.5cqw), 76px);
}
#teamStopwatchTop.team-driver-mode #teamTimeBox { order: 2; }
#teamStopwatchTop.team-driver-mode #teamTimeBox .time-display {
  font-size: clamp(16px, min(6.5cqh, 4.5cqw), 30px);
}
.last-lap-delta {
  display: inline-block;
  font-size: clamp(11px, 1.8cqh, 15px);
  font-weight: 700;
  margin-left: 0.4em;
}
.last-lap-delta.trend-up { color: #4ade80; }
.last-lap-delta.trend-down { color: #ef4444; }
.last-lap-box.is-clickable { cursor: pointer; transition: border-color 0.15s ease; }
.last-lap-box.is-clickable:hover, .last-lap-box.is-clickable:focus-visible { border-color: #9dff3f; outline: none; }

.stopwatch-controls {
  display: flex;
  justify-content: center;
  gap: 3cqw;
  width: min(94%, 560px);
  margin: 0.5cqh auto 0;
  flex-shrink: 0;
}

/* LAP is what gets pressed constantly mid-run (once per lap) — it's the
   dominant control. START/STOP is only pressed twice a session, so it
   gets a smaller, secondary footprint even though it starts everything. */
.stopwatch-btn {
  appearance: none;
  -webkit-appearance: none;
  flex: 1 1 0;
  min-height: 68px;
  padding: 1.8cqh 2cqw;
  border-radius: 999px;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  letter-spacing: 1.5px;
  font-size: clamp(18px, 3.6cqh, 28px);
  cursor: pointer;
  border: 2px solid;
  transition: filter 0.15s ease, transform 0.08s ease, background 0.15s ease, border-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}
.stopwatch-btn:active { transform: scale(0.97); }

.stopwatch-btn.start, .stopwatch-btn.stop {
  flex: 0.8 1 0;
  max-width: 190px;
  min-height: 58px;
  font-size: clamp(15px, 3cqh, 22px);
}

.stopwatch-btn.start {
  background: linear-gradient(180deg, #b6ff4f, #7fcc1f);
  border-color: #9dff3f;
  color: #10230a;
}
.stopwatch-btn.start:hover { filter: brightness(1.06); }

.stopwatch-btn.stop {
  background: linear-gradient(180deg, #ff6a6a, #cc2020);
  border-color: #ff4f4f;
  color: #2a0808;
}
.stopwatch-btn.stop:hover { filter: brightness(1.06); }

.stopwatch-btn.secondary {
  flex: 1.5 1 0;
  max-width: 340px;
  min-height: 80px;
  font-size: clamp(20px, 4.4cqh, 34px);
  background: rgba(157,255,63,0.04);
  border-color: rgba(157,255,63,0.35);
  color: #cfe9a8;
}
.stopwatch-btn.secondary:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; color: #eafccf; }
.stopwatch-btn.secondary:disabled,
.stopwatch-btn:disabled {
  opacity: 0.4;
  cursor: default;
  pointer-events: none;
}

/* deliberately minor/compact — secondary actions, tucked up near the
   header so the big START/STOP + LAP pair can dominate the page */
.stopwatch-secondary-row {
  display: flex;
  gap: 1.6cqw;
  width: min(94%, 560px);
  margin: 0.4cqh auto 0;
  flex-shrink: 0;
}
.stopwatch-mini-btn {
  flex: 1 1 0;
  min-height: 30px;
  padding: 0.4cqh 1cqw;
  border-radius: 999px;
  font-weight: 600;
  letter-spacing: 0.5px;
  font-size: clamp(13px, 2.4cqh, 17px);
  text-align: center;
  cursor: pointer;
  border: 1.5px solid;
  background: rgba(157,255,63,0.04);
  border-color: rgba(157,255,63,0.35);
  color: #cfe9a8;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}
.stopwatch-mini-btn:hover { background: rgba(157,255,63,0.1); border-color: #9dff3f; color: #eafccf; }
.stopwatch-mini-btn.danger {
  background: rgba(255,79,79,0.06);
  border-color: rgba(255,79,79,0.5);
  color: #ff8080;
}
.stopwatch-mini-btn.danger:hover { background: rgba(255,79,79,0.14); border-color: #ff4f4f; color: #ffb3b3; }
.stopwatch-mini-btn:disabled {
  opacity: 0.4;
  cursor: default;
  pointer-events: none;
}

.badge.worst { color: #ff8080; }

/* ============== STATS PAGE ============== */
.stats-grid {
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.4cqh 2cqw;
  flex: 1;
  align-content: center;
  min-height: 0;
}
.stat-card {
  border: 1.5px solid #4b6b1f;
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(157,255,63,0.04), rgba(0,0,0,0.2));
  padding: 2cqh 1.6cqw;
  text-align: center;
}
.stat-card .stat-label { font-size: clamp(12px, 2cqh, 15px); color: #9a9a9a; letter-spacing: 1px; margin-bottom: 0.8cqh; }
.stat-card .stat-value {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(18px, 3.3cqh, 28px);
  color: #9dff3f;
  text-shadow: 0 0 10px rgba(157,255,63,0.4);
}

/* stats_mobile.html only (scoped via this wrapper class, not plain
   .stat-card — that class is shared by several other pages that shouldn't
   re-play an entrance animation every time their own JS refreshes it) —
   each card fades/slides up in on page load, staggered left-to-right,
   top-to-bottom. */
.stats-grid-animated .stat-card {
  animation: stats-card-in 0.45s ease both;
}
.stats-grid-animated .stat-card:nth-child(1) { animation-delay: 0.03s; }
.stats-grid-animated .stat-card:nth-child(2) { animation-delay: 0.08s; }
.stats-grid-animated .stat-card:nth-child(3) { animation-delay: 0.13s; }
.stats-grid-animated .stat-card:nth-child(4) { animation-delay: 0.18s; }
.stats-grid-animated .stat-card:nth-child(5) { animation-delay: 0.23s; }
.stats-grid-animated .stat-card:nth-child(6) { animation-delay: 0.28s; }
.stats-grid-animated .stat-card:nth-child(7) { animation-delay: 0.33s; }
@keyframes stats-card-in {
  0% { opacity: 0; transform: translateY(10px) scale(0.96); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* ============== KART NUMBER (My Race) ============== */
/* the "start your race" nudge — MY RACE blinks while a kart is claimed
   and ready/waiting on track, so it's obvious there's something to go
   confirm; stops the instant the ride starts or the kart's freed again
   (see static/js/track-status.js toggling this class based on the same
   live kart-status polling the badge above already does). */
@keyframes menu-btn-race-ready-blink {
  0%, 100% { border-color: #4b6b1f; box-shadow: none; }
  50% { border-color: #9dff3f; box-shadow: 0 0 22px rgba(157,255,63,0.5); }
}
.menu-btn.is-race-ready {
  animation: menu-btn-race-ready-blink 1.1s ease-in-out infinite;
}

.kart-box {
  width: 100%;
  max-width: 560px;
  margin: 0 auto 1cqh;
  flex-shrink: 0;
}
.kart-entry-row {
  display: flex;
  gap: 2cqw;
  align-items: center;
}
.kart-entry-row .text-input { flex: 1; }
.kart-entry-row .regenerate-btn { padding: 1.3cqh 2.2cqw; }

/* full-screen keypad — same look as the login PIN pad. Used by two pages:
   my_race.html (landscape-only, only while no kart number is set yet — the
   lap list is hidden then) and kart_number_entry.html (the main menu's
   Kart #N button, usable in either orientation since it's reached from the
   portrait main menu). Both give it the whole page to itself, so it can be
   sized generously either way. Key height is capped with max-height (not
   just aspect-ratio) — aspect-ratio alone ties height to the grid column's
   width with no ceiling, which overflowed short landscape screens (e.g.
   320px tall). */
.kart-entry-full {
  width: 100%;
  max-width: min(94cqw, 680px);
  margin: 0 auto;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 0;
}
.kart-dots {
  max-width: 300px;
  margin: 0.6cqh auto 1.1cqh;
}
.kart-dots .slot {
  font-size: clamp(22px, 5.4cqh, 42px);
}
.kart-keypad {
  gap: 0.9cqh 1.6cqw;
}
.kart-keypad .key {
  aspect-ratio: 1.8 / 1;
  max-height: clamp(40px, 15cqh, 104px);
  font-size: clamp(20px, 5.4cqh, 38px);
  border-radius: 8px;
}

/* ============== LAP LIST / LEADERBOARD TABLE ============== */
.lap-list {
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.6cqh;
  flex: 1;
  min-height: 0;
}
.lap-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1cqh 1.2cqw;
  border: 1px solid #2a2a2a;
  border-radius: 6px;
  font-size: clamp(15px, 2.5cqh, 20px);
  color: #d8d8d8;
}
.lap-row.best { border-color: #9dff3f; background: rgba(157,255,63,0.06); }
.lap-row .lap-num { color: #9a9a9a; letter-spacing: 1px; font-size: 0.85em; }
.lap-row .lap-time { font-family: 'Orbitron', sans-serif; font-weight: 700; color: #f2f2f2; }
.lap-row.best .lap-time { color: #9dff3f; }
.lap-row .badge { font-size: 0.65em; color: #9dff3f; letter-spacing: 1px; margin-left: 1cqw; }

/* ============== ALL DRIVERS TABLE ============== */
/* Landscape-only page (see .rotate-notice) — real column table instead of
   the vertical .lap-list, matching the reference project's live
   leaderboard columns. Horizontal scroll is the safety net for narrower
   landscape phones instead of shrinking text past legibility. */
/* shell is the non-scrolling positioning context, so the swipe hint below
   can pin to its corner without getting dragged along by the table's own
   horizontal scroll (which .drivers-table-wrap itself does). */
.drivers-table-shell {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  width: 100%;
}
.drivers-table-wrap {
  width: 100%;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
}
/* narrower landscape phones can't fit every column at once — this pulses
   a "swipe for more" hint until the driver actually scrolls the table
   once, so the STATUS/expand columns off-screen don't read as missing */
.scroll-hint {
  display: none;
  position: absolute;
  right: 0.7cqw;
  bottom: 0.6cqh;
  background: #9dff3f;
  color: #0a1a02;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: clamp(11px, 1.6cqh, 14px);
  letter-spacing: 0.5px;
  padding: 0.35em 0.8em;
  border-radius: 12px;
  pointer-events: none;
  animation: swipe-hint-pulse 1.6s ease-in-out infinite;
  z-index: 5;
}
.drivers-table-shell.is-scrollable:not(.has-scrolled) .scroll-hint { display: block; }
@keyframes swipe-hint-pulse { 0%, 100% { opacity: 0.95; } 50% { opacity: 0.45; } }

/* full-screen expand (STATISTICS page tables) — blows the existing shell
   up to cover the whole viewport instead of duplicating the table markup
   into a separate overlay; the tab-switching JS already targets
   [data-tab-panel] globally so it keeps working unchanged while expanded */
.drivers-table-shell.is-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(5,5,5,0.98);
  padding: max(2.4cqh, env(safe-area-inset-top)) max(3.5cqw, env(safe-area-inset-right)) max(2.4cqh, env(safe-area-inset-bottom)) max(3.5cqw, env(safe-area-inset-left));
}
.drivers-table-shell.is-fullscreen .drivers-table-wrap { height: 100%; }
.drivers-table-shell.is-fullscreen .drivers-table { font-size: clamp(15px, 2.6cqh, 20px); }

/* tap-the-table-to-expand, same hover/focus treatment as MY RACE's
   .full-laps-wrap so both "tap to see it full-screen" tables in the app
   look and feel identical on desktop too (a mouse pointer + a visible
   hover border communicate "clickable" — a touch phone doesn't need
   either, so this is purely a desktop nicety, same as MY RACE) */
.drivers-table-shell.is-expandable { cursor: pointer; }
.drivers-table-shell.is-expandable .drivers-table-wrap { transition: border-color 0.15s ease; }
.drivers-table-shell.is-expandable:hover .drivers-table-wrap,
.drivers-table-shell.is-expandable:focus-visible .drivers-table-wrap { border-color: #9dff3f; }
.drivers-table-shell.is-expandable:focus-visible { outline: none; }
.drivers-table-shell.is-fullscreen.is-expandable { cursor: default; }
.drivers-table {
  width: 100%;
  min-width: 760px;
  border-collapse: collapse;
  font-size: clamp(15px, 2.5cqh, 19px);
  color: #d8d8d8;
}
.drivers-table thead th {
  position: sticky;
  top: 0;
  background: #16180f;
  color: #9dff3f;
  text-align: right;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: 0.78em;
  letter-spacing: 0.6px;
  padding: 0.9cqh 0.7cqw;
  border-bottom: 2px solid #3a4a1f;
  white-space: nowrap;
}
.drivers-table th.col-name, .drivers-table th.col-nr { text-align: left; }
.drivers-table th.col-expand { width: 3.6em; }
.drivers-table td.col-expand { text-align: center; }
/* purely decorative — the row itself is already the click target (see
   .clickable-row); this just signals "tap this row to open it" the same
   way the +/- .expand-btn column does elsewhere, for tables (ALL DROPIN)
   whose rows navigate straight to another page instead of expanding in
   place */
.drivers-table tbody tr.clickable-row td.col-expand .row-arrow-icon {
  color: #9dff3f;
  font-weight: 700;
  font-size: 1.3em;
  line-height: 1;
}

.drivers-table td {
  padding: 0.8cqh 0.7cqw;
  border-bottom: 1px solid #222;
  text-align: right;
  white-space: nowrap;
}
.drivers-table td.col-name, .drivers-table td.col-nr, .drivers-table td.col-status { text-align: left; }
.drivers-table td.mono { font-family: 'Orbitron', sans-serif; }
.drivers-table td.best-lap { color: #9dff3f; font-weight: 700; }
/* ALL DROPIN's session list — each row opens that session's lap detail */
.drivers-table tbody tr.clickable-row { cursor: pointer; transition: background 0.12s ease; }
.drivers-table tbody tr.clickable-row:hover { background: rgba(157,255,63,0.06); }
.drivers-table tbody tr.clickable-row td.col-name a { color: #9dff3f; font-weight: 700; text-decoration: none; }
.drivers-table tbody tr.clickable-row td.col-name a:hover { text-decoration: underline; }
/* the single fastest lap in a table (see MY STATISTICS BY TIME) — the
   whole row pulses gently so it's unmistakable at a glance, and the time
   itself carries a small labeled badge, not just a color change. */
@keyframes best-lap-pulse {
  0%, 100% { background: rgba(157,255,63,0.06); }
  50% { background: rgba(157,255,63,0.22); }
}
.drivers-table tr.best-lap-row {
  animation: best-lap-pulse 1.6s ease-in-out infinite;
}
.best-lap-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  margin-left: 0.6em;
  padding: 0.15em 0.6em;
  border-radius: 999px;
  border: 1px solid #9dff3f;
  background: rgba(157,255,63,0.14);
  color: #9dff3f;
  font-size: 0.7em;
  font-weight: 700;
  letter-spacing: 0.4px;
  vertical-align: middle;
  white-space: nowrap;
}
.best-lap-badge svg { width: 1.1em; height: 1.1em; flex-shrink: 0; }
.drivers-table td.col-name { color: #f2f2f2; font-weight: 600; }
/* the driver's name is the tap target that opens their full-page live
   view — underline-on-hover is the only hint on a table this dense, but
   it's a real link so touch devices get standard link affordance too. */
.driver-name-link { color: inherit; text-decoration: none; border-bottom: 1px dashed rgba(157,255,63,0.5); }
.driver-name-link:hover, .driver-name-link:active { color: #9dff3f; border-bottom-color: #9dff3f; }

/* S1/S2 sector columns: desktop only. A phone landscape screen is already
   tight enough that the swipe-to-scroll pattern above is the right
   tradeoff there — but on a desktop-sized window there's room to show
   them without needing that scroll at all, so this hides them by default
   and only reveals them (and drops the table's forced min-width so it
   fits the actual window instead of always demanding horizontal scroll)
   inside the same desktop breakpoint the rest of the site's desktop
   sizing already uses. Mobile is completely untouched by this rule. */
.col-desktop-only { display: none; }
@media (min-width: 860px) and (min-height: 500px) {
  .col-desktop-only { display: table-cell; }
  /* table-layout:auto (the mobile default) sizes columns off their
     unwrapped content width and simply grows past 100% when 13 columns
     don't fit — which is exactly what forced the sideways scroll on
     desktop. Fixed layout with an explicit width per column is the only
     way to GUARANTEE the table never exceeds its container, so this is a
     real layout mode switch, not just a min-width tweak. Percentages sum
     to <=100%, and the font is deliberately smaller than the mobile
     clamp() — the first pass here still left columns too narrow for their
     own "00:46.930"-style content at 14px, which didn't overflow the
     TABLE (fixed layout prevents that) but did visually overlap into the
     next cell, which read as broken/garbled. overflow:hidden below is a
     second, independent safety net: even if some content is still too
     wide for its column, it now clips inside its own cell instead of
     bleeding into the next one. */
  .drivers-table {
    table-layout: fixed;
    min-width: 0;
    font-size: 12px;
  }
  .drivers-table th, .drivers-table td {
    padding: 6px 4px;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .drivers-table th.col-pos, .drivers-table td.col-pos { width: 4%; }
  .drivers-table th.col-nr, .drivers-table td.col-nr { width: 5%; }
  .drivers-table th.col-name, .drivers-table td.col-name { width: 12%; }
  .drivers-table th.col-num, .drivers-table td.col-num { width: 8%; }
  .drivers-table th.col-status, .drivers-table td.col-status { width: 8%; }
  .drivers-table th.col-expand, .drivers-table td.col-expand { width: 4%; }
  .status-badge { padding: 0.15em 0.4em; }
  .kart-badge { padding: 0.1em 0.4em; }
  /* the table can no longer overflow, so the swipe hint (a mobile-only
     affordance) has nothing to do here — belt-and-braces on top of
     updateScrollHint() naturally computing is-scrollable as false now */
  .scroll-hint { display: none !important; }
}
.drivers-table td.empty-cell { text-align: center; color: #9a9a9a; padding: 3cqh 1cqw; white-space: normal; }

.driver-row.rank-1 { background: rgba(157,255,63,0.08); }
.driver-row.rank-1 td.col-pos { color: #9dff3f; font-weight: 700; }
.driver-row.is-you { background: rgba(157,255,63,0.05); }
.driver-row .you-tag { color: #9dff3f; font-size: 0.8em; }

/* MY STATISTICS "compare to others" leaderboard — the row(s) matching the
   driver's own kart at that track, picked out of the full ranked field */
.compare-you-row { background: rgba(157,255,63,0.09); }
.compare-you-row td { color: #eafccf; }
.compare-you-tag {
  display: inline-block;
  background: #9dff3f;
  color: #10230a;
  font-weight: 700;
  font-size: 0.7em;
  letter-spacing: 0.5px;
  padding: 0.2em 0.6em;
  border-radius: 8px;
}

/* any change to a driver's row (new lap, position, status) replays this
   flash once on the freshly-rendered <tr> so it's obvious at a glance
   which car just updated on a table that's otherwise repainted every
   second. Re-triggers naturally each poll since the row is rebuilt from
   scratch — no JS timer needed to clear the class. */
.driver-row.row-flash { animation: row-flash 1.1s ease-out; }
@keyframes row-flash {
  0% { background: rgba(157,255,63,0.45); }
  100% { background: transparent; }
}

/* small trend indicator in front of the kart number: greener/up when the
   driver's last lap beat their previous one, red/down when it was slower */
.trend-arrow {
  display: inline-block;
  font-size: 0.75em;
  line-height: 1;
  margin-right: 0.35em;
}
.trend-arrow.trend-up { color: #4ade80; }
.trend-arrow.trend-down { color: #ef4444; }

.kart-badge {
  display: inline-block;
  background: #2a2f1a;
  color: #d8ffb0;
  border-radius: 5px;
  padding: 0.15em 0.55em;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: 0.85em;
}

.delta-faster { color: #4ade80; }
.delta-slower { color: #ef4444; }

.status-badge {
  display: inline-block;
  padding: 0.2em 0.6em;
  border-radius: 10px;
  font-size: 0.78em;
  font-weight: 700;
  letter-spacing: 0.4px;
  /* every prior use of this class also adds a .status-* modifier that
     overrides this, but a badge with no modifier (e.g. team-timer's role
     badge) still needs a readable color instead of falling through to
     whatever black/dark default it would otherwise inherit */
  color: #f2f2f2;
  background: rgba(255,255,255,0.06);
}
.status-badge.status-running { background: rgba(157,255,63,0.15); color: #9dff3f; }
.status-badge.status-pit { background: rgba(245,158,11,0.18); color: #f5a623; }
.status-badge.status-finished { background: rgba(239,68,68,0.18); color: #ef4444; }
.status-badge.status-waiting { background: rgba(255,255,255,0.08); color: #9a9a9a; }

/* the + button is the ONLY way to open a driver's lap detail (tapping the
   row itself does nothing) — sized well past the table's own font scale
   so it stays a comfortable, unambiguous touch target on a phone */
.expand-btn {
  width: clamp(32px, 4.6cqh, 42px);
  height: clamp(32px, 4.6cqh, 42px);
  border-radius: 8px;
  border: 1.5px solid #4b6b1f;
  background: rgba(255,255,255,0.03);
  color: #9dff3f;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(16px, 2.6cqh, 21px);
  line-height: 1;
  cursor: pointer;
}
.expand-btn:active { background: rgba(157,255,63,0.2); }

.driver-detail-row td {
  background: rgba(0,0,0,0.35);
  padding: 0.9cqh 1cqw;
  white-space: normal;
}
.lap-detail-empty { color: #9a9a9a; font-size: 0.85em; text-align: center; padding: 0.6cqh 0; }
.lap-detail-table {
  width: 100%;
  max-width: 360px;
  border-collapse: collapse;
  font-size: 0.9em;
}
.lap-detail-table th {
  text-align: left;
  color: #9a9a9a;
  font-weight: 600;
  font-size: 0.8em;
  letter-spacing: 0.5px;
  padding: 0.2em 0.6em;
  border-bottom: 1px solid #2a2a2a;
}
.lap-detail-table td {
  padding: 0.25em 0.6em;
  font-family: 'Orbitron', sans-serif;
  color: #d8d8d8;
}
.lap-detail-table tr.lap-fastest td { color: #9dff3f; }
.lap-best-tag { font-size: 0.7em; color: #9dff3f; letter-spacing: 0.5px; }

/* ============== DRIVER VIEW (single-driver live page) ============== */
.driver-page-title {
  text-align: center;
  color: #f2f2f2;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(18px, 3.6cqh, 28px);
  letter-spacing: 1px;
  margin-bottom: 0.6cqh;
  flex-shrink: 0;
}

.driver-view-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  width: 100%;
  /* anchors .dv-current-corner — scoped to this page only, doesn't touch
     the shared .phone rule every other page also uses */
  position: relative;
}
.driver-view-body.driver-not-found .dv-lastlap,
.driver-view-body.driver-not-found .dv-stats-row { opacity: 0.45; }

/* LAST LAP is the page's main focus: centered, big, always the most
   recently completed lap — everything else here is supporting detail. */
.dv-lastlap {
  text-align: center;
  flex-shrink: 0;
  margin: 0.2cqh auto 0.6cqh;
}
.dv-lastlap-label {
  font-size: clamp(12px, 2.2cqh, 16px);
  letter-spacing: 1.5px;
  color: #9a9a9a;
  margin-bottom: 0.2cqh;
}
.time-display.dv-lastlap-display {
  font-size: clamp(36px, min(13cqh, 15cqw), 88px);
}
.dv-prev-line {
  margin-top: 0.3cqh;
  font-size: clamp(11px, 1.8cqh, 14px);
  color: #9a9a9a;
  letter-spacing: 0.5px;
}
.dv-prev-line #prevLapValue { color: #cfcfcf; font-family: 'Orbitron', sans-serif; font-weight: 700; }

.dv-stats-row {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 1cqh 3cqw;
  flex-shrink: 0;
  margin-bottom: 0.8cqh;
}
.dv-stat {
  min-width: 5.5em;
  text-align: center;
  border: 1.5px solid #4b6b1f;
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(157,255,63,0.05), rgba(0,0,0,0.2));
  padding: 0.7cqh 1.6cqw;
}
.dv-stat-label { font-size: clamp(10px, 1.7cqh, 13px); letter-spacing: 1.5px; color: #9a9a9a; margin-bottom: 0.25cqh; }
.dv-stat-value {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(15px, 2.6cqh, 20px);
  color: #f2f2f2;
}
.dv-stat-value.faster { color: #4ade80; }
.dv-stat-value.slower { color: #ef4444; }

/* ticking "current lap" badge, tucked in a corner instead of competing
   with LAST LAP for attention — tapping it opens the same clock full-size
   (see .dv-current-overlay), so it's sized to stay a clear, legible tap
   target rather than shrinking down to purely decorative size. */
.dv-current-corner {
  position: absolute;
  top: 0;
  right: 0;
  text-align: right;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  background: rgba(0,0,0,0.4);
  padding: 0.6cqh 1.4cqw;
  cursor: pointer;
  z-index: 2;
}
.dv-current-corner:hover, .dv-current-corner:focus-visible { border-color: #9dff3f; outline: none; }
.dv-current-label {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.35em;
  font-size: clamp(11px, 1.9cqh, 14px);
  letter-spacing: 1px;
  color: #9a9a9a;
  margin-bottom: 0.15cqh;
}
.dv-status-icon { width: 1.15em; height: 1.15em; flex-shrink: 0; }
.dv-current-time {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(18px, 3cqh, 25px);
  color: #cfe9a8;
  font-variant-numeric: tabular-nums;
}
.dv-current-time .dv-sep { color: #6b6b6b; margin: 0 0.05em; }

/* one glance at the corner badge's color/label tells you which of the
   four states this driver is in — matches the same green/amber/red
   vocabulary as the status badges in the All Drivers table. */
.dv-current-corner.status-running .dv-current-label { color: #9dff3f; }
.dv-current-corner.status-pit .dv-current-label,
.dv-current-corner.status-waiting .dv-current-label { color: #f5a623; }
.dv-current-corner.status-pit .dv-current-time,
.dv-current-corner.status-waiting .dv-current-time { color: #f5a623; }
.dv-current-corner.status-finished .dv-current-label { color: #ef4444; }
.dv-current-corner.status-finished .dv-current-time { color: #ef4444; }

@media (orientation: landscape) and (max-height: 500px) {
  .time-display.dv-lastlap-display { font-size: clamp(26px, min(16cqh, 11cqw), 50px); }
  .dv-stats-row { gap: 0.5cqh 2cqw; margin-bottom: 0.5cqh; }
  .dv-stat { padding: 0.4cqh 1.2cqw; min-width: 4.2em; }
  .dv-current-corner { padding: 0.3cqh 1cqw; }
  .dv-current-label { font-size: clamp(9px, 2.4cqh, 12px); }
  .dv-current-time { font-size: clamp(14px, 3.6cqh, 19px); }
}

/* full-screen "current lap" clock, opened by tapping the corner badge —
   same overlay chrome (header/close button) as the laps overlay below,
   reused rather than duplicated. */
.dv-current-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(5,5,5,0.98);
  display: flex;
  flex-direction: column;
  padding: max(2.4cqh, env(safe-area-inset-top)) max(3.5cqw, env(safe-area-inset-right)) max(2.4cqh, env(safe-area-inset-bottom)) max(3.5cqw, env(safe-area-inset-left));
}
.dv-current-overlay-body {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.time-display.dv-current-big-display {
  font-size: clamp(48px, min(20cqh, 20cqw), 140px);
}

/* brief animated flag overlay — shared by the green START flash (first
   time the current-lap clock starts ticking) and the checkered FINISHED
   flash (see playStartFlash()/playFinishFlash() in driver-view.js).
   pointer-events:none so it never blocks a tap on the page underneath. */
.dv-flag-flash {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: none;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 1.2cqh;
  pointer-events: none;
  background: radial-gradient(circle, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0) 68%);
}
.dv-flag-flash.show {
  display: flex;
  animation: finish-flash-pop 2.6s ease-in-out forwards;
}
.dv-flag-flash-svg { width: clamp(80px, 22cqh, 160px); height: clamp(80px, 22cqh, 160px); }
.dv-flag-flash-text {
  font-family: 'Orbitron', sans-serif;
  font-weight: 900;
  font-size: clamp(26px, 6.5cqh, 52px);
  letter-spacing: 3px;
}
.dv-flag-flash-text.start { color: #9dff3f; text-shadow: 0 0 20px rgba(157,255,63,0.6); }
.dv-flag-flash-text.finish { color: #ef4444; text-shadow: 0 0 20px rgba(239,68,68,0.6); }
@keyframes finish-flash-pop {
  0% { opacity: 0; transform: scale(0.6); }
  15% { opacity: 1; transform: scale(1.08); }
  25% { opacity: 1; transform: scale(1); }
  75% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.12); }
}

/* ============== LIVE LEADERBOARD: winner popup ==============
   Appears the instant every driver in the current heat has finished (see
   static/js/live-leaderboard.js), holds briefly, then auto-hides — a tap
   anywhere dismisses it early too. */
.winner-overlay {
  position: fixed;
  inset: 0;
  z-index: 400;
  background: rgba(5,5,5,0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4cqh 4cqw;
  cursor: pointer;
}
.winner-card {
  text-align: center;
  max-width: 480px;
  padding: 4cqh 5cqw;
  border: 2px solid #9dff3f;
  border-radius: 20px;
  background: linear-gradient(180deg, rgba(157,255,63,0.08), rgba(0,0,0,0.4));
  box-shadow: 0 0 60px rgba(157,255,63,0.25);
}
.winner-card.winner-anim { animation: winner-pop 0.6s cubic-bezier(0.2, 1.4, 0.4, 1) both; }
@keyframes winner-pop {
  0% { opacity: 0; transform: scale(0.6) translateY(20px); }
  70% { opacity: 1; transform: scale(1.05) translateY(0); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}
.winner-trophy {
  font-size: clamp(48px, 12cqh, 90px);
  line-height: 1;
  margin-bottom: 0.6cqh;
  animation: winner-bounce 1.6s ease-in-out infinite;
}
@keyframes winner-bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}
.winner-label {
  color: #9dff3f;
  font-weight: 800;
  letter-spacing: 4px;
  font-size: clamp(13px, 2.4cqh, 17px);
  margin-bottom: 0.6cqh;
}
.winner-name {
  font-family: 'Orbitron', sans-serif;
  font-weight: 800;
  font-size: clamp(24px, 5.5cqh, 40px);
  color: #f2f2f2;
  text-shadow: 0 0 16px rgba(157,255,63,0.4);
  margin-bottom: 0.6cqh;
}
.winner-meta {
  color: #cfcfcf;
  font-size: clamp(13px, 2.2cqh, 16px);
}
.winner-history {
  margin-top: 1cqh;
  padding-top: 1cqh;
  border-top: 1px solid rgba(157,255,63,0.25);
  color: #9dff3f;
  font-size: clamp(12px, 2cqh, 15px);
}

/* registered-vs-guest badge next to a name on the Live Leaderboard —
   deliberately tiny and monochrome-ish, a glance-level detail, not
   another loud color competing with the rank/status badges */
.reg-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.3em;
  height: 1.3em;
  border-radius: 50%;
  font-size: 0.75em;
  font-weight: 800;
  vertical-align: middle;
  margin-right: 0.2em;
}
.reg-badge.reg-yes { background: rgba(157,255,63,0.18); color: #9dff3f; border: 1px solid rgba(157,255,63,0.5); }
.reg-badge.reg-no { background: rgba(255,255,255,0.06); color: #9a9a9a; border: 1px solid rgba(255,255,255,0.15); }

/* the whole small laps table is one big tap target that opens the same
   table full-screen (see .dv-laps-overlay) — a phone-width table can only
   show so many rows/columns comfortably at once. */
.full-laps-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  cursor: pointer;
}
.full-laps-wrap:hover, .full-laps-wrap:focus-visible { border-color: #9dff3f; outline: none; }
.full-laps-hint {
  position: sticky;
  top: 0.4cqh;
  float: right;
  margin: 0.4cqh 0.6cqw 0 0;
  font-size: clamp(9px, 1.5cqh, 12px);
  font-weight: 700;
  letter-spacing: 0.5px;
  color: #0a1a02;
  background: #9dff3f;
  padding: 0.25em 0.7em;
  border-radius: 10px;
  pointer-events: none;
  z-index: 3;
}

/* ============== COMPARE TO OTHERS — your own row/tag in the leaderboard ============== */
.compare-you-row { background: rgba(157,255,63,0.09); }
.compare-you-row td { color: #eafccf; }
.compare-you-tag {
  display: inline-block;
  background: #9dff3f;
  color: #10230a;
  font-weight: 700;
  font-size: 0.7em;
  letter-spacing: 0.5px;
  padding: 0.2em 0.6em;
  border-radius: 8px;
}

/* ============== STATISTICS PAGE — simple bar chart (busiest days) ==============
   Portrait, phone-shell page (see templates/stats_mobile.html) — no
   rotate-notice/orientation-lock here on purpose, unlike the landscape-only
   pages, since this one is meant to be read one-handed like the dashboard. */
.bar-chart-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  flex-shrink: 0;
  margin-bottom: 1cqh;
}
.bar-chart {
  display: flex;
  align-items: flex-start;
  gap: 2cqw;
  padding: 1cqh 1cqw 0;
  width: max-content;
  min-width: 100%;
  box-sizing: border-box;
}
.bar-chart .bar-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 13cqw;
  min-width: 52px;
  flex-shrink: 0;
}
/* the bar's percentage height needs a fixed-height ancestor to resolve
   against — kept separate from bar-value/bar-label so a long, wrapped
   track name can't get squeezed into (and overflow/overlap) that same
   fixed box; the label grows freely underneath instead. */
.bar-chart .bar-track {
  height: 16cqh;
  min-height: 90px;
  width: 100%;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  border-bottom: 1.5px solid #2a2a2a;
}
.bar-chart .bar {
  width: 60%;
  min-width: 12px;
  max-width: 26px;
  background: linear-gradient(180deg, #b6ff4f, #7fcc1f);
  border-radius: 4px 4px 0 0;
  min-height: 3px;
  transform-origin: bottom;
  animation: bar-chart-grow 0.5s cubic-bezier(0.2, 0.9, 0.3, 1) both;
}
@keyframes bar-chart-grow {
  0% { transform: scaleY(0); opacity: 0; }
  100% { transform: scaleY(1); opacity: 1; }
}
/* full label, never truncated — long track names wrap onto further lines
   instead of being sliced to a few unreadable characters, or overlapping
   the neighboring column */
.bar-chart .bar-label {
  color: #9a9a9a;
  font-size: clamp(9px, 1.5cqh, 11px);
  margin-top: 0.6cqh;
  white-space: normal;
  text-align: center;
  line-height: 1.25;
  word-break: break-word;
  max-width: 100%;
}
.bar-chart .bar-value {
  color: #cfe9a8;
  font-size: clamp(8px, 1.3cqh, 10px);
  margin-bottom: 0.3cqh;
  white-space: nowrap;
}

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4cqh 3cqw;
  margin-bottom: 0.8cqh;
  flex-shrink: 0;
}
.chart-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-size: clamp(10px, 1.7cqh, 13px);
  color: #cfcfcf;
}
.chart-legend-dot { width: 0.8em; height: 0.8em; border-radius: 50%; flex-shrink: 0; }

/* ============== TEAM STOPWATCH — role select + online indicator ============== */
.role-select {
  display: flex;
  gap: 2.5cqw;
  width: 100%;
  max-width: 560px;
  justify-content: center;
}
.role-card {
  /* a <button>'s native platform styling can otherwise fight with the
     inherited text color below on some browsers/OSes — reset it so this
     is a plain styled box, not a system button */
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  flex: 1;
  max-width: 220px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5cqh;
  border: 1.5px solid #4b6b1f;
  border-radius: 10px;
  background: rgba(255,255,255,0.02);
  padding: 1.8cqh 1.5cqw;
  cursor: pointer;
  color: #cfcfcf;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.role-card:hover { border-color: #9dff3f; background: rgba(157,255,63,0.06); }
.role-card.active { border-color: #9dff3f; background: rgba(157,255,63,0.14); color: #eafccf; }

/* ============== WELCOME PAGE: SPLASH SCREEN ==============
   Shown for a moment on first load of the welcome page, admin-toggleable
   (see admin_dashboard.html's SPLASH SCREEN card) with an admin-editable
   duration. Reuses the same logo mark / Orbitron wordmark as the rest of
   the app so it reads as part of one design, not a separate loading
   library bolted on. Sits on top of the already-rendered welcome page
   (no layout shift, nothing to wait on) and fades itself out. */
.splash-screen {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: #0a0a0a;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2.4vh;
  transition: opacity 0.6s ease, visibility 0.6s ease;
}
.splash-screen.is-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.splash-logo-mark {
  width: clamp(56px, 14vh, 96px);
  height: clamp(56px, 14vh, 96px);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
  transform: skewX(-10deg);
  border-radius: 4px;
  overflow: hidden;
  animation: splash-logo-in 0.7s cubic-bezier(0.2, 1.4, 0.4, 1) both;
}
.splash-logo-mark span { background: #e8e8e8; }
.splash-logo-mark span:nth-child(odd) { background: #1a1a1a; }
.splash-logo-mark span:nth-child(4n+1), .splash-logo-mark span:nth-child(4n) { background: #9dff3f; }
@keyframes splash-logo-in {
  0% { opacity: 0; transform: skewX(-10deg) scale(0.4); }
  100% { opacity: 1; transform: skewX(-10deg) scale(1); }
}
.splash-logo-text {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(20px, 4.5vh, 32px);
  letter-spacing: 1px;
  line-height: 1.1;
  text-align: center;
  opacity: 0;
  animation: splash-fade-up 0.6s ease 0.25s both;
}
.splash-logo-text .k1 { color: #ffffff; }
.splash-logo-text .k2 { color: #9dff3f; display: block; }
.splash-progress {
  width: min(180px, 40vw);
  height: 3px;
  border-radius: 3px;
  background: rgba(157,255,63,0.15);
  overflow: hidden;
  opacity: 0;
  animation: splash-fade-up 0.6s ease 0.4s both;
}
.splash-progress-bar {
  height: 100%;
  width: 0%;
  background: #9dff3f;
  box-shadow: 0 0 8px rgba(157,255,63,0.6);
  border-radius: 3px;
  animation-name: splash-fill;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}
@keyframes splash-fade-up {
  0% { opacity: 0; transform: translateY(8px); }
  100% { opacity: 1; transform: translateY(0); }
}
@keyframes splash-fill {
  from { width: 0%; }
  to { width: 100%; }
}
.role-card-icon { width: clamp(28px, 5cqh, 40px); height: clamp(28px, 5cqh, 40px); color: #9dff3f; }
.role-card-icon svg { width: 100%; height: 100%; }
/* explicit color on both, rather than relying on inheritance from the
   button — the reported bug was WATCHER's title rendering invisible/black */
.role-card-title { display: block; color: #eaeaea; font-family: 'Orbitron', sans-serif; font-weight: 700; letter-spacing: 1px; font-size: clamp(13px, 2.2cqh, 17px); }
.role-card.active .role-card-title { color: #eafccf; }
.role-card-sub { display: block; font-size: clamp(10px, 1.6cqh, 13px); color: #9a9a9a; text-align: center; }

.online-indicator-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6cqw;
  margin-top: 0.8cqh;
  font-size: clamp(11px, 1.8cqh, 14px);
  color: #9a9a9a;
}
.online-dot {
  width: 0.7em;
  height: 0.7em;
  border-radius: 50%;
  background: #ef4444;
  box-shadow: 0 0 6px #ef4444;
  flex-shrink: 0;
  transition: background 0.2s ease, box-shadow 0.2s ease;
}
.online-dot.online { background: #4ade80; box-shadow: 0 0 6px #4ade80; }
.lap-detail-table.full { max-width: none; font-size: clamp(14px, 2.2cqh, 18px); }
.lap-detail-table.full th { position: sticky; top: 0; background: #16180f; padding: 0.6em 0.8em; border-bottom: 2px solid #3a4a1f; }
.lap-detail-table.full td { padding: 0.5em 0.8em; }

@media (orientation: landscape) and (max-height: 500px) {
  .driver-page-title { font-size: clamp(15px, 4.2cqh, 20px); margin-bottom: 0.4cqh; }
}

/* ============== DRIVER VIEW: full-screen lap history overlay ==============
   Covers the whole device viewport (not just the .phone card) — on a real
   phone .phone already IS full-bleed, so this lines up exactly; on the
   desktop card view it's a standard full-viewport modal, which is fine
   since it's an explicit, dismissible overlay either way. */
.dv-laps-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(5,5,5,0.98);
  display: flex;
  flex-direction: column;
  padding: max(2.4cqh, env(safe-area-inset-top)) max(3.5cqw, env(safe-area-inset-right)) max(2.4cqh, env(safe-area-inset-bottom)) max(3.5cqw, env(safe-area-inset-left));
}
.dv-laps-overlay-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
  margin-bottom: 1.6cqh;
}
.dv-laps-overlay-title {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(18px, 3.4cqh, 28px);
  color: #9dff3f;
  letter-spacing: 1.5px;
}
.dv-laps-overlay-close {
  width: clamp(38px, 6.4cqh, 52px);
  height: clamp(38px, 6.4cqh, 52px);
  padding: 0;
  border-radius: 50%;
  border: 1.5px solid rgba(255,79,79,0.5);
  background: rgba(255,79,79,0.08);
  color: #ff8080;
  font-size: clamp(22px, 4.2cqh, 30px);
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  /* a plain <button> with just line-height:1 doesn't actually center the
     × glyph inside a round button — this is what makes it a real,
     evenly-centered circle instead of the × sitting off to one side */
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.dv-laps-overlay-close:hover { background: rgba(255,79,79,0.18); border-color: #ff4f4f; color: #ffb3b3; }
.dv-laps-overlay-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
}
.lap-detail-table.big { font-size: clamp(16px, 2.8cqh, 23px); }
.lap-detail-table.big th { padding: 0.7em 0.9em; }
.lap-detail-table.big td { padding: 0.55em 0.9em; }

/* live status banner (All Drivers page) */
.live-status-banner {
  width: 100%;
  max-width: 900px;
  margin: 0 auto 1cqh;
  text-align: center;
  font-size: clamp(12px, 1.9cqh, 15px);
  color: #9a9a9a;
  letter-spacing: 0.4px;
  flex-shrink: 0;
}
.live-status-banner.stale { color: #ffb84d; }
.live-status-dot {
  display: inline-block;
  width: 0.6em;
  height: 0.6em;
  border-radius: 50%;
  background: #9dff3f;
  margin-right: 0.5em;
  box-shadow: 0 0 6px rgba(157,255,63,0.8);
  animation: live-pulse 1.4s ease-in-out infinite;
}
.live-status-banner.stale .live-status-dot { background: #ffb84d; box-shadow: 0 0 6px rgba(255,184,77,0.8); animation: none; }
@keyframes live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

.home-bar {
  width: 90px;
  max-width: 22cqw;
  height: 4px;
  background: #555;
  border-radius: 3px;
  margin: 0.5cqh auto 0;
  flex-shrink: 0;
}
