:root {
  color-scheme: light;

  /* ------------------------------------------------------------------
     NORYA-merkpalet. Drie dragers, bewust weinig kleuren:
       Ivory    - warme neutrale ondergrond (rust, ruimte)
       Graphite - tekst, structuur en premium contrast
       Teal Balance - het enige accent (richting, bevestiging, data)
     Elke andere waarde in deze stylesheet verwijst naar een token
     hieronder; er staat opzettelijk geen losse kleur in een regel.
     ------------------------------------------------------------------ */
  /* Ivory en Graphite komen letterlijk uit `NORYA_brand_colors.json` in het
     merk-master-pack; ze worden hier niet benaderd maar overgenomen. */
  --ivory: #f7f6f0;
  --ivory-raised: #fffefa;
  --ivory-sunk: #efede4;
  /* Dezelfde Ivory, half doorschijnend: de balk laat de pagina er zacht
     doorheen schemeren zonder een tweede, losse kleur te introduceren. */
  --ivory-veil: rgba(255, 254, 250, 0.88);
  --graphite: #0b0d0f;
  --graphite-soft: #5a6470;

  /* Teal Balance zoals het merk hem definieert: de kleur van de horizon in het
     logo. Hij is licht, want de lockup leeft op een donker vlak (#050C10). */
  --teal-core: #74c3b6;
  --horizon-left: #63c7c1;
  --horizon-right: #9bd39b;

  /* Op Ivory haalt de core-teal geen leesbaar contrast (~1,9:1). Voor tekst,
     links en interactieve vlakken wordt dezelfde tint dieper gezet tot ze AA
     haalt (4,76:1 op Ivory). Dat is geen tweede merkkleur maar dezelfde teal,
     donkerder gezet omdat het oppervlak omdraait; het logo zelf blijft
     onaangeroerd. */
  --teal: #0f7b6c;
  --teal-deep: #0a5b50;
  --teal-wash: #e6f1ee;
  --teal-edge: rgba(15, 123, 108, 0.28);

  /* Semantische tokens: pagina's en componenten gebruiken uitsluitend deze. */
  --bg: var(--ivory);
  --bg-raised: var(--ivory-raised);
  --panel: var(--ivory-raised);
  --panel-strong: var(--ivory-sunk);
  --border: rgba(27, 32, 38, 0.10);
  --border-strong: rgba(27, 32, 38, 0.20);
  --text: var(--graphite);
  --muted: var(--graphite-soft);
  --accent: var(--teal);
  --accent-strong: var(--teal-deep);
  --accent-ink: #ffffff;
  --ok: #17715a;
  --ok-edge: rgba(23, 113, 90, 0.35);
  /* `--warn` is de historische naam van de aandachtsrol en blijft bestaan
     zodat bestaande regels niet hoeven te verhuizen - maar hij wijst vanaf
     hier naar `--caution` en dus niet langer naar dezelfde waarde als
     `--event`. Dat is de hele gedragswijziging. */
  --warn: var(--caution);
  --warn-edge: var(--caution-edge);

  /* De streefdag van een doel: dezelfde warme amber als `--warn`, maar een
     eigen semantisch token en geen alias ervan.
     Waarom apart, terwijl de waarde vandaag gelijk is: een evenement is geen
     waarschuwing. Zou de evenementdag `--warn` gebruiken, dan zou elke latere
     wijziging aan waarschuwingsstijl - roder, een uitroepteken, een rand -
     meteen op de dag van Luik-Bastenaken-Luik verschijnen, en dan leest de
     mooiste dag van het seizoen als een probleem. De amber staat er om die dag
     te *onderscheiden*, niet om te alarmeren; vandaar ook geen rood.
     Het is geen vierde merkkleur: het is de bestaande amber, hier met een naam
     die zegt waarvoor hij dient. */
  --event: #8a5d0f;
  --event-wash: #fbf2e3;
  --event-edge: rgba(138, 93, 15, 0.30);

  /* AANDACHT. Tot hier deelde 'er is iets aan de hand' precies dezelfde waarde
     als de streefdag van een doel: `--warn` was `#8a5d0f` en `--event` ook.
     Een gedegradeerde koppeling en de mooiste dag van het seizoen droegen dus
     dezelfde kleur, en geen enkele test kon dat zien omdat er niets faalde.

     Dit is de scheiding. De aandachtstint staat één stap roder dan de amber
     van het evenement (24° tegenover 39°) en één stap goudener dan het rood
     van een echte fout - drie warme rollen, drie vaste stappen, in beide
     verschijningen dezelfde stappen. Gemeten op de lichte gronden: 6,01:1 op
     `--bg`, 6,45:1 op `--panel` en 5,55:1 op `--panel-strong`; overal ruim AA.

     De kleur is nooit het enige signaal: elk aandachtsvlak draagt daarnaast
     het waarschuwingsicoon en een woord (zie `web.icons`). Wie het verschil
     tussen twee warme tinten niet ziet, ziet nog altijd een driehoek naast een
     vlag. */
  --caution: #94491a;
  --caution-wash: #fbf0e7;
  --caution-edge: rgba(148, 73, 26, 0.30);

  /* INFORMATIE EN TAPER. Een stille, ontzadigde blauwtint: de enige koele
     semantische rol. Ze draagt twee dingen die allebei 'dit is context, geen
     oordeel' betekenen - een toelichting, en de taperfase naar een doel toe.
     Taper is bewust géén eigen vierde warme kleur: het is een rustige,
     aflopende fase en hoort niet naast het evenement te schreeuwen.
     Gemeten: 5,94:1 op `--bg`, 6,37:1 op `--panel`, 5,48:1 op
     `--panel-strong`. */
  --info: #2f6389;
  --info-wash: #eaf0f5;
  --info-edge: rgba(47, 99, 137, 0.28);
  --taper: var(--info);
  --taper-wash: var(--info-wash);
  --taper-edge: var(--info-edge);

  /* OPBOUW. De opbouwrol had nog geen naam en leende overal rechtstreeks
     `--accent`. Nu heeft ze er een, zodat 'dit is een opbouwdag' en 'dit is
     het merkaccent' apart verzet kunnen worden. De waarde is vandaag gelijk:
     het beeld verandert niet. */
  --progress: var(--accent);
  --progress-wash: var(--accent-wash, var(--teal-wash));
  --progress-edge: var(--teal-edge);

  /* Elevatie in plaats van kaderlijnen: rustiger dan een randenraster. */
  --shadow-sm: 0 1px 2px rgba(27, 32, 38, 0.04),
    0 1px 3px rgba(27, 32, 38, 0.03);
  --shadow-md: 0 2px 4px rgba(27, 32, 38, 0.04),
    0 8px 24px rgba(27, 32, 38, 0.06);

  --radius: 16px;
  --radius-sm: 10px;
  --maxw: 1120px;
}

* { box-sizing: border-box; }
/* `hidden` is de enige manier waarop dit product iets verbergt, dus het moet
   ook werkelijk verbergen. Zonder deze regel wint elke eigen `display` van de
   UA-regel `[hidden] { display: none }` - en dan blijft een verborgen knop
   gewoon staan. Dat is precies wat er met de startlocatieknop gebeurde. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial,
    sans-serif;
  line-height: 1.55;
  min-height: 100vh;
}

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(20px, 4vw, 48px) clamp(16px, 4vw, 32px);
}

/* Toegankelijke skip-link: onzichtbaar tot toetsenbordfocus. */
.skiplink {
  position: absolute;
  left: -999px;
  top: 8px;
  z-index: 30;
  padding: 10px 16px;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  text-decoration: none;
}
.skiplink:focus-visible { left: 8px; }

/* Merkkop op de anonieme statuspagina: rustig, geen gradient-tekst. */
.hero { text-align: center; margin-bottom: clamp(24px, 5vw, 44px); }

.brand {
  font-size: clamp(2.2rem, 8vw, 3.4rem);
  font-weight: 750;
  letter-spacing: 0.1em;
  margin: 0;
  overflow-wrap: anywhere;
  color: var(--text);
}

.tagline {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: clamp(1rem, 3.5vw, 1.2rem);
  letter-spacing: 0.02em;
  overflow-wrap: anywhere;
}

.statuspill {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 22px;
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel);
  font-size: 0.9rem;
  color: var(--text);
}

.statusdot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--muted);
  flex: 0 0 auto;
}
.statuspill[data-state="online"] .statusdot { background: var(--ok); }
.statuspill[data-state="degraded"] .statusdot { background: var(--warn); }

.section-title {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--muted);
  margin: 0 0 14px;
}

.modules {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  margin: 0 0 clamp(28px, 6vw, 48px);
}

@media (min-width: 640px) {
  .modules { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 940px) {
  .modules { grid-template-columns: repeat(3, 1fr); }
}

.card {
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: var(--radius);
  padding: 22px;
  box-shadow: var(--shadow-sm);
}

.card h3 { margin: 0 0 6px; font-size: 1.1rem; }
.card p { margin: 0; color: var(--muted); font-size: 0.95rem; }

.badge {
  display: inline-block;
  margin-top: 14px;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  color: var(--muted);
  white-space: nowrap;
}

.panel {
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: var(--radius);
  padding: clamp(20px, 4vw, 32px);
  margin-bottom: 22px;
  box-shadow: var(--shadow-sm);
}

.panel h2 { margin: 0 0 12px; font-size: 1.2rem; }

.factlist { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.factlist li {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 4px 16px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 10px;
}
.factlist li:last-child { border-bottom: 0; padding-bottom: 0; }
.factlist .k { color: var(--muted); }
.factlist .v { font-variant-numeric: tabular-nums; text-align: right; }

.note { color: var(--muted); font-size: 0.9rem; margin: 10px 0 0; }

.footer {
  margin-top: 40px;
  text-align: center;
  color: var(--muted);
  font-size: 0.82rem;
}

/* Standaard-linkkleur: leesbaar accent op donkere panelen (geen browser-blauw).
   Component-links (.btn, .navlink, .langlink, .card-link, .topbrand, .account)
   zetten hun eigen kleur en overschrijven dit. */
a { color: var(--accent); }
a:hover { color: var(--text); }

a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
  border-radius: 4px;
}

/* App-shell: topbar + primaire navigatie + taalkeuze */
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  /* Smal: twee regels. Merk en instellingen delen de bovenste regel, de
     navigatie krijgt de onderste in haar geheel. Dat is geen kolom van drie
     dingen onder elkaar (dan wordt de topbar op een telefoon een derde van
     het scherm) maar een raster van twee. */
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "brand actions"
    "nav nav";
  align-items: center;
  gap: 8px;
  padding: 10px clamp(16px, 4vw, 32px);
  border-bottom: 1px solid var(--border);
  background: var(--ivory-veil);
  backdrop-filter: blur(12px);
  box-shadow: var(--shadow-sm);
}
.topbrand { grid-area: brand; }
.nav { grid-area: nav; }
.topbar-right { grid-area: actions; }
/* Eén regel pas wanneer alles er werkelijk naast elkaar op past. Gemeten op
   de reviewlane, in de langste taal (FR): 64px padding + 129px merk + 860px
   navigatie + 114px instellingen + 32px tussenruimte = 1199px. Onder die
   breedte houdt het raster hierboven de navigatie op haar eigen volle regel,
   waar ze wél past. Deze grens stond op 860px - ruim onder wat de rij met
   woorden nodig heeft - en dat is precies waarom de rij werd afgesneden. */
@media (min-width: 1200px) {
  .topbar {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
  }
}
.topbrand {
  text-decoration: none;
  color: var(--text);
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
/* Het Horizon-symbool behoudt zijn eigen verhouding; alleen de hoogte wordt
   gezet, nooit beide assen (geen uitrekken, geen bijsnijden). */
.topbrand-mark {
  /* Alleen de hoogte wordt gezet; de breedte volgt de eigen verhouding van het
     symbool (234:135). Op 34px leest de Teal Balance-horizon nog mee - daar
     onder wordt hij een grijze veeg. */
  height: 34px;
  width: auto;
  display: block;
  flex: 0 0 auto;
}
@media (max-width: 859px) {
  .topbrand-mark { height: 30px; }
}
.topbrand-name {
  font-weight: 750;
  letter-spacing: 0.1em;
  font-size: 1.05rem;
  overflow-wrap: anywhere;
}
/* ==========================================================================
   HOOFDNAVIGATIE - en waarom ze niet meer schuift
   ==========================================================================

   Hier stond `overflow-x: auto` met `width: max-content`: een rij die breder
   werd dan het scherm en dan een scrollvlak werd. Dat is geen navigatie. Wat
   er rechts buiten beeld stond, bestond voor de atleet niet, en een verloop
   aan de rand maakt dat zichtbaar zonder het op te lossen.

   De rij past nu altijd, en dat komt van drie dingen samen:

   * er staan zeven vlakken in plaats van acht plus zes schakelaars (taal,
     weergave en koppelingen verhuisden naar `/settings`);
   * de rij **wikkelt**. Past ze niet op één regel, dan wordt ze twee regels.
     Ze wordt nooit geknepen en nooit afgesneden;
   * onder 640px verdwijnt het *woord* en blijft het *icoon* staan. Het woord
     wordt visueel verborgen maar niet weggehaald, dus de toegankelijke naam
     van de link blijft "Training" - een schermlezer merkt niets van de
     overgang.

   Op elke breedte daarboven staan icoon én woord, want een naamloos
   pictogram is voor wie het product niet kent geen navigatie. Er is dus geen
   breedte waarop deze rij moet schuiven, en daarom staat hier geen
   `overflow-x` meer. Een achtste entry zou de rekensom van de brede regel
   breken; vandaar de grens in `web.shell`. */
.nav { min-width: 0; }
.navrow {
  display: flex;
  /* Wikkelen, niet knijpen en niet schuiven. Een rij die niet past wordt hier
     twee regels; ze wordt nooit afgesneden. Dat is het verschil tussen een
     vlak dat de atleet kan bereiken en een vlak dat voor hem niet bestaat -
     en het is meetbaar: op 1024px was de Franse rij 860px breed in een vak van
     686px, dus vier vlakken stonden buiten beeld. */
  flex-wrap: wrap;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
  align-items: center;
}
.navlink {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid transparent;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  font-size: 0.92rem;
}
.navlink:hover { color: var(--text); }
.navlink.active {
  color: var(--text);
  background: var(--panel-strong);
  border-color: var(--border);
}
/* De actieve entry draagt naast het vlak ook een duidelijker icoon: kleur is
   nooit het enige verschil. */
.navlink.active .icon { color: var(--accent); }

/* Compact: icoon zonder woord. Het tikdoel blijft 40px hoog en wordt vierkant
   in plaats van smaller - een icoonknop die kleiner is dan de tekstknop die
   hij vervangt, is een regressie.

   Deze grens lag op 779px, en dat was te hoog: een tablet in portret (768px)
   kreeg daardoor zeven naamloze pictogrammen, terwijl daar ruimte genoeg is
   voor het woord. Ze ligt nu op de eerste echte breakpoint van deze
   stylesheet (640), zodat alleen een telefoon compact wordt. */
@media (max-width: 639px) {
  .navrow { gap: 2px; }
  .navlink { padding: 6px; min-width: 40px; justify-content: center; }
  .navlink .navlabel,
  .topsettings .navlabel {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* De instellingeningang rechts. Zelfde vorm als een navigatiepil, zodat de
   topbar één familie blijft en niet twee. */
.topsettings {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  min-width: 40px;
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  font-size: 0.92rem;
}
.topsettings:hover { color: var(--text); }
.topsettings.active {
  color: var(--text);
  background: var(--panel-strong);
  border-color: var(--border-strong);
}
@media (max-width: 639px) {
  .topsettings { padding: 6px; justify-content: center; }
}

/* ==========================================================================
   ICONEN
   ==========================================================================
   Eén regel voor de hele set. De iconen tekenen in `currentColor`, dus ze
   volgen elk semantisch token zonder dat er ooit een kleurwaarde in
   `web.icons` staat. */
.icon {
  width: 1.15em;
  height: 1.15em;
  flex: 0 0 auto;
  display: inline-block;
  vertical-align: -0.18em;
}

/* Taalkeuze: compacte, expliciete linkgroep. */
.topbar-right {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.langswitch, .themeswitch {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 999px;
  overflow: hidden;
}
.langlink, .themelink {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  min-height: 40px;
  padding: 4px 10px;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
}
.langlink + .langlink, .themelink + .themelink {
  border-left: 1px solid var(--border);
}
.langlink:hover, .themelink:hover { color: var(--text); }
.langlink.active, .themelink.active {
  color: var(--accent-ink);
  background: var(--accent);
  font-weight: 700;
}

/* De verschijningskeuze draagt woorden in plaats van een tweeletterige code,
   dus iets meer ruimte en geen letterspatiëring die het woord uitrekt. */
.themelink { min-width: 0; letter-spacing: 0.01em; padding: 4px 12px; }

/* Account/sessie-indicator in de topbar */
.account {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  font-size: 0.9rem;
}
.account:hover { color: var(--text); }
.account.active { color: var(--text); background: var(--panel-strong); }
.account-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--muted);
  flex: 0 0 auto;
}
.account-dot.account-in { background: var(--ok); }
.account-status { display: flex; align-items: center; gap: 10px; margin: 0 0 10px; }
.account-label { font-weight: 600; }

.pagehero { margin-bottom: clamp(18px, 4vw, 30px); }
.pagehero h1 {
  margin: 0 0 8px;
  font-size: clamp(1.8rem, 6vw, 2.4rem);
  letter-spacing: -0.01em;
}
.lead {
  margin: 0;
  color: var(--muted);
  font-size: clamp(1rem, 3.5vw, 1.12rem);
  max-width: 62ch;
}

.bullets {
  margin: 0;
  padding-left: 1.1rem;
  color: var(--muted);
  display: grid;
  gap: 6px;
}

/* Home-modulekaarten als navigatie */
.card-link {
  display: block;
  text-decoration: none;
  color: inherit;
  position: relative;
}
.card-link:hover, .card-link:focus-visible { border-color: var(--border-strong); }
.cardgo {
  display: inline-block;
  margin-top: 10px;
  color: var(--accent);
  font-size: 0.85rem;
}

/* Provider cards (Connect) en activiteitkaarten (Performance) */
.providers {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  margin-top: 14px;
}
@media (min-width: 640px) { .providers { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 940px) { .providers { grid-template-columns: repeat(3, 1fr); } }
.provider-head, .activity-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px 10px;
}
.provider-head h3, .activity-head h3 { margin: 0; overflow-wrap: anywhere; }
.activity-date { color: var(--muted); font-size: 0.85rem; white-space: nowrap; }
.activity .factlist { margin-top: 12px; font-size: 0.9rem; }
.provider-cat { margin: 6px 0 0; color: var(--muted); font-size: 0.9rem; }
.provider-caps { margin: 12px 0 0; font-size: 0.85rem; overflow-wrap: anywhere; }
.provider-caps .k { color: var(--muted); }
/* Twee Connect-dimensies (providerondersteuning + jouw koppeling) */
.provider-dim { margin: 8px 0 0; font-size: 0.9rem; overflow-wrap: anywhere; }
.provider-dim .k { color: var(--muted); }
.provider-dim .v { font-weight: 600; }
.provider-history { margin: 4px 0 0; font-size: 0.8rem; }

/* Het welzijnsvlak: één kaart per gemeten feit.
   `auto-fit` met een minimum van 12rem, zodat de kaarten op een telefoon onder
   elkaar staan en op een breed scherm naast elkaar - zonder een breekpunt te
   kiezen dat bij een langere Franse label-tekst alsnog knelt. */
.wellnessfacts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.wellnessfact {
  padding: 12px 14px;
  border: 1px solid var(--edge);
  border-radius: 10px;
  background: var(--panel-raised, transparent);
}
.wellnessfact h3 {
  margin: 0;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  /* Franse labels zijn lang ("Variabilité de la fréquence cardiaque"); ze
     mogen afbreken in plaats van de kaart open te duwen. */
  overflow-wrap: anywhere;
}
.wellnessvalue {
  margin: 6px 0 0;
  font-size: 1.35rem;
  font-weight: 600;
  color: var(--text);
}
.wellnessfact .note { margin: 4px 0 0; font-size: 0.8rem; }
.provider-note { font-size: 0.85rem; }
.badge-ok { color: var(--ok); border-color: var(--ok-edge); }
.badge-muted { color: var(--muted); }

/* CTA binnen provider-kaarten: echte actie = link; status = niet-interactief. */
.cta {
  display: inline-flex;
  align-items: center;
  min-height: 42px;
  margin-top: 14px;
  padding: 8px 18px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--accent-strong);
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
}
.cta:hover { color: var(--accent-ink); background: var(--accent); }
.cta-disabled {
  border: 1px dashed var(--border);
  color: var(--muted);
  font-weight: 500;
}
.cta-disabled:hover { color: var(--muted); background: transparent; }

/* Lege metric-cards */
.metrics {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin: 4px 0 14px;
}
@media (min-width: 640px) { .metrics { grid-template-columns: repeat(4, 1fr); } }
.metric {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 14px;
  background: var(--panel);
}
.metric-label {
  display: block;
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  color: var(--muted);
}
.metric-empty { display: block; margin-top: 6px; color: var(--muted); font-size: 0.85rem; }
.emptystate .note { margin-top: 4px; }

/* Athlete State-statistieken (Performance) */
.statgrid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin: 14px 0 18px;
}
@media (min-width: 860px) { .statgrid { grid-template-columns: repeat(4, 1fr); } }
/* Home toont alleen de metingen die nog niet in taal zijn gezegd, dus het
   aantal kaarten varieert. Een vast raster van vier zou dan half leeg staan;
   deze variant verdeelt de beschikbare breedte over wat er werkelijk is. */
.contextgrid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
@media (min-width: 860px) {
  .contextgrid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
}
.stat {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 14px;
  background: var(--panel);
  display: grid;
  gap: 4px;
  align-content: start;
}
.stat-label {
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  color: var(--muted);
  overflow-wrap: anywhere;
}
.stat-value {
  font-size: 1.35rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.stat-meta { font-size: 0.8rem; color: var(--muted); overflow-wrap: anywhere; }

@media (prefers-reduced-motion: no-preference) {
  .statusdot { transition: background-color 200ms ease; }
}

/* Formulieren: login, activatie, check-in en beheeracties */
.authform { display: flex; flex-direction: column; gap: 8px; max-width: 24rem; }
.authform label { font-size: 0.85rem; color: var(--muted); letter-spacing: 0.02em; }
.authform input[type="text"],
.authform input[type="password"] {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  background: var(--ivory-sunk);
  color: var(--text);
  font-size: 1rem;
  margin-bottom: 6px;
}
.authform input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.authform-inline { margin-top: 12px; }
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 10px 18px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}
.btn:hover { filter: brightness(1.06); }
.btn-link { background: transparent; color: var(--accent); }
.formerror {
  border: 1px solid var(--border);
  border-left: 3px solid var(--warn);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin-bottom: 12px;
  color: var(--text);
}
.formnotice {
  border: 1px solid var(--border);
  border-left: 3px solid var(--ok);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin-bottom: 12px;
  color: var(--text);
}
.authalt { margin-top: 14px; }
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

/* Human-centered Home: attention budget */
.attention { display: grid; gap: 14px; margin-bottom: 18px; }
.insight {
  border: 1px solid var(--border);
  border-left: 3px solid var(--muted);
  background: var(--panel);
  border-radius: var(--radius);
  padding: 16px 18px;
}
.insight.primary {
  border-left-color: var(--accent);
  background: var(--teal-wash);
  border-color: var(--teal-edge);
  padding: 24px 26px;
}
/* Op de teal-wash haalt de gewone accent-teal net geen AA (4,47:1). Op dit
   ene vlak schrijft de diepere tint (6,93:1); het merkpalet zelf verandert
   niet, alleen de tint die op deze ondergrond leesbaar is. */
.insight.primary a { color: var(--accent-strong); }
.insight.primary h3 { font-size: 1.25rem; }
.insight.tone-positive { border-left-color: var(--ok); }
.insight.tone-attention { border-left-color: var(--warn); }
.insight h3 { margin: 0 0 4px; font-size: 1.05rem; }
.insight .why { margin: 6px 0 0; color: var(--muted); font-size: 0.92rem; }
.insight-cat {
  display: inline-block;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 4px;
}
.secondary-insights { display: grid; gap: 10px; }

/* Sessie van vandaag: één rustige regel met de intentie, niet een kaartenmuur. */
.sessionpanel .section-title { display: block; }
.sessionline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 14px;
  margin-bottom: 6px;
}
.sessionkind {
  font-size: clamp(1.35rem, 3.5vw, 1.7rem);
  font-weight: 640;
  letter-spacing: -0.01em;
  color: var(--text);
}
.sessionfact {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--teal-wash);
  border: 1px solid var(--teal-edge);
  color: var(--accent-strong);
  font-size: 0.86rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sessiongoal { margin: 10px 0 0; color: var(--muted); font-size: 0.92rem; }
.sessiongoal strong { color: var(--text); font-weight: 600; }

/* Connect-waardeketen: vier genummerde stappen die de weg van de data tonen.
   Bewust een <ol>: de volgorde is de boodschap. */
.valuechain {
  list-style: none;
  counter-reset: chain;
  margin: 18px 0 0;
  padding: 0;
  display: grid;
  gap: 14px;
}
@media (min-width: 900px) {
  .valuechain { grid-template-columns: repeat(4, 1fr); gap: 12px; }
}
.chainstep {
  counter-increment: chain;
  position: relative;
  padding: 16px 16px 16px 18px;
  border-radius: var(--radius-sm);
  background: var(--ivory-sunk);
  border-left: 3px solid var(--teal-edge);
}
.chainstep::before {
  content: counter(chain);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-bottom: 8px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 0.72rem;
  font-weight: 700;
}
.chainstep-label {
  display: block;
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent-strong);
  margin-bottom: 4px;
}
.chainstep-body {
  display: block;
  font-size: 0.9rem;
  color: var(--text);
}
.provenance {
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.86rem;
}

/* Provider-kaart: label boven waarde, zodat 'Platform support' en de status
   niet als één zin samenvloeien. */
.provider-dim { margin: 8px 0 0; }
.provider-dim .k {
  display: block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.provider-dim .v { color: var(--text); font-size: 0.94rem; }


@media (min-width: 720px) {
  .secondary-insights { grid-template-columns: repeat(2, 1fr); }
  /* Het attention budget laat hoogstens twee secundaire inzichten toe, maar
     vaak draagt het bewijs er maar één. Dat ene inzicht hoort dan de volle
     breedte te krijgen: een halve kaart naast een lege kolom leest als een
     ontbrekend tweede inzicht, terwijl er gewoon niets meer te zeggen valt. */
  .secondary-insights > .insight:only-child { grid-column: 1 / -1; }
}

/* Recente historie / trendcontext (Coach): hergebruikt de insight-kaart en de
   centrale merk-tokens; geen eigen kleuren, geen scorebord. */
.trendlist { display: grid; gap: 10px; margin-top: 12px; }

/* Uitleg bij de richting: compacte label/waarde-regels op de centrale tokens.
   Op smalle schermen staat het label boven de waarde zodat lange (Franse)
   teksten nooit horizontaal overlopen. */
.explainlist { display: grid; gap: 8px; margin-top: 10px; }
.explainline { margin: 0; display: grid; gap: 2px; }
.explainline .k {
  color: var(--muted);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.explainline .v { color: var(--text); }
@media (min-width: 720px) {
  .explainline { grid-template-columns: 13rem 1fr; gap: 12px; align-items: baseline; }
}

/* Doelcontext-formulier (Coach) */
.goalform { display: grid; gap: 6px; margin-top: 12px; max-width: 24rem; }
.goalform label { font-size: 0.85rem; color: var(--muted); }
.goalform select {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  background: var(--panel);
  color: var(--text);
  font-size: 1rem;
  min-height: 44px;
  /* Lange vertaalde opties mogen het formulier nooit breder maken dan de
     pagina (intrinsieke select-breedte begrenzen). */
  width: 100%;
  max-width: 100%;
  min-width: 0;
}
.goalform .btn { justify-self: start; margin-top: 6px; }

/* Mislukte formulieractie: zelfde notitiepatroon, waarschuwende accentlijn. */
.formnotice.form-error { border-left-color: var(--warn); }

/* Plan-van-vandaag-formulier (Coach): radio-chips + optionele duur. */
.planform { display: grid; gap: 8px; margin-top: 12px; max-width: 28rem; }
.planform fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.planform legend, .planform label { font-size: 0.85rem; color: var(--muted); }
.planchips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.planchip input[type="radio"] {
  position: absolute;
  opacity: 0;
  width: 1px; height: 1px;
}
.planchip label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 9px 14px;
  min-height: 44px;
  background: var(--panel);
  color: var(--text);
  font-size: 0.95rem;
  cursor: pointer;
}
/* Geselecteerd is nooit alleen kleur: rand + vinkje + gewicht. */
.planchip input[type="radio"]:checked + label {
  border-color: var(--accent-strong);
  border-width: 2px;
  padding: 8px 13px;
  font-weight: 600;
}
.planchip input[type="radio"]:checked + label::before {
  content: "✓";
  font-weight: 700;
}
.planchip input[type="radio"]:focus-visible + label {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.planform input[type="number"] {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  background: var(--panel);
  color: var(--text);
  font-size: 1rem;
  min-height: 44px;
  width: 100%;
  max-width: 12rem;
  min-width: 0;
}
.planform .btn { justify-self: start; margin-top: 6px; }
.planclear { margin-top: 10px; }
/* Elke uitklap is een aanraakdoel, ook zonder eigen klasse. Deze basisregel
   staat vóór de specifieke regels, zodat die haar nog kunnen overrulen. */
details > summary {
  min-height: 44px;
  display: flex;
  align-items: center;
}

.btn-secondary {
  /* Een tweede knop blijft een knop: dezelfde aanraakhoogte als `.btn`, ook
     wanneer het element die klasse niet ook draagt. */
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
}

/* Check-in form */
.checkin { display: grid; gap: 12px; margin-top: 14px; max-width: none; }
.checkin-row { display: grid; gap: 4px; }
.checkin-row label, .checkin-row legend { font-size: 0.85rem; color: var(--muted); }
.checkin fieldset.checkin-row legend { font-size: 0.95rem; color: var(--text); font-weight: 600; }
.checkin .formdisclosure { display: grid; gap: 10px; }
.checkin .planchips { margin-top: 4px; }
.checkin > .btn { justify-self: start; }
.askform { display: grid; gap: 12px; margin-top: 8px; }
.askform > .btn { justify-self: start; }
.askform h3 { margin: 8px 0 0; font-size: 0.95rem; }
.asksuggestions .btn { white-space: normal; text-align: left; }
.ask-answer-text p { margin: 0 0 10px; line-height: 1.55; }
.ask-sources summary { min-height: 44px; display: flex; align-items: center;
  cursor: pointer; color: var(--muted, #6b6b63); font-size: 0.9rem; }
.ask-sources p { margin: 0 0 4px; }
.checkin select, .checkin textarea, .askform textarea {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  background: var(--ivory-sunk);
  color: var(--text);
  font-size: 1rem;
  width: 100%;
  max-width: 24rem;
  min-height: 44px;
}
.checkin textarea { min-height: 60px; }
.askform textarea { max-width: none; min-height: 84px; font-family: inherit; }
@media (min-width: 640px) {
  .checkin-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
}

/* Charts */
.chart { margin: 0 0 8px; }
.chart figcaption { font-size: 0.92rem; margin-bottom: 4px; font-weight: 600; }
.chart-unit { color: var(--muted); font-size: 0.85rem; font-weight: 400; }
.chart-explain { margin: 0 0 8px; color: var(--muted); font-size: 0.82rem; }
.chart-svg {
  width: 100%; height: auto; display: block;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--ivory-sunk);
}
.chart-line { stroke: var(--accent); stroke-width: 2; }
.chart-dot { fill: var(--accent-strong); }
.chart-band { fill: var(--accent); opacity: 0.12; }
.chart-bar { fill: var(--accent-strong); opacity: 0.85; }
.chart-axis { fill: var(--muted); font-size: 11px; }
.chart-data { margin-top: 8px; font-size: 0.85rem; }
.chart-data summary { cursor: pointer; color: var(--muted); min-height: 44px; }
.chart-data table { width: 100%; border-collapse: collapse; margin-top: 6px; }
.chart-data th, .chart-data td {
  text-align: left; padding: 4px 8px; border-bottom: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
}
.charts { display: grid; gap: 20px; }
@media (min-width: 940px) { .charts { grid-template-columns: repeat(2, 1fr); } }
/* Twee grafieken naast elkaar horen op dezelfde hoogte te beginnen. Hun
   bijschrift en uitleg lopen per taal over een verschillend aantal regels, dus
   een vaste hoogte zou in het Frans meteen weer scheef staan. Subgrid laat de
   rasterrijen zelf de uitlijning dragen: bijschrift bij bijschrift, uitleg bij
   uitleg, grafiek bij grafiek - in elke taal. Waar subgrid ontbreekt blijft de
   huidige, gewoon gestapelde weergave staan; dat is een cosmetisch verschil,
   geen verlies van inhoud. */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 940px) {
    /* De rijafstand verhuist naar de figuur zelf: het raster telt nu de
       deelrijen van elke grafiek, dus een rasterrij-gap zou tussen bijschrift
       en grafiek komen te staan in plaats van tussen twee grafieken. */
    .charts { row-gap: 0; column-gap: 20px; }
    .charts > .chart {
      display: grid;
      grid-template-rows: subgrid;
      grid-row: span 4;
      row-gap: 0;
      margin-bottom: 24px;
    }
  }
}
/* ------------------------------------------------------------------
   Routes: formulier, voortgang, kaart en resultaat.
   Mobile-first: de keuzegroepen zijn kolommen op een telefoon en pas
   op ruimere schermen rijen. Elke raakbare control haalt minstens
   44px hoogte, zodat de flow buiten bruikbaar blijft.
   ------------------------------------------------------------------ */
.routeform { display: grid; gap: 1.25rem; }
.routefield { border: 0; padding: 0; margin: 0; min-width: 0; }
.routefield legend {
  padding: 0;
  margin-bottom: 0.5rem;
  font-weight: 600;
  color: var(--text);
}
.routechoices { display: grid; gap: 0.5rem; }
.routechoices-compass { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.routechoice-input:disabled + .routechoice {
  opacity: 0.55;
  cursor: not-allowed;
}
.routestart-elsewhere { justify-self: start; margin-top: 0.5rem; }
.routesearch { display: grid; gap: 0.5rem; margin-bottom: 0.75rem; }
.routesearch-label { display: grid; gap: 0.25rem; }
.routesearch-results {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.25rem;
}
.routesearch-result {
  width: 100%;
  text-align: left;
  display: grid;
  gap: 0.1rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
  /* Ruim genoeg om op een smartphone met de duim te raken. */
  min-height: 2.75rem;
}
.routesearch-name { font-weight: 600; }
.routesearch-where { font-size: 0.9em; opacity: 0.85; }
.routesearch-kind { font-size: 0.85em; opacity: 0.75; }
/* Het vinkje bij een exact gevonden huisnummer. Kleur alleen zou het verschil
   dragen voor wie hem ziet; het woord staat er daarom voluit bij. */
.routesearch-exact { color: var(--ok, var(--accent-strong)); opacity: 1; font-weight: 600; }
.routesearch-again { justify-self: start; }
.routeheading { margin-top: 0.5rem; }
.routechoices-wrap { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.routechoice-input {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
.routechoice {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
}
.routechoice-input:checked + .routechoice {
  border-color: var(--accent);
  background: var(--teal-wash);
  color: var(--accent-strong);
  font-weight: 600;
}
.routechoice-input:focus-visible + .routechoice {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.routecoords { display: grid; gap: 0.6rem; margin-top: 0.6rem; }
.routecoord { display: grid; gap: 0.25rem; font-size: 0.9rem; }
.routecoord input,
.routedistance input {
  min-height: 44px;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--bg-raised);
  color: var(--text);
  font: inherit;
  width: 100%;
  min-width: 0;
}
.routelocate { margin-bottom: 0.4rem; }
.routechips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.6rem; }
.routechip {
  /* 44 px is de ondergrens voor een aanraakdoel; 40 was er net onder en de
     chips staan op een telefoon dicht naast elkaar. */
  min-height: 44px;
  padding: 0.35rem 0.8rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.routechip[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--teal-wash);
  color: var(--accent-strong);
}
.routedistance { display: flex; align-items: center; gap: 0.5rem; }
.routeunit { color: var(--muted); }
.routesubmit { min-height: 52px; font-size: 1.05rem; }

/* Voortgang: stappen + gemeten tijd. Geen percentagebalk - die zou een
   precisie suggereren die de dienst niet levert. */
.routeprogress { display: grid; gap: 0.75rem; }
.routephases { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.35rem; }
.routephase {
  padding-left: 1.5rem;
  position: relative;
  color: var(--muted);
}
.routephase::before {
  content: "";
  position: absolute;
  left: 0; top: 0.45em;
  width: 0.6rem; height: 0.6rem;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
}
.routephase-done { color: var(--text); }
.routephase-done::before { background: var(--accent); border-color: var(--accent); }
.routephase-current { color: var(--accent-strong); font-weight: 600; }
.routephase-current::before {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--teal-edge);
}
.routetiming { font-size: 1.05rem; margin: 0; }
.routeeta { font-size: 1.05rem; font-weight: 600; color: var(--accent-strong); margin: 0; }
.routeworking { margin: 0; color: var(--text); }
.routecandidates { margin: 0; color: var(--muted); }
.routespinner {
  width: 1.6rem; height: 1.6rem;
  border-radius: 50%;
  border: 3px solid var(--border-strong);
  border-top-color: var(--accent);
}
@media (prefers-reduced-motion: no-preference) {
  .routespinner { animation: routespin 1s linear infinite; }
}
@keyframes routespin { to { transform: rotate(360deg); } }

/* Kaart: inline SVG, schaalt mee, nooit horizontale overflow. */
/* De beginwaarden zijn de hele-route-stand. Zonder JavaScript blijven ze staan,
   en dat is precies goed: de server-getekende kaart *is* dan de hele route. */
.routemap, .sessionmap {
  position: relative;
  --map-zoom: 1; --map-stroke: 4.4; --map-halo-width: 7.8; --map-base: 1;
  --map-marker: 1;
}
.routemap { margin: 0 0 1rem; }
/* De knoppen liggen op de kaart en niet erboven: op een telefoon is verticale
   ruimte het schaarst, en een knoppenrij die de kaart wegdrukt maakt precies
   het ding kleiner waar het om gaat. Rechtsboven, weg van de route die meestal
   het midden vult. */
.routemap-controls {
  position: absolute;
  top: 0.5rem; right: 0.5rem;
  display: flex; flex-direction: column; gap: 0.35rem;
  z-index: 1;
}
.routemap-control {
  min-width: 44px; min-height: 44px;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--panel);
  color: var(--text);
  font-size: 1.1rem; font-weight: 600;
  cursor: pointer;
}
.routemap-control-fit { font-size: 0.8rem; padding: 0 0.5rem; min-width: 0; }
.routemap-svg, .sessionmap .sm-canvas { touch-action: none; cursor: grab; }
.routemap-svg:active, .sessionmap .sm-canvas:active { cursor: grabbing; }
/* Lijndikten worden in beeldpunten gerekend en niet in tekeneenheden, zodat het
   venster ze niet meeschaalt. Wát die beeldpunten zijn, hangt af van hoe diep er
   is ingezoomd - en dat is de kern van deze kaart.

   De vorige regel hield de route op elke zoomstand even dik op het scherm. Dat
   klinkt als 'de route blijft goed zichtbaar', maar het betekende dat de
   verhouding tussen de route en de weg eronder nooit veranderde: de route lag
   permanent als een balk van zeven beeldpunten over een straat van ruim één, en
   inzoomen kon dus nooit laten zien wélke straat het is. */
.routemap-line {
  vector-effect: non-scaling-stroke;
  stroke-width: calc(var(--map-stroke) * 1px);
}
/* `--map-halo-width` en niet `--map-halo`. Die tweede naam bestaat al als
   KLEURTOKEN op `:root` (wit op licht, grafiet op donker), en een tweede
   definitie met dezelfde naam op deze scope overschaduwde haar: elke
   `stroke: var(--map-halo)` hierbinnen loste op naar het kale getal, werd
   ongeldig, en de donkere halokleur is daardoor nooit toegepast. Op grafiet
   kreeg de route dus een witte rand van bijna acht beeldpunten - precies het
   tegendeel van 'de route valt op zonder de kaart te overschreeuwen'. Twee
   betekenissen horen niet op één tokennaam. */
.routemap-halo {
  vector-effect: non-scaling-stroke;
  stroke-width: calc(var(--map-halo-width) * 1px);
}
/* De ondergrond gaat de andere kant op: dieper inzoomen maakt de wegen dikker.
   Zonder dat blijft een woonstraat een haarlijn van 1,2 beeldpunt op elke
   schaal, en levert 'meer detail' alleen meer grijs op in plaats van een
   leesbaar wegennet met kruispunten. */
.routemap .sm-base, .sessionmap .sm-base { vector-effect: non-scaling-stroke; }
.routemap .sm-base-water, .sessionmap .sm-base-water { stroke-width: calc(1.6px * var(--map-base)); }
.routemap .sm-base-rail, .sessionmap .sm-base-rail { stroke-width: calc(1px * var(--map-base)); }
.routemap .sm-base-path, .sessionmap .sm-base-path { stroke-width: calc(0.8px * var(--map-base)); }
.routemap .sm-base-road, .sessionmap .sm-base-road { stroke-width: calc(1px * var(--map-base)); }
.routemap .sm-base-major, .sessionmap .sm-base-major { stroke-width: calc(2.2px * var(--map-base)); }
/* De rand om een plaatsnaam hoort bij de letter en niet bij het venster: zonder
   deze regel groeit ze met de zoom mee tot de naam een vlek is. */
.routemap .sm-place, .sessionmap .sm-place {
  font-size: calc(12px * var(--map-zoom));
  vector-effect: non-scaling-stroke;
}
/* Straat- en wegnamen: klein, gedempt, langs de weg, en nooit boven de route.
   pointer-events uit, zodat een naam nooit een tik op de kaart vangt. */
.sm-way {
  fill: #5f5b50; font-size: calc(11px * var(--map-zoom)); text-anchor: middle;
  paint-order: stroke; stroke: var(--panel-strong, #f7f7f5); stroke-width: 3px;
  vector-effect: non-scaling-stroke; pointer-events: none;
}
.sm-way-major { font-weight: 600; }
.sm-way-path { font-style: italic; fill: #7a7668; }
/* Markeringen: een stip op straatniveau, geen bal op de hele route. De straal
   wordt in tekeneenheden gezet (r via CSS), dus ze volgt het venster tenzij de
   zoomfactor haar corrigeert - en --map-marker laat haar bovendien krimpen. */
.routemap-start { r: calc(8px * var(--map-marker) * var(--map-zoom)); }
.routemap-end { r: calc(7px * var(--map-marker) * var(--map-zoom)); }
.sessionmap .sm-start, .sessionmap .sm-end { r: calc(7px * var(--map-marker) * var(--map-zoom)); }
.sessionmap .sm-cursor { r: calc(9px * var(--map-marker) * var(--map-zoom)); }
.routemap-start, .routemap-end, .sessionmap .sm-cursor { vector-effect: non-scaling-stroke; }
/* De gereden lijn volgt dezelfde diepteregel als de gegenereerde route. */
.sessionmap .sm-line { stroke-width: calc(var(--map-stroke) * 0.85px); }
.sessionmap .sm-line-window { stroke-width: calc(var(--map-stroke) * 1.1px); }
.sessionmap .sm-line-faded { stroke-width: calc(var(--map-stroke) * 0.55px); }
/* De acties staan naast elkaar zolang er plaats is, en onder elkaar zodra die
   er niet meer is. Downloaden is de hoofdactie; een andere route zoeken staat
   ernaast en niet verstopt onderaan de pagina. */
.routeactions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.75rem 0 0; }
.routeactions .btn { flex: 1 1 auto; }
.pagehero-compact { padding-bottom: 0.25rem; }
.routemap-svg {
  display: block;
  width: 100%;
  height: auto;
  max-width: 100%;
  background: var(--panel-strong);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.routemap-line { stroke: var(--accent); }
/* Een lichte rand onder de routelijn. Zonder die rand verdwijnt de route op een
   kaart vol wegen precies daar waar ze het meest telt: in het dorp. Ze krimpt
   sneller dan de lijn zelf, want bij straatdetail is contrast goedkoper dan
   ruimte - en de rand is wat de weg eronder afdekt. */
.routemap-halo { stroke: #ffffff; opacity: 0.85; }
.routemap-start { fill: var(--accent-strong); stroke: var(--accent-ink); stroke-width: 2; }
.routemap-end { fill: var(--warn); stroke: var(--accent-ink); stroke-width: 2; }
.routemap-caption { margin-top: 0.5rem; }

/* De bewijstoestand van 'Je context'. Kleur is hier een HULP en nooit de
   drager: de zin ernaast zegt hetzelfde, en wie de kleur niet ziet mist niets.

   Lees wat deze rollen betekenen. Ze gaan over het BEWIJS en niet over de
   atleet: groen zegt 'er is genoeg vergelijkbaar bewijs om te beschrijven waar
   vandaag ligt', niet 'het gaat goed'. Een rusthartslag onder de eigen band
   krijgt hier dus géén waarschuwingskleur - de eigenaar van dit bewijs
   verklaart uitdrukkelijk dat onder de band niet 'slechter' betekent, en een
   kleur die dat wel zou zeggen, voegt een oordeel toe dat geen enkel
   NORYA-domein heeft genomen. */
.readystate {
  display: inline-flex; align-items: center; gap: 0.4rem;
  margin: 0 0 0.75rem; font-size: 0.9rem; font-weight: 600;
}
.readystate::before {
  content: ""; width: 0.6rem; height: 0.6rem; border-radius: 50%;
  background: currentColor; flex: 0 0 auto;
}
.readystate-ready { color: var(--ok); }
.readystate-attention { color: var(--warn); }
.readystate-neutral { color: var(--muted); }

/* Resultaat: feiten en intent-uitkomsten. */
.routefacts { display: grid; gap: 0.6rem; margin: 1rem 0; }
.routefact { display: flex; justify-content: space-between; gap: 1rem; }
.routefact-label { color: var(--muted); }
.routefact-value { font-weight: 600; text-align: right; }
.routeoutcomes { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem; }
.routeoutcome {
  padding: 0.6rem 0.75rem;
  border-left: 3px solid var(--border-strong);
  border-radius: 0 8px 8px 0;
  background: var(--panel-strong);
  display: grid;
  gap: 0.2rem;
}
.routeoutcome-ok { border-left-color: var(--ok); }
.routeoutcome-attention { border-left-color: var(--warn); }
.routeoutcome-reason { color: var(--muted); font-size: 0.9rem; }
.routegpx { display: inline-flex; min-height: 52px; align-items: center; }
/* De Garmin-course draagt een lang label - in het Frans 'Parcours Garmin avec
   messages d'entrainement' - en staat op een telefoon daarom op een eigen
   regel. Zonder die basis knijpt de flexrij de drie acties tot onleesbare
   kolommen; vanaf 640 px is er breedte genoeg om weer mee te delen. */
.routecourse {
  display: inline-flex;
  min-height: 52px;
  align-items: center;
  justify-content: center;
  text-align: center;
  flex: 1 1 100%;
}
.routedetails { margin-top: 1rem; }
.routedetails summary { cursor: pointer; color: var(--muted); min-height: 44px; }

@media (min-width: 640px) {
  .routechoices { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .routechoices-wrap {
    grid-auto-flow: row;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  /* De kompasroos telt negen keuzes. Zonder deze regel zet de kolomflow
     hierboven ze op één rij en wordt elke knop onleesbaar smal. */
  .routechoices-compass {
    grid-auto-flow: row;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .routecoords { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Zoekveld en knop naast elkaar zodra er breedte is; op een smartphone
     blijven ze onder elkaar staan en dus met de duim bereikbaar. */
  .routesearch { grid-template-columns: 1fr auto; align-items: end; }
  .routesearch-label { grid-column: 1; }
  .routesearch-go { grid-column: 2; }
  .routesearch > .note,
  .routesearch-results { grid-column: 1 / -1; }
  .routecourse { flex: 1 1 auto; }
}

/* ------------------------------------------------------------------
   Dagelijkse trainingservaring.

   Vier kleine componenten bovenop de bestaande tokens en kaarten; geen tweede
   design system. Ze bestaan omdat de bestaande varianten opmaak dragen die op
   deze markup niet past: `.planchip` is voor een radioknop mét label, en
   `.chainstep` telt binnen een teller die zijn eigen container reset.
   ------------------------------------------------------------------ */

/* Ritme tussen de kaarten binnen één sectie. */
.tcard + .tcard { margin-top: 14px; }
.tcard h3 { margin: 0 0 10px; }

/* Statuspillen: compact, niet-interactief, en op smalle schermen aflopend
   in plaats van uitlopend. */
.tchips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 12px;
  /* Ook als lijst (`<ul>`) gebruikt: geen opsommingstekens en geen inspringing,
     anders staat er een punt naast elke knop. */
  list-style: none;
  padding: 0;
}
.tchips > li { list-style: none; }
/* Kalenderweek: een voorbije dag blijft leesbaar maar treedt terug; vandaag
   krijgt de accentrand zodat het oog er als eerste op valt. */
.tcard-past { opacity: 0.72; }
.tcard-past h3 { color: var(--muted); }
.tcard-today { border-color: var(--accent-strong); border-width: 2px; }
.home-coach-day { display: grid; gap: 8px; margin-top: 6px; }
/* Het voorschrift: de regel die een atleet overtypt in TrainingPeaks of op
   zijn fietscomputer. Ze staat open en leest als één zin. */
.prescription { display: grid; gap: 8px; margin: 10px 0 4px; }
/* Begeleiding leest als tekst en niet als tabel: het bereik hoort onder zijn
   label te staan, met de bron eronder. Links uitgelijnd - een rechts
   uitgelijnd bereik zweeft los van het woord waar het bij hoort. */
.fuel-guidance li {
  display: grid;
  gap: 2px;
  padding: 8px 0;
  justify-items: start;
}
.fuel-guidance .v { font-weight: 600; text-align: left; }
.fuel-source { color: var(--muted); font-size: 0.8rem; }

/* Het maaltijdvoorstel. Mobile-first: één kolom, de maaltijd als kaart, de
   hoeveelheid direct naast het voedingsmiddel zodat een boodschappenlijst
   leesbaar blijft op 390 px. Geen tabel - een tabel breekt op een telefoon. */
/* Home als persoonlijk vertrekpunt: datum klein en rustig boven de
   begroeting, en daaronder één zin. Geen dashboard-kop. */
.homehero-date {
  margin: 0 0 2px;
  color: var(--muted);
  font-size: 0.85rem;
  text-transform: lowercase;
}
.homehero h1 { margin-top: 0; }
.homehero-summary {
  margin: 10px 0 0;
  font-size: 1.02rem;
  line-height: 1.55;
}
.homehero-encouragement {
  margin: 8px 0 0;
  padding: 8px 12px;
  border-left: 3px solid var(--accent-strong);
  background: var(--ivory-sunk);
  border-radius: var(--radius-sm);
  font-weight: 600;
}
.homefuel-energy { margin: 4px 0 2px; font-weight: 600; }
.homefuel-next { margin: 2px 0 8px; }
/* De tweede navigatierij draagt de vlakken die zelden nodig zijn. Ze staat
   visueel onder de eerste en is even bereikbaar; kleiner, niet verstopt. */
.navsecondary { margin-top: 2px; }
.navsecondary .navlink { font-size: 0.85rem; opacity: 0.85; }
/* Een geneste uitklap staat visueel ín zijn ouder, zodat 'ergens last?' niet
   als losse vraag naast de rest komt te staan. */
.formdisclosure-nested {
  margin: 8px 0 4px;
  padding-left: 10px;
  border-left: 2px solid var(--line);
}
/* De contextuele vraag aan NORYA: zichtbaar, maar nooit de primaire actie. */
.askcontext { font-weight: 600; }
/* Een groep achtergrondpanelen. De kop is een echte, aanraakbare regel; de
   panelen erbinnen houden hun eigen vorm. */
.panelgroup {
  margin: 12px 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--ivory);
}
.panelgroup > summary {
  padding: 14px 16px;
  min-height: 44px;
  display: flex;
  align-items: center;
  font-weight: 600;
  cursor: pointer;
}
.panelgroup > summary::marker { color: var(--muted); }
.panelgroup > .panel { margin: 0 10px 10px; }
.mealplan-panel .lead { margin-bottom: 4px; }
.mealplan-energy {
  margin: 6px 0 2px;
  font-size: 1.05rem;
  font-weight: 600;
}
.mealplan {
  list-style: none;
  margin: 14px 0 10px;
  padding: 0;
  display: grid;
  gap: 10px;
}
.mealcard {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--ivory-sunk);
  padding: 12px 14px;
}
.mealcard-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 6px;
}
.mealcard-title { margin: 0; font-size: 1rem; }
.mealcard-time { color: var(--muted); font-size: 0.85rem; }
.mealcard-energy {
  margin-left: auto;
  font-weight: 600;
  font-size: 0.9rem;
  white-space: nowrap;
}
.mealitems { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.mealitem {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  column-gap: 10px;
  padding: 6px 0;
  border-top: 1px solid var(--line);
}
.mealitem-name { font-weight: 500; }
.mealitem-amount { font-variant-numeric: tabular-nums; white-space: nowrap; }
.mealitem-energy {
  grid-column: 1;
  color: var(--muted);
  font-size: 0.82rem;
}
/* De registratielink is een echt aanraakbaar doel en geen tekstje: 44 px hoog,
   rechts van de hoeveelheid, en zichtbaar als actie. */
.mealitem-log {
  grid-column: 2;
  align-self: center;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 4px;
  font-size: 0.85rem;
  font-weight: 600;
}
.mealmacros {
  list-style: none;
  margin: 10px 0 6px;
  padding: 0;
  display: grid;
  gap: 6px;
}
.mealmacro { display: grid; gap: 1px; }
.mealmacro-value { font-weight: 600; }
.mealmacro-band { color: var(--muted); font-size: 0.82rem; }
@media (min-width: 720px) {
  .mealplan { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mealmacros { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.prescription-line {
  margin: 0;
  padding: 10px 12px;
  border-left: 3px solid var(--accent-strong);
  background: var(--ivory-sunk);
  border-radius: var(--radius-sm);
  font-size: 0.98rem;
  line-height: 1.5;
}
.home-coach-day .tchips { margin: 0; }
.tchip {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--panel-strong);
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.35;
  /* Franse labels zijn de langste; ze mogen breken in plaats van de rij te
     verbreden en horizontale overflow te veroorzaken. */
  overflow-wrap: anywhere;
}
.tchip-ok { color: var(--accent-strong); border-color: var(--teal-edge); background: var(--teal-wash); }
.tchip-muted { color: var(--muted); }
/* De evenementdag. Een eigen toon, want ze is noch een gewone trainingsdag
   (teal) noch een rustdag (gedempt). Het gewicht komt van de kleur én van het
   vettere label: kleur alleen zou de dag onvindbaar maken voor wie haar niet
   ziet. */
.tchip-event {
  color: var(--event);
  border-color: var(--event-edge);
  background: var(--event-wash);
  font-weight: 600;
}

/* De dagen ná het evenement. Een eigen toon naast rust, training en evenement,
   want deze dag is geen van die drie: er staat wél een voorschrift, maar het is
   met opzet lichter dan de opbouw eromheen. Warm en stil - verwant aan de amber
   van het evenement waar dit herstel bij hoort, en duidelijk niet de teal van
   een opbouwdag. Nooit alleen kleur: de pil draagt haar eigen tekst
   ('Herstel na je doel') en de dagkaart legt het in een eigen blok uit. */
.tchip-recovery {
  color: var(--recovery);
  border-color: var(--recovery-edge);
  background: var(--recovery-wash);
  font-weight: 600;
}

/* Het blok onder de chips op een evenementdag: welk doel deze dag opeist, en
   wat er daardoor niet staat. Geen kader rondom maar een gekleurde rand aan één
   zijde - dat onderscheidt zonder er een waarschuwingsvak van te maken. */
.tevent {
  margin: 10px 0 0;
  padding: 10px 12px;
  border-left: 3px solid var(--event);
  background: var(--event-wash);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.tevent p { margin: 0; }
.tevent .tevent-goal { font-weight: 600; color: var(--text); }
.tevent .tevent-note { margin-top: 4px; color: var(--muted); font-size: 0.9rem; }

/* Het blok onder de chips op een hersteldag: dat deze dag na het doel valt, en
   welk plafond Coach er hanteert. Dezelfde vorm als het evenementblok - een rand
   aan één zijde, geen waarschuwingsvak - in de rustiger herstelkleur, want dit
   herstel hoort bij dat evenement maar vraagt minder aandacht dan de dag zelf.
   Het staat naast het voorschrift en niet in plaats ervan: de atleet moet nog
   steeds kunnen lezen wat hij vandaag rijdt. */
.trecovery {
  margin: 10px 0 0;
  padding: 10px 12px;
  border-left: 3px solid var(--recovery);
  background: var(--recovery-wash);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.trecovery p { margin: 0; }
.trecovery .trecovery-lead { font-weight: 600; color: var(--text); }
.trecovery .trecovery-note {
  margin-top: 4px;
  color: var(--muted);
  font-size: 0.9rem;
}

/* De opbouw van een voorschrift: een genummerde lijst, want de volgorde is de
   boodschap. De teller wordt hier gereset, zodat een tweede training op
   dezelfde dag weer bij 1 begint. */
.tblocks {
  list-style: none;
  counter-reset: tblock;
  margin: 10px 0 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.tblock {
  counter-increment: tblock;
  position: relative;
  padding: 14px 16px 14px 46px;
  border-radius: var(--radius-sm);
  background: var(--panel-strong);
  border-left: 3px solid var(--teal-edge);
}
.tblock::before {
  content: counter(tblock);
  position: absolute;
  left: 14px;
  top: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--border);
  font-size: 0.72rem;
  color: var(--muted);
}
.tblock-name {
  display: block;
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent-strong);
  margin-bottom: 8px;
}
.tblock .tchips { margin-bottom: 0; }
.tblock .note { margin-top: 8px; }

/* Doelacties: twee kleine knoppen die op een telefoon onder elkaar mogen. */
.tactions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
}
.tactions form { margin: 0; }

/* De bevestigde verwijdering. Twee stappen in het document zelf: de balk opent
   de bevestiging, en pas daarbinnen bestaat een verzendknop. `<details>` draagt
   de open/dicht-toestand voor een schermlezer, werkt met toetsenbord en werkt
   zonder JavaScript - drie dingen die een `confirm()` geen van alle doet. */
.confirm { width: 100%; }
.confirm-open {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 10px 14px;
  font-weight: 600;
  color: var(--accent);
  border-radius: var(--radius-sm);
}
.confirm-open:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
}
.confirm-body {
  margin-top: 8px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  /* Een gedempte waarschuwingskleur en geen alarmrood: dit is een handeling die
     de atleet zelf koos, geen storing die hem overkomt. */
  border-left: 3px solid var(--warn);
  border-radius: var(--radius-sm);
}
.confirm-body .note { margin: 0 0 8px; }
.confirm-body form { margin: 4px 0 0; }
/* De onomkeerbare knop draagt de waarschuwingskleur, en daarnaast staat het
   woord dat zegt wat er gebeurt - kleur is nooit de enige drager. */
/* Een onomkeerbare actie draagt de gevaarrol, niet de aandachtsrol: die
   twee betekenen niet hetzelfde en mogen er dus niet hetzelfde uitzien. */
.btn-danger { background: var(--danger); color: var(--danger-ink); }

/* Formuliervelden van het doelformulier. Volle breedte binnen `.goalform`,
   met een raakdoel dat op een telefoon werkt. */
.tfield { display: grid; gap: 4px; margin-top: 8px; }
.tfield > span:first-child { font-size: 0.85rem; color: var(--muted); }
.tfield input,
.tfield select {
  width: 100%;
  min-height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  background: var(--panel);
  color: var(--text);
  font-size: 1rem;
}
.tfield .note { margin-top: 2px; font-size: 0.8rem; }

/* Een metriek zonder waarde draagt een toestand, geen getal. Ze krijgt daarom
   het rustige tekstformaat: als groot cijfer gezet zou 'te weinig bewijs' als
   meting lezen. */
.tstat-state { align-self: end; }
.goalform { max-width: 32rem; }

/* Het voorschriftformulier. Één kolom op een telefoon, twee vanaf een breed
   scherm: de velden zijn kort en een enkele kolom van twintig regels dwingt
   onnodig scrollen af. Nergens een vaste breedte, zodat de langere Franse
   labels niets buiten de viewport duwen. */
.workoutform { max-width: 48rem; }

/* Het invoervlak is ondergeschikt aan wat er vandaag staat: het staat
   dichtgeklapt tot de atleet het opent. Werkt zonder JavaScript en blijft
   toetsenbord- en schermlezerbedienbaar. */
.formdisclosure > summary {
  cursor: pointer;
  padding: 10px 0;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--accent-strong);
}
.formdisclosure > summary::marker { color: var(--muted); }
.formdisclosure[open] > summary { margin-bottom: 4px; }
.wblock {
  margin: 12px 0 0;
  padding: 12px 14px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel-alt, transparent);
  min-width: 0;
}
.wblock > legend {
  padding: 0 6px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
}
/* Een bereik is één begrip met twee grenzen: ze staan naast elkaar zodat
   'vanaf' en 'tot' als paar leesbaar zijn, en onder elkaar zodra dat niet
   meer past. */
.trange {
  margin: 8px 0 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.trange > legend {
  padding: 0;
  font-size: 0.85rem;
  color: var(--muted);
}
.trange .tfield { margin-top: 4px; }

@media (min-width: 640px) {
  .trange {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
  }
  .trange > legend { grid-column: 1 / -1; }
}

/* Fuel: dagbeeld, snel vastleggen, herhalen en gezondheidscontext.

   Mobile-first en bewust arm aan nieuwe vormen: het paneel, de stat-kaart,
   de knop en de keuzeknop bestaan al en worden hier hergebruikt. Wat er
   bijkomt is uitsluitend de lijstopmaak die voeding nodig heeft - een regel
   per registratie met de hoeveelheid ernaast, en genoeg raakoppervlak om
   staand in de keuken te bedienen.
   ------------------------------------------------------------------ */
.fuelmeal + .fuelmeal { margin-top: 1.25rem; }
.fuelentries,
.fuelrecents,
.fuelresults { list-style: none; margin: 0.4rem 0 0; padding: 0; display: grid; gap: 0.5rem; }

.fuelentry {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.4rem 0.8rem;
  align-items: start;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--border);
}
.fuelentry:last-child { border-bottom: 0; }
.fuelentry-main { display: grid; gap: 0.15rem; min-width: 0; }
.fuelentry-name { font-weight: 600; overflow-wrap: anywhere; }
.fuelentry-quantity { color: var(--muted); font-variant-numeric: tabular-nums; }
.fuelentry-measured { color: var(--muted); font-size: 0.85rem; }
.fuelentry-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.2rem;
}
.fuelentry-energy { font-variant-numeric: tabular-nums; font-weight: 600; }
/* Een registratie zonder voedingswaarde krijgt een eigen regel over de volle
   breedte: die uitleg mag niet als voetnoot naast een getal verdwijnen. */
.fuelentry-missing {
  grid-column: 1 / -1;
  margin: 0.1rem 0 0;
  color: var(--muted);
  font-size: 0.85rem;
}
.fuelwithdraw { margin: 0; }
.fuelwithdraw button {
  min-height: 44px;
  padding: 0 0.2rem;
  border: 0;
  background: transparent;
  color: var(--accent);
  font: inherit;
  cursor: pointer;
}
.fuelwithdraw button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.fuelempty-title { font-weight: 600; margin: 0.2rem 0; }
/* De dekking is geen voetnoot maar een voorwaarde om de totalen te lezen. */
.fuelcoverage {
  border: 1px solid var(--border);
  border-left: 3px solid var(--warn);
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.75rem;
  margin: 0.2rem 0 0.8rem;
}

.fuelsearch { display: grid; gap: 0.35rem; margin-bottom: 0.8rem; }
.fuelsearch-row { display: flex; gap: 0.5rem; }
.fuelsearch input[type="search"] {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--bg-raised);
  color: var(--text);
  font: inherit;
}

.fuelresult {
  display: grid;
  gap: 0.15rem;
  min-height: 52px;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--panel);
  color: var(--text);
  text-decoration: none;
}
.fuelresult:hover { border-color: var(--accent); background: var(--teal-wash); }
.fuelresult-name { font-weight: 600; overflow-wrap: anywhere; }
.fuelresult-meta { color: var(--muted); font-size: 0.85rem; overflow-wrap: anywhere; }

.fuelrecent form {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
}
.fuelrecent:last-child form { border-bottom: 0; }
.fuelrecent-main { display: grid; gap: 0.1rem; min-width: 0; }
.fuelrecent-name { font-weight: 600; overflow-wrap: anywhere; }
.fuelrecent-meta { color: var(--muted); font-size: 0.85rem; }

.fuelform { display: grid; gap: 0.5rem; }
.fuelform label { font-size: 0.9rem; color: var(--muted); }
.fuelform input[type="text"],
.fuelform input[type="date"],
.fuelform select {
  min-height: 44px;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--bg-raised);
  color: var(--text);
  font: inherit;
  width: 100%;
  min-width: 0;
}
.fuelform .btn { justify-self: start; margin-top: 0.4rem; }
.fuelfield { border: 0; padding: 0; margin: 0.4rem 0 0; min-width: 0; }
.fuelfield legend { padding: 0; margin-bottom: 0.4rem; font-weight: 600; color: var(--text); }
.fuelchoices { display: grid; gap: 0.4rem; }
.fuelchoice {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  color: var(--text);
  font-size: 1rem;
}
.fuelmanual,
.fuellipidadd { margin-top: 0.8rem; }
.fuelmanual summary,
.fuellipidadd summary {
  min-height: 44px;
  display: flex;
  align-items: center;
  color: var(--accent);
  font-weight: 600;
  cursor: pointer;
}

/* De koerskeuze staat altijd onder elkaar, ook op een breed scherm: elke regel
   draagt een label en soms een hele redenzin, en die naast elkaar persen maakt
   de langste (Franse) variant onleesbaar. Vandaar een eigen klasse in plaats van
   een aanpassing van .fuelchoices, dat elders juist wel naast elkaar hoort. */
.fuelchoice-block { align-items: flex-start; flex-wrap: wrap; padding: 0.1rem 0; }
.fuelchoice-block .fuelchoice-label { flex: 1 1 auto; min-width: 0; }
/* 'Niet beschikbaar' staat als woorden in de regel zelf; deze opmaak is het
   zwakste van de drie signalen en nooit het enige. */
.fuelchoice-reason {
  flex: 1 0 100%;
  margin-left: 1.6rem;
  color: var(--muted);
  font-size: 0.9rem;
}
.fuelchoice.is-off .fuelchoice-label { color: var(--muted); }
/* De gekozen koers zegt 'actief' in woorden; de omlijning is het tweede signaal. */
.fuelchoice.is-active { border-color: var(--accent); }
.fuelchoice-active {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.05rem 0.45rem;
  border-radius: 999px;
  background: var(--accent-wash, rgba(111, 184, 171, 0.18));
  color: var(--accent);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  vertical-align: middle;
}
/* Het berekende bereik is informatie naast de keuze, geen uitgeschakelde keuze:
   een eigen blok met een eigen kop, zodat 'nog niet beschikbaar' over het
   bereik gaat en nooit over 'prestatie eerst'. */
.fuelrange {
  margin-top: 1rem;
  padding: 0.75rem 0.9rem;
  border: 1px dashed var(--border);
  border-radius: 0.6rem;
}
.fuelrange-heading { margin: 0 0 0.2rem; font-size: 0.95rem; }
.fuelrange-state { margin: 0 0 0.3rem; color: var(--muted); font-weight: 600; font-size: 0.85rem; }
.fuelrange .note { margin: 0; }

@media (min-width: 640px) {
  .fuelchoices { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .fuelchoices-stacked { grid-auto-flow: row; grid-auto-columns: auto; }
  .fuelform input[type="text"],
  .fuelform input[type="date"],
  .fuelform select { max-width: 22rem; }
}

/* ---------------------------------------------------------------------------
   Laboratoriumverslag-voorbeeld.

   Bewust geen tabel met vijf kolommen: dit scherm wordt op een telefoon gebruikt
   (daar komt het verslag binnen), en een brede tabel valt daar uit elkaar of
   dwingt tot horizontaal schuiven. Elke bepaling is daarom een zelfstandig blok
   dat op elke breedte hetzelfde leest. --------------------------------------- */
.hr-form { display: grid; gap: 10px; justify-items: start; }
.hr-form input[type="file"] {
  width: 100%;
  max-width: 100%;
  color: var(--muted);
  font: inherit;
}
.hr-candidates { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 14px; }
.hr-candidate {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  background: var(--panel-strong);
}
.hr-candidate-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin: 0 0 10px;
}
.hr-candidate-name { font-weight: 600; }
/* De redenen horen bij hun eigen bepaling. Losgeknipt zouden ze als algemene
   waarschuwing gaan klinken, en dat is een sterkere uitspraak dan de ontleding
   deed. */
.hr-reasons { list-style: disc; margin: 10px 0 0; padding-left: 20px; }
.hr-reasons li + li { margin-top: 6px; }
.hr-failure { border-color: var(--warn-edge, var(--border)); }

/* Maaltijdfoto: uploadpaneel, voorstel en nakijkscherm.

   Mobiel eerst en zonder vaste breedtes: dit scherm wordt met een telefoon in
   de hand gebruikt, staand naast een bord. Alles stapelt onder 640px, de
   invoervelden zijn met een duim te raken, en de Franse teksten (die langer
   zijn) breken af in plaats van horizontaal te schuiven. */
.mp-panel .mp-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 12px 0 0;
}
.mp-panel input[type="file"] {
  width: 100%;
  max-width: 100%;
  padding: 10px 0;
}
.mp-privacy { margin-top: 12px; }
.mp-result:empty { display: none; }
.mp-result { margin-top: 14px; }

.mp-items {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 14px 0;
}
.mp-item {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  background: var(--panel-strong);
}
.mp-item-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 12px;
  margin: 0 0 8px;
}
.mp-item-name { font-weight: 600; }
/* De zekerheid staat in woorden náást de naam en nooit als kleur alleen:
   status die alleen met kleur wordt verteld, bestaat niet voor wie haar niet
   ziet. */
.mp-confidence { white-space: nowrap; }
.mp-said { font-style: italic; }
/* De geschatte band is hulp, geen invulling. Ze staat visueel apart van het
   veld zodat ze nooit voor een ingevulde waarde kan worden aangezien. */
.mp-estimate { font-weight: 500; }
.mp-unresolved { margin-top: 8px; }

.mp-item-form,
.mp-search {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 8px 10px;
  margin: 10px 0 0;
}
.mp-item-form label,
.mp-search label {
  flex: 1 1 100%;
  font-size: 0.92em;
}
.mp-item-form input,
.mp-search input {
  flex: 1 1 8rem;
  min-width: 0;
  min-height: 44px;
}
.mp-item-form .btn,
.mp-search .btn { min-height: 44px; }
.mp-item-reject { margin: 10px 0 0; }

.mp-choices {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.mp-choice {
  border-top: 1px solid var(--border);
  padding-top: 10px;
}
.mp-choice-name { font-weight: 600; }
.mp-item-rejected { opacity: 0.72; }
.mp-item-confirmed .mp-item-confirmed { font-weight: 600; }

.mp-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.mp-actions .btn { min-height: 44px; }

@media (min-width: 640px) {
  .mp-item-form label,
  .mp-search label { flex: 0 0 auto; }
  .mp-actions {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }
}
/* ------------------------------------------------------------------
   De opbouwstrook: acht weken op één blik.

   Eén rij per week, en op een telefoon precies dezelfde rij - geen tweede
   opmaak die anders kan verouderen. De balk is beeld: hij draagt aria-hidden
   en de weekduur staat er in letters naast, zodat een schermlezer de week
   volledig hoort zonder de balk te moeten kunnen zien.
   ------------------------------------------------------------------ */
.prograil { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 10px; }
.prograil-row {
  display: grid;
  grid-template-columns: minmax(4.5rem, auto) 1fr;
  grid-template-areas: "when chips" "bar time";
  align-items: center;
  gap: 6px 12px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel-strong);
}
/* De huidige week is de rij waar de atleet naar zoekt; ze krijgt de accentrand
   en verder niets - geen kleurvlak dat de chips onleesbaar maakt. */
.prograil-now { border-color: var(--teal-edge, var(--border-strong)); }
.prograil-when { grid-area: when; font-weight: 600; overflow-wrap: anywhere; }
.prograil-chips { grid-area: chips; display: flex; flex-wrap: wrap; gap: 6px; }
.prograil-bar {
  grid-area: bar;
  display: block;
  height: 8px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}
.prograil-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent, #0f766e);
}
.prograil-time { grid-area: time; text-align: right; color: var(--muted); font-size: 0.85rem; }
.prograil-go { grid-area: go; color: var(--muted); align-self: center; }

/* De rij is sinds de weeknavigatie een echte <a>. De grid staat daarom op de
   link en niet meer op de <li>: zo is het hele vlak het aanraakgebied, en niet
   een datum van vier tekens. Geen eigen focusstijl - de stylesheet heeft er al
   een, en een tweede zou ervan kunnen afwijken. */
.prograil-link {
  display: grid;
  grid-template-columns: minmax(4.5rem, auto) 1fr auto;
  grid-template-areas: "when chips go" "bar time time";
  align-items: center;
  gap: 6px 12px;
  min-height: 48px;
  color: inherit;
  text-decoration: none;
}
.prograil-link:hover .prograil-when { text-decoration: underline; }
/* De week die de atleet op dit moment leest. De rand is de versterking; het
   woord ('Je leest deze week') en aria-current dragen de betekenis. Zou het
   verschil uitsluitend in de achtergrondkleur zitten, dan bestond het niet voor
   wie die kleur niet ziet. */
.prograil-selected { border-color: var(--accent, #0f766e); border-width: 2px; padding: 9px 11px; }
@media (min-width: 700px) {
  .prograil-link {
    grid-template-columns: minmax(6rem, auto) minmax(0, 1fr) minmax(6rem, 10rem) auto auto;
    grid-template-areas: "when chips bar time go";
  }
}

/* ------------------------------------------------------------------
   De doelen: waar je training naartoe gaat.

   Kaarten en geen tabel, want op een telefoon is een tabel met vier kolommen
   onleesbaar en op een desktop zijn het er hoogstens een handvol. Het
   ondersteunende doel is rustiger, maar het verschil staat ook in de tekstpil -
   kleur versterkt hier niets dat niet ook in woorden staat.
   ------------------------------------------------------------------ */
.goalcards {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}
@media (min-width: 820px) { .goalcards { grid-template-columns: repeat(2, 1fr); } }
.goalcard {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px;
  border: 1px solid var(--border-strong, var(--border));
  border-radius: var(--radius-sm);
  background: var(--panel-strong);
}
.goalcard-supporting { border-color: var(--border); background: var(--panel); }
/* Een doel waarvoor werkelijk lokaal wordt voorbereid (COACH ADR 0022). Een
   accentrand en geen alarmkleur: dit is goed nieuws, geen waarschuwing. De rand
   is bovendien nooit de enige drager - onder de kaart staat de zin die hetzelfde
   zegt. */
.goalcard-prepared { border-left: 3px solid var(--accent); }
.goalcard-name { margin: 0; font-weight: 600; font-size: 1.05rem; overflow-wrap: anywhere; }

/* De twee helften van het beschikbaarheidsformulier: wat jij opgeeft, en wat
   Coach beslist. Ze staan naast elkaar zodra er ruimte is en onder elkaar op
   een telefoon. */
.splitnote {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  margin: 10px 0 4px;
}
@media (min-width: 760px) { .splitnote { grid-template-columns: 1fr 1fr; gap: 16px; } }

/* De uitklapbare beschikbare week. Het formulier is nuttig maar lang; als
   dichtgeklapte balk kost het één regel en blijft de planning erboven zichtbaar.
   `<details>`/`<summary>` draagt zelf de open/dicht-toestand voor een
   schermlezer en werkt zonder JavaScript - er staat hier dus alleen vormgeving,
   geen gedrag. */
.disclosure {
  margin: 10px 0 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel-alt, transparent);
}
.disclosure-bar {
  cursor: pointer;
  /* Ruim boven de 44 px die een vinger nodig heeft, ook op een telefoon waar
     de samenvatting onder de titel valt. */
  min-height: 48px;
  padding: 10px 14px;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  font-weight: 600;
  color: var(--accent-strong);
}
.disclosure-bar::marker { color: var(--muted); }
.disclosure-bar:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
}
.disclosure-title { overflow-wrap: anywhere; }
/* De samenvatting is een feit en geen kop: normaal gewicht, gedempte kleur. Ze
   mag afbreken op een smal scherm in plaats van de balk te laten scrollen. */
.disclosure-summary {
  font-weight: 400;
  color: var(--muted);
  font-size: 0.94rem;
  overflow-wrap: anywhere;
}
.disclosure-body { padding: 0 14px 14px; }
.disclosure[open] > .disclosure-bar { border-bottom: 1px solid var(--border); }

/* Vorige/volgende week. */
.weeknav {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  margin: 16px 0;
}

/* ------------------------------------------------------------------
   De beschikbare week: één compacte regel per dag.

   Zeven dagen maal vijf velden was een pagina lang scrollen om te zeggen dat je
   op dinsdag en donderdag kunt. De velden staan nu op één rij zodra er ruimte
   is, en stapelen op een telefoon - geen tabel, want een tabel van vijf kolommen
   is op 390px onleesbaar en zou horizontaal moeten scrollen.
   ------------------------------------------------------------------ */
.dayrow {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel-strong);
  padding: 10px 12px;
  margin: 0 0 10px;
}
.dayrow > legend { font-weight: 600; padding: 0 4px; }
/* De samenvatting naast de dagnaam: 'Avond · 18:30 · 2 u · Buiten · Clubrit'.
   Ze wikkelt en krimpt mee; op 390 px valt ze onder de dagnaam in plaats van de
   rij horizontaal te laten scrollen. */
.dayrow-summary {
  display: inline;
  margin-left: 8px;
  font-weight: 400;
  font-size: 0.85rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}
.dayrow-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 12px;
  align-items: end;
}
@media (min-width: 760px) {
  .dayrow-fields { grid-template-columns: auto repeat(3, minmax(0, 1fr)); }
}
.dayrow-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.dayrow-field > span { font-size: 0.85rem; color: var(--muted); }
/* Het vinkje blijft links van zijn label staan en rekt niet mee met de
   invoervelden ernaast. De 24px is de kleinste maat waarop een vingertop hem
   nog raakt zonder de rij hoger te maken dan de andere velden. */
.dayrow-available { flex-direction: row; align-items: center; gap: 8px; }
.dayrow-available > input { min-width: 24px; min-height: 24px; }
.dayrow-club { margin-top: 10px; }
.dayrow-club > summary { cursor: pointer; font-size: 0.9rem; min-height: 32px; }
.dayrow-club > .dayrow-fields { margin-top: 8px; }

/* ------------------------------------------------------------------
   De week als navigatie: zeven dagkaarten die elk één klik zijn.
   ------------------------------------------------------------------ */
.weekgrid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin-top: 14px;
}
@media (min-width: 700px) { .weekgrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .weekgrid { grid-template-columns: repeat(3, 1fr); } }

/* De hele kaart is de knop. Een echte <a>, dus zonder JavaScript bruikbaar,
   met de gewone focusring van de stylesheet en een aanraakvlak dat ruim boven
   de 44px van een vingertop uitkomt. */
.daycard {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 96px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel);
  color: inherit;
  text-decoration: none;
}
.daycard:hover, .daycard:focus-visible {
  border-color: var(--border-strong);
  color: inherit;
}
.daycard-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
}
.daycard-day { font-weight: 600; }
.daycard-date { color: var(--muted); font-size: 0.85rem; }
.daycard-title { margin: 0; font-size: 1rem; font-weight: 600; }
/* De feiten op één regel: sport · duur · binnen of buiten. Ze lopen af in
   plaats van uit op een smal scherm. */
.daycard-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--muted);
  font-size: 0.9rem;
}
.daycard-facts li + li::before { content: "· "; }
.daycard-go {
  margin-top: auto;
  color: var(--accent);
  font-size: 0.88rem;
  font-weight: 600;
}
/* Rust en training zijn visueel verschillend, maar de rustdag verdwijnt niet:
   ze is een geplande uitkomst en houdt haar eigen kaart. */
.daycard-rest { background: var(--panel-strong); }
/* De clubritdag. Een eigen toestand naast rust en training, en het verschil
   staat ook in de titel ('Clubrit') en in een pil - de rand versterkt het
   alleen. Een rit van anderhalf uur die als rustdag oogt, is een onwaarheid. */
.daycard-club { border-style: dashed; }
.daycard-rest .daycard-title { font-weight: 500; color: var(--muted); }
/* De streefdag van een doel. De premium-behandeling van deze week: een warme
   amber wash en een steviger linkerrand, zodat de dag in het weekraster
   onmiddellijk opvalt zonder te alarmeren - geen rood, geen uitroepteken.
   Het verschil staat ook in de titel ('Doelevenement') en in een pil, want een
   dag die alleen door kleur verschilt, verschilt niet voor wie die kleur niet
   ziet. */
.daycard-event {
  background: var(--event-wash);
  border-color: var(--event-edge);
  border-left: 3px solid var(--event);
}
.daycard-event .daycard-title { font-weight: 700; color: var(--event); }
.daycard-today { border-color: var(--accent-strong); border-width: 2px; }
.daycard-past { opacity: 0.74; }

/* ------------------------------------------------------------------
   De sessie als voorschrift: opwarming, hoofdblok, herstel, afkoeling.

   Twee niveaus, precies zoals de eigenaar publiceert: een blok (`.wblock`)
   dat `n` keer wordt uitgevoerd, met daarin de stappen (`.wstep`). Een
   herhaald blok is EEN kaart met het aantal erboven en nooit een
   uitgeschreven lijst van dezelfde stappen; daarmee staan de drie getallen
   die een atleet nodig heeft ook visueel uit elkaar: hoe vaak, hoe lang je
   werkt, en hoe lang je herstelt.
   ------------------------------------------------------------------ */
/* De koppen boven de blokken en boven de samenvatting krijgen lucht: ze
   staan nu bovenaan het scherm in plaats van weggestopt achter een
   uitklapper, en een kop die tegen de regel erboven plakt leest niet als kop. */
.panel .section-title + .wblocks { margin-top: 0; }
.wtotal + .section-title { margin-top: 18px; }
.factlist + .section-title,
.tchips + .section-title,
.bullets + .section-title { margin-top: 16px; }
.wblocks { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 14px; }
.wblock { display: grid; gap: 0; }
/* Een herhaald blok krijgt een eigen omhulsel: het is een eenheid die je als
   geheel n keer doet, en dat moet je kunnen zien zonder te lezen. */
.wblock-repeat {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.wblock-rep {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin: 0;
  padding: 10px 14px;
  background: var(--teal-wash);
  border-bottom: 1px solid var(--border-strong);
}
/* Het aantal is het getal dat je als eerste zoekt; het staat groot en apart
   van de duur van de stappen eronder. */
.wblock-rep-count {
  font-size: 1.3rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.wblock-rep-label {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--muted);
}
.wblock-rep-total {
  margin-left: auto;
  font-size: 0.85rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 420px) { .wblock-rep-total { margin-left: 0; flex-basis: 100%; } }
.wblock-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.wblock-repeat .wblock-steps { padding: 10px; background: var(--panel); }
.wstep {
  display: grid;
  gap: 4px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-strong);
  border-radius: var(--radius-sm);
  background: var(--panel-strong);
}
/* De rol van een stap is ook zonder kleur leesbaar: elke stap draagt haar
   naam voluit. De randdikte versterkt die naam, ze vervangt hem niet. */
.wstep-work { border-left-width: 5px; }
.wstep-rest, .wstep-warm, .wstep-cool { border-left-color: var(--border-strong); }
.wstep-kind {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 700;
}
/* De duur van EEN uitvoering. Staat de stap in een herhaald blok, dan zegt de
   regel eronder dat met zoveel woorden. */
.wstep-headline { font-weight: 600; font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.wstep-per { font-size: 0.8rem; color: var(--muted); }
/* De doelen staan onder elkaar als label-waardeparen en niet als een reeks
   met punten ertussen. Deze getallen worden overgetypt in Garmin of
   TrainingPeaks: dan moet je ze kunnen aflopen, niet uit een zin vissen. Het
   is dezelfde opmaak als het totaalblok, zodat er een taal is en geen twee. */
.wstep-facts {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px 24px;
  margin: 2px 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}
@media (min-width: 700px) { .wstep-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.wstep-facts li {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
  justify-content: space-between;
}
.wstep-facts .k { color: var(--muted); }
/* Een bereik breekt nooit middenin: '0' op de ene regel en 'bpm-137 bpm' op
   de volgende leest als twee getallen in plaats van als een bereik. */
.wstep-facts li > span:last-child { white-space: nowrap; }
/* Een waarde die de eigenaar niet publiceerde, staat er als toestand en nooit
   als getal: rustige tekst, geen tabelcijfer. */
.wstep-facts .missing { color: var(--muted); font-style: italic; white-space: normal; }
/* Het slotblok: wat deze training in totaal is. Geen samenvatting die iets
   nieuws beweert - vijf feiten die elk al ergens anders vandaan komen. */
.wtotal {
  margin-top: 14px;
  padding: 12px 14px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--panel-strong);
}
.wtotal-heading {
  margin: 0 0 8px;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--muted);
}
.wtotal-facts {
  display: grid;
  grid-template-columns: 1fr;
  gap: 4px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-variant-numeric: tabular-nums;
}
@media (min-width: 620px) { .wtotal-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.wtotal-facts li { display: flex; flex-wrap: wrap; gap: 4px 8px; justify-content: space-between; }
.wtotal-facts .k { color: var(--muted); }
/* De ingang naar de eigen pagina van deze training: een knop, geen zin. */
.sessioncta { margin-top: 14px; }
.sessioncta .btn { min-height: 44px; display: inline-flex; align-items: center; }
@media (max-width: 520px) {
  .sessioncta .btn { display: flex; justify-content: center; }
}
/* De primaire vervolgactie van een sessie (route, resultaat) krijgt ruimte en
   staat op mobiel over de volle breedte - een knop die je met een duim raakt. */
.sessionactions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 16px;
}
.sessionactions .btn { min-height: 44px; display: inline-flex; align-items: center; }
@media (max-width: 520px) {
  .sessionactions { flex-direction: column; align-items: stretch; }
  .sessionactions .btn { justify-content: center; }
}

/* ------------------------------------------------------------------
   Het resultaat na een sessie: wat je deed, plan versus uitvoering.
   ------------------------------------------------------------------ */
/* Gepland en uitgevoerd staan naast elkaar als twee gelijkwaardige feiten.
   Er staat geen derde kolom met een oordeel: dat oordeel bestaat niet. */
.comparerow {
  display: grid;
  grid-template-columns: 1fr;
  gap: 4px 16px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.comparerow:last-child { border-bottom: 0; }
@media (min-width: 560px) {
  .comparerow { grid-template-columns: minmax(0, 1fr) auto auto; align-items: baseline; }
}
.comparerow-name { font-weight: 600; }
.comparerow-side { font-variant-numeric: tabular-nums; }
.comparerow-side .k { color: var(--muted); font-size: 0.8rem; display: block; }
.comparerow-state { color: var(--muted); font-size: 0.85rem; }
.comparelist { list-style: none; margin: 10px 0 0; padding: 0; }

/* De bewijsvelden van het bronsysteem zijn opsommingen en geen getallen. Ze
   staan daarom onder hun label en links uitgelijnd: een lange komma-lijst
   rechts uitgelijnd onder een kort label zweeft los van het woord waar ze bij
   hoort. */
.evidencelist li { display: grid; gap: 2px; justify-items: start; }
.evidencelist .v { text-align: left; font-variant-numeric: normal; }

/* De trainingscontext boven het routeformulier: waar deze route bij hoort. */
.routecontext {
  border-left: 3px solid var(--accent-strong);
  background: var(--teal-wash);
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  margin-bottom: 14px;
}
.routecontext h2 { margin: 0 0 6px; font-size: 1rem; }
.routecontext .factlist { margin-top: 8px; }

.sessiongraph { padding-block: 1.1rem 1.35rem; border-radius: 16px; }
.sessiongraph h2 { margin-bottom: .5rem; }
.sg-canvas {
  width: 100%; height: clamp(200px, 42vw, 300px); display: block;
  background: var(--surface-2, #f7f7f5); border-radius: 10px; touch-action: pan-y;
}
.sg-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke; }
.sg-power { stroke: var(--accent, #0f766e); }
/* Beweging draagt haar eigen kleur en haar eigen streepjespatroon: op een loop
   of een tocht is dit de lijn waar de vraag over gaat, en ze moet ook zonder
   kleur van de hartslag te onderscheiden zijn. */
.sg-speed { stroke: #2f6f9f; stroke-dasharray: 9 3 2 3; }
.sg-heart { stroke: #b4436c; stroke-dasharray: 5 3; }
.sg-cadence { stroke: #7a6a9b; stroke-dasharray: 1 3; }
.sg-altitude { stroke: #8a8578; stroke-dasharray: 8 4; }
/* Context concurreert niet met het antwoord: cadans en hoogte zijn dunner en
   lichter dan het paar waar de vraag over gaat. */
.sg-secondary .sg-line { stroke-width: 1.25; opacity: .7; }
.sg-toggle-off span { color: var(--muted, #6b6b63); }
.sg-trace[hidden] { display: none; }
/* De banden liggen onder de lijnen en horen daar te blijven liggen: ze zijn
   context voor het oog, geen tweede grafiek. */
.sg-band { fill: rgba(15, 118, 110, .035); }
.sg-band-1 { fill: rgba(15, 118, 110, .075); }
.sg-stop { stroke: #b4436c; stroke-width: 1; stroke-dasharray: 2 4; opacity: .55;
  vector-effect: non-scaling-stroke; }
.sg-cursor { stroke: var(--ink, #23241f); stroke-width: 1; opacity: .55;
  vector-effect: non-scaling-stroke; pointer-events: none; }
.sg-axis { font-size: 11px; fill: var(--muted, #6b6b63); }
.sg-axis-end { text-anchor: end; }
.sg-legend { display: flex; flex-wrap: wrap; gap: .4rem .75rem; margin-top: .3rem; }
.sg-toggle { display: inline-flex; align-items: center; gap: .35rem;
  min-height: 44px; font-size: .95rem; cursor: pointer; }
.sg-toggle span::before {
  content: ""; display: inline-block; width: 1.1em; height: .2em; margin-right: .4rem;
  vertical-align: middle; border-radius: 2px;
}
.sg-toggle.sg-power span::before { background: var(--accent, #0f766e); }
.sg-toggle.sg-speed span::before {
  background: repeating-linear-gradient(90deg,#2f6f9f 0 9px,transparent 9px 12px); }
.sg-toggle.sg-heart span::before {
  background: repeating-linear-gradient(90deg,#b4436c 0 5px,transparent 5px 8px); }
.sg-toggle.sg-cadence span::before {
  background: repeating-linear-gradient(90deg,#7a6a9b 0 1px,transparent 1px 4px); }
.sg-toggle.sg-altitude span::before {
  background: repeating-linear-gradient(90deg,#8a8578 0 8px,transparent 8px 12px); }
.sg-readout {
  display: flex; flex-wrap: wrap; gap: .25rem 1rem; min-height: 1.5rem;
  margin: .5rem 0 0; font-variant-numeric: tabular-nums; font-size: .95rem;
}
.sg-readout .k { color: var(--muted, #6b6b63); }
.sg-readout .sg-scope { flex-basis: 100%; color: var(--muted, #6b6b63);
  font-size: .85rem; text-transform: uppercase; letter-spacing: .04em; }
.sg-idle { color: var(--muted, #6b6b63); font-size: .9rem; }
.sg-blocks { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .8rem; }
.sg-chip {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 34px; min-width: 34px; padding: 0 .7rem;
  border-radius: 999px; border: 1px solid var(--line, #e4e2db);
  background: var(--surface-2, #f7f7f5); color: inherit;
  font-size: .88rem; line-height: 1; text-decoration: none;
}
.sg-chip:hover, .sg-chip:focus-visible { border-color: var(--accent, #0f766e); }
.sg-chip-on {
  background: var(--accent, #0f766e); border-color: var(--accent, #0f766e);
  color: #fff; font-weight: 600;
}
.sg-current { font-weight: 600; }
@media (prefers-reduced-motion: no-preference) { .sg-line { transition: opacity .15s; } }


.sa-overview { margin-bottom: .75rem; }
.sa-overview-label { margin: 0 0 .3rem; color: var(--muted, #6b6b63);
  font-size: .85rem; text-transform: uppercase; letter-spacing: .04em; }
.sa-cells { display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; }
.sa-cell { display: flex; flex-direction: column; min-width: 6.5em; }
.sa-cell-label { color: var(--muted, #6b6b63); font-size: .82rem; }
.sa-cell-value { font-size: 1.2rem; font-weight: 600;
  font-variant-numeric: tabular-nums; }
/* De tabel mag breder zijn dan de telefoon en schuift dan binnen haar eigen
   kader. `max-width` en `min-width: 0` staan erbij omdat een scroller zonder
   die twee alsnog haar ouder oprekt - en dan schuift de hele pagina mee. */
.sa-table-wrap { overflow-x: auto; max-width: 100%; min-width: 0; }
.sa-table { width: 100%; border-collapse: collapse;
  font-variant-numeric: tabular-nums; }
.sa-table { min-width: 0; }
.sa-table th, .sa-table td { padding: .45rem .4rem; text-align: right;
  border-bottom: 1px solid var(--line, #e4e2db); white-space: nowrap; }
.sa-table thead th { color: var(--muted, #6b6b63); font-weight: 500;
  font-size: .85rem; }
.sa-table th[scope="row"] { text-align: left; font-weight: 500; }
.sa-strong { font-weight: 600; }
.sa-count { color: var(--muted, #6b6b63); font-size: .82rem; text-align: left;
  white-space: normal; }
.sa-absent { color: var(--muted, #6b6b63); text-align: left; }
.sa-figure { margin: .1rem 0 .4rem; font-size: 2rem; font-weight: 600;
  font-variant-numeric: tabular-nums; line-height: 1.1; }
.sa-detail summary { min-height: 44px; display: flex; align-items: center;
  cursor: pointer; }
.sa-detail summary h2 { margin: 0; font-size: 1.05rem; }
.sa-detail summary::-webkit-details-marker { color: var(--muted, #6b6b63); }
.sa-why { margin-top: .6rem; }
.sa-why summary { min-height: 44px; display: flex; align-items: center;
  cursor: pointer; color: var(--accent, #0f766e); }
/* Het tempovlak staat in het getallenpaneel en niet in een eigen kaart: het is
   hetzelfde soort feit als de rest, alleen in de eenheid die een loper leest. */
.sf-pace { margin: .2rem 0 .9rem; }
.sf-pace-absent { margin: 0 0 .6rem; }
/* Klimmen en afdalingen: kaartjes die op een telefoon onder elkaar staan en op
   een breed scherm naast elkaar, zonder ooit horizontaal te schuiven. */
.sa-segments { list-style: none; margin: .8rem 0 .4rem; padding: 0;
  display: grid; gap: .7rem; }
.sa-segment { padding: .7rem .8rem; border-radius: 12px;
  border: 1px solid var(--line, #e4e2db); background: var(--surface-2, #f7f7f5); }
.sa-segment h3 { margin: 0 0 .4rem; font-size: 1rem; }
.sa-segment .sa-cell { min-width: 5.5em; }
.sa-segment .sa-cell-value { font-size: 1.05rem; }
.sa-segment .note { margin: .45rem 0 0; }
.sa-groups { display: grid; gap: 1rem; }
.sa-group h3 { margin: 0 0 .3rem; font-size: 1rem; }
.sa-asklist { list-style: none; margin: .4rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: .25rem .5rem; }
.sa-askchip {
  display: inline-flex; align-items: center; min-height: 40px;
  padding: 0 .85rem; border-radius: 999px;
  border: 1px solid var(--line, #e4e2db); background: var(--surface-2, #f7f7f5);
  color: inherit; font-size: .9rem; line-height: 1.2; text-decoration: none;
}
.sa-askchip:hover, .sa-askchip:focus-visible {
  border-color: var(--accent, #0f766e); color: var(--accent, #0f766e);
}
@media (min-width: 48rem) {
  .sa-groups { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }
  .sa-segments { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
}


.sessionstory {
  display: grid; gap: 1rem; margin-bottom: 1rem;
}
.sessionstory > .sessiongraph { margin: 0; }
.sessionmap {
  margin: 0; padding: .9rem .9rem .6rem; border-radius: 16px;
  background: var(--surface, #fff); border: 1px solid var(--line, #e4e2db);
}
.sm-canvas {
  width: 100%; height: clamp(230px, 52vw, 360px); display: block;
  background: #f4f2ec; border-radius: 12px;
  touch-action: pan-y; cursor: crosshair;
}
.sm-canvas-bare { background: var(--surface-2, #f7f7f5); }
/* De ondergrond draagt de route en concurreert er niet mee: gedempte tinten,
   dunne lijnen, en alles onder de gereden lijn. */
.sm-base { vector-effect: non-scaling-stroke; }
.sm-base-waterarea { fill: #dde9ee; stroke: none; }
.sm-base-water { stroke: #cfdfe6; stroke-width: 1.6; }
.sm-base-rail { stroke: #d8d5cc; stroke-width: 1; stroke-dasharray: 6 4; }
.sm-base-path { stroke: #e6e4dc; stroke-width: .8; }
/* De gewone weg trad een stap terug: hij is er nog, met kruispunt en al, maar
   hij is niet langer bijna even zwaar als de route erboven. De grote weg houdt
   zijn gewicht - die draagt de oriëntatie. */
.sm-base-road { stroke: #dedbd2; stroke-width: 1; }
.sm-base-major { stroke: #c4c0b3; stroke-width: 2.2; }
.sm-place {
  fill: #8a8578; font-size: 11px; text-anchor: middle;
  paint-order: stroke; stroke: var(--surface-2, #f7f7f5); stroke-width: 3px;
}
.sm-place-1 { font-size: 14px; fill: #6b6b63; }
.sm-place-2 { font-size: 12px; }

.sm-line { stroke: var(--accent, #0f766e); stroke-width: 3;
  vector-effect: non-scaling-stroke; }
/* Bij een gekozen blok blijft de hele rit zichtbaar, maar licht: zo is te zien
   wáár in de rit dat blok lag in plaats van dat de rest verdwijnt. */
.sm-line-faded { stroke-opacity: .28; stroke-width: 2; }
.sm-line-window { stroke: var(--accent, #0f766e); stroke-width: 4;
  vector-effect: non-scaling-stroke; }
.sm-start { fill: var(--accent, #0f766e); }
.sm-end { fill: #b4436c; }
.sm-cursor { fill: #fff; stroke: var(--ink, #23241f); stroke-width: 2;
  vector-effect: non-scaling-stroke; pointer-events: none; }
.sm-caption { margin: .5rem 0 0; font-size: .82rem; }
.sm-gap { margin: .25rem 0 0; font-size: .82rem; }

/* De kerngetallen in de hero: groot genoeg om in een blik te lezen, klein
   genoeg om de kaart en de grafiek niet naar beneden te duwen. */
.sf-facts {
  display: flex; flex-wrap: wrap; gap: .75rem 1.6rem; margin-top: .9rem;
}
.sf-fact { display: flex; flex-direction: column; gap: .1rem; }
.sf-value { font-size: 1.45rem; font-weight: 600; line-height: 1.1;
  font-variant-numeric: tabular-nums; }
.sf-label { color: var(--muted, #6b6b63); font-size: .8rem; }
.sf-rows { display: grid; gap: .3rem; }
.sf-row { display: flex; flex-wrap: wrap; gap: .2rem .75rem;
  padding: .45rem 0; border-bottom: 1px solid var(--line, #e4e2db); }
.sf-row:last-child { border-bottom: 0; }
.sf-row-label { min-width: 7rem; color: var(--muted, #6b6b63); }
.sf-row-value { font-variant-numeric: tabular-nums; }
.sf-more { margin-top: .6rem; }
.sf-more summary { min-height: 44px; display: flex; align-items: center;
  cursor: pointer; color: var(--accent, #0f766e); font-size: .92rem; }

/* Zachtere kaders voor de panelen van dit scherm, en meer lucht eromheen. */
.sessiongraph, .sa-drift, .sa-findings, .sa-ask, .sa-detail, .sessionmap,
.sa-elevation {
  border-radius: 16px;
}
.sa-drift, .sa-findings, .sa-ask, .sa-elevation {
  padding-block: 1.1rem 1.25rem;
}

@media (min-width: 60rem) {
  /* Kaart en grafiek naast elkaar op een breed scherm: het is één verhaal, en
     twee volle-breedte kaarten onder elkaar maken er twee losse dingen van. */
  .sessionstory { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    align-items: start; }
  .sessionstory-solo { grid-template-columns: minmax(0, 1fr); }
  .sm-canvas { height: clamp(300px, 28vw, 420px); }
}


/* -- De blokbalk ---------------------------------------------------------
   Een horizontaal schuivende strip en geen uitklapmenu: op een telefoon moet
   de atleet met een duim langs de stappen kunnen, en de structuur van zijn
   training hoort niet achter een knop te verdwijnen. Verborgen uitgeleverd,
   want ze doet uitsluitend iets aan het kaartvenster. */
.routerail { display: grid; gap: .45rem; margin: 0; }
.routerail-chips {
  display: flex;
  gap: .4rem;
  overflow-x: auto;
  padding-bottom: .3rem;
  scrollbar-width: thin;
}
.railchip {
  flex: 0 0 auto;
  min-height: 44px;
  white-space: nowrap;
}
/* Smalle schermen: de rij past niet en moet dat ook tonen. Dezelfde oplossing
   als de navigatiestrip - het laatste item loopt zacht uit in plaats van
   middenin een woord te worden afgekapt, en dat leest als 'er is meer' in
   plaats van als een defect. Puur CSS: geen script, geen tikdoel dat eronder
   verdwijnt. Franse labels zijn langer dan Nederlandse, en juist daar is dit
   het verschil tussen 'twee stappen' en 'de hele training'. */
@media (max-width: 859px) {
  .routerail-chips {
    -webkit-mask-image: linear-gradient(
      to right, #000 calc(100% - 24px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
    padding-right: 24px;
  }
}
.railchip[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent-strong);
  color: var(--accent-ink);
}

/* -- De uitvoeringslijst -------------------------------------------------
   Dezelfde vorm als de stappen van de trainingsplanning, want het is dezelfde
   training. Wat er hier bijkomt is uitsluitend de plaats op de route. */
/* De uitvoering is een vlak bínnen de resultaatkaart. Een lijn scheidt haar
   van de routecijfers erboven; het is dezelfde sessie, geen tweede kaart. */
.rexecblock {
  border-top: 1px solid var(--border);
  margin-top: 1rem;
  padding-top: .9rem;
}
.rexecblock > h2 { font-size: 1.05rem; margin: 0 0 .5rem; }
.rexec { display: grid; gap: .85rem; }
.rcues { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.rcue {
  display: grid;
  gap: 6px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--panel-strong);
}
/* Een werkblok is het enige waar de atleet iets moet dóen; het krijgt daarom
   de accentrand. De andere stappen zijn context. */
.rcue-work { border-left: 5px solid var(--accent-strong); }
.rcue-head {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 12px;
  justify-content: space-between;
  margin: 0;
}
.rcue-role {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 700;
}
.rcue-at { font-size: 0.85rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* De cue zelf: de enige regel die de atleet onderweg moet onthouden. */
.rcue-lap { margin: 0; font-weight: 600; font-size: 1.02rem; }
.rcue-lap-hint { margin: .2rem 0 0; font-size: .85rem; color: var(--muted); }
.rcue-targets-heading, .rcue-why {
  margin: .5rem 0 .15rem;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 700;
}
.rcue-more { margin-top: .2rem; }
.rcue-more summary {
  min-height: 44px;
  display: flex;
  align-items: center;
  cursor: pointer;
  color: var(--accent);
  font-size: .92rem;
}
.rcue-reasons, .rcue-notices { margin: .2rem 0 0; font-size: .9rem; }
.rcue-notices { color: var(--muted); }

/* -- De cue op de kaart --------------------------------------------------
   Compact, en meeschalend met dezelfde twee factoren als elke andere
   markering: --map-marker laat haar krimpen bij inzoomen, --map-zoom houdt
   haar op het scherm even groot. */
.routecue-dot { r: calc(6px * var(--map-marker) * var(--map-zoom)); }
.routecue-number {
  font-size: calc(7px * var(--map-marker) * var(--map-zoom));
  text-anchor: middle;
  dominant-baseline: central;
  font-weight: 700;
  pointer-events: none;
}
.routecue-dot { fill: var(--panel); stroke: var(--border-strong); stroke-width: 1.5; }
.routecue-number { fill: var(--text); }
.routecue-work .routecue-dot { fill: var(--accent-strong); stroke: var(--accent-ink); }
.routecue-work .routecue-number { fill: var(--accent-ink); }
.routecue-dot { vector-effect: non-scaling-stroke; }
/* De gekozen stap: haar markering wordt groter en krijgt een zwaardere rand.
   Twee dragers en niet alleen kleur - de balkknop staat tegelijk ingedrukt en
   noemt de stap voluit, dus de kaart hoeft de betekenis niet alleen te dragen. */
.routecue[data-selected] .routecue-dot {
  r: calc(9px * var(--map-marker) * var(--map-zoom));
  stroke-width: 3;
}
.routecue[data-selected] .routecue-number {
  font-size: calc(9px * var(--map-marker) * var(--map-zoom));
}
/* De nadruk op het gekozen blok. Leeg tot het script haar vult; zonder script
   wordt er niets gekozen en blijft ze onzichtbaar. */
.routemap-window {
  stroke: var(--accent-ink);
  stroke-width: calc(var(--map-stroke) * 1.5px);
  opacity: .85;
}


/* ==================================================================
   1. GROND EN ELEVATIE
   Een kaart kan alleen oplichten tegen iets dat donkerder is. De grond
   gaat daarom een stap dieper de warme ivoor in, en het paneel wordt de
   lichtste waarde op het scherm in plaats van bijna dezelfde.
   ================================================================== */
:root {
  /* Dezelfde warme ivoorfamilie, een stap dieper. Geen nieuwe kleur: het is
     Ivory met minder licht, zodat `--panel` erboven kan uitkomen. */
  --ivory-ground: #f1efe6;
  --bg: var(--ivory-ground);
  --panel: #fffdf7;

  /* Elevatie draagt nu de scheiding die eerst van randen kwam. Warm getint
     en niet grijs: een neutrale schaduw op ivoor leest als vuil. */
  --shadow-sm: 0 1px 2px rgba(43, 38, 28, 0.05),
    0 2px 8px rgba(43, 38, 28, 0.04);
  --shadow-md: 0 2px 6px rgba(43, 38, 28, 0.05),
    0 14px 32px rgba(43, 38, 28, 0.07);
  --shadow-hero: 0 18px 40px rgba(10, 91, 80, 0.22);

  --radius: 20px;
  --radius-sm: 12px;

  /* De teal gaat één stap dieper mee met de grond, en dat is geen
     smaakwijziging maar een gemeten correctie.

     De basisstylesheet koos `--teal: #0f7b6c` omdat die op Ivory (#f7f6f0)
     precies AA haalt: 4,76:1. Deze laag maakt de grond donkerder, en daarmee
     zakte diezelfde teal naar 4,48:1 op de nieuwe grond en 4,40:1 op
     `--panel-strong` - onder AA. De afwerking mag geen leesbaarheid kosten,
     dus schuift het accent mee.

     Gemeten met deze waarde (#0e7365, relatieve luminantie 0,1329):
       op --bg #f1efe6 .......... 4,98:1  AA
       op --panel-strong #efede4  4,90:1  AA
       op --panel #fffdf7 ....... 5,70:1  AA
       wit op de knopvulling .... 5,74:1  AA
     Het is dezelfde teal, dieper gezet omdat het oppervlak veranderde -
     dezelfde redenering als in de basisstylesheet, en geen vierde kleur. */
  --teal: #0e7365;
  --accent: var(--teal);

  /* Een rand is vanaf hier een uitzondering, geen basis. */
  --border: rgba(27, 32, 38, 0.07);
  --border-strong: rgba(27, 32, 38, 0.16);
}

/* ==================================================================
   2. PANELEN
   Geen omlijnde doos meer maar een gedragen vlak. Meer lucht binnenin,
   meer afstand ertussen: groeperen doet het wit, niet de lijn.
   ================================================================== */
.panel {
  border: 0;
  background: var(--panel);
  border-radius: var(--radius);
  padding: clamp(22px, 4vw, 34px);
  margin-bottom: clamp(18px, 3vw, 26px);
  box-shadow: var(--shadow-sm);
}

.panel h2 {
  margin: 0 0 14px;
  font-size: 1.24rem;
  letter-spacing: -0.01em;
}

/* De sectiekop was een schreeuw in kapitalen. Hij mag een label blijven,
   maar een rustiger een: minder spatiëring, minder gewicht in het oog. */
.section-title {
  font-size: 0.74rem;
  letter-spacing: 0.10em;
  color: var(--muted);
  font-weight: 600;
  margin: 0 0 12px;
}

/* ==================================================================
   3. DE MASTHEAD
   Eén diep teal vlak bovenaan waar eerst zwarte tekst op wit stond. Het
   geeft de pagina een begin en het merk een plek, en het is compact: een
   kop, een zin, een terugweg. Geen diagnostiek.
   ================================================================== */
.pagehero {
  position: relative;
  margin-bottom: clamp(20px, 4vw, 30px);
  padding: clamp(22px, 4.5vw, 34px) clamp(20px, 4vw, 34px);
  border-radius: var(--radius);
  background: linear-gradient(135deg, var(--teal-deep) 0%, var(--teal) 100%);
  color: var(--ivory-raised);
  box-shadow: var(--shadow-hero);
  overflow: hidden;
}

/* De horizon uit het merk, heel zacht, als textuur. Puur decoratief en
   daarom niet in de toegankelijkheidsboom: het is een achtergrond. */
.pagehero::after {
  content: "";
  position: absolute;
  right: -14%;
  top: -60%;
  width: 60%;
  height: 220%;
  background: radial-gradient(
    closest-side,
    rgba(155, 211, 155, 0.30),
    rgba(155, 211, 155, 0)
  );
  pointer-events: none;
}

.pagehero > * { position: relative; }

.pagehero h1 {
  margin: 0 0 8px;
  font-size: clamp(1.9rem, 6vw, 2.5rem);
  letter-spacing: -0.02em;
  line-height: 1.12;
  color: var(--ivory-raised);
}

/* De inleidende zin draagt op teal geen `--muted`: dat token is voor een
   lichte ondergrond gemaakt en zou hier onleesbaar worden. */
.pagehero .lead {
  color: rgba(255, 254, 250, 0.90);
  max-width: 60ch;
}

.pagehero .note { margin: 14px 0 0; }

/* De terugweg in de hero is een secundaire actie op een donker vlak. */
.pagehero .btn-link {
  border-color: rgba(255, 254, 250, 0.45);
  color: var(--ivory-raised);
  background: rgba(255, 254, 250, 0.08);
}

.pagehero .btn-link:hover { background: rgba(255, 254, 250, 0.18); }

/* Focus moet op teal even hard zichtbaar zijn als op ivoor. */
.pagehero a:focus-visible {
  outline: 3px solid var(--ivory-raised);
  outline-offset: 2px;
}

.pagehero-compact {
  padding-top: clamp(18px, 3.5vw, 26px);
  padding-bottom: clamp(18px, 3.5vw, 26px);
}

/* ==================================================================
   4. KNOPHIËRARCHIE
   Vier rollen, vier gewichten. Eerder zag elke actie er even sterk uit,
   en dan kiest het oog niet.
   ================================================================== */
.btn {
  border-radius: var(--radius-sm);
  font-weight: 650;
  letter-spacing: 0.005em;
  box-shadow: var(--shadow-sm);
  transition: background-color 120ms ease, border-color 120ms ease;
}

.btn:hover { filter: none; background: var(--accent-strong); }

/* Secundair: zichtbaar, maar het trekt de blik niet weg van de hoofdactie. */
.btn-link {
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--teal-edge);
  box-shadow: none;
}

.btn-link:hover {
  background: var(--teal-wash);
  border-color: var(--accent);
}

/* ==================================================================
   5. DOELKAARTEN
   Drie rollen die eerder alleen in tekst verschilden. De kleur is de
   versterking; de naam van de rol staat er nog steeds bij.
   ================================================================== */
.goalcard {
  padding: 16px 18px;
  border: 0;
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--panel);
  box-shadow: var(--shadow-sm);
}

/* Het ondersteunende doel is stiller: geen eigen accent, alleen een rustige
   rand. Het telt mee, het stuurt niet. */
.goalcard-supporting {
  border-left-color: var(--border-strong);
  background: var(--panel-strong);
  box-shadow: none;
}

/* Het doel waarvoor nu werkelijk wordt voorbereid: amber, dezelfde taal als
   de evenementdag zelf, zodat 'dit is een kalendermoment' één kleur heeft. */
.goalcard-prepared {
  border-left-color: var(--event);
  background: var(--event-wash);
  box-shadow: none;
}

.goalcard-name { font-size: 1.06rem; letter-spacing: -0.01em; }

/* ==================================================================
   6. DE OPBOUWRAIL
   Van een lijst omlijnde rijen naar een tijdlijn: rustige rijen, één
   duidelijk heden. De rand blijft bestaan voor de geselecteerde week -
   kleur alleen zou de betekenis dragen, en dat mag niet.
   ================================================================== */
.prograil { gap: 6px; }

.prograil-row {
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--panel-strong);
  padding: 12px 14px;
  transition: background-color 120ms ease;
}

.prograil-row:hover { background: var(--teal-wash); }

/* De week die de atleet leest. Naast deze opvulling dragen het woord en
   `aria-current` de betekenis al; dit is de versterking, niet de bron. */
.prograil-selected {
  background: var(--teal-wash);
  border: 2px solid var(--accent);
  padding: 10px 12px;
}

.prograil-now { box-shadow: inset 3px 0 0 var(--accent); }

.prograil-bar {
  height: 10px;
  background: rgba(27, 32, 38, 0.08);
}

.prograil-fill {
  background: linear-gradient(90deg, var(--teal) 0%, var(--horizon-right) 140%);
}

.prograil-when { font-variant-numeric: tabular-nums; }

.prograil-time { font-variant-numeric: tabular-nums; font-weight: 600; }

/* ==================================================================
   7. DAGKAARTEN
   Vier rollen, vier rustige behandelingen. Rust moet er rustig uitzien,
   het evenement moet eruit springen, en de clubrit moet herkenbaar zijn
   zonder belangrijker te lijken dan het doelevenement.
   ================================================================== */
.daycard {
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--panel);
  box-shadow: var(--shadow-sm);
  padding: 14px 16px;
}

.daycard-title { letter-spacing: -0.01em; }

/* Rust: geen kaart die om aandacht vraagt. Vlak, zacht, stil. */
.daycard-rest {
  background: var(--panel-strong);
  box-shadow: none;
}

/* De clubrit is een afspraak: herkenbaar, maar rustiger dan het
   doelevenement. Een streep, geen vlak. */
.daycard-club { box-shadow: inset 3px 0 0 var(--accent), var(--shadow-sm); }

/* Vandaag, en een dag die al voorbij is. */
.daycard-today { box-shadow: inset 0 0 0 2px var(--accent), var(--shadow-sm); }
.daycard-past { opacity: 0.72; box-shadow: none; }

/* De dag van het doel. Amber, en met meer gewicht dan alles eromheen: dit
   is de dag waar de hele opbouw naartoe werkt. Geen rood - het is de
   mooiste dag van het seizoen en geen probleem.

   **Deze regel staat bewust als laatste en op twee klassen.** De toestanden
   hierboven zijn niet wederzijds uitsluitend: `is_goal_event`, `committed`,
   `past` en `today` zijn onafhankelijke vlaggen, dus één kaart kan
   `daycard-event daycard-club` of `daycard-event daycard-past` dragen. Met
   gelijke specificiteit zou de laatst geschreven regel de amber dan
   wegnemen - en dan zou juist deze afwerking de dag onzichtbaar maken die
   dit hele kandidaat-spoor kwam repareren. Twee klassen wint altijd van
   één, ongeacht de volgorde waarin de toestanden worden samengesteld. */
.daycard.daycard-event {
  background: var(--event-wash);
  box-shadow: inset 0 0 0 2px var(--event-edge), var(--shadow-md);
}

/* Een voorbije doeldag blijft een doeldag. Ze dimt mee met elke andere
   voorbije dag, maar ze verliest haar ring niet. */
.daycard.daycard-event.daycard-past {
  opacity: 0.72;
  box-shadow: inset 0 0 0 2px var(--event-edge), var(--shadow-sm);
}

/* De dagen ná het doel. Ze moeten er als herstel uitzien en niet als opbouw:
   een warme, stille rand en geen teal.

   **Twee klassen, en met opzet na de evenementregel.** Herstel en 'voorbij' en
   'vandaag' zijn onafhankelijke vlaggen, dus één kaart kan
   `daycard-recovery daycard-today` dragen; met gelijke specificiteit zou de
   laatst geschreven regel de herstelkleur dan wegnemen. En staat de kaart
   tegelijk als evenementdag gemarkeerd, dan wint het evenement - dat is de
   zwaardere uitspraak, en de decoder sluit die combinatie bovendien uit. */
.daycard.daycard-recovery {
  background: var(--recovery-wash);
  box-shadow: inset 3px 0 0 var(--recovery), var(--shadow-sm);
}

.daycard.daycard-recovery.daycard-past {
  opacity: 0.72;
  box-shadow: inset 3px 0 0 var(--recovery-edge);
}

.daycard-date { font-variant-numeric: tabular-nums; }

/* ==================================================================
   8. HET GESTRUCTUREERDE VOORSCHRIFT
   De blokken lezen als een volgorde in plaats van als een tabel.
   ================================================================== */
.wblock {
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--panel-strong);
  box-shadow: none;
}

.wstep {
  border-radius: 10px;
  border: 0;
  box-shadow: inset 3px 0 0 var(--border-strong);
  background: var(--panel);
}

/* Elke soort stap krijgt zijn eigen streep. De naam van de stap staat er
   nog steeds bij: dit is versterking, geen vervanging. */
.wstep-warm { box-shadow: inset 3px 0 0 var(--horizon-right); }
.wstep-work { box-shadow: inset 3px 0 0 var(--accent); }
.wstep-rest { box-shadow: inset 3px 0 0 var(--border-strong); }
.wstep-cool { box-shadow: inset 3px 0 0 var(--teal-core); }

.wstep-facts { font-variant-numeric: tabular-nums; }
.wtotal-facts { font-variant-numeric: tabular-nums; }

/* ==================================================================
   9. BESCHIKBAARHEID
   Eén rustige planningskaart in plaats van een formulier tussen randen.
   ================================================================== */
.disclosure {
  border: 0;
  border-radius: var(--radius);
  background: var(--panel-strong);
  box-shadow: none;
  overflow: hidden;
}

.disclosure-summary {
  padding: 16px 18px;
  min-height: 56px;
  border-radius: var(--radius);
}

.disclosure-summary:hover { background: var(--teal-wash); }

.disclosure-title { font-weight: 650; letter-spacing: -0.005em; }

.disclosure-body { padding: 4px 18px 18px; }

.dayrow {
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--panel);
  box-shadow: var(--shadow-sm);
  padding: 12px 14px;
}

/* Een dag die de atleet opgaf, is te zien zonder de tekst te lezen. */
.dayrow-available { box-shadow: inset 3px 0 0 var(--accent), var(--shadow-sm); }
.dayrow-club { box-shadow: inset 3px 0 0 var(--event), var(--shadow-sm); }

/* ==================================================================
   10. TYPOGRAFIE EN LEESRUST
   Rustiger metadata, iets meer regelafstand in lopende tekst, en cijfers
   die onder elkaar uitlijnen waar ze vergeleken worden.
   ================================================================== */
.factlist li { border-bottom-color: var(--border); }
.factlist .v { font-variant-numeric: tabular-nums; font-weight: 600; }

.note { color: var(--muted); }

.bullets li { margin-bottom: 4px; }

/* De lange verantwoordingsteksten onderaan een planningspagina zijn eerlijk
   en horen te blijven staan, maar ze hoeven niet even zwaar te wegen als de
   planning zelf. Iets kleiner, iets rustiger. */
.strip { color: var(--muted); font-size: 0.95rem; }

/* ==================================================================
   11. AANRAAKVLAK
   Niets in deze afwerking mag een doel kleiner maken dan het al was.
   ================================================================== */
.prograil-link { min-height: 48px; }
.daycard-go { min-height: 44px; display: inline-flex; align-items: center; }


:root {
  /* Verhoogd vlak: de lichtste waarde op het scherm. Bestond al als
     `--bg-raised`; krijgt hier de naam die bij de vlakkenfamilie hoort. */
  --panel-raised: var(--bg-raised);

  /* Het zachte accentvlak had al een waarde (`--teal-wash`) maar geen
     rolnaam. Vanaf hier is 'gedempt primair' een token. */
  --accent-wash: var(--teal-wash);

  /* HERSTEL. Tot nu toe had een herstelvlak geen eigen kleur: het leende de
     rustbehandeling en las daardoor als 'er gebeurt niets', terwijl er wel
     iets voorgeschreven staat. Een zachte warme zandtint - verwant aan de
     amber van de evenementdag, want herstel hoort bij dat evenement, maar
     stiller. Gemeten op de lichte gronden: 5,37:1 op `--bg` #f1efe6,
     5,27:1 op `--panel-strong` #efede4 en 5,45:1 op `--recovery-wash`
     zelf - overal AA. */
  --recovery: #7a5c2e;
  --recovery-wash: #f6f0e4;
  --recovery-edge: rgba(122, 92, 46, 0.28);

  /* RUST. Bewust het bestaande gedempte grijs en geen nieuwe kleur: rust
     hoort er rustig uit te zien. Als token bestaat de rol nu wél, zodat een
     rustvlak niet langer 'toevallig `--muted`' is. */
  --rest: var(--muted);
  --rest-wash: var(--panel-strong);

  /* FOCUS. De focusring gebruikte overal `--accent-strong` of `--accent`
     door elkaar. Eén naam, zodat de ring in beide verschijningen in één
     regel te verzetten is en nooit stil onder AA zakt. */
  --focus: var(--accent-strong);

  /* GEVAAR. `.btn-danger` gebruikte `--warn`, en `--warn` was dezelfde amber
     als de evenementdag. Een onomkeerbare actie en de mooiste dag van het
     seizoen hoorden nooit dezelfde kleur te dragen.

     De rol had al een eigen naam; hier krijgt ze eindelijk ook een eigen
     waarde. Een echt rood, en niet de aandachtstint: 'dit ging mis' en 'let
     hier op' zijn twee verschillende boodschappen. Gemeten op de lichte
     gronden: 7,33:1 op `--bg` #f7f6f0, 7,86:1 op `--panel` #fffefa en 6,76:1
     op `--panel-strong` #efede4; wit op het gevulde vlak haalt 7,93:1. */
  --danger: #962a1f;
  --danger-edge: rgba(150, 42, 31, 0.35);
  --danger-ink: #ffffff;

  /* Aliassen voor tokens die elders al aangeroepen werden zonder ooit
     gedefinieerd te zijn. Zolang ze alleen als `var(--line, #e4e2db)`
     bestonden, stond er een ingebakken lichte waarde in de regel zelf en
     was er geen donkere variant mogelijk. */
  --line: var(--border);
  --ink: var(--text);
  --surface: var(--panel);
  --surface-2: var(--panel-strong);
  --panel-alt: transparent;

  /* De masthead als eigen rol. In licht is dat het diepe tealvlak dat de
     afwerking introduceerde; in donker mag het geen fel vlak worden, en
     zonder eigen token zou dat verschil in losse regels moeten leven. */
  --hero-bg: linear-gradient(135deg, var(--teal-deep) 0%, var(--teal) 100%);
  --hero-ink: var(--ivory-raised);
  --hero-ink-soft: rgba(255, 254, 250, 0.90);
  --hero-edge: rgba(255, 254, 250, 0.45);
  --hero-veil: rgba(255, 254, 250, 0.08);
  --hero-veil-strong: rgba(255, 254, 250, 0.18);
  --hero-shadow: var(--shadow-hero);

  /* Datareeksen in de sessiegrafiek. Ze stonden als losse hexwaarden in de
     regels; als token kunnen ze in donker meebewegen zonder dat de grafiek
     een tweede stylesheet krijgt. */
  --series-power: var(--accent);
  --series-speed: #2f6f9f;
  --series-heart: #b4436c;
  --series-cadence: #7a6a9b;
  --series-altitude: #8a8578;

  /* De kaart: labelkleur, wegnaam en de halo die een lijn leesbaar houdt. */
  --map-ink: #5f5b50;
  --map-ink-soft: #7a7668;
  --map-halo: #ffffff;
}

/* `.panelgroup` vroeg `var(--line)` zonder fallback. Dat token bestond niet,
   dus de hele declaratie was ongeldig en de groep had in de praktijk geen
   rand. Nu `--line` wel bestaat, zou daar een rand bij komen die er nooit
   stond - en de afwerking gaat juist de andere kant op: minder kader, meer
   vlak. Dus expliciet geen rand, in plaats van er per ongeluk een te maken. */
.panelgroup { border: 0; }

/* De focusring gaat vanaf hier door één token. Zelfde dikte, zelfde afstand,
   zelfde kleur als vandaag in licht; in donker beweegt hij mee. */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* Een onomkeerbare actie draagt vanaf hier de gevaarsrol en niet de
   evenement-amber. Dezelfde waarde in licht, een eigen waarde in donker. */
.btn-danger { background: var(--danger); color: var(--danger-ink); }

/* GEMETEN DEFECT, in een echte browser op de reviewlane: de datum op de
   Home-masthead stond in lichte modus op 1,05:1 en was dus onleesbaar.

   De oorzaak is precies waar de afwerking al voor waarschuwde: `--muted` is voor
   een lichte ondergrond gemaakt, en de masthead is in lichte modus een diep
   tealvlak. `.pagehero .lead` was daarom al apart gezet, maar `.homehero-date`
   en een gewone `.note` in diezelfde masthead waren dat niet, dus vielen ze terug
   op grafietgrijs op teal.

   Eén regel voor de hele rol, via het token dat hiervoor bestaat: gedempte tekst
   in de masthead draagt de zachte masthead-inkt. Dat klopt in beide
   verschijningen - in donker is `--hero-ink-soft` gewoon `--muted`, want daar is
   de masthead grafiet en was er nooit een probleem. */
.pagehero .note,
.pagehero .homehero-date { color: var(--hero-ink-soft); }

/* AANRAAKVLAK. Ook gemeten in de browser: de pillen in de topbar - navigatie,
   taalkeuze, verschijningskeuze en de sessie-indicator - stonden allemaal op
   40px hoog. Dat is vier pixels onder de 44px die dit product elders wel
   aanhoudt (`.prograil-link`, `.daycard-go`, elk formulierveld), en het raakt
   precies de rij die op een telefoon het vaakst wordt aangetikt.

   Vier pixels, en daarom hier in plaats van 'later': het is dezelfde rol op
   dezelfde rij, en de helft ervan verhogen zou de rij ongelijk maken. Er gaat
   geen ruimte verloren die iets zei - de pil was al hoger dan haar tekst. */
.navlink,
.langlink,
.themelink,
.account { min-height: 44px; }

/* En de taalpil was 42px breed: hoog genoeg, twee pixels te smal. Een doel dat
   op één as onder de norm ligt, ligt onder de norm. */
.langlink { min-width: 44px; }

/* Een paneel heeft lucht nodig, geen kamer. */
.panel {
  padding: clamp(20px, 3.4vw, 28px);
  margin-bottom: clamp(14px, 2.4vw, 20px);
}

/* De masthead is een begin, niet een banner. */
.pagehero {
  margin-bottom: clamp(16px, 3vw, 22px);
  padding: clamp(18px, 3.6vw, 26px) clamp(18px, 3.4vw, 28px);
}

.pagehero h1 { font-size: clamp(1.7rem, 5vw, 2.15rem); }

/* De buitenrand van de pagina op groot scherm was de grootste losse
   hoogtepost: 48px boven en onder. De zijkanten blijven zoals ze waren - daar
   is het de leesbreedte die telt, en op de telefoon de gutter. */
.wrap { padding: clamp(18px, 3vw, 32px) clamp(16px, 4vw, 32px); }

/* Feitenlijsten lezen als een tabel; die hoeft niet luchtig te zijn. */
.factlist { gap: 7px; }
.factlist li { padding-bottom: 7px; }

/* De inleidende en toelichtende zinnen stonden elk op een eigen regelafstand
   bovenop de vorige. */
.note { margin-top: 8px; }
.bullets { gap: 4px; }

/* De pillenrij boven een voorschrift is metadata en geen sectie. */
.tchips { margin-bottom: 8px; }

/* De lange verantwoordingsstrook onderaan een planningspagina blijft staan -
   ze is eerlijk en hoort er - maar ze hoeft niet even veel hoogte te krijgen
   als de planning zelf. */
.strip { font-size: 0.92rem; line-height: 1.5; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    /* Drie stappen grond. De hiërarchie komt hiervan, niet van randen. */
    --graphite-ground: #14171a;
    --graphite-surface: #1c2024;
    --graphite-raised: #23282d;
    --graphite-sunk: #181b1e;

    --bg: var(--graphite-ground);
    --bg-raised: var(--graphite-raised);
    --panel: var(--graphite-surface);
    --panel-raised: var(--graphite-raised);
    --panel-strong: var(--graphite-sunk);
    --surface: var(--panel);
    --surface-2: var(--panel-strong);
    --panel-alt: transparent;

    /* De merk-neutralen die elders rechtstreeks als vlak worden aangeroepen.
       `--ivory-raised` staat er bewust niet bij: dat token wordt uitsluitend
       als *inkt* op de masthead gebruikt, en die masthead heeft hieronder haar
       eigen donkere regels. Een vlak-remap zou daar zwarte tekst op zwart
       zetten. */
    --ivory: var(--graphite-ground);
    --ivory-sunk: var(--graphite-sunk);
    --ivory-veil: rgba(20, 23, 26, 0.90);

    /* Gebroken wit, geen wit: 15:1 op deze grond leest als een lamp. */
    --text: #e8eae7;
    --ink: var(--text);
    --muted: #a7b0b8;

    /* Teal Balance op een donkere grond. Dit is dezelfde kleur als in het
       logo-familie, hier gedempt in plaats van fel: de lichte core-teal
       (#74c3b6) haalt op deze grond 8,76:1 en dat is voor een vlak-vullend
       accent te schreeuwend. Eén stap terug houdt AAA (7,81:1) en blijft
       rustig. */
    --teal: #6fb8ab;
    --teal-core: #8ac9be;
    --teal-deep: #4f9e92;
    --teal-wash: rgba(111, 184, 171, 0.13);
    --teal-edge: rgba(111, 184, 171, 0.38);
    --accent: var(--teal);
    --accent-strong: var(--teal-core);
    --accent-wash: var(--teal-wash);
    /* Inkt op een gevuld accentvlak. Bijna-zwart op de gedempte teal:
       8,24:1, en 10,10:1 op de lichtere hover-teal. Ruim AAA, en het houdt de
       knop een vlak in plaats van een omlijning. */
    --accent-ink: #0d1113;

    /* De evenementdag: ingehouden warme amber. Geen oranje alarm. */
    --event: #e0ac55;
    --event-wash: rgba(224, 172, 85, 0.14);
    --event-edge: rgba(224, 172, 85, 0.42);

    /* Herstel: zacht warm zand/brons. Verwant aan de amber, duidelijk stiller,
       en onmiskenbaar niet de teal van een opbouwdag. */
    --recovery: #c9b79a;
    --recovery-wash: rgba(201, 183, 154, 0.13);
    --recovery-edge: rgba(201, 183, 154, 0.38);

    /* Rust: een stil, koel neutraal. Het vraagt niets. */
    --rest: #98a2aa;
    --rest-wash: rgba(152, 162, 170, 0.09);

    /* Aandacht. Dezelfde scheiding als in licht, met dezelfde stappen: één
       stap roder dan de evenement-amber `#e0ac55` en één stap goudener dan het
       gevaar-rood `#e08a7d`. Gemeten: 8,24:1 op `--bg`, 7,51:1 op `--panel`,
       6,81:1 op `--panel-raised` - overal AAA. */
    --caution: #e6a06e;
    --caution-wash: rgba(230, 160, 110, 0.13);
    --caution-edge: rgba(230, 160, 110, 0.40);
    --warn: var(--caution);
    --warn-edge: var(--caution-edge);

    /* Informatie en taper: de enige koele semantische rol. Gemeten: 8,51:1 op
       `--bg`, 7,75:1 op `--panel`, 7,03:1 op `--panel-raised`. */
    --info: #9ab6cc;
    --info-wash: rgba(154, 182, 204, 0.12);
    --info-edge: rgba(154, 182, 204, 0.36);
    --taper: var(--info);
    --taper-wash: var(--info-wash);
    --taper-edge: var(--info-edge);

    /* Opbouw volgt het accent, net als in licht. */
    --progress: var(--accent);
    --progress-wash: var(--accent-wash);
    --progress-edge: var(--teal-edge);

    --ok: #6ec2a0;
    --ok-edge: rgba(110, 194, 160, 0.40);

    /* Gevaar is hier wél een eigen kleur, en niet de amber: op donker is een
       gedempt rood leesbaar (6,94:1) en het zegt iets anders dan een
       kalendermoment. */
    --danger: #e08a7d;
    --danger-edge: rgba(224, 138, 125, 0.42);
    --danger-ink: #180a07;

    /* De focusring een stap lichter dan het accent, zodat hij ook bovenop een
       accentvlak nog een ring is. */
    --focus: #9fd6cb;

    /* Randen zijn licht en zeer zacht: een donkere rand op een donkere grond is
       een groef, geen scheiding. */
    --border: rgba(232, 234, 231, 0.10);
    --border-strong: rgba(232, 234, 231, 0.24);
    --line: var(--border);

    /* Elevatie op donker komt niet van een schaduw - die is onzichtbaar - maar
       van de grondstappen hierboven. De schaduw blijft staan als diepte onder
       een vlak dat werkelijk zweeft, en wordt daarvoor echt zwart. */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.40),
      0 2px 8px rgba(0, 0, 0, 0.28);
    --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.44),
      0 14px 32px rgba(0, 0, 0, 0.34);
    --shadow-hero: 0 14px 34px rgba(0, 0, 0, 0.42);

    /* De masthead is op donker geen fel tealvlak maar een verhoogd
       grafietvlak met een tealrail. Een lichtgevende balk bovenaan een donkere
       pagina is precies de gamerlook die dit product niet is. */
    --hero-bg: var(--graphite-raised);
    --hero-ink: var(--text);
    --hero-ink-soft: var(--muted);
    --hero-edge: var(--border-strong);
    --hero-veil: rgba(232, 234, 231, 0.06);
    --hero-veil-strong: rgba(232, 234, 231, 0.12);
    --hero-shadow: var(--shadow-sm);

    /* Datareeksen, opgelicht tot ze op grafiet leesbaar zijn. */
    --series-power: var(--accent);
    --series-speed: #7fb3dc;
    --series-heart: #e08aa8;
    --series-cadence: #b3a6d6;
    --series-altitude: #bdb7a6;

    /* De kaart keert mee om: lichte labels met een donkere halo eronder. */
    --map-ink: #cdd3d8;
    --map-ink-soft: #a8aeb4;
    --map-halo: #0f1215;
  }

  /* De masthead. Rail in plaats van vlak: één tealstreep links zegt hetzelfde
     als een heel teal vlak, en laat de pagina donker beginnen. */
  :root:not([data-theme="light"]) .pagehero {
    background: var(--hero-bg);
    box-shadow: inset 3px 0 0 var(--accent), var(--hero-shadow);
  }

  /* De decoratieve horizon-gloed hoort bij het lichte tealvlak. Op grafiet is
     ze een groene waas; ze gaat uit. */
  :root:not([data-theme="light"]) .pagehero::after { background: none; }

  :root:not([data-theme="light"]) .pagehero h1 { color: var(--hero-ink); }
  :root:not([data-theme="light"]) .pagehero .lead { color: var(--hero-ink-soft); }
  :root:not([data-theme="light"]) .pagehero .btn-link {
    border-color: var(--teal-edge);
    color: var(--accent);
    background: transparent;
  }
  :root:not([data-theme="light"]) .pagehero .btn-link:hover { background: var(--accent-wash); }
  :root:not([data-theme="light"]) .pagehero a:focus-visible { outline-color: var(--focus); }

  /* De voortgangsbalk in de rail: de lege helft was een donkere schaduw op
     licht; op donker moet ze licht zijn om nog een balk te zijn. */
  :root:not([data-theme="light"]) .prograil-bar { background: rgba(232, 234, 231, 0.10); }

  /* Een voorbije dag dimt door dekking te verliezen. Gemeten: op `--panel`
     zakt de gedempte tekst bij dekking 0,72 naar 4,55:1 - dat is AA op de rand
     van de rand. Bij 0,82 staat ze op 5,46:1 en blijft de dag nog steeds
     duidelijk voorbij. Het lichte palet houdt 0,72, want daar staat dezelfde
     tekst op een ivoren grond en is er marge. */
  :root:not([data-theme="light"]) .daycard-past { opacity: 0.82; }
  :root:not([data-theme="light"]) .daycard.daycard-event.daycard-past { opacity: 0.82; }

  /* De sessiegrafiek: reekskleuren en hun legendastalen door hun token. */
  :root:not([data-theme="light"]) .sg-speed { stroke: var(--series-speed); }
  :root:not([data-theme="light"]) .sg-heart { stroke: var(--series-heart); }
  :root:not([data-theme="light"]) .sg-cadence { stroke: var(--series-cadence); }
  :root:not([data-theme="light"]) .sg-altitude { stroke: var(--series-altitude); }
  :root:not([data-theme="light"]) .sg-stop { stroke: var(--series-heart); }
  :root:not([data-theme="light"]) .sg-toggle.sg-speed span::before {
    background: repeating-linear-gradient(90deg,
      var(--series-speed) 0 9px, transparent 9px 12px);
  }
  :root:not([data-theme="light"]) .sg-toggle.sg-heart span::before {
    background: repeating-linear-gradient(90deg,
      var(--series-heart) 0 5px, transparent 5px 8px);
  }
  :root:not([data-theme="light"]) .sg-toggle.sg-cadence span::before {
    background: repeating-linear-gradient(90deg,
      var(--series-cadence) 0 1px, transparent 1px 4px);
  }
  :root:not([data-theme="light"]) .sg-toggle.sg-altitude span::before {
    background: repeating-linear-gradient(90deg,
      var(--series-altitude) 0 8px, transparent 8px 12px);
  }
  /* De banden achter de grafiek waren donkere veegjes op licht. */
  :root:not([data-theme="light"]) .sg-band { fill: rgba(111, 184, 171, 0.05); }
  :root:not([data-theme="light"]) .sg-band-1 { fill: rgba(111, 184, 171, 0.10); }

  /* De kaart. De halo onder een lijn of label is de grond, niet wit. */
  :root:not([data-theme="light"]) .sm-label, :root:not([data-theme="light"]) .sm-way { fill: var(--map-ink); stroke: var(--map-halo); }
  :root:not([data-theme="light"]) .sm-way-path { fill: var(--map-ink-soft); }
  :root:not([data-theme="light"]) .routemap-halo { stroke: var(--map-halo); opacity: 0.70; }
  /* De ondergrond keert mee om, en tot hier deed ze dat niet. De wegtinten staan
     in de lichte bladwijzer als gedempte greige lijnen op ivoor; op grafiet bleven
     ze staan en werden ze het lichtste wat op de kaart stond - lichter dan de
     route zelf. De atleet zag dan een wegennet met een lijn erin, in plaats van
     een route op een ondergrond.

     De waarden hieronder zijn niet nieuw bedacht: het zijn exact de tinten die het
     kaartdocument voor de telefoon al uitlevert, en die de atleet daar heeft
     goedgekeurd. Web en telefoon tekenen dezelfde kaart, dus ze horen dezelfde
     grond te tekenen - en de grond zelf (`--panel-strong`, #181b1e) is er al
     gelijk aan. De grote weg blijft het zwaarst van de ondergrond: hij draagt de
     geografische oriëntatie die de route juist leesbaar maakt.

     **Uitdrukkelijk binnen `.routemap` en niet op elke `.sm-base-*`.** Diezelfde
     klassen tekenen ook de sessiekaart, en die heeft een eigen doek:
     `.sm-canvas` staat op een letterlijke ivoren `#f4f2ec` zonder donkere
     tegenhanger. Ongescoped zouden deze tinten dáár bijna-zwarte wegen op ivoor
     zetten en de plaatsnamen onleesbaar maken - een omkering op een vlak dat
     deze slice niet aanraakt. De sessiekaart draait haar grond niet om, dus zij
     hoort haar wegen ook niet om te draaien. */
  :root:not([data-theme="light"]) .routemap .sm-base-waterarea { fill: #22303a; stroke: none; }
  :root:not([data-theme="light"]) .routemap .sm-base-water { stroke: #2b3d48; }
  :root:not([data-theme="light"]) .routemap .sm-base-rail { stroke: #3a3e43; }
  :root:not([data-theme="light"]) .routemap .sm-base-path { stroke: #2f3336; }
  :root:not([data-theme="light"]) .routemap .sm-base-road { stroke: #3b4045; }
  :root:not([data-theme="light"]) .routemap .sm-base-major { stroke: #4c5259; }
  :root:not([data-theme="light"]) .routemap .sm-place { fill: #c4c0b4; }

  /* Formuliervelden en keuzevlakken moeten op donker een vlak zijn en geen
     uitgesneden gat: het verhoogde grafiet, niet de grond. */
  :root:not([data-theme="light"]) input, :root:not([data-theme="light"]) select, :root:not([data-theme="light"]) textarea { background: var(--panel-raised); }

}

:root[data-theme="dark"] {
  color-scheme: dark;

  /* Drie stappen grond. De hiërarchie komt hiervan, niet van randen. */
  --graphite-ground: #14171a;
  --graphite-surface: #1c2024;
  --graphite-raised: #23282d;
  --graphite-sunk: #181b1e;

  --bg: var(--graphite-ground);
  --bg-raised: var(--graphite-raised);
  --panel: var(--graphite-surface);
  --panel-raised: var(--graphite-raised);
  --panel-strong: var(--graphite-sunk);
  --surface: var(--panel);
  --surface-2: var(--panel-strong);
  --panel-alt: transparent;

  /* De merk-neutralen die elders rechtstreeks als vlak worden aangeroepen.
     `--ivory-raised` staat er bewust niet bij: dat token wordt uitsluitend
     als *inkt* op de masthead gebruikt, en die masthead heeft hieronder haar
     eigen donkere regels. Een vlak-remap zou daar zwarte tekst op zwart
     zetten. */
  --ivory: var(--graphite-ground);
  --ivory-sunk: var(--graphite-sunk);
  --ivory-veil: rgba(20, 23, 26, 0.90);

  /* Gebroken wit, geen wit: 15:1 op deze grond leest als een lamp. */
  --text: #e8eae7;
  --ink: var(--text);
  --muted: #a7b0b8;

  /* Teal Balance op een donkere grond. Dit is dezelfde kleur als in het
     logo-familie, hier gedempt in plaats van fel: de lichte core-teal
     (#74c3b6) haalt op deze grond 8,76:1 en dat is voor een vlak-vullend
     accent te schreeuwend. Eén stap terug houdt AAA (7,81:1) en blijft
     rustig. */
  --teal: #6fb8ab;
  --teal-core: #8ac9be;
  --teal-deep: #4f9e92;
  --teal-wash: rgba(111, 184, 171, 0.13);
  --teal-edge: rgba(111, 184, 171, 0.38);
  --accent: var(--teal);
  --accent-strong: var(--teal-core);
  --accent-wash: var(--teal-wash);
  /* Inkt op een gevuld accentvlak. Bijna-zwart op de gedempte teal:
     8,24:1, en 10,10:1 op de lichtere hover-teal. Ruim AAA, en het houdt de
     knop een vlak in plaats van een omlijning. */
  --accent-ink: #0d1113;

  /* De evenementdag: ingehouden warme amber. Geen oranje alarm. */
  --event: #e0ac55;
  --event-wash: rgba(224, 172, 85, 0.14);
  --event-edge: rgba(224, 172, 85, 0.42);

  /* Herstel: zacht warm zand/brons. Verwant aan de amber, duidelijk stiller,
     en onmiskenbaar niet de teal van een opbouwdag. */
  --recovery: #c9b79a;
  --recovery-wash: rgba(201, 183, 154, 0.13);
  --recovery-edge: rgba(201, 183, 154, 0.38);

  /* Rust: een stil, koel neutraal. Het vraagt niets. */
  --rest: #98a2aa;
  --rest-wash: rgba(152, 162, 170, 0.09);

  /* Aandacht. Dezelfde scheiding als in licht, met dezelfde stappen: één
     stap roder dan de evenement-amber `#e0ac55` en één stap goudener dan het
     gevaar-rood `#e08a7d`. Gemeten: 8,24:1 op `--bg`, 7,51:1 op `--panel`,
     6,81:1 op `--panel-raised` - overal AAA. */
  --caution: #e6a06e;
  --caution-wash: rgba(230, 160, 110, 0.13);
  --caution-edge: rgba(230, 160, 110, 0.40);
  --warn: var(--caution);
  --warn-edge: var(--caution-edge);

  /* Informatie en taper: de enige koele semantische rol. Gemeten: 8,51:1 op
     `--bg`, 7,75:1 op `--panel`, 7,03:1 op `--panel-raised`. */
  --info: #9ab6cc;
  --info-wash: rgba(154, 182, 204, 0.12);
  --info-edge: rgba(154, 182, 204, 0.36);
  --taper: var(--info);
  --taper-wash: var(--info-wash);
  --taper-edge: var(--info-edge);

  /* Opbouw volgt het accent, net als in licht. */
  --progress: var(--accent);
  --progress-wash: var(--accent-wash);
  --progress-edge: var(--teal-edge);

  --ok: #6ec2a0;
  --ok-edge: rgba(110, 194, 160, 0.40);

  /* Gevaar is hier wél een eigen kleur, en niet de amber: op donker is een
     gedempt rood leesbaar (6,94:1) en het zegt iets anders dan een
     kalendermoment. */
  --danger: #e08a7d;
  --danger-edge: rgba(224, 138, 125, 0.42);
  --danger-ink: #180a07;

  /* De focusring een stap lichter dan het accent, zodat hij ook bovenop een
     accentvlak nog een ring is. */
  --focus: #9fd6cb;

  /* Randen zijn licht en zeer zacht: een donkere rand op een donkere grond is
     een groef, geen scheiding. */
  --border: rgba(232, 234, 231, 0.10);
  --border-strong: rgba(232, 234, 231, 0.24);
  --line: var(--border);

  /* Elevatie op donker komt niet van een schaduw - die is onzichtbaar - maar
     van de grondstappen hierboven. De schaduw blijft staan als diepte onder
     een vlak dat werkelijk zweeft, en wordt daarvoor echt zwart. */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.40),
    0 2px 8px rgba(0, 0, 0, 0.28);
  --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.44),
    0 14px 32px rgba(0, 0, 0, 0.34);
  --shadow-hero: 0 14px 34px rgba(0, 0, 0, 0.42);

  /* De masthead is op donker geen fel tealvlak maar een verhoogd
     grafietvlak met een tealrail. Een lichtgevende balk bovenaan een donkere
     pagina is precies de gamerlook die dit product niet is. */
  --hero-bg: var(--graphite-raised);
  --hero-ink: var(--text);
  --hero-ink-soft: var(--muted);
  --hero-edge: var(--border-strong);
  --hero-veil: rgba(232, 234, 231, 0.06);
  --hero-veil-strong: rgba(232, 234, 231, 0.12);
  --hero-shadow: var(--shadow-sm);

  /* Datareeksen, opgelicht tot ze op grafiet leesbaar zijn. */
  --series-power: var(--accent);
  --series-speed: #7fb3dc;
  --series-heart: #e08aa8;
  --series-cadence: #b3a6d6;
  --series-altitude: #bdb7a6;

  /* De kaart keert mee om: lichte labels met een donkere halo eronder. */
  --map-ink: #cdd3d8;
  --map-ink-soft: #a8aeb4;
  --map-halo: #0f1215;
}

/* De masthead. Rail in plaats van vlak: één tealstreep links zegt hetzelfde
   als een heel teal vlak, en laat de pagina donker beginnen. */
:root[data-theme="dark"] .pagehero {
  background: var(--hero-bg);
  box-shadow: inset 3px 0 0 var(--accent), var(--hero-shadow);
}

/* De decoratieve horizon-gloed hoort bij het lichte tealvlak. Op grafiet is
   ze een groene waas; ze gaat uit. */
:root[data-theme="dark"] .pagehero::after { background: none; }

:root[data-theme="dark"] .pagehero h1 { color: var(--hero-ink); }
:root[data-theme="dark"] .pagehero .lead { color: var(--hero-ink-soft); }
:root[data-theme="dark"] .pagehero .btn-link {
  border-color: var(--teal-edge);
  color: var(--accent);
  background: transparent;
}
:root[data-theme="dark"] .pagehero .btn-link:hover { background: var(--accent-wash); }
:root[data-theme="dark"] .pagehero a:focus-visible { outline-color: var(--focus); }

/* De voortgangsbalk in de rail: de lege helft was een donkere schaduw op
   licht; op donker moet ze licht zijn om nog een balk te zijn. */
:root[data-theme="dark"] .prograil-bar { background: rgba(232, 234, 231, 0.10); }

/* Een voorbije dag dimt door dekking te verliezen. Gemeten: op `--panel`
   zakt de gedempte tekst bij dekking 0,72 naar 4,55:1 - dat is AA op de rand
   van de rand. Bij 0,82 staat ze op 5,46:1 en blijft de dag nog steeds
   duidelijk voorbij. Het lichte palet houdt 0,72, want daar staat dezelfde
   tekst op een ivoren grond en is er marge. */
:root[data-theme="dark"] .daycard-past { opacity: 0.82; }
:root[data-theme="dark"] .daycard.daycard-event.daycard-past { opacity: 0.82; }

/* De sessiegrafiek: reekskleuren en hun legendastalen door hun token. */
:root[data-theme="dark"] .sg-speed { stroke: var(--series-speed); }
:root[data-theme="dark"] .sg-heart { stroke: var(--series-heart); }
:root[data-theme="dark"] .sg-cadence { stroke: var(--series-cadence); }
:root[data-theme="dark"] .sg-altitude { stroke: var(--series-altitude); }
:root[data-theme="dark"] .sg-stop { stroke: var(--series-heart); }
:root[data-theme="dark"] .sg-toggle.sg-speed span::before {
  background: repeating-linear-gradient(90deg,
    var(--series-speed) 0 9px, transparent 9px 12px);
}
:root[data-theme="dark"] .sg-toggle.sg-heart span::before {
  background: repeating-linear-gradient(90deg,
    var(--series-heart) 0 5px, transparent 5px 8px);
}
:root[data-theme="dark"] .sg-toggle.sg-cadence span::before {
  background: repeating-linear-gradient(90deg,
    var(--series-cadence) 0 1px, transparent 1px 4px);
}
:root[data-theme="dark"] .sg-toggle.sg-altitude span::before {
  background: repeating-linear-gradient(90deg,
    var(--series-altitude) 0 8px, transparent 8px 12px);
}
/* De banden achter de grafiek waren donkere veegjes op licht. */
:root[data-theme="dark"] .sg-band { fill: rgba(111, 184, 171, 0.05); }
:root[data-theme="dark"] .sg-band-1 { fill: rgba(111, 184, 171, 0.10); }

/* De kaart. De halo onder een lijn of label is de grond, niet wit. */
:root[data-theme="dark"] .sm-label, :root[data-theme="dark"] .sm-way { fill: var(--map-ink); stroke: var(--map-halo); }
:root[data-theme="dark"] .sm-way-path { fill: var(--map-ink-soft); }
:root[data-theme="dark"] .routemap-halo { stroke: var(--map-halo); opacity: 0.70; }
/* De ondergrond keert mee om, en tot hier deed ze dat niet. De wegtinten staan
   in de lichte bladwijzer als gedempte greige lijnen op ivoor; op grafiet bleven
   ze staan en werden ze het lichtste wat op de kaart stond - lichter dan de
   route zelf. De atleet zag dan een wegennet met een lijn erin, in plaats van
   een route op een ondergrond.

   De waarden hieronder zijn niet nieuw bedacht: het zijn exact de tinten die het
   kaartdocument voor de telefoon al uitlevert, en die de atleet daar heeft
   goedgekeurd. Web en telefoon tekenen dezelfde kaart, dus ze horen dezelfde
   grond te tekenen - en de grond zelf (`--panel-strong`, #181b1e) is er al
   gelijk aan. De grote weg blijft het zwaarst van de ondergrond: hij draagt de
   geografische oriëntatie die de route juist leesbaar maakt.

   **Uitdrukkelijk binnen `.routemap` en niet op elke `.sm-base-*`.** Diezelfde
   klassen tekenen ook de sessiekaart, en die heeft een eigen doek:
   `.sm-canvas` staat op een letterlijke ivoren `#f4f2ec` zonder donkere
   tegenhanger. Ongescoped zouden deze tinten dáár bijna-zwarte wegen op ivoor
   zetten en de plaatsnamen onleesbaar maken - een omkering op een vlak dat
   deze slice niet aanraakt. De sessiekaart draait haar grond niet om, dus zij
   hoort haar wegen ook niet om te draaien. */
:root[data-theme="dark"] .routemap .sm-base-waterarea { fill: #22303a; stroke: none; }
:root[data-theme="dark"] .routemap .sm-base-water { stroke: #2b3d48; }
:root[data-theme="dark"] .routemap .sm-base-rail { stroke: #3a3e43; }
:root[data-theme="dark"] .routemap .sm-base-path { stroke: #2f3336; }
:root[data-theme="dark"] .routemap .sm-base-road { stroke: #3b4045; }
:root[data-theme="dark"] .routemap .sm-base-major { stroke: #4c5259; }
:root[data-theme="dark"] .routemap .sm-place { fill: #c4c0b4; }

/* Formuliervelden en keuzevlakken moeten op donker een vlak zijn en geen
   uitgesneden gat: het verhoogde grafiet, niet de grond. */
:root[data-theme="dark"] input, :root[data-theme="dark"] select, :root[data-theme="dark"] textarea { background: var(--panel-raised); }


.settings-section + .settings-section { margin-top: 18px; }
.settings-heading {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
  font-size: 1.2rem;
}
.settings-heading .icon { color: var(--accent); width: 1.1em; height: 1.1em; }

/* Een keuzegroep: echte links, met het vinkje als tweede kanaal naast de
   achtergrond. Zonder dat vinkje zou 'welke taal staat aan' uitsluitend een
   kleurverschil zijn. */
.choicegroup {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.choicelink {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--panel-strong);
  color: var(--muted);
  text-decoration: none;
  font-size: 0.95rem;
}
.choicelink:hover { color: var(--text); border-color: var(--border-strong); }
.choicelink.active {
  color: var(--text);
  border-color: var(--accent);
  background: var(--accent-wash);
}
/* Het vinkje neemt zijn ruimte ook in wanneer het er niet is, zodat de
   labels niet verspringen op het moment dat je kiest. */
.choicemark {
  display: inline-flex;
  width: 1.15em;
  height: 1.15em;
  flex: 0 0 auto;
}
.choicelink.active .choicemark { color: var(--accent); }

/* De toestandslegenda. */
.legendlist {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.legendrow {
  display: grid;
  grid-template-columns: 4px auto minmax(0, 1fr);
  align-items: start;
  gap: 12px;
  padding: 10px 12px;
  border-radius: var(--radius-sm, 10px);
  background: var(--panel-strong);
}
.legendswatch {
  align-self: stretch;
  border-radius: 999px;
  background: var(--legend-colour, var(--muted));
  min-height: 100%;
}
.legendicon { color: var(--legend-colour, var(--muted)); display: inline-flex; }
.legendicon .icon { width: 1.3em; height: 1.3em; }
.legendtext { display: grid; gap: 2px; min-width: 0; }
.legendname { font-weight: 600; }
.legendbody { color: var(--muted); font-size: 0.92rem; }

/* De koppeling tussen een toestand en haar token. Dit is de enige plek waar
   die koppeling in CSS staat; componenten elders gebruiken het token
   rechtstreeks. */
.state-progress { --legend-colour: var(--progress); }
.state-recovery { --legend-colour: var(--recovery); }
.state-event { --legend-colour: var(--event); }
.state-taper { --legend-colour: var(--taper); }
.state-rest { --legend-colour: var(--rest); }
.state-caution { --legend-colour: var(--caution); }
.state-error { --legend-colour: var(--danger); }
