/* =============================================================================
 * results.stintbox.dk — Phase 1 stylesheet.
 *
 * Design tokens are scoped per-theme:
 *   - default: light/dark auto from prefers-color-scheme (data-theme="auto")
 *   - data-theme="sun": forced "Solskin" override — extra-high contrast,
 *                       brighter background, near-black text. Designed for use
 *                       in direct sunlight at a rally venue.
 * Light backdrop is intentionally #FAFAF7 (off-white) — pure white burns in
 * direct sun.
 * ===========================================================================*/

:root,
:root[data-theme="auto"] {
  /* light defaults */
  --bg: #FAFAF7;
  --surface: #ffffff;
  --surface-2: #f1f1ec;
  --surface-3: #e6e6df;
  --border: #d8d8d2;
  --border-strong: #b6b6ae;
  --text: #0e1116;
  --text-muted: #4a525a;
  --accent: #0a4d8c;
  --accent-on: #ffffff;
  --good: #1f7a3a;
  --warn: #8a5a00;
  --bad: #b3261e;
  --status-prov-bg: #fff7e0;
  --status-prov-border: #c08300;
  --status-prov-text: #5a3d00;
  --status-off-bg: #e3f4e8;
  --status-off-border: #1f7a3a;
  --status-off-text: #0e3b1c;
  --pb-bg: #f4ebff;
  --pb-fg: #5b21b6;
  --pb-border: #8b5cf6;
  --cb-bg: #e3f1fb;
  --cb-fg: #0a3b66;
  --cb-border: #2563ad;
  --ob-bg: #fff4cc;
  --ob-fg: #6b4f00;
  --ob-border: #b58a00;
  /* Mærke-tokens (slot-skabelon) — én diskret farve per slot.
     WCAG AA tekstkontrast >= 4.5:1 på --surface og row-tint, og en luminans-
     trappe der bevarer skelnelighed under deuteranopia. Form (★▣▲●✚◆) er
     primær signal; farve er reinforcement.
       1=halm    (gylden,   Mine kørere)
       2=mose    (skovgrøn, Konkurrenter)
       3=hav     (navy,     Holdet)
       4=skifer  (mørk teal, Interessante)
       5=vinrod  (bordeaux, Klubvenner)
       6=sten    (grafit,   Andet) */
  --tag-1: #8a5a00;
  --tag-2: #157a37;
  --tag-3: #1f4f8c;
  --tag-4: #0e6b73;
  --tag-5: #9c2858;
  --tag-6: #2e2e36;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.04);
  --shadow-strong: 0 4px 16px rgba(0, 0, 0, 0.12);
  --radius: 10px;
  --radius-sm: 6px;
  --radius-pill: 999px;
}

@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] {
    --bg: #0e1116;
    --surface: #161b22;
    --surface-2: #1f2630;
    --surface-3: #2a3340;
    --border: #2a3340;
    --border-strong: #3b4555;
    --text: #e6edf3;
    --text-muted: #9aa4af;
    --accent: #58a6ff;
    --accent-on: #0e1116;
    --good: #3fb950;
    --warn: #d29922;
    --bad: #f85149;
    --status-prov-bg: rgba(210,153,34,0.10);
    --status-prov-border: #d29922;
    --status-prov-text: #f0c674;
    --status-off-bg: rgba(63,185,80,0.10);
    --status-off-border: #3fb950;
    --status-off-text: #84e69a;
    --pb-bg: rgba(139,92,246,0.18);
    --pb-fg: #cdb6ff;
    --pb-border: #8b5cf6;
    --cb-bg: rgba(88,166,255,0.18);
    --cb-fg: #b6d4ff;
    --cb-border: #58a6ff;
    --ob-bg: rgba(210,153,34,0.18);
    --ob-fg: #ffd76a;
    --ob-border: #d29922;
    /* Mørk-mode mærketokens — lysere peers med god luminance-spredning. */
    --tag-1: #e6c168;
    --tag-2: #5cd683;
    --tag-3: #88ccee;
    --tag-4: #44aa99;
    --tag-5: #ee99aa;
    --tag-6: #888e98;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);
    --shadow-strong: 0 4px 16px rgba(0, 0, 0, 0.5);
  }
}

/* Forced dark mode — same tokens as auto-dark, but applied regardless of OS. */
:root[data-theme="dark"] {
  --bg: #0e1116;
  --surface: #161b22;
  --surface-2: #1f2630;
  --surface-3: #2a3340;
  --border: #2a3340;
  --border-strong: #3b4555;
  --text: #e6edf3;
  --text-muted: #9aa4af;
  --accent: #58a6ff;
  --accent-on: #0e1116;
  --good: #3fb950;
  --warn: #d29922;
  --bad: #f85149;
  --status-prov-bg: rgba(210,153,34,0.10);
  --status-prov-border: #d29922;
  --status-prov-text: #f0c674;
  --status-off-bg: rgba(63,185,80,0.10);
  --status-off-border: #3fb950;
  --status-off-text: #84e69a;
  --pb-bg: rgba(139,92,246,0.18);
  --pb-fg: #cdb6ff;
  --pb-border: #8b5cf6;
  --cb-bg: rgba(88,166,255,0.18);
  --cb-fg: #b6d4ff;
  --cb-border: #58a6ff;
  --ob-bg: rgba(210,153,34,0.18);
  --ob-fg: #ffd76a;
  --ob-border: #d29922;
  /* Forced-mørk mærketokens — duplicate af auto-mørk. */
  --tag-1: #e6c168;
  --tag-2: #5cd683;
  --tag-3: #88ccee;
  --tag-4: #44aa99;
  --tag-5: #ee99aa;
  --tag-6: #888e98;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);
  --shadow-strong: 0 4px 16px rgba(0, 0, 0, 0.5);
}

/* Solskin: forced extra-contrast palette. Same colour roles as light, but
   pushed for outdoor readability. */
:root[data-theme="sun"] {
  --bg: #ffffff;
  --surface: #ffffff;
  --surface-2: #f4f4f0;
  --surface-3: #e6e6df;
  --border: #000000;
  --border-strong: #000000;
  --text: #000000;
  --text-muted: #1a1a1a;
  --accent: #002f6c;
  --accent-on: #ffffff;
  --good: #0d5c2a;
  --warn: #5a3d00;
  --bad: #8a0e09;
  --status-prov-bg: #fff3b8;
  --status-prov-border: #5a3d00;
  --status-prov-text: #2a1c00;
  --status-off-bg: #c9eed2;
  --status-off-border: #0d5c2a;
  --status-off-text: #052f15;
  --pb-bg: #efe1ff;
  --pb-fg: #2a0e6e;
  --pb-border: #2a0e6e;
  --cb-bg: #d2e6f7;
  --cb-fg: #001f4a;
  --cb-border: #001f4a;
  --ob-bg: #ffe999;
  --ob-fg: #3b2700;
  --ob-border: #3b2700;
  /* Solskin: maks-kontrast mærkefarver — pushet mod næsten-AAA på hvid. */
  --tag-1: #7a4a00; /* halm */
  --tag-2: #0d6b3a; /* mose */
  --tag-3: #0a2d5c; /* hav */
  --tag-4: #0e6b73; /* skifer */
  --tag-5: #7a0e34; /* vinrod */
  --tag-6: #3a3d44; /* sten */
}

/* -----------------------------------------------------------------------------
 * Base
 * ---------------------------------------------------------------------------*/
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

body {
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  /* Tabular figures everywhere — kept consistent across rows. */
  font-variant-numeric: tabular-nums;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Min 44px touch targets on interactive controls. */
button, [role="button"] { min-height: 44px; }

/* Screen-reader only content. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* -----------------------------------------------------------------------------
 * Site chrome
 * ---------------------------------------------------------------------------*/
.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 30;
  /* GPU-composite layer to suppress sub-pixel rendering artifacts during
     scroll. Without this, mobile WebKit can show a 1-2px hairline of body
     content above the sticky bar between scroll snapshots. */
  will-change: transform;
  transform: translateZ(0);
}
.brand { font-weight: 700; color: var(--text); letter-spacing: -0.01em; }
.site-header nav { display: flex; align-items: center; gap: 14px; }
.site-header nav a { color: var(--text-muted); }
.theme-toggle {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 6px 10px;
  color: var(--text);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
}
.theme-toggle[aria-pressed="true"] { background: var(--ob-bg); border-color: var(--ob-border); color: var(--ob-fg); }
.theme-toggle-icon::before {
  content: "☀";
  font-size: 16px;
  line-height: 1;
}
.container { max-width: 1100px; margin: 0 auto; padding: 18px 16px 120px; }
/* Race page is data-dense (Tabel spreadsheet, Detaljer 4-cell run grid) and
   benefits from a wider canvas than other routes. Cap at 1800px so content
   keeps a ~305px gutter on 2410px monitors (avoids the "lost at sea" feel
   of pure edge-to-edge), and fills viewport-minus-32px on smaller screens.
   Other routes stay at 1100px so prose stays readable. */
.container[data-page="race"] { max-width: min(1800px, calc(100vw - 32px)); }
.site-footer { padding: 30px 16px; text-align: center; color: var(--text-muted); }

h1 { margin: 0 0 8px; font-size: clamp(22px, 2vw + 14px, 28px); font-weight: 700; letter-spacing: -0.01em; }
h2 { margin: 22px 0 10px; font-size: 18px; font-weight: 600; }

/* -----------------------------------------------------------------------------
 * Race header + status pill
 * ---------------------------------------------------------------------------*/
.race-header {
  position: sticky;
  /* Stick exactly under the page header, with a 1-px overlap to absorb
     sub-pixel rendering gaps that would otherwise reveal a hairline of
     scrolling content (often a class-color border-flag) between the bars. */
  top: calc(var(--header-h, 60px) - 1px);
  z-index: 20;
  background: var(--bg);
  padding: 10px 0;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--border);
  /* Force a GPU-composited layer so sub-pixel scroll positions don't leave
     a 1-2px gap of body content visible at the bottom or top edge. */
  will-change: transform;
  transform: translateZ(0);
}
.race-header-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.race-meta { color: var(--text-muted); font-size: 13px; display: flex; gap: 12px; align-items: center; margin-top: 4px; flex-wrap: wrap; }

/* Weather pill — newspaper aesthetic. Hairline border + sharp edges + flat
   surface to match motorsport-timing pages. NO rounded card / drop-shadow /
   left-stripe accent (those are AI-design tropes — see CLAUDE.md). */
.weather-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
  border-radius: 2px;
}
.weather-pill[hidden] { display: none; }
.weather-pill { cursor: pointer; }
.weather-pill:focus-visible { outline: 2px solid var(--focus, currentColor); outline-offset: 1px; }
.weather-pill-icon {
  font-size: 14px;
  line-height: 1;
  transform: translateY(-0.5px);
}
.weather-pill-text { white-space: nowrap; }

/* Expanded provenance panel — same aesthetic as the pill. Hairline border,
   sharp edges, no shadow, no rounding. Anchored under the pill via the meta
   container's flow. */
.weather-panel {
  display: block;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 12px;
  line-height: 1.45;
  padding: 8px 10px;
  margin-top: 6px;
  max-width: 280px;
  border-radius: 0;
  box-shadow: none;
}
.weather-panel[hidden] { display: none; }
.weather-panel-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 0 0 6px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
.weather-panel-condition { font-weight: 600; font-size: 13px; }
.weather-panel-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1px 8px;
  margin: 0 0 6px;
  font-variant-numeric: tabular-nums;
}
.weather-panel-grid dt { color: var(--text-muted); font-weight: 500; }
.weather-panel-grid dd { margin: 0; }
.weather-panel-grid dt[hidden],
.weather-panel-grid dd[hidden] { display: none; }
.weather-panel-row { display: flex; gap: 6px; margin: 0 0 4px; flex-wrap: wrap; }
.weather-panel-row[hidden] { display: none; }
.weather-panel-label { font-weight: 600; }
.weather-panel-value { font-variant-numeric: tabular-nums; }
.weather-panel-note {
  margin: 4px 0 0;
  font-style: italic;
  color: var(--text-muted);
}
.weather-panel-attribution {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 11px;
}

/* Per-run weather chip — Detaljer mode only. Tabular numerals, muted color
   so it doesn't compete with run-time. Buttoned so it's tap/keyboard-accessible
   for the per-run popover; reset native button chrome to keep it inline. */
.run-weather {
  display: none;
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 2px;
  white-space: nowrap;
  /* Reset native button styling — chip should look inline, not like a button */
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
  text-align: left;
}
.run-weather:focus-visible { outline: 1px dashed currentColor; outline-offset: 2px; }
.run-weather:hover { color: var(--text); }
.run-weather-icon { margin-right: 2px; }
.run-weather-temp { margin-right: 6px; }
.run-weather-wind { margin-right: 6px; }
.run-weather-precip { font-weight: 500; color: var(--text); }
body.mode-details .run-weather { display: inline-flex; align-items: baseline; gap: 2px; }

/* Per-run weather popover. Page-level singleton; positioned by JS via fixed.
   Newspaper aesthetic: hairline, sharp corners, no shadow. */
.run-weather-popover {
  position: fixed;
  z-index: 50;
  min-width: 200px;
  max-width: 260px;
  padding: 8px 10px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  box-shadow: none;
  font-size: 12px;
  line-height: 1.45;
}
.run-weather-popover[hidden] { display: none; }
.run-weather-popover-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 0 0 4px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 4px;
}
.run-weather-popover-condition { font-weight: 600; }
.run-weather-popover-close {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  font-size: 16px;
  line-height: 1;
  padding: 0 0 0 8px;
  cursor: pointer;
}
.run-weather-popover-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1px 8px;
  margin: 0 0 6px;
  font-variant-numeric: tabular-nums;
}
.run-weather-popover-grid dt {
  color: var(--text-muted);
  font-weight: 500;
}
.run-weather-popover-grid dd { margin: 0; }
.run-weather-popover-source {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px solid var(--border);
  font-size: 11px;
}
.run-weather-popover-source [data-rwp-source-label] { font-weight: 600; }
.run-weather-popover-source [data-rwp-source-detail] { color: var(--text-muted); }
.run-weather-popover-time {
  font-size: 11px;
  color: var(--text-muted);
}
.run-weather-popover-note {
  margin-top: 4px;
  font-size: 11px;
  font-style: italic;
  color: var(--text-muted);
}
.run-weather-popover-note[hidden] { display: none; }

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  border: 2px solid transparent;
}
.status-pill-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}
.status-pill-provisional {
  background: var(--status-prov-bg);
  color: var(--status-prov-text);
  border-color: var(--status-prov-border);
  border-style: dashed;
}
.status-pill-provisional .status-pill-dot { animation: pulse 1.6s ease-in-out infinite; }
.status-pill-official {
  background: var(--status-off-bg);
  color: var(--status-off-text);
  border-color: var(--status-off-border);
  border-style: solid;
}
.status-pill-completed {
  background: var(--surface-2);
  color: var(--fg-muted);
  border-color: var(--border);
  border-style: solid;
}
.status-pill-completed .status-pill-dot {
  background: var(--fg-muted);
  /* Static — race is done, nothing to pulse for. */
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.5; transform: scale(0.7); }
}
@media (prefers-reduced-motion: reduce) {
  .status-pill-provisional .status-pill-dot { animation: none; }
}

/* Click-to-refresh: when Provisorisk data is older than the threshold (set
   by live.js via .is-stale + .is-refreshable), the pill becomes a button.
   Subtle hover bump signals it's interactive without screaming. */
.status-pill.is-refreshable {
  cursor: pointer;
  transition: filter 120ms ease, transform 120ms ease;
}
.status-pill.is-refreshable:hover { filter: brightness(0.95); transform: scale(1.02); }
.status-pill.is-refreshable.is-stale {
  /* Tone shifts slightly amber to signal "data is getting old". */
  border-color: var(--warn);
  color: var(--warn);
}
.status-pill.is-refreshable.is-stale .status-pill-dot { background: var(--warn); }
.status-pill.is-busy {
  cursor: progress;
  pointer-events: none;
  opacity: 0.7;
}
.status-pill.is-busy .status-pill-dot { animation: pulse 0.8s ease-in-out infinite; }

/* Offline read-mode indicator.
   Newspaper aesthetic: hairline border, sharp edges, tabular numerals.
   Sits BELOW the sticky site-header (so it doesn't cover the theme/settings
   buttons) and OVERLAYS the page content (so toggling it visible doesn't
   shift the page below). The header's own JS sets `--header-h` to the
   measured header height so the indicator lines up exactly under the bar
   regardless of viewport size. */
.offline-indicator {
  position: fixed;
  /* Overlap the site-header by 1px to absorb sub-pixel gaps that would
     otherwise reveal a 1-2px hairline of body content between the bar and
     the indicator. */
  top: calc(var(--header-h, 60px) - 1px);
  left: 0;
  right: 0;
  z-index: 29;
  padding: 7px 12px 6px;
  font: 600 12px/1.2 inherit;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  text-align: center;
  border-bottom: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
}
.offline-indicator[data-state="offline"] {
  background: var(--warn);
  color: var(--bg);
  border-bottom-color: var(--warn);
}
.offline-indicator[data-state="stale"] {
  background: var(--surface-2);
  color: var(--text-muted);
}
.offline-indicator[hidden] { display: none; }

/* Legacy status chips (used in lists / admin). */
.status {
  display: inline-block;
  padding: 2px 10px;
  font-size: 12px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.status-active { color: var(--good); border-color: var(--good); }
.status-dormant { color: var(--warn); border-color: var(--warn); }
.status-archived { color: var(--text-muted); }

/* -----------------------------------------------------------------------------
 * Index list
 * ---------------------------------------------------------------------------*/
.race-list { list-style: none; padding: 0; margin: 12px 0; }
.race-list li {
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 8px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: var(--shadow);
}

/* -----------------------------------------------------------------------------
 * Heat / class chips
 * ---------------------------------------------------------------------------*/
.heat-tabs, .grid-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0; }
.heat-tab, .chip {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 8px 14px;
  border-radius: var(--radius-pill);
  cursor: pointer;
  font-size: 14px;
  min-height: 40px;
}
.heat-tab.active, .chip.active {
  background: var(--accent);
  color: var(--accent-on);
  border-color: var(--accent);
  font-weight: 600;
}

/* -----------------------------------------------------------------------------
 * Row cards
 * ---------------------------------------------------------------------------*/
/* No AI-design tropes: hairline rules, sharp edges, no card chrome on rows.
 * Class color shows as a small flag, never a rounded left-stripe. */
.row-cards {
  list-style: none;
  padding: 0;
  margin: 8px 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  border-top: 1px solid var(--border);
}
/* ---------------------------------------------------------------------------
 * Row-card layout — newspaper aesthetic, 2-column outer grid (left rail +
 * content). The rail hosts the tag/follow button so it sits in the SAME
 * screen-x as Tabel mode's .t-fav column. The content column hosts a 2-row
 * grid: top line is rank/id/name/time/menu; second line is co-driver · car ·
 * weather chip (Detaljer mode only — hidden in Hurtig).
 * ------------------------------------------------------------------------ */
.row-card {
  position: relative;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  padding: 8px 12px 8px 4px;
  box-shadow: none;
  display: grid;
  grid-template-columns: 36px 1fr;
  column-gap: 8px;
  align-items: start;
}
.row-card.is-me {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  outline: none;
  font-weight: 600;
}
.row-card.is-following {
  background: color-mix(in srgb, var(--ob-bg) 50%, transparent);
}
/* Class flag — small solid block in front of class label, NOT a left-stripe. */
.row-class-flag {
  display: inline-block;
  width: 10px;
  height: 10px;
  background: var(--class-color, var(--border-strong));
  margin-right: 4px;
  vertical-align: -1px;
}

/* Left rail tag/follow button — single visual primitive across all 3 modes.
   `min-height` override neutralises the global 44px touch-target rule which
   would stretch this icon-button to 44px tall and break the row-card grid. */
.row-tag {
  position: relative;
  grid-column: 1;
  grid-row: 1 / -1;            /* spans the full row including .row-runs */
  align-self: start;
  margin-top: 4px;
  width: 32px;
  height: 32px;
  min-height: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  cursor: pointer;
  padding: 0;
  /* iOS: suppress long-press text-selection + callout on neighbour cells / picker labels. */
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  user-select: none;
  touch-action: manipulation;
}
.row-tag svg { width: 18px; height: 18px; display: block; }
.row-tag:hover { color: var(--text); border-color: var(--text-muted); }
.row-tag[aria-pressed="true"] {
  background: color-mix(in srgb, var(--tag-color, var(--ob-bg)) 18%, var(--surface));
  color: var(--tag-color, var(--ob-fg));
  border-color: color-mix(in srgb, var(--tag-color, var(--ob-border)) 60%, var(--border));
}
.row-tag[data-tag-count]:not([data-tag-count="0"]):not([data-tag-count="1"])::after {
  content: attr(data-tag-count);
  position: absolute;
  bottom: -2px;
  right: -4px;
  font-size: 9px;
  font-weight: 700;
  color: var(--tag-color, var(--text));
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 3px;
  line-height: 1.2;
}

/* Inner 2-row grid: top line + (Detaljer-only) meta line. */
.row-card-head {
  grid-column: 2;
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto auto;
  grid-template-areas:
    "rank id   name  time menu"
    "meta meta meta  meta meta";
  align-items: baseline;
  column-gap: 10px;
  row-gap: 2px;
  min-width: 0;
}
.row-rank {
  grid-area: rank;
  font-weight: 700;
  font-size: 18px;
  min-width: 36px;
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.row-rank-class { color: var(--text-muted); font-size: 12px; font-weight: 500; }
.row-id {
  grid-area: id;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
  color: var(--text-muted);
}
.row-nr { font-weight: 700; color: var(--text); font-size: 14px; }
.row-class { font-size: 11px; }
.row-name {
  grid-area: name;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.row-driver { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row-city { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row-time { grid-area: time; text-align: right; }
.row-total { font-weight: 700; font-size: 16px; display: block; }
.row-gap { font-size: 12px; color: var(--text-muted); display: block; }

/* Detaljer-mode second line. Co-driver · car · weather chip. Single line,
   ellipsizes from the longest field (.row-car) first. Hidden in Hurtig. */
.row-meta {
  grid-area: meta;
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12px;
  color: var(--text-muted);
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
}
.row-meta:empty { display: none; }
.row-codriver {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 0 1 auto;
}
.row-codriver[href] { color: inherit; text-decoration: underline; text-decoration-color: var(--border-strong); text-underline-offset: 2px; }
.row-car {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  /* flex: 0 1 auto — can shrink (ellipsis), but does NOT grow. With grow=1
     car would suck up all remaining horizontal space and push the weather
     chip to the far right edge, making it look like part of the time area. */
  flex: 0 1 auto;
}
.row-meta-sep { color: var(--border-strong); flex: 0 0 auto; }
/* Row-level weather chip reuses the per-run chip styling — same look,
   different data scope (matches the visible heat-time). */
.row-weather {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
  text-align: left;
  display: inline-flex;
  align-items: baseline;
  gap: 2px;
  white-space: nowrap;
}
.row-weather:hover { color: var(--text); }
.row-weather:focus-visible { outline: 1px dashed currentColor; outline-offset: 2px; }
.row-weather .run-weather-icon { margin-right: 2px; }
.row-weather .run-weather-temp { margin-right: 4px; }
.row-weather .run-weather-wind { margin-right: 4px; }
.row-weather .run-weather-precip { font-weight: 500; color: var(--text); }
body.mode-quick .row-meta { display: none; }

/* Three-dot row menu — quiet by default; outlined when active. */
.row-menu {
  grid-area: menu;
  align-self: start;
  width: 28px;
  height: 28px;
  min-height: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  cursor: pointer;
  padding: 0;
}
.row-menu:hover,
.row-menu[aria-expanded="true"] {
  border-color: var(--border);
  color: var(--text);
}
.row-menu svg { display: block; width: 16px; height: 16px; fill: currentColor; }

/* Row-menu popover — same newspaper aesthetic as the run-weather popover. */
.row-menu-popover {
  position: fixed;
  z-index: 50;
  min-width: 160px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  box-shadow: none;
  padding: 4px 0;
}
.row-menu-popover[hidden] { display: none; }
.row-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  padding: 8px 12px;
  font: inherit;
  color: var(--text);
  cursor: pointer;
}
.row-menu-item:hover,
.row-menu-item:focus-visible {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  outline: none;
}
.row-menu-item[hidden] { display: none; }

.row-runs {
  /* Explicit col-2 placement: grid auto-placement otherwise puts this in
     col-1 (the 36px rail) because .row-tag's `grid-row: 1 / -1` only spans
     the EXPLICIT grid (1 row), leaving col-1 of implicit row 2 free. */
  grid-column: 2;
  margin-top: 8px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}
.row-penalty { grid-column: 2; }
.run-cell {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 6px 8px;
  font-size: 13px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.run-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.run-value { font-weight: 600; display: flex; align-items: center; gap: 4px; }
.run-badge {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.05em;
  padding: 1px 5px;
  border-radius: 4px;
  border: 1px solid currentColor;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.run-pb .run-value { color: var(--pb-fg); text-decoration: underline; text-underline-offset: 2px; font-weight: 700; }
.run-pb { background: var(--pb-bg); border-color: var(--pb-border); }
.run-pb .run-badge { color: var(--pb-fg); background: transparent; }
.run-pb .run-badge::before { content: "● "; }
.run-cb .run-value { color: var(--cb-fg); text-decoration: underline; text-underline-offset: 2px; font-weight: 700; }
.run-cb { background: var(--cb-bg); border-color: var(--cb-border); }
.run-cb .run-badge { color: var(--cb-fg); background: transparent; }
.run-cb .run-badge::before { content: "▲ "; }
.run-ob .run-value { color: var(--ob-fg); text-decoration: underline; text-underline-offset: 2px; font-weight: 700; }
.run-ob { background: var(--ob-bg); border-color: var(--ob-border); }
.run-ob .run-badge { color: var(--ob-fg); background: transparent; }
.run-ob .run-badge::before { content: "◆ "; }

.row-penalty { margin-top: 6px; }
.penalty-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--bad);
  color: #ffffff;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  font-weight: 600;
}
.penalty-amount { font-weight: 700; }
.penalty-sep { opacity: 0.7; }
.penalty-label { opacity: 0.9; font-weight: 500; }

/* -----------------------------------------------------------------------------
 * Race-controls strip: search + favs-only filter (in sticky header).
 * ---------------------------------------------------------------------------*/
.race-controls {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 8px;
  flex-wrap: wrap;
}
/* Shared height for the three race-controls children: search-field, filter
 * group, and class-filter group. Tied to a single CSS variable so they line
 * up edge-to-edge regardless of which one has the tallest content. */
.race-controls { --control-h: 40px; }
.race-controls .search-field,
.race-controls .filter-group,
.race-controls .filter-toggle,
.race-controls .filter-dropdown-toggle,
.race-controls .class-filter-toggle,
.race-controls .class-filter-toggle-label-btn,
.race-controls .class-filter-toggle-chip-btn {
  height: var(--control-h);
  min-height: var(--control-h);
  box-sizing: border-box;
}
.search-field {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  padding: 4px 10px;
}
.search-icon {
  color: var(--text-muted);
  font-size: 16px;
  line-height: 1;
}
.search-input {
  flex: 1;
  background: transparent;
  border: 0;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  outline: none;
  min-width: 0;
}
.search-input::placeholder { color: var(--text-muted); }
.filter-group {
  display: inline-flex;
  align-items: stretch;
}
.filter-toggle,
.filter-dropdown-toggle {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--text);
  border-radius: 0;
  cursor: pointer;
}
.filter-toggle {
  padding: 6px 10px;
  font: 600 13px/1 inherit;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.filter-toggle[aria-pressed="true"] {
  background: var(--ob-bg);
  border-color: var(--ob-border);
  color: var(--ob-fg);
}
.filter-toggle .filter-icon { font-size: 14px; line-height: 1; }
/* The two filter buttons share a hairline boundary — no double border, no
   rounded gap. The pressed-state of "Mine" wins on the shared edge. */
.filter-group .filter-toggle { border-right: 0; }
.filter-group .filter-dropdown-toggle { border-left: 1px solid var(--border-strong); margin-left: 0; }
/* When the "Udvalgte" filter is on, the chevron dropdown sibling adopts the
 * SAME OB-bg/border/text colours so the whole group reads as one highlighted
 * pill — matches the .class-filter-toggle.is-active treatment. Without this
 * the chevron looked detached + neutral while the main button glowed gold. */
.filter-group .filter-toggle[aria-pressed="true"] + .filter-dropdown-toggle {
  background: var(--ob-bg);
  border-color: var(--ob-border);
  color: var(--ob-fg);
}
.filter-dropdown-toggle {
  color: var(--text-muted);
  padding: 0 6px;
  display: inline-flex;
  align-items: center;
}
.filter-dropdown-toggle:hover { color: var(--text); }
.filter-dropdown-toggle[aria-expanded="true"] {
  background: var(--surface-2);
  color: var(--text);
}
.filter-dropdown-toggle .icon { width: 14px; height: 14px; }
/* Dropdown panel for picking a specific slot. */
.filter-dropdown[hidden] { display: none; }
.filter-dropdown {
  /* Mounted on <body> (root stacking context) and positioned via JS coords
     against the toggle button. `fixed` keeps it anchored when the page scrolls
     and lets the z-index actually beat the sticky thead floater (z=25). */
  position: fixed;
  z-index: 60;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  min-width: 220px;
  max-width: calc(100vw - 24px);
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 12px color-mix(in srgb, var(--text) 18%, transparent);
}
/* Backdrop is rendered as a sibling element on <body>. Hidden on desktop
   (the dropdown is a popover anchored to the toggle); shown on mobile when
   the dropdown becomes a bottom-sheet modal. */
.filter-dropdown-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: color-mix(in srgb, var(--text) 32%, transparent);
  z-index: 1099;
}
.filter-dropdown-backdrop[hidden] { display: none !important; }
.filter-dropdown button {
  background: transparent;
  border: 0;
  padding: 10px 14px;
  text-align: left;
  cursor: pointer;
  color: var(--text);
  font: 500 13px/1.2 inherit;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  border-bottom: 1px solid var(--border);
}
.filter-dropdown button:last-child { border-bottom: 0; }
.filter-dropdown button:hover { background: var(--surface-2); }
.filter-dropdown button[aria-pressed="true"] {
  background: color-mix(in srgb, var(--accent) 10%, var(--surface));
  font-weight: 700;
}
.filter-dropdown button .icon-tag {
  width: 16px;
  height: 16px;
  fill: var(--tag-color);
  stroke: var(--tag-color);
  stroke-width: 1;
  flex-shrink: 0;
}
.filter-dropdown button.filter-pick-any .icon-tag {
  fill: none;
  stroke: var(--text-muted);
}
.filter-dropdown button[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}
.filter-dropdown button[disabled]:hover { background: transparent; }
.filter-pick-count {
  margin-left: auto;
  color: var(--text-muted);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  min-width: 22px;
  text-align: right;
}
.filter-dropdown button[aria-pressed="true"] .filter-pick-count { color: var(--text); }
.mode-hint { color: var(--text-muted); font-size: 12px; }
.mode-hint [data-mode-label] { color: var(--text); font-weight: 600; }

/* Inline tooltip beneath the filter button when user tries to enable Mine
   without any favourites set. Auto-fades after a few seconds. */
.race-controls { position: relative; }
.filter-hint {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  background: var(--text);
  color: var(--bg);
  font-size: 12px;
  padding: 6px 10px;
  max-width: 280px;
  z-index: 30;
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity 0.18s, transform 0.18s;
}
.filter-hint-visible { opacity: 1; transform: translateY(0); }

/* -----------------------------------------------------------------------------
 * Per-class filter — collapsible chip strip below the search/filter bar.
 * Hidden by default; "Filtrer pr. klasse" toggle expands it. Composes with
 * the tag-slot filter (AND-applied via body[data-filter-class] + body[data-
 * filter-slot]). Newspaper aesthetic: hairline borders, sharp edges, no
 * accents on the chips themselves; active state inverts to body-text.
 * ---------------------------------------------------------------------------*/
/* Class-filter toggle now sits INLINE with the search field + Mine pill so it
   doesn't eat a whole second row — the modal carries the chip strip on click.
   On mobile the .race-controls flex-wrap lets it land on a second line. */
.class-filter {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}
/* Two-button group for class-filter: outer wrapper holds the layout, the
 * inner buttons (label + chip) inherit the look. When .is-active is set on
 * the wrapper (= ≥1 class selected) BOTH buttons get the same OB-bg highlight
 * the "Udvalgte" filter uses, so the user can't miss the active state. */
.class-filter-toggle {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--border-strong);
  border-radius: 0;
  overflow: hidden;
}
.class-filter-toggle-label-btn,
.class-filter-toggle-chip-btn {
  background: var(--surface);
  border: 0;
  color: var(--text);
  cursor: pointer;
  font: 600 13px/1 inherit;
  padding: 6px 10px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-radius: 0;
}
.class-filter-toggle-label-btn:hover,
.class-filter-toggle-chip-btn:hover {
  background: var(--surface-2);
}
/* Hairline divider between the two buttons. */
.class-filter-toggle-chip-btn {
  border-left: 1px solid var(--border-strong);
  /* Locked width so the wrapper stays the SAME total size regardless of
   * content — "Vælg klasse" placeholder, "Kl. 10", and "99 klasser" all fit
   * inside this box. Without an explicit width the chip would grow/shrink
   * with content, causing adjacent buttons (like "Udvalgte") to slide
   * sideways and creating a mis-click hazard the user reported. */
  width: 130px;
  flex: 0 0 auto;
  justify-content: space-between;
  overflow: hidden;
}
.class-filter-toggle-chip-btn .class-filter-current {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* When no class is selected: chip-button stays VISIBLE and clickable, with a
 * muted "Vælg klasse"-style placeholder so the empty area still reads as a
 * meaningful affordance — clicking it opens the modal just like the label-
 * button does in the empty state. The min-width above keeps the wrapper at
 * a constant total size regardless of state. */
.class-filter-current.is-placeholder {
  color: var(--text-muted);
  font-weight: 400;
  font-style: italic;
}
/* Active state: same colour treatment as .filter-toggle[aria-pressed="true"]
 * — OB background + border so it's visually unmistakable. Applies to BOTH
 * buttons via the wrapper's .is-active class so the whole control reads as
 * pressed. */
.class-filter-toggle.is-active { border-color: var(--ob-border); }
.class-filter-toggle.is-active .class-filter-toggle-label-btn,
.class-filter-toggle.is-active .class-filter-toggle-chip-btn {
  background: var(--ob-bg);
  color: var(--ob-fg);
}
.class-filter-toggle.is-active .class-filter-toggle-chip-btn { border-left-color: var(--ob-border); }
.class-filter-toggle .icon { width: 12px; height: 12px; transition: transform 0.15s; }
.class-filter-toggle .class-filter-toggle-chip-btn[aria-expanded="true"] .icon { transform: rotate(180deg); }
.class-filter-current {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.class-filter-current[hidden] { display: none; }
/* Modal "Videre" button — primary action, full-width on mobile. */
.class-filter-modal-footer {
  display: flex;
  justify-content: flex-end;
  padding: 12px 16px 16px;
  border-top: 1px solid var(--border);
  margin-top: 8px;
}
.class-filter-modal-done {
  padding: 8px 18px;
  background: var(--accent);
  color: var(--bg);
  border: 1px solid var(--accent);
  font: 600 13px/1 inherit;
  cursor: pointer;
  border-radius: 0;
}
.class-filter-modal-done:hover { background: var(--text); border-color: var(--text); }
.class-filter-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

/* Class-filter modal. <dialog> with a hairline header + chip grid. The chip
   strip used to expand inline below the toggle, but it could grow huge on
   rallies with many classes AND the floating sticky thead overlapped it on
   scroll. A modal sidesteps both issues — works the same on mobile + desktop. */
/* Modal box. overflow:hidden is load-bearing — without it the <dialog>
 * default (overflow:auto) creates a SECOND scrollbar on top of the strip's
 * own scrollbar when contents exceed max-height. */
.class-filter-modal {
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  padding: 0;
  max-width: 720px;            /* desktop room for 2 columns */
  width: calc(100% - 24px);
  max-height: min(80vh, 720px);
  border-radius: 0;
  overflow: hidden;
}
.class-filter-modal::backdrop { background: color-mix(in srgb, var(--text) 32%, transparent); }
.class-filter-modal[open] { display: block; }
/* Flex column so the strip can grow + scroll between header and footer.
 * AVOID height: 100% here — iOS Safari resolves percentage heights against
 * the parent <dialog>'s explicit height, and the dialog has only max-height
 * (no height), so 100% collapses to 0 and the modal renders as a 1px line
 * (only the dialog border is visible). Use the SAME explicit max-height as
 * the dialog so the form is independently sized; the strip's flex:1 + its
 * own overflow-y:auto handles the scrolling. */
.class-filter-modal-form {
  display: flex;
  flex-direction: column;
  max-height: min(80vh, 720px);
}
.class-filter-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.class-filter-modal-header h3 {
  margin: 0;
  font: 600 14px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.class-filter-modal-close {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 22px;
  line-height: 1;
  padding: 0 6px;
  min-height: 32px;
  min-width: 32px;
}
.class-filter-modal-close:hover { color: var(--text); }

/* Strip = CSS grid with auto-fill. At 720px modal interior we naturally
 * get 2 columns; below ~600px viewport one column. The 1px gap + a
 * background:var(--border) on the grid container produces hairline dividers
 * in BOTH axes for free — cells sit on top of the border-coloured grid bg. */
.class-filter-modal .class-filter-strip {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1px;
  background: var(--border);
  padding: 0;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  align-content: start;
}
.class-filter-modal .class-chip-group {
  background: var(--surface);
  display: flex;
  align-items: stretch;
  width: 100%;
  min-width: 0;
  border-bottom: 0;
  align-self: stretch;
}
/* "Alle" spans every column. */
.class-filter-modal .class-chip-group-all {
  grid-column: 1 / -1;
  box-shadow: 0 1px 0 var(--border-strong);
}

.class-chip {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  cursor: pointer;
  font: 600 14px/1.2 inherit;
  font-variant-numeric: tabular-nums;
  padding: 10px 14px;
  min-height: 52px;
  border-radius: 0;
  white-space: normal;
  display: flex;
  align-items: center;
  gap: 12px;
  text-align: left;
  justify-content: flex-start;
}
.class-chip:hover { background: var(--surface-2); }
/* Pressed-state: subtle warm tint (35% --ob-bg over surface). Text stays
 * the regular --text colour — no yellow text. The filled checkbox carries
 * the strong "selected" signal; the row tint is just a calm backdrop.
 * The 2px amber rail (inset shadow on the LEFT edge) anchors the selection
 * without the forbidden rounded-card-stripe combo (we're flat + hairline). */
.class-chip[aria-pressed="true"] {
  background: color-mix(in srgb, var(--ob-bg) 35%, transparent);
  box-shadow: inset 2px 0 0 var(--ob-border);
}
.class-chip[aria-pressed="true"]:hover {
  background: color-mix(in srgb, var(--ob-bg) 55%, transparent);
}
.class-chip-all {
  text-transform: uppercase;
  letter-spacing: 0.04em;
  min-height: 44px;
}

/* Check glyph: 18×18 hairline-bordered square. When pressed, fills with
 * --text and shows a high-contrast checkmark in --bg — clear "this is
 * ticked" signal that reads in any theme. Decoupled from the row tint so
 * the checkbox carries the selection load while the row stays subtle. */
.class-row-check {
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--border-strong);
  background: var(--surface);
  flex-shrink: 0;
  position: relative;
  display: inline-block;
}
.class-chip[aria-pressed="true"] .class-row-check {
  background: var(--text);
  border-color: var(--text);
}
.class-chip[aria-pressed="true"] .class-row-check::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 6px;
  height: 11px;
  border-right: 2px solid var(--bg);
  border-bottom: 2px solid var(--bg);
  transform: rotate(45deg);
}

/* Class-color glyph — slim vertical bar tied to the same Wong palette as the
 * row left-edge in results. Slimmer (3×16) so the chip strip reads calm
 * rather than confetti. "Alle" has no stripe. Colours stay AA-distinguishable
 * for colorblind users; in dark mode we desaturate via color-mix with the
 * surface so the bright Wong palette doesn't glow against the dark UI. */
.class-chip-stripe {
  display: inline-block;
  width: 3px;
  height: 16px;
  background: var(--class-color, transparent);
  flex-shrink: 0;
  border-radius: 0;
}
/* Invisible placeholder so the "Alle" row's title aligns horizontally
 * with the per-class titles below — same width + height, transparent bg. */
.class-chip-stripe-empty { background: transparent; }
[data-theme="dark"] .class-chip-stripe:not(.class-chip-stripe-empty) {
  background: color-mix(in srgb, var(--class-color, transparent) 70%, var(--surface));
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="sun"]):not([data-theme="dark"]) .class-chip-stripe:not(.class-chip-stripe-empty) {
    background: color-mix(in srgb, var(--class-color, transparent) 70%, var(--surface));
  }
}

/* Title + optional short_desc stack vertically. Title may include an
 * inline count suffix "(5 deltagere)" rendered muted alongside the
 * class name. Desc wraps to 2 lines on desktop; on mobile we constrain
 * it to 1 line with ellipsis (the (i) info modal carries the full text). */
.class-row-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: flex-start;
  overflow: hidden;
}
.class-row-title {
  font: 600 14px/1.25 inherit;
  font-variant-numeric: tabular-nums;
  width: 100%;
  /* Allow the inline count to wrap to a second line if it must, but
   * keep the class name + "(N)" together when there's room. */
}
.class-row-count-inline {
  font-weight: 400;
  color: var(--text-muted);
  margin-left: 2px;
  font-size: 0.92em;
}
.class-chip[aria-pressed="true"] .class-row-count-inline {
  color: var(--text-muted);
}
.class-row-desc {
  font: 400 12px/1.35 inherit;
  color: var(--text-muted);
  max-width: 100%;
}
.class-chip[aria-pressed="true"] .class-row-desc {
  color: var(--text-muted);
}

/* Mobile compactness: smaller text, tighter padding, lower row min-height
 * so more classes fit in the viewport without scrolling on phones.
 * Triggers below 480px viewport — mid-range phones and below. */
@media (max-width: 480px) {
  .class-filter-modal {
    width: calc(100% - 16px);
    max-height: min(78vh, 600px);
  }
  .class-filter-modal-header {
    padding: 8px 12px;
  }
  .class-filter-modal-header h3 {
    font: 600 13px/1.2 inherit;
  }
  .class-filter-modal .class-filter-strip {
    grid-template-columns: 1fr;
  }
  .class-chip {
    padding: 7px 12px;
    min-height: 44px;
    gap: 10px;
  }
  .class-chip-all {
    min-height: 38px;
  }
  .class-row-title {
    font: 600 13px/1.25 inherit;
  }
  .class-row-desc {
    font: 400 10.5px/1.3 inherit;
    /* Single-line on mobile — long descriptions truncate with ellipsis.
     * (i) info button still opens the full long_desc when needed. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
    width: 100%;
  }
  .class-row-count-inline {
    font-size: 0.88em;
  }
  .class-chip-stripe {
    width: 3px;
    height: 18px;
  }
  .class-row-check {
    width: 16px;
    height: 16px;
  }
  .class-chip[aria-pressed="true"] .class-row-check::after {
    left: 2px;
    width: 7px;
    height: 11px;
  }
}

/* Legacy chip-count — used elsewhere if any caller still has the old
 * inline (N) markup. Kept for safety. */
.class-chip-count {
  font-weight: 400;
  opacity: 0.7;
  font-size: 11px;
}

/* Hide rows whose class doesn't match the active filter. ME row stays
   visible so the user can keep their reference point even when filtering
   to a class they aren't in. AND-combined with the tag-slot filter via
   the existing body.filter-favs-only / body[data-filter-slot] rules.
   The .class-filter-hidden class is toggled by JS per row when the user
   picks a chip — same shape as the search-hidden pattern. */
.row-card.class-filter-hidden:not(.is-me),
tr.t-row.class-filter-hidden:not(.is-me) { display: none !important; }

/* -----------------------------------------------------------------------------
 * Inline SVG icons — shared sizing/coloring rules. Icons inherit currentColor
 * so theme changes apply automatically. Star toggles fill via aria-pressed.
 * ---------------------------------------------------------------------------*/
.icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex-shrink: 0;
}
.icon-star {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
}
.filter-toggle[aria-pressed="true"] .icon-star {
  fill: var(--ob-fg);
  stroke: var(--ob-fg);
}
/* Når et specifikt slot er valgt swappes ikonet til en icon-tag-form
   (firkant/trekant/…) og pillen får --tag-color sat via JS. Slot-farven
   trumfer den generelle pressed-state, så pillen afspejler hvilket slot
   man har filtreret efter. */
.filter-toggle .icon-tag {
  fill: var(--tag-color);
  stroke: var(--tag-color);
}
.filter-toggle[aria-pressed="true"] .icon-tag {
  fill: var(--tag-color);
  stroke: var(--tag-color);
}
/* Mærke-glyf inde i en follow-button. Outline når slot 0 (Tilføj),
   fyldt med slot-farve når mindst ét slot er aktivt. */
.icon-tag {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
}
[data-action="favourite"][aria-pressed="true"] .icon-tag {
  fill: currentColor;
  stroke: currentColor;
}
[data-action="favourite"][aria-pressed="true"] {
  color: var(--tag-color, var(--ob-fg));
}

/* Theme icons: only one shows at a time depending on [data-theme]. */
.theme-toggle-icon { display: none; }
:root[data-theme="auto"] .icon-theme-auto,
:root:not([data-theme]) .icon-theme-auto { display: inline-block; }
:root[data-theme="sun"] .icon-theme-sun { display: inline-block; }
:root[data-theme="dark"] .icon-theme-dark { display: inline-block; }
.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted);
  cursor: pointer;
  padding: 4px 10px;
  font: 600 12px/1 inherit;
  min-height: 32px;
  border-radius: 0;
}
.theme-toggle:hover { color: var(--text); border-color: var(--border); }
.theme-toggle .icon { width: 16px; height: 16px; }
.theme-toggle-label { color: var(--text-muted); }

/* Language switcher: a small DA▾ pill in the header that opens a menu of the
   six supported languages. Native names ("Dansk", "English", ...) are not
   themselves translated — they're shown in their own language. */
.lang-switcher { position: relative; display: inline-flex; }
.lang-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted);
  cursor: pointer;
  padding: 4px 8px;
  font: 600 12px/1 inherit;
  min-height: 32px;
  border-radius: 0;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.lang-toggle:hover { color: var(--text); border-color: var(--border); }
.lang-toggle[aria-expanded="true"] { background: var(--surface-2); color: var(--text); border-color: var(--border); }
.lang-toggle .icon { width: 12px; height: 12px; }
.lang-menu[hidden] { display: none; }
.lang-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 60;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  min-width: 160px;
  display: flex;
  flex-direction: column;
}
.lang-menu-item {
  background: transparent;
  border: 0;
  padding: 10px 14px;
  text-align: left;
  cursor: pointer;
  color: var(--text);
  font: 500 13px/1.2 inherit;
  min-height: 40px;
  border-bottom: 1px solid var(--border);
}
.lang-menu-item:last-child { border-bottom: 0; }
.lang-menu-item:hover { background: var(--surface-2); }
.lang-menu-item[aria-pressed="true"] {
  background: color-mix(in srgb, var(--accent) 10%, var(--surface));
  font-weight: 700;
}

/* Settings gear button in the header. */
.settings-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted);
  cursor: pointer;
  padding: 4px 8px;
  min-height: 32px;
  min-width: 32px;
  border-radius: 0;
}
.settings-toggle:hover { color: var(--text); border-color: var(--border); }
.settings-toggle .icon { width: 18px; height: 18px; }
.settings-toggle-label {
  margin-left: 6px;
  color: var(--text-muted);
  font: 600 12px/1 inherit;
}
.settings-toggle:hover .settings-toggle-label { color: var(--text); }
@media (max-width: 640px) {
  /* Mobile header is tight on horizontal space — drop the verbose labels.
     Icons remain (universally recognised) and aria-label/title carry the
     accessible name for screen readers. */
  .settings-toggle-label,
  .theme-toggle-label { display: none; }
}

/* Settings sheet (reuses .tag-picker-* chrome). */
.settings-sheet .settings-section {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.settings-sheet .settings-section:first-of-type {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.settings-sheet h4 {
  margin: 0 0 8px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}
.settings-sheet .settings-empty { margin: 4px 0; font-size: 13px; }
.settings-sheet .settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
}
.settings-row-text { flex: 1; min-width: 0; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.settings-action {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text);
  padding: 6px 12px;
  font: 600 12px/1 inherit;
  cursor: pointer;
  min-height: 36px;
  flex-shrink: 0;
}
.settings-action:hover { background: var(--surface-2); }
.settings-action-danger { border-color: var(--bad); color: var(--bad); }
.settings-action-danger:hover { background: color-mix(in srgb, var(--bad) 8%, var(--surface)); }
.settings-slot-group { margin: 10px 0; }
.settings-slot-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  font-size: 13px;
}
.settings-slot-icon { display: inline-flex; align-items: center; color: var(--tag-color); }
.settings-slot-icon .icon-tag { width: 16px; height: 16px; fill: currentColor; stroke: currentColor; }
.settings-slot-list {
  list-style: none;
  margin: 0;
  padding: 0 0 0 24px;
  border-left: 1px solid var(--border);
}
.settings-slot-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 0;
  font-size: 13px;
}
.settings-row-rm {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
  min-height: 32px;
  min-width: 32px;
}
.settings-row-rm:hover { color: var(--bad); }

/* =============================================================================
 * Settings sheet redesign — tabs + per-tab help + per-tab content layouts
 * (May 2026). Builds on .tag-picker chrome but adds the tab strip + larger
 * content area. Visually still newspaper-aesthetic: hairline rules, hard
 * edges, tabular spacing.
 * ===========================================================================*/

/* The settings sheet has a FIXED outer size that does not jump as the user
   switches tabs — the panels area scrolls internally instead. Without this,
   each tab click re-rendered the whole sheet at content-height and the modal
   visibly resized between tabs (user complaint, 2026-05-08). */
.settings-sheet .settings-sheet-inner {
  display: flex;
  flex-direction: column;
}
@media (min-width: 640px) {
  .settings-sheet .settings-sheet-inner {
    max-width: 540px;
    height: 600px;
    max-height: 84vh;
    padding: 14px 16px 12px;
  }
}
@media (max-width: 639.9px) {
  .settings-sheet .settings-sheet-inner {
    height: 78vh;
    max-height: 78vh;
    padding: 12px 12px max(12px, env(safe-area-inset-bottom));
  }
}
.settings-sheet-head {
  flex: 0 0 auto;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0;
}

/* Tab strip — horizontal scroll on narrow viewports so all four tabs stay
   reachable without truncation. Active tab is the only one with a thick
   bottom rule (newspaper-section divider style). */
.settings-tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  scrollbar-width: none;
  flex: 0 0 auto;
}
.settings-tabs::-webkit-scrollbar { display: none; }
.settings-tab {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  font: 600 12px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 10px 12px;
  cursor: pointer;
  min-height: 40px;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px; /* overlap parent border so the rule stays a single px */
  flex-shrink: 0;
}
.settings-tab:hover { color: var(--text); }
.settings-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.settings-tab.is-active {
  color: var(--text);
  /* No bottom-rule — relies on weight + colour contrast for the active state. */
}

.settings-panels {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  min-height: 0; /* allow flex child to actually shrink + scroll */
  padding: 0 2px;
}
.settings-panel { padding: 10px 0 14px; }
.settings-help {
  margin: 8px 0 12px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-muted);
  border-left: 2px solid var(--border);
  padding-left: 8px;
}
.settings-section-h {
  margin: 0 0 8px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  font-weight: 700;
}

/* Foot stays anchored to the bottom of the fixed-height sheet — outside the
   scrollable panels area, so it never disappears mid-scroll. */
.settings-sheet .tag-picker-foot {
  flex: 0 0 auto;
  border-top: 1px solid var(--border);
  padding-top: 10px;
  margin-top: 8px;
}

/* "Mig" tab — card style with current-ME info on top + push toggle.
   Newspaper-style: hairline border, no rounded corners. */
.settings-me-card {
  border: 1px solid var(--border);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.settings-me-line {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 15px;
}
.settings-me-name { font-weight: 700; }
.settings-me-context { font-size: 12px; }
.settings-me-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.settings-me-bell {
  margin-top: 6px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
}
.settings-me-bell .settings-help { margin: 0; padding-left: 0; border-left: 0; font-size: 12px; }
.tag-picker-bell-me {
  color: var(--text);
  border-color: var(--border-strong);
  padding: 0 12px;
  gap: 6px;
  min-height: 38px;
  font-size: 12px;
}
@media (max-width: 639.9px) {
  .tag-picker-bell-me {
    width: 100%;
    justify-content: flex-start;
    min-height: 36px;
    padding: 0 10px;
  }
  .tag-picker-bell-me .tag-picker-bell-label {
    font-size: 11px;
    white-space: normal;
    text-align: left;
    line-height: 1.2;
  }
}
.tag-picker-bell-me:hover {
  background: var(--surface-2);
  border-color: var(--text);
  color: var(--text);
}
.tag-picker-bell-me[aria-pressed="true"] {
  background: var(--text);
  border-color: var(--text);
  color: var(--bg);
}
.tag-picker-bell-me[aria-pressed="true"]:hover {
  background: var(--text);
  color: var(--bg);
}

/* "Udvalgte" tab (May-2026 redesign) — single merged tab replacing the old
   "Mine kategorier" + "Mine kørere". Newspaper-style: hairline rules, sharp
   edges, no rounded card+stripe combo (forbidden — see CLAUDE.md). Density
   over comfort. Mobile-first; works at 360px wide.

   Layout:
     [ category-bell toolbar — wraps on narrow screens   ]
     [ Sortér efter: <select>                            ]
     [ push-status pill                                  ]
     [ flat list / grouped list of driver rows           ]
     [ Ryd alle mærker (danger row)                      ]
*/

/* Category bar — filter chips + inline mini-bells. Click chip = filter list
   to that slot. Click mini-bell (right side of chip) = toggle push for slot.
   The two are separate buttons; mini-bell stops propagation. */
.settings-cat-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0 0 8px;
}
.settings-cat-chip-wrap {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.settings-cat-chip-wrap:hover { border-color: var(--border-strong); }
.settings-cat-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: transparent;
  border: 0;
  color: var(--text);
  padding: 0 8px;
  font: 600 11px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
  min-height: 28px;
}
.settings-cat-chip-all {
  border: 1px solid var(--border);
  margin-right: 2px;
}
.settings-cat-chip:hover { background: var(--surface-2); }
.settings-cat-chip[aria-pressed="true"] {
  background: var(--text);
  color: var(--bg);
}
.settings-cat-chip-all[aria-pressed="true"] {
  background: var(--text);
  border-color: var(--text);
  color: var(--bg);
}
.settings-cat-chip-shape {
  display: inline-flex;
  color: var(--tag-color, currentColor);
}
.settings-cat-chip[aria-pressed="true"] .settings-cat-chip-shape { color: var(--bg); }
.settings-cat-chip-shape .icon-tag {
  width: 12px; height: 12px;
  fill: currentColor; stroke: currentColor;
}
.settings-cat-chip-name { font-weight: 700; }
.settings-cat-chip-count {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.settings-cat-chip[aria-pressed="true"] .settings-cat-chip-count { color: var(--bg); }
/* Mini-bell sub-button on the right of the chip wrapper. Stays separate so
   pressing it never changes the filter, only the push pref. */
.settings-cat-bell {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-left: 1px solid var(--border);
  color: var(--text-muted);
  cursor: pointer;
  padding: 0 6px;
  min-width: 28px;
  min-height: 28px;
}
.settings-cat-bell:hover { color: var(--text); }
.settings-cat-bell .icon-bell {
  width: 14px; height: 14px;
  fill: none; stroke: currentColor; stroke-width: 1.5;
}
.settings-cat-bell[aria-pressed="true"] {
  background: var(--tag-color);
  color: var(--bg);
}
.settings-cat-bell[aria-pressed="true"] .icon-bell {
  fill: #ffd24a;
  stroke: #4a2f00;
  stroke-width: 1;
}

/* Sort dropdown row — label + native <select>. Native because mobile gets
   the OS picker for free, which beats any custom widget on touch. */
.settings-sort {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 6px;
  padding: 6px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.settings-sort-label {
  font: 600 11px/1 inherit;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  flex-shrink: 0;
}
.settings-sort-select {
  flex: 1;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--text);
  padding: 6px 8px;
  font: 600 13px/1.2 inherit;
  cursor: pointer;
  min-height: 36px;
}
.settings-sort-select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* Status line is no longer rendered — kept hidden in case any cached HTML
   from a stale service-worker still has it. */
.settings-status-line { display: none; }

/* Clear-tags confirm dialog — modal-over-modal. Reuses .tag-picker chrome
   (backdrop, inner box, head/foot) so visual language is consistent. The
   list is one row per slot with a checkbox + count. */
.clear-tags-dialog { z-index: 1100; } /* above settings sheet */
.clear-tags-inner {
  max-width: 440px;
  display: flex;
  flex-direction: column;
  gap: 0;
}
@media (min-width: 640px) {
  .clear-tags-inner { padding: 16px 18px 14px; }
}
.clear-tags-list {
  list-style: none;
  margin: 8px 0 12px;
  padding: 0;
  border-top: 1px solid var(--border);
}
.clear-tags-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 4px;
  border-bottom: 1px solid var(--border);
}
.clear-tags-row input[type="checkbox"] {
  width: 18px; height: 18px;
  accent-color: var(--bad);
  cursor: pointer;
}
.clear-tags-row-label {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  gap: 10px;
  align-items: center;
  flex: 1;
  cursor: pointer;
  font: 600 14px/1 inherit;
}
.clear-tags-shape {
  display: inline-flex;
  color: var(--tag-color);
}
.clear-tags-shape .icon-tag {
  width: 16px; height: 16px;
  fill: currentColor; stroke: currentColor;
}
.clear-tags-name { font-weight: 700; }
.clear-tags-count {
  font: 700 12px/1 inherit;
  color: var(--text-muted);
  padding: 2px 8px;
  border: 1px solid var(--border);
}
.clear-tags-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.clear-tags-foot .tag-picker-done.settings-action-danger {
  background: var(--bad);
  color: var(--bg);
  border-color: var(--bad);
}
.clear-tags-foot .tag-picker-done.settings-action-danger:hover {
  background: color-mix(in srgb, var(--bad) 85%, var(--text));
}

/* Grouped view (sort=tag) — slot header + the same flat list under it. */
.settings-driver-groups {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.settings-driver-group { padding: 0; }
.settings-driver-group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0 4px;
  border-bottom: 1px solid var(--border);
}
.settings-driver-group-icon { color: var(--tag-color); display: inline-flex; }
.settings-driver-group-icon .icon-tag {
  width: 14px; height: 14px;
  fill: currentColor; stroke: currentColor;
}
.settings-driver-group-name {
  font: 700 12px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.settings-driver-group-count {
  margin-left: auto;
  font: 700 11px/1 inherit;
  color: var(--text-muted);
}

/* Flat list — hairline-separated rows. Tag-color stripe lives on the
   left-edge SHAPE icon (currentColor=tag-color) — NOT on the row left-edge.
   The row+left-stripe combo is the forbidden AI trope; the icon does the
   visual identity work instead.
   Row layout (works at 360px+):
     [shape] [name + meta block (flex)] [bell] [×]
*/
.settings-driver-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.settings-driver-row {
  display: grid;
  grid-template-columns: 16px 1fr 32px 24px;
  gap: 8px;
  align-items: center;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  min-height: 38px;
}
.settings-driver-row:last-child { border-bottom: 0; }
.settings-driver-shape {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  color: var(--tag-color, var(--text-muted));
}
.settings-driver-shape .icon-tag {
  width: 16px; height: 16px;
  fill: currentColor; stroke: currentColor;
}
.settings-driver-id {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.settings-driver-name {
  font: 600 14px/1.2 inherit;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.settings-driver-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font: 500 11px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.settings-driver-meta .settings-driver-nr,
.settings-driver-meta .settings-driver-cls {
  font-variant-numeric: tabular-nums;
}
.settings-driver-multi {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  padding: 0 4px;
  border: 1px solid var(--tag-color, var(--border-strong));
  color: var(--tag-color, var(--text-muted));
  font: 700 10px/1.4 inherit;
  letter-spacing: 0;
}
.settings-driver-row .tag-picker-bell-driver {
  min-width: 32px;
  min-height: 32px;
  padding: 0;
  gap: 0;
}
/* The driver-bell inside Udvalgte rows has no inline label — keep the
   parent .tag-picker-bell-driver padding/gap defaults from leaking through.
   Hide any accidental label children. */
.settings-driver-row .tag-picker-bell-driver .tag-picker-bell-label { display: none; }
.settings-driver-row .settings-row-rm {
  min-width: 28px;
  padding: 4px;
  text-align: center;
}
.settings-panel[data-settings-panel="udvalgte"] .settings-row-danger {
  border-top: 1px solid var(--border);
  margin-top: 14px;
  padding: 14px 0 4px;
}

/* "Andet" tab — list of toggles + reset rows. */
.settings-other-list {
  display: flex;
  flex-direction: column;
  gap: 0;
}
.settings-other-list .settings-row {
  border-bottom: 1px solid var(--border);
  padding: 12px 0;
}
.settings-other-list .settings-row:last-child { border-bottom: 0; }
.settings-row-danger { padding: 14px 0 4px; border-top: 1px solid var(--border); margin-top: 14px; }

/* Picker footer extras — Send test-besked + Slå push fra. Surfaced when the
   picker is opened from /driver (raceSlug starts with "driver:"). Keep the
   look subordinate to the primary "Færdig" button. */
.tag-picker-foot {
  align-items: center;
  gap: 12px;
}
.tag-picker-foot-spacer { flex: 1; }
.tag-picker-link {
  background: transparent;
  border: 0;
  color: var(--text);
  text-decoration: underline;
  cursor: pointer;
  font: inherit;
  padding: 4px 0;
  min-height: 36px;
}
.tag-picker-link:hover { color: var(--accent); }
.tag-picker-link-warn { color: var(--bad); opacity: 0.85; }
.tag-picker-link-warn:hover { color: var(--bad); opacity: 1; }

/* =============================================================================
 * Driver-hero action buttons (May 2026) — Bell, Categories, Det-er-mig
 * inline next to the driver name. Replaces the old big push-CTA card.
 * ===========================================================================*/
.driver-hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 14px 0 18px;
}
.driver-hero-bell {
  /* Inherits .tag-picker-bell-driver — accent outline, yellow bell when on. */
  flex-shrink: 0;
}
.driver-hero-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text);
  font: 600 13px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 10px 14px;
  cursor: pointer;
  min-height: 44px;
  flex-shrink: 0;
}
.driver-hero-btn:hover { background: var(--surface-2); }
.driver-hero-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.driver-hero-btn .icon { width: 18px; height: 18px; fill: currentColor; stroke: currentColor; stroke-width: 1.2; }
.driver-hero-btn .icon-me {
  fill: none;
  stroke-width: 1.5;
}
.driver-hero-itsme[aria-pressed="true"],
.driver-hero-itsme.is-me {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
}
.driver-hero-itsme[aria-pressed="true"] .icon-me,
.driver-hero-itsme.is-me .icon-me { stroke: currentColor; }
.driver-hero-categories .icon-tag {
  fill: var(--tag-1, currentColor);
  stroke: none;
}

/* Me-confirm dialog on /driver (reuses .me-confirm chrome but adds a target
   line that surfaces the new pick). */
.driver-me-confirm .me-confirm-target {
  margin: 8px 0 4px;
  font-size: 16px;
}
.me-confirm-body { white-space: pre-wrap; }

/* Tabel-mode follow column. */
.results-tabel .t-fav { width: 32px; padding: 2px 4px; text-align: center; }
.results-tabel thead th.t-fav { background: var(--surface-2); }
.t-fav-btn {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1;
  padding: 0;
  /* iOS: suppress long-press text-selection + callout on neighbour cells / picker labels. */
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  user-select: none;
  touch-action: manipulation;
}
.t-fav-btn:hover { color: var(--text); }
.t-fav-btn[aria-pressed="true"] { color: var(--tag-color, var(--ob-fg)); position: relative; }
.t-fav-btn[data-tag-count]:not([data-tag-count="0"]):not([data-tag-count="1"])::after {
  content: attr(data-tag-count);
  position: absolute;
  bottom: 0;
  right: 0;
  font-size: 8px;
  font-weight: 700;
  background: var(--surface);
  color: var(--tag-color, var(--text));
  padding: 0 2px;
  line-height: 1.1;
  border-radius: 999px;
}
.results-tabel tbody tr.is-following .t-fav-btn { color: var(--row-tag-color, var(--ob-fg)); }
.results-tabel tbody tr.is-following td { background: color-mix(in srgb, var(--row-tag-color, var(--ob-bg)) 14%, transparent); }
.results-tabel tbody tr.is-me td { background: color-mix(in srgb, var(--accent) 12%, transparent); font-weight: 600; }

/* Search-hidden + favs-only filter: hide rows that don't match. */
.row-card.search-hidden,
tr.t-row.search-hidden { display: none !important; }

/* Search match highlighting. Two parallel paths render the same accent:
   1. CSS Custom Highlight API path — used in modern browsers (Chrome 105+,
      Firefox 140+, Safari 17.2+, Edge 105+). Highlights are registered by
      live.js via CSS.highlights.set("search", ...) and styled via the
      ::highlight pseudo. No DOM mutation; survives morphdom patches that
      don't touch text nodes.
   2. <mark class="search-match"> fallback — DOM-mutation path for older
      browsers without the API. live.js wraps matched substrings in the
      visible row cells. Same colour tokens so visual parity is preserved. */
::highlight(search) {
  background: var(--accent);
  color: var(--accent-on);
}
mark.search-match {
  background: var(--accent);
  color: var(--accent-on);
  padding: 0;
  border-radius: 0;
}
body.filter-favs-only .row-card:not(.is-following):not(.is-me),
body.filter-favs-only tr.t-row:not(.is-following):not(.is-me) { display: none !important; }
/* Specific-slot filter (chosen via the chevron dropdown). ME stays visible. */
body[data-filter-slot="1"] .row-card:not(.has-slot-1):not(.is-me),
body[data-filter-slot="1"] tr.t-row:not(.has-slot-1):not(.is-me),
body[data-filter-slot="2"] .row-card:not(.has-slot-2):not(.is-me),
body[data-filter-slot="2"] tr.t-row:not(.has-slot-2):not(.is-me),
body[data-filter-slot="3"] .row-card:not(.has-slot-3):not(.is-me),
body[data-filter-slot="3"] tr.t-row:not(.has-slot-3):not(.is-me),
body[data-filter-slot="4"] .row-card:not(.has-slot-4):not(.is-me),
body[data-filter-slot="4"] tr.t-row:not(.has-slot-4):not(.is-me),
body[data-filter-slot="5"] .row-card:not(.has-slot-5):not(.is-me),
body[data-filter-slot="5"] tr.t-row:not(.has-slot-5):not(.is-me),
body[data-filter-slot="6"] .row-card:not(.has-slot-6):not(.is-me),
body[data-filter-slot="6"] tr.t-row:not(.has-slot-6):not(.is-me) { display: none !important; }

/* Row-menu trigger flash on copy-link success — re-uses the menu hover style. */
.row-menu.share-flash { color: var(--good); border-color: var(--good); }

/* -----------------------------------------------------------------------------
 * Hurtig (compact list) — newspaper-table dense. No card chrome, no left-stripe.
 * Class color shows as a tiny flag inside the row, not on the border.
 * ---------------------------------------------------------------------------*/
.mode-quick .row-card {
  padding: 4px 12px 4px 4px;
  min-height: 28px;
}
.mode-quick .row-card-head {
  column-gap: 8px;
  padding: 0;
  font-size: 13px;
  line-height: 1.35;
  /* Hurtig drops the meta line — keep the same area template but compress
     the explicit grid since the meta row is hidden anyway. */
}
.mode-quick .row-name { gap: 0; }
.mode-quick .row-driver { font-weight: 500; }
.mode-quick .row-runs,
.mode-quick .row-penalty,
.mode-quick .row-rank-class,
.mode-quick .row-city,
.mode-quick .row-class { display: none; }
.mode-quick .row-total { display: none; }
.mode-quick .row-heat-time {
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  display: inline-block;
}
/* Detaljer / Tabel default: show aggregate, hide heat-specific. */
.row-heat-time { display: none; }
.mode-details .row-heat-time { display: none; }
.mode-quick .row-rank { min-width: 26px; font-size: 13px; font-weight: 700; }
.mode-quick .row-nr { font-size: 12px; color: var(--text-muted); min-width: 28px; }
.mode-quick .row-gap { font-size: 12px; color: var(--text-muted); }
/* Hurtig: keep the same 32px tag button size as Detaljer for consistency
   across modes (and to give it visible weight against sparse rows). The
   menu trigger can shrink slightly since it's secondary. */
.mode-quick .row-tag { margin-top: 0; align-self: center; }
.mode-quick .row-menu { width: 24px; height: 24px; align-self: center; }
/* Subtle zebra (newspaper-grade, not card-grade). */
.mode-quick .row-card:nth-child(even) {
  background: color-mix(in srgb, var(--surface-2) 60%, transparent);
}
.mode-quick .row-card.is-me:nth-child(even) {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}

/* Detaljer = default, no override needed. */

/* Sammenlign — hide regular rows, show compare panel. */
.mode-compare .heat-tabs,
.mode-compare .grid-tabs,
.mode-compare .heat .row-cards,
.mode-compare .heat .results-tabel-wrap,
.mode-compare .heat .empty { display: none; }
.mode-compare .compare-panel { display: block; }
/* -----------------------------------------------------------------------------
 * Compare panel — newspaper-table styling, no AI-card-chrome.
 * ---------------------------------------------------------------------------*/
.compare-panel {
  display: none;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  margin: 8px 0 24px;
}
.compare-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}
.compare-head h2 {
  font-size: 16px;
  font-weight: 700;
  margin: 0;
}
.compare-actions { display: flex; gap: 6px; }
.compare-add-btn,
.compare-clear-btn {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--text);
  padding: 4px 10px;
  font: 600 12px/1 inherit;
  cursor: pointer;
  min-height: 28px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.compare-add-btn { background: var(--accent); color: var(--accent-on); border-color: var(--accent); }
.compare-clear-btn:hover { background: var(--surface-2); }
.compare-anchor-line {
  font-size: 13px;
  color: var(--text);
  margin-bottom: 4px;
  border-top: 1px solid var(--border);
  padding-top: 6px;
}
.compare-warn {
  font-size: 12px;
  color: var(--warn);
  background: var(--status-prov-bg);
  border: 1px solid var(--status-prov-border);
  padding: 6px 8px;
  margin: 6px 0;
}
.compare-empty {
  padding: 20px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.compare-empty p { margin: 0 0 6px; font-size: 14px; }
.compare-empty p.muted { font-size: 13px; }

.compare-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 -12px;
  padding: 0 12px;
  border-top: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
}
.compare-tabel {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  background: transparent;
}
.compare-tabel thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--bg);
  color: var(--text-muted);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 0.04em;
  text-align: left;
  padding: 6px 4px;
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
}
.compare-tabel tbody td {
  padding: 6px 4px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  vertical-align: top;
}
.compare-tabel tbody tr.is-anchor td { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.compare-tabel tbody tr.is-me td { font-weight: 600; }

.compare-tabel .c-rm { width: 28px; padding: 4px; text-align: center; }
.compare-rm {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  width: 24px;
  height: 24px;
  font-size: 16px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.compare-rm:hover { color: var(--bad); }

.compare-tabel .c-driver { min-width: 100px; max-width: 160px; padding-right: 8px; }
.compare-tabel .c-driver-name { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.compare-tabel .c-driver-meta { display: block; font-size: 11px; color: var(--text-muted); font-weight: 400; }
.me-badge {
  display: inline-block;
  background: var(--accent);
  color: var(--accent-on);
  font-size: 9px;
  font-weight: 700;
  padding: 1px 5px;
  margin-right: 4px;
  vertical-align: 1px;
  letter-spacing: 0.04em;
}

.compare-tabel .c-num { text-align: right; min-width: 56px; padding: 6px 6px; }
.compare-tabel .c-time { display: block; font-weight: 500; }
.compare-tabel .c-total .c-time { font-weight: 700; }
.compare-tabel .c-delta {
  display: block;
  font-size: 11px;
  font-weight: 600;
  margin-top: 2px;
}
.compare-tabel .c-delta.delta-better { color: var(--good); }
.compare-tabel .c-delta.delta-worse { color: var(--bad); }
.compare-tabel .c-delta.delta-equal { color: var(--text-muted); }
.compare-tabel .c-delta.delta-cross-class {
  color: var(--text-muted);
  opacity: 0.55;
  text-decoration: line-through dotted;
}

/* Other-class rows: dim slightly so anchor's class is dominant. */
.compare-tabel tbody tr.is-other-class td { color: var(--text-muted); }
.compare-tabel tbody tr.is-other-class .c-driver-name,
.compare-tabel tbody tr.is-other-class .c-time { color: var(--text); }
.other-class-tag { color: var(--warn); font-weight: 500; }

/* No-data rows sink to the bottom and dim — they're visible but de-emphasised. */
.compare-tabel tbody tr.is-no-data td { opacity: 0.6; }
.compare-tabel tbody tr.is-no-data .c-driver-name { color: var(--text-muted); font-weight: 500; }

/* Explicit column widths so 360px layout is predictable. */
.compare-tabel col.c-rm-col { width: 32px; }
.compare-tabel col.c-driver-col { width: 38%; min-width: 110px; }
.compare-tabel col.c-num-col { width: 64px; }

.compare-hint {
  font-size: 12px;
  color: var(--text-muted);
  margin: 8px 0 0;
  line-height: 1.5;
}

/* -----------------------------------------------------------------------------
 * Tabel-mode — true HTML table, all columns, spreadsheet-dense.
 * Inspired by the original Vola layout but with proper typography.
 * Hidden by default; shown only when body.mode-tabel.
 * Card-based row-cards are hidden when tabel is active.
 * ---------------------------------------------------------------------------*/
.results-tabel-wrap { display: none; overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0 -12px; padding: 0 12px; }
.mode-tabel .results-tabel-wrap { display: block; }
.mode-tabel .heat .row-cards { display: none; }
/* Default mode-quick / mode-details: keep tabel-wrap fully hidden. */
.mode-quick .results-tabel-wrap,
.mode-details .results-tabel-wrap { display: none; }

.results-tabel {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  background: var(--surface);
}
.results-tabel thead th {
  /* Native CSS `position: sticky` is broken inside .results-tabel-wrap because
     overflow-x: auto turns the wrap into the sticky containing block, and
     the wrap doesn't scroll vertically. live.js attachStickyTableHeader()
     handles vertical sticky-thead via a JS-driven floating clone. */
  background: var(--surface-2);
  color: var(--text-muted);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 0.04em;
  text-align: left;
  padding: 6px 6px;
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
}
.results-tabel tbody td {
  padding: 4px 6px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  color: var(--text);
}
.results-tabel tbody tr:nth-child(even) td {
  background: var(--surface-2);
}
.results-tabel tbody tr.is-me td {
  background: color-mix(in srgb, var(--accent) 14%, var(--surface));
  font-weight: 600;
}
.results-tabel tbody tr.is-me:nth-child(even) td {
  background: color-mix(in srgb, var(--accent) 14%, var(--surface-2));
}
.results-tabel tbody tr.is-following td {
  background: color-mix(in srgb, var(--row-tag-color, var(--ob-bg)) 16%, var(--surface));
}
.results-tabel tbody tr.is-following:nth-child(even) td {
  background: color-mix(in srgb, var(--row-tag-color, var(--ob-bg)) 16%, var(--surface-2));
}
/* Class-color stripe: applied as an inset shadow on the FIRST cell of each
   row (t-fav) instead of as a tr-level border-left. tr.border-left would
   create a 3px gap on the left edge of the screen during horizontal scroll
   — sticky cols sit AFTER the tr's border, so the border stays visible
   left-of-the-sticky-cols. Putting the stripe on t-fav (which is sticky
   left:0) keeps the visual cue moving WITH the sticky col, eliminating the
   gap. */
.results-tabel tbody tr td.t-fav {
  box-shadow: inset 3px 0 0 var(--class-color, transparent);
}
.results-tabel .t-rank { font-weight: 700; }
.results-tabel .t-nr { color: var(--text-muted); }
.results-tabel .t-driver { font-weight: 500; overflow: hidden; text-overflow: ellipsis; }
/* Driver-name links inside tabel + row-cards: inherit color so the cell
   doesn't blue-up the whole leaderboard. Underline on hover only. */
.t-driver-link, .t-codriver-link, .row-driver-link {
  color: inherit;
  text-decoration: none;
}
.t-driver-link:hover, .t-codriver-link:hover, .row-driver-link:hover {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* -----------------------------------------------------------------------------
 * Sticky left-columns when the table is scrolled horizontally on mobile.
 * Følg + Pl + Nr + Kører pin to the left edge so the user keeps a stable
 * "who am I looking at" anchor while the rest of the row scrolls into view.
 * Widths are explicit and accumulate as `left:` offsets per column.
 * ---------------------------------------------------------------------------*/
.results-tabel th.t-fav,
.results-tabel td.t-fav {
  position: sticky;
  left: 0;
  width: 32px;
  min-width: 32px;
  z-index: 3;
  background: var(--surface);
}
.results-tabel th.t-rank,
.results-tabel td.t-rank {
  position: sticky;
  left: 32px;
  width: 32px;
  min-width: 32px;
  z-index: 3;
  background: var(--surface);
  padding-left: 4px;
  padding-right: 4px;
}
.results-tabel th.t-nr,
.results-tabel td.t-nr {
  position: sticky;
  left: 64px;
  width: 40px;
  min-width: 40px;
  z-index: 3;
  background: var(--surface);
  padding-left: 4px;
  padding-right: 4px;
}
.results-tabel th.t-driver,
.results-tabel td.t-driver {
  position: sticky;
  left: 104px;
  z-index: 3;
  background: var(--surface);
  /* Subtle shadow on the right edge marks the "frozen" boundary. */
  box-shadow: 1px 0 0 var(--border-strong);
  padding-left: 6px;
  padding-right: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 120px;
  max-width: 220px;
}
/* "PÅ BANEN" — driver is currently on track NOW. Derived from Vola's grid 2
   (GRID_CURRENT). Sharp newspaper styling: solid border, no radius, blinking
   dot via keyframes (CSP-safe — no inline JS). */
.pill-on-track {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 6px;
  margin-left: 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--bad);
  border: 1px solid var(--bad);
  background: color-mix(in srgb, var(--bad) 10%, var(--surface));
  text-transform: uppercase;
  vertical-align: middle;
  white-space: nowrap;
}
.pill-on-track::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  background: var(--bad);
  border-radius: 50%;
  animation: pill-on-track-blink 1.4s ease-in-out infinite;
}
@keyframes pill-on-track-blink {
  0%, 60% { opacity: 1; }
  70%, 100% { opacity: 0.25; }
}
@media (prefers-reduced-motion: reduce) {
  .pill-on-track::before { animation: none; }
}
.row-card.is-on-track .row-class-flag,
tr.is-on-track {
  /* Subtle highlight at row-level so the live status reads even with the pill
     scrolled out of view in Tabel mode. */
}
tr.is-on-track td {
  border-top: 1px solid var(--bad) !important;
  border-bottom: 1px solid var(--bad) !important;
}

/* `is-highlighted` — temporarily added by live.js when the URL hash carries
   `highlight=<nr>` (driver-profile back-link). Pulses for 3.5s, then JS
   removes the class.

   Architecture: an absolutely-positioned ::before overlay carries the
   highlight tint and fades to opacity:0. Underneath, the row's actual
   background (zebra / is-me / is-following / surface) shows through —
   no "snap to default surface, then snap to actual color" mid-fade.
   Only top + bottom inset shadows (horizontal stripes), no vertical
   border to clash with the sticky-col visual rhythm. */
/* Highlight = top + bottom hairline stripes that fade out. No fill overlay
   (an earlier ::before tint created layout artifacts on sticky cells +
   visually obscured cell content). Pure box-shadow — zero layout impact. */
.row-card.is-highlighted,
tr.t-row.is-highlighted td {
  animation: row-highlight-shadow 3.5s ease-out forwards;
}
@keyframes row-highlight-shadow {
  0%, 60% { box-shadow: inset 0 3px 0 var(--accent), inset 0 -3px 0 var(--accent); }
  100%    { box-shadow: inset 0 0 0 transparent, inset 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .row-card.is-highlighted,
  tr.t-row.is-highlighted td {
    animation: none;
    box-shadow: inset 0 3px 0 var(--accent), inset 0 -3px 0 var(--accent);
  }
}

/* `is-ghost` — drivers entered (Vola startlist) but absent from this heat's
   ranking grid. Rendered so the user can search for + tag them, but visually
   afdæmpet so they don't compete with active timing data for attention. The
   class-color stripe stays so class-membership is still scannable. */
.row-card.is-ghost,
tr.t-row.is-ghost {
  opacity: 0.55;
}
.row-card.is-ghost .row-driver,
.row-card.is-ghost .row-codriver,
tr.t-row.is-ghost .t-driver,
tr.t-row.is-ghost .t-codriver {
  font-style: italic;
}
/* Tag/follow + menu buttons stay full opacity so they're clearly tappable. */
.row-card.is-ghost .row-tag,
.row-card.is-ghost .row-menu,
tr.t-row.is-ghost .t-fav-btn {
  opacity: 1;
}

/* Sortable headers: tiny chevron after the label when active. */
.results-tabel thead th.is-sortable {
  cursor: pointer;
  user-select: none;
}
.results-tabel thead th.is-sortable:hover { background: var(--surface-3); }
.results-tabel thead th.is-sortable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.results-tabel thead th[aria-sort]::after {
  content: "";
  display: inline-block;
  margin-left: 4px;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  vertical-align: middle;
}
.results-tabel thead th[aria-sort="ascending"]::after {
  border-bottom: 5px solid currentColor;
}
.results-tabel thead th[aria-sort="descending"]::after {
  border-top: 5px solid currentColor;
}

/* Default: show full driver name. Abbreviated form is hidden. */
.t-driver-full { display: inline; }
.t-driver-short { display: none; }
/* Mobile: only when the table has been horizontally scrolled (set by JS on
   the wrap), shrink the sticky cell and swap to the abbreviated form. We
   keep the same font-size to avoid a jarring re-flow on scroll. */
@media (max-width: 640px) {
  .results-tabel-wrap.is-scrolled .results-tabel th.t-driver,
  .results-tabel-wrap.is-scrolled .results-tabel td.t-driver {
    width: 96px;
    min-width: 96px;
    max-width: 96px;
  }
  .results-tabel-wrap.is-scrolled .t-driver-full { display: none; }
  .results-tabel-wrap.is-scrolled .t-driver-short { display: inline; }
}
/* Sticky leftmost columns (horizontal-sticky inside the wrap) keep their
   z-index. The headers' surface-2 background already comes from the rule
   above. */
.results-tabel thead th.t-fav,
.results-tabel thead th.t-rank,
.results-tabel thead th.t-nr,
.results-tabel thead th.t-driver {
  background: var(--surface-2);
}

/* Floating thead clone — JS-managed (live.js attachStickyTableHeader). When
   the user scrolls the page past the table's real thead, this fixed-position
   table-clone takes over so the column headers stay visible at the top of
   the viewport. Sized in JS to match the source table's column widths.
   Positioned BELOW the full sticky stack (site-header + .race-header) via
   the --sticky-stack-h variable (computed in sw-register.js).

   The floater is itself a horizontal scroll container, so the sticky-col
   declarations on its leftmost cells (t-fav/t-rank/t-nr/t-driver) actually
   work — JS syncs `floater.scrollLeft = wrap.scrollLeft` so the frozen
   columns mirror the body-table's frozen behaviour. The scrollbar is
   visually hidden — pointer-events:none means the user can't even reach
   the floater. */
.results-tabel-floater {
  position: fixed;
  /* Overlap the sticky stack by 1px to absorb sub-pixel gaps. */
  top: calc(var(--sticky-stack-h, var(--header-h, 60px)) - 1px);
  left: 0;
  z-index: 25;
  display: none;
  pointer-events: none;
  margin: 0;
  background: var(--surface-2);
  box-shadow: 0 1px 0 var(--border-strong);
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.results-tabel-floater::-webkit-scrollbar { width: 0; height: 0; display: none; }
.results-tabel-floater.is-visible { display: block; }
.results-tabel-floater table {
  margin: 0;
  border-collapse: collapse;
  table-layout: fixed;
  background: var(--surface-2);
}
.results-tabel-floater th {
  background: var(--surface-2);
  color: var(--text-muted);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 0.04em;
  text-align: left;
  padding: 4px 6px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
/* Sticky columns inside the floater mirror the body-table's frozen-col
   behaviour. Because the floater is itself a horizontal scroll container,
   `position: sticky` actually works here. */
.results-tabel-floater th.t-fav {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--surface-2);
}
.results-tabel-floater th.t-rank {
  position: sticky;
  left: 32px;
  z-index: 2;
  background: var(--surface-2);
}
.results-tabel-floater th.t-nr {
  position: sticky;
  left: 64px;
  z-index: 2;
  background: var(--surface-2);
}
.results-tabel-floater th.t-driver {
  position: sticky;
  left: 104px;
  z-index: 2;
  background: var(--surface-2);
  box-shadow: 1px 0 0 var(--border-strong);
}
/* Zebra-stripe sticky cells must match their row's actual background.
   Without this, the sticky cells render var(--surface) and fail to hide the
   scrolled non-sticky content behind them. */
.results-tabel tbody tr:nth-child(even) td.t-fav,
.results-tabel tbody tr:nth-child(even) td.t-rank,
.results-tabel tbody tr:nth-child(even) td.t-nr,
.results-tabel tbody tr:nth-child(even) td.t-driver {
  background: var(--surface-2);
}
.results-tabel tbody tr.is-me td.t-fav,
.results-tabel tbody tr.is-me td.t-rank,
.results-tabel tbody tr.is-me td.t-nr,
.results-tabel tbody tr.is-me td.t-driver {
  background: color-mix(in srgb, var(--accent) 18%, var(--surface));
}
.results-tabel tbody tr.is-me:nth-child(even) td.t-fav,
.results-tabel tbody tr.is-me:nth-child(even) td.t-rank,
.results-tabel tbody tr.is-me:nth-child(even) td.t-nr,
.results-tabel tbody tr.is-me:nth-child(even) td.t-driver {
  background: color-mix(in srgb, var(--accent) 18%, var(--surface-2));
}
.results-tabel tbody tr.is-following td.t-fav,
.results-tabel tbody tr.is-following td.t-rank,
.results-tabel tbody tr.is-following td.t-nr,
.results-tabel tbody tr.is-following td.t-driver {
  background: color-mix(in srgb, var(--row-tag-color, var(--ob-bg)) 20%, var(--surface));
}
.results-tabel tbody tr.is-following:nth-child(even) td.t-fav,
.results-tabel tbody tr.is-following:nth-child(even) td.t-rank,
.results-tabel tbody tr.is-following:nth-child(even) td.t-nr,
.results-tabel tbody tr.is-following:nth-child(even) td.t-driver {
  background: color-mix(in srgb, var(--row-tag-color, var(--ob-bg)) 20%, var(--surface-2));
}
.results-tabel .t-codriver,
.results-tabel .t-car { color: var(--text-muted); max-width: 140px; overflow: hidden; text-overflow: ellipsis; }
.results-tabel .t-class { text-align: center; font-weight: 600; font-size: 11px; }
.results-tabel .t-num { text-align: right; min-width: 56px; }
.results-tabel .t-total { font-weight: 700; }
.results-tabel .t-gap { color: var(--text-muted); }
.results-tabel .t-pen { color: var(--warn); font-weight: 600; }
.results-tabel .t-pen-active {
  background: color-mix(in srgb, var(--warn) 14%, var(--surface));
  /* No left-border — the cell tint alone is enough emphasis; the orange
     2px stripe was visually heavy + read as a separator between columns. */
}
/* Per-run penalty caption: a tiny orange line of text under the run-time in
   the Tabel cell. Only renders when Vola publishes per-run penalty data
   (e.g., "+5s K R1"); otherwise the span is omitted entirely. */
.results-tabel td.t-num .t-run-time { display: inline-block; }
.results-tabel td.t-num .t-run-pen {
  display: block;
  font-size: 10px;
  font-weight: 600;
  color: var(--warn);
  line-height: 1.2;
  letter-spacing: 0.02em;
}
/* Per-run penalty in the row-card runs grid (Hurtig/Detaljer). */
.run-cell .run-pen {
  display: block;
  margin-top: 2px;
  font-size: 10px;
  font-weight: 600;
  color: var(--warn);
  letter-spacing: 0.02em;
}
.results-tabel .t-ob { color: var(--ob-fg); font-weight: 700; }
.results-tabel .t-cb { color: var(--cb-fg); font-weight: 600; }
.results-tabel .t-pb { color: var(--pb-fg); font-weight: 600; }

/* Test-run columns (slot.counts === false). Visually de-emphasised so users
 * can tell at a glance these don't count toward Total. NEWSPAPER aesthetic:
 * just a softer text colour, no badge or "(test)" suffix in the cell — the
 * column header carries the affordance via the t-prefix and tooltip. */
.results-tabel th.t-trun,
.results-tabel td.t-trun { color: var(--text-muted); }
/* Hairline divider between the last test-column and the first non-test
 * column (or vice versa if a category re-orders). Newspaper-style separator,
 * NOT a card boundary. */
.results-tabel th.t-trun + th:not(.t-trun),
.results-tabel td.t-trun + td:not(.t-trun) { border-left: 1px solid var(--border); }
.results-tabel th:not(.t-trun) + th.t-trun,
.results-tabel td:not(.t-trun) + td.t-trun { border-left: 1px solid var(--border); }
/* Hurtig/Detaljer .row-runs equivalent: muted opacity for test-run pills. */
.run-cell.is-test { opacity: 0.6; }
.run-cell.is-test .run-label { color: var(--text-muted); }

/* Driver-page recent-results: test-source rows render the heat label as
 * "T{n}" (instead of "R{n}") and get a soft mute on the cell so the eye
 * naturally separates test from race entries within the same race block.
 * Newspaper-style — no badge or pill chrome. */
.driver-results .d-heat-test { color: var(--text-muted); font-style: italic; }
.driver-results .d-heat-test a { color: inherit; }
.mode-tabel .heat-tabs { margin-bottom: 4px; }
.mode-tabel .grid-tabs { margin-bottom: 4px; }
/* On wide screens we can shrink even tighter. */
@media (min-width: 720px) {
  .results-tabel { font-size: 13px; }
  .results-tabel tbody td { padding: 5px 8px; }
}

/* -----------------------------------------------------------------------------
 * Sticky-me dock
 * ---------------------------------------------------------------------------*/
.me-sticky {
  position: sticky;
  top: 120px;
  z-index: 15;
  margin: 8px 0;
  pointer-events: auto;
}
.me-sticky-inner {
  background: var(--surface);
  border: 2px solid var(--accent);
  border-radius: var(--radius);
  padding: 8px 12px;
  box-shadow: var(--shadow-strong);
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}
.me-sticky-inner .me-pill {
  background: var(--accent);
  color: var(--accent-on);
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  letter-spacing: 0.04em;
}
.me-sticky-inner .me-text { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.me-sticky-inner .me-name { font-weight: 600; }
.me-sticky-inner .me-summary { font-size: 12px; color: var(--text-muted); }
.me-sticky-inner .me-time { font-weight: 700; }

/* -----------------------------------------------------------------------------
 * Mode switcher (fixed bottom segmented control)
 * ---------------------------------------------------------------------------*/
.mode-switcher {
  position: fixed;
  bottom: max(12px, env(safe-area-inset-bottom));
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 4px;
  gap: 2px;
  z-index: 25;
  box-shadow: var(--shadow-strong);
}
.mode-btn {
  background: transparent;
  border: 0;
  color: var(--text);
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  min-height: 40px;
}
.mode-btn.active {
  background: var(--accent);
  color: var(--accent-on);
  font-weight: 600;
}

/* -----------------------------------------------------------------------------
 * Confirm dialog
 * ---------------------------------------------------------------------------*/
.me-confirm {
  border: 0;
  border-radius: var(--radius);
  padding: 0;
  background: transparent;
  max-width: 420px;
  width: 90%;
}
.me-confirm::backdrop { background: rgba(0, 0, 0, 0.5); }
.me-confirm-form {
  background: var(--surface);
  color: var(--text);
  padding: 20px;
  border-radius: var(--radius);
}
.me-confirm-form h2 { margin: 0 0 8px; font-size: 18px; }
.me-confirm-body { margin: 8px 0; }
.me-confirm-actions {
  list-style: none;
  padding: 0;
  margin: 16px 0 0;
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}
.me-confirm-actions button {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 10px 16px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-weight: 500;
}
.me-confirm-actions [data-me-ok] {
  background: var(--accent);
  color: var(--accent-on);
  border-color: var(--accent);
  font-weight: 600;
}
.me-confirm-actions [data-me-ok]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* -----------------------------------------------------------------------------
 * Existing pages (admin / driver)
 * ---------------------------------------------------------------------------*/
.results { width: 100%; border-collapse: collapse; background: var(--surface); border-radius: var(--radius-sm); overflow: hidden; font-size: 14px; }
.results th, .results td { padding: 8px 10px; border-bottom: 1px solid var(--border); white-space: nowrap; }
.results thead th { background: var(--surface-2); font-weight: 600; color: var(--text-muted); text-transform: uppercase; font-size: 11px; letter-spacing: 0.04em; }
.results tr:last-child td { border-bottom: 0; }
.results tbody tr:hover { background: var(--surface-2); }
.results td { font-variant-numeric: tabular-nums; }

.align-left { text-align: left; }
.align-center { text-align: center; }
.align-right { text-align: right; }

.empty { color: var(--text-muted); padding: 16px; }
.muted { color: var(--text-muted); }

.sources { margin-top: 22px; color: var(--text-muted); font-size: 13px; }
.sources summary { cursor: pointer; }
.err { color: var(--bad); }

.admin-header { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.admin-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; margin-bottom: 22px; box-shadow: var(--shadow); }

.grid-form { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 16px; }
.grid-form .full,
.grid-form label.full { grid-column: 1 / -1; }
.grid-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-muted); }
input, select, textarea, button {
  font: inherit;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
}
/* Native select chevron — replace the OS default with a hairline triangle so
   the control reads consistent across light/dark/sun themes. */
select {
  appearance: none;
  -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-muted) 50%),
                    linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
  background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 28px;
  cursor: pointer;
}
button { cursor: pointer; background: var(--accent); color: var(--accent-on); border-color: var(--accent); font-weight: 600; }
button:hover { filter: brightness(1.06); }
button.danger { background: transparent; color: var(--bad); border-color: var(--bad); }
form.inline { display: inline; }
form.inline-form { display: flex; gap: 6px; margin-top: 8px; }
form.inline-form input { flex: 1; }

.race-row { padding: 14px 0; border-bottom: 1px solid var(--border); }
.race-row:last-child { border-bottom: 0; }
.race-row-head { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.source-list { list-style: none; padding: 0; margin: 8px 0; }
.source-list li { padding: 6px 0; font-size: 13px; color: var(--text-muted); }
.source-list small { color: var(--text-muted); font-size: 12px; }

/* Per-link rows on "Opret nyt løb" form — repeater UI mirroring the per-
 * source edit form on existing races. Density over comfort, hairline rules. */
.url-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 6px;
  margin-bottom: 8px;
}
.url-row {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}
.url-row .url-row-url {
  flex: 1 1 260px;
  min-width: 200px;
  font-size: 12px;
  padding: 4px 6px;
}
.url-row .url-row-narrow { width: 90px; flex: 0 0 auto; font-size: 12px; padding: 4px 6px; }
.url-row .js-cat-preset { flex: 0 0 auto; font-size: 12px; padding: 4px 6px; }
.url-row .row-remove {
  flex: 0 0 auto;
  padding: 4px 8px;
  font-size: 14px;
  line-height: 1;
}
.row-add {
  font-size: 12px;
  padding: 4px 8px;
  background: transparent;
  border: 1px dashed var(--border);
  cursor: pointer;
}
.row-add:hover { background: var(--surface-2); }

/* Per-source config form — admin can re-categorise a source after creation.
 * Compact one-row layout, density over comfort. The narrow-fields shrink to
 * fit a 2-3 char input (prefix, order, counts). Labels are above inputs in
 * column-flex so they don't wrap awkwardly when the row gets crowded. */
form.source-config-form,
form.source-add-form {
  display: flex;
  gap: 6px;
  align-items: flex-end;
  flex-wrap: wrap;
  margin-top: 6px;
  font-size: 12px;
}
form.source-config-form .src-field,
form.source-add-form > * {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
form.source-config-form .src-field input,
form.source-config-form .src-field select,
form.source-add-form input,
form.source-add-form select {
  font-size: 12px;
  padding: 4px 6px;
}
form.source-config-form .src-field-narrow input,
form.source-config-form .src-field-narrow select {
  width: 70px;
}
form.source-add-form input[name="url"] { flex: 1; min-width: 220px; }
form.source-add-form input[name="label"] { flex: 0 1 140px; }

.flash { padding: 10px 14px; border-radius: var(--radius-sm); margin-bottom: 14px; }
.flash-error { background: rgba(179, 38, 30, 0.1); border: 1px solid var(--bad); color: var(--bad); }
.flash-info { background: rgba(10, 77, 140, 0.1); border: 1px solid var(--accent); color: var(--accent); }

.login-form { display: flex; flex-direction: column; gap: 10px; max-width: 320px; }
.login-form label { display: flex; flex-direction: column; gap: 4px; }

/* -----------------------------------------------------------------------------
 * Driver profile page — newspaper aesthetic.
 * Hairline rules, sharp edges, tabular nums. NO rounded-card+stripe combo,
 * NO drop-shadows on data rows. Reference: F1.com results / FlashScore.
 * ---------------------------------------------------------------------------*/
.driver-page { padding-top: 14px; }
.driver-hero {
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: 14px;
  margin-bottom: 22px;
}
.driver-hero-row { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; }
.driver-hero h1 { margin: 0; }
.driver-badge {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--good);
  border: 1px solid var(--good);
  padding: 1px 6px;
}
.driver-city { color: var(--text-muted); margin: 4px 0 0; font-size: 14px; }
.driver-alts { color: var(--text-muted); margin: 6px 0 0; font-size: 13px; }
.driver-alts-label { font-weight: 600; color: var(--text); }
.driver-notes { color: var(--text-muted); font-size: 13px; margin: 8px 0 0; font-style: italic; }
.driver-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
  margin: 14px 0 0;
  padding: 0;
  border-top: 1px solid var(--border);
}
.driver-stat {
  padding: 10px 12px;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.driver-stat:last-child { border-right: 0; }
.driver-stat dt {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.driver-stat dd {
  margin: 0;
  font-size: 22px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.driver-stat-time { font-size: 18px; }
.driver-stat-sub { font-weight: 400; font-size: 14px; color: var(--text-muted); margin-left: 4px; }
.driver-section { margin: 24px 0; }
.driver-section h2 {
  margin: 0 0 8px;
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text);
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: 4px;
}
.driver-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0 -12px; padding: 0 12px; }
.driver-results {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  background: var(--surface);
}
.driver-results thead th {
  background: var(--surface-2);
  color: var(--text-muted);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 0.04em;
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
}
.driver-results tbody td {
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  color: var(--text);
}
.driver-results tbody tr:nth-child(even) td {
  background: color-mix(in srgb, var(--surface-2) 60%, transparent);
}
.driver-results .d-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.driver-results .d-rank { font-weight: 700; white-space: nowrap; }
.driver-results .d-rank-class { font-weight: 400; color: var(--text-muted); }
.driver-results .d-nr { color: var(--text-muted); white-space: nowrap; }
.driver-results .d-class { font-weight: 600; }
/* Race-type label after the display code in podium rows. Only renders when
   the aggregate is bound to a known race_type. Muted weight so the class
   code stays the lead. */
.driver-results .d-class-type {
  font-weight: 400;
  color: var(--text-muted);
}
.driver-results .d-date { color: var(--text-muted); white-space: nowrap; }
.driver-results .d-race a { font-weight: 500; }
.driver-results .d-car,
.driver-results .d-codriver { color: var(--text-muted); }
.driver-list {
  list-style: none;
  padding: 0;
  margin: 0;
  font-variant-numeric: tabular-nums;
}
.driver-list li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
}
.driver-list li:last-child { border-bottom: 0; }
.driver-list-meta { color: var(--text-muted); font-size: 13px; }
@media (max-width: 640px) {
  .driver-stats { grid-template-columns: repeat(2, 1fr); }
  .driver-stat { border-bottom: 1px solid var(--border); }
  .driver-stat:nth-child(2n) { border-right: 0; }
  .driver-stat:nth-last-child(-n+2) { border-bottom: 0; }
}

/* -----------------------------------------------------------------------------
 * Mobile tightening
 * ---------------------------------------------------------------------------*/
@media (max-width: 640px) {
  .grid-form { grid-template-columns: 1fr; }
  .results { font-size: 13px; }
  .results th, .results td { padding: 6px 7px; }
  /* Mobile row layout: keep the 36px left rail, compress content area to a
     2-row grid where rank+name share the top, id+meta+menu share the bottom.
     Time always lives at the right edge of the top row so it never wraps. */
  .row-card { grid-template-columns: 32px 1fr; column-gap: 6px; padding-right: 8px; }
  .row-tag { width: 28px; height: 28px; margin-top: 2px; }
  .row-card-head {
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    grid-template-areas:
      "rank name name time"
      "id   meta meta menu";
    column-gap: 6px;
  }
  .row-rank { grid-area: rank; }
  .row-id   { grid-area: id; font-size: 11px; }
  .row-name { grid-area: name; }
  .row-time { grid-area: time; }
  .row-meta { grid-area: meta; font-size: 11px; line-height: 1.3; }
  .row-meta .row-weather { font-size: 11px; }
  .row-menu { grid-area: menu; align-self: end; }
  /* On phones the weather chip is most useful at the right edge of meta — let
     the car string ellipsize first to keep weather visible. */
  .row-car { flex: 0 1 auto; min-width: 32px; }
  .row-runs { grid-template-columns: repeat(2, 1fr); }

  /* Edge-to-edge layout on phones: kill the container's horizontal padding so
     the topbar (race-header, search, filter) and the leaderboard table fill
     the full viewport width. Add per-section padding for things that need a
     visual gutter (heat-tabs, row-cards). The Tabel itself is already pulled
     to the edges via its own margin/padding rule above. */
  .container { padding-left: 0; padding-right: 0; }
  /* Override desktop's race-page max-width: min(1800px, 100vw - 32px) — on
     mobile we want zero margin, full viewport. */
  .container[data-page="race"] { max-width: none; }
  .race-header { padding-left: 12px; padding-right: 12px; }
  .heat-tabs,
  .grid-tabs { padding-left: 12px; padding-right: 12px; }
  .row-cards { padding-left: 12px; padding-right: 12px; }
  .compare-panel { padding-left: 12px; padding-right: 12px; }
  .race-list,
  .empty,
  .compare-empty { padding-left: 12px; padding-right: 12px; }
  /* tabel-wrap was pulling itself out of the container with `-16px` margin —
     now that container has 0 padding, no offset is needed. */
  .mode-tabel .results-tabel-wrap { margin: 0; padding: 0; }

  /* Mobile race-controls layout: search field on its own row (full width so
     placeholder text doesn't get cropped to "Søg navn, nr, bil eller co-dr"),
     then "Udvalgte" + "Filtrer klasse" side-by-side on row 2 with fixed
     widths so the layout doesn't reflow as the user types. */
  .race-controls .search-field { flex: 1 1 100%; }
  .race-controls .filter-group { flex: 0 0 auto; min-width: 130px; }
  .race-controls .class-filter { flex: 0 0 auto; }
  .race-controls .class-filter-toggle { white-space: nowrap; }

  /* "Udvalgte" filter-dropdown becomes a bottom-sheet modal on mobile (parity
     with the class-filter modal). The backdrop element is rendered separately
     so clicks on it can close the sheet. */
  .filter-dropdown {
    inset: auto 0 0 0 !important;
    top: auto !important;
    right: 0 !important;
    left: 0 !important;
    width: 100%;
    max-width: none;
    min-width: 0;
    z-index: 1100;
    border-left: 0;
    border-right: 0;
    border-bottom: 0;
    box-shadow: 0 -8px 24px color-mix(in srgb, var(--text) 24%, transparent);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .filter-dropdown-backdrop {
    display: block;
  }
  .filter-dropdown button {
    min-height: 48px;
  }

  /* Mode-switcher: on mobile, full-width fixed bottom bar (newspaper-style,
     hard edges, hairline rule on top — NOT a centered floating pill). The
     centered pill works on desktop but feels tiny + draws less attention on
     phones. Edge-to-edge bar is finger-thumb-friendly. */
  .mode-switcher {
    left: 0;
    right: 0;
    bottom: 0;
    transform: none;
    border: 0;
    border-top: 1px solid var(--border-strong);
    border-radius: 0;
    box-shadow: 0 -2px 8px color-mix(in srgb, var(--text) 8%, transparent);
    padding: 4px 4px max(4px, env(safe-area-inset-bottom));
    width: 100%;
    justify-content: stretch;
    gap: 0;
  }
  .mode-switcher .mode-btn {
    flex: 1 1 0;
    border-radius: 0;
    padding: 10px 6px;
    min-height: 44px;
    font-size: 13px;
  }
  /* Reserve space at the bottom of the page so the fixed bar doesn't cover
     the last row of content (compare panel, last heat, etc.). */
  main.container {
    padding-bottom: calc(56px + env(safe-area-inset-bottom));
  }
}

/* -----------------------------------------------------------------------------
 * Tag-picker bottom-sheet. Long-press on a follow-button opens this. The
 * design follows the newspaper-table aesthetic: hairline rules, sharp edges,
 * no rounded-card-stripes, no drop-shadows on chips.
 * ---------------------------------------------------------------------------*/
.tag-picker[hidden] { display: none; }
.tag-picker {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.tag-picker-backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--text) 32%, transparent);
}
.tag-picker-inner {
  position: relative;
  width: 100%;
  max-width: 480px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-bottom: 0;
  padding: 16px 14px 24px;
  /* No rounded sheet on mobile (newspaper aesthetic). On desktop, a tiny */
  /* radius is fine because the backdrop centers the sheet vertically. */
  /* iOS: if finger still down when picker opens, must not select option labels. */
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  user-select: none;
}
@media (min-width: 640px) {
  .tag-picker {
    align-items: center;
  }
  .tag-picker-inner {
    border-bottom: 1px solid var(--border-strong);
    padding: 18px 18px 18px;
  }
}
.tag-picker-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}
.tag-picker-title {
  font-weight: 700;
  font-size: 15px;
  color: var(--text);
}
.tag-picker-title .muted {
  color: var(--text-muted);
  font-weight: 500;
}
.tag-picker-close {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  font-size: 24px;
  line-height: 1;
  padding: 0 8px;
  cursor: pointer;
  min-height: 44px;
  min-width: 44px;
}
.tag-picker-close:hover { color: var(--text); }
.tag-picker-help {
  margin: 0 0 12px;
  font-size: 12px;
  color: var(--text-muted);
}
/* Column header row above .tag-picker-list. Same typography as the
   .results-tabel thead — 10px uppercase, muted, letter-spacing 0.04em — so
   the user reads them as table column labels, not as inline row text.
   Two right-aligned cells whose widths mirror the controls beneath:
   - "AKTIV" sits over the inline state-pill in the chip column (right-aligned
     end of the chip).
   - "PUSH" sits over the bell button.
   A hairline divider between them mirrors the visual separator between the
   chip and the bell, reinforcing the two-column reading. */
.tag-picker-cols {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 4px 4px 6px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
}
/* AKTIV label sits flush-right of the chip area. The actual chip-state pill
   inside .tag-chip lives at the chip's right edge (grid column "auto"), so
   "AKTIV" ends up directly above where the state-pill renders. */
.tag-picker-cols .tag-picker-col-active {
  margin-left: auto;
  text-align: right;
  padding-right: 4px;
}
/* PUSH label hovers over the bell. min-width matches the bell's min-width
   (44px) so the label centres above the button. A hairline left-divider
   echoes the column boundary; the bell beneath inherits its own box-border
   so we don't add weight inside each row. The 8px padding-left clears the
   divider from the label glyphs. */
.tag-picker-cols .tag-picker-col-push {
  min-width: 44px;
  padding: 0 0 0 8px;
  margin-left: 0;
  text-align: center;
  border-left: 1px solid var(--border);
}
.tag-picker-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.tag-picker-list li {
  border-bottom: 1px solid var(--border);
}
/* tag-picker-row wraps the tag-chip + the per-slot push-bell on the same line.
   The chip takes the available width; the bell sits flush right.
   AKTIV vs PUSH separation: the gap is widened from 6px to 16px and the bell
   already carries its own 1px box-border (see .tag-picker-bell), so the
   chip-state ("AKTIV") and the bell read as two distinct controls. The
   column-header row above the list (.tag-picker-cols) reinforces this with
   labels + a hairline divider between the AKTIV and PUSH columns. */
.tag-picker-row {
  display: flex;
  align-items: stretch;
  gap: 16px;
}
.tag-picker-row .tag-chip { flex: 1 1 auto; min-width: 0; }
.tag-chip {
  width: 100%;
  display: grid;
  grid-template-columns: 28px 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 12px 4px;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: var(--text);
  font: inherit;
  min-height: 48px;
}
.tag-chip:hover { background: var(--surface-2); }
.tag-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.tag-chip-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  color: var(--text-muted);
}
.tag-chip-icon .icon-tag {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
}
.tag-chip[aria-pressed="true"] .tag-chip-icon {
  color: var(--tag-color);
}
.tag-chip[aria-pressed="true"] .tag-chip-icon .icon-tag {
  fill: currentColor;
  stroke: currentColor;
}
.tag-chip-label {
  font-weight: 500;
  font-size: 14px;
}
.tag-chip[aria-pressed="true"] .tag-chip-label { font-weight: 700; }
.tag-chip-state {
  font-size: 11px;
  color: var(--tag-color, var(--text-muted));
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.tag-picker-foot {
  margin-top: 14px;
  display: flex;
  justify-content: flex-end;
}
.tag-picker-done {
  background: var(--text);
  color: var(--bg);
  border: 1px solid var(--text);
  padding: 8px 18px;
  font: 600 14px/1 inherit;
  cursor: pointer;
  min-height: 44px;
}
.tag-picker-done:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-on); }

/* Push-bell buttons inside the tag-picker.
   - Off: thin outline, muted bell glyph (clearly "off").
   - On:  bell glyph glows BRIGHT YELLOW + button is filled with the slot's
          (or driver's) own colour. Strong dual signal so a glance at the
          picker tells you which categories you've got push enabled for. */
.tag-picker-bell {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  min-width: 44px;
  padding: 0 10px;
  flex-shrink: 0;
  border-radius: 0;
  transition: background 0.15s, border-color 0.15s;
}
.tag-picker-bell:hover { color: var(--text); border-color: var(--text); }
.tag-picker-bell .icon-bell {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linejoin: round;
}

/* The driver-bell carries an inline label ("Notifikationer") so the user
   immediately understands what the bell does. Slot bells skip the label —
   one explicit label at the top is enough context for the rest. */
.tag-picker-bell-label {
  margin-left: 8px;
  font: 600 12px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
/* DRIVER bell — accent (blue) bg, yellow glow when on. Wider than slot bells
   to fit its label comfortably. */
.tag-picker-bell-driver {
  color: var(--accent);
  border-color: var(--accent);
  padding: 0 14px;
  gap: 6px;
}
.tag-picker-bell-driver:hover {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.tag-picker-bell-driver[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
}
.tag-picker-bell-slot[aria-pressed="true"] .tag-picker-bell-label,
.tag-picker-bell-driver[aria-pressed="true"] .tag-picker-bell-label {
  color: inherit;
}
/* SLOT bell — outline in slot-color, slot-color bg when on. */
.tag-picker-bell-slot {
  color: var(--tag-color);
  border-color: var(--tag-color);
}
.tag-picker-bell-slot:hover {
  background: color-mix(in srgb, var(--tag-color) 12%, transparent);
}
.tag-picker-bell-slot[aria-pressed="true"] {
  background: var(--tag-color);
  border-color: var(--tag-color);
}
/* Yellow bell glyph when ON — universal "notification active" signal. The
   dark stroke keeps the glyph readable on light slot colours (gold, teal). */
.tag-picker-bell[aria-pressed="true"] .icon-bell {
  fill: #ffd24a;
  stroke: #4a2f00;
  stroke-width: 1;
}
/* Tint the row when its slot bell is on so the activated state reads at a
   glance even when scrolling past. Slot bells set --tag-color on the parent
   <li>; we read it via the data-bell-on flag toggled by JS. */
.tag-picker-row[data-bell-on="true"] {
  background: color-mix(in srgb, var(--tag-color) 14%, transparent);
}

/* While the picker is open, prevent body scroll on mobile. */
body.has-tag-picker { overflow: hidden; }

/* Discoverability tip toast. Fixed at bottom of viewport so it never blocks
   any row. Sticky — no auto-fade — the user dismisses with × or by actually
   opening the picker. Persisted-as-seen in localStorage. */
.tag-hint {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: 16px;
  margin: 0 auto;
  max-width: 420px;
  background: var(--text);
  color: var(--bg);
  font-size: 13px;
  line-height: 1.35;
  padding: 10px 8px 10px 14px;
  z-index: 500;
  display: none;
  align-items: flex-start;
  gap: 4px;
  box-shadow: 0 4px 14px rgba(0,0,0,0.35);
  /* Pill text is informational — pass clicks through. Only the × dismisses. */
  pointer-events: none;
}
.tag-hint.tag-hint-visible {
  display: flex;
}
.tag-hint-text { flex: 1; min-width: 0; }
.tag-hint-close {
  background: transparent;
  border: 0;
  color: inherit;
  font-size: 20px;
  line-height: 1;
  padding: 0 8px;
  cursor: pointer;
  flex-shrink: 0;
  min-height: 36px;
  min-width: 36px;
  pointer-events: auto;
}
.tag-hint-close:hover { opacity: 0.8; }

/* =============================================================================
 * PWA push notifications — driver-page CTA + modal + status pill + toast.
 *
 * Aesthetic constraints (CLAUDE.md): hard edges, hairline rules, no rounded
 * card+left-stripe combos, no drop shadows on data rows. The CTA itself is a
 * BUTTON (not a row), so a modest border-radius is fine — but no glow / accent
 * stripe.
 * =========================================================================*/
.visually-hidden {
  position: absolute !important;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  width: 1px; height: 1px;
  overflow: hidden;
  white-space: nowrap;
}

.driver-push {
  margin: 16px 0 24px;
}
.push-cta {
  display: grid;
  grid-template-columns: 36px 1fr auto;
  align-items: center;
  gap: 12px;
  width: 100%;
  background: var(--surface);
  border: 2px solid var(--border-strong, var(--border));
  padding: 14px 16px;
  cursor: pointer;
  color: var(--text);
  font: inherit;
  text-align: left;
  min-height: 56px;
  transition: background 0.15s ease;
}
.push-cta:hover { background: var(--surface-2); }
.push-cta:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}
.push-cta[data-disabled="true"] {
  opacity: 0.6;
  cursor: not-allowed;
}
.push-cta-icon {
  width: 28px; height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text);
}
.push-cta-icon svg { width: 22px; height: 22px; }
.push-cta-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.push-cta-title {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.2;
}
.push-cta-subtitle {
  font-size: 13px;
  color: var(--muted, var(--text));
  opacity: 0.8;
  line-height: 1.3;
}
.push-cta-status {
  font-size: 12px;
  font-weight: 600;
  padding: 3px 8px;
  border: 1px solid var(--border);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.push-cta-status[data-state="active"] {
  background: var(--surface-2);
  border-color: var(--text);
}
.push-cta-status[data-state="inactive"] {
  opacity: 0.7;
}
.push-cta-error {
  margin: 8px 4px 0;
  padding: 8px 10px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 13px;
  color: var(--text);
}

/* ---- Modal ------------------------------------------------------------- */
.push-modal {
  border: 1px solid var(--border-strong, var(--border));
  background: var(--surface);
  color: var(--text);
  padding: 0;
  max-width: min(440px, 92vw);
  width: 100%;
}
.push-modal::backdrop {
  background: rgba(0, 0, 0, 0.45);
}
.push-modal[hidden] { display: none; }
.push-modal-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
}
.push-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 8px;
  margin-bottom: 4px;
}
.push-modal-header h3 { margin: 0; font-size: 18px; font-weight: 700; }
.push-modal-close {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  width: 32px; height: 32px;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
}
.push-modal-help { margin: 0; font-size: 13px; opacity: 0.85; }
.push-modal-slots {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  border: 1px solid var(--border);
}
.push-modal-slot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
  border-right: 1px solid var(--border);
  font-size: 14px;
  min-height: 44px;
}
.push-modal-slot:nth-child(2n) { border-right: 0; }
.push-modal-slot:nth-last-child(-n+2) { border-bottom: 0; }
.push-modal-slot input[type="radio"] {
  margin: 0;
  width: 18px; height: 18px;
  accent-color: var(--text);
}
.push-modal-slot:has(input:checked) {
  background: var(--surface-2);
  font-weight: 700;
}
.push-modal-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  border-top: 1px solid var(--border);
  padding-top: 10px;
  margin-top: 4px;
}
.push-modal-btn {
  border: 1px solid var(--border-strong, var(--border));
  background: var(--surface);
  color: var(--text);
  padding: 10px 16px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  min-height: 44px;
}
.push-modal-btn:hover { background: var(--surface-2); }
.push-modal-confirm {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
}
.push-modal-confirm:hover {
  background: var(--text);
  opacity: 0.9;
}
.push-modal-extras {
  display: flex;
  gap: 16px;
  font-size: 13px;
  border-top: 1px solid var(--border);
  padding-top: 10px;
  margin-top: 4px;
}
.push-modal-link {
  background: transparent;
  border: 0;
  color: var(--text);
  text-decoration: underline;
  cursor: pointer;
  font: inherit;
  padding: 0;
}
.push-modal-link-warn { opacity: 0.85; }

/* ---- Toast ------------------------------------------------------------- */
.push-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--text);
  color: var(--bg);
  padding: 10px 16px;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  border: 1px solid var(--text);
  z-index: 9999;
  letter-spacing: 0.01em;
}
.push-toast[hidden] { display: none; }

/* ---- Status card (Phase C — scoped down to a tiny section in settings) - */
.push-status-card {
  margin: 12px 0;
  border: 1px solid var(--border);
  background: var(--surface);
}
.push-status-card-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: transparent;
  border: 0;
  padding: 10px 12px;
  cursor: pointer;
  color: var(--text);
  font: inherit;
  font-weight: 700;
  text-align: left;
  min-height: 40px;
}
.push-status-card-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--border);
}
.push-status-card-list[hidden] { display: none; }
.push-status-card-item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 8px;
  align-items: center;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.push-status-card-item:last-child { border-bottom: 0; }
.push-status-card-item-nr {
  font-feature-settings: "tnum";
  font-weight: 700;
  min-width: 28px;
}
.push-status-card-item-name a {
  color: var(--text);
  text-decoration: none;
}
.push-status-card-item-name a:hover { text-decoration: underline; }
.push-status-card-item-pill {
  font-size: 11px;
  padding: 2px 6px;
  border: 1px solid var(--border);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.push-status-card-item-pill[data-state="active"] {
  background: var(--surface-2);
  border-color: var(--text);
}
.push-status-card-empty {
  padding: 10px 12px;
  font-size: 13px;
  opacity: 0.75;
}

/* =============================================================================
 * Driver page — mobile polish (≤640px).
 *
 * Goal: tighten spacing on phone screens. The Seneste resultater table is the
 * worst offender — Dato + Løb columns wrap awkwardly when race names are long
 * ("DRSC Vest 2 - 2026"). On mobile we collapse Dato into a small grey label
 * stacked ABOVE the race name in the Løb cell (via ::before on .d-race[data-date])
 * and hide the standalone Dato column. All other columns stay as-is.
 *
 * Newspaper aesthetic: hairline rules, sharp edges. No drop-shadows on rows.
 * ===========================================================================*/
@media (max-width: 640px) {
  /* Driver-page container has 0 horizontal padding (set by global mobile rule).
     Restore a thin gutter for the hero + sections so text doesn't kiss the edge.
     The .driver-table-wrap below pulls itself out to use the full width. */
  .driver-page { padding-top: 10px; padding-left: 12px; padding-right: 12px; }

  /* Hero: tighten the stat-grid border alignment. */
  .driver-hero { padding-bottom: 12px; margin-bottom: 16px; }
  .driver-hero h1 { font-size: 22px; line-height: 1.2; }
  .driver-stats { margin-top: 12px; }
  .driver-stat { padding: 8px 10px; }
  .driver-stat dd { font-size: 19px; }
  .driver-stat-time { font-size: 16px; }

  /* Section headings sit closer to their content on mobile. */
  .driver-section { margin: 18px 0; }
  .driver-section h2 { font-size: 13px; }

  /* Pull the table out to the screen edges so we get more horizontal room
     for the right-hand columns (Run / Klasse / Nr / Plac. / Tid / Bil).
     The container has 0 padding on mobile, so we offset the section gutter. */
  .driver-table-wrap { margin-left: -12px; margin-right: -12px; padding-left: 0; padding-right: 0; }

  /* Hide the standalone Dato column. Date is rendered as a small grey label
     above the race name in the .d-race cell via ::before. */
  .driver-results th.d-date,
  .driver-results td.d-date { display: none; }

  /* Two-line race cell: small muted Dato above the race-name link.
     `content: attr(data-date)` pulls the date from the EJS-set attribute. */
  .driver-results td.d-race {
    line-height: 1.3;
    padding-top: 6px;
    padding-bottom: 6px;
  }
  .driver-results td.d-race[data-date]::before {
    content: attr(data-date);
    display: block;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    margin-bottom: 1px;
  }
  .driver-results td.d-race a {
    display: inline-block;
    font-weight: 500;
  }

  /* Tighter cell padding on mobile so all columns fit without horizontal
     scrolling on a 412-wide phone (Pixel 7). 5px is the smallest that still
     reads as separated rows under thumb-tap targets. */
  .driver-results thead th,
  .driver-results tbody td {
    padding: 5px 6px;
    font-size: 12px;
  }
  .driver-results thead th { font-size: 9.5px; }

  /* Driver-list (co-drivers, cars) — tighter row height + smaller meta text. */
  .driver-list li { padding: 5px 0; font-size: 13px; }
  .driver-list-meta { font-size: 12px; }
}

/* =============================================================================
 * Sparklines + Tendens cards + class-median delta pills.
 *
 * Newspaper aesthetic — hairline strokes, no fills, no drop-shadows. Lines
 * inherit the current text colour by default; named colours come from --tag-N
 * tokens for multi-driver overlays. Cards use hairline borders, NOT rounded
 * card+left-stripe (forbidden — see CLAUDE.md "no AI-design tropes").
 * ===========================================================================*/
.sparkline {
  display: inline-block;
  vertical-align: middle;
  overflow: visible;
}
.sparkline-empty {
  fill: var(--text-muted);
  font-family: inherit;
}
.sparkline-line {
  /* Pure stroke, no fill. */
}
.sparkline-line.is-ghost {
  stroke-dasharray: 0;
}
.sparkline-dot,
.sparkline-dot-last {
  /* Inherits fill from attribute. */
}
.sparkline-axis-label {
  font-family: inherit;
  font-variant-numeric: tabular-nums;
}
.sparkline-bound {
  opacity: 0.45;
}

/* Inline cell sparkline — fits in the d-trend column (max 80px wide). */
.d-trend {
  width: 88px;
  text-align: center;
}
.d-trend-spark {
  display: inline-block;
  width: 80px;
  height: 24px;
  vertical-align: middle;
}
@media (max-width: 720px) {
  .d-trend { width: 56px; }
  .d-trend-spark { width: 50px; height: 20px; }
}

/* Trend section + cards. Hairline, sharp edges. */
.driver-trend { margin-top: 24px; }
.trend-card {
  border: 1px solid var(--border);
  background: var(--surface);
  padding: 12px 14px;
  margin: 0 0 16px;
}
.trend-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 10px;
  flex-wrap: wrap;
}
.trend-card-title {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text);
}
.trend-toggle-row {
  display: inline-flex;
  gap: 0;
  border: 1px solid var(--border);
}
.chart-toggle {
  border: none;
  background: var(--surface);
  color: var(--text-muted);
  padding: 4px 10px;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  font-family: inherit;
  border-right: 1px solid var(--border);
}
.chart-toggle:last-child { border-right: none; }
.chart-toggle:hover { background: var(--surface-2); }
.chart-toggle.is-active {
  background: var(--text);
  color: var(--surface);
}
.chart-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.trend-chart {
  display: block;
  width: 100%;
  min-height: 80px;
  text-align: center;
}
.trend-chart .sparkline {
  max-width: 100%;
  height: auto;
}
.trend-empty {
  margin: 16px 0;
  font-size: 13px;
  text-align: center;
}
.trend-caption {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--text-muted);
}

/* YoY seasons table — same shape as the existing driver-results, but with
   visual emphasis on the year column. We keep this selector distinct from
   .driver-results so the existing tests' `table.driver-results.first()`
   keeps targeting the Resultater table even though Tendens renders above it. */
.trend-seasons { margin: 16px 0; }
.driver-seasons-tabel {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
  font-size: 13px;
}
.driver-seasons-tabel thead th {
  text-align: right;
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  color: var(--text-muted);
}
.driver-seasons-tabel tbody td {
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  text-align: right;
  color: var(--text);
}
.driver-seasons-tabel tbody td:first-child {
  text-align: left;
  font-weight: 600;
}

/* Class-median delta pill in driver Resultater table. Uses semantic colours
   from the existing token set so it matches PB/CB/OB chip language. */
.d-delta {
  width: 60px;
  text-align: right;
}
.d-delta-pill {
  display: inline-block;
  padding: 1px 6px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  border: 1px solid transparent;
  white-space: nowrap;
}
.d-delta-pill.delta-better {
  color: var(--good);
  border-color: color-mix(in srgb, var(--good) 35%, transparent);
  background: color-mix(in srgb, var(--good) 8%, transparent);
}
.d-delta-pill.delta-worse {
  color: var(--text-muted);
  border-color: var(--border);
  background: var(--surface);
}
.d-delta-pill.delta-equal {
  color: var(--text-muted);
  border-color: var(--border);
}

/* Compare-mode chart wrap. Same hairline aesthetic as trend cards. */
.compare-chart-wrap {
  margin-top: 12px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  background: var(--surface);
}
.compare-chart {
  display: block;
  width: 100%;
  min-height: 80px;
  text-align: center;
  margin: 6px 0 4px;
}
.compare-chart .sparkline {
  max-width: 100%;
  height: auto;
}
.sparkline-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin: 6px 0 0;
  font-size: 11px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.sparkline-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.sparkline-legend-item.is-ghost { opacity: 0.6; }
.sparkline-legend-swatch {
  display: inline-block;
  width: 10px;
  height: 2px;
  background: var(--text);
}
.sparkline-legend-swatch.is-dashed {
  background: repeating-linear-gradient(to right, var(--text-muted) 0 3px, transparent 3px 5px);
}

@media (max-width: 720px) {
  .trend-card { padding: 10px 12px; }
  .trend-card-title { font-size: 12px; }
  .chart-toggle { padding: 3px 8px; font-size: 11px; }
  .compare-chart-wrap { padding: 8px 10px; }
  .sparkline-legend { font-size: 10px; gap: 4px 10px; }
}

/* -----------------------------------------------------------------------------
 * Admin venue editor.
 * Newspaper aesthetic — hairline rules, hard edges, density. See CLAUDE.md
 * "no AI design" rules. The Mapbox attribution + ctrl buttons stay visible
 * (legal requirement) but are visually toned down to match.
 * ---------------------------------------------------------------------------*/
.venues-list-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.venues-list-head h2 { margin: 0; }

.btn-primary {
  display: inline-block;
  background: var(--accent);
  color: var(--accent-on);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  font-weight: 600;
  text-decoration: none;
}
.btn-primary:hover { filter: brightness(1.06); }

.btn-link {
  color: var(--accent);
  text-decoration: underline;
  font-weight: 500;
  margin-right: 8px;
}

.venues-list { overflow-x: auto; }
.venues-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.venues-table thead th {
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-strong);
  background: var(--surface-2);
}
.venues-table thead th.num { text-align: right; }
.venues-table thead th.actions { text-align: right; width: 1%; }
.venues-table tbody td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.venues-table tbody tr:last-child td { border-bottom: 0; }
.venues-table tbody td.num { text-align: right; }
.venues-table tbody td.actions { text-align: right; white-space: nowrap; }
.venues-table tbody td.venue-name { font-weight: 500; }
.venues-table tbody td code {
  font-size: 12px;
  color: var(--text-muted);
  background: transparent;
  padding: 0;
}
.venues-table tbody tr:hover td { background: var(--surface-2); }
.venues-table .actions form.inline { margin-left: 4px; }
.venues-table .actions button.danger {
  padding: 4px 10px;
  font-size: 12px;
}
.venues-table .actions button.danger[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

/* ----- Form ---------------------------------------------------------------*/
.venue-form .grid-form { gap: 14px 16px; }
.venue-form-actions { display: flex; gap: 12px; align-items: center; margin-top: 6px; }

.venue-help-text {
  display: block;
  margin-top: 4px;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.4;
}

.venue-delete-card { border-color: var(--bad); }
.venue-delete-card h2 { color: var(--bad); margin-top: 0; font-size: 16px; }

/* ----- Map section --------------------------------------------------------*/
.venue-map-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 4px 0 4px;
}

.venue-search { position: relative; }
.venue-search-label {
  display: block;
  font-size: 13px;
  color: var(--text-muted);
  margin-bottom: 4px;
}
.venue-search input[type="search"] {
  width: 100%;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font: inherit;
}
.venue-search input[type="search"]:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}

/* Geocoder dropdown. Higher-specificity selectors so the global `button {
   background: var(--accent) }` rule loses the cascade — without that the
   results render as bright blue blocks instead of newspaper-flat rows. */
ul.venue-search-results {
  position: absolute;
  z-index: 10;
  left: 0;
  right: 0;
  top: 100%;
  margin: 2px 0 0;
  padding: 0;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  max-height: 240px;
  overflow-y: auto;
}
ul.venue-search-results[hidden] { display: none; }
ul.venue-search-results li {
  margin: 0;
  padding: 0;
  list-style: none;
  border-bottom: 1px solid var(--border);
}
ul.venue-search-results li:last-child { border-bottom: 0; }
ul.venue-search-results li::marker { content: ""; }

ul.venue-search-results .venue-search-result,
button.venue-search-result {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  color: var(--text);
  border: 0;
  border-radius: 0;
  padding: 8px 10px;
  font: inherit;
  font-size: 0.95em;
  font-weight: 400;
  cursor: pointer;
}
ul.venue-search-results .venue-search-result:hover,
ul.venue-search-results .venue-search-result:focus,
button.venue-search-result:hover,
button.venue-search-result:focus {
  background: var(--surface-2);
  color: var(--text);
  outline: none;
  filter: none;
}

.venue-search-empty {
  padding: 8px 10px;
  color: var(--text-muted);
  font-size: 0.9em;
  font-style: italic;
}

.venue-map {
  width: 100%;
  height: 360px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
}

.venue-position-readout {
  margin: 0;
  padding: 6px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 13px;
}
.venue-position-label {
  color: var(--text-muted);
  font-weight: 600;
  margin-right: 8px;
}
.venue-position-coords {
  color: var(--text);
  font-family: ui-monospace, "SF Mono", "Menlo", "Consolas", monospace;
  font-variant-numeric: tabular-nums;
}
.venue-dmi-readout {
  margin: 6px 0 0 0;
  padding: 6px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 13px;
}
.venue-dmi-info strong { color: var(--text); margin-right: 4px; }

@media (max-width: 720px) {
  .venue-map { height: 280px; }
  .venues-table thead th,
  .venues-table tbody td { padding: 6px 8px; font-size: 13px; }
}

/* ----- Mapbox chrome — tone down to match newspaper aesthetic --------------
   Attribution stays visible (Mapbox ToS) but uses our token palette so it
   doesn't visually shout. */
.venue-map .mapboxgl-ctrl-attrib {
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: 10px;
  border-radius: 0;
}
.venue-map .mapboxgl-ctrl-attrib a { color: var(--text-muted); }
.venue-map .mapboxgl-ctrl-bottom-left,
.venue-map .mapboxgl-ctrl-bottom-right {
  background: transparent;
}
.venue-map .mapboxgl-ctrl-group {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 0;
  box-shadow: none;
}
.venue-map .mapboxgl-ctrl-group button {
  border-radius: 0;
  border-bottom: 1px solid var(--border);
}
.venue-map .mapboxgl-ctrl-group button:last-child { border-bottom: 0; }
.venue-map .mapboxgl-ctrl-logo {
  /* Required by Mapbox ToS — leave visible but matte. */
  opacity: 0.7;
}

/* -----------------------------------------------------------------------------
 * Admin combobox — searchable enhancement for <select data-combobox>.
 * The original <select> stays in the DOM (form-submission compat) but is
 * visually hidden; JS builds an <input>+<ul> pair beside it. Same hairline
 * aesthetic as the geocoder dropdown — they render in identical visual
 * grammar so the admin UI stays coherent.
 * ---------------------------------------------------------------------------*/
select.adm-combobox-source.is-enhanced {
  /* Keep the select in the layout for form submit but invisible. We do not
     use display:none because some browsers skip submitting hidden selects. */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
  pointer-events: none;
}

.adm-combobox {
  position: relative;
  display: block;
}
.adm-combobox-input {
  width: 100%;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font: inherit;
}
.adm-combobox-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}
.adm-combobox.is-open .adm-combobox-input {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

ul.adm-combobox-options {
  position: absolute;
  z-index: 10;
  left: 0;
  right: 0;
  top: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-top: 0;
  max-height: 280px;
  overflow-y: auto;
}
ul.adm-combobox-options[hidden] { display: none; }
ul.adm-combobox-options li {
  margin: 0;
  padding: 0;
  list-style: none;
  border-bottom: 1px solid var(--border);
}
ul.adm-combobox-options li::marker { content: ""; }
ul.adm-combobox-options li:last-child { border-bottom: 0; }

ul.adm-combobox-options .adm-combobox-option,
button.adm-combobox-option {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  color: var(--text);
  border: 0;
  border-radius: 0;
  padding: 8px 10px;
  font: inherit;
  font-size: 0.95em;
  font-weight: 400;
  cursor: pointer;
}
ul.adm-combobox-options .adm-combobox-option:hover,
ul.adm-combobox-options .adm-combobox-option.is-active,
ul.adm-combobox-options .adm-combobox-option:focus,
button.adm-combobox-option:hover,
button.adm-combobox-option.is-active,
button.adm-combobox-option:focus {
  background: var(--surface-2);
  color: var(--text);
  outline: none;
  filter: none;
}
.adm-combobox-option .adm-combobox-meta {
  color: var(--text-muted);
  font-size: 0.85em;
  margin-left: 6px;
}
.adm-combobox-empty {
  padding: 8px 10px;
  color: var(--text-muted);
  font-size: 0.9em;
  font-style: italic;
}

/* Per-race rebind row uses inline-form (display:flex). Make the combobox
   wrap participate in the flex without collapsing — the dropdown still
   absolute-overlays so it's not constrained by the flex track height. */
.race-row .inline-form .adm-combobox { flex: 0 1 240px; min-width: 180px; }
.race-row .inline-form .adm-combobox-input { padding: 6px 10px; }

/* -----------------------------------------------------------------------------
 * Admin shell — sidebar + main content. Dropping `.container`'s narrow
 * max-width because admin pages benefit from horizontal density (tables,
 * forms with maps). Sidebar collapses below the content on narrow viewports.
 * ---------------------------------------------------------------------------*/
.admin-shell {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 24px;
  max-width: 1400px;
  margin: 24px auto;
  padding: 0 24px;
}
.admin-sidebar {
  position: sticky;
  top: 80px;
  align-self: start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 0;
}
.admin-sidebar-heading {
  margin: 0 0 8px;
  padding: 4px 16px 8px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
}
.admin-sidebar-heading-extra {
  margin-top: 12px;
  border-top: 1px solid var(--border);
  padding-top: 12px;
  border-bottom: 1px solid var(--border);
}
.admin-sidebar nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.admin-sidebar nav a {
  display: block;
  padding: 9px 16px;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  border-left: 3px solid transparent;
}
.admin-sidebar nav a:hover { background: var(--surface-2); }
.admin-sidebar nav a.is-active {
  background: var(--surface-2);
  border-left-color: var(--accent);
  font-weight: 600;
}
.admin-sidebar-foot {
  margin-top: 12px;
  padding: 12px 16px 4px;
  border-top: 1px solid var(--border);
}
.admin-sidebar-foot form { margin: 0; }
.admin-sidebar-foot button {
  width: 100%;
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
  font-weight: 500;
}
.admin-sidebar-foot button:hover {
  color: var(--text);
  border-color: var(--border-strong);
}
.admin-main { min-width: 0; /* lets flex-children shrink in tables */ }

@media (max-width: 720px) {
  .admin-shell {
    grid-template-columns: 1fr;
    padding: 0 12px;
    margin: 12px auto;
  }
  .admin-sidebar {
    position: static;
    padding: 8px 0;
  }
  .admin-sidebar nav ul {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 0 4px;
  }
  .admin-sidebar nav a {
    padding: 6px 12px;
    border-left: 0;
    border-bottom: 2px solid transparent;
  }
  .admin-sidebar nav a.is-active {
    border-left: 0;
    border-bottom-color: var(--accent);
  }
  .admin-sidebar-heading,
  .admin-sidebar-foot { display: none; }
}

.admin-nav {
  display: flex;
  gap: 14px;
  align-items: center;
}
.admin-nav a {
  color: var(--accent);
  text-decoration: none;
  font-size: 14px;
}
.admin-nav a:hover { text-decoration: underline; }

.venue-rebind-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-muted);
}

/* =============================================================================
 * Identity admin — visual polish pass.
 *
 * Newspaper / motorsport-timing language: hairline 1px rules, hard rectangular
 * badges, uppercase 11px section heads, dense rows. Reference: F1.com results,
 * FlashScore mobile. NO rounded card + colored left-stripe combo. Left-accent
 * is used only on linear banners. NO drop-shadows on rows. All colors via
 * tokens.
 *
 * Scoping: rules under `.admin-main:has(.admin-subnav)` apply only to identity
 * pages. :has() requires modern browsers — admin-only feature.
 * ===========================================================================*/

.admin-main:has(.admin-subnav) .admin-card {
  padding: 14px 16px;
  margin-bottom: 14px;
  box-shadow: none;
  border-radius: var(--radius-sm);
}
.admin-main:has(.admin-subnav) .admin-card > h2:first-child {
  margin: 0 -16px 10px;        /* extend rule edge-to-edge with card */
  padding: 0 16px 6px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text);
  border-bottom: 1px solid var(--border-strong);
}

/* ----- 1. Tab strip — proper button-tabs --------------------------------
 * Each tab is a hairline-bordered rectangle with surface fill. Active tab
 * raises to surface (lighter than surface-2 strip) with accent border-top.
 * Hover gets a stronger border + text color. Counts sit inline.
 *
 * Reads like F1.com section nav: not naked links, not pills — proper
 * tab-buttons that you can clearly click.
 * --------------------------------------------------------------------- */

.admin-subnav {
  margin: 4px 0 18px;
  overflow-x: auto;
  scrollbar-width: none;
  border-bottom: 1px solid var(--border-strong);
}
.admin-subnav::-webkit-scrollbar { display: none; }
.admin-subnav ul {
  list-style: none;
  padding: 0;
  margin: 0 0 -1px;             /* overlap the strip's bottom border so active tab covers it */
  display: flex;
  gap: 2px;
  flex-wrap: nowrap;
}
.admin-subnav li { margin: 0; }
.admin-subnav a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px 9px;
  background: var(--surface-2);
  color: var(--text-muted);
  text-decoration: none;
  border: 1px solid var(--border);
  border-bottom: 1px solid var(--border-strong);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  transition: color 80ms ease, background 80ms ease, border-color 80ms ease;
  position: relative;
}
.admin-subnav a:hover {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border-strong);
}
.admin-subnav a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  z-index: 2;
}
.admin-subnav a.is-active {
  background: var(--surface);
  color: var(--text);
  font-weight: 700;
  border-color: var(--border-strong);
  border-bottom-color: var(--surface);  /* hide bottom border so tab "lifts" off the strip */
  border-top: 2px solid var(--accent);
  padding-top: 7px;             /* compensate for the heavier top-border */
  margin-bottom: -1px;          /* trække over rule so tab covers it pixel-perfect */
  z-index: 1;
}
.admin-subnav a .tab-count {
  /* Bare number — no border, no fill. Newspaper-style metric. */
  display: inline-block;
  margin-left: 6px;
  padding: 0;
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  vertical-align: baseline;
}
.admin-subnav a.is-active .tab-count {
  color: var(--text-muted);
}
/* Warn variant only fires when the count > 0 — solid pill calls attention. */
.admin-subnav a .tab-count-warn {
  padding: 1px 5px;
  background: var(--warn);
  color: var(--surface);
  border: 0;
  font-weight: 700;
  font-size: 10px;
  vertical-align: 1px;
}
.admin-subnav a.is-active .tab-count-warn {
  color: var(--surface);
}

/* ----- 2. Badges --------------------------------------------------------- */

.badge {
  display: inline-block;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  line-height: 1.4;
  border: 1px solid var(--border);
  color: var(--text-muted);
  background: transparent;
  border-radius: 0;
  vertical-align: 1px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.badge-ok    { color: var(--good); border-color: var(--good); }
.badge-muted { color: var(--text-muted); border-color: var(--border); background: var(--surface-2); }
.badge-warn  { color: var(--warn); border-color: var(--warn); }
.badge-bad   { color: var(--bad); border-color: var(--bad); }

/* ----- 3. Generic admin-table base -------------------------------------- */

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.admin-table thead th {
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-strong);
  background: var(--surface-2);
}
.admin-table thead th.num { text-align: right; }
.admin-table tbody td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.admin-table tbody td.num { text-align: right; }
.admin-table tbody tr:last-child td { border-bottom: 0; }
.admin-table tbody tr:hover td { background: var(--surface-2); }
.admin-table tr.row-muted td { opacity: 0.55; }
.admin-table tr.row-merged td { color: var(--text-muted); }
.admin-table .strong { font-weight: 600; }

/* ----- 4. Drivers list -------------------------------------------------- */

.admin-table.drivers-list tbody td {
  padding: 7px 10px;
  font-size: 13.5px;
  line-height: 1.35;
}
.admin-table.drivers-list tbody td:first-child { white-space: nowrap; }
.admin-table.drivers-list tbody td .badge { margin-left: 6px; }
.admin-table.drivers-list td.car-cell {
  max-width: 240px;
  line-height: 1.4;
  font-size: 12.5px;
  vertical-align: top;
}
.admin-table.drivers-list th.actions,
.admin-table.drivers-list td.actions {
  text-align: right;
  white-space: nowrap;
  width: 1%;
}
.admin-table.drivers-list td.actions a.btn-link + a.btn-link { margin-left: 14px; }
/* Mobile — drop secondary numeric columns; admin's primary scan is name + city + car + actions.
   Layout columns: 1=Navn, 2=By, 3=Bil, 4=Løb, 5=Aliases, 6=Sidst kørt, 7=actions */
@media (max-width: 720px) {
  .admin-table.drivers-list thead th:nth-child(4),
  .admin-table.drivers-list thead th:nth-child(5),
  .admin-table.drivers-list thead th:nth-child(6),
  .admin-table.drivers-list tbody td:nth-child(4),
  .admin-table.drivers-list tbody td:nth-child(5),
  .admin-table.drivers-list tbody td:nth-child(6) { display: none; }
}

.admin-table tbody tr.row-merged td {
  color: var(--text-muted);
  background: linear-gradient(
    -45deg,
    transparent 0,
    transparent 8px,
    var(--surface-2) 8px,
    var(--surface-2) 9px,
    transparent 9px,
    transparent 16px
  );
  background-size: 16px 16px;
}
.admin-table tbody tr.row-merged:hover td { background: var(--surface-2); }
.admin-table tbody tr.row-action td { box-shadow: inset 2px 0 0 var(--warn); }

/* ----- 5. Compare table — survivor accent + role eyebrows -------------- */

.compare-table { table-layout: auto; }
.compare-table thead th { vertical-align: top; padding-bottom: 4px; }
.compare-table thead th:nth-child(2)::after,
.compare-table thead th:nth-child(3)::after {
  display: block;
  margin-top: 2px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.compare-table thead th:nth-child(2)::after { content: "STRYGES"; color: var(--bad); }
.compare-table thead th:nth-child(3)::after { content: "→ BEHOLDES"; color: var(--good); }
.compare-table tbody td:first-child {
  font-weight: 600;
  color: var(--text-muted);
  width: 22%;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.compare-table tbody td:nth-child(2) { color: var(--text-muted); }
.compare-table tbody td:empty::after {
  content: "—";
  color: var(--text-muted);
}
.compare-table tbody td:last-child {
  font-weight: 500;
  box-shadow: inset 2px 0 0 var(--accent);
}

/* Diff-highlight: row-match rules a row green-tinted when A and B agree on
   that field. Helps admin scan "how many fields agree" at a glance. */
.compare-table tbody tr.row-match td {
  background: color-mix(in srgb, var(--good) 8%, var(--surface));
}
.compare-table tbody tr.row-match:hover td {
  background: color-mix(in srgb, var(--good) 14%, var(--surface));
}
.compare-table tbody tr.row-match td:first-child {
  color: var(--good);
  font-weight: 700;
}
.compare-table .match-glyph {
  display: inline-block;
  width: 12px;
  margin-right: 4px;
  text-align: center;
  color: var(--good);
}

/* Match summary banner above the compare-table — strong version is the most
   important signal on the merge page when admin's about to commit. */
.match-summary {
  margin: -4px 0 12px;
  padding: 10px 14px;
  font-size: 13px;
  border: 1px solid var(--border);
  border-left-width: 3px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.match-summary::before {
  font-weight: 700;
  font-size: 14px;
}
.match-summary-strong {
  border-left-color: var(--warn);
  color: var(--text);
  background: color-mix(in srgb, var(--warn) 10%, var(--surface));
  font-weight: 500;
}
.match-summary-strong::before { content: "⚠"; color: var(--warn); }
.match-summary-strong strong { color: var(--warn); }
.match-summary-weak {
  border-left-color: var(--text-muted);
  color: var(--text-muted);
  background: var(--surface-2);
}
.match-summary-weak::before { content: "i"; color: var(--text-muted); font-style: italic; }

/* ----- 6. Bucket cards (unmerge) --------------------------------------- */

.admin-card.bucket-a > h2:first-child::before,
.admin-card.bucket-b > h2:first-child::before,
.admin-card.bucket-c > h2:first-child::before {
  display: inline-block;
  margin-right: 8px;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  border: 1px solid var(--border);
  color: var(--text-muted);
  vertical-align: 1px;
  text-transform: uppercase;
}
.admin-card.bucket-a > h2:first-child::before { content: "BUCKET A — AUTOMATISK"; }
.admin-card.bucket-b > h2:first-child::before { content: "BUCKET B — UÆNDRET"; }
.admin-card.bucket-c {
  border-top: 2px solid var(--warn);
  padding-top: 14px;
}
.admin-card.bucket-c > h2:first-child::before {
  content: "BUCKET C — KRÆVER BESLUTNING";
  color: var(--warn);
  border-color: var(--warn);
}
.admin-card.bucket-c > h2:first-child { color: var(--warn); }
.admin-card.bucket-c .admin-table thead th:first-child { color: var(--warn); }

/* ----- 7. Filter bar --------------------------------------------------- */

.filter-bar {
  display: flex;
  gap: 10px;
  align-items: stretch;
  flex-wrap: wrap;
  margin: 0 -16px 12px;
  padding: 10px 16px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.filter-bar > label:not(.filter-checkbox) {
  flex: 1 1 280px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.filter-bar > label:not(.filter-checkbox) > span.muted {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.filter-bar input[type="search"],
.filter-bar input[type="text"] {
  width: 100%;
  padding: 6px 10px;
  font-size: 14px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
}
.filter-bar input[type="search"]:focus-visible,
.filter-bar input[type="text"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-color: var(--accent);
}
.filter-bar .filter-checkbox {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: end;
  padding: 6px 10px;
  font-size: 12px;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 0;
  background: var(--surface);
  cursor: pointer;
  transition: border-color 80ms ease, color 80ms ease, box-shadow 80ms ease;
  user-select: none;
}
.filter-bar .filter-checkbox:hover {
  border-color: var(--border-strong);
  color: var(--text);
}
.filter-bar .filter-checkbox:has(input:checked) {
  color: var(--text);
  border-color: var(--border-strong);
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--accent);
}
.filter-bar .filter-checkbox input[type="checkbox"] {
  margin: 0;
  width: 12px;
  height: 12px;
  accent-color: var(--accent);
}
.filter-bar > button {
  align-self: end;
  padding: 6px 12px;
  font-size: 13px;
  border-radius: 0;
}
.filter-bar > .btn-link {
  align-self: center;
  margin-left: auto;
  font-size: 12px;
}
.filter-bar select {
  align-self: end;
  padding: 6px 10px;
  font-size: 13px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
}

/* ----- 8. Form polish ------------------------------------------------- */

.admin-main:has(.admin-subnav) .grid-form { gap: 10px 14px; }
.admin-main:has(.admin-subnav) .grid-form label {
  gap: 3px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.admin-main:has(.admin-subnav) .grid-form label input,
.admin-main:has(.admin-subnav) .grid-form label select,
.admin-main:has(.admin-subnav) .grid-form label textarea,
.admin-main:has(.admin-subnav) .grid-form label .combobox,
.admin-main:has(.admin-subnav) .grid-form label .combobox * {
  font-size: 14px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--text);
}
.admin-main:has(.admin-subnav) .grid-form label .combobox .listbox li .meta { color: var(--text-muted); font-size: 11px; }
.admin-main:has(.admin-subnav) .grid-form label .combobox .listbox li .city { color: var(--text-muted); font-size: 12px; }
.admin-main:has(.admin-subnav) .grid-form label small {
  font-size: 11px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--text-muted);
  margin-top: 2px;
  line-height: 1.4;
}
.admin-main:has(.admin-subnav) .grid-form label:has(input[required]) > :first-child::after,
.admin-main:has(.admin-subnav) .grid-form label:has(textarea[required]) > :first-child::after,
.admin-main:has(.admin-subnav) .grid-form label:has(select[required]) > :first-child::after {
  content: " *";
  color: var(--bad);
  font-weight: 700;
}
.admin-main:has(.admin-subnav) .grid-form > button[type="submit"]:last-child,
.admin-main:has(.admin-subnav) .grid-form > button:last-child:not([type]) {
  grid-column: 1 / -1;
  justify-self: end;
  margin-top: 4px;
}

/* ----- 9. Flash messages -------------------------------------------- */

.admin-main:has(.admin-subnav) .flash {
  padding: 10px 14px 10px 12px;
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: 0;
  margin: -2px 0 14px;
  background: var(--surface);
  font-size: 13.5px;
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.admin-main:has(.admin-subnav) .flash::before { font-weight: 700; font-size: 13px; line-height: 1.4; }
.admin-main:has(.admin-subnav) .flash-ok    { border-left-color: var(--good);   color: var(--text); background: transparent; }
.admin-main:has(.admin-subnav) .flash-ok::before    { content: "✓"; color: var(--good); }
.admin-main:has(.admin-subnav) .flash-error { border-left-color: var(--bad);    color: var(--text); background: transparent; }
.admin-main:has(.admin-subnav) .flash-error::before { content: "!"; color: var(--bad); }
.admin-main:has(.admin-subnav) .flash-info  { border-left-color: var(--accent); color: var(--text); background: transparent; }
.admin-main:has(.admin-subnav) .flash-info::before  { content: "i"; color: var(--accent); font-style: italic; }

/* ----- 10. Anti-merge / warn card --------------------------------- */

.admin-main:has(.admin-subnav) .admin-card.warn-card {
  border-top: 3px solid var(--warn);
  padding-top: 12px;
  background: var(--surface);
}
.admin-main:has(.admin-subnav) .admin-card.warn-card > h2:first-child {
  color: var(--warn);
  border-bottom-color: var(--warn);
  font-size: 13px;
  letter-spacing: 0.04em;
}
.admin-main:has(.admin-subnav) .admin-card.warn-card p {
  font-size: 13.5px;
  color: var(--text);
  margin: 8px 0;
}
.admin-main:has(.admin-subnav) .admin-card.warn-card strong {
  color: var(--warn);
  font-weight: 700;
}

/* ----- 11. Page header — magazine feel + eyebrow ----------------- */

.admin-main:has(.admin-subnav) .admin-header {
  align-items: flex-end;
  border-bottom: 1px solid var(--border);
  padding-bottom: 10px;
  margin-bottom: 0;
  gap: 12px 18px;
}
.admin-main:has(.admin-subnav) .admin-header h1 {
  margin: 0;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.005em;
  line-height: 1.15;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.admin-main:has(.admin-subnav) .admin-header h1[data-eyebrow]::before {
  content: attr(data-eyebrow);
  flex-basis: 100%;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-muted);
  margin-bottom: 4px;
}
.admin-main:has(.admin-subnav) .admin-header > p.muted {
  margin: 4px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  flex-basis: 100%;
}
.admin-main:has(.admin-subnav) .admin-header h1 .badge {
  font-size: 11px;
  padding: 2px 7px;
  vertical-align: 3px;
}

/* ----- 12. Pending row -------------------------------------------- */

.admin-main:has(.admin-subnav) .pending-row {
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.admin-main:has(.admin-subnav) .pending-row:last-of-type { border-bottom: 0; }
.admin-main:has(.admin-subnav) .pending-row header {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: baseline;
  font-size: 14px;
  margin-bottom: 4px;
}
.admin-main:has(.admin-subnav) .pending-row header strong {
  font-size: 15px;
  font-weight: 700;
}
.admin-main:has(.admin-subnav) .pending-row .reasoning {
  font-size: 12.5px;
  color: var(--text-muted);
  margin: 6px 0;
  padding-left: 8px;
  border-left: 2px solid var(--border);
}
.admin-main:has(.admin-subnav) .pending-row .candidates {
  list-style: none;
  margin: 4px 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 12px;
}
.admin-main:has(.admin-subnav) .pending-row .candidates label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  font-size: 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.admin-main:has(.admin-subnav) .pending-row .candidates label:has(input:checked) {
  border-color: var(--accent);
  color: var(--accent);
}
.admin-main:has(.admin-subnav) .pending-row .candidates input[type="radio"] {
  accent-color: var(--accent);
  width: 12px;
  height: 12px;
}
.admin-main:has(.admin-subnav) .decide-form {
  display: flex;
  gap: 8px;
  margin-top: 8px;
}
.admin-main:has(.admin-subnav) .decide-form button {
  font-size: 13px;
  padding: 6px 12px;
}
.admin-main:has(.admin-subnav) .decide-form button[value="create_new"] {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border);
  font-weight: 500;
}
.admin-main:has(.admin-subnav) .decide-form button[value="split"] {
  background: var(--surface);
  color: var(--text-muted);
  border-color: var(--border);
  font-weight: 400;
}

/* ----- 13. Pagination -------------------------------------------- */

.admin-main:has(.admin-subnav) .pagination {
  display: flex;
  gap: 24px;
  margin-top: 12px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  justify-content: space-between;
  color: var(--text-muted);
}
.admin-main:has(.admin-subnav) .pagination a {
  padding: 2px 0;
  color: var(--text);
  text-decoration: none;
  border: 0;
  border-radius: 0;
  font-weight: 600;
  background: transparent;
  border-bottom: 1px solid var(--border-strong);
}
.admin-main:has(.admin-subnav) .pagination a:hover {
  border-bottom-color: var(--text);
  background: transparent;
}

/* ----- 14. Misc -------------------------------------------------- */

.admin-main:has(.admin-subnav) .row-detail {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 2px 12px;
  font-size: 12.5px;
  margin: 6px 0;
  padding: 8px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.admin-main:has(.admin-subnav) .row-detail dt {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.admin-main:has(.admin-subnav) .row-detail dd { font-variant-numeric: tabular-nums; margin: 0; }

/* Driver-detail action bar — unified toolbar with shared border (1px between
   buttons, no gaps). Reads as one connected control surface, not 4 floating
   boxes. Profile-link pushed to right edge. */
.driver-actionbar {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: 0;
  margin: 0 0 14px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
}
.driver-actionbar .inline-form { gap: 0; display: flex; }
.driver-actionbar .actionbar-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  background: transparent;
  border: 0;
  border-right: 1px solid var(--border);
  border-radius: 0;
  cursor: pointer;
  transition: background 80ms ease, color 80ms ease;
}
.driver-actionbar .actionbar-btn:hover {
  background: var(--surface-2);
}
.driver-actionbar .actionbar-btn-active {
  background: color-mix(in srgb, var(--good) 10%, var(--surface));
  color: var(--good);
  font-weight: 600;
}
.driver-actionbar .actionbar-btn-ghost {
  margin-left: auto;
  border-left: 1px solid var(--border);
  border-right: 0;
  color: var(--text-muted);
}
.driver-actionbar .actionbar-btn:last-child:not(.actionbar-btn-ghost) { border-right: 0; }

/* Driver-detail body: two-column grid (left wide, right narrow). When the
   right side has nothing but the empty "Hold adskilt fra"-card, fall back to
   a single column so the page doesn't feel hollow. The .has-conflicts class
   on the grid gates the 2-col layout to drivers that ACTUALLY have right-side
   content (anti-merge or potential conflicts). */
.driver-detail-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  align-items: start;
}
.driver-detail-grid.has-conflicts {
  grid-template-columns: 2fr 1fr;
}
@media (max-width: 980px) {
  .driver-detail-grid.has-conflicts { grid-template-columns: 1fr; }
}
.driver-detail-left,
.driver-detail-right {
  min-width: 0;
}

/* Profile-edit collapsible — discrete summary, full form when expanded. */
.profile-edit summary {
  cursor: pointer;
  list-style: none;
  user-select: none;
  font-size: 13px;
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: wrap;
}
.profile-edit summary::-webkit-details-marker { display: none; }
.profile-edit summary::before {
  content: "▸";
  display: inline-block;
  width: 12px;
  font-size: 11px;
  color: var(--text-muted);
}
.profile-edit[open] summary::before { content: "▾"; }
.profile-edit .profile-summary-name { font-weight: 600; }
.profile-edit .profile-form { margin-top: 12px; }

/* Anti-merge list — compact card-side layout. */
.anti-merge-list {
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
}
.anti-merge-list li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 7px 0;
  border-top: 1px solid var(--border);
  font-size: 13px;
}
.anti-merge-list li:first-child { border-top: 0; }
.anti-merge-list li > div { flex: 1; min-width: 0; }
.anti-merge-list .strong { font-weight: 600; }

/* Hub: auto-merge suspects banner. */
.suspects-card { /* uses warn-card base */ }
.suspects-list {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
}
.suspect-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  border-top: 1px solid var(--border);
}
.suspect-item:first-child { border-top: 0; }
.suspect-main {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 12px;
  min-width: 0;
}
.suspect-actions {
  display: flex;
  gap: 12px;
  flex-shrink: 0;
}

/* Split-driver page — suggested cluster groups. */
.split-groups {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 10px;
}
.split-group {
  border: 1px solid var(--border);
  padding: 10px 12px;
  background: var(--surface-2);
}
.split-group-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.split-group .small { font-size: 11px; }
.split-group .split-pick-group {
  margin-top: 8px;
  padding: 5px 10px;
  font-size: 12px;
}
.split-group-actions {
  margin-top: 6px;
}

/* New-drivers list (N-way split). */
.new-drivers-list {
  list-style: none;
  margin: 6px 0 10px;
  padding: 0;
}
.new-driver-row {
  display: grid;
  grid-template-columns: minmax(120px, 130px) 1fr 1fr auto;
  gap: 8px;
  margin-bottom: 6px;
  align-items: center;
}
.new-driver-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.new-driver-row input {
  padding: 6px 10px;
  font-size: 13px;
  border: 1px solid var(--border);
  border-radius: 0;
  background: var(--surface);
  color: var(--text);
}
.new-driver-row .remove-new-driver {
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  font-size: 11px;
  padding: 4px 10px;
  cursor: pointer;
  border-radius: 0;
}
.new-driver-row .remove-new-driver:hover {
  border-color: var(--bad);
  color: var(--bad);
}

/* Bulk-apply control above the entries table. */
.bulk-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 4px 0 10px;
}
.bulk-controls select {
  padding: 4px 8px;
  font-size: 12px;
  border: 1px solid var(--border);
  border-radius: 0;
  background: var(--surface);
  color: var(--text);
}

.split-entries .entry-dest,
.split-aliases .alias-dest {
  padding: 3px 6px;
  font-size: 12px;
  border: 1px solid var(--border);
  border-radius: 0;
  background: var(--surface);
  color: var(--text);
  min-width: 130px;
}
.admin-table.split-entries tbody td,
.admin-table.split-aliases tbody td {
  font-size: 12.5px;
  padding: 6px 8px;
}
.admin-table.split-entries th input[type="checkbox"],
.admin-table.split-aliases td input[type="checkbox"] { accent-color: var(--accent); }

/* Anti-merge: proactive conflict suggestions list. */
.conflicts-suggest {
  margin: 8px 0 4px;
  padding: 10px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--warn);
}
.conflicts-suggest h3 {
  margin: 0 0 4px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--warn);
}
.conflicts-suggest > p { margin: 0 0 8px; font-size: 12.5px; }
.conflicts-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.conflict-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 7px 0;
  border-top: 1px solid var(--border);
}
.conflict-item:first-child { border-top: 0; }
.conflict-main {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  min-width: 0;
  font-size: 13px;
}
.conflict-main .strong { font-weight: 700; }
.conflict-reason { margin-left: auto; }

.admin-main:has(.admin-subnav) .add-anti-merge {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.admin-main:has(.admin-subnav) .add-anti-merge summary {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  color: var(--accent);
  margin-bottom: 10px;
}

.inline-form { display: inline-flex; align-items: center; gap: 8px; }
.inline-form button.small,
button.small { padding: 4px 10px; font-size: 12px; }

.small { font-size: 12px; }
.ok { color: var(--good); }
.error { color: var(--bad); }

form.disabled { opacity: 0.5; pointer-events: none; }

/* Day-group separator on history page (one row per day). */
.admin-table tbody tr.day-group td {
  padding: 12px 10px 4px;
  border-bottom: 1px solid var(--border-strong);
  background: transparent;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.admin-table tbody tr.day-group:first-child td { padding-top: 4px; }
.admin-table tbody tr.day-group:hover td { background: transparent; }

/* Live-search loading state — applied via aria-busy on the tbody. */
.admin-table tbody[aria-busy="true"] {
  opacity: 0.6;
  pointer-events: none;
}

/* ----- Merge picker layout (two slots side-by-side with → arrow) -------- */

.merge-help {
  border: 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  padding: 8px 0;
  margin: 0 0 14px;
  background: transparent;
}
.merge-help summary {
  cursor: pointer;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  list-style: none;
  user-select: none;
}
.merge-help summary:hover { color: var(--text); }
.merge-help summary::before {
  content: "▸";
  display: inline-block;
  width: 14px;
  font-size: 11px;
  color: var(--text-muted);
  vertical-align: 1px;
  transition: transform 120ms ease;
}
.merge-help[open] summary::before { transform: rotate(90deg); }
.merge-help-body {
  margin-top: 6px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text);
}
.merge-help-body p { margin: 6px 0; }
.merge-help-body ol {
  margin: 8px 0 8px 22px;
  padding: 0;
}
.merge-help-body ol li {
  margin: 4px 0;
}
.merge-help-body strong { font-weight: 600; }

.merge-picker-card { /* nothing extra, just a hook */ }

.merge-picker-grid {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 16px;
  align-items: end;             /* anchor the arrow to the bottom of the inputs */
  margin-top: 12px;
}
.merge-slot {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  justify-content: flex-end;
}
.merge-slot .slot-label {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 0;
}
.merge-slot .slot-eyebrow {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: 1px;
}
.merge-slot .slot-eyebrow-bad  { color: var(--bad); }
.merge-slot .slot-eyebrow-good { color: var(--good); }
.merge-slot .slot-label-name {
  display: block;
  font-weight: 700;
  color: var(--text);
  font-size: 13px;
}

/* Slot identity is carried by the STRYGES / → BEHOLDES eyebrow labels above
   the inputs. We deliberately do NOT add color stripes on the inputs or
   picked-cards — that would be the rounded-card+left-stripe trope CLAUDE.md
   forbids. Inputs stay neutral; eyebrows do the work. */

.merge-slot-arrow {
  align-self: end;
  margin: 0 0 12px;
  font-size: 16px;
  font-weight: 400;
  color: var(--border-strong);
  padding: 0 2px;
  line-height: 1;
}

@media (max-width: 720px) {
  .merge-picker-grid {
    grid-template-columns: 1fr;
    gap: 8px;
  }
  .merge-slot-arrow {
    transform: rotate(90deg);
    margin: 0 auto;
    padding: 4px 0;
  }
}

/* Combobox autocomplete (merge picker). Lives over the input field. */
.combobox {
  position: relative;
}
.combobox input {
  width: 100%;
  padding: 8px 10px;
  font-size: 14px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-sizing: border-box;
}
.combobox input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-color: var(--accent);
}
.combobox .listbox {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: -1px;             /* flush with input bottom-border */
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-top-color: var(--border);
  border-radius: 0;             /* sharp continuation from input */
  z-index: 30;
  max-height: 320px;
  overflow-y: auto;
  list-style: none;
  padding: 0;
  box-shadow: 0 1px 0 var(--border-strong);
}
/* Listbox stays neutral — no colored slot-edge. */
.combobox .listbox[hidden] { display: none; }
.combobox .listbox li {
  padding: 8px 12px;
  font-size: 13px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
}
.combobox .listbox li:last-child { border-bottom: 0; }
.combobox .listbox li.empty { cursor: default; opacity: 0.7; display: block; }
.combobox .listbox li:not(.empty) { transition: background 60ms ease, box-shadow 60ms ease; }
.combobox .listbox li:hover:not(.empty),
.combobox .listbox li[aria-selected="true"]:not(.empty) {
  background: var(--surface-2);
  box-shadow: inset 2px 0 0 var(--accent);
}
.combobox .listbox li .hit-main { min-width: 0; line-height: 1.35; }
.combobox .listbox li .hit-hint {
  margin-top: 2px;
  font-size: 11px;
  color: var(--text-muted);
}
.combobox .listbox li .meta {
  font-size: 11px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
  align-self: start;
  line-height: 1.35;
}
.combobox .listbox li .name { font-weight: 600; color: var(--text); margin-right: 6px; }
.combobox .listbox li .city { font-size: 12px; color: var(--text-muted); margin-right: 4px; }

.picked-card {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: 0;
  font-size: 14px;
}
.picked-card strong { font-weight: 700; }
.picked-card .picked-meta { color: var(--text-muted); font-size: 12px; }
.picked-card button.unpick {
  margin-left: auto;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 11px;
  padding: 2px 8px;
  cursor: pointer;
  border-radius: 0;
}
.picked-card button.unpick:hover {
  border-color: var(--bad);
  color: var(--bad);
}

/* Hard guard against ghost element rendering when hidden — some flex/inline
   declarations have been observed leaking through in edge cases. */
.picked-card[hidden],
.combobox .listbox[hidden] { display: none !important; }

/* ---------------------------------------------------------------------------
 * Race-type class catalog (Step 1).
 *
 * Per-class (i) info button next to each chip in the filter strip; per-class
 * detail modal mirroring the class-filter modal. Tabel/row class cells
 * become clickable when their race has a catalog entry — pointer cursor +
 * hover signal + same data-action="class-detail" handler.
 * ------------------------------------------------------------------------- */
.class-chip-group {
  display: inline-flex;
  align-items: stretch;
  gap: 0;
}
.class-chip-info {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-left: 0;            /* visually shares an edge with the chip */
  color: var(--text-muted);
  cursor: pointer;
  padding: 0 6px;
  min-height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 0;
}
.class-chip-info:hover { color: var(--text); border-color: var(--text); }
.class-chip-info .icon-info { width: 14px; height: 14px; }

/* Inside the filter modal the (i) becomes a separate full-row-height column
 * at the right edge, hairline-divided from the chip body. 44×44 hit target. */
.class-filter-modal .class-chip-info {
  border: 0;
  border-left: 1px solid var(--border);
  background: transparent;
  min-width: 44px;
  min-height: 44px;
  flex-shrink: 0;
  align-self: stretch;
  padding: 0;
}
.class-filter-modal .class-chip-info:hover {
  background: var(--surface-2);
  color: var(--text);
}
.class-filter-modal .class-chip-info .icon-info {
  width: 16px;
  height: 16px;
}
/* When the row beside (i) is pressed, tint (i) lightly so it still belongs
 * to the same cell visually but stays distinguishable as its own affordance. */
.class-filter-modal .class-chip-group:has(.class-chip[aria-pressed="true"]) .class-chip-info {
  background: color-mix(in srgb, var(--ob-bg) 50%, transparent);
}
@media (max-width: 480px) {
  .class-filter-modal .class-chip-info {
    min-width: 38px;
    min-height: 38px;
  }
  .class-filter-modal .class-chip-info .icon-info {
    width: 14px;
    height: 14px;
  }
}

/* Tabel class cell + Hurtig/Detaljer row-class button — clickable affordance
   when the race has a catalog. We deliberately don't add background colour or
   a heavy hover — the cell stays dense (newspaper aesthetic). */
td.t-class[data-action="class-detail"] { cursor: pointer; }
td.t-class[data-action="class-detail"]:hover { text-decoration: underline; }
td.t-class[data-action="class-detail"]:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: -1px;
}
.row-class.row-class-btn {
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
  font: inherit;
  padding: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.row-class.row-class-btn:hover { text-decoration: underline; }
.row-class.row-class-btn:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 1px;
}

/* Class-detail dialog. Mirrors .class-filter-modal sizing + positioning;
   different content layout (title + short subtitle + long body). */
.class-detail-modal {
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  padding: 0;
  max-width: 480px;
  width: calc(100% - 32px);
  max-height: 80vh;
  border-radius: 0;
}
.class-detail-modal::backdrop { background: color-mix(in srgb, var(--text) 32%, transparent); }
.class-detail-modal[open] { display: block; }
.class-detail-form {
  display: flex;
  flex-direction: column;
  max-height: 80vh;
}
.class-detail-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.class-detail-header h3 {
  margin: 0;
  font: 600 18px/1.2 inherit;
  letter-spacing: 0.02em;
}
.class-detail-close {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 22px;
  line-height: 1;
  padding: 0 6px;
  min-height: 32px;
  min-width: 32px;
}
.class-detail-close:hover { color: var(--text); }
.class-detail-short {
  margin: 0;
  padding: 12px 14px 4px;
  font: 600 13px/1.4 inherit;
  color: var(--text-muted);
}
.class-detail-short:empty { display: none; }
.class-detail-long {
  margin: 0;
  padding: 6px 14px 14px;
  font: 14px/1.5 inherit;
  overflow-y: auto;
}
.class-detail-empty {
  margin: 0;
  padding: 12px 14px;
  font: 14px/1.4 inherit;
  color: var(--text-muted);
}

/* Admin race-class card list (admin-race-type-form.ejs). Hairline-divided
   stack of per-class cards — newspaper aesthetic; no rounded corners, no
   shadows. Each card has its own form for upsert + a side delete form. */
.race-class-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 16px;
}
.race-class-card {
  border: 1px solid var(--border);
  padding: 12px;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 12px;
  align-items: start;
}
.race-class-card-actions {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
}
.inline-form-right { align-self: start; }

/* =============================================================================
 * Admin overhaul (2026-05-10) — dashboard + races page + cross-cutting fixes
 *
 * Goals
 *   1) Single canonical button system with consistent heights, hovers, and
 *      a real disabled state (was inconsistent across admin pages).
 *   2) Newspaper / motorsport-timing aesthetic — hard edges, hairlines, no
 *      AI-design tropes (no rounded card + colored left-stripe).
 *   3) Solid flash + status colours that read in all 3 themes (auto / sun /
 *      dark), replacing the rgba+colored-text pattern that failed AA.
 *   4) Native <details>/<summary> for the per-race fold/expand on the new
 *      /admin/races page.
 *
 * Cross-cutting fixes also targeted at the global `<button>` so the old
 * admin pages (venue-form, race-type-form, identity) improve incidentally.
 * =========================================================================== */

/* --- 1) BUTTON SYSTEM ---------------------------------------------------- */

/* Canonical .btn for new admin pages. Old `<button>` rules above stay so
   existing identity / venue / race-type forms aren't churned. New pages
   either apply .btn explicitly or sit inside .race-card / .admin-create
   which scope-extend the rules below. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font: 600 14px/1.2 inherit;
  padding: 8px 14px;
  min-height: 32px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  border-radius: 4px;
  cursor: pointer;
  transition: background 80ms, border-color 80ms, color 80ms;
}
.btn:hover { background: var(--surface-2); border-color: var(--text-muted); color: var(--text); }
.btn:active { background: var(--surface-3); }
.btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

/* Primary — used sparingly: Opret, Gem (per inline form). */
.btn-primary {
  background: var(--accent);
  color: var(--accent-on);
  border-color: var(--accent);
}
.btn-primary:hover {
  /* Darken instead of brightening — readable on the dark-blue Solskin
     accent where +6% brightness was imperceptible. */
  filter: brightness(0.92);
  border-color: var(--accent);
  color: var(--accent-on);
}

/* Danger — destructive actions. Solid invert on hover so the user sees a
   clear "you're about to do a destructive thing" affordance. */
.btn-danger {
  background: var(--surface);
  color: var(--bad);
  border-color: var(--bad);
}
.btn-danger:hover {
  background: var(--bad);
  color: #ffffff;
  border-color: var(--bad);
}

/* Small / chip variants — keep newspaper density; min-height 28px is
   reachable on iPhone but doesn't bloat dense rows. */
.btn-small {
  min-height: 28px;
  padding: 4px 10px;
  font-size: 12px;
}
.btn-chip {
  min-height: 28px;
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.btn-chip.is-active,
.btn-chip[aria-pressed="true"] {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
}

/* Link-style pill (e.g. /race/:slug ↗ in the card top-bar). Underline-on-hover. */
.btn-link-pill {
  font: 12px/1.2 inherit;
  padding: 4px 10px;
  min-height: 24px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 4px;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.btn-link-pill:hover { border-color: var(--text); text-decoration: underline; }

/* Disabled state — applies to .btn AND to bare global <button>, so AJAX
   forms in admin-races.js get a real visual cue while in-flight. */
.btn:disabled, .btn[aria-busy="true"],
.admin-shell button:disabled, .admin-shell button[aria-busy="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  background: var(--surface-2);
  color: var(--text-muted);
  border-color: var(--border);
  filter: none;
}

/* --- 2) GLOBAL BUTTON HOVER FIX (visual fix #4) ------------------------- */
/* The old `button:hover { filter: brightness(1.06) }` was imperceptible
   on dark backgrounds. Replace with explicit colour-changes for non-.btn
   buttons too. .danger gets a real hover (visual fix #1). */
.admin-shell button:not(.btn):not(.row-add):not(.row-remove):not(.adm-combobox-option):hover {
  filter: brightness(0.92);
}
.admin-shell button.danger {
  background: var(--surface);
  color: var(--bad);
  border-color: var(--bad);
}
.admin-shell button.danger:hover {
  background: var(--bad);
  color: #ffffff;
  border-color: var(--bad);
  filter: none;
}

/* --- 3) SIDEBAR FOOT BUTTON (visual fix #6) ----------------------------- */
.admin-sidebar-foot button {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  font-weight: 500;
}
.admin-sidebar-foot button:hover {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--text-muted);
}

/* --- 4) FLASH MESSAGES (visual fix #3) ---------------------------------- */
/* Old .flash-* used rgba(.,.,.,0.1) bg + coloured text → ~3:1 contrast on
   light theme, AA-fail. Solid bg + white text + darker left-anchor is
   readable in all 3 themes. */
.flash {
  padding: 10px 14px;
  margin-bottom: 14px;
  border-radius: 0;
  border-left: 3px solid currentColor;
  font-weight: 500;
}
.flash-success {
  background: var(--good);
  color: #ffffff;
  border-left-color: rgba(0, 0, 0, 0.35);
}
.flash-error {
  background: var(--bad);
  color: #ffffff;
  border-left-color: rgba(0, 0, 0, 0.35);
}
.flash-info {
  background: var(--accent);
  color: var(--accent-on);
  border-left-color: rgba(0, 0, 0, 0.35);
}
.flash-warn {
  background: var(--warn);
  color: #ffffff;
  border-left-color: rgba(0, 0, 0, 0.35);
}

/* Inline AJAX toast (admin-races.js writes here). Lives below the page
   header, full-width hairline strip — sharp edges, no shadow. */
.admin-toast {
  padding: 8px 14px;
  margin-bottom: 12px;
  font: 600 13px/1.2 inherit;
  border-left: 3px solid rgba(0, 0, 0, 0.35);
}
.admin-toast-ok { background: var(--good); color: #ffffff; }
.admin-toast-fail { background: var(--bad); color: #ffffff; }

/* --- 5) FORM FIELD UNIFICATION (visual fix #5) -------------------------- */
/* Inside admin shell, unify all form-field paddings so .grid-form, .src-field
   and .url-row stop fighting each other. Outer rules above stay intact —
   we just override within the admin scope. */
.admin-shell .grid-form input,
.admin-shell .grid-form select,
.admin-shell .grid-form textarea,
.admin-shell .src-config-grid input,
.admin-shell .src-config-grid select,
.admin-shell .url-row .url-row-url,
.admin-shell .url-row .url-row-narrow,
.admin-shell .src-add-form input,
.admin-shell .src-add-form select,
.admin-shell .admin-form-inline select,
.admin-shell .admin-form-inline input {
  padding: 7px 10px;
  min-height: 32px;
  font-size: 13px;
}
.admin-shell input:focus-visible,
.admin-shell select:focus-visible,
.admin-shell textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-color: var(--accent);
}

/* --- 6) DASHBOARD ------------------------------------------------------- */

.admin-header-meta {
  margin: 0;
  font: 12px/1.4 inherit;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.admin-header-actions {
  display: flex;
  gap: 8px;
}

.admin-kpis {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
  border: 1px solid var(--border);
  background: var(--surface);
  margin-bottom: 22px;
}
.admin-kpi {
  padding: 14px 16px;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.admin-kpi:last-child { border-right: 0; }
.admin-kpi-label {
  font: 600 11px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.admin-kpi-value {
  font: 700 28px/1 inherit;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.admin-kpi-frac {
  font-weight: 400;
  color: var(--text-muted);
  font-size: 18px;
}
.admin-kpi-detail {
  font: 12px/1.3 inherit;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 760px) {
  .admin-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .admin-kpi:nth-child(2) { border-right: 0; }
  .admin-kpi:nth-child(1), .admin-kpi:nth-child(2) {
    border-bottom: 1px solid var(--border);
  }
}

.admin-card-h {
  margin: 0 0 12px;
  font: 600 13px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px;
}

.admin-attention {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
}
.admin-attention-empty {
  font: 14px/1.4 inherit;
  color: var(--good);
  font-weight: 500;
}
.admin-attention-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--bad);
  background: color-mix(in srgb, var(--bad) 8%, var(--surface));
  color: var(--text);
}
.admin-attention-pending-matches {
  border-color: var(--warn);
  background: color-mix(in srgb, var(--warn) 8%, var(--surface));
}
.admin-attention-text {
  font: 14px/1.4 inherit;
  font-weight: 500;
}
.admin-attention-link {
  flex-shrink: 0;
  font: 12px/1.2 inherit;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  padding: 4px 10px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  white-space: nowrap;
}
.admin-attention-link:hover {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
}

.admin-grid-2col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 22px;
}
@media (max-width: 760px) {
  .admin-grid-2col { grid-template-columns: 1fr; }
}

.admin-shortcuts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  border: 1px solid var(--border);
}
.admin-shortcuts li { display: flex; }
.admin-shortcut {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  text-decoration: none;
  color: var(--text);
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  min-height: 44px;
}
.admin-shortcut:hover {
  background: var(--surface-2);
  color: var(--text);
}
.admin-shortcut-label { font: 600 14px/1.2 inherit; }
.admin-shortcut-count {
  font: 700 16px/1 inherit;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.admin-shortcut-primary {
  background: var(--accent);
  color: var(--accent-on);
}
.admin-shortcut-primary:hover {
  background: var(--accent);
  color: var(--accent-on);
  filter: brightness(0.92);
}
.admin-shortcuts li:nth-child(odd) .admin-shortcut { border-right: 1px solid var(--border); }
.admin-shortcuts li:nth-child(even) .admin-shortcut { border-right: 0; }
.admin-shortcuts li:nth-last-child(-n+2) .admin-shortcut { border-bottom: 0; }

.admin-merges {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0;
  font-variant-numeric: tabular-nums;
}
.admin-merges li {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 12px;
  align-items: baseline;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  font: 13px/1.4 inherit;
}
.admin-merges li:last-child { border-bottom: 0; }
.admin-merge-time { color: var(--text-muted); font-size: 12px; }
.admin-merge-arrow { color: var(--text); font-weight: 500; }
.admin-merge-reverted {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

/* --- 7) RACES PAGE — collapsible cards + grouped forms ------------------ */

.admin-races-toolbar {
  padding: 14px 16px;
  margin-bottom: 12px;
}
.admin-races-toolbar-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 12px;
  align-items: center;
}
@media (max-width: 760px) {
  .admin-races-toolbar-row {
    grid-template-columns: 1fr;
  }
}
.admin-search {
  width: 100%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  padding: 7px 10px;
  font: 13px/1.2 inherit;
  border-radius: 0;
  min-height: 32px;
}
.admin-filter-chips {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}

.admin-empty {
  padding: 16px;
  border: 1px dashed var(--border);
  color: var(--text-muted);
  text-align: center;
}

.admin-races {
  display: grid;
  gap: 0;
  border: 1px solid var(--border);
  background: var(--surface);
}

.race-card {
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.race-card:last-child { border-bottom: 0; }
.race-card[hidden] { display: none; }

.race-card-summary {
  list-style: none;
  cursor: pointer;
  padding: 10px 12px;
  display: grid;
  grid-template-columns: 16px 1fr auto auto;
  gap: 12px;
  align-items: center;
  user-select: none;
}
.race-card-summary::-webkit-details-marker { display: none; }
.race-card-summary::marker { content: ""; }
.race-card-chevron {
  width: 12px; height: 12px;
  display: inline-block;
  position: relative;
}
.race-card-chevron::before {
  content: "";
  position: absolute;
  top: 2px; left: 1px;
  width: 7px; height: 7px;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(-45deg);
  transition: transform 120ms ease;
}
.race-card[open] .race-card-chevron::before {
  transform: rotate(45deg);
  top: 0; left: 2px;
}
.race-card-summary:hover {
  background: var(--surface-2);
}
.race-card[open] > .race-card-summary {
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.race-card-title {
  font: 600 15px/1.2 inherit;
  color: var(--text);
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.race-card-badges {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-shrink: 0;
}
.race-card-prefix {
  font: 600 11px/1 inherit;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  border: 1px solid var(--border-strong);
  padding: 2px 6px;
  text-transform: uppercase;
}
.race-card-meta {
  font: 12px/1.2 inherit;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  text-align: right;
}
@media (max-width: 760px) {
  .race-card-summary {
    grid-template-columns: 16px 1fr auto;
  }
  .race-card-meta { display: none; }
}

.status-error {
  background: var(--bad);
  color: #ffffff;
  padding: 2px 6px;
  font: 600 11px/1 inherit;
  text-transform: uppercase;
}

.race-card-body {
  padding: 14px 16px;
  display: grid;
  gap: 18px;
}

.race-card-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-variant-numeric: tabular-nums;
}
.race-card-id {
  font: 12px/1.2 inherit;
  color: var(--text-muted);
}

.race-card-section-h {
  font: 600 11px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
  padding-bottom: 4px;
  margin: 0 0 10px;
}

/* --- Source cards inside a race ------------------------------------------ */

.source-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0;
  border: 1px solid var(--border);
}
.source-card {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  display: grid;
  gap: 8px;
}
.source-card:last-child { border-bottom: 0; }
.source-card.is-error { border-left: 3px solid var(--bad); padding-left: 9px; }

.source-card-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 10px;
  align-items: center;
  min-width: 0;
}
.source-card-prefix {
  font: 700 12px/1 inherit;
  letter-spacing: 0.04em;
  color: var(--text);
  background: var(--surface-2);
  padding: 4px 8px;
  border: 1px solid var(--border-strong);
}
.source-card-url {
  font: 12px/1.2 ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-decoration: none;
  min-width: 0;
}
.source-card-url:hover { text-decoration: underline; }
.source-card-meta {
  font: 12px/1.2 inherit;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  text-align: right;
  white-space: nowrap;
}
.source-card-meta-row {
  display: flex;
  gap: 14px;
  font: 12px/1.2 inherit;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  flex-wrap: wrap;
}
.source-card-err { color: var(--bad); font-weight: 500; }

.src-config-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 8px;
}
.src-config-grid label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font: 11px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
@media (max-width: 760px) {
  .src-config-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.source-card-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.src-add {
  margin-top: 12px;
  border: 1px dashed var(--border);
  padding: 0;
}
.src-add-summary {
  cursor: pointer;
  padding: 8px 12px;
  font: 600 12px/1.2 inherit;
  color: var(--text-muted);
  list-style: none;
  user-select: none;
}
.src-add-summary::-webkit-details-marker { display: none; }
.src-add-summary:hover { color: var(--text); background: var(--surface-2); }
.src-add[open] .src-add-summary {
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.src-add-form {
  padding: 10px 12px;
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
}
.src-add-form input[name="url"] {
  flex: 1 1 280px;
  min-width: 200px;
}

/* --- Race-level inline forms (venue / race-type / status) --------------- */

.race-card-stamdata {
  display: grid;
  gap: 10px;
}
.admin-form-inline {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.admin-form-inline-label {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 0;
  min-width: 240px;
}
.admin-form-inline-label > span {
  font: 600 11px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  flex-shrink: 0;
  min-width: 64px;
}
.admin-form-inline-label > select,
.admin-form-inline-label > input {
  flex: 1;
  min-width: 0;
}

.admin-form-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 8px;
}

/* --- Save-status badge — sits next to the submit button ----------------- */
.save-status {
  font: 12px/1.2 inherit;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  padding: 0 8px;
  white-space: nowrap;
  min-width: 80px;
}
.save-status.idle { color: var(--text-muted); }
.save-status.busy { color: var(--text-muted); font-style: italic; }
.save-status.ok   { color: var(--good); font-weight: 600; }
.save-status.fail { color: var(--bad);  font-weight: 600; }

/* --- Avanceret fold ------------------------------------------------------ */

.race-card-advanced {
  border-top: 1px solid var(--border);
  margin-top: 4px;
  padding-top: 8px;
}
.race-card-advanced-summary {
  cursor: pointer;
  font: 600 11px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  list-style: none;
  user-select: none;
  padding: 4px 0;
}
.race-card-advanced-summary::-webkit-details-marker { display: none; }
.race-card-advanced-summary::before {
  content: "▸ ";
  color: var(--text-muted);
}
.race-card-advanced[open] .race-card-advanced-summary::before { content: "▾ "; }
.race-card-advanced-body {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 0 0;
}

/* --- Create-race fold (top of /admin/races) ----------------------------- */

.admin-create {
  margin-bottom: 20px;
}
.admin-create-summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  user-select: none;
}
.admin-create-summary::-webkit-details-marker { display: none; }
.admin-create-summary h2 {
  margin: 0;
  font: 600 16px/1.2 inherit;
}
.admin-create-summary::before {
  content: "▸";
  color: var(--text-muted);
  font-size: 14px;
}
.admin-create[open] .admin-create-summary::before { content: "▾"; }
.admin-create-hint {
  font: 12px/1.2 inherit;
  color: var(--text-muted);
}
.admin-create form { margin-top: 16px; }
.admin-create-summary-title {
  font: 600 16px/1.2 inherit;
}

/* Per-race "Gem ændringer" anchor — full-width strip with the single primary
   action + its status slot. Sits BELOW Stamdata + Kilder, ABOVE Avanceret.
   Sticky on tall cards so the button doesn't slide off while scrolling. */
.race-card-save {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  margin: 4px -16px -2px -16px;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  position: sticky;
  bottom: 0;
  z-index: 1;
}
.race-card-save .save-status { margin-left: 0; min-width: 160px; }
.race-card-save .btn { min-width: 160px; }

/* Settings forms have no per-form Gem button; trim padding accordingly. */
.src-config-form { margin: 0; }
.race-card-stamdata form { margin: 0; }

/* ===========================================================================
   ADMIN /admin/races — FLAT REDESIGN
   Drops panel-boxes for generous whitespace, hairline section dividers,
   inline SVG icons, and flex-based source rows.
   =========================================================================== */

/* ---------- Breadcrumb + page heading ----------------------------------- */

.admin-breadcrumb { margin-bottom: 18px; }
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-muted);
  font-size: 13px;
  text-decoration: none;
  padding: 4px 8px 4px 4px;
  margin-left: -4px;
  border-radius: 6px;
  transition: color 120ms ease, background 120ms ease;
}
.back-link:hover { color: var(--text); background: var(--surface-2); }
.back-link svg { transition: transform 120ms ease; }
.back-link:hover svg { transform: translateX(-2px); }

.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 32px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--border);
}
.page-head-main { flex: 1 1 0; min-width: 0; position: relative; }
.page-title {
  font: 700 28px/1.15 inherit;
  letter-spacing: -0.01em;
  margin: 0 0 4px 0;
  color: var(--text);
}
.page-subtitle {
  font-size: 13.5px;
  color: var(--text-muted);
  margin: 0;
  line-height: 1.4;
}
.page-meta {
  font-size: 12.5px;
  color: var(--text-muted);
  margin: 6px 0 0 0;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  line-height: 1.4;
}
.page-meta-slug {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  color: var(--text-muted);
  text-decoration: none;
  padding: 2px 6px;
  margin: -2px -6px;
  border-radius: 4px;
  transition: color 120ms ease, background 120ms ease;
}
.page-meta-slug:hover { color: var(--text); background: var(--surface-2); }
.page-meta-sep { opacity: 0.5; }
.page-actions { display: flex; gap: 8px; flex-shrink: 0; }

.race-status-strip {
  height: 3px;
  width: 64px;
  margin: 0 0 14px 0;
  border-radius: 2px;
  background: var(--text-muted);
}
.race-status-strip[data-status="active"] { background: var(--good); }
.race-status-strip[data-status="dormant"] { background: var(--warn); }
.race-status-strip[data-status="archived"] { background: var(--border-strong); }
.race-status-strip[data-status="completed"] { background: var(--text-muted); }

/* ---------- Sections (flat, no panel boxes) ----------------------------- */

.section { margin-bottom: 40px; }
.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}
.section-title {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font: 600 12px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.section-title svg { color: var(--text-muted); opacity: 0.8; }
.section-title-danger { color: var(--bad); }
.section-title-danger svg { color: var(--bad); opacity: 0.9; }
.section-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 18px;
  padding: 0 6px;
  margin-left: 4px;
  border-radius: 9px;
  background: var(--surface-2);
  color: var(--text-muted);
  font: 600 11px/1 inherit;
  letter-spacing: 0;
  text-transform: none;
}
.section-hint {
  margin: 4px 0 0 0;
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.45;
}
.section-empty {
  font-size: 13.5px;
  color: var(--text-muted);
  margin: 0 0 16px 0;
  font-style: italic;
}
.section-empty-hint {
  margin: 10px 0 0 0;
  font-size: 12px;
  line-height: 1.45;
}
.section-aside { margin-top: 12px; font-size: 12.5px; }

.btn-section-save {
  opacity: 0.4;
  pointer-events: none;
  transition: opacity 140ms ease;
}
.section.is-dirty .btn-section-save,
[data-panel].is-dirty .btn-section-save {
  opacity: 1;
  pointer-events: auto;
}

.section-danger { margin-top: 56px; }

/* ---------- Field grid -------------------------------------------------- */

.field-grid { display: grid; gap: 18px 24px; }
.field-grid-2 { grid-template-columns: 1fr 1fr; }
.field-grid-3 { grid-template-columns: 1fr 1fr 1fr; }
.field-full,
.field.field-full,
.field-grid > .field-full { grid-column: 1 / -1; }
@media (max-width: 720px) {
  .field-grid-2, .field-grid-3 { grid-template-columns: 1fr; }
}

.field { display: flex; flex-direction: column; gap: 6px; margin: 0; }
.field > label { display: flex; flex-direction: column; gap: 6px; margin: 0; }
.field-label {
  font: 600 11.5px/1.2 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.field-hint {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  font-size: 11px;
  opacity: 0.7;
  margin-left: 4px;
}
.field input[type="text"],
.field input[type="url"],
.field input[type="number"],
.field input:not([type]),
.field select,
.field textarea {
  width: 100%;
  min-height: 36px;
  padding: 8px 10px;
  font-size: 13.5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.field-readonly .field-value {
  padding: 8px 0;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text);
}
.field-value-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  color: var(--text-muted);
}

/* ---------- Segmented control (Status) -------------------------------- */

.segmented {
  display: inline-flex;
  align-items: center;
  gap: 0;
  padding: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.segmented-option {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted);
  border-radius: 6px;
  user-select: none;
  transition: color 120ms ease, background 120ms ease;
}
.segmented-option input { position: absolute; opacity: 0; pointer-events: none; }
.segmented-option:hover:not(.is-active):not(.is-readonly) { color: var(--text); }
.segmented-option.is-active {
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--text) 10%, transparent);
}
.segmented-option.is-readonly { cursor: default; font-style: italic; }
.segmented-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted); }
.segmented-dot-active { background: var(--good); }
.segmented-dot-archived { background: var(--border-strong); }
.segmented-dot-dormant { background: var(--warn); }
.segmented-dot-completed { background: var(--text-muted); }

/* ---------- Source list (flat) ---------------------------------------- */

.source-list {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid var(--border);
}
.source-item {
  border-bottom: 1px solid var(--border);
  transition: background 120ms ease;
}
.source-item:hover { background: color-mix(in srgb, var(--surface-2) 60%, transparent); }
.source-item.has-error { background: color-mix(in srgb, var(--bad) 4%, transparent); }
.source-item.has-error:hover { background: color-mix(in srgb, var(--bad) 7%, transparent); }
.source-item-main {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 4px;
  position: relative;
}

.source-prefix {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  font: 700 13px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  letter-spacing: 0.04em;
}
.source-prefix-add {
  background: transparent;
  border-style: dashed;
  color: var(--text-muted);
  font-size: 18px;
  font-weight: 400;
}

.source-info { flex: 1 1 0; min-width: 0; }
.source-url {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  font: 12.5px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--text);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.source-url:hover { color: var(--accent); text-decoration: underline; }
.source-url-ext { opacity: 0.5; flex-shrink: 0; margin-left: 2px; }
.source-health {
  margin-top: 4px;
  font-size: 11.5px;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.source-health.is-error { color: var(--bad); }
.health-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--text-muted);
  flex-shrink: 0;
}
.health-dot-ok { background: var(--good); }
.health-dot-idle { background: var(--warn); }
.health-dot-error { background: var(--bad); }
.health-error-text { color: var(--bad); }

/* ---------- New flat source-item layout (all fields always visible) ---- */

.source-head {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 4px 6px 4px;
}
.source-head-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
}

/* Always-visible config fields (Preset · Type-navn · Kort · Tæller · Rk) */
.source-config-row {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  padding: 4px 4px 14px 54px;
  margin: 0;
  flex-wrap: wrap;
}
.source-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  min-width: 0;
}
.source-field-label {
  font: 600 10.5px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.source-field input,
.source-field select {
  min-height: 32px;
  padding: 6px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
  width: 100%;
}
.source-field input:focus,
.source-field select:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.source-field-grow { flex: 1 1 0; min-width: 140px; }
.source-field-tight { flex: 0 0 70px; max-width: 90px; }
.source-field:not(.source-field-grow):not(.source-field-tight) { flex: 0 0 auto; min-width: 130px; }

/* Add-source slot: same head + config-row pattern */
.source-item-add .source-head { padding: 14px 4px 6px 4px; }
.source-item-add .source-info { flex: 1 1 0; min-width: 0; }
.source-item-add .source-add-url {
  width: 100%;
  min-height: 36px;
  padding: 8px 12px;
  font-size: 13.5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.source-item-add .source-add-url:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

/* ---------- Create-form: per-link visible field grid ----------------- */

.vola-link-row {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.vola-link-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  min-width: 0;
}
.vola-link-field-label {
  font: 600 10.5px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.vola-link-field input,
.vola-link-field select {
  width: 100%;
  min-height: 36px;
  padding: 8px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.vola-link-field input:focus,
.vola-link-field select:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.vola-link-field-url { flex: 1 1 100%; }
.vola-link-config {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}
.vola-link-field-preset { flex: 0 0 160px; min-width: 140px; }
.vola-link-field-name { flex: 1 1 140px; min-width: 120px; }
.vola-link-field-prefix { flex: 0 0 80px; max-width: 100px; }
.vola-link-field-counts { flex: 0 0 100px; max-width: 120px; }
.vola-link-config .row-remove {
  flex-shrink: 0;
  margin-bottom: 0;
  align-self: flex-end;
}

@media (max-width: 720px) {
  .vola-link-config { flex-direction: column; align-items: stretch; gap: 10px; }
  .vola-link-field-preset,
  .vola-link-field-name,
  .vola-link-field-prefix,
  .vola-link-field-counts { flex: 1 1 100%; max-width: none; }
  .source-config-row { padding-left: 4px; }
}

/* Legacy (dormant) — kept for safety, no EJS references currently */
.source-controls {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 12px;
}
.source-control-label { display: flex; flex-direction: column; gap: 4px; margin: 0; }
.source-control-label > span {
  font: 600 10.5px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.source-control-label select {
  min-width: 110px;
  min-height: 32px;
  padding: 6px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.source-control-label select:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.source-preset-form, .source-counts-form { margin: 0; }

.source-actions { flex: 0 0 auto; display: flex; align-items: center; gap: 4px; }

.source-advanced {
  background: color-mix(in srgb, var(--surface-2) 55%, transparent);
  border-top: 1px dashed var(--border);
  padding: 16px 50px 18px 50px;
}
.source-advanced[hidden] { display: none; }
.source-advanced-form { margin: 0; }

.source-item-add { border-bottom: 0; }
.source-item-add:hover { background: transparent; }
.source-add-form {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 4px;
  margin: 0;
}
.source-add-url {
  flex: 1 1 280px;
  min-width: 200px;
  min-height: 36px;
  padding: 8px 12px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.source-add-url:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.source-add-preset {
  flex: 0 0 140px;
  min-height: 36px;
  padding: 8px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.btn-add-source { white-space: nowrap; }

/* Icon-only button (used for ⚙ ⟳ ×) */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
}
.icon-btn:hover {
  color: var(--text);
  background: var(--surface-2);
  border-color: var(--border);
}
.icon-btn:focus-visible {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.icon-btn-danger:hover {
  color: var(--bad);
  background: color-mix(in srgb, var(--bad) 8%, transparent);
  border-color: color-mix(in srgb, var(--bad) 30%, var(--border));
}
.icon-btn-ghost { color: var(--text-muted); }
.icon-btn[aria-expanded="true"] {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
}

.text-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  margin-top: 10px;
  background: transparent;
  border: 0;
  color: var(--accent);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  border-radius: 6px;
  transition: background 120ms ease;
}
.text-btn:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }

.btn-ghost {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
}
.btn-ghost:hover { background: var(--surface-2); border-color: var(--border-strong); }

.inline-form { display: inline-block; margin: 0; }
.inline-form + .inline-form { margin-left: 0; }

.link-external {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--text-muted);
  text-decoration: none;
  font-size: 12.5px;
  padding: 2px 6px;
  margin-left: -6px;
  border-radius: 4px;
  transition: color 120ms ease, background 120ms ease;
}
.link-external:hover {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}

/* ---------- Danger actions -------------------------------------------- */

.danger-actions { display: flex; flex-direction: column; gap: 0; }
.danger-action {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 16px 0;
  border-bottom: 1px solid var(--border);
}
.danger-action:last-child { border-bottom: 0; padding-bottom: 0; }
.danger-action:first-child { padding-top: 0; }
.danger-action-text { flex: 1 1 0; min-width: 0; }
.danger-action-text strong { display: block; font-size: 14px; font-weight: 600; color: var(--text); }
.danger-action-text p { margin: 4px 0 0 0; line-height: 1.45; font-size: 12.5px; color: var(--text-muted); }

/* ---------- Create-form Vola-link rows -------------------------------- */

.create-form { max-width: 720px; }
.vola-link-rows { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.vola-link-row { display: flex; align-items: center; gap: 10px; }
.vola-link-url {
  flex: 1 1 0;
  min-width: 0;
  min-height: 36px;
  padding: 8px 12px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.vola-link-url:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.vola-link-preset {
  flex: 0 0 160px;
  min-height: 36px;
  padding: 8px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.vola-link-row .row-remove { flex-shrink: 0; }

.form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}

/* ---------- Responsive: stack source-item bits on narrow screens ------ */

@media (max-width: 920px) {
  .source-item-main { flex-wrap: wrap; }
  .source-info { flex-basis: calc(100% - 50px); }
  .source-controls {
    flex-basis: 100%;
    margin-top: 8px;
    padding-left: 50px;
  }
  .source-actions {
    position: absolute;
    top: 14px;
    right: 4px;
  }
  .source-advanced { padding: 16px 16px 18px 16px; }
}

@media (max-width: 540px) {
  .vola-link-row { flex-wrap: wrap; }
  .vola-link-preset { flex: 1 1 100%; }
  .source-controls { flex-wrap: wrap; }
  .source-control-label select { width: 100%; }
}

/* ---------- List page: toolbar + race-list -------------------------------- */

.list-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.list-search {
  position: relative;
  flex: 1 1 280px;
  max-width: 420px;
  min-width: 220px;
}
.list-search svg {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  pointer-events: none;
}
.list-search input[type="search"] {
  width: 100%;
  min-height: 38px;
  padding: 8px 12px 8px 36px;
  font-size: 13.5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.list-search input[type="search"]:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

.filter-chips {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.chip:hover { color: var(--text); background: var(--surface-2); }
.chip.is-active {
  color: var(--accent-on);
  background: var(--accent);
  border-color: var(--accent);
}
.chip-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 16px;
  padding: 0 5px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--text-muted) 20%, transparent);
  color: inherit;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0;
}
.chip.is-active .chip-count {
  background: color-mix(in srgb, var(--accent-on) 25%, transparent);
}

/* The flat race list — replaces the previous .races-table. */
.race-list {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid var(--border);
}
.race-list-item {
  border-bottom: 1px solid var(--border);
  transition: background 120ms ease;
}
.race-list-item:hover { background: color-mix(in srgb, var(--surface-2) 60%, transparent); }
.race-list-item.has-error { background: color-mix(in srgb, var(--bad) 4%, transparent); }
.race-list-item.has-error:hover { background: color-mix(in srgb, var(--bad) 7%, transparent); }
.race-list-item[hidden] { display: none; }

.race-list-main {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 8px;
  text-decoration: none;
  color: inherit;
}
.race-list-main:hover { text-decoration: none; }

.race-status-dot {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-muted);
}
.race-status-dot-active { background: var(--good); }
.race-status-dot-dormant { background: var(--warn); }
.race-status-dot-archived { background: var(--border-strong); }
.race-status-dot-completed { background: var(--text-muted); }
.race-status-dot.has-error { background: var(--bad); }

.race-list-content {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.race-list-title {
  font: 600 14.5px/1.3 inherit;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.race-list-meta {
  font-size: 12.5px;
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  line-height: 1.4;
}
.race-list-meta > span:not(.dot-sep):not(.race-list-prefixes) {
  white-space: nowrap;
}
.dot-sep {
  display: inline-block;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--border-strong);
  flex-shrink: 0;
}
.race-list-prefixes {
  display: inline-flex;
  gap: 3px;
}
.prefix-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 18px;
  padding: 0 5px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  font: 600 10.5px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--text);
  letter-spacing: 0.04em;
}

.race-list-status {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.race-status {
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  font: 600 10.5px/1.4 inherit;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-radius: 999px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.race-status-active {
  background: color-mix(in srgb, var(--good) 14%, transparent);
  border-color: color-mix(in srgb, var(--good) 45%, var(--border));
  color: var(--good);
}
.race-status-dormant {
  background: color-mix(in srgb, var(--warn) 14%, transparent);
  border-color: color-mix(in srgb, var(--warn) 40%, var(--border));
  color: var(--warn);
}
.race-status-archived {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text-muted);
}
.race-status-completed {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text-muted);
}
.race-status-fejl {
  background: color-mix(in srgb, var(--bad) 14%, transparent);
  border-color: color-mix(in srgb, var(--bad) 45%, var(--border));
  color: var(--bad);
}

.race-list-time {
  flex: 0 0 auto;
  width: 170px;
  text-align: right;
  font-size: 12px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.race-list-chevron {
  flex: 0 0 auto;
  color: var(--text-muted);
  opacity: 0.5;
  transition: transform 120ms ease, opacity 120ms ease;
}
.race-list-item:hover .race-list-chevron {
  opacity: 1;
  transform: translateX(2px);
}

/* Empty state */
.empty-state {
  text-align: center;
  padding: 60px 20px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: 10px;
}
.empty-state h2 {
  margin: 0 0 8px 0;
  font: 600 18px/1.2 inherit;
}
.empty-state p { margin: 0 0 16px 0; }

/* page-head can have an `<div>` wrapper, not just .page-head-main — make
   both work. */
.page-head > div { flex: 1 1 0; min-width: 0; }

/* Responsive — collapse race-list rows on narrow screens. */
@media (max-width: 720px) {
  .race-list-time { display: none; }
  .race-list-main { gap: 10px; padding: 12px 6px; }
  .race-list-status { font-size: 11px; }
  .list-toolbar { gap: 8px; }
  .filter-chips { gap: 4px; }
  .chip { padding: 5px 10px; font-size: 12px; }
}

@media (max-width: 540px) {
  .race-list-meta { gap: 4px; }
  .race-list-title { font-size: 14px; }
  .race-list-status { display: none; }
  .race-list-main { gap: 8px; }
  .race-status-dot { width: 6px; height: 6px; }
}

/* ===========================================================================
   Source items v3 — all fields ALWAYS visible (no ⚙ fold).
   Each source has two rows: source-head (prefix + url + actions) and
   source-config-row (preset + type-navn + korttekst + tæller + rk).
   =========================================================================== */

.source-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 4px 4px 4px;
}
.source-head .source-info { flex: 1 1 0; min-width: 0; }
.source-head-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
}

.source-config-row {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  padding: 4px 4px 14px 56px; /* indent under the prefix-badge */
  margin: 0;
  flex-wrap: wrap;
}
.source-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  min-width: 0;
}
.source-field-label {
  font: 600 10.5px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.source-field input,
.source-field select {
  min-height: 34px;
  padding: 6px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.source-field input:focus,
.source-field select:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
/* Default widths for the fields */
.source-field select { min-width: 130px; }
.source-field input { width: 100%; min-width: 100px; }
.source-field-grow { flex: 1 1 180px; min-width: 140px; }
.source-field-tight { flex: 0 0 70px; }
.source-field-tight input { min-width: 0; }

/* Add-source slot uses the same source-head + source-config-row layout. */
.source-item-add { background: color-mix(in srgb, var(--accent) 2%, transparent); }
.source-item-add .source-info input.source-add-url {
  width: 100%;
  min-height: 36px;
  padding: 8px 12px;
  font-size: 13.5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.source-item-add .source-info input.source-add-url:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.btn-add-source { white-space: nowrap; }

@media (max-width: 720px) {
  .source-config-row {
    padding-left: 4px;
    gap: 8px;
  }
  .source-field { flex: 1 1 calc(50% - 8px); }
  .source-field-tight { flex: 0 0 70px; }
  .source-field-grow { flex: 1 1 100%; }
}

/* ===========================================================================
   Vola-link create form — same "all visible" pattern. Each link has a wide
   URL field at top, then a row of 4 fields (Preset / Type-navn / Korttekst /
   Tæller) plus a remove icon.
   =========================================================================== */

.vola-link-rows {
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: 8px;
}
.vola-link-row {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px;
  background: color-mix(in srgb, var(--surface-2) 40%, transparent);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.vola-link-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  min-width: 0;
}
.vola-link-field-label {
  font: 600 10.5px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.vola-link-field input,
.vola-link-field select {
  min-height: 36px;
  padding: 8px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
  width: 100%;
}
.vola-link-field input:focus,
.vola-link-field select:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.vola-link-field-url { flex: 1 1 100%; }

.vola-link-config {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}
.vola-link-config .vola-link-field-preset { flex: 0 0 150px; }
.vola-link-config .vola-link-field-name { flex: 1 1 160px; }
.vola-link-config .vola-link-field-prefix { flex: 0 0 80px; }
.vola-link-config .vola-link-field-counts { flex: 0 0 110px; }
.vola-link-config .row-remove { flex: 0 0 auto; align-self: center; margin-top: 18px; }

@media (max-width: 720px) {
  .vola-link-config { gap: 8px; }
  .vola-link-config .vola-link-field-preset { flex: 1 1 calc(50% - 4px); }
  .vola-link-config .vola-link-field-name { flex: 1 1 100%; }
  .vola-link-config .vola-link-field-prefix { flex: 1 1 calc(50% - 4px); }
  .vola-link-config .vola-link-field-counts { flex: 1 1 calc(50% - 4px); }
}

/* ---------- Source-item: two-row layout (head + always-visible fields) -- */

.source-head {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 14px 4px 8px 4px;
}
.source-head .source-info { padding-top: 2px; }
.source-head-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
}

/* The always-visible field row below the source URL/health.
   Replaces the old gear-toggled advanced fold. */
.source-config-row {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  padding: 0 4px 14px 54px;  /* indent so fields align under URL, not prefix */
  margin: 0;
  flex-wrap: wrap;
}
.source-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  min-width: 0;
}
.source-field-label {
  font: 600 10.5px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.source-field input,
.source-field select {
  min-height: 34px;
  padding: 6px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  width: 100%;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.source-field input:focus,
.source-field select:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.source-field select { min-width: 130px; }
.source-field-grow { flex: 1 1 200px; }
.source-field-tight { flex: 0 0 70px; }
.source-field-tight input { text-align: center; font-variant-numeric: tabular-nums; }

@media (max-width: 720px) {
  .source-config-row {
    padding-left: 4px;
    gap: 8px;
  }
  .source-field { flex: 1 1 calc(50% - 4px); }
  .source-field-grow { flex: 1 1 100%; }
  .source-field-tight { flex: 0 0 calc(50% - 4px); }
}

/* ---------- Create page: Vola-link rows with all fields visible -------- */

.vola-link-rows {
  display: flex;
  flex-direction: column;
  gap: 20px;
  margin-top: 4px;
}
.vola-link-row {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "url     remove"
    "config  config";
  gap: 10px;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.vola-link-row:hover { border-color: var(--border-strong); }

.vola-link-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  min-width: 0;
}
.vola-link-field-label {
  font: 600 10.5px/1 inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.vola-link-field input,
.vola-link-field select {
  min-height: 36px;
  padding: 8px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  width: 100%;
  /* Override legacy .url-row-url flex-basis that would otherwise stretch
     the input vertically inside the column-flex .vola-link-field parent. */
  flex: 0 0 auto;
  height: auto;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.vola-link-field input:focus,
.vola-link-field select:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

.vola-link-field-url { grid-area: url; }
.vola-link-config {
  grid-area: config;
  display: grid;
  grid-template-columns: minmax(140px, 1fr) minmax(160px, 1.5fr) minmax(70px, 90px) minmax(110px, 1fr);
  gap: 10px;
  align-items: flex-end;
}
.vola-link-field-prefix input { text-align: center; font-variant-numeric: tabular-nums; }

.vola-link-row .row-remove {
  grid-area: remove;
  align-self: flex-end;
  margin-bottom: 0;
}

@media (max-width: 720px) {
  .vola-link-config {
    grid-template-columns: 1fr 1fr;
  }
  .vola-link-row {
    grid-template-areas:
      "url url"
      "config config"
      "remove remove";
  }
}

/* The "Add source" row at the bottom of the source-list keeps its single
   inline-form layout — restore those styles since the new EJS reuses them. */
.source-item-add { border-bottom: 0; }
.source-item-add:hover { background: transparent; }
.source-add-form {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 4px;
  margin: 0;
}
.source-add-url {
  flex: 1 1 280px;
  min-width: 200px;
  min-height: 36px;
  padding: 8px 12px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.source-add-url:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.source-add-preset {
  flex: 0 0 160px;
  min-height: 36px;
  padding: 8px 10px;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.btn-add-source { white-space: nowrap; }
.source-prefix-add {
  background: transparent;
  border-style: dashed;
  color: var(--text-muted);
  font-size: 18px;
  font-weight: 400;
}

/* =============================================================================
 * Install nudge — Layer 1 hairline strip + Layer 2 modal-sheet body.
 * Modal chrome reuses .tag-picker classes (backdrop, head, foot, etc.) so
 * keyboard focus, esc-close, and z-index behave identically across all sheets.
 * Newspaper aesthetic: hard edges, hairline rules, no drop-shadows.
 * ===========================================================================*/
.install-strip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  font-size: 13px;
  line-height: 1.3;
  color: var(--text);
}
.install-strip-icon {
  display: inline-flex;
  align-items: center;
  color: var(--text-muted);
  flex: 0 0 auto;
}
.install-strip-icon .icon-install {
  width: 16px;
  height: 16px;
}
.install-strip-text {
  flex: 1 1 auto;
  min-width: 0;
}
.install-strip-cta {
  flex: 0 0 auto;
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
  padding: 4px 10px;
  font: 600 12px/1.2 inherit;
  cursor: pointer;
  /* Sharp edges per project style — no border-radius. */
}
.install-strip-cta:hover {
  background: var(--accent);
  color: var(--accent-on);
}
.install-strip-close {
  flex: 0 0 auto;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font: 400 18px/1 inherit;
  width: 28px;
  height: 28px;
  cursor: pointer;
  padding: 0;
}
.install-strip-close:hover { color: var(--text); }

/* Install-sheet body — sits inside .tag-picker chrome */
.install-sheet-body {
  padding: 4px 0 8px;
}
.install-sheet-lead {
  margin: 0 0 14px;
  font-size: 14px;
  color: var(--text);
  line-height: 1.45;
}
.install-sheet-android {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.4;
}

/* iOS step list — three numbered steps with the share-icon glyph inline */
.install-ios-steps {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
}
.install-ios-steps li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
}
.install-ios-steps li:last-child { border-bottom: none; }
.install-step-num {
  flex: 0 0 22px;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font: 700 12px/1 var(--mono, "JetBrains Mono", "Menlo", monospace);
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--border);
  color: var(--text-muted);
  /* Hairline square — no border-radius */
}
.install-step-text {
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.4;
}
.install-step-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  color: var(--accent);
}
.install-step-icon .icon-ios-share {
  width: 18px;
  height: 22px;
}

/* "Spørg ikke igen" link styled subdued — destructive but quiet */
.install-sheet-foot .install-sheet-never {
  color: var(--text-muted);
  opacity: 0.75;
}
.install-sheet-foot .install-sheet-never:hover {
  color: var(--bad);
  opacity: 1;
}

/* Settings sheet — "Andet" tab Install-app + Test-notification rows */
.settings-row.install-row .settings-row-text { color: var(--text); }
.settings-row.install-row .settings-action[disabled] {
  opacity: 0.5;
  cursor: default;
}
