/* tracker — single stylesheet, mobile-first, iOS-flavored.
   Targets recent iOS Safari, Android Chrome/Firefox, desktop browsers.
   No vendor prefixes for properties widely supported since ~2022. */

:root {
    /* Light defaults — Taunus Bikepacking brand. The inline <head> script
       sets data-theme-active on <html> very early, so this block is the
       fallback for the brief moment before that runs (or when JS is off). */
    --color-bg: #d7d3c8;
    --color-surface: #efece5;
    --color-border: rgba(40, 30, 20, 0.18);
    --color-text: #1c1c1e;
    --color-text-secondary: #6c6c70;
    --color-tint: #007aff;
    --color-tint-inactive: #8e8e93;
    --color-tabbar-bg: rgba(215, 211, 200, 0.88);
    --color-status: #6c6c70;
    --color-num-bg: rgba(0, 0, 0, 0.06);
    --color-flag-bg: rgba(0, 0, 0, 0.04);

    --tab-bar-h: 56px;
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-top: env(safe-area-inset-top, 0px);

    --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

:root[data-theme-active="dark"] {
    --color-bg: #000000;
    --color-surface: #1c1c1e;
    --color-border: rgba(120, 120, 128, 0.32);
    --color-text: #f2f2f7;
    --color-text-secondary: #98989f;
    --color-tabbar-bg: rgba(28, 28, 30, 0.85);
    --color-status: #98989f;
    --color-num-bg: rgba(255, 255, 255, 0.08);
    --color-flag-bg: rgba(255, 255, 255, 0.06);
}

* { box-sizing: border-box; }

/* Make the [hidden] attribute reliable across all our flex/grid blocks.
   Without this, `display: flex` on a class wins over the UA stylesheet's
   `[hidden] { display: none }` rule. */
[hidden] { display: none !important; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--color-bg);
    color: var(--color-text);
    font-family: var(--font);
    font-size: 16px;
    line-height: 1.4;
    -webkit-font-smoothing: antialiased;
    overscroll-behavior-y: contain;
}

a { color: var(--color-tint); text-decoration: none; }
a:hover { text-decoration: underline; }

/* App frame: full viewport on mobile, capped + centered on desktop. */
.app-frame {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
    width: 100%;
    max-width: 768px;
    margin: 0 auto;
    background: var(--color-bg);
    position: relative;
}

/* Content area scrolls; bottom space accounts for the fixed tab bar. */
.content {
    flex: 1 1 auto;
    padding: calc(env(safe-area-inset-top, 0px) + 12px) 16px
             calc(var(--tab-bar-h) + var(--safe-bottom) + 24px) 16px;
}

.view-header {
    padding: 8px 0 12px 0;
}

.view-header h1 {
    margin: 0;
    font-size: 28px;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.view-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
}

.meta-count {
    font-size: 14px;
    color: var(--color-text-secondary);
}

.status-line {
    margin: 4px 0 0 0;
    font-size: 13px;
    color: var(--color-status);
}

.btn-refresh {
    margin-left: auto;
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--color-tint);
    padding: 8px;
    border-radius: 8px;
    cursor: pointer;
    line-height: 0;
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.btn-refresh:hover { background: rgba(0, 122, 255, 0.08); }
.btn-refresh:disabled { color: var(--color-tint-inactive); cursor: progress; }
.btn-refresh.is-spinning svg { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* CP filter pill row above the riders list. Horizontal scroll so a
   long CP list (15+ CPs) doesn't push the list down on phones. */
.cp-filter-row {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding: 4px 0 10px 0;
    margin: 0 0 6px 0;
    scrollbar-width: none;
}
.cp-filter-row::-webkit-scrollbar { display: none; }

.cp-pill {
    appearance: none;
    border: 1px solid var(--color-border);
    background: transparent;
    color: var(--color-text);
    border-radius: 14px;
    padding: 5px 12px;
    font: 600 13px/1.2 var(--font);
    white-space: nowrap;
    cursor: pointer;
    flex-shrink: 0;
}
.cp-pill:hover { background: rgba(0, 0, 0, 0.04); }
:root[data-theme-active="dark"] .cp-pill:hover { background: rgba(255, 255, 255, 0.06); }
.cp-pill.is-active {
    background: var(--color-tint);
    border-color: var(--color-tint);
    color: #fff;
}

/* Header card shown above the per-CP standings list. */
.cp-header {
    padding: 4px 4px 10px 4px;
}
.cp-header h2 {
    font: 600 17px/1.3 var(--font);
    margin: 0;
    color: var(--color-text);
}
.cp-subtitle {
    margin: 2px 0 0;
    color: var(--color-text-secondary);
    font-size: 13px;
}

/* Riders list: simple iOS-style grouped row look. */
.riders-list {
    list-style: none;
    margin: 0;
    padding: 0;
    background: var(--color-surface);
    border-radius: 12px;
    overflow: hidden;
}

.riders-group + .riders-group { margin-top: 20px; }

.riders-group-title {
    display: flex;
    align-items: baseline;
    margin: 0 8px 6px 8px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-secondary);
}
.riders-group-count {
    margin-left: 4px;
    font-weight: 400;
    opacity: 0.7;
}

.rider-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    border-top: 1px solid var(--color-border);
    min-height: 44px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.rider-row:hover { background: rgba(0, 0, 0, 0.02); }
:root[data-theme-active="dark"] .rider-row:hover { background: rgba(255, 255, 255, 0.04); }
.rider-row:focus { outline: 2px solid var(--color-tint); outline-offset: -2px; }
.rider-row:focus:not(:focus-visible) { outline: none; }
.rider-row:first-child { border-top: 0; }

/* Start number + flag form a 2-row left column. The bib sits on top
   in its own pill; the country flag sits beneath, sized down so the
   row height stays in line with the rider-body. */
.rider-num-col {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    min-width: 36px;
}
.rider-num {
    min-width: 36px;
    padding: 2px 6px;
    border-radius: 6px;
    background: var(--color-num-bg);
    font-family: ui-monospace, SFMono-Regular, Menlo, "Roboto Mono", monospace;
    font-size: 13px;
    font-weight: 600;
    text-align: center;
    color: var(--color-text);
}
.rider-num:empty {
    background: transparent;
}

.rider-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.rider-name {
    font-size: 16px;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.rider-dist {
    font-size: 12px;
    line-height: 1.25;     /* tight line-box so the speed pill below
                              hugs the text instead of floating apart */
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
}
/* Speed pill on its own line under the meta row, matching the
   Nearby tab so the pill stays visible even on narrow viewports.
   No explicit margin — the parent .rider-body's gap controls
   spacing. */
.rider-speed-line {
    display: block;
}

.rider-meta {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--color-text-secondary);
}

/* Country flag — sits beneath the bib, smaller than before because
   it's now a sub-element of the bib column. Populated lazily by JS
   after the main paint via [data-country]. */
.rider-flag {
    flex: 0 0 auto;
    width: 20px;
    height: 14px;
    border-radius: 2px;
    overflow: hidden;
    background: var(--color-flag-bg);
}
.rider-flag img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Right-edge column — bare number; the "km left" label sits once
   above the list as a column header (.riders-col-header). For
   finishers the column flips to a tinted "FIN" badge with the
   final time printed small underneath. */
.rider-right {
    flex: 0 0 auto;
    margin-left: auto;
    text-align: right;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}
.rider-right-value {
    font-size: 18px;
    font-weight: 700;
    color: var(--color-text);
}
.rider-right--empty { min-width: 0; }
.rider-right--fin .rider-right-value {
    color: #34c759;            /* iOS green — same family as the speed-pill */
    letter-spacing: 0.04em;
}
.rider-right-result {
    margin-top: 1px;
    font-size: 11px;
    font-weight: 500;
    color: var(--color-text-secondary);
    white-space: nowrap;
}

/* Column header above the entire riders list — appears once, aligned
   with the right-edge value column. Hidden when no rider has DTF. */
/* Inline column-header label that lives on the right side of the
   first group title ("SOLO 49  KM LEFT"). Same baseline as the
   title so it doesn't float as a stray strip above the list. */
.riders-col-tag {
    margin-left: auto;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-secondary);
}

/* Coloured speed pill — red up to 3 km/h, yellow up to 10, green
   up to 25, purple beyond. Same colours appear on the map labels. */
.speed-pill {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 8px;
    font-size: 11px;
    font-weight: 700;
    color: #fff;
    font-variant-numeric: tabular-nums;
    line-height: 1.4;
}
.speed-pill--zero   { background: #ff3b30; }   /* iOS red */
.speed-pill--slow   { background: #ffcc00; color: #1c1c1e; }  /* yellow + dark text */
.speed-pill--medium { background: #34c759; }   /* iOS green */
.speed-pill--fast   { background: #af52de; }   /* iOS purple */

/* Position-change marker on per-CP rows (Riders → CP pill view).
   Replaces the live-view's rider-right slot. ▲ green = gained,
   ▼ red = lost positions since the previous CP.
   The arrow lives in a fixed-width slot at the left of the marker
   column so arrows line up vertically across rows even when only
   some have a count digit after them. */
.cp-delta {
    flex: 0 0 36px;
    width: 36px;
    margin-left: auto;
    display: flex;
    align-items: baseline;
    justify-content: flex-start;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    font-size: 16px;
    line-height: 1.1;
    white-space: nowrap;
}
.cp-delta-arrow {
    flex: 0 0 16px;
    text-align: center;
}
.cp-delta--up   { color: #34c759; }
.cp-delta--down { color: #ff3b30; }
/* No-change marker: neutral foreground (black on light, white on dark)
   so it reads as "held position" rather than a coloured win/loss. */
.cp-delta--flat {
    color: var(--color-text);
    font-weight: 600;
    font-size: 14px;
}
.cp-delta-num {
    flex: 0 0 auto;
    font-size: 11px;
    font-weight: 600;
    margin-left: 2px;
}

/* Overall position — leading column shared with the Nearby tab via
   the same dimensions. Centered "Pn" so single, double, and triple-
   digit ranks all read symmetrically. */
.rider-pos {
    flex: 0 0 38px;
    min-width: 38px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    font-size: 16px;
    color: var(--color-tint);
}
.rider-pos:empty { color: transparent; }

.rider-row.is-scratched .rider-name,
.rider-row.is-scratched .rider-num,
.rider-row.is-scratched .rider-pos {
    color: var(--color-text-secondary);
}
.rider-row.is-scratched .rider-name {
    text-decoration: line-through;
}

/* Self-highlight in the Riders list — same blue tint we use on the
   Nearby tab so the user can spot themselves at a glance in both
   the live standings and any per-CP filter view. */
.rider-row--self {
    background: rgba(0, 122, 255, 0.10);
}
.rider-row--self .rider-name {
    color: var(--color-tint);
    font-weight: 600;
}

/* Off-Track flag. Two flavours:
   - .off-track-badge: prominent pill next to "You" in the self tile.
   - .off-track-tag: inline coloured text in any peer row's meta line.
   Same iOS-orange that FMC uses, so the connection is obvious. */
.off-track-badge {
    display: inline-block;
    margin-left: 8px;
    padding: 2px 7px;
    border-radius: 8px;
    background: #ff9500;
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    vertical-align: middle;
}
.off-track-tag {
    color: #ff9500;
    font-weight: 600;
}

.empty-list {
    margin: 24px 0;
    text-align: center;
    color: var(--color-text-secondary);
    font-size: 14px;
}

/* Info view */
.info-body {
    background: var(--color-surface);
    border-radius: 12px;
    padding: 16px;
    margin-top: 8px;
}
.info-body p { margin: 0 0 12px 0; }
.info-grid {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 8px 16px;
    margin: 16px 0;
    font-size: 14px;
}
.info-grid dt { color: var(--color-text-secondary); }
.info-grid dd { margin: 0; word-break: break-all; }
.info-foot { margin-top: 16px !important; font-size: 13px; color: var(--color-text-secondary); }

/* Export-section action buttons. iOS-tint pill, full row width on
   mobile so taps are easy. Hint text underneath each button uses the
   secondary colour so the button stays the focal point. */
.info-action-btn {
    appearance: none;
    background: var(--color-tint);
    color: #fff;
    border: 0;
    border-radius: 10px;
    padding: 10px 16px;
    font: 600 14px/1.2 var(--font);
    cursor: pointer;
    margin-top: 12px;
}
.info-action-btn:hover { opacity: 0.92; }
.info-action-btn:active { transform: scale(0.98); }
.info-hint {
    margin: 10px 0 22px 0;
    font-size: 12px;
    line-height: 1.5;
    color: var(--color-text-secondary);
}

/* Empty / "coming soon" state */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 48px 16px;
    color: var(--color-text-secondary);
}
.empty-state svg { color: var(--color-tint-inactive); margin-bottom: 16px; }
.empty-state h2 { margin: 0 0 4px 0; font-size: 22px; color: var(--color-text); }
.empty-state p { margin: 0; font-size: 14px; }

/* ====== Bottom Tab Bar ====== */
.tab-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    height: calc(var(--tab-bar-h) + var(--safe-bottom));
    padding-bottom: var(--safe-bottom);
    background: var(--color-tabbar-bg);
    border-top: 1px solid var(--color-border);
    backdrop-filter: saturate(180%) blur(20px);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    z-index: 100;
}

/* On desktop the tab bar spans the full viewport width — the content
   area stays centered at 768 px, but the bar reads as a global app
   chrome edge-to-edge. */

.tab {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    color: var(--color-tint-inactive);
    font-size: 10px;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    min-height: 44px;
}
.tab:hover { text-decoration: none; }
.tab[aria-selected="true"] { color: var(--color-tint); }
.tab-label {
    font-size: 10px;
    line-height: 1;
    font-weight: 500;
}

/* Hide views by default fallback; JS switches `hidden`. */
.view[hidden] { display: none; }

/* ====== Reports view ====== */
.view-reports {
    position: fixed;
    inset: 0 0 calc(var(--tab-bar-h) + var(--safe-bottom)) 0;
    display: flex;
    flex-direction: column;
    background: var(--color-bg);
    z-index: 1;
}
@media (min-width: 600px) {
    .view-reports {
        left: 50%;
        right: auto;
        width: 100%;
        max-width: 768px;
        transform: translateX(-50%);
    }
}
.view-reports .view-header--compact {
    display: flex;
    align-items: center;
    gap: 12px;
}
.reports-link {
    margin-left: auto;
    font-size: 14px;
    font-weight: 500;
    color: var(--color-tint);
    text-decoration: none;
}
.reports-link:hover { text-decoration: underline; }
.reports-frame {
    flex: 1 1 auto;
    width: 100%;
    border: 0;
    background: #ffffff;
    color-scheme: light;
}
/* Dark theme: cross-origin CSS can't reach inside the iframe, so we
   invert the rendered pixels. hue-rotate(180deg) keeps colours roughly
   correct (red stays red, etc.); photos render as negatives but the
   feed is mostly text. The dark surface behind matches the rest of
   the app so the iframe blends in instead of being a white slab. */
:root[data-theme-active="dark"] .reports-frame {
    background: #1c1c1e;
    color-scheme: dark;
    filter: invert(1) hue-rotate(180deg);
}

/* ====== Map view ====== */
/* The map view is special: it fills the viewport between the top safe
   area and the bottom tab bar, ignoring the default .content padding. */
.view-map {
    position: fixed;
    inset: 0 0 calc(var(--tab-bar-h) + var(--safe-bottom)) 0;
    display: flex;
    flex-direction: column;
    background: var(--color-bg);
    z-index: 1;
}
.view-header--compact {
    padding: calc(var(--safe-top) + 8px) 16px 8px 16px;
    background: var(--color-bg);
}
.view-header--compact h1 {
    margin: 0;
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.01em;
}
.map-canvas {
    flex: 1 1 auto;
    width: 100%;
    background: var(--color-surface);
}
.map-fab {
    position: absolute;
    right: 16px;
    width: 48px;
    height: 48px;
    border: 0;
    border-radius: 50%;
    background: var(--color-surface);
    color: var(--color-tint);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 1000;     /* above Leaflet panes */
}

/* Floating search bar at the top of the map. Overlays the canvas
   rather than shrinking it, so the visible map area stays full-bleed. */
.map-search {
    position: absolute;
    top: calc(var(--safe-top, 0px) + 8px);
    left: 12px;
    width: calc(100% - 24px);
    max-width: 360px;     /* desktop cap — names and bib numbers are short */
    z-index: 1100;     /* above .map-fab and Leaflet panes */
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 8px 10px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}
.map-search-icon {
    flex: 0 0 auto;
    color: var(--color-text-secondary);
}
.map-search-input {
    flex: 1 1 auto;
    appearance: none;
    border: 0;
    outline: none;
    background: transparent;
    color: var(--color-text);
    font: inherit;
    min-width: 0;
    padding: 4px 0;
}
.map-search-input::placeholder { color: var(--color-text-secondary); }
.map-search-input::-webkit-search-cancel-button { display: none; }
.map-search-clear {
    flex: 0 0 auto;
    appearance: none;
    border: 0;
    background: transparent;
    color: var(--color-text-secondary);
    font-size: 22px;
    line-height: 1;
    width: 24px;
    height: 24px;
    padding: 0;
    cursor: pointer;
}
.map-search-clear:hover { color: var(--color-text); }
.map-fab:hover { background: rgba(0, 122, 255, 0.08); }
.map-fab:active { transform: scale(0.96); }
#btn-center-me { bottom: 16px; }
#btn-fit-route { bottom: 72px; }     /* stacked above center-me */

.leaflet-container {
    font-family: var(--font);
    background: var(--color-surface);
}

/* Push the Leaflet zoom bar below the iOS notch / dynamic island AND
   below the floating search bar (which sits at safe-top + 8 with
   ~44 px height). Shape its buttons like the round FAB chrome on the
   bottom-right corner so both controls feel like part of the same UI. */
.leaflet-top.leaflet-left {
    top: calc(var(--safe-top) + 64px);
    left: 12px;
}
.leaflet-bar {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
}
.leaflet-bar a,
.leaflet-bar a:hover {
    width: 40px;
    height: 40px;
    line-height: 40px;
    font-size: 22px;
    text-align: center;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Dark-theme tweaks for Leaflet's own UI: zoom buttons (top-left) and
   the attribution pill (bottom-right) are white-on-dark by default.
   Override them so the chrome blends with the dark map tiles instead
   of glaring against them. */
:root[data-theme-active="dark"] .leaflet-bar a,
:root[data-theme-active="dark"] .leaflet-bar a:hover {
    background-color: #2c2c2e;
    color: #f2f2f7;
    border-bottom-color: rgba(255, 255, 255, 0.12);
}
:root[data-theme-active="dark"] .leaflet-bar a:hover {
    background-color: #3a3a3c;
}
:root[data-theme-active="dark"] .leaflet-bar {
    box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6);
    border-color: rgba(255, 255, 255, 0.12);
}
:root[data-theme-active="dark"] .leaflet-control-attribution {
    background: rgba(28, 28, 30, 0.85);
    color: #98989f;
}
:root[data-theme-active="dark"] .leaflet-control-attribution a {
    color: var(--color-tint);
}
.leaflet-popup-content {
    margin: 10px 12px;
    font-size: 13px;
    line-height: 1.4;
}

/* Dark-theme popup: surface-coloured bubble + matching tip arrow so
   the popup blends with the dark map tiles instead of glaring white.
   Close-X tinted secondary so it doesn't draw the eye. */
:root[data-theme-active="dark"] .leaflet-popup-content-wrapper,
:root[data-theme-active="dark"] .leaflet-popup-tip {
    background: #1c1c1e;
    color: #f2f2f7;
    box-shadow: 0 3px 14px rgba(0, 0, 0, 0.55);
}
:root[data-theme-active="dark"] .leaflet-popup-content {
    color: #f2f2f7;
}
:root[data-theme-active="dark"] .leaflet-popup-content a { color: var(--color-tint); }
:root[data-theme-active="dark"] .leaflet-popup-close-button {
    color: #98989f;
}
:root[data-theme-active="dark"] .leaflet-popup-close-button:hover {
    color: #f2f2f7;
}

/* Permanent label on each rider marker — fully-rounded pill with bib
   + initials, tinted by current speed (same palette as the
   .speed-pill in rider rows). DNF stays red regardless. */
.leaflet-tooltip.rider-label {
    background: #34c759;            /* default green; speed class overrides */
    color: #fff;
    border: 0;
    padding: 2px 8px;
    border-radius: 9999px;
    font-size: 10px;
    line-height: 12px;
    font-weight: 700;
    letter-spacing: 0.02em;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    white-space: nowrap;
    font-family: var(--font);
}
.leaflet-tooltip.rider-label::before { display: none; }
.leaflet-tooltip.rider-label--zero   { background: #ff3b30; color: #fff; }
.leaflet-tooltip.rider-label--slow   { background: #ffcc00; color: #1c1c1e; }
.leaflet-tooltip.rider-label--medium { background: #34c759; color: #fff; }
.leaflet-tooltip.rider-label--fast   { background: #af52de; color: #fff; }
.leaflet-tooltip.rider-label.is-scratched {
    background: #ff3b30;
    color: #fff;
}

/* Bike-shaped rider marker — bare SVG, no badge. A faint white halo
   via drop-shadow keeps the blue strokes legible on dark map tiles
   without obscuring the bike outline. SVG uses currentColor so DNF
   flips to red without a separate icon. */
.bike-marker {
    background: transparent;
    border: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #0a84ff;
    filter: drop-shadow(0 0 1.5px rgba(255, 255, 255, 0.95))
            drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
}
.bike-marker.is-scratched {
    color: #ff3b30;
    opacity: 0.85;
}
:root[data-theme-active="dark"] .bike-marker {
    filter: drop-shadow(0 0 1.5px rgba(0, 0, 0, 0.95))
            drop-shadow(0 1px 1px rgba(0, 0, 0, 0.6));
}

/* SVG overlay that connects offset rider labels back to their bike. */
.rider-leader-lines {
    color: #0a84ff;
    overflow: visible;
}
:root[data-theme-active="dark"] .rider-leader-lines {
    color: #5ac8fa;
}

/* Distance markers along the route. Tiny white pill so they stay
   readable against both road and terrain tiles. The pane sits below
   rider markers, so dense clusters never hide rider positions. */
.km-marker { background: transparent; border: 0; }
.km-pill {
    background: rgba(255, 255, 255, 0.92);
    color: #1c1c1e;
    border: 1px solid rgba(0, 0, 0, 0.35);
    border-radius: 8px;
    padding: 0 5px;
    font-size: 9px;
    line-height: 13px;
    font-weight: 600;
    text-align: center;
    white-space: nowrap;
    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
    font-family: var(--font);
    transform: translate(-50%, -50%);
    display: inline-block;
}
:root[data-theme-active="dark"] .km-pill {
    background: rgba(28, 28, 30, 0.92);
    color: #f2f2f7;
    border-color: rgba(255, 255, 255, 0.35);
}

/* Permanent labels for named race checkpoints (matches the look FMC
   uses on its own map: white pill with an orange-cream border). */
.leaflet-tooltip.cp-label {
    background: #ffffff;
    color: #1c1c1e;
    border: 1px solid #f5b298;
    border-radius: 3px;
    padding: 2px 6px;
    font-size: 11px;
    line-height: 13px;
    box-shadow: none;
    white-space: nowrap;
    font-family: var(--font);
}
.leaflet-tooltip.cp-label::before { display: none; }   /* no caret arrow */
:root[data-theme-active="dark"] .leaflet-tooltip.cp-label {
    background: #2c2c2e;
    color: #f2f2f7;
    border-color: #ff9500;
}

/* Popup body for a checkpoint marker — title + optional detail line
   (km position + segment length). Detail uses secondary colour so
   the title reads as the headline. */
.cp-popup-title {
    display: block;
    font-size: 14px;
    font-weight: 600;
}
.cp-popup-detail {
    margin-top: 3px;
    font-size: 12px;
    color: var(--color-text-secondary);
}
.cp-popup-actions {
    margin-top: 8px;
    display: flex;
    justify-content: flex-end;
}

/* Jump-to-Riders button at the bottom of every map popup. */
.popup-action {
    display: inline-block;
    padding: 5px 12px;
    border: 0;
    border-radius: 8px;
    background: var(--color-tint);
    color: #fff;
    font-size: 12px;
    font-weight: 600;
    font-family: var(--font);
    cursor: pointer;
}
.popup-action:hover { opacity: 0.92; }

/* Compact rider popup layout — tight rows so the bubble doesn't
   sprawl. Title + meta + stats + speed pill + action button, each
   row on its own line with minimal vertical padding. */
.rider-popup .popup-name {
    display: block;
    font-size: 14px;
    font-weight: 700;
    margin-bottom: 3px;
}
.rider-popup-meta {
    font-size: 12px;
    color: var(--color-text-secondary);
    margin-bottom: 4px;
    line-height: 1.3;
}
.rider-popup-stats {
    font-size: 12px;
    margin-bottom: 6px;
    line-height: 1.3;
}
.rider-popup-speed {
    margin-bottom: 8px;
}
.rider-popup-actions {
    margin-top: 4px;
    display: flex;
    justify-content: flex-end;
}

/* Brief orange flash on a rider row that we just scrolled to from
   the map popup, so users can see where it landed. */
.rider-row--flash {
    animation: rowFlash 1.4s ease-out;
}
@keyframes rowFlash {
    0%   { background: rgba(255, 149, 0, 0.40); }
    100% { background: transparent; }
}
.leaflet-popup-content .popup-scratched {
    color: var(--color-text-secondary);
}
.leaflet-popup-content .popup-scratched .popup-name {
    color: var(--color-text-secondary);
    text-decoration: line-through;
}

/* ====== Me tab ====== */
.me-group-title {
    display: flex;
    align-items: baseline;
    margin: 20px 8px 6px 8px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-secondary);
}
.me-group-title:first-child { margin-top: 8px; }

.me-list {
    list-style: none;
    margin: 0;
    padding: 0;
    background: var(--color-surface);
    border-radius: 12px;
    overflow: hidden;
}
.me-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 16px;
    border-top: 1px solid var(--color-border);
    min-height: 48px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.me-row:hover { background: rgba(0, 0, 0, 0.02); }
:root[data-theme-active="dark"] .me-row:hover { background: rgba(255, 255, 255, 0.04); }
.me-row:focus { outline: 2px solid var(--color-tint); outline-offset: -2px; }
.me-row:focus:not(:focus-visible) { outline: none; }
.me-row:first-child { border-top: 0; }

.me-pos {
    flex: 0 0 38px;
    min-width: 38px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    font-size: 16px;
    color: var(--color-tint);
}
.me-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.me-line1 {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
}
.me-name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 15px;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.me-gap {
    flex: 0 0 auto;
    margin-left: auto;
    font-size: 18px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--color-text);
}
.me-line2 {
    display: flex;
    align-items: baseline;
    gap: 6px;
    font-size: 13px;
    color: var(--color-text-secondary);
    flex-wrap: wrap;
}
.me-bib { font-variant-numeric: tabular-nums; }
.me-speed { font-variant-numeric: tabular-nums; }
.me-group { white-space: nowrap; }
.me-cp { white-space: nowrap; }
.me-sep { opacity: 0.5; }
/* Speed pill on its own line so a long bib · category · CP · km-left
   meta row doesn't squeeze it on narrow viewports. */
.me-line3 {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 2px;
}

.me-row--ahead .me-gap  { color: #ff9500; }   /* iOS orange — riders you still need to catch */
.me-row--behind .me-gap { color: #34c759; }   /* iOS green — riders you're ahead of */
.me-gap--neutral { color: var(--color-text); }   /* free-routing: no ahead/behind semantics */
.me-row--self {
    background: rgba(0, 122, 255, 0.10);
}
.me-row--self .me-name strong {
    color: var(--color-tint);
}

/* Right-aligned stat stack — sibling of .me-body inside .me-row, so
   the stack sits in its own column and never bloats the body's
   line1/line2 spacing. Two-column grid: label on the left, rounded
   km value on the right. Both columns auto-size to widest content so
   numbers right-align flush ("771 km" / " 96 km"). */
.me-self-stats {
    flex: 0 0 auto;
    margin-left: auto;
    display: grid;
    grid-template-columns: auto auto;
    column-gap: 6px;
    row-gap: 1px;
    align-items: baseline;
    line-height: 1.15;
}
.me-self-stat-tag {
    color: var(--color-text-secondary);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-align: right;
}
.me-self-stat-value {
    font-size: 14px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--color-text);
    white-space: nowrap;
    text-align: right;
}
.me-self-stat-value strong {
    font-weight: 700;
    font-size: 17px;
}

/* ====== Weather ====== */
.weather-body { padding: 12px; }
.weather-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
}
.weather-card {
    background: var(--color-num-bg);
    border-radius: 10px;
    padding: 10px 4px;
    text-align: center;
    min-height: 96px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 2px;
}
.weather-card--placeholder { opacity: 0.35; }
.weather-card--now { outline: 1px solid var(--color-tint); }
.weather-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-secondary);
}
.weather-icon { font-size: 24px; line-height: 1.1; margin-top: 2px; }
.weather-temp { font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; }
.weather-meta { font-size: 11px; color: var(--color-text-secondary); }
.weather-wind {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 11px;
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
    margin-top: 2px;
}
.weather-wind-arrow {
    display: inline-block;
    line-height: 1;
    font-size: 12px;
    transition: transform 200ms ease;
}
.weather-empty {
    grid-column: 1 / -1;
    padding: 20px;
    text-align: center;
    color: var(--color-text-secondary);
    font-size: 13px;
}
.weather-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    font-size: 12px;
}
.weather-source { color: var(--color-text-secondary); }

/* Sun-event cards rendered below the weather row. Half the width of
   the weather strip (2 cards instead of 4) so they read as a tighter
   pair, with the same card body so the visual rhythm carries over. */
.sun-row {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
    margin-top: 6px;
}
.sun-card {
    background: var(--color-num-bg);
    border-radius: 10px;
    padding: 8px 4px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
}
.sun-card-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-secondary);
}
.sun-card-icon { font-size: 20px; line-height: 1.1; }
.sun-card-time {
    font-size: 16px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.sun-card-day {
    font-size: 11px;
    color: var(--color-text-secondary);
}

.weather-sun {
    color: var(--color-text-secondary);
    font-size: 13px;
    white-space: nowrap;
}
.weather-loc-btn {
    margin-left: auto;
    appearance: none;
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 6px 10px;
    font: inherit;
    font-size: 13px;
    color: var(--color-tint);
    cursor: pointer;
}
.weather-loc-btn:hover { background: rgba(0, 122, 255, 0.06); }

/* ====== Bib input ====== */
.info-label {
    display: block;
    font-size: 13px;
    color: var(--color-text-secondary);
    margin-bottom: 8px;
}
.bib-input-row {
    display: flex;
    gap: 6px;
    align-items: center;
}
.bib-input {
    appearance: none;
    flex: 1 1 auto;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 10px 12px;
    background: var(--color-bg);
    color: var(--color-text);
    font: inherit;
    font-variant-numeric: tabular-nums;
    min-height: 40px;
}
.bib-input:focus {
    outline: 2px solid var(--color-tint);
    outline-offset: 1px;
    border-color: transparent;
}
.bib-clear {
    appearance: none;
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: 8px;
    background: var(--color-num-bg);
    color: var(--color-text-secondary);
    cursor: pointer;
    font-size: 20px;
    line-height: 1;
}

/* ====== Segmented control (Theme picker in Info tab) ====== */
.info-section-title {
    margin: 24px 8px 8px 8px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-secondary);
}
.seg {
    display: inline-flex;
    background: var(--color-num-bg);
    border-radius: 9px;
    padding: 2px;
    gap: 2px;
}
.seg-btn {
    appearance: none;
    background: transparent;
    border: 0;
    border-radius: 7px;
    padding: 8px 14px;
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    color: var(--color-text-secondary);
    cursor: pointer;
    min-height: 36px;
    -webkit-tap-highlight-color: transparent;
}
.seg-btn[aria-checked="true"] {
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

/* ====== Login overlay ====== */
.login-overlay {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-bg);
    z-index: 9999;
    padding: 24px;
}
.login-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    width: 100%;
    max-width: 320px;
    text-align: center;
}
.login-title {
    margin: 0;
    font-size: 36px;
    font-weight: 700;
    letter-spacing: -0.5px;
    color: var(--color-text);
}
.login-subtitle {
    margin: 0;
    font-size: 15px;
    color: var(--color-text-secondary);
}
.btn-login-github {
    margin-top: 12px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    appearance: none;
    background: var(--color-text);
    color: var(--color-bg);
    border: 0;
    border-radius: 12px;
    padding: 14px 22px;
    font: inherit;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: opacity 0.15s;
}
.btn-login-github:hover { opacity: 0.82; }
.btn-login-github:active { opacity: 0.65; }
.btn-login-github:disabled { opacity: 0.4; cursor: default; }
.login-error {
    margin: 0;
    font-size: 14px;
    color: #ff3b30;
    text-align: center;
}
.btn-logout {
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-size: 14px;
    color: #ff3b30;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.btn-logout:hover { text-decoration: underline; }
