/* Performance Dashboard v2 — quiet, editorial, Apple-adjacent.
   Typography: Inter (self-served via Google Fonts), falls back to San Francisco
   on this Mac if offline. One accent hue, used sparingly; structure carried by
   type scale and whitespace, not boxes. */

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600&display=swap');

:root {
  color-scheme: light;
  --bg: #fbfbfd;
  --bg-raised: #ffffff;
  --ink: #1d1d1f;
  --ink-soft: #6e6e73;
  --ink-faint: #a1a1a6;
  --hairline: #d2d2d7;
  --hairline-soft: #e8e8ed;

  --accent: #2f6fd1;     /* distance / primary volume */
  --accent-soft: rgba(47, 111, 209, 0.10);
  --amber: #b8873f;      /* elevation / climbing */
  --amber-soft: rgba(184, 135, 63, 0.12);
  --sage: #4f8a6e;       /* recovery */
  --coral: #c9553f;      /* cutoff risk / attention */
  --coral-soft: rgba(201, 85, 63, 0.10);

  --shadow-1: 0 1px 2px rgba(0,0,0,.04), 0 8px 24px rgba(0,0,0,.04);
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --bg: #000000;
    --bg-raised: #1d1d1f;
    --ink: #f5f5f7;
    --ink-soft: #a1a1a6;
    --ink-faint: #6e6e73;
    --hairline: #38383a;
    --hairline-soft: #2c2c2e;

    --accent: #4a90ff;
    --accent-soft: rgba(74, 144, 255, 0.14);
    --amber: #d9a35c;
    --amber-soft: rgba(217, 163, 92, 0.14);
    --sage: #6bab8a;
    --coral: #e2725c;
    --coral-soft: rgba(226, 114, 92, 0.14);
    --shadow-1: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.3);
  }
}

* { box-sizing: border-box; }
::selection { background: var(--accent-soft); }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", system-ui, sans-serif;
  font-weight: 300;
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  transition: background .3s ease, color .3s ease;
}

.shell { max-width: 980px; margin: 0 auto; padding: 0 28px 100px; }
.shell-wide { max-width: 1180px; margin: 0 auto; padding: 0 28px 100px; }

/* ---- Nav: thin, translucent, sticky — two rows: macro category, then its pages ---- */
.topnav {
  position: sticky; top: 0; z-index: 40;
  padding: 12px 28px 10px;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: saturate(180%) blur(16px);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid var(--hairline-soft);
}
/* Row1 uses a 3-column grid (brand | nav | spacer) so the nav buttons sit
   genuinely centered on the row regardless of the brand text's width, rather
   than merely centered in the space left over after it. */
.topnav-row1 { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; }
.topnav .brand {
  font-weight: 500; font-size: 14px; letter-spacing: -0.005em;
  white-space: nowrap; color: var(--ink); justify-self: start;
}
.topnav a {
  color: var(--ink-soft); text-decoration: none; font-size: 13.5px; font-weight: 400;
  padding: 7px 13px; border-radius: 100px; transition: color .2s ease, background .2s ease;
  letter-spacing: -0.005em; white-space: nowrap;
}
.topnav a:hover { color: var(--ink); }
.topnav a.active { color: var(--ink); background: var(--hairline-soft); font-weight: 500; }
.nav-groups { display: flex; gap: 4px; justify-self: center; }
.nav-groups a { font-size: 12.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }
.nav-groups a.active { background: var(--accent-soft); color: var(--accent); }
@media (max-width: 640px) {
  .topnav { padding: 10px 16px 8px; }
  .topnav .brand { display: none; }
  .topnav-row1 { grid-template-columns: 1fr; }
}

/* ---- Race-day countdown banner: the site's new focal point, meant to be
   seen immediately — big tabular-nums digits, high-contrast coral panel. ---- */
.countdown-banner {
  margin: 24px 0 8px; padding: 22px 28px; border-radius: 20px; color: #fff;
  background: linear-gradient(135deg, var(--coral), color-mix(in srgb, var(--coral) 60%, var(--ink) 40%));
  box-shadow: var(--shadow-1);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 18px;
}
.countdown-banner .cd-label { font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; opacity: .85; }
.countdown-banner .cd-sub { font-size: 13px; opacity: .85; margin-top: 3px; }
.countdown-banner .cd-digits { display: flex; gap: 22px; }
.countdown-banner .cd-group { text-align: center; }
.countdown-banner .cd-value {
  font-size: 42px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -0.02em;
}
.countdown-banner .cd-unit { font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; opacity: .8; margin-top: 5px; }
@media (max-width: 640px) {
  .countdown-banner { padding: 18px 20px; flex-direction: column; align-items: flex-start; margin-top: 16px; }
  .countdown-banner .cd-digits { gap: 14px; }
  .countdown-banner .cd-value { font-size: 32px; }
}

/* ---- Fanzones: a spectator card per checkpoint ---- */
.fanzone-card {
  background: var(--bg-raised); border: 1px solid var(--hairline-soft); border-radius: 16px;
  padding: 22px 24px; box-shadow: var(--shadow-1); margin-bottom: 16px;
}
.fanzone-card:last-child { margin-bottom: 0; }
.fanzone-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.fanzone-name { font-size: 19px; font-weight: 500; color: var(--ink); }
.fanzone-km { font-size: 13px; color: var(--ink-soft); font-variant-numeric: tabular-nums; white-space: nowrap; }
.fanzone-row { display: flex; gap: 12px; align-items: flex-start; margin-top: 12px; flex-wrap: wrap; }
.fanzone-row .row-label {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-faint); min-width: 100px; padding-top: 2px; flex: none;
}
.fanzone-eta { font-size: 14.5px; color: var(--ink); font-variant-numeric: tabular-nums; font-weight: 500; }
.fanzone-eta .sub { display: block; font-size: 12.5px; color: var(--ink-soft); font-weight: 400; margin-top: 2px; }
/* Deliberately loud — a placeholder that's easy to skim past would defeat the
   point of marking it as one; this is meant to be filled in before race day. */
.fanzone-access {
  border: 1.5px dashed var(--amber); background: var(--amber-soft); color: var(--amber);
  border-radius: 10px; padding: 8px 12px; font-size: 13px; font-weight: 500; flex: 1; min-width: 200px;
}
@media (max-width: 640px) {
  .fanzone-card { padding: 18px 18px; }
  .fanzone-row .row-label { min-width: 100%; margin-bottom: -2px; }
}

/* ---- Type scale ---- */
h1 {
  font-size: clamp(32px, 5vw, 48px); font-weight: 200; letter-spacing: -0.02em;
  margin: 56px 0 8px; color: var(--ink); line-height: 1.08;
}
h2 {
  font-size: 24px; font-weight: 300; letter-spacing: -0.015em; margin: 0 0 4px; color: var(--ink);
}
h3 { font-size: 15px; font-weight: 500; margin: 0 0 4px; color: var(--ink); }
.eyebrow {
  font-size: 11.5px; font-weight: 500; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-faint); margin: 0 0 10px;
}
.page-sub { color: var(--ink-soft); font-weight: 300; margin: 0 0 40px; font-size: 17px; max-width: 640px; }
.section { margin-bottom: 64px; }
.section-head { margin-bottom: 22px; }
.section-note { color: var(--ink-faint); font-size: 12.5px; margin-top: 8px; font-weight: 300; }
p { font-weight: 300; }
b, strong { font-weight: 500; }

/* ---- Reveal-on-scroll ---- */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity .7s cubic-bezier(.16,1,.3,1), transform .7s cubic-bezier(.16,1,.3,1); }
.reveal.in { opacity: 1; transform: translateY(0); }
.reveal-d1.in { transition-delay: .08s; }
.reveal-d2.in { transition-delay: .16s; }
.reveal-d3.in { transition-delay: .24s; }

/* ---- Hero stat row: no boxes, just numbers + hairline dividers ---- */
.hero-stats { display: flex; flex-wrap: wrap; gap: 0; margin: 0 -20px; }
.hero-stat {
  flex: 1 1 150px; padding: 0 20px; border-left: 1px solid var(--hairline-soft);
}
.hero-stat:first-child { border-left: none; }
.hero-stat .label { font-size: 11.5px; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .07em; font-weight: 500; }
.hero-stat .value {
  font-size: clamp(28px, 3.4vw, 40px); font-weight: 200; letter-spacing: -0.02em;
  margin-top: 6px; font-variant-numeric: tabular-nums; color: var(--ink);
}
.hero-stat .sub { font-size: 12.5px; color: var(--ink-soft); margin-top: 3px; font-weight: 300; }

/* ---- Plain panel (used sparingly — charts, tables) ---- */
.panel { padding: 26px 0 4px; }
.panel-boxed {
  background: var(--bg-raised); border-radius: 18px; padding: 28px 30px;
  box-shadow: var(--shadow-1); border: 1px solid var(--hairline-soft);
}

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; }
@media (max-width: 860px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .hero-stat { flex: 1 1 46%; border-left: none; border-top: 1px solid var(--hairline-soft); padding: 16px 0 0; }
  .hero-stats { margin: 0; gap: 20px 24px; }
  .map-shell { height: 420px; }
}

/* ---- Disclosure: native <details>, styled quiet ---- */
details.dig {
  margin-top: 8px; border-top: 1px solid var(--hairline-soft); padding-top: 0;
}
details.dig summary {
  list-style: none; cursor: pointer; padding: 18px 0; display: flex; align-items: center; gap: 8px;
  font-size: 14px; color: var(--ink-soft); font-weight: 400; user-select: none;
  transition: color .2s ease;
}
details.dig summary::-webkit-details-marker { display: none; }
details.dig summary:hover { color: var(--ink); }
details.dig summary::before {
  content: '›'; display: inline-block; font-size: 18px; font-weight: 400; color: var(--ink-faint);
  transition: transform .3s cubic-bezier(.16,1,.3,1); transform: rotate(0deg); width: 12px;
}
details.dig[open] summary::before { transform: rotate(90deg); }
details.dig .dig-body { padding-bottom: 28px; animation: fadeIn .4s ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(-4px);} to { opacity: 1; transform: translateY(0);} }

/* ---- Tables — quiet, no borders except hairline rows ---- */
table { width: 100%; border-collapse: collapse; font-size: 13.5px; font-weight: 300; }
thead th {
  text-align: left; color: var(--ink-faint); font-weight: 500; font-size: 11px;
  text-transform: uppercase; letter-spacing: .05em; padding: 0 12px 10px; border-bottom: 1px solid var(--hairline);
}
tbody td { padding: 11px 12px; border-bottom: 1px solid var(--hairline-soft); font-variant-numeric: tabular-nums; color: var(--ink); }
tbody tr { transition: background .15s ease; }
tbody tr:hover { background: var(--hairline-soft); }
.table-wrap { overflow-x: auto; }

/* ---- Charts ---- */
.viz-root { position: relative; }
.viz-svg { display: block; overflow: visible; }
.viz-baseline { stroke: var(--hairline); stroke-width: 1; }
.viz-grid-line { stroke: var(--hairline-soft); stroke-width: 1; }
.viz-tick { fill: var(--ink-faint); font-size: 11px; font-weight: 400; font-family: inherit; }
.viz-line { stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.viz-bar { }
.viz-hover-line { stroke: var(--ink-faint); stroke-width: 1; stroke-dasharray: 2 3; }
.viz-hover-dot { stroke: var(--bg-raised); stroke-width: 2; }
.viz-marker-dot { stroke: var(--bg-raised); stroke-width: 2; }
.viz-marker-label {
  font-size: 11px; font-weight: 700; font-family: inherit; fill: #fff;
}
.viz-legend { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 14px; }
.viz-legend-item { font-size: 12.5px; color: var(--ink-soft); display: inline-flex; align-items: center; gap: 6px; font-weight: 400; }
.viz-legend-swatch { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.viz-empty { color: var(--ink-faint); font-size: 13px; padding: 40px 0; text-align: center; }

.viz-tooltip {
  position: fixed; display: none; background: var(--bg-raised);
  border: 1px solid var(--hairline-soft); border-radius: 10px; padding: 9px 12px;
  font-size: 12.5px; pointer-events: none; box-shadow: var(--shadow-1); z-index: 50; max-width: 220px;
  backdrop-filter: blur(8px);
}
/* Alternative to .viz-tooltip for charts passing tooltipBar: true — a static
   one-line readout above the graph instead of a box that floats over the
   data (and, on touch, over the finger reading it). Same head/value/extra
   markup as the floating tooltip; flex just lines it up horizontally.
   overflow-x lets it scroll rather than wrap or clip on the narrowest
   phones if the content is ever too wide for one line. */
.viz-tt-bar {
  display: flex; align-items: center; gap: 6px; margin-bottom: 8px;
  background: var(--bg-raised); border: 1px solid var(--hairline-soft); border-radius: 10px;
  padding: 8px 10px; font-size: 12px; min-height: 32px; box-sizing: border-box;
  overflow-x: auto; scrollbar-width: none;
  /* Without its own line-height this inherits body's 1.55, which needs more
     vertical room than the 16px of top+bottom padding leaves before the box
     grows past min-height the instant hover/touch fills it with text. 1.2
     keeps a line comfortably within that padding-free space instead. */
  line-height: 1.2;
}
.viz-tt-bar::-webkit-scrollbar { display: none; }
/* Normalise the three pieces (head/value/extra rows) to one consistent size
   and weight — they're borrowed from .viz-tooltip, where each had its own
   distinct styling for a stacked layout (small caption, then a big number,
   then detail rows). Side by side on one line that mix of sizes just looked
   inconsistent, so this flattens them to a single, even look with a plain
   "·" separator between segments instead of relying on visual hierarchy. */
.viz-tt-bar .viz-tt-head, .viz-tt-bar .viz-tt-value, .viz-tt-bar .viz-tt-row {
  flex: none; white-space: nowrap; margin: 0;
  font-size: 10.5px; font-weight: 400; color: var(--ink);
  text-transform: none; letter-spacing: normal;
}
.viz-tt-bar > *:not(:first-child)::before {
  content: "·"; margin-right: 6px; color: var(--ink-faint);
}
.viz-tt-head { font-weight: 500; margin-bottom: 3px; color: var(--ink-faint); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
.viz-tt-value { font-weight: 500; color: var(--ink); font-size: 15px; font-variant-numeric: tabular-nums; }
.viz-tt-row { display: flex; align-items: center; gap: 6px; color: var(--ink); font-weight: 400; }
.viz-tt-swatch { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }

/* ---- Segmented control (period selector) ---- */
.segmented {
  display: inline-flex; background: var(--hairline-soft); border-radius: 100px; padding: 3px; gap: 2px;
}
.segmented button {
  border: none; background: transparent; color: var(--ink-soft); font-family: inherit;
  font-size: 12.5px; font-weight: 400; padding: 7px 14px; border-radius: 100px; cursor: pointer;
  transition: all .25s cubic-bezier(.16,1,.3,1);
}
.segmented button.active { background: var(--bg-raised); color: var(--ink); font-weight: 500; box-shadow: 0 1px 3px rgba(0,0,0,.08); }
.segmented button:hover:not(.active) { color: var(--ink); }

/* ---- Sport-type filter (multi-select chips) ---- */
.sport-filter { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 24px; }
.sport-filter button {
  border: 1px solid var(--hairline); background: transparent; color: var(--ink-soft);
  font-family: inherit; font-size: 12.5px; font-weight: 400; padding: 6px 14px;
  border-radius: 100px; cursor: pointer; transition: all .2s cubic-bezier(.16,1,.3,1);
}
.sport-filter button:hover { color: var(--ink); border-color: var(--ink-faint); }
.sport-filter button.active {
  background: var(--accent-soft); border-color: transparent; color: var(--accent); font-weight: 500;
}

/* ---- Checkpoint timeline (TUX070 page) ---- */
.timeline { position: relative; padding-left: 2px; }
.timeline::before {
  content: ''; position: absolute; left: 7px; top: 10px; bottom: 10px; width: 1px; background: var(--hairline);
}
.tl-item { position: relative; padding: 0 0 34px 32px; }
.tl-item:last-child { padding-bottom: 0; }
/* A discreet divider between stations' content blocks — offset past the dot/
   spine column (left: 32px) so the continuous vertical timeline line isn't
   visually cut by it, and vertically centered in the existing 34px gap
   rather than adding extra space of its own. */
.tl-item:not(:last-child)::after {
  content: ''; position: absolute; left: 32px; right: 0; bottom: 17px;
  height: 1px; background: var(--hairline-soft);
}
.tl-dot {
  position: absolute; left: 0; top: 3px; width: 15px; height: 15px; border-radius: 50%;
  background: var(--bg-raised); border: 2px solid var(--accent);
}
.tl-name-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tl-name { font-size: 16px; font-weight: 500; color: var(--ink); }
.tl-meta { font-size: 13px; color: var(--ink-soft); margin-top: 3px; display: flex; gap: 18px; flex-wrap: wrap; }
.tl-meta span b { color: var(--ink); font-weight: 500; font-variant-numeric: tabular-nums; }

/* ---- Aid Stations: no-gels banner ---- */
.tl-no-gels-note {
  font-size: 12.5px; color: var(--amber); background: var(--amber-soft);
  border-radius: 10px; padding: 8px 14px; margin: 0 0 16px; display: inline-block;
}

/* ---- Aid Stations: quick-jump rail + per-card stat grid. Kept deliberately
   simple (plain horizontal scroll, native #anchor + the site-wide
   `scroll-behavior:smooth` already on <html>) rather than a hand-rolled
   scroll-snap/JS-driven widget — fewer moving parts to break on an iPhone
   on race day. ---- */
.aid-rail-wrap { overflow-x: auto; margin: 0 0 4px; padding: 2px 2px 10px; -webkit-overflow-scrolling: touch; }
.aid-rail { display: flex; gap: 8px; width: max-content; }
.aid-chip {
  flex: none; display: flex; flex-direction: column; gap: 3px;
  padding: 10px 16px; border-radius: 14px; text-decoration: none;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  transition: border-color .2s ease, background .2s ease;
}
.aid-chip:hover, .aid-chip:focus-visible { border-color: var(--accent); }
.aid-chip-name { font-size: 12.5px; font-weight: 500; color: var(--ink); white-space: nowrap; }
.aid-chip-meta { font-size: 11px; color: var(--ink-soft); white-space: nowrap; font-variant-numeric: tabular-nums; }
.aid-chip-meta .cutoff { color: var(--amber); }

.tl-stats { display: flex; gap: 22px; flex-wrap: wrap; margin-top: 10px; }
.tl-stat { display: flex; flex-direction: column; gap: 2px; min-width: 64px; }
.tl-stat-label { font-size: 10px; font-weight: 500; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint); }
.tl-stat-value { font-size: 14.5px; font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums; }

/* ---- Aid Stations: food/drinks tags folded into each checkpoint's own
   .tl-item — tag chips instead of a comma-separated sentence, so the whole
   spread at every station is scannable at a glance without opening
   anything. The baseline every station stocks is stated once above the
   list (see #common-supplies-note) rather than repeated per station. ---- */
.aid-supply-group { margin-top: 12px; }
.aid-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.aid-tag {
  font-size: 12px; font-weight: 400; color: var(--ink-soft);
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  border-radius: 100px; padding: 4px 12px;
}
.aid-tag.drink { color: var(--accent); border-color: var(--accent-soft); background: var(--accent-soft); }
.aid-tag-note { font-size: 12.5px; color: var(--ink-faint); font-style: italic; }
.aid-tag-note.aid-tag-warn { color: var(--amber); font-style: normal; }

@media (max-width: 640px) {
  .tl-stats { gap: 16px 22px; }
}

/* ---- Compare page ---- */
.compare-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 12px; padding: 14px 0; border-bottom: 1px solid var(--hairline-soft); }
.compare-row .metric { grid-column: 1 / -1; color: var(--ink-faint); font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; margin-bottom: 4px; font-weight: 500; }
.compare-val { font-size: 22px; font-weight: 300; font-variant-numeric: tabular-nums; color: var(--ink); }
.compare-delta { font-size: 12px; text-align: center; min-width: 66px; font-weight: 500; font-variant-numeric: tabular-nums; }
.delta-up { color: var(--sage); }
.delta-down { color: var(--coral); }

/* ---- Rutekort (3D terrain map) ---- */
.map-shell {
  position: relative; height: 560px; border-radius: 18px; overflow: hidden;
  border: 1px solid var(--hairline-soft); box-shadow: var(--shadow-1); background: var(--bg-raised);
}
.map-shell #map { position: absolute; inset: 0; }
/* Mapbox GL renders through a hardware-accelerated <canvas>, which .map-
   shell's own border-radius + overflow:hidden doesn't reliably clip at the
   corners — the canvas's own (near-black) background shows through as a
   sharp wedge right at the curve instead of following it. Rounding the
   canvas itself (and its wrapper) clips the actual rendered pixels directly,
   rather than depending on the parent's compositing to catch it. */
.map-shell .mapboxgl-map, .map-shell .mapboxgl-canvas { border-radius: 18px; }
.map-controls {
  position: absolute; top: 16px; left: 16px; z-index: 5;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.map-controls .segmented {
  background: color-mix(in srgb, var(--bg-raised) 88%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); box-shadow: var(--shadow-1);
}
/* Play/pause for "fly the route" — sits in the scrub bar itself, video-
   player style, rather than a separate labeled button elsewhere on the map. */
.map-play-btn {
  flex: none; width: 28px; height: 28px; border: none; border-radius: 50%; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  /* No padding nudge needed — the play triangle path (tux070.html's
     FLY_PLAY_ICON, M6.5 5v14l11-7z) is itself corrected to sit centered in
     its 24x24 viewBox (was M8 5v14l11-7z: bounding box x8-19, center 13.5,
     1.5 units right of the viewBox's own center at 12 — a real, measurable
     offset the old padding-left hack was compounding rather than fixing). */
  color: #fff; background: var(--accent); box-shadow: var(--shadow-1); transition: opacity .2s ease, background .2s ease;
}
.map-play-btn:hover { opacity: .85; }
.map-play-btn.flying { background: var(--coral); }

.map-cp-marker {
  font-size: 11.5px; font-weight: 500; color: var(--ink);
  background: color-mix(in srgb, var(--bg-raised) 92%, transparent);
  padding: 4px 10px; border-radius: 100px; white-space: nowrap;
  box-shadow: var(--shadow-1); border: 1px solid var(--hairline-soft); pointer-events: none;
}
.map-cp-dot {
  width: 12px; height: 12px; border-radius: 50%; box-sizing: border-box;
  background: var(--accent); border: 2px solid var(--bg-raised); box-shadow: var(--shadow-1);
}
.live-ping-label {
  display: flex; align-items: center; gap: 6px; cursor: pointer;
  padding: 4px 10px 4px 4px; border-radius: 100px; white-space: nowrap;
  background: color-mix(in srgb, var(--bg-raised) 92%, transparent);
  box-shadow: var(--shadow-1); border: 1px solid var(--hairline-soft);
}
.live-ping-label .map-runner-pace { font-size: 11.5px; }

.map-fs-btn {
  position: absolute; top: 16px; right: 16px; z-index: 6;
  width: 34px; height: 34px; border: none; border-radius: 10px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink);
  background: color-mix(in srgb, var(--bg-raised) 88%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); box-shadow: var(--shadow-1);
}
.map-fs-btn:hover { opacity: .85; }

.map-runner-chip {
  display: flex; align-items: center; gap: 8px; border: none; cursor: pointer;
  padding: 6px 12px 6px 6px; border-radius: 100px; font-family: inherit;
  background: color-mix(in srgb, var(--bg-raised) 88%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--shadow-1); border: 1px solid var(--hairline-soft);
  overflow: hidden; transition: box-shadow .2s ease, background .2s ease;
}
/* Active state is a background tint, not a border/ring — a border or
   box-shadow outline on a backdrop-filter + border-radius element doesn't
   always clip evenly at the curve (shows as a harder edge right at the
   corner instead of blending). A background tint has no edge to clip. */
.map-runner-chip.active { background: rgba(62, 207, 126, 0.22); }
.map-runner-avatar {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--sage); color: #fff; font-size: 11px; font-weight: 600;
}
.map-runner-pace { font-size: 12px; font-weight: 500; color: var(--ink); white-space: nowrap; }

/* ---- Fullscreen: only the map and the runner selector
   stay — everything else is the "clean view" the button is for.
   This is a JS-driven class, not the native Fullscreen API (:fullscreen) —
   iOS Safari doesn't support requestFullscreen() on arbitrary elements (only
   <video>), so a button built on it silently does nothing there. A
   position:fixed overlay covering the viewport works identically on every
   browser instead, at the cost of not hiding the browser's own chrome —
   an acceptable trade next to a button that simply doesn't work at all. */
.map-shell.is-fullscreen {
  position: fixed; inset: 0; z-index: 1000;
  width: 100vw; height: 100vh; height: 100dvh; max-width: none; border-radius: 0;
}
.map-shell.is-fullscreen .mapboxgl-map, .map-shell.is-fullscreen .mapboxgl-canvas { border-radius: 0; }
/* Fullscreen: controls start visible, fade out after a few seconds of no
   mouse/touch activity, and reappear on the next move or tap — video-player
   style, so a fullscreen flyover or fullscreen live view stays clean without
   ever making the controls unreachable. */
.map-shell.is-fullscreen .map-controls,
.map-shell.is-fullscreen .map-scrub-bar,
.map-shell.is-fullscreen .map-fs-btn {
  opacity: 1; transition: opacity .4s ease;
}
.map-shell.is-fullscreen.controls-idle .map-controls,
.map-shell.is-fullscreen.controls-idle .map-scrub-bar,
.map-shell.is-fullscreen.controls-idle .map-fs-btn {
  opacity: 0; pointer-events: none;
}
/* The runner panel is exempt from the auto-hide-on-idle behaviour above —
   it stays put in fullscreen (never fades away on its own) and is instead
   shown/hidden explicitly via its own expand/collapse arrow. */

/* ---- Timeline scrubber, overlaid on the map itself (video-player style) ---- */
.map-scrub-bar {
  position: absolute; left: 16px; right: 16px; bottom: 46px; z-index: 5;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 16px; border-radius: 100px;
  background: color-mix(in srgb, var(--bg-raised) 88%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--shadow-1);
}
.map-scrub-bar .fly-value { min-width: auto; white-space: nowrap; }

.fly-value {
  font-size: 12.5px; color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; min-width: 52px;
}
.fly-range {
  flex: 1; appearance: none; -webkit-appearance: none; height: 4px; border-radius: 100px;
  background: var(--hairline-soft); outline: none; cursor: pointer; margin: 0;
}
.fly-range::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%;
  background: var(--accent); box-shadow: var(--shadow-1); cursor: pointer;
  border: 2px solid var(--bg-raised); margin-top: -1px;
}
.fly-range::-moz-range-thumb {
  width: 16px; height: 16px; border-radius: 50%; background: var(--accent);
  box-shadow: var(--shadow-1); cursor: pointer; border: 2px solid var(--bg-raised);
}

/* Mapbox's own chrome, restyled to sit quietly inside the same palette */
.mapboxgl-ctrl-group {
  background: var(--bg-raised) !important; box-shadow: var(--shadow-1) !important;
  border: 1px solid var(--hairline-soft);
}
.mapboxgl-ctrl-group button { background: transparent !important; }
.mapboxgl-ctrl-attrib { background: transparent !important; font-size: 10px !important; color: var(--ink-faint) !important; }
.mapboxgl-ctrl-attrib a { color: var(--ink-faint) !important; }
.mapboxgl-popup-content { background: var(--bg-raised) !important; color: var(--ink) !important; box-shadow: var(--shadow-1) !important; }
@media (prefers-color-scheme: dark) {
  .mapboxgl-ctrl-icon { filter: invert(1) brightness(1.6); }
}

/* ---- Følg mig live (TUX070 race-day tracking) ---- */
.livetrack-panel { margin-bottom: 24px; }
.livetrack-panel:last-child { margin-bottom: 0; }

/* ---- Methodology / footnote card ---- */
.method-note {
  font-size: 13px; color: var(--ink-soft); line-height: 1.65; font-weight: 300;
  border-left: 2px solid var(--hairline); padding-left: 18px; margin-top: 8px;
}

/* ---- Buttons / links (subtle) ---- */
.nav-card {
  display: block; text-decoration: none; color: inherit; padding: 24px 0;
  border-top: 1px solid var(--hairline-soft); transition: opacity .2s ease;
}
.nav-card:hover { opacity: .65; }
.nav-card .arrow { display: inline-block; transition: transform .25s cubic-bezier(.16,1,.3,1); }
.nav-card:hover .arrow { transform: translateX(4px); }

footer.page-footer {
  margin-top: 72px; padding-top: 22px; border-top: 1px solid var(--hairline-soft);
  color: var(--ink-faint); font-size: 12px; font-weight: 300; line-height: 1.7;
}
footer.page-footer ul { margin: 8px 0 0; padding-left: 16px; }

/* =========================================================================
   TUX070 dark "liquid glass" redesign — scoped to html.tux-app so the rest
   of the site (fitness/restitution/rutekort/sammenlign/træning/index) keeps
   its existing light/dark theme untouched. Visual reskin only: everything
   below reuses the same ids/classes the map, countdown and live-tracking
   scripts already read and write — no script was changed for this.
   ========================================================================= */
:root.tux-app {
  color-scheme: dark;
  --bg: #08090b;
  /* Never overridden before — every rule using --bg-raised (chart tooltip,
     mapbox popups/controls, chip backgrounds, range-slider thumbs, ...) was
     silently falling back to the light theme's white, e.g. white tooltip
     background behind text colored via the (correctly dark-themed) --ink,
     making it unreadable. */
  --bg-raised: #17181b;
  --ink: #f5f6f8;
  --ink-soft: #a6acb5;
  --ink-faint: #6c7278;
  --hairline: rgba(255,255,255,0.14);
  --hairline-soft: rgba(255,255,255,0.08);

  --accent: #2dd4c8;
  --accent-soft: rgba(45, 212, 200, 0.14);
  --amber: #e3a866;
  --amber-soft: rgba(227, 168, 102, 0.14);
  --sage: #3ecf7e;
  --coral: #e2725c;
  --coral-soft: rgba(226, 114, 92, 0.14);
  --shadow-1: 0 8px 32px rgba(0,0,0,.45);

  --glass-bg: rgba(255,255,255,0.045);
  --glass-bg-strong: rgba(255,255,255,0.08);
  --glass-border: rgba(255,255,255,0.09);
}
html.tux-app, html.tux-app body {
  background:
    radial-gradient(ellipse 1200px 700px at 20% -10%, rgba(45,212,200,0.09), transparent 60%),
    radial-gradient(ellipse 900px 600px at 100% 0%, rgba(226,114,92,0.07), transparent 55%),
    var(--bg);
  background-attachment: fixed;
}

/* ---- Unified top bar: badge · tabs · countdown pill, one row ---- */
.tux-topbar {
  position: sticky; top: 0; z-index: 40;
  padding: 14px 28px;
  background: rgba(8,9,11,0.72);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--hairline-soft);
}
.tux-topbar-inner {
  max-width: 1180px; margin: 0 auto;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px;
}
.tux-badge {
  display: inline-flex; align-items: center; gap: 8px; justify-self: start;
  padding: 7px 14px 7px 10px; border-radius: 100px;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
}
.tux-live-dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--sage); flex: none;
  box-shadow: 0 0 0 3px rgba(62,207,126,0.22);
}
.tux-badge-name { font-size: 13.5px; font-weight: 600; color: var(--ink); letter-spacing: -0.005em; white-space: nowrap; }
.tux-badge-sub { font-size: 12.5px; font-weight: 400; color: var(--ink-soft); white-space: nowrap; }

.tux-tabs.nav-groups {
  justify-self: center; display: inline-flex; gap: 2px; padding: 3px;
  background: var(--glass-bg); border: 1px solid var(--glass-border); border-radius: 100px;
}
.tux-tabs.nav-groups a {
  font-size: 12.5px; font-weight: 500; text-transform: none; letter-spacing: -0.005em;
  padding: 7px 16px; border-radius: 100px; color: var(--ink-soft);
}
.tux-tabs.nav-groups a.active { background: var(--glass-bg-strong); color: var(--ink); box-shadow: 0 1px 3px rgba(0,0,0,.3); }
.tux-tabs.nav-groups a:hover { color: var(--ink); }

.tux-countdown-pill {
  justify-self: end; display: inline-flex; align-items: baseline; gap: 8px;
  padding: 8px 16px; border-radius: 100px; white-space: nowrap;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
}
.tux-countdown-label { font-size: 10.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-faint); }
.tux-countdown-value { font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--ink); letter-spacing: -0.01em; }
.tux-countdown-sub {
  text-align: center; font-size: 12px; color: var(--ink-faint); font-weight: 300;
  margin: 10px 0 0; padding: 0 16px;
}
@media (max-width: 780px) {
  .tux-topbar-inner { grid-template-columns: 1fr; justify-items: center; gap: 10px; }
  .tux-badge, .tux-tabs.nav-groups, .tux-countdown-pill { justify-self: center; }
}

/* ---- Glass-card treatment for existing content blocks ---- */
html.tux-app .panel-boxed,
html.tux-app .map-shell,
html.tux-app .fanzone-card,
html.tux-app .timeline {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  box-shadow: var(--shadow-1);
}
html.tux-app .map-shell { background: #050506; }
html.tux-app .timeline { border-radius: 18px; padding: 22px 24px; }
html.tux-app .fanzone-card { border-radius: 18px; }
html.tux-app .tl-dot { background: transparent; border-color: var(--accent); }
html.tux-app .tl-dot.aid { border-color: var(--ink-faint); opacity: .65; }
html.tux-app .tl-badge {
  font-size: 10.5px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
  padding: 2px 9px; border-radius: 100px; white-space: nowrap;
}
html.tux-app .tl-badge-cutoff { background: var(--accent-soft); color: var(--accent); }

/* Hero stats as a glass card grid instead of hairline-divided columns —
   auto-fit so it fills the full page width now that there's no sidebar
   competing for space, while still wrapping sensibly on narrow screens. */
html.tux-app .hero-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin: 0; }
html.tux-app .hero-stat {
  border-left: none; padding: 18px 20px; border-radius: 16px;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
}
@media (max-width: 640px) {
  html.tux-app .hero-stats { grid-template-columns: 1fr 1fr; }
}

/* ---- Live tracking: one big map, margins to the page edge like the rest
   of the site, one merged overlay panel (title + status + runner picker). ---- */
.tux-hero-map-wrap { max-width: 1180px; margin: 0 auto; padding: 0 28px; }
.tux-hero-map {
  height: calc(100vh - 66px); min-height: 480px; max-height: 760px;
}
.tux-hero-note { max-width: 1180px; margin: 10px auto 0; padding: 0 28px; }

.tux-hero-panel {
  position: absolute; z-index: 5;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  backdrop-filter: blur(20px) saturate(140%); -webkit-backdrop-filter: blur(20px) saturate(140%);
  border-radius: 18px; box-shadow: var(--shadow-1);
  /* backdrop-filter is a GPU-composited layer that overflow:hidden alone
     doesn't always clip correctly at a rounded corner — clip-path forces a
     real clip of the rendered pixels instead of relying on that compositing
     to behave, which is what let the map show through as a sharp-edged
     wedge right at the curve instead of fading out with it. */
  clip-path: inset(0 round 18px);
}
.tux-hero-panel-left {
  top: 24px; left: 24px; max-height: calc(100% - 48px); width: min(380px, calc(100% - 48px));
  padding: 18px 22px; display: flex; flex-direction: column;
}
.tux-hero-panel-head {
  position: relative; display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; padding-right: 40px; /* clears the absolutely-positioned toggle button */
}
.tux-hero-h1 { margin: 0; font-size: clamp(24px, 3vw, 30px); text-align: left; }
/* Expand/collapse arrow for the runner panel — sits over the corner rather
   than in the flex row, so it doesn't push the left-aligned heading over. */
.tux-panel-toggle {
  position: absolute; top: 50%; right: 0; transform: translateY(-50%);
  width: 32px; height: 32px; border: none; border-radius: 9px; cursor: pointer;
  background: var(--hairline-soft); color: var(--ink); line-height: 1;
  display: flex; align-items: center; justify-content: center; transition: background .2s ease;
}
.tux-panel-toggle:hover { background: var(--hairline); }
/* Both toggle arrows are SVG chevrons (not font glyphs) so they're crisp and
   properly sized everywhere; the same "closed" (pointing down) shape just
   rotates 180° when its section is open, rather than swapping icons. */
.tux-panel-toggle svg, .tux-chart-arrow svg { display: block; transition: transform .25s ease; }
.tux-hero-panel-left:not(.collapsed) .tux-panel-toggle svg { transform: rotate(180deg); }
/* The runner list is the part that can grow long — it scrolls internally
   so the panel itself never grows taller than the map behind it. */
.tux-hero-panel-body {
  display: flex; flex-direction: column; min-height: 0;
  overflow: hidden; margin-top: 14px;
  max-height: 640px; opacity: 1; transition: max-height .3s ease, opacity .25s ease, margin-top .3s ease;
}
.tux-hero-panel-left.collapsed .tux-hero-panel-body {
  max-height: 0; opacity: 0; margin-top: 0; pointer-events: none;
}
.tux-hero-panel-left .tux-runners-list { flex: 1 1 auto; min-height: 0; }

@media (max-width: 860px) {
  .tux-hero-map { height: 78vh; min-height: 460px; max-height: none; }
  .tux-hero-panel-left {
    /* As wide as the map allows — right stops short of .map-fs-btn (16px
       right + 34px wide = 50px from the edge), with a small gap so the
       panel's own corner (and its toggle button) never sits under it. */
    top: 12px; left: 12px; right: 60px; max-height: calc(100% - 24px); width: auto; padding: 12px 16px;
  }
  .tux-hero-panel-left .tux-hero-h1 { font-size: 20px; }
  .tux-hero-panel-body { max-height: 60vh; }
}
@media (max-width: 860px) and (max-height: 700px) {
  .tux-hero-map { height: 88vh; }
}

/* Elevation-profile-with-runners chart, overlaid on the map itself instead
   of taking a separate section below it. Its header bar is always visible;
   the chart itself opens/closes via the arrow, so it stays "diskret" by
   default without ever disappearing entirely. */
.tux-map-chart-overlay {
  position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 4;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  border-radius: 14px; padding: 0 14px;
  backdrop-filter: blur(18px) saturate(140%); -webkit-backdrop-filter: blur(18px) saturate(140%);
}
/* The chart's axis labels use the site-wide --ink-faint, tuned for solid
   cards — against this overlay's glass backing over the satellite map it
   stayed too faint even at --ink-soft, so use full --ink (near-white in
   this dark theme) here specifically. */
.tux-map-chart-overlay .viz-tick { fill: var(--ink); }
.tux-map-chart-overlay .viz-grid-line { stroke: var(--hairline); }
.tux-chart-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 0; cursor: pointer; user-select: none;
  font-size: 12.5px; font-weight: 600; color: var(--ink);
}
.tux-chart-arrow { display: flex; color: var(--ink); }
/* This overlay is anchored to the map's bottom edge and grows upward as it
   opens (unlike the top-anchored runner panel), so the arrow points the
   opposite way: up while closed (there's more above if you open it), down
   while open (closing retracts it downward). */
.tux-map-chart-overlay.collapsed .tux-chart-arrow svg { transform: rotate(180deg); }
/* Each selected runner's current distance/elevation, in plain text above the
   chart. max-height is a generous ceiling (not a real cap — see overflow-y
   below), sized well past what even several wrapped runner rows need, purely
   so the open/close transition has a fixed number to animate to/from
   (height:auto can't be transitioned). Text must never be clipped here: on a
   narrow phone width outside fullscreen, several runners' rows used to wrap
   past the old 60px cap and get cut off with no way to see the rest. */
.tux-chart-runners {
  display: flex; flex-wrap: wrap; gap: 4px 12px; overflow-y: auto;
  /* Reserved regardless of content — without this the box has no size of its
     own and visibly grows/shrinks the instant runner text appears or
     disappears, shoving the chart below it up and down. Sized to one line at
     the font/line-height below (0 or 1 runner selected, the common case) —
     tighter than reserving for 2 wrapped lines, which left a visibly empty
     gap under the header whenever fewer runners were shown. 2+ runners
     wrapping still grows past this rather than clipping, same as before —
     now a real (if rarer) jump instead of a permanently oversized reservation. */
  min-height: 16px; max-height: 220px; opacity: 1; margin-bottom: 4px;
  transition: max-height .3s ease, opacity .25s ease, margin .3s ease;
}
/* Small enough, and left free to wrap (not nowrap), that one runner's row
   reliably fits the overlay's width without pushing the bar's rendered size
   around as rows are added/removed — wrapping is the fallback for an
   unusually long name or a narrow phone width, not the normal case. */
.tux-chart-runner-stat { font-size: 9.5px; line-height: 1.4; color: var(--ink-soft); white-space: normal; }
.tux-chart-runner-stat b { color: var(--ink); font-weight: 600; }
.tux-map-chart-overlay.collapsed .tux-chart-runners { min-height: 0; max-height: 0; opacity: 0; margin-bottom: 0; pointer-events: none; }

.tux-map-chart-overlay #chart-progress,
.tux-map-chart-overlay #chart-profile {
  /* 150px chart + the .viz-tt-bar above it (~40px incl. margin) + slack */
  overflow: hidden; max-height: 230px; opacity: 1; margin-bottom: 4px;
  transition: max-height .3s ease, opacity .25s ease, margin .3s ease;
}
.tux-map-chart-overlay.collapsed #chart-progress,
.tux-map-chart-overlay.collapsed #chart-profile {
  max-height: 0; opacity: 0; margin-bottom: 0; pointer-events: none;
}

/* TUX070's route map (unlike Live Tracking's) also has a play/scrub bar
   anchored to the same bottom edge — raise the chart overlay above it
   instead of the default bottom:12px so the two never overlap. */
.route-map-shell .tux-map-chart-overlay { bottom: 96px; }
@media (max-width: 860px) {
  .route-map-shell .tux-map-chart-overlay { bottom: 90px; }
}

.tux-runners-empty { color: var(--ink-faint); font-size: 13px; margin: 0; }
.tux-runners-count { font-size: 10.5px; font-weight: 600; color: var(--sage); text-transform: uppercase; letter-spacing: .04em; white-space: nowrap; }
.tux-runners-list { overflow-y: auto; display: flex; flex-direction: column; }
.map-runner-select {
  width: 17px; height: 17px; flex: none; accent-color: var(--sage); cursor: pointer;
}

/* Runner list rows (live-tracking's side panel) vs. the small floating pills
   (TUX070's map HUD) — same .map-runner-chip base, different context. */
.tux-runners-list .map-runner-chip {
  width: 100%; padding: 9px 10px; border-radius: 12px; margin-bottom: 6px;
  background: var(--glass-bg); border: none; overflow: hidden;
  clip-path: inset(0 round 12px); /* see .tux-hero-panel's clip-path comment */
}
.tux-runners-list .map-runner-chip:last-child { margin-bottom: 0; }
.tux-runners-list .map-runner-chip.active { background: rgba(62, 207, 126, 0.16); }
.map-runner-info { display: flex; flex-direction: column; gap: 3px; align-items: flex-start; flex: 1; min-width: 0; }
.map-runner-name { font-size: 13px; font-weight: 600; color: var(--ink); }
.map-runner-meta { font-size: 11px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.map-runner-progress { width: 100%; height: 4px; border-radius: 100px; background: var(--hairline-soft); overflow: hidden; margin-top: 2px; }
.map-runner-progress span { display: block; height: 100%; background: var(--accent); border-radius: 100px; }

/* ---- Aid Stations: runner picker (same chip look as the map HUD, standalone) ---- */
.tux-runner-picker { display: flex; flex-wrap: wrap; gap: 8px; }
.tux-runner-picker .map-runner-chip { background: var(--glass-bg); border: 1px solid var(--glass-border); backdrop-filter: none; box-shadow: none; cursor: pointer; }

/* ---- Login page: one centred card, same materials as the rest of the site ---- */
.login-wrap {
  min-height: calc(100vh - 62px);
  display: flex; align-items: center; justify-content: center; padding: 40px 20px;
}
.login-card {
  width: 100%; max-width: 380px;
  background: var(--bg-raised); border: 1px solid var(--hairline-soft); border-radius: 18px;
  padding: 32px 30px; box-shadow: var(--shadow-1);
  display: flex; flex-direction: column; gap: 16px;
}
.login-card .eyebrow { text-align: center; margin: 0; }
.login-card h1 { margin: 0 0 4px; font-size: 24px; text-align: center; }
.login-field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--ink-soft); }
.login-field input {
  font-family: inherit; font-size: 15px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--hairline); border-radius: 10px; padding: 10px 12px;
  transition: border-color .2s ease;
}
.login-field input:focus { outline: none; border-color: var(--accent); }
.login-remember { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-soft); cursor: pointer; }
.login-remember input { width: 16px; height: 16px; flex: none; accent-color: var(--accent); cursor: pointer; }
.login-error { color: var(--coral); font-size: 13px; margin: 0; }
.login-submit {
  border: none; border-radius: 100px; padding: 12px 18px; font-family: inherit;
  font-size: 14.5px; font-weight: 500; color: #fff; cursor: pointer;
  background: var(--accent); box-shadow: var(--shadow-1); transition: opacity .2s ease;
}
.login-submit:hover { opacity: .88; }
.login-submit:disabled { opacity: .6; cursor: default; }

html.tux-app .map-controls .segmented,
html.tux-app .map-runner-chip,
html.tux-app .live-ping-label,
html.tux-app .map-cp-marker,
html.tux-app .map-fs-btn,
html.tux-app .map-scrub-bar,
html.tux-app .mapboxgl-ctrl-group {
  background: var(--glass-bg-strong) !important;
  border-color: var(--glass-border) !important;
}
/* Chips inside the dropdown runner-list panel are a different case from the
   ones above: those float directly on the satellite map and want the darker
   --glass-bg-strong for contrast, but these already sit on .tux-hero-panel's
   own --glass-bg — a *different* colour showed as a dark square patch
   leaking past the chip's rounded corners (backdrop-filter's blur doesn't
   always respect the parent's border-radius clip). Matching the panel's own
   background, and dropping the chip's own blur (redundant this deep inside
   the panel's already-blurred glass), removes the mismatch instead of
   papering over it — same fix already applied to .tux-runner-picker's chips
   for the identical reason. */
html.tux-app .tux-runners-list .map-runner-chip {
  background: var(--glass-bg) !important;
  backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
}

/* Gallery section on live-tracking.html */
.gallery-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.gallery-add-btn {
  width: 34px; height: 34px; border-radius: 100px; border: 1px solid var(--hairline);
  background: var(--accent-soft); color: var(--accent); font-size: 20px; line-height: 1;
  cursor: pointer; flex: none;
}
.gallery-add-btn:disabled { opacity: .5; cursor: default; }
.gallery-status { font-size: 12.5px; color: var(--ink-soft); margin: 4px 0 12px; font-weight: 300; }
.gallery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px; margin-top: 4px; }
.gallery-item { position: relative; cursor: pointer; }
.gallery-thumb {
  width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 10px;
  border: 1px solid var(--hairline-soft); background: var(--bg-raised); display: block;
}
.gallery-play-badge {
  position: absolute; left: 6px; bottom: 6px; padding: 2px 7px; border-radius: 100px;
  background: rgba(0,0,0,.6); color: #fff; font-size: 11px; letter-spacing: .02em;
  display: flex; align-items: center; gap: 3px; pointer-events: none;
}
.gallery-delete-btn {
  position: absolute; top: 6px; right: 6px; width: 22px; height: 22px; border-radius: 100px;
  border: none; background: rgba(0,0,0,.6); color: #fff; font-size: 15px; line-height: 1;
  cursor: pointer;
}
.gallery-lightbox {
  position: fixed; inset: 0; background: rgba(0,0,0,.9); z-index: 1000;
}
/* :not([hidden]) rather than a bare display:flex above -- an unconditional
   display here would override the browser's own [hidden]{display:none} UA
   rule (same specificity, author stylesheet wins), showing the lightbox
   by default and making it un-closeable since closeGalleryLightbox() only
   toggles the hidden attribute, not this rule. */
.gallery-lightbox:not([hidden]) { display: flex; align-items: center; justify-content: center; }
.gallery-lightbox img { max-width: 92vw; max-height: 92vh; object-fit: contain; }
.gallery-lightbox-close {
  position: absolute; top: 16px; right: 20px; background: none; border: none;
  color: #fff; font-size: 32px; line-height: 1; cursor: pointer;
}
@media (max-width: 640px) {
  /* 2-column grid on phones, per spec */
  .gallery-grid { grid-template-columns: 1fr 1fr; }
}

.tux-logout-btn {
  position: fixed; top: 12px; right: 12px; z-index: 900;
  padding: 6px 14px; border-radius: 100px; border: 1px solid var(--hairline);
  background: var(--bg-raised); color: var(--ink-soft); font-size: 12.5px; font-weight: 300;
  cursor: pointer; box-shadow: var(--shadow-1);
}
.tux-logout-btn:disabled { opacity: .5; cursor: default; }
@media (max-width: 640px) {
  /* Small enough on phones to not collide with the topbar's own controls
     (countdown pill, badge) which already claim most of that width. */
  .tux-logout-btn { top: auto; bottom: 12px; right: 12px; }
}

/* ---- Training stats pages (index/traening/fitness/restitution/sammenlign)
   on the TUX dark theme: same top bar and glass materials as the race pages. */
html.tux-app .nav-card {
  padding: 22px 24px; margin-bottom: 12px; border-radius: 18px;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  transition: background .2s ease;
}
html.tux-app .nav-card:hover { opacity: 1; background: var(--glass-bg-strong); }
html.tux-app details.dig {
  border-radius: 18px; padding: 4px 20px;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
}
