/* Colors/type below are aliases onto brand/tokens/tokens.css's --th-*
   custom properties (loaded via brand-tokens.css) — that file is the
   single source of truth for the palette; keep these in sync with it
   rather than hardcoding hex here. */
:root {
    --bg: var(--th-bg);
    --card: var(--th-surface);
    --text: var(--th-text);
    --muted: var(--th-text-muted);
    --accent: var(--th-accent);
    --on-accent: var(--th-on-accent);
    --border: var(--th-line);
    --surface-2: var(--th-surface-2);
    --positive: var(--th-positive);
    --negative: var(--th-negative);
    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.2), 0 8px 24px rgba(0, 0, 0, 0.12);
    /* The left nav rail always renders in the brand's dark "ink" surface,
       a fixed chrome element (like the app
       icon's own background) rather than page content. */
    --sidebar-width: 220px;
    --sidebar-bg: var(--th-ink);
    --sidebar-border: #2e3b4a;
    --sidebar-text: #9aa3b2;
    --sidebar-text-active: var(--th-chalk);
    --sidebar-hover-bg: rgba(255, 255, 255, 0.06);
    --sidebar-active-bg: rgba(255, 255, 255, 0.1);
    color-scheme: dark;
}

.lucide {
    width: 16px;
    height: 16px;
    stroke-width: 2;
    flex-shrink: 0;
    vertical-align: -3px;
}
.icon-sm { width: 13px; height: 13px; }
.icon-lg { width: 22px; height: 22px; vertical-align: -5px; }
.icon-xl { width: 40px; height: 40px; vertical-align: -10px; }
h1 .lucide { width: 22px; height: 22px; vertical-align: -3px; }
.logo .lucide { width: 20px; height: 20px; color: var(--accent); }
.disc-icon .lucide, .tile-icon .lucide { width: 20px; height: 20px; }

* { box-sizing: border-box; }

body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--th-font-ui);
    margin: 0;
    padding: 24px 16px 40px calc(var(--sidebar-width) + 16px);
    -webkit-font-smoothing: antialiased;
}
/* The pre-login connect screen has no sidebar to make room for. */
body.no-sidebar { padding-left: 16px; }

/* The left nav rail — fixed for the life of the scroll, its own deep-purple
   brand color (see --sidebar-* in :root). Everything
   that used to live in a horizontal sticky <header> above the content now
   lives here instead, freeing the full page width — including the sticky
   filter bar — for content. */
header {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--sidebar-width);
    background: var(--sidebar-bg);
    border-right: 1px solid var(--sidebar-border);
    overflow-y: auto;
    z-index: 300;
}

.sidebar-inner { display: flex; flex-direction: column; height: 100%; padding: 20px 14px; gap: 4px; }

.logo { display: flex; align-items: center; text-decoration: none; padding: 4px 10px 22px; }
.logo-full { height: 22px; width: auto; display: block; }
.logo-compact { height: 26px; width: auto; display: none; }

/* overflow-y:auto + min-height:0 — without this, once the nav list's
   items outgrow the space flex left for them above the theme
   toggle/Settings footer, they don't push those footer items down (a
   shrunk flex item's overflowing content doesn't affect sibling layout);
   it just visually spills over them. Scrolling internally instead keeps
   the footer always clear, regardless of how many nav items there are. */
.sidenav { display: flex; flex-direction: column; gap: 2px; flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; }
.sidenav a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border-radius: 8px;
    color: var(--sidebar-text);
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    transition: background 0.12s, color 0.12s;
}
.sidenav a .lucide { width: 18px; height: 18px; }
.sidenav a:hover { color: var(--sidebar-text-active); background: var(--sidebar-hover-bg); }
.sidenav a.active { color: var(--sidebar-text-active); background: var(--sidebar-active-bg); box-shadow: inset 3px 0 0 var(--accent); }
.sidenav-divider { height: 1px; background: var(--sidebar-border); margin: 8px 10px; }

/* Collapsible nav groups — see _nav.html's collapse/expand script. */
.nav-group { display: flex; flex-direction: column; }
.nav-group-header {
    display: flex; align-items: center; gap: 8px;
    padding: 10px 10px 4px; margin-top: 4px;
    background: none; border: none; width: 100%; text-align: left; cursor: pointer;
    font: 600 11px/1 var(--th-font-ui); letter-spacing: 0.04em; text-transform: uppercase;
    color: var(--sidebar-text); opacity: 0.6;
}
.nav-group-header:hover { opacity: 1; }
.nav-group-chevron { width: 13px !important; height: 13px !important; transition: transform 0.15s; }
.nav-group.is-collapsed .nav-group-chevron { transform: rotate(-90deg); }
.nav-group-items { display: flex; flex-direction: column; gap: 2px; }
.nav-group.is-collapsed .nav-group-items { display: none; }

.sidenav-settings, .sidenav-bottom-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    color: var(--sidebar-text);
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    transition: background 0.12s, color 0.12s;
    background: none;
    border: none;
    width: 100%;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.sidenav-settings {
    margin-top: 8px;
    padding: 15px 10px 9px;
    border-top: 1px solid var(--sidebar-border);
}
.sidenav-settings .lucide, .sidenav-bottom-item .lucide { width: 18px; height: 18px; flex-shrink: 0; }
.sidenav-settings:hover, .sidenav-settings.active, .sidenav-bottom-item:hover, .sidenav-bottom-item.active { color: var(--sidebar-text-active); }
.sidenav-settings:disabled { opacity: 0.6; cursor: default; }

/* Below ~760px the rail collapses to icons only, reclaiming horizontal
   space for content rather than a hamburger menu — this app is mostly
   used at desktop widths, so a full mobile nav pattern isn't worth it. */
@media (max-width: 760px) {
    :root { --sidebar-width: 60px; }
    .sidebar-inner { padding: 16px 8px; align-items: center; }
    .logo { padding: 4px 0 18px; justify-content: center; }
    .logo-full { display: none; }
    .logo-compact { display: block; }
    .sidenav a, .sidenav-settings, .sidenav-bottom-item { justify-content: center; padding: 10px; width: 100%; }
    .sidenav a span, .sidenav-settings span, .sidenav-bottom-item span { display: none; }
    /* Icon-only rail has no room for a text group label, and nothing to
       collapse toward — every group always shows, in full, with no header. */
    .nav-group-header { display: none; }
    .nav-group.is-collapsed .nav-group-items { display: flex; }
}

.filter-bar-title {
    font-family: var(--th-font-display);
    font-weight: 800;
    font-stretch: 125%;
    letter-spacing: -0.02em;
}

.settings-layout { display: flex; flex-direction: column; gap: 16px; margin-top: -8px; }
.settings-panels { display: flex; flex-direction: column; gap: 20px; min-width: 0; flex: 1; }

.settings-tabs {
    display: flex;
    gap: 4px;
    overflow-x: auto;
    border-bottom: 1px solid var(--border);
    margin: 0 0 4px;
}
.settings-tab {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 9px 14px;
    background: none;
    border: none;
    color: var(--muted);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
    flex-shrink: 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.settings-tab:hover { color: var(--text); }
.settings-tab.active { color: var(--text); border-bottom-color: var(--accent); }
.settings-panel { display: none; flex-direction: column; gap: 20px; }
.settings-panel.active { display: flex; }

/* On wide screens the tab bar becomes a left sidebar instead — on narrow
   screens it stays a horizontally-scrollable strip (never wraps mid-word
   or clips off-screen, which a plain flex-wrap row used to do once there
   were enough tabs to not fit one line). */
@media (min-width: 860px) {
    .settings-layout { flex-direction: row; align-items: flex-start; gap: 24px; }
    .settings-tabs {
        flex-direction: column;
        overflow-x: visible;
        border-bottom: none;
        border-right: 1px solid var(--border);
        padding-right: 14px;
        width: 190px;
        flex-shrink: 0;
        gap: 2px;
    }
    .settings-tab {
        justify-content: flex-start;
        white-space: normal;
        border-bottom: none;
        border-left: 2px solid transparent;
        border-radius: 6px;
        margin-bottom: 0;
        padding: 9px 12px;
    }
    .settings-tab:hover { background: var(--surface-2); }
    .settings-tab.active { background: var(--surface-2); border-left-color: var(--accent); }
}

.theme-picker { display: inline-flex; gap: 4px; background: var(--surface-2); border-radius: 10px; padding: 4px; }
.theme-option {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 16px;
    background: none;
    border: none;
    border-radius: 8px;
    color: var(--muted);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.12s, color 0.12s;
}
.theme-option:hover { color: var(--text); }
.theme-option.active { background: var(--card); color: var(--text); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); }

.ask-card { display: flex; flex-direction: column; gap: 14px; }
.ask-messages { display: flex; flex-direction: column; gap: 14px; min-height: 320px; max-height: 60vh; overflow-y: auto; padding: 4px; }

/* Empty-state hero — this tool can see the same data every other page
   renders, so the blank state should sell that rather than read as a
   placeholder. */
.ask-hero { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 10px; padding: 32px 16px; }
.ask-hero-icon {
    display: flex; align-items: center; justify-content: center;
    width: 52px; height: 52px; border-radius: 50%;
    background: color-mix(in srgb, var(--accent) 14%, transparent);
    color: var(--accent);
    margin-bottom: 4px;
}
.ask-hero-icon .lucide { width: 24px; height: 24px; }
.ask-hero-title { margin: 0; font-family: var(--th-font-display); font-weight: 800; font-stretch: 125%; font-size: 22px; letter-spacing: -0.01em; }
.ask-hero-sub { margin: 0; max-width: 40ch; color: var(--muted); font-size: 14px; line-height: 1.5; }
.ask-chip-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 6px; max-width: 480px; }
.ask-chip {
    padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border);
    background: var(--card); color: var(--text); font-size: 13px; font-weight: 500;
    cursor: pointer; transition: background 0.12s, border-color 0.12s;
}
.ask-chip:hover { background: var(--surface-2); border-color: var(--muted); }

.ask-msg { display: flex; gap: 8px; align-items: flex-end; }
.ask-msg-user { justify-content: flex-end; }
.ask-msg-assistant { justify-content: flex-start; }
.ask-msg-avatar {
    display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    width: 26px; height: 26px; border-radius: 50%; margin-bottom: 2px;
    background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent);
}
.ask-msg-avatar .lucide { width: 14px; height: 14px; }
.ask-msg-bubble {
    max-width: 75%;
    padding: 11px 15px;
    border-radius: 16px;
    font-size: 14px;
    line-height: 1.5;
}
.ask-msg-user .ask-msg-bubble { background: var(--accent); color: var(--on-accent); border-bottom-right-radius: 4px; }
.ask-msg-assistant .ask-msg-bubble { background: var(--card); border: 1px solid var(--border); border-bottom-left-radius: 4px; box-shadow: var(--shadow-card); }
.ask-msg-pending { display: flex; align-items: center; gap: 8px; color: var(--muted); }
.ask-msg-bubble p { margin: 0 0 8px; }
.ask-msg-bubble p:last-child { margin-bottom: 0; }
.ask-msg-bubble ul, .ask-msg-bubble ol { margin: 0 0 8px; padding-left: 20px; }
.ask-msg-bubble ul:last-child, .ask-msg-bubble ol:last-child { margin-bottom: 0; }
.ask-msg-bubble li { margin-bottom: 2px; }
.ask-msg-bubble strong { font-weight: 700; }
.ask-msg-bubble code { background: rgba(128,128,128,0.15); padding: 1px 5px; border-radius: 4px; font-size: 0.9em; }

.ask-composer {
    display: flex; align-items: center; gap: 6px;
    padding: 6px 6px 6px 18px; border-radius: 999px;
    background: var(--card); border: 1px solid var(--border);
    transition: border-color 0.12s;
}
.ask-composer:focus-within { border-color: var(--accent); }
.ask-composer input {
    flex: 1; border: none; background: none; outline: none;
    font: 400 14px/1.4 var(--th-font-ui); color: var(--text); padding: 8px 0;
}
.ask-composer input::placeholder { color: var(--muted); }
.ask-send-btn {
    display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    width: 34px; height: 34px; border-radius: 50%; border: none;
    background: var(--accent); color: var(--on-accent); cursor: pointer;
    transition: filter 0.12s;
}
.ask-send-btn:hover { filter: brightness(1.08); }
.ask-send-btn:disabled { opacity: 0.5; cursor: default; filter: none; }
h2 {
    font-size: 16px;
    font-weight: 600;
    margin: 0 0 12px;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 8px;
    letter-spacing: -0.005em;
}
h3 { display: flex; align-items: center; gap: 8px; }

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

/* One consistent legend style for every chart in the app — dataset legends
   (rendered by renderChartLegend()) and the static phase-color legend alike. */
.chart-legend {
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
    justify-content: flex-end;
    margin: -6px 0 14px;
    font-size: 12px;
    color: var(--muted);
}
.chart-legend-item { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.chart-legend-item.clickable { cursor: pointer; user-select: none; }
.chart-legend-item.clickable:hover { color: var(--text); }
.chart-legend-item.legend-hidden { opacity: 0.35; text-decoration: line-through; }
.legend-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }

/* Pairs a chart's own dataset legend (left) with the static phase-color
   legend (right) on one line, when a chart has both. */
.chart-legend-row { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin: -6px 0 14px; }
.chart-legend-row .chart-legend { margin: 0; }
.chart-legend-row .chart-legend:first-child { justify-content: flex-start; }

.race-flag { display: inline-flex; color: var(--accent); margin-left: 6px; vertical-align: -2px; }

main {
    max-width: 900px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 20px;
}

main.wide { max-width: 1400px; }

/* Every Chart.js canvas here declares a small `height` attribute (a legacy
   aspect-ratio hint Chart.js reads before it takes over sizing) — until its
   JS actually runs, the browser lays it out at that raw ~90px, then Chart.js
   resizes it to its real responsive height (~200-350px) once a chart is
   created. That growth-on-load is what reads as the page "bouncing" on
   first load — reserving realistic space up front avoids it.
   This floor belongs on the *wrapper* Chart.js measures (.th-canvas-wrap,
   from loaders.js withCanvasChartLoading), not on the canvas element
   itself: Chart.js sets the canvas's own `height` via inline style once it
   initializes, and CSS min-height on that same element only ever acts as
   an extra floor on top of it (min-height wins over a smaller inline
   height — they aren't the same property, so specificity doesn't apply) —
   forcing the canvas's CSS box taller than the bitmap Chart.js actually
   drew at, which stretches and blurs it. Constraining the wrapper instead
   lets Chart.js measure and draw at the reserved size correctly the first
   time, with nothing left to conflict with afterwards.

   A flat min-height wasn't enough on its own, though: none of these
   charts set an explicit aspectRatio, so with maintainAspectRatio (the
   default) Chart.js locks onto the ratio implied by the bare <canvas>
   element's own width/height *HTML attributes* at creation — default
   width 300 over whatever `height="N"` the template gave it (90 for most
   charts here) — and keeps that ratio through every later resize,
   regardless of the container's own size. A flat 220px (or a generic
   2:1) floor doesn't match that per-chart ratio, so the wrapper still
   grew or shrank out from under the loader once the real chart replaced
   it — read as the whole page "bouncing". withCanvasChartLoading (in
   loaders.js) sets this wrapper's aspect-ratio inline from that same
   canvas attribute before anything ever draws into it, so the two always
   agree; the aspect-ratio below is only a fallback for the instant before
   that JS runs. */
.th-canvas-wrap { aspect-ratio: 300 / 90; min-height: 160px; }

/* Reserve roughly the same space these JS-populated containers end up
   with, matching the height their loading skeleton uses (see loaders.js
   withChartLoading calls) — so the very first paint doesn't start at 0
   and then jump once data arrives. */
#lifetime-stats, #personal-bests-groups { min-height: 130px; }
#heatmap { min-height: 140px; }
#power-curve { min-height: 100px; }
#hr-zones { min-height: 90px; }
#overall-summary { min-height: 240px; }

/* JS-populated placeholder containers (forms, banners, review queues) still
   count as flex children — and so still eat a `gap` — even with zero height
   while empty, which reads as unexplained blank space above the next card. */
main > div:empty { display: none; }

.goal-card { border: 1px solid var(--accent); }
.goal-card-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px; margin-bottom: 12px; }
.goal-card-header h2 { margin: 0; }

.tile-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }

.tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 14px 20px;
    cursor: pointer;
    color: var(--text);
    font-size: 13px;
    min-width: 84px;
    transition: border-color 0.15s, background 0.15s, transform 0.1s;
}
.tile:hover { border-color: var(--accent); transform: translateY(-1px); }
.tile-selected { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--card)); box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent); }
.tile-icon { font-size: 24px; }
.tile-label { font-weight: 500; }
.tile-small { padding: 8px 14px; min-width: unset; }
.tile-small .tile-label { font-weight: 400; }

.goal-description { margin: 8px 0 0; }

.badge {
    font-size: 11px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 999px;
    margin-left: auto;
}
.badge-key { background: color-mix(in srgb, var(--positive) 15%, transparent); color: var(--positive); }
.badge-secondary { background: rgba(144, 153, 168, 0.15); color: var(--muted); }

.disc-card-secondary { opacity: 0.6; }

.global-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    margin-bottom: 16px;
}
.global-field {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 12px;
}
.global-field.field-modified { border-color: var(--accent); }
.global-field label { display: block; font-size: 13px; font-weight: 600; margin-bottom: 6px; }
.global-field input { width: 100%; margin-bottom: 6px; }
.field-desc { margin: 4px 0; }
.field-default { margin: 0; font-style: italic; }

.goal-time-inputs { display: flex; align-items: center; gap: 6px; }
/* Split calculator's Delta column — predicted vs. goal-time split. */
.split-delta-behind { color: var(--negative); font-weight: 600; }
.split-delta-ahead { color: var(--positive); font-weight: 600; }
.goal-time-inputs input { width: 56px; flex: none; text-align: center; margin-bottom: 0; -moz-appearance: textfield; }
.goal-time-inputs input::-webkit-outer-spin-button, .goal-time-inputs input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.goal-time-inputs span { color: var(--muted); font-size: 13px; margin-right: 4px; }

.logic-actions { display: flex; align-items: center; gap: 12px; margin-top: 12px; }

.mix-type-heading { font-size: 15px; margin: 20px 0 8px; color: var(--muted); }
.mix-type-heading:first-child { margin-top: 0; }

.mix-config-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-bottom: 8px; }
.mix-config-table th { text-align: left; color: var(--muted); font-weight: 500; padding: 6px 8px; border-bottom: 1px solid var(--border); }
.mix-config-table td { padding: 8px; border-bottom: 1px solid var(--border); vertical-align: middle; }

.mix-cell-inner { display: flex; align-items: center; gap: 4px; white-space: nowrap; }
.mix-cell-icon { font-size: 14px; }
.mix-input {
    width: 46px;
    background: var(--card);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 4px;
    font-size: 12px;
}
.mix-weight { margin-left: 6px; font-weight: 600; color: var(--accent); font-size: 12px; }
.mix-row-actions { display: flex; gap: 6px; white-space: nowrap; }

.health-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    background: #2a1f10;
    border: 1px solid #7a5a1e;
    border-radius: 10px;
    padding: 14px 18px;
    margin-bottom: 20px;
}
.health-banner-text { font-size: 14px; }
.health-banner-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.health-form-card { margin-bottom: 20px; }
.health-form-card label { display: block; font-size: 12px; color: var(--muted); margin: 8px 0 4px; }
.health-form-card input, .health-form-card textarea, .health-form-card select { width: 100%; }
/* flex, not grid — a form row shouldn't stretch its fields to fill the
   card the way a card grid does; with only 2 fields (e.g. Type/Distance)
   in a wide card, grid's auto-fit 1fr pushed them to opposite edges with
   a huge gap between. Fields now sit compactly, left-aligned. */
.health-form-row { display: flex; flex-wrap: wrap; gap: 12px; }
.health-form-row > * { flex: 0 1 220px; min-width: 160px; }

.health-events-list { display: flex; flex-direction: column; gap: 10px; }
.health-event-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 8px;
    background: var(--bg);
    border-left: 4px solid;
}
.health-event-row.illness { border-color: #e0577a; }
.health-event-row.injury { border-color: #f4a261; }
.health-event-row.taper { border-color: #90999a; }
.health-event-row.recovery { border-color: #3d5afe; }
.health-event-main { font-size: 14px; }
.health-event-meta { color: var(--muted); font-size: 12px; }

/* Section label above each of the Races page's two stacked lists
   (upcoming, then past — both always visible, no tab to switch). */
.race-list-heading {
    display: flex; align-items: center; gap: 8px;
    margin: 20px 0 10px; font-size: 14px; font-weight: 600; color: var(--muted);
}
.race-list-heading:first-of-type { margin-top: 16px; }

.race-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 14px;
    border-radius: 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    margin-bottom: 10px;
}
.race-card-main { cursor: pointer; flex: 1; min-width: 0; }
.race-card-main:hover .race-name { color: var(--accent); text-decoration: underline; }

/* The Goal page's "which upcoming race is this actually for" link — a
   compact one-line card in the same family as .race-card, styled as a
   link (the whole thing navigates to the Races page). */
.linked-race-card {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 12px;
    padding: 10px 14px;
    border-radius: 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--text);
    text-decoration: none;
}
.linked-race-card:hover { border-color: var(--accent); }
.linked-race-card:hover strong { color: var(--accent); }
.race-countdown { font-size: 28px; font-weight: 700; color: var(--accent); }
.race-name { font-weight: 600; }
.race-meta { color: var(--muted); font-size: 13px; }
/* A quick glance at what's been backfilled for a past race yet — see
   raceDataSummaryHTML() in races.js. */
.race-data-summary { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }
.race-data-chip { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--muted); }
.race-data-chip .lucide { width: 13px; height: 13px; }
.race-data-chip.is-filled { color: var(--positive); }

.race-legs { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.race-leg-row {
    display: grid;
    grid-template-columns: 24px 1fr 90px 70px 90px 90px;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 13px;
    text-decoration: none;
    color: var(--text);
}
.race-leg-row:hover { border-color: var(--accent); }
.race-leg-icon { display: flex; color: var(--accent); }
.race-leg-name { font-weight: 500; }

/* T1/T2 logging in the race-detail popup — legs alone always undercount
   a multi-leg race's real result, so this fills the gap manually. */
.race-transitions { margin-top: 0; }
.race-transitions-row { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.race-transitions-row label { flex: 1; min-width: 0; margin: 0; font-size: 13px; color: var(--muted); }
.race-transitions-total { font-size: 14px; margin-top: 4px; }
#rr-overall-fields:disabled, #rr-ag-fields:disabled { opacity: 0.4; }

/* The race-detail popup accumulated a lot of features (distance/category,
   legs, transitions, results-finder, manual results) all in one flat
   stack — grouped into clearly titled sections instead, each with its
   own top border, so it reads as a sequence of small forms rather than
   one long one. */
.race-detail-section { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
.race-detail-section:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.race-detail-section-title {
    display: flex; align-items: center; gap: 8px;
    font-size: 14px; font-weight: 600; margin: 0 0 12px;
}
.race-detail-section-title .lucide { width: 16px; height: 16px; color: var(--muted); }
.race-results-import-row { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 4px; }
.race-results-manual-title { font-size: 13px; font-weight: 600; color: var(--muted); margin: 14px 0 10px; }

.gap-context-cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin: 12px 0;
}
.gap-context-label { font-size: 12px; font-weight: 600; color: var(--muted); margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.02em; }
.gap-activity-row {
    display: grid;
    grid-template-columns: 76px 1fr 60px 60px 64px;
    gap: 8px;
    font-size: 12px;
    padding: 4px 0;
    border-bottom: 1px solid var(--border);
    color: var(--text);
}
.gap-activity-row span:nth-child(2) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hr-flag {
    background: rgba(244, 162, 97, 0.12);
    border: 1px solid rgba(244, 162, 97, 0.4);
    border-radius: 8px;
    padding: 8px 12px;
    font-size: 13px;
    margin: 10px 0;
}
.gap-data-note { font-style: italic; margin-top: 8px; }
.closest-race-note {
    background: rgba(244, 197, 0, 0.1);
    border: 1px solid rgba(244, 197, 0, 0.35);
    border-radius: 8px;
    padding: 8px 12px;
    font-size: 13px;
    margin-bottom: 10px;
}

/* Metrics are the loudest thing on most screens (brand type scale): every
   prominent number reads in tabular IBM Plex Mono, not the UI face. */
.stat-card-value, .disc-pct, .gauge-pct, .race-countdown, .mix-weight {
    font-family: var(--th-font-data);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

/* Top-lit gradient surface + a corner spotlight tinted by the card's own
   "glow" color. Only cards that opt in via --card-glow (the :has()
   selectors below, one per chart) get a visible spotlight — a card with
   no chart identity has nothing meaningful to tint it, and defaulting
   the glow to the plain --accent painted every card (stat tiles, text
   panels) with the same generic accent wash, which reads as a stain
   rather than a chart-specific highlight. */
.card {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    background: linear-gradient(180deg, color-mix(in srgb, var(--text) 5%, var(--card)) 0%, var(--card) 55%);
    border: 1px solid color-mix(in srgb, var(--text) 9%, transparent);
    border-radius: 20px;
    padding: 22px 22px 18px;
    box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 9%, transparent), var(--shadow-card);
}
.card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 240px;
    z-index: -1;
    pointer-events: none;
    background: radial-gradient(72% 100% at 88% -10%, color-mix(in srgb, var(--card-glow, transparent) 15%, transparent), transparent 72%);
}

/* Tints each chart card's corner spotlight (--card-glow, used by .card::
   before above) to that chart's own series color — "a corner spotlight
   tinted by the chart's own colour" — without needing to touch the JS
   that renders into each canvas. */
.card:has(#fitness-chart) { --card-glow: #2DD4BF; }
.card:has(#hr-zone-series-chart) { --card-glow: #FF5D8F; }
.card:has(#hrv-chart) { --card-glow: #9F8CFF; }
.card:has(#weight-chart), .card:has(#resting-hr-chart) { --card-glow: #FF5D8F; }
.card:has(#vo2max-chart) { --card-glow: #6FA83A; }
.card:has(#readiness-series-chart) { --card-glow: var(--accent); }
.card:has(#tc-chart) { --card-glow: var(--accent); }

.btn {
    display: inline-block;
    background: var(--accent);
    color: var(--on-accent);
    padding: 8px 16px;
    border-radius: 6px;
    text-decoration: none;
    border: none;
    cursor: pointer;
    font-weight: 500;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    transition: filter 0.12s, transform 0.06s;
    font-size: 14px;
}
.btn:hover { filter: brightness(1.08); }
.btn:active { transform: scale(0.98); }

.btn-secondary {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text);
    box-shadow: none;
}
.btn-secondary:hover { filter: none; border-color: var(--muted); }

.select {
    background: var(--card);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 13px;
}

/* The page's title + its sticky filter/range controls share one purple
   bar in the sidebar's own color, flush against the top of the viewport
   (canceling body's top padding) so it reads as the sidebar's rail
   continuing across the top — an "L" of matching chrome around the
   content rather than a separate bordered header. */
.filter-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    margin: -24px -16px 24px -16px;
    padding: 12px 20px;
    position: sticky;
    top: 0;
    z-index: 150;
    background: var(--sidebar-bg);
}
/* A second filter bar further down a page (e.g. Readiness's chart-scoped
   Day/Week/Month/Year controls) isn't page chrome — reusing the dark,
   sticky, sidebar-colored bar there reads as a second, disconnected nav
   rail stranded mid-page. Giving this variant its own card-like box (an
   earlier attempt: background/border/radius) just traded one detached
   floating element for another. This one isn't boxed at all — a plain
   control row sitting directly in the page flow, the same way a .hint
   paragraph does, so there's no rectangle left to look disconnected. */
.filter-bar.filter-bar-inline {
    position: static;
    margin: 0 0 16px;
    padding: 0;
    background: none;
    border: none;
}
.filter-bar-title {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--sidebar-text-active);
    font-size: 16px;
    font-weight: 700;
    white-space: nowrap;
}
.filter-bar-title .lucide { width: 20px; height: 20px; color: var(--accent); }
.filter-bar-controls { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.filter-bar-divider { width: 1px; height: 20px; background: var(--sidebar-border); margin: 0 2px; }
.filter-bar .hint { color: var(--sidebar-text); }
.filter-bar .btn-secondary { color: var(--sidebar-text-active); border-color: var(--sidebar-border); }
.filter-bar .btn-secondary:hover { border-color: var(--sidebar-text); }
.filter-bar.filter-bar-inline .hint { color: var(--muted); }
.filter-bar.filter-bar-inline .btn-secondary { color: var(--text); border-color: var(--border); }
.filter-bar.filter-bar-inline .btn-secondary:hover { border-color: var(--muted); }
.filter-bar.filter-bar-inline .filter-bar-divider { background: var(--border); }

.segmented {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--card);
    padding: 3px;
    gap: 2px;
}
.segmented button {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: transparent;
    border: none;
    color: var(--muted);
    padding: 6px 11px;
    font-size: 13px;
    border-radius: 6px;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.12s, color 0.12s, transform 0.06s;
}
.segmented button:hover:not(.seg-active) { background: var(--surface-2); color: var(--text); }
.segmented button.seg-active {
    background: var(--accent);
    color: var(--on-accent);
    font-weight: 600;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.segmented button:active { transform: scale(0.96); }

/* ---------- Readiness: training comparison ---------- */
.tc-controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.tc-race-list { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.tc-race-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px 6px 10px; border-radius: 999px; border: 1px solid var(--border);
    background: var(--card); font-size: 13px; cursor: pointer; user-select: none;
    transition: border-color 0.12s, background 0.12s;
}
.tc-race-chip input { margin: 0; accent-color: var(--accent); }
.tc-race-chip:hover { border-color: var(--muted); }
.tc-race-chip.is-checked { border-color: var(--tc-chip-color, var(--accent)); background: color-mix(in srgb, var(--tc-chip-color, var(--accent)) 10%, var(--card)); }
.tc-race-chip-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--tc-chip-color, var(--accent)); flex-shrink: 0; }
.seg-icon { font-size: 13px; line-height: 1; }

.switch-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    font-size: 13px;
    color: var(--muted);
    user-select: none;
}
.switch-track {
    position: relative;
    width: 38px;
    height: 22px;
    background: var(--border);
    border-radius: 11px;
    transition: background 0.15s;
    flex-shrink: 0;
}
.switch-track::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    background: #fff;
    border-radius: 50%;
    transition: transform 0.15s;
}
.switch-toggle input { display: none; }
.switch-toggle input:checked + .switch-track { background: var(--accent); }
.switch-toggle input:checked + .switch-track::after { transform: translateX(16px); }

.date-input { width: 140px; padding: 6px 8px; }

.custom-range { position: relative; }
.custom-range-toggle.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.custom-range-popover {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    flex-direction: column;
    gap: 10px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 14px;
    box-shadow: var(--shadow-card);
    z-index: 200;
    min-width: 190px;
}
.custom-range-popover.open { display: flex; }
.custom-range-popover label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); }
.btn-small { padding: 6px 10px; font-size: 13px; }
.btn-taper { background: #6b7280; }
.btn-recovery { background: #3d5afe; }

.axis-picker {
    display: flex;
    gap: 24px;
    align-items: flex-end;
    margin-bottom: 16px;
    flex-wrap: wrap;
}
.axis-picker label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 4px; }

.gap-toggle-label { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); cursor: pointer; white-space: nowrap; }

.burst-day-card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 12px 14px;
    margin-bottom: 10px;
}
.burst-day-header { display: flex; justify-content: space-between; align-items: center; cursor: pointer; }
.burst-activities { display: none; margin-top: 10px; }
.burst-activities.open { display: block; }
.burst-activity-row {
    display: grid;
    grid-template-columns: 130px 1fr 90px 70px 90px;
    gap: 8px;
    align-items: center;
    font-size: 13px;
    padding: 6px 0;
    border-top: 1px solid var(--border);
}
.drilldown-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    z-index: 1000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 40px 20px;
    overflow-y: auto;
}
.drilldown-modal {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 24px;
    max-width: 1100px;
    width: 100%;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.drilldown-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
.drilldown-header h3 { margin: 0 0 4px; font-size: 18px; }
.drilldown-summary { font-size: 13px; color: var(--muted); margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.drilldown-table-wrap { max-height: 60vh; overflow-y: auto; }
.drilldown-table-wrap table { font-size: 13px; }
.chart-clickable { cursor: pointer; }

.data-link { color: var(--text); text-decoration: none; font-weight: 500; }
.data-link:hover { color: var(--accent); text-decoration: underline; }

.excluded-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 8px;
    font-size: 13px;
}

/* flex, not grid — grid's auto-fit locks every row to the same column
   tracks, so a leftover item alone on the last row (e.g. 5 cards at a
   width that fits 4 per row) can't stretch to fill it and leaves a huge
   gap. Flex-wrap distributes growth per row, so a lone last item always
   fills the row it's on. */
.discipline-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}
.discipline-grid > * { flex: 1 1 220px; min-width: 220px; }

#compare-charts.discipline-grid { gap: 20px; }
#compare-charts.discipline-grid > * { flex-basis: 460px; }
.compare-metric-card h3 { font-size: 15px; margin: 0 0 12px; }

.stat-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}
.stat-cards > * { flex: 1 1 220px; min-width: 220px; }
/* Plain fallback tile — kinds the KPI-tile redesign below doesn't cover
   yet (a race-goal view's "Races confirmed" / "Next race"). */
.stat-card {
    display: flex; align-items: center; gap: 12px; min-width: 0;
    background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px;
}
.stat-card-icon {
    display: flex; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
    border-radius: 8px; padding: 8px; flex-shrink: 0;
}
.stat-card-icon .lucide { width: 20px; height: 20px; }
.stat-card-body { min-width: 0; flex: 1; }
.stat-card-value-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.stat-card-value { font-size: 22px; font-weight: 700; line-height: 1.1; }
.stat-card-label { color: var(--muted); font-size: 12px; margin-top: 2px; }
.sparkline { width: 56px; height: 22px; flex-shrink: 0; opacity: 0.85; }

/* ---------- KPI tiles: each number gets a picture that explains it ----------
   (ActivitiesTile/EarthTile/DaysTile/EverestTile/DialTile/StreakTile) —
   ported from the trihard-ui design kit's records.tsx. Each tile carries
   its own --tone (an accent color) for its icon chip and corner glow. */
.th-kpi {
    position: relative; overflow: hidden; isolation: isolate;
    display: flex; flex-direction: column; gap: 12px; min-width: 0; max-width: 420px;
    padding: 16px 18px 15px; border-radius: 20px;
    background: var(--card); border: 1px solid var(--border);
}
.th-kpi::before {
    content: ""; position: absolute; right: -25%; top: -45%; width: 80%; height: 130%;
    z-index: -1; pointer-events: none;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--tone) 24%, transparent), transparent);
}
.th-kpi__head { display: flex; align-items: center; gap: 10px; font: 500 13px/1 var(--th-font-ui); color: var(--muted); }
.th-kpi__ico {
    display: grid; place-items: center; width: 28px; height: 28px; border-radius: 9px;
    color: var(--tone); background: color-mix(in srgb, var(--tone) 16%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tone) 32%, transparent);
}
.th-kpi__row { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; min-width: 0; }
.th-kpi__cap { font: 500 12px/1.35 var(--th-font-ui); color: var(--muted); }
.th-kpi__subcap { opacity: 0.7; }
.th-gauge-num { fill: var(--text); font: 600 17px/1 var(--th-font-data); }
.th-gauge-tick { fill: var(--muted); font: 500 10px/1 var(--th-font-data); }
/* EarthTile's arc fill-in and DialTile's needle sweep — both rendered at
   their resting state with the real value stashed in a data attribute,
   applied a frame later by mountKpiMotion() (filters.js) so these
   transitions have a "from" state to animate from. */
.th-earth-arc { transition: stroke-dashoffset 1500ms cubic-bezier(.16, .84, .24, 1); }
.th-dial-needle { transition: transform 1300ms cubic-bezier(.3, 1.5, .5, 1); }
@media (prefers-reduced-motion: reduce) { .th-earth-arc, .th-dial-needle, .th-days i { transition: none; animation: none; } }
.th-days { display: grid; grid-template-columns: repeat(auto-fill, 10px); gap: 3px; max-width: 100%; }
.th-days i { width: 10px; height: 10px; border-radius: 3px; background: linear-gradient(135deg, var(--th-violet), color-mix(in srgb, var(--th-violet) 55%, var(--th-rose))); animation: th-fade-in 500ms var(--th-ease) both; }
.th-days i.is-last { box-shadow: 0 0 10px var(--th-violet); }
.th-flame { overflow: visible; }
.th-flame.is-live { transform-origin: 50% 90%; animation: th-flicker 1.6s ease-in-out infinite alternate; filter: drop-shadow(0 0 10px color-mix(in srgb, var(--th-bike) 70%, transparent)); }
@keyframes th-flicker { from { transform: scale(1, 1) rotate(-1deg); } to { transform: scale(1.04, 0.97) rotate(1deg); } }
.th-weeks { display: flex; gap: 5px; }
.th-weeks i { flex: 1; height: 8px; max-width: 18px; border-radius: 3px; background: color-mix(in srgb, var(--text) 10%, transparent); }
.th-weeks i.is-on { background: linear-gradient(180deg, var(--th-gold), var(--th-bike)); box-shadow: 0 0 8px -1px var(--th-bike); }
.th-odo {
    display: inline-flex; align-items: baseline; gap: .05em; max-width: 100%; white-space: nowrap;
    line-height: 1.12; font-family: var(--th-font-data); font-weight: 600; font-variant-numeric: tabular-nums;
    color: var(--odo, var(--text));
}
/* Mechanical rolling digits — mountOdometers() (filters.js) sets each
   drum's strip to translateY(-Nch * 1.12em) one frame after insertion,
   so the CSS transition below actually has a "from" state to animate. */
.th-odo__drum { position: relative; display: inline-block; height: 1.12em; overflow: hidden; padding: 0 .03em; border-radius: .16em; }
.th-odo__strip { display: flex; flex-direction: column; transition: transform 1500ms cubic-bezier(.16, .84, .24, 1); }
.th-odo__strip span { display: block; width: .6em; height: 1.12em; line-height: 1.12em; text-align: center; }
.th-odo__sep { opacity: .65; margin: 0 -.02em; }
.th-odo__unit { margin-left: .28em; font: 500 .38em/1 var(--th-font-ui); letter-spacing: .02em; color: var(--muted); }
@media (prefers-reduced-motion: reduce) { .th-odo__strip { transition: none; } }
.th-chip { display: inline-flex; align-items: center; gap: 4px; height: 22px; padding: 0 8px; border-radius: 999px; font: 600 12px/1 var(--th-font-data); font-variant-numeric: tabular-nums; }
.th-chip--good { color: var(--positive); background: color-mix(in srgb, var(--positive) 14%, transparent); }
.th-chip--bad { color: var(--negative); background: color-mix(in srgb, var(--negative) 14%, transparent); }

/* ---------- Lifetime distance by discipline (LifetimeBar + DisciplineCard) ---------- */
.th-life { display: flex; flex-direction: column; gap: 12px; }
.th-life__bar { display: flex; gap: 3px; height: 16px; }
.th-life__bar span { flex-basis: 0; min-width: 6px; border-radius: 6px; }
.th-life__legend { display: flex; flex-wrap: wrap; gap: 8px 22px; font: 500 13px/1 var(--th-font-ui); color: var(--muted); align-items: center; }
.th-life__legend i { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 8px; }
.th-life__legend b { font: 600 13px/1 var(--th-font-data); color: var(--text); margin-left: 4px; }
.th-life__total { margin-left: auto; font: 600 13px/1 var(--th-font-data); color: var(--text); }
/* flex, not grid — see .discipline-grid above for why (a lone card on the
   last row needs to stretch to fill it, which grid's auto-fit can't do). */
/* margin-top, not gap on the shared #lifetime-stats parent — .th-life
   (the share bar) and .th-discs are unrelated siblings dropped into that
   parent's innerHTML, so the parent has no gap of its own to inherit. */
.th-discs { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 20px; }
.th-discs > * { flex: 1 1 220px; min-width: 220px; }
.th-disc {
    position: relative; isolation: isolate; overflow: hidden;
    display: flex; flex-direction: column; gap: 16px; min-width: 0; max-width: 480px; padding: 18px 18px 16px; border-radius: 22px;
    background: var(--card);
    border: 1px solid color-mix(in srgb, var(--c) 45%, transparent);
    box-shadow: inset 0 1px 0 color-mix(in srgb, var(--c) 45%, transparent);
}
.th-disc__mark { position: absolute; right: -26px; bottom: -22px; z-index: -1; color: var(--c); opacity: .09; transform: rotate(-8deg); }
.th-disc__mark .lucide { width: 150px; height: 150px; }
.th-disc__head { display: flex; align-items: center; gap: 10px; }
.th-disc__head b { font: 700 16px/1 var(--th-font-ui); }
.th-disc__ico { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 10px; color: var(--c); background: color-mix(in srgb, var(--c) 16%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 34%, transparent); }
.th-disc__count { margin-left: auto; font: 500 12px/1 var(--th-font-ui); color: var(--muted); }
.th-disc__track { height: 8px; border-radius: 4px; overflow: hidden; background: color-mix(in srgb, var(--text) 9%, transparent); }
.th-disc__track i { display: block; height: 100%; border-radius: 4px; transition: width 1500ms cubic-bezier(.16, .84, .24, 1); box-shadow: 0 0 12px -1px var(--c); }
.th-disc__miletext { display: flex; justify-content: space-between; margin-top: 8px; font: 500 12px/1 var(--th-font-ui); color: var(--muted); }
.th-disc__miletext b { font-family: var(--th-font-data); color: var(--text); font-weight: 600; }
.th-disc__stats { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 0; padding-top: 12px; border-top: 1px solid color-mix(in srgb, var(--text) 10%, transparent); }
.th-disc__stats dt { font: 500 11px/1 var(--th-font-ui); color: var(--muted); margin-bottom: 6px; }
.th-disc__stats dd { margin: 0; font: 600 14px/1 var(--th-font-data); font-variant-numeric: tabular-nums; color: var(--text); }
@media (prefers-reduced-motion: reduce) { .th-disc__track i { transition: none; } }

/* ---------- TrophyCase: the Personal Bests medal wall ---------- */
.th-cases { display: grid; gap: 16px; }
.th-case {
    position: relative; isolation: isolate; overflow: hidden; padding: 18px 22px 24px; border-radius: 22px;
    background: linear-gradient(180deg, color-mix(in srgb, var(--case) 9%, var(--card)), var(--card) 62%);
    border: 1px solid color-mix(in srgb, var(--case) 30%, transparent);
    box-shadow: inset 0 1px 0 color-mix(in srgb, var(--case) 30%, transparent);
}
.th-case::before { content: ""; position: absolute; inset: 0 0 35% 0; z-index: -1; background: radial-gradient(64% 100% at 50% 0%, color-mix(in srgb, var(--case) 20%, transparent), transparent 72%); }
.th-case__head { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.th-case__ico { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 10px; color: var(--case); background: color-mix(in srgb, var(--case) 16%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--case) 34%, transparent); }
.th-case__head h4 { margin: 0; font: 700 19px/1 var(--th-font-ui); }
.th-case__count { margin-left: auto; font: 500 12px/1 var(--th-font-data); color: var(--muted); }
.th-case__rail { position: relative; height: 9px; border-radius: 5px; margin-bottom: 16px; background: linear-gradient(180deg, color-mix(in srgb, var(--text) 40%, transparent), color-mix(in srgb, var(--text) 9%, transparent)); box-shadow: 0 8px 16px -8px rgb(0 0 0 / .6); }
.th-case__row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; align-items: start; }
.th-case__item { position: relative; margin: 0; display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.th-case__cone {
    position: absolute; top: 0; left: 50%; width: 160%; height: 100%; z-index: -1; transform: translateX(-50%); pointer-events: none;
    clip-path: polygon(46% 0, 54% 0, 100% 100%, 0 100%);
    background: linear-gradient(180deg, color-mix(in srgb, var(--case) 26%, transparent), transparent 88%); opacity: .75;
}
.th-case__medal { position: relative; }
.th-case__event { position: absolute; right: -14px; bottom: 4px; }
.th-case__item figcaption { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.th-case__time { font: 600 21px/1 var(--th-font-data); font-variant-numeric: tabular-nums; letter-spacing: -.02em; color: var(--text); }
.th-case__name { font: 700 10.5px/1.2 var(--th-font-ui); letter-spacing: .1em; text-transform: uppercase; color: var(--case); }
.th-case__meta { font: 500 12px/1.35 var(--th-font-ui); color: var(--muted); }
.th-case__item.is-locked .th-case__time { font: 500 15px/1 var(--th-font-ui); color: var(--muted); letter-spacing: 0; }
.th-case__item.is-locked .th-case__name { color: var(--muted); opacity: .8; }
.th-medal { display: block; overflow: visible; transform-origin: 50% 0; animation: th-sway 7s ease-in-out infinite alternate; }
.th-medal.is-locked { filter: grayscale(1); opacity: .34; animation: none; color: var(--text); }
@keyframes th-sway { from { transform: rotate(-1.8deg); } to { transform: rotate(1.8deg); } }
.th-medal__label { font: 800 30px/1 var(--th-font-display); font-stretch: 125%; letter-spacing: -.02em; fill: #101820; }
.th-twinkle { transform-box: fill-box; transform-origin: center; animation: th-twinkle 2.4s ease-in-out infinite; }
@keyframes th-twinkle { 0%, 100% { transform: scale(1) rotate(0); } 50% { transform: scale(1.22) rotate(14deg); } }
@media (prefers-reduced-motion: reduce) { .th-medal, .th-twinkle { animation: none; } }

/* ---------- RecordPlaque: hardest effort / longest activity / biggest week ---------- */
.records-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}
.records-row > * { flex: 1 1 220px; min-width: 220px; }
.th-plaque {
    position: relative; isolation: isolate; overflow: hidden;
    display: flex; flex-direction: column; gap: 10px; min-width: 0;
    padding: 18px 20px 16px; border-radius: 20px;
    background: var(--card); border: 1px solid var(--border);
    cursor: pointer; transition: transform 0.12s;
}
.th-plaque:not([data-activity-id]) { cursor: default; }
.th-plaque:hover { transform: translateY(-2px); }
.th-plaque::after {
    content: ""; position: absolute; right: -40px; top: -40px; width: 160px; height: 160px; border-radius: 50%; z-index: -1;
    border: 1px solid color-mix(in srgb, var(--tone) 22%, transparent);
    box-shadow: 0 0 0 18px color-mix(in srgb, var(--tone) 5%, transparent), 0 0 0 40px color-mix(in srgb, var(--tone) 3%, transparent);
}
.th-plaque__top { display: flex; align-items: center; gap: 10px; }
.th-plaque__medallion {
    display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; color: #101820;
    background: radial-gradient(circle at 32% 26%, color-mix(in srgb, var(--tone) 55%, white), var(--tone) 55%, color-mix(in srgb, var(--tone) 55%, black));
    box-shadow: 0 8px 18px -6px var(--tone), inset 0 0 0 2px color-mix(in srgb, white 35%, transparent);
}
.th-plaque__label { font: 700 11px/1.2 var(--th-font-ui); letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.th-plaque__event { margin-left: auto; }
.th-plaque__sub { margin: 0; font: 500 13px/1.4 var(--th-font-ui); color: var(--muted); }
.th-pctl { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.th-pctl__cap { font: 500 12px/1 var(--th-font-ui); color: var(--muted); }
.th-pctl__cap b { font-family: var(--th-font-data); }
.th-event {
    display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px 0 8px; border-radius: 999px;
    font: 700 10px/1 var(--th-font-ui); letter-spacing: .1em; text-transform: uppercase; color: var(--text);
    background: color-mix(in srgb, var(--text) 8%, transparent);
}
/* A real brand mark (see BRAND_ASSETS in filters.js) sits on a small
   white tile so a dark logo stays legible on the dark theme too — falls
   back to the plain .th-event chip above if the file 404s. */
.th-event--logo { width: 26px; height: 26px; padding: 0; justify-content: center; border-radius: 8px; background: #fff; box-shadow: 0 4px 10px -4px rgb(0 0 0 / .5); }
.th-event--logo img { max-width: 76%; max-height: 76%; object-fit: contain; }
.progress-track { height: 8px; background: var(--surface-2); border-radius: 4px; overflow: hidden; margin-top: 10px; }
.progress-fill { height: 100%; background: var(--accent); border-radius: 4px; transition: width 0.2s; }

.heatmap-wrap { overflow-x: auto; padding-bottom: 4px; }
/* Grid layout: months row spans the top, day-labels form a narrow left
   column, and the heat grid fills the remaining cell — the labels sit in
   the same grid row as the heat grid so they stretch to match its height
   (set by the grid's own aspect-ratio) and their 7 sub-rows line up with
   its 7 day-rows. */
.heatmap-composite {
    display: grid;
    grid-template-columns: 26px 1fr;
    grid-template-rows: auto 1fr;
    gap: 4px 6px;
}
.heatmap-months {
    grid-column: 2;
    grid-row: 1;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(6px, 1fr);
    gap: 3px;
}
.heatmap-month-cell { font-size: 10px; color: var(--muted); white-space: nowrap; overflow: visible; }
.heatmap-daylabels {
    grid-column: 1;
    grid-row: 2;
    display: grid;
    grid-template-rows: repeat(7, 1fr);
    gap: 3px;
    font-size: 10px;
    color: var(--muted);
    white-space: nowrap;
}
.heatmap-daylabels div { display: flex; align-items: center; }
.heatmap-grid {
    grid-column: 2;
    grid-row: 2;
    display: grid;
    grid-template-rows: repeat(7, 1fr);
    grid-auto-flow: column;
    grid-auto-columns: minmax(6px, 1fr);
    gap: 3px;
    width: 100%;
    aspect-ratio: 53 / 7;
}
.heat-cell { position: relative; border-radius: 2px; background: var(--surface-2); cursor: default; }
.heat-cell[data-date] { cursor: pointer; }
.heat-cell.heat-pad { background: transparent; }
/* A fixed "heat" scale (cool -> hot) rather than tints of the page's own
   accent color — a distinct, unmistakable ramp reads faster than shades
   of one hue, and doesn't disappear on discipline pages whose accent is
   already used elsewhere on the same card (e.g. records, stat icons). */
.heat-cell.heat-1 { background: #ffd666; }
.heat-cell.heat-2 { background: #ffa93d; }
.heat-cell.heat-3 { background: #ff6b4a; }
.heat-cell.heat-4 { background: #e0293d; }
.heatmap-legend { display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--muted); margin-top: 10px; }
.heatmap-legend .heat-cell { width: 11px; height: 11px; cursor: default; }

.hrzone-bar { display: flex; height: 28px; border-radius: 8px; overflow: hidden; background: var(--surface-2); }
.hrzone-segment { height: 100%; transition: width 0.2s; }
.hrzone-legend {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 8px;
    margin-top: 14px;
}
.hrzone-legend-item { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.hrzone-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.hrzone-legend-value { color: var(--muted); font-size: 12px; margin-left: auto; }

.disc-card {
    background: var(--card);
    border: 1px solid var(--border);
    border-left: 4px solid;
    border-radius: 10px;
    padding: 18px;
    box-shadow: var(--shadow-card);
    transition: transform 0.12s;
}
.disc-card:hover { transform: translateY(-2px); }

.disc-header { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.disc-icon { font-size: 20px; }
.disc-name { font-weight: 600; }
.disc-pct { font-size: 36px; font-weight: 700; line-height: 1; }
.disc-sub { color: var(--muted); font-size: 12px; margin: 4px 0 14px; }
.disc-sub strong { color: var(--text); font-weight: 600; }
/* The readiness composite's per-factor breakdown — see
   metrics.readiness_report() and the Logic settings page for the reasoning. */
.factor-breakdown { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.factor-chip {
    display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--muted);
    background: var(--surface-2); border-radius: 999px; padding: 3px 9px;
}
.factor-chip b { color: var(--text); font-weight: 600; }
.disc-row { display: flex; justify-content: space-between; font-size: 13px; padding: 4px 0; border-top: 1px solid var(--border); }
.disc-row span:first-child { color: var(--muted); }
.disc-row span:last-child { font-weight: 600; }

/* Radial readiness gauge — a 270°-sweep progress ring (gap centered at
   the bottom) built from two stroke-dasharray'd circles, both rotated so
   the gap sits at the bottom. Colored by status (red/amber/green), not
   accent or discipline, since it's a score rather than an identity. */
.readiness-gauge-wrap { display: flex; align-items: center; gap: 32px; flex-wrap: wrap; padding: 4px 0; }
.readiness-gauge { position: relative; width: 190px; height: 190px; flex-shrink: 0; }
.gauge-svg { width: 100%; height: 100%; transform: rotate(125deg); }
.gauge-track { fill: none; stroke: var(--surface-2); stroke-width: 14; stroke-linecap: round; }
.gauge-fill { fill: none; stroke-width: 14; stroke-linecap: round; transition: stroke-dasharray 0.5s ease; }
.gauge-center {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
}
.gauge-pct { font-size: 34px; font-weight: 800; line-height: 1; }
.gauge-label { font-size: 12px; color: var(--muted); margin-top: 6px; max-width: 120px; }

.gauge-side { flex: 1; min-width: 220px; display: flex; flex-direction: column; gap: 10px; }
.gauge-side-title { font-size: 13px; color: var(--muted); margin-bottom: 2px; }
.gauge-bar-row { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.gauge-bar-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.gauge-bar-label { width: 64px; flex-shrink: 0; font-weight: 500; }
.gauge-bar-track { flex: 1; height: 8px; background: var(--surface-2); border-radius: 4px; overflow: hidden; }
.gauge-bar-fill { height: 100%; border-radius: 4px; transition: width 0.4s ease; }
.gauge-bar-value { width: 38px; text-align: right; flex-shrink: 0; color: var(--muted); font-variant-numeric: tabular-nums; }
.gauge-most-behind { margin-top: 4px; }

.mix-row { display: grid; grid-template-columns: 80px 1fr 240px; align-items: center; gap: 12px; margin-bottom: 14px; }
.mix-label { font-weight: 600; }
.mix-track { position: relative; height: 14px; background: var(--surface-2); border-radius: 7px; }
.mix-fill { position: absolute; left: 0; top: 0; height: 100%; border-radius: 7px; }
.mix-target { position: absolute; top: -4px; height: 22px; background: rgba(255,255,255,0.08); border-left: 2px solid var(--muted); border-right: 2px solid var(--muted); pointer-events: none; }
.mix-value { font-size: 13px; white-space: nowrap; }

.connect-screen {
    max-width: 400px;
    margin: 120px auto;
    text-align: center;
}
.connect-logo {
    display: inline-flex;
    background: var(--th-ink);
    border-radius: var(--th-radius-lg);
    padding: 32px 40px;
    margin-bottom: 28px;
}
.connect-logo img { height: 64px; width: auto; display: block; }
.connect-screen p { color: var(--muted); margin-bottom: 20px; }

/* The login screen's mark is a live TraceLoader (loaders.js), not a static
   image — the same white-line-races-to-the-dot-then-ignites-orange
   animation every chart uses elsewhere, looping forever here instead of
   tied to a real fetch. Needs an explicit width (not inline-flex's
   shrink-to-content) since the mounted SVG sizes itself to fill its
   container at width:100%. */
.login-mark { width: 100%; max-width: 260px; margin: 0 auto 18px; }

/* Sit the form higher: the old fixed 120px top margin pushed the card well
   below the fold's midline on a laptop. Scales with the viewport instead. */
.connect-screen.login-screen { margin-top: clamp(20px, 6vh, 64px); margin-bottom: 40px; }

.connect-screen p.login-tagline {
    font: 800 20px/1.35 var(--th-font-display);
    font-stretch: 125%;
    letter-spacing: -0.01em;
    color: var(--text);
    margin-bottom: 18px;
}
.login-tagline span {
    display: block;
    margin-top: 8px;
    font: 500 13px/1.5 var(--th-font-ui);
    letter-spacing: 0;
    color: var(--muted);
}

/* A small row of discipline chips under the tagline — purely illustrative
   (what this app actually tracks), not interactive, so the login screen
   doesn't read as just an empty form on a black page. */
.login-disciplines {
    display: flex; justify-content: center; gap: 18px; flex-wrap: wrap;
    margin-bottom: 22px; color: var(--muted);
    font: 500 12px/1 var(--th-font-ui);
}
.login-disciplines span { display: flex; align-items: center; gap: 6px; }

/* The form itself sits in a real card (border + background + a soft
   brand-colored glow, same device the KPI tiles use) rather than floating
   directly on the page background — gives the screen some structure
   beyond "logo, then inputs". */
.login-card {
    position: relative; overflow: hidden; isolation: isolate;
    background: var(--card); border: 1px solid var(--border); border-radius: var(--th-radius-lg);
    padding: 28px 28px 26px; text-align: left;
    box-shadow: 0 24px 60px -30px rgba(0, 0, 0, .6);
}
.login-card::before {
    content: ""; position: absolute; right: -20%; top: -40%; width: 70%; height: 120%;
    z-index: -1; pointer-events: none;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--th-accent) 18%, transparent), transparent);
}

.login-form { display: flex; flex-direction: column; gap: 16px; }

.login-field label { display: block; font-size: 13px; font-weight: 600; margin-bottom: 8px; }

/* The input's own bordered box IS this wrapper — icon, <input>, and the
   password toggle are flex siblings inside it, not stacked/absolutely
   positioned over each other, so this holds up regardless of how lucide
   swaps the <i> for an <svg> after load. */
.login-input-wrap {
    display: flex; align-items: center; gap: 10px;
    background: color-mix(in srgb, var(--bg) 70%, var(--card)); border: 1px solid var(--border); border-radius: 10px;
    padding: 0 14px; min-height: 48px;
    transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
}
.login-input-wrap:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
.login-input-wrap:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.login-input-wrap .lucide { color: var(--muted); flex-shrink: 0; transition: color .15s ease; }
.login-input-wrap:focus-within .lucide { color: var(--accent); }
/* 16px stops iOS zooming the page when a field is focused. */
.login-input-wrap input, .login-input-wrap select {
    flex: 1; min-width: 0; border: none; background: none; padding: 12px 0; margin: 0;
    font: 500 16px/1.3 var(--th-font-ui); color: var(--text);
}
.login-input-wrap input::placeholder { color: var(--muted); opacity: .6; }
.login-input-wrap input:focus, .login-input-wrap select:focus { outline: none; }
/* Browser autofill otherwise paints its own pale yellow/white over the field. */
.login-input-wrap input:-webkit-autofill {
    -webkit-text-fill-color: var(--text);
    box-shadow: 0 0 0 100px color-mix(in srgb, var(--bg) 70%, var(--card)) inset;
    caret-color: var(--text);
}
.login-password-toggle {
    background: none; border: none; color: var(--muted); cursor: pointer;
    display: flex; align-items: center; padding: 2px; flex-shrink: 0;
}
.login-password-toggle:hover { color: var(--text); }

.login-footer { margin-top: 20px !important; font-size: 12px !important; }

.login-submit { width: 100%; margin-top: 6px; min-height: 48px; font-size: 15px; font-weight: 700; border-radius: 10px; }
.login-submit:disabled { opacity: .7; cursor: default; }
.connect-screen p.login-alert {
    display: flex; align-items: center; gap: 8px; margin: 0; padding: 10px 12px;
    border-radius: 10px; font-size: 13px; line-height: 1.4; text-align: left;
}
.login-alert .lucide { flex-shrink: 0; }
.connect-screen p.login-alert-error { color: var(--negative); background: color-mix(in srgb, var(--negative) 12%, transparent); border: 1px solid color-mix(in srgb, var(--negative) 35%, transparent); }
.connect-screen p.login-alert-ok { color: var(--positive); background: color-mix(in srgb, var(--positive) 12%, transparent); border: 1px solid color-mix(in srgb, var(--positive) 35%, transparent); }

/* Onboarding wizard's 3-step progress strip (Profile/Strava/Garmin) —
   a plain numbered-dot + connecting-line pattern, same device as any
   other step indicator; "done"/"active" are purely a color state, not
   separate markup, so the line itself never needs to change shape. */
.onboard-steps { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 0 0 40px; }
.onboard-step {
    display: flex; flex-direction: column; align-items: center; gap: 4px;
    width: 32px; height: 32px; border-radius: 50%;
    background: var(--card); border: 1px solid var(--border); color: var(--muted);
    font: 600 13px/32px var(--th-font-ui); text-align: center; position: relative; flex-shrink: 0;
}
.onboard-step span {
    position: absolute; top: 38px; left: 50%; transform: translateX(-50%);
    font: 500 11px/1 var(--th-font-ui); color: var(--muted); white-space: nowrap;
}
.onboard-step.is-active { background: var(--th-accent); border-color: var(--th-accent); color: #101820; }
.onboard-step.is-done { background: color-mix(in srgb, var(--positive) 18%, transparent); border-color: var(--positive); color: var(--positive); }
.onboard-step-line { width: 32px; height: 1px; background: var(--border); flex-shrink: 0; }

/* The sync result text floats below the button instead of sitting inline
   in the filter bar's flex row — as an inline sibling it added its own
   width to that row every time it had text, which could push the row
   past its available width and force the range/grain buttons to wrap a
   line earlier than they otherwise would. */
.sync-btn-wrap { position: relative; }
#sync-status {
    position: absolute; top: 100%; right: 0; margin-top: 4px;
    color: var(--muted); font-size: 13px; white-space: nowrap;
    opacity: 0; pointer-events: none; transition: opacity 200ms var(--th-ease, ease);
}
#sync-status:not(:empty) { opacity: 1; }

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 8px 6px; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-weight: 500; }
tr { cursor: pointer; transition: background 0.1s; }
tr:hover td { background: var(--surface-2); }
thead tr { cursor: default; }
thead tr:hover td { background: transparent; }

/* A Triathlon leaderboard row expands in place to show its swim/T1/bike/
   T2/run breakdown (race_performance.js) instead of navigating away —
   there's no single activity a multi-leg race could link to. */
.leaderboard-expand-chevron { transition: transform 0.15s ease; }
tr.is-expandable.is-open .leaderboard-expand-chevron { transform: rotate(90deg); }
tr.leg-detail-row { cursor: default; }
tr.leg-detail-row:hover td { background: transparent; }
tr.leg-detail-row td { border-bottom: none; padding: 4px 6px 12px; }

/* Compact density (Settings -> Appearance) — tightens the same components
   rather than introducing new ones, so it stays a drop-in override. */
html[data-density="compact"] main { gap: 12px; }
html[data-density="compact"] .card { padding: 12px 14px; }
html[data-density="compact"] .filter-bar { padding: 9px 20px; }
html[data-density="compact"] .tile { padding: 8px 14px; gap: 4px; }
html[data-density="compact"] .stat-cards, html[data-density="compact"] .discipline-grid, html[data-density="compact"] .records-row { gap: 8px; }
html[data-density="compact"] .stat-card { padding: 10px 12px; gap: 8px; }
html[data-density="compact"] .disc-card { padding: 12px; }
html[data-density="compact"] .global-field { padding: 8px; }
html[data-density="compact"] .race-card, html[data-density="compact"] .race-leg-row, html[data-density="compact"] .burst-day-card, html[data-density="compact"] .excluded-row { padding: 8px 10px; }
html[data-density="compact"] th, html[data-density="compact"] td { padding: 5px 6px; }
html[data-density="compact"] .health-event-row { padding: 7px 10px; }

/* Goal pace gap table under the Training comparison chart */
.tc-gap { margin-top: 1.25rem; }
.tc-gap-title { font-size: 0.95rem; margin: 0 0 0.5rem; }
.tc-gap-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.tc-gap-table th, .tc-gap-table td { text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--border, rgba(255,255,255,0.08)); }
.tc-gap-table th { font-weight: 500; opacity: 0.7; font-size: 0.8rem; }
.tc-gap-behind { color: var(--th-rose, #C8503D); }
.tc-gap-ahead { color: var(--th-teal, #3D9E8F); }
.tc-gap .hint { margin: 0; }
.tc-gap > .hint { margin-top: 10px; }
.tc-gap-table tr { cursor: default; }
.tc-gap-table tr:hover td { background: transparent; }

/* ---- Public signup / checkout / account-recovery pages ---- */
.pub-body { padding-left: 0 !important; min-height: 100vh; display: flex; flex-direction: column; background: var(--th-bg); }
.pub-header { display: flex; align-items: center; justify-content: space-between; padding: 18px 28px; border-bottom: 1px solid var(--border); }
.pub-nav { display: flex; gap: 22px; align-items: center; font-size: 14px; }
.pub-nav a { color: var(--muted); text-decoration: none; }
.pub-nav a:hover { color: var(--text); }
.pub-nav .pub-nav-login { color: var(--text); font-weight: 600; }
.pub-main { flex: 1; width: 100%; max-width: 560px; margin: 0 auto; padding: 40px 20px 56px; }
.pub-main.pub-wide { max-width: 1040px; }
.pub-footer { display: flex; gap: 22px; justify-content: center; padding: 22px; font-size: 12px; color: var(--muted); border-top: 1px solid var(--border); }
.pub-footer a { color: var(--muted); text-decoration: none; }
.pub-footer a:hover { color: var(--text); }
.pub-title { font-family: var(--th-font-display); font-weight: 800; font-stretch: 125%; letter-spacing: -0.02em; line-height: 1; font-size: clamp(28px, 5vw, 44px); margin: 0 0 12px; }
.pub-lede { color: var(--muted); font-size: 16px; line-height: 1.55; margin: 0 0 28px; max-width: 60ch; }
.pub-card { position: relative; background: linear-gradient(180deg, var(--th-surface-2), var(--th-surface)); border: 1px solid var(--border); border-radius: 20px; padding: 28px; }
.pub-center { text-align: center; }
.pub-center .pub-lede { margin-left: auto; margin-right: auto; }
.pub-icon-badge { width: 56px; height: 56px; border-radius: 16px; display: grid; place-items: center; margin: 0 auto 18px; background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); }
.pub-icon-badge .lucide { width: 26px; height: 26px; }
.pub-error { color: var(--negative); font-size: 13px; margin: 0; }
.pub-notice { color: var(--positive); font-size: 13px; margin: 0 0 12px; }
.pub-small { font-size: 13px; color: var(--muted); }
.pub-small a, .pub-link { color: var(--accent); text-decoration: none; }
.pub-small a:hover, .pub-link:hover { text-decoration: underline; }
.pub-stack { display: flex; flex-direction: column; gap: 14px; }
.pub-btn-row { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.pub-btn-ghost { background: transparent; border: 1px solid var(--border); color: var(--text); }
.pub-steps { display: flex; justify-content: center; gap: 6px; margin: 0 0 32px; flex-wrap: wrap; font-size: 12px; color: var(--muted); }
.pub-steps span { padding: 4px 10px; border: 1px solid var(--border); border-radius: 999px; }
.pub-steps .is-active { background: var(--th-accent); border-color: var(--th-accent); color: var(--th-on-accent); font-weight: 700; }
.pub-steps .is-done { border-color: var(--positive); color: var(--positive); }
.pub-pwmeter { height: 4px; border-radius: 2px; background: var(--border); overflow: hidden; margin-top: 8px; }
.pub-pwmeter > i { display: block; height: 100%; width: 0; background: var(--negative); transition: width var(--th-dur-base) var(--th-ease), background var(--th-dur-base); }
.pub-check { display: flex; gap: 10px; align-items: flex-start; font-size: 13px; color: var(--muted); line-height: 1.45; }
.pub-check input { margin-top: 3px; accent-color: var(--accent); }
.pub-two { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 520px) { .pub-two { grid-template-columns: 1fr; } .pub-header { padding: 14px 16px; } }

/* Plans */
.pub-plans { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin: 0 0 28px; }
@media (max-width: 760px) { .pub-plans { grid-template-columns: 1fr; } }
.pub-plan { position: relative; display: flex; flex-direction: column; cursor: pointer; background: linear-gradient(180deg, var(--th-surface-2), var(--th-surface)); border: 1px solid var(--border); border-radius: 20px; padding: 26px; transition: border-color var(--th-dur-fast), transform var(--th-dur-fast); }
.pub-plan:hover { border-color: var(--muted); }
.pub-plan input { position: absolute; opacity: 0; pointer-events: none; }
.pub-plan.is-selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), 0 18px 50px -24px var(--accent); }
.pub-plan-name { font-size: 13px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.pub-plan-price { font-family: var(--th-font-data); font-weight: 600; font-size: 40px; letter-spacing: -0.02em; margin: 10px 0 2px; }
.pub-plan-price small { font-size: 14px; color: var(--muted); font-weight: 500; }
.pub-plan-sub { color: var(--muted); font-size: 13px; min-height: 20px; }
.pub-ribbon { position: absolute; top: -12px; right: 20px; background: var(--th-accent); color: var(--th-on-accent); font-size: 12px; font-weight: 700; padding: 4px 12px; border-radius: 999px; }
.pub-saving { display: inline-block; margin-top: 12px; padding: 4px 10px; border-radius: 8px; font-size: 12px; font-weight: 600; color: var(--positive); background: color-mix(in srgb, var(--positive) 14%, transparent); }
.pub-features { list-style: none; padding: 0; margin: 18px 0 0; display: grid; gap: 8px; font-size: 14px; }
.pub-features li { display: flex; gap: 10px; align-items: flex-start; }
.pub-features .lucide { color: var(--positive); width: 16px; height: 16px; margin-top: 3px; flex-shrink: 0; }
.pub-trust { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: 34px; }
@media (max-width: 860px) { .pub-trust { grid-template-columns: 1fr 1fr; } }
.pub-trust > div { font-size: 13px; color: var(--muted); line-height: 1.5; }
.pub-trust b { display: flex; gap: 8px; align-items: center; color: var(--text); font-size: 14px; margin-bottom: 4px; }
.pub-trust .lucide { color: var(--accent); width: 18px; height: 18px; }
.pub-summary { display: grid; gap: 10px; font-size: 14px; }
.pub-summary > div { display: flex; justify-content: space-between; gap: 16px; }
.pub-summary .pub-total { border-top: 1px solid var(--border); padding-top: 12px; font-size: 16px; font-weight: 700; }
.pub-summary .mono { font-family: var(--th-font-data); font-weight: 600; }
.pub-checkout-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 24px; align-items: start; }
@media (max-width: 860px) { .pub-checkout-grid { grid-template-columns: 1fr; } }
.pub-nudge { margin-top: 14px; padding: 12px 14px; border-radius: 12px; border: 1px dashed var(--accent); font-size: 13px; color: var(--text); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.pub-nudge button { background: none; border: 0; color: var(--accent); font-weight: 700; cursor: pointer; padding: 0; font: inherit; font-weight: 700; }
.pub-table { width: 100%; font-size: 13px; }
.pub-table td, .pub-table th { padding: 8px 6px; vertical-align: top; }
.pub-table tr { cursor: default; }
.pub-table tr:hover td { background: transparent; }
.pub-mail { background: #fff; border-radius: 12px; overflow: hidden; }
.pub-mail iframe { width: 100%; height: 420px; border: 0; background: #101820; }

.login-link { color: var(--accent); text-decoration: none; font-size: inherit; }
.login-link:hover { text-decoration: underline; }

/* Settings > Billing */
.bill-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 8px; }
@media (max-width: 640px) { .bill-grid { grid-template-columns: 1fr; } }
.bill-box { border: 1px solid var(--border); border-radius: 14px; padding: 14px 16px; background: color-mix(in srgb, var(--surface-2) 60%, transparent); }
.bill-label { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.bill-value { font-size: 16px; font-weight: 600; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.pill-ok, .pill-warn { font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: 999px; }
.pill-ok { color: var(--positive); background: color-mix(in srgb, var(--positive) 16%, transparent); }
.pill-warn { color: var(--th-gold); background: color-mix(in srgb, var(--th-gold) 16%, transparent); }
.bill-table { width: 100%; font-size: 13px; }
.bill-table tr { cursor: default; }
.bill-table tr:hover td { background: transparent; }
.bill-table a { color: var(--accent); text-decoration: none; font-family: var(--th-font-data); }
.bill-box .hint { margin: 6px 0 0; }
.bill-box[hidden] { display: none; }

/* ---------- Operator admin (/admin/*) ---------- */
.adm-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 18px; border-bottom: 1px solid var(--border); padding-bottom: 10px; }
.adm-tabs a { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: 10px; color: var(--muted); text-decoration: none; font-weight: 600; font-size: 14px; }
.adm-tabs a:hover { color: var(--text); background: color-mix(in srgb, var(--text) 6%, transparent); }
.adm-tabs a.is-active { color: var(--text); background: color-mix(in srgb, var(--accent) 16%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent); }
.adm-badge { background: var(--accent); color: var(--on-accent); border-radius: 999px; font-size: 11px; font-weight: 800; padding: 1px 7px; margin-left: 2px; }
.adm-h { font-size: 13px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); margin: 22px 0 10px; }
.adm-h3 { font-size: 13px; color: var(--muted); margin: 18px 0 8px; font-weight: 600; }
.adm-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); gap: 16px; margin: 16px 0; align-items: start; }
.adm-grid > .card { margin: 0; }
@media (max-width: 480px) { .adm-grid { grid-template-columns: 1fr; } }
.adm-scroll { overflow-x: auto; }
.adm-row { cursor: pointer; }
.adm-filter { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 14px; align-items: center; }
.adm-head { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 4px; }
.adm-pill { font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: 999px; text-transform: capitalize; white-space: nowrap;
    color: var(--muted); background: color-mix(in srgb, var(--text) 10%, transparent); }
.adm-active { color: var(--positive); background: color-mix(in srgb, var(--positive) 16%, transparent); }
.adm-cancelling, .adm-past_due, .adm-pending, .adm-unverified { color: var(--th-gold); background: color-mix(in srgb, var(--th-gold) 16%, transparent); }
.adm-canceled, .adm-deactivated { color: var(--negative); background: color-mix(in srgb, var(--negative) 14%, transparent); }
.adm-complimentary { color: var(--th-violet); background: color-mix(in srgb, var(--th-violet) 16%, transparent); }
.adm-bar-row { display: grid; grid-template-columns: minmax(110px, 38%) 1fr auto; gap: 10px; align-items: center; margin: 7px 0; font-size: 13px; }
.adm-bar { height: 10px; border-radius: 6px; background: color-mix(in srgb, var(--text) 8%, transparent); overflow: hidden; }
.adm-bar > span { display: block; height: 100%; background: var(--accent); border-radius: 6px; }
.adm-bar-value { min-width: 56px; text-align: right; font-variant-numeric: tabular-nums; }
.adm-quote { border-left: 2px solid var(--border); padding: 4px 0 4px 12px; margin: 10px 0; font-size: 13px; }
.adm-quote > div { color: var(--muted); margin-top: 3px; white-space: pre-wrap; }
.adm-reply { margin-top: 8px; padding: 8px 12px; border-radius: 10px; font-size: 13px; background: color-mix(in srgb, var(--positive) 10%, transparent); white-space: pre-wrap; }
.adm-act { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 10px 0; font-size: 13px; }
.adm-act > label { width: 120px; color: var(--muted); font-size: 12px; }
.adm-spark { display: flex; align-items: flex-end; gap: 3px; height: 90px; }
.adm-spark > span { flex: 1; background: var(--accent); border-radius: 3px 3px 0 0; min-height: 3px; }
.adm-ticket { border: 1px solid var(--border); border-radius: 14px; padding: 14px 16px; margin: 12px 0; }
.adm-ticket-head { display: flex; justify-content: space-between; gap: 10px; align-items: flex-start; }
.adm-msg { white-space: pre-wrap; margin: 10px 0 0; font-size: 14px; }
.adm-reply-box[hidden] { display: none; }
.adm-sub { color: var(--muted); font-size: 12px; margin: 2px 0 0; line-height: 1.4; }
.adm-flash { margin: 10px 0 0; font-size: 13px; }
.adm-flash:empty { display: none; }
.adm-cards > * { flex: 1 1 160px; min-width: 150px; }
.card .health-form-row label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 4px; }

/* Admin > Emails */
.adm-mail { display: grid; grid-template-columns: 300px 1fr; gap: 16px; align-items: start; margin-bottom: 16px; }
@media (max-width: 900px) { .adm-mail { grid-template-columns: 1fr; } }
.adm-mail > .card { margin: 0; }
.adm-mail-item { display: block; width: 100%; text-align: left; background: none; border: 1px solid transparent; color: var(--text); border-radius: 10px; padding: 9px 12px; margin: 2px 0; cursor: pointer; font: inherit; }
.adm-mail-item b { display: block; font-size: 14px; }
.adm-mail-item span { display: block; color: var(--muted); font-size: 12px; margin-top: 2px; line-height: 1.35; }
.adm-mail-item:hover { background: color-mix(in srgb, var(--text) 6%, transparent); }
.adm-mail-item.is-on { background: color-mix(in srgb, var(--accent) 14%, transparent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.adm-mail-bar { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; align-items: center; margin-bottom: 14px; }
.adm-seg { display: inline-flex; background: var(--surface-2); border-radius: 10px; padding: 4px; gap: 2px; }
.adm-seg button { background: none; border: 0; color: var(--muted); font: inherit; font-size: 13px; font-weight: 600; padding: 6px 14px; border-radius: 8px; cursor: pointer; }
.adm-seg button.is-on { background: var(--card); color: var(--text); box-shadow: 0 1px 2px rgba(0,0,0,.25); }
.adm-mail-meta { display: grid; grid-template-columns: 2fr 1.2fr 2fr; gap: 14px; font-size: 13px; margin-bottom: 14px; }
@media (max-width: 700px) { .adm-mail-meta { grid-template-columns: 1fr; } }
.adm-device { background: color-mix(in srgb, var(--text) 5%, transparent); border-radius: 14px; padding: 18px; display: flex; justify-content: center; overflow: auto; }
.adm-device iframe { width: 100%; max-width: 700px; border: 0; border-radius: 10px; background: #fff; min-height: 300px; }
.adm-device[data-mode="phone"] iframe { width: 375px; max-width: 100%; border: 8px solid #05080c; border-radius: 28px; box-shadow: 0 0 0 1px #2e3b4a; }
.adm-device pre { margin: 0; width: 100%; max-width: 700px; white-space: pre-wrap; word-break: break-word; font: 13px/1.6 var(--th-font-data); color: var(--text); background: var(--card); padding: 18px; border-radius: 10px; }
.adm-color { display: flex; gap: 6px; align-items: center; }
.adm-color input[type="color"] { width: 38px; height: 34px; padding: 0; border: 1px solid var(--border); border-radius: 6px; background: none; cursor: pointer; flex-shrink: 0; }
.adm-color .select { width: 100%; font-family: var(--th-font-data); text-transform: uppercase; }
.adm-check { display: flex; gap: 12px; align-items: flex-start; padding: 9px 0; border-bottom: 1px solid var(--border); }
.adm-check:last-child { border-bottom: 0; }
.adm-check .adm-pill { flex-shrink: 0; margin-top: 2px; min-width: 84px; text-align: center; }
.adm-ctl { display: flex; justify-content: space-between; gap: 16px; align-items: center; flex-wrap: wrap; }
.adm-val { word-break: break-word; }

/* Year at a glance: what the data says. Compact tiles that flex to fill each row, so an uneven
   count never leaves a gap, and one-line notes so every tile is the same height. Generous vertical
   rhythm: the grid, its legend, the insights title and the tiles each get room to breathe. */
.heatmap-wrap { margin-top: 12px; }
.heatmap-legend { margin-top: 16px !important; }
.heat-insights-title { margin: 30px 0 14px; font-size: 12px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 700; }
.heat-insights { display: flex; flex-wrap: wrap; gap: 12px; }
.heat-insight { flex: 1 1 158px; border: 1px solid var(--border); border-radius: 12px; padding: 14px 16px 13px; background: color-mix(in srgb, var(--surface-2) 55%, transparent); min-width: 0; }
.heat-insight[data-date] { cursor: pointer; }
.heat-insight[data-date]:hover { border-color: var(--accent); }
.heat-insight-label { font-size: 12px; color: var(--muted); line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.heat-insight-value { font-size: 18px; font-weight: 700; margin: 7px 0 5px; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.heat-insight-note { font-size: 12px; color: var(--muted); line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Illness / injury overlay on the year grid: faint, so the load colour still shows through. */
.heat-flag { position: absolute; display: block; color: #fff; opacity: .82; pointer-events: none;
    filter: drop-shadow(0 0 1px rgba(10, 16, 22, .9)) drop-shadow(0 0 .5px rgba(10, 16, 22, .9)); }
.heat-flag svg { display: block; width: 100%; height: 100%; }
.heat-cell.has-flag .heat-flag { inset: 5%; }
.heat-cell.has-both .heat-flag { width: 64%; height: 64%; }
.heat-cell.has-both .heat-flag-illness { top: 2%; left: 2%; }
.heat-cell.has-both .heat-flag-injury { bottom: 2%; right: 2%; }
.heat-key { display: inline-flex; align-items: center; gap: 4px; margin-left: 16px; }
.heat-key-icon { display: inline-block; width: 14px; height: 14px; color: var(--text); opacity: .8; }
.heat-key-icon svg { display: block; width: 100%; height: 100%; }

/* A titled sub-section inside a card (e.g. "Totals for this range" under a chart). */
.card-section-title { margin: 22px 0 10px; padding-top: 16px; border-top: 1px solid var(--border); font-size: 12px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 700; }

/* Health log: quick actions, the "currently ill" strip, and the ongoing checkbox */
.health-event-row { gap: 12px; }
.health-event-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.health-done { font-size: 12px; color: var(--positive); white-space: nowrap; }
.health-now { display: flex; justify-content: space-between; gap: 12px; align-items: center; flex-wrap: wrap; padding: 12px 16px; margin-bottom: 12px; border-radius: 12px;
    border: 1px solid var(--border); border-left: 4px solid #e0577a; background: color-mix(in srgb, #e0577a 10%, var(--card)); }
.health-now.injury { border-left-color: #f4a261; background: color-mix(in srgb, #f4a261 10%, var(--card)); }
.health-now-text { font-size: 14px; }
.health-now-text .health-event-meta { margin-left: 6px; }
.health-form-card label.health-ongoing { display: flex; align-items: center; gap: 8px; margin-top: 8px; color: var(--text); font-size: 13px; }
.health-form-card label.health-ongoing input { width: auto; }

/* Aerobic efficiency: one panel per discipline */
.ef-note { font-size: 12px; color: var(--muted); }
.ef-row { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 22px; align-items: center; padding: 18px 0; border-top: 1px solid var(--border); }
.ef-row:first-of-type { border-top: 0; }
@media (max-width: 800px) { .ef-row { grid-template-columns: 1fr; gap: 12px; } }
.ef-disc { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.ef-change { font: 700 32px/1.1 var(--th-font-data); font-variant-numeric: tabular-nums; margin-top: 8px; }
.ef-state { font-size: 13px; font-weight: 700; margin-top: 2px; }
.ef-sentence { font-size: 13px; line-height: 1.5; margin: 10px 0 8px; }
.ef-meta { font-size: 11px; color: var(--muted); }
.ef-help { margin-top: 8px; font-size: 13px; color: var(--muted); border-top: 1px solid var(--border); padding-top: 12px; }
.ef-help summary { cursor: pointer; font-weight: 600; color: var(--text); }
.ef-help ul { margin: 10px 0 0; padding-left: 20px; display: grid; gap: 7px; line-height: 1.5; }
.ef-key { display: flex; gap: 18px; flex-wrap: wrap; justify-content: flex-end; font-size: 11px; color: var(--muted); margin-top: 6px; }
.ef-key span { display: inline-flex; align-items: center; gap: 6px; }
.ef-key i { display: inline-block; }
.ef-key .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); }
.ef-key .line { width: 18px; height: 3px; border-radius: 2px; background: var(--muted); }
.ef-key .dash { width: 18px; height: 0; border-top: 1.5px dashed var(--muted); }

/* Goals: past races at this distance */
.goal-history-title { font-size: 15px; margin: 24px 0 8px; }
.goal-history-scroll { overflow-x: auto; }
.goal-history-table { width: 100%; font-size: 13px; min-width: 560px; }
.goal-history-table th { white-space: nowrap; }
.goal-history-table td { vertical-align: top; }
.goal-history-table tr { cursor: default; }
.goal-history-table tr:hover td { background: transparent; }
.goal-history-table .mono { font-family: var(--th-font-data); font-variant-numeric: tabular-nums; font-weight: 600; }
.goal-history-table .hint { margin: 0; font-size: 11px; }
.delta-over { color: var(--negative); }
.delta-under { color: var(--positive); }
.goal-history-scroll + .hint { margin-top: 10px; }

/* Goals page: spacing, collapsible cards, nudge */
#goals-list { display: grid; gap: 20px; margin-bottom: 20px; }
#goals-list > .card, #goals-nudge > .card { margin: 0; }
#goals-nudge:not(:empty) { margin-bottom: 20px; }
.goals-toolbar { display: flex; justify-content: flex-end; gap: 8px; }
.goal-card > .goal-card-header { gap: 12px; cursor: pointer; margin: 0; }
.goal-chevron { display: inline-flex; transition: transform .15s; transform: rotate(-90deg); color: var(--th-text-muted, var(--text-muted)); }
.goal-card.is-open .goal-chevron { transform: none; }
.goal-summary { display: flex; flex-wrap: wrap; gap: 8px; flex: 1; min-width: 0; }
.goal-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 999px; font-size: 12px; border: 1px solid var(--border); white-space: nowrap; }
.goal-chip-muted { opacity: .6; }
.goal-chip-behind { color: var(--th-danger, #f87171); border-color: currentColor; }
.goal-chip-ahead { color: var(--th-success, #4ade80); border-color: currentColor; }
.goal-chip[hidden] { display: none; }
.goal-body { display: none; padding-top: 18px; }
.goal-body > * + * { margin-top: 16px; }
.goal-body .goal-description:empty { display: none; }
.goal-body .hint { margin-top: 0; }
.goal-card.is-open .goal-body { display: block; }
.goal-nudge ul { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 12px; }
.goal-nudge li { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.goal-nudge li .hint { display: block; margin: 2px 0 0; }
.goal-chevron svg { width: 18px; height: 18px; }


/* Chart controls: one pattern everywhere. A row (.chart-tools) holding, in this order,
   a segmented picker (2-5 options: .segmented), a select (6+ options: .select) and on/off
   switches (.switch-toggle). In a card header it sits right of the title; under a hint it
   sits on its own row (.chart-tools-row). */
.chart-tools { display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap; }
.chart-tools-row { margin: 4px 0 14px; }
.chart-tools .segmented { max-width: 100%; overflow-x: auto; }
.chart-tools .tool-note { font-size: 12px; color: var(--muted); }
.tc-controls { display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap; }
@media (max-width: 640px) { .goal-card-header > .chart-tools { width: 100%; } }

/* Activities page */
.act-filters { align-items: center; }
.act-search { min-width: 220px; flex: 1 1 220px; max-width: 340px; }
.act-date { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
.act-export { margin-left: auto; }
.act-summary { margin: 0 0 10px; }
.act-table-wrap { overflow-x: auto; }
.act-table th[data-sort] { cursor: pointer; user-select: none; white-space: nowrap; }
.act-table th[data-sort]:hover { color: var(--text); }
.act-table th.sorted::after { content: ' ↓'; color: var(--accent); }
.act-table th.sorted[data-dir="asc"]::after { content: ' ↑'; }
.act-table .num { text-align: right; white-space: nowrap; }
.act-table tbody tr[data-id] { cursor: pointer; }
.act-pager { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 14px; }
.act-pager-btns { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.view-all-link { display: inline-flex; align-items: center; gap: 6px; margin-top: 12px; font-size: 13px; font-weight: 600; }

/* Page header: the title/controls row is tall enough that its centre sits on the sidebar logo's centre
   (logo centre = 35px from the top: 20px sidebar padding + 4px + half the 22px wordmark). */
.filter-bar:not(.filter-bar-inline) .filter-bar-title { min-height: 46px; }
html[data-density="compact"] .filter-bar:not(.filter-bar-inline) .filter-bar-title { min-height: 52px; }

/* Goals: roomier fields */
.goal-body .select { padding: 9px 14px; min-height: 40px; }
.goal-body .health-form-row { gap: 16px 20px; }
.goal-body .health-form-row label { display: block; margin-bottom: 6px; }
.goal-body .goal-description { margin-top: 14px; line-height: 1.5; }
.goal-body .goal-time-inputs { gap: 8px 10px; }
.goal-history-sub { font-size: 12px; font-weight: 400; color: var(--muted); margin-left: 6px; }
.goal-save-status { margin: 0; min-width: 44px; }

/* Plain-language chart copy: a lead line (.hint), a live "what this means for you" read-out
   (.chart-takeaway) and the technical detail tucked behind a click (.th-science). */
/* Insight panel: sits BELOW the chart it explains (never a coloured stripe above it). Neutral surface, one quiet label. */
.chart-foot { margin-top: 16px; display: grid; gap: 10px; }
.chart-takeaway { margin: 0; padding: 14px 16px; border: 1px solid var(--border); background: var(--surface-2); border-radius: 12px; font-size: 14.5px; line-height: 1.55; color: var(--text); }
.chart-takeaway::before { content: "What this means"; display: block; margin-bottom: 6px; font: 600 11px/1 var(--th-font-data); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.chart-takeaway:empty { display: none; }
.chart-foot .th-science { margin: 0; }
.th-science { margin: 0 0 14px; font-size: 13px; color: var(--muted); }
.th-science summary { cursor: pointer; display: inline-block; font-weight: 600; color: var(--muted); user-select: none; }
.th-science summary:hover { color: var(--text); }
.th-science p { margin: 8px 0 0; padding: 10px 14px; border: 1px solid var(--border); border-radius: 8px; line-height: 1.55; }

/* Coaching */
.coach-pill { position: fixed; right: 18px; bottom: 18px; z-index: 400; display: flex; align-items: center; gap: 12px; padding: 10px 14px; border-radius: 999px;
    background: var(--card); border: 1px solid var(--accent); box-shadow: 0 8px 28px rgba(0,0,0,.45); font-size: 13px; }
.coach-pill .lucide { color: var(--accent); }
.coach-pitch { list-style: none; margin: 18px 0 8px; padding: 0; display: grid; gap: 14px; }
.coach-pitch li { display: flex; gap: 14px; align-items: flex-start; }
.coach-pitch .lucide { flex: none; width: 22px; height: 22px; color: var(--accent); margin-top: 2px; }
.coach-pitch b { display: block; }
.coach-pitch span { color: var(--muted); font-size: 14px; line-height: 1.5; }
.coach-form-title { font-size: 18px; margin: 26px 0 10px; }
.coach-terms { margin: 14px 0 18px; padding: 14px 16px; border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: 10px; display: grid; gap: 4px; }
.coach-terms span { color: var(--muted); font-size: 13px; }
.coach-attn, .coach-race { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--border); }
.coach-attn:first-of-type, .coach-race:first-of-type { border-top: 0; }
.coach-days { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--accent); }
.coach-flags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.coach-flag { font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px; color: var(--muted); background: color-mix(in srgb, var(--text) 10%, transparent); }
.coach-flag-bad { color: var(--negative); background: color-mix(in srgb, var(--negative) 14%, transparent); }
.coach-flag-warn { color: var(--th-gold); background: color-mix(in srgb, var(--th-gold) 16%, transparent); }
.coach-form { font-size: 12px; font-weight: 700; }
.coach-form-good { color: var(--positive); } .coach-form-warn { color: var(--th-gold); } .coach-form-bad { color: var(--negative); } .coach-form-muted { color: var(--muted); }
.coach-table td { vertical-align: top; }
.coach-actions { display: flex; gap: 8px; align-items: center; white-space: nowrap; }
.coach-actions form { margin: 0; }

/* Public pages: fuller header nav and a trust strip */
.pub-nav { gap: 26px; }
.pub-trust { display: flex; justify-content: center; gap: 10px 28px; flex-wrap: wrap; padding: 9px 16px; font-size: 12px; color: var(--muted);
    background: color-mix(in srgb, var(--text) 4%, transparent); border-bottom: 1px solid var(--border); }
.pub-trust span { display: inline-flex; align-items: center; gap: 6px; }
.pub-trust .lucide { color: var(--positive); }
@media (max-width: 720px) { .pub-nav-opt { display: none; } .pub-nav { gap: 16px; } }

.pub-two > * { min-width: 0; }
.pub-two .login-input-wrap input { min-width: 0; width: 100%; }
.chart-legend-events { opacity: .85; font-size: 12px; }
.legend-bar { display: inline-block; width: 12px; height: 4px; border-radius: 2px; margin-right: 6px; vertical-align: middle; }
.legend-line { display: inline-block; width: 12px; height: 0; border-top: 1px dashed rgba(255, 200, 87, .7); margin-right: 6px; vertical-align: middle; }

/* Fresh-or-tired card: readouts first, then one question at a time. */
.ff-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 14px 0; }
.ff-tile { display: flex; flex-direction: column; gap: 6px; padding: 14px; border: 1px solid var(--border); border-radius: 12px; background: var(--surface-2); }
.ff-tile-main { border-color: color-mix(in srgb, var(--accent) 35%, var(--border)); }
.ff-l { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; color: var(--muted); }
.ff-v { font-size: 26px; font-weight: 600; line-height: 1; letter-spacing: -.01em; }
.ff-s { font-size: 12px; color: var(--muted); }
.ff-chip { padding: 2px 8px; border-radius: 999px; font: 600 11px/1.3 var(--th-font-ui); }
.ff-pos { color: var(--positive); background: color-mix(in srgb, var(--positive) 16%, transparent); }
.ff-warm { color: var(--th-gold); background: color-mix(in srgb, var(--th-gold) 16%, transparent); }
.ff-neg { color: var(--negative); background: color-mix(in srgb, var(--negative) 14%, transparent); }
.ff-mode { margin: 4px 0 12px; }
@media (max-width: 640px) { .ff-tiles { grid-template-columns: 1fr; } }
