/*
 * Sillage : le design bleu Performance, commun à toutes les pages, en clair et en sombre.
 * Les couleurs des coureurs (--athlete-*), de la pente (--grade-*) et des maillots (--jersey-*)
 * gardent leur sens sur les cartes, les profils et les courbes.
 * Classes du système : .btn, .card, .field, .input, .chip, .dot, .table, .stat, .seg, .chart, .runner.
 */

:root {
  --bg: #edf6ff;
  --surface: #ffffff;
  --surface-2: #e5f1ff;
  --line: #d7e5fa;
  --line-strong: #b7ceee;
  --text: #081338;
  --muted: #526387;
  --faint: #7182a3;
  --primary: #0866ff;
  --primary-text: #ffffff;
  --power-zone-1: #64748b;
  --power-zone-2: #2563eb;
  --power-zone-3: #16a34a;
  --power-zone-4: #ca8a04;
  --power-zone-5: #ea580c;
  --power-zone-6: #dc2626;
  --danger: #b3261e;
  --danger-soft: #fdecea;
  --ok: #006300;
  --ok-soft: #e6f4e6;
  --shadow: 0 1px 3px rgb(8 19 56 / 3%), 0 8px 24px rgb(8 102 255 / 3%);
  --radius: 14px;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;

  /* Les huit couleurs de coureur, dans un ordre fixe, et l'encre lisible posée dessus. */
  --athlete-1: #2a78d6; --athlete-1-ink: #ffffff;
  --athlete-2: #eb6834; --athlete-2-ink: #0b0b0b;
  --athlete-3: #1baf7a; --athlete-3-ink: #0b0b0b;
  --athlete-4: #eda100; --athlete-4-ink: #0b0b0b;
  --athlete-5: #e87ba4; --athlete-5-ink: #0b0b0b;
  --athlete-6: #008300; --athlete-6-ink: #ffffff;
  --athlete-7: #4a3aa7; --athlete-7-ink: #ffffff;
  --athlete-8: #e34948; --athlete-8-ink: #ffffff;
  /* Les mêmes dans la maquette, qui a son jour et sa nuit à elle, quel que soit le thème de l'écran
     (lib/theme.js, `athleteColor`) : celles du thème clair le jour, celles du thème sombre la nuit. */
  --athlete-1-day: #2a78d6; --athlete-1-night: #3987e5;
  --athlete-2-day: #eb6834; --athlete-2-night: #d95926;
  --athlete-3-day: #1baf7a; --athlete-3-night: #199e70;
  --athlete-4-day: #eda100; --athlete-4-night: #c98500;
  --athlete-5-day: #e87ba4; --athlete-5-night: #d55181;
  --athlete-6-day: #008300; --athlete-6-night: #008300;
  --athlete-7-day: #4a3aa7; --athlete-7-night: #9085e9;
  --athlete-8-day: #e34948; --athlete-8-night: #e66767;

  /* La pente, sur le profil d'un segment (lib/grade.js). Les montées ont les couleurs des sites de profils de
     cols (l'échelle de Climbfinder, relevée le 2026-10-12) : du jaune pâle au rouge sombre puis au presque noir,
     un palier à 1, 2, 4, 6, 8, 10, 12, 15 et 20 %. Le plat est gris ; les descentes en bleu, un palier à 2, 5, 8
     et 11 %. Les mêmes en thème clair et en thème sombre : c'est un code, il ne change pas avec l'écran. Ne pas
     les redéfinir dans le bloc du thème sombre. */
  --grade-flat: #e2e1dc;
  --grade-up-1: #fed976; --grade-up-2: #feb24c; --grade-up-3: #fd8d3c; --grade-up-4: #fc4e2a; --grade-up-5: #e31a1c;
  --grade-up-6: #bd0026; --grade-up-7: #98001f; --grade-up-8: #4f0017; --grade-up-9: #24000a;
  --grade-down-1: #86b6ef; --grade-down-2: #5598e7; --grade-down-3: #256abf; --grade-down-4: #104281;

  /* Les deux maillots d'une sortie à plusieurs (`jersey`, dans OutingsHelper) : le jaune, et le blanc à pois
     rouges. Comme la pente, c'est un code : les mêmes en thème clair et en thème sombre, à ne pas redéfinir
     dans le bloc du thème sombre. */
  --jersey-yellow: #ffd91a; --jersey-white: #ffffff; --jersey-dots: #e0261c;
  --accent: #065dff;
  --accent-soft: #e5f1ff;
  --accent-line: #d0e1fb;
  /* Le relief vu d'en haut de la page du passage idéal (lib/relief_map.js) : le fond de la page, l'ombre, la lumière,
     les courbes et une courbe sur cinq. Puis l'écart au meilleur temps dans sa grille, de tout près (0) à 13 % et plus
     (5) : plus une case en est loin, plus elle se fond dans la carte. */
  --relief-paper: #edf6ff; --relief-shade: #bccfeb; --relief-light: #ffffff; --relief-line: #bdd0ed; --relief-bold: #8dabd9;
  --ideal-gap-0: #6d8fc7; --ideal-gap-1: #8fa9d6; --ideal-gap-2: #aec2e3; --ideal-gap-3: #c8d7ee; --ideal-gap-4: #dde7f6; --ideal-gap-5: #edf2fa;
}

/* Le thème sombre. Il s'applique quand le système le demande et que l'on n'a pas choisi le clair sur cet appareil,
   ou quand on a choisi le sombre (`data-theme`, posé sur `body` par le gabarit d'après `ThemesController`). Les
   couleurs sont donc sur `body`, pas sur `:root`, et c'est là que `lib/theme.js` les lit. Les deux blocs disent
   la même chose, mot pour mot : toucher à l'un, c'est toucher à l'autre (un test le vérifie). */
@media (prefers-color-scheme: dark) {
  body:not([data-theme="light"]) {
    --bg: #0b1322;
    --surface: #131f32;
    --surface-2: #1a3053;
    --line: #2a3e5c;
    --line-strong: #47618a;
    --text: #f0f5ff;
    --muted: #a9bad8;
    --faint: #8195b5;
    --primary: #245edb;
    --primary-text: #ffffff;
    --danger: #f2877f;
    --danger-soft: #3a1b18;
    --ok: #0ca30c;
    --ok-soft: #132a13;
    --shadow: 0 1px 3px rgb(0 0 0 / 20%), 0 8px 24px rgb(0 0 0 / 10%);

    --athlete-1: #3987e5; --athlete-1-ink: #ffffff;
    --athlete-2: #d95926; --athlete-2-ink: #ffffff;
    --athlete-3: #199e70; --athlete-3-ink: #0b0b0b;
    --athlete-4: #c98500; --athlete-4-ink: #0b0b0b;
    --athlete-5: #d55181; --athlete-5-ink: #ffffff;
    --athlete-6: #008300; --athlete-6-ink: #ffffff;
    --athlete-7: #9085e9; --athlete-7-ink: #0b0b0b;
    --athlete-8: #e66767; --athlete-8-ink: #0b0b0b;
    --accent: #82adff;
    --accent-soft: #1a3053;
    --accent-line: #304b73;
    --relief-paper: #0b1322; --relief-shade: #040913; --relief-light: #17263e; --relief-line: #182841; --relief-bold: #2c4469;
    --ideal-gap-0: #b9d2f5; --ideal-gap-1: #8eaedb; --ideal-gap-2: #6a88b6; --ideal-gap-3: #4c6690; --ideal-gap-4: #34496b; --ideal-gap-5: #22324e;
  }
}
body[data-theme="dark"] {
  --bg: #0b1322;
  --surface: #131f32;
  --surface-2: #1a3053;
  --line: #2a3e5c;
  --line-strong: #47618a;
  --text: #f0f5ff;
  --muted: #a9bad8;
  --faint: #8195b5;
  --primary: #245edb;
  --primary-text: #ffffff;
  --danger: #f2877f;
  --danger-soft: #3a1b18;
  --ok: #0ca30c;
  --ok-soft: #132a13;
  --shadow: 0 1px 3px rgb(0 0 0 / 20%), 0 8px 24px rgb(0 0 0 / 10%);

  --athlete-1: #3987e5; --athlete-1-ink: #ffffff;
  --athlete-2: #d95926; --athlete-2-ink: #ffffff;
  --athlete-3: #199e70; --athlete-3-ink: #0b0b0b;
  --athlete-4: #c98500; --athlete-4-ink: #0b0b0b;
  --athlete-5: #d55181; --athlete-5-ink: #ffffff;
  --athlete-6: #008300; --athlete-6-ink: #ffffff;
  --athlete-7: #9085e9; --athlete-7-ink: #0b0b0b;
  --athlete-8: #e66767; --athlete-8-ink: #0b0b0b;
  --accent: #82adff;
  --accent-soft: #1a3053;
  --accent-line: #304b73;
  --relief-paper: #0b1322; --relief-shade: #040913; --relief-light: #17263e; --relief-line: #182841; --relief-bold: #2c4469;
  --ideal-gap-0: #b9d2f5; --ideal-gap-1: #8eaedb; --ideal-gap-2: #6a88b6; --ideal-gap-3: #4c6690; --ideal-gap-4: #34496b; --ideal-gap-5: #22324e;
}
/* Les champs, les listes et les barres de défilement du navigateur suivent le thème choisi. */
body[data-theme="dark"] { color-scheme: dark; }
body[data-theme="light"] { color-scheme: light; }

*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.5 var(--sans);
}

h1, h2, h3, p, figure { margin: 0; }
h1 { font-size: clamp(2rem, 5vw, 2.6rem); line-height: 1.15; letter-spacing: -0.045em; }
h2 { font-size: 1.08rem; line-height: 1.3; letter-spacing: -0.01em; }
h3 { font-size: 0.95rem; line-height: 1.3; }
a { color: inherit; }
[hidden] { display: none !important; }

.muted { color: var(--muted); }
.faint { color: var(--faint); }
.num { font-variant-numeric: tabular-nums; }
.icon { flex: none; }
.nowrap { white-space: nowrap; }

:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; border-radius: 6px; }

.skip { position: absolute; left: -999px; }
.skip:focus { left: 12px; top: 12px; z-index: 2000; background: var(--surface); padding: 8px 12px; }

/* --- En-tête ------------------------------------------------------------ */

.topbar { background: transparent; border-bottom: 1px solid transparent; }
.topbar__inner {
  max-width: 1160px;
  margin: 0 auto;
  padding: 10px 20px;
  display: flex;
  align-items: center;
  gap: 8px 20px;
  flex-wrap: wrap;
}
.topbar__actions { margin-left: auto; display: flex; gap: 8px; }
.topbar form { margin: 0; }

.brand { display: inline-flex; align-items: center; gap: 9px; font-weight: 700; text-decoration: none; letter-spacing: -0.02em; font-size: 1.05rem; }
.brand__mark {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 11px;
  background: var(--primary);
  color: var(--primary-text);
}

.nav { display: flex; gap: 2px; margin-right: auto; flex-wrap: wrap; }

/* Sur un téléphone, le site se parcourt comme les applications : les cinq mêmes onglets au pied de l'écran, à portée
   de pouce (`tab_link`). Le bandeau, qui passait sur trois lignes, n'y garde que le nom du site ; « Compte » mène
   aux autres rubriques et à la déconnexion. `--foot` dit à ce qui se colle en bas la place que la barre occupe. */
:root { --foot: 0px; }
.tabbar { display: none; }
@media (max-width: 640px) {
  .topbar .nav, .topbar__inner > form { display: none; }
  body:has(> .tabbar) { --foot: calc(59px + env(safe-area-inset-bottom)); }
  body:has(> .tabbar) .container { padding-bottom: calc(var(--foot) + 28px); }
  .tabbar { position: fixed; inset: auto 0 0; z-index: 900; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); padding: 4px 6px calc(4px + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); background: var(--surface); }
  .tabbar__link { display: grid; justify-items: center; align-content: center; gap: 3px; min-height: 50px; border-radius: 10px; color: var(--muted); font-size: 0.7rem; font-weight: 550; text-decoration: none; -webkit-tap-highlight-color: transparent; }
  .tabbar__link:active { background: var(--surface-2); }
  .tabbar__link.is-current { color: var(--accent); font-weight: 700; }
  .tabbar__link.is-current .icon { stroke-width: 2.5; }
  .is-riding .tabbar { display: none; } /* une séance en plein écran prend toute la fenêtre */
}
.nav__link { padding: 6px 11px; border-radius: 7px; text-decoration: none; color: var(--muted); font-weight: 500; }
.nav__link:hover, .nav__link.is-current { color: var(--accent); background: var(--accent-soft); }

/* Dans l'application (dossier `ios/`) : la barre de navigation porte le titre, la page commence plus haut. */
.is-native .container { padding-top: 16px; }
.is-native h1.is-titled, .is-native .crumb { display: none; } /* le retour est le bouton de la barre */
/* Un bouton que la barre de navigation de l'application a repris (`bar`) ne se montre plus dans la page. */
.is-native [data-bar], .is-native form:has(> [data-bar]) { display: none; }

/* La page « Compte » y donne en liste les rubriques que le bandeau propose sur le site. */
.menu { display: grid; overflow: hidden; }
.menu__item { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; text-decoration: none; font-weight: 500; }
.menu__item + .menu__item { border-top: 1px solid var(--line); }
.menu__item:hover { background: var(--surface-2); }
.menu__item::after { content: "›"; color: var(--faint); font-size: 1.2rem; line-height: 1; }
/* Une rubrique : son pictogramme, ce qu'elle est, ce qu'elle vaut (un nombre, un choix), et le chevron. */
.menu__icon { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 10px; background: var(--accent-soft); color: var(--accent); flex: none; }
.menu__item:hover .menu__icon { background: var(--surface); }
.menu__text { flex: 1; display: grid; gap: 2px; min-width: 0; }
.menu__hint { color: var(--muted); font-size: 0.88rem; font-weight: 400; }
.menu__value { color: var(--muted); font-size: 0.92rem; font-weight: 400; white-space: nowrap; }
/* Qui est connecté : la pastille du coureur, son nom. */
.menu__item--me { padding-top: 16px; padding-bottom: 16px; gap: 14px; }
.menu__item--me .profile__face { width: 48px; height: 48px; font-size: 1.1rem; }
.menu__item--me strong { font-size: 1.1rem; letter-spacing: -0.01em; overflow-wrap: anywhere; }
@media (max-width: 640px) { .signout { width: 100%; } }
/* Un réglage sur une ligne : ce qu'il vaut, et de quoi le changer, replié dessous. */
.setting + .setting { border-top: 1px solid var(--line); }
/* Une liste de réglages dont certains sont dans un cadre Turbo (le profil) : le filet se met entre ses lignes, cadre ou non. */
.settings > turbo-frame { display: block; }
.settings > * + * { border-top: 1px solid var(--line); }
/* Une ligne sans rien à déplier (un bouton suffit) garde son bouton en face du texte, comme les autres. */
.settings .setting__row { flex-wrap: nowrap; }
.settings .setting__row .setting__what { flex: 1; }
.settings .setting__row > .btn, .settings .setting__row > form { flex: none; }
.setting__value .chip { color: var(--text); }
.setting > summary, .setting__row { display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; padding: 14px 20px; }
.setting > summary { list-style: none; cursor: pointer; }
.setting > summary::-webkit-details-marker { display: none; }
.setting__row { flex-wrap: wrap; }
.setting__row form { margin: 0; }
.setting__what { display: grid; gap: 2px; min-width: 0; flex: 1 1 260px; }
.setting > summary .setting__what { flex: 1; }
.setting__value { color: var(--muted); font-size: 0.92rem; overflow-wrap: anywhere; }
.setting[open] .setting__edit, .setting:not([open]) .setting__close { display: none; }
.setting__body { padding: 4px 20px 18px; }
/* Sous un formulaire replié, ce qui en tient lieu quand on ne peut pas le remplir (le mot de passe oublié). */
.setting__aside { display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; flex-wrap: wrap; padding-top: 14px; border-top: 1px solid var(--line); }
.setting__aside form { margin: 0; }
@media (max-width: 640px) { .setting .input { font-size: 16px; } } /* en deçà, iOS grossit la page au toucher */

/* --- Page ---------------------------------------------------------------- */

.container { width: 100%; max-width: 1160px; margin: 0 auto; padding: 28px 20px 56px; flex: 1; }
.container.narrow { max-width: 460px; }
.container.entry { max-width: 940px; } /* la porte d'entrée : connexion, inscription (`.auth`) */
.container.medium { max-width: 720px; }

.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 14px 20px; flex-wrap: wrap; margin-bottom: 22px; }
.page-head p { margin-top: 4px; }
.page-head__actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.page-head__actions form { margin: 0; }
/* La tête d'une activité : son nom, et sur la même ligne, à droite, l'œil qui dit si elle se montre au fil des groupes ;
   dessous, ce qu'elle est, et ce que l'on en fait. */
.activity-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 6px 20px; }
.activity-head__title { grid-column: 1; grid-row: 1; }
.activity-head__eye { grid-column: 2; grid-row: 1; align-self: center; justify-self: end; }
.activity-head__eye form { margin: 0; }
.activity-head__about { grid-column: 1; grid-row: 2; }
.activity-head > .page-head__actions { grid-column: 2; grid-row: 2; justify-content: flex-end; }
.feed-eye { display: inline-grid; place-items: center; width: 40px; height: 40px; color: var(--accent); }
.feed-eye.is-off { color: var(--faint); }
@media (max-width: 640px) {
  .activity-head > .page-head__actions { grid-column: 1 / -1; grid-row: 3; justify-content: flex-start; }
}

.crumb { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); text-decoration: none; font-size: 0.9rem; margin-bottom: 10px; }
.crumb:hover { color: var(--text); }
/* Le retour à l'écran « Compte » : sur un téléphone seulement, où le bandeau ne montre plus les rubriques. */
.crumb--narrow { display: none; }
@media (max-width: 640px) { .crumb--narrow { display: inline-flex; } }

.stack { display: grid; gap: 16px; grid-template-columns: minmax(0, 1fr); }
.stack--lg { gap: 24px; }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.section-title { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }

.flash { display: flex; gap: 8px; align-items: flex-start; padding: 10px 14px; border-radius: var(--radius); margin-bottom: 18px; }
.flash .icon { margin-top: 3px; }
.flash--notice { background: var(--ok-soft); color: var(--text); }
.flash--notice .icon { color: var(--ok); }
.flash--alert { background: var(--danger-soft); color: var(--text); border-left: 3px solid var(--danger); }
/* Dans une carte qui vient de se recharger seule : le message de l'action, au-dessus de ce qu'elle a changé. */
.card__body > .flash { margin-bottom: 14px; }
.stack > .flash, .card__note > .flash { margin-bottom: 0; } /* `.card__note` : un corps de carte fait de ce seul message */
/* Le temps qu'une carte se recharge (une carte dans son cadre ; pas un cadre qui se charge à l'ouverture). */
turbo-frame[busy] > .card { opacity: 0.6; }

/* --- Boutons ------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 8px 14px;
  border: 1px solid var(--line-strong);
  border-radius: 9px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-weight: 550;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover { background: var(--surface-2); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn--primary { background: var(--primary); border-color: var(--primary); color: var(--primary-text); }
.btn--primary:hover { background: var(--primary); opacity: 0.88; }
.btn--quiet { border-color: transparent; background: transparent; color: var(--muted); }
.btn--quiet:hover { color: var(--text); }
.btn--danger { color: var(--danger); }
.btn--small { padding: 5px 10px; font-size: 0.9rem; }
.btn--wide { width: 100%; }
.btn--icon { padding: 8px; }

/* --- Cartes, formulaires ------------------------------------------------- */

.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.card--pad { padding: 18px 20px; }
.card__head { padding: 14px 20px; border-bottom: 1px solid var(--line); display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.card__body { padding: 16px 20px; }
/* Le pied d'une carte : ce qui suit sa liste, sous un filet (une remarque, de quoi y ajouter). */
.card__foot { margin: 0; padding: 12px 20px; border-top: 1px solid var(--line); }
.card__foot .feed__row { padding: 7px 0; align-items: center; }
.card__foot .feed__row form { margin: 0; flex: none; }
.card__foot > p { margin-top: 8px; }

.field { display: grid; gap: 5px; }
fieldset.field { border: 0; padding: 0; margin: 0; min-width: 0; }
fieldset.field legend { padding: 0; margin-bottom: 6px; }
.field__label { font-weight: 550; font-size: 0.92rem; }
.field__hint { color: var(--muted); font-size: 0.88rem; }
.field__error { color: var(--danger); font-size: 0.88rem; }
.fields { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

.input, .select {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--line-strong);
  border-radius: 9px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
}
.select { appearance: none; padding-right: 30px; background-image: linear-gradient(45deg, transparent 50%, var(--faint) 50%), linear-gradient(135deg, var(--faint) 50%, transparent 50%); background-position: calc(100% - 15px) 50%, calc(100% - 10px) 50%; background-size: 5px 5px; background-repeat: no-repeat; }
.input:focus-visible, .select:focus-visible { outline-offset: 0; }
/* Un choix parmi des cases à cocher (la qualité des vues, dans les réglages d'affichage) : à leur taille. */
.select--small { width: auto; padding: 3px 28px 3px 9px; font-size: 0.9rem; }

.copy { display: flex; gap: 8px; }
.copy .input { font-variant-numeric: tabular-nums; min-width: 0; }
/* Un lien à copier ou à partager : sur un téléphone, le lien sur une ligne, ses deux boutons dessous. */
@media (max-width: 640px) {
  .copy--share { flex-wrap: wrap; }
  .copy--share .input { flex: 1 1 100%; }
  .copy--share .btn { flex: 1; }
}
/* Sur la page d'un segment, ce qui tient au home trainer (ou au tapis) : un filet l'écarte de la route, un titre
   l'annonce, et les mêmes cartes que plus haut y suivent, chacune le disant dans son titre. */
.indoor { padding-top: 24px; border-top: 1px solid var(--line-strong); }
.indoor__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px 20px; flex-wrap: wrap; }
.indoor__head > div { flex: 1; min-width: min(100%, 320px); display: grid; gap: 4px; }
.indoor__head h2 { font-size: 1.25rem; }
/* Un coureur face à ses propres temps : une ligne par coureur, ses comparaisons toutes prêtes. */
.versus { border-top: 1px solid var(--line); display: grid; gap: 4px; }
.versus__list { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 8px; }
.versus__row { display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; }
.versus__actions { display: inline-flex; gap: 6px; flex-wrap: wrap; }
/* Le choix de l'espace (un groupe, ou les segments personnels) où vont les segments créés d'un clic. */
.space-switch { display: flex; align-items: center; gap: 8px 10px; flex-wrap: wrap; margin: 0 0 14px; color: var(--muted); font-size: 0.92rem; }
.space-switch .select { width: auto; padding-top: 5px; padding-bottom: 5px; }
.card__head .space-switch { margin: 8px 0 0; }
.space-tabs { margin-bottom: 16px; }
.chips { display: flex; gap: 4px 12px; flex-wrap: wrap; }
.share { display: grid; gap: 10px; }
.share__bar { display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap; }
.share__bar .copy { flex: 1; min-width: min(100%, 280px); }
.share__bar form { margin: 0; }
.share__title { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.share__cell { min-width: 260px; }
.share__watch { display: flex; align-items: center; gap: 8px 12px; flex-wrap: wrap; margin: 0; }

/* Connexion et inscription : la porte d'entrée du site. Le formulaire, et ce que Sillage fait (`.auth__pitch`) :
   dessous sur un téléphone, où qui revient se connecte d'abord ; à gauche du formulaire sur un écran large. */
.auth { display: grid; gap: 32px 64px; align-items: start; }
.auth__form { width: 100%; max-width: 420px; margin: 0 auto; }
.auth__brand { display: flex; justify-content: center; margin: 4px 0 8px; font-size: 1.2rem; }
.auth__pitch { display: grid; gap: 10px; justify-items: center; text-align: center; width: 100%; max-width: 420px; margin: 0 auto; padding-top: 28px; border-top: 1px solid var(--line); }
.auth__tagline { font-size: 1.3rem; letter-spacing: -0.02em; text-wrap: balance; }
.auth__points { list-style: none; margin: 8px 0 4px; padding: 0; display: grid; gap: 10px; text-align: left; }
.auth__points li { display: flex; align-items: center; gap: 12px; }
.auth__note { font-size: 0.9rem; }
@media (min-width: 900px) {
  .auth { grid-template-columns: minmax(0, 1fr) minmax(0, 420px); padding-top: 32px; }
  .auth__form { margin: 0; }
  .auth__pitch { order: -1; justify-items: start; text-align: left; max-width: 440px; margin: 0; padding-top: 14px; border-top: 0; }
  .auth__pitch .welcome__art { max-width: 380px; margin-bottom: 10px; }
  .auth__tagline { font-size: 1.6rem; }
}
/* Un mot de passe que l'on peut montrer : le bouton est posé dans le champ, à droite. */
.peek { position: relative; }
.peek .input { padding-right: 88px; }
.peek__button { position: absolute; top: 50%; right: 5px; transform: translateY(-50%); padding: 5px 9px; border: 0; border-radius: 7px; background: transparent; color: var(--muted); font: inherit; font-size: 0.88rem; font-weight: 550; cursor: pointer; }
.peek__button:hover { color: var(--text); background: var(--surface-2); }
@media (max-width: 640px) { .auth .input { font-size: 16px; } } /* en deçà, iOS grossit la page au toucher */
.auth-head { text-align: center; margin: 12px 0 22px; }
.auth-head p { color: var(--muted); margin-top: 6px; }
.auth-links { text-align: center; margin-top: 16px; color: var(--muted); }
/* Le choix de la langue, sous un formulaire d'entrée ou au pied d'une course partagée : deux mots, celui en vigueur
   en gras. */
.languages { display: flex; align-items: center; justify-content: center; gap: 4px; margin-top: 16px; color: var(--muted); font-size: 0.88rem; }
.languages__choice { padding: 6px 8px; border: 0; border-radius: 6px; background: none; color: inherit; font: inherit; cursor: pointer; }
.languages__choice:hover { color: var(--text); background: var(--surface-2); }
.languages__choice[aria-pressed="true"] { color: var(--text); font-weight: 600; }
.fine-print__links { margin-top: 4px; text-align: center; color: var(--muted); font-size: 0.82rem; }
.fine-print__links a { color: inherit; }
/* Les pages légales : des listes à puces aérées, et les coordonnées en regard de leur intitulé. */
.legal__points { display: grid; gap: 8px; padding-left: 1.2em; }
.legal__facts { display: grid; gap: 10px; margin: 0; }
.legal__facts > div { display: grid; grid-template-columns: minmax(9rem, 14rem) 1fr; gap: 12px; }
.legal__facts dt { color: var(--muted); }
.legal__facts dd { margin: 0; }
@media (max-width: 640px) { .legal__facts > div { grid-template-columns: 1fr; gap: 2px; } }
/* « ou », entre le bouton Google et le formulaire : un mot entre deux filets. */
.auth-or { display: flex; align-items: center; gap: 12px; margin: 14px 0; color: var(--muted); font-size: 0.88rem; }
.auth-or::before, .auth-or::after { content: ""; flex: 1; border-top: 1px solid var(--line); }

/* --- Pastilles, vignettes -------------------------------------------------- */

.dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; flex: none; background: var(--faint); }
.chip { display: inline-flex; align-items: center; gap: 7px; font-weight: 550; }
.badge { display: inline-block; padding: 1px 8px; border-radius: 999px; background: var(--surface-2); color: var(--muted); font-size: 0.8rem; font-weight: 550; white-space: nowrap; }

.dot--1, .lane--1 { background: var(--athlete-1); color: var(--athlete-1-ink); }
.dot--2, .lane--2 { background: var(--athlete-2); color: var(--athlete-2-ink); }
.dot--3, .lane--3 { background: var(--athlete-3); color: var(--athlete-3-ink); }
.dot--4, .lane--4 { background: var(--athlete-4); color: var(--athlete-4-ink); }
.dot--5, .lane--5 { background: var(--athlete-5); color: var(--athlete-5-ink); }
.dot--6, .lane--6 { background: var(--athlete-6); color: var(--athlete-6-ink); }
.dot--7, .lane--7 { background: var(--athlete-7); color: var(--athlete-7-ink); }
.dot--8, .lane--8 { background: var(--athlete-8); color: var(--athlete-8-ink); }

.ink--1 { color: var(--athlete-1); } .ink--2 { color: var(--athlete-2); } .ink--3 { color: var(--athlete-3); }
.ink--4 { color: var(--athlete-4); } .ink--5 { color: var(--athlete-5); } .ink--6 { color: var(--athlete-6); }
.ink--7 { color: var(--athlete-7); } .ink--8 { color: var(--athlete-8); }

/* Numéro de couloir : la couleur ne porte jamais seule l'identité d'un coureur. */
.lane { display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 6px; border-radius: 11px; font-size: 0.76rem; font-weight: 700; flex: none; font-variant-numeric: tabular-nums; }

.shape { display: block; flex: none; }
.shape__line { fill: none; stroke: var(--text); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.shape__start { fill: var(--surface); stroke: var(--text); stroke-width: 2; }

/* --- Listes -------------------------------------------------------------- */

/* `min(100%, …)` : sur un écran de moins de 360 px, une colonne de 320 px dépassait, et toute la page défilait de côté. */
.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); }

.grid--wide { grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr)); }

/* Un segment proposé : sa carte, ce qu'il mesure, qui l'a parcouru, et de quoi le créer. */
.proposal { overflow: hidden; display: flex; flex-direction: column; }
.proposal .map { border: 0; border-bottom: 1px solid var(--line); border-radius: 0; }
.proposal__body { padding: 14px 16px 14px; display: grid; gap: 8px; align-content: start; flex: 1; }
.proposal__name { font-size: 1.05rem; letter-spacing: -0.01em; }
.proposal .facts { margin: 0; }
.proposal__who { font-size: 0.9rem; }
.proposal__who .sport { display: inline-flex; vertical-align: middle; }
/* Le nom proposé convient le plus souvent : de quoi en choisir un autre est replié. */
.proposal__form { display: grid; gap: 5px; width: 100%; }
.proposal__form details.more { margin-top: 0; }
.proposal__form details.more[open] { display: grid; gap: 5px; }
.proposal__actions { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 2px; }
.proposal__actions form { margin: 0; }
/* À la place d'une proposition créée ou écartée : ce qui vient de se passer, en deux lignes. */
.proposal--done { flex-direction: row; align-items: center; justify-content: space-between; gap: 10px 14px; flex-wrap: wrap; padding: 14px 16px; background: var(--surface-2); box-shadow: none; }
.proposal__done { display: flex; align-items: flex-start; gap: 8px; min-width: 0; flex: 1 1 220px; }
.proposal__done .icon { margin-top: 3px; color: var(--ok); flex: none; }
.proposal--done .proposal__actions { margin-top: 0; padding-top: 0; }
/* Chaque proposition est dans son cadre : c'est lui la case de la grille, et la carte en prend la hauteur. */
.grid > turbo-frame { display: grid; min-width: 0; }
/* La recherche en cours : la page est là, la liste arrive. */
.searching progress { width: min(240px, 100%); height: 6px; accent-color: var(--primary); }
turbo-frame[busy] > .card.searching { opacity: 1; }
@media (max-width: 640px) {
  /* Sur un téléphone, neuf cartes se suivent : la carte de chacune est plus basse, et sans boutons de zoom
     (deux doigts suffisent). */
  .proposal .map--small { height: 160px; }
  .proposal .leaflet-control-zoom { display: none; }
}
.count { display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px; background: var(--primary); color: var(--primary-text); font-size: 0.78rem; font-weight: 700; font-variant-numeric: tabular-nums; }

/* Une carte de liste (un segment, un segment à rouler) : la forme du parcours sur sa vignette, le nom, ses chiffres
   clés sous leur intitulé (`facts`), puis qui est passé. La carte entière se touche ; le chevron le dit. */
.seg { display: flex; gap: 14px; align-items: center; padding: 14px 16px; text-decoration: none; -webkit-tap-highlight-color: transparent; }
.seg:hover { border-color: var(--line-strong); }
.seg:active { background: var(--surface-2); }
.seg__shape { flex: none; align-self: flex-start; display: grid; place-items: center; width: 72px; height: 72px; border-radius: 10px; background: var(--surface-2); }
.seg__body { flex: 1; min-width: 0; display: grid; gap: 3px; }
.seg__name { font-weight: 650; line-height: 1.3; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
.seg__meta { color: var(--muted); font-size: 0.88rem; }
.seg__foot { display: flex; align-items: center; gap: 6px 10px; flex-wrap: wrap; color: var(--muted); font-size: 0.86rem; }
.seg__foot .bubbles { margin-top: 0; }
.seg__go { color: var(--faint); }
/* Où l'on en est soi-même sur le segment. */
.seg__you { color: var(--muted); font-size: 0.86rem; }
.seg__you strong { color: var(--text); font-weight: 600; }
/* Les derniers passages, à côté d'une liste : qui, où, en combien, quand. */
.feed__who { display: grid; gap: 1px; min-width: 0; }
.feed__who .chip { font-weight: 600; }
.feed__who .badge { margin-left: 4px; }
.feed__where { color: var(--muted); font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feed__row .feed__where a { font-weight: 400; color: inherit; }
/* Le profil d'un segment en silhouette (« Rouler ») : la ligne de crête sur son aplat. */
.relief { display: block; flex: none; }
.relief__area { fill: var(--line-strong); opacity: 0.55; }
.relief__line { fill: none; stroke: var(--text); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
/* Le segment de la dernière séance, en tête de « Rouler » : toute la largeur, son profil en grand, et le bouton
   que l'on vient chercher. */
.seg--lead { grid-column: 1 / -1; border-color: var(--line-strong); }
.seg--lead .seg__shape { width: 216px; height: 116px; }
.seg--lead .seg__shape .relief { width: 100%; height: 100%; }
.seg--lead .seg__body { gap: 5px; }
.seg--lead .seg__name { font-size: 1.15rem; }
.seg--lead .facts { max-width: 420px; }
.seg--lead .seg__cta { padding: 8px 18px; font-size: 0.95rem; }
/* Une liste et ce qui l'accompagne (« Rouler » : les segments et les dernières séances ; « Segments » : la liste
   et les derniers passages), puis des explications : côte à côte sur un grand écran, à la suite sur un téléphone. */
.duo { display: grid; gap: 24px; }
.duo > * { min-width: 0; }
.duo__notes, .duo__notes .more { margin-top: 0; }
@media (min-width: 960px) {
  .duo--split { grid-template-columns: minmax(0, 1fr) 340px; grid-template-areas: "main side" "notes side"; align-items: start; }
  .duo--split .duo__main { grid-area: main; }
  .duo--split .duo__side { grid-area: side; }
  .duo--split .duo__notes { grid-area: notes; }
  /* La page d'un groupe : ce qu'il partage, et à côté les derniers passages puis les membres. Dans la page, les
     derniers passages viennent d'abord : c'est l'ordre d'un téléphone. */
  .duo--news { grid-template-columns: minmax(0, 1fr) 340px; grid-template-areas: "main news" "main side"; grid-template-rows: auto 1fr; align-items: start; }
  .duo--news > .duo__main { grid-area: main; }
  .duo--news > .duo__news { grid-area: news; }
  .duo--news > .duo__side { grid-area: side; }
}
/* Face à qui l'on roulera : leurs pastilles dans la phrase. */
.seg__rivals { display: flex; align-items: center; gap: 3px 7px; flex-wrap: wrap; }
.seg__rivals .bubbles { margin-top: 0; }
.seg__kicker { color: var(--muted); font-size: 0.78rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
/* La carte d'un col (« Les grands cols ») : son profil comme celui d'une étape, sur toute la largeur, kilomètre par
   kilomètre à la couleur de la pente (les classes `.grade--*`, ici en aplat de dessin), un filet entre deux
   kilomètres, la pente écrite sous chacun et l'altitude au-dessus du sommet ; sa catégorie en picto, dans le ciel du
   profil, à gauche, où la montée n'est pas encore haute. */
.seg--col { flex-direction: column; align-items: stretch; gap: 10px; }
.seg--col .seg__shape { position: relative; width: 100%; height: auto; padding: 6px 6px 2px; }
.col-profile { display: block; width: 100%; }
.col-profile__pc { fill: var(--muted); font-size: 11px; font-weight: 600; text-anchor: middle; font-variant-numeric: tabular-nums; }
.col-profile__top { fill: var(--text); font-size: 12px; font-weight: 700; text-anchor: end; font-variant-numeric: tabular-nums; }
.col-profile__km { stroke: var(--surface-2); stroke-width: 1; vector-effect: non-scaling-stroke; }
.col-profile__line { fill: none; stroke: var(--text); stroke-width: 1.5; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.cat-picto { display: block; flex: none; }
/* Le pays d'un col : un code, les mêmes couleurs dans les deux thèmes, le blanc tenu par un filet. */
.country-flag { display: inline-block; vertical-align: -1px; border-radius: 1px; box-shadow: 0 0 0 1px var(--line); }
.country-flag rect:nth-of-type(2) { fill: #fff; }
.country-flag--fr rect:nth-of-type(1) { fill: #0055a4; }
.country-flag--fr rect:nth-of-type(3) { fill: #ef4135; }
.country-flag--it rect:nth-of-type(1) { fill: #008c45; }
.country-flag--it rect:nth-of-type(3) { fill: #cd212a; }
.country-flag--be rect:nth-of-type(1) { fill: #000; }
.country-flag--be rect:nth-of-type(2) { fill: #fdda24; }
.country-flag--be rect:nth-of-type(3) { fill: #ef3340; }
.seg--col .cat-picto { position: absolute; top: 8px; left: 10px; }
.cat-picto__peak { fill: var(--text); }
.cat-picto__mark { fill: var(--surface); font-size: 9px; font-weight: 800; text-anchor: middle; }
@media (max-width: 640px) {
  /* Sur un téléphone : le profil sur toute la largeur de la carte, puis le reste dessous. */
  .seg--lead { flex-direction: column; align-items: stretch; }
  .seg--lead .seg__shape { width: 100%; height: 76px; }
  .seg--lead .seg__cta { flex: 1 1 100%; justify-content: center; margin-left: 0; padding: 10px 18px; }
}
.seg__cta { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; padding: 5px 12px; border-radius: 999px; background: var(--primary); color: var(--primary-text); font-size: 0.88rem; font-weight: 600; }
.facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px 12px; margin: 4px 0 3px; }
.fact { display: grid; min-width: 0; }
.fact dt { color: var(--muted); font-size: 0.74rem; }
.fact dd { margin: 0; font-weight: 600; white-space: nowrap; }
/* Dans la carte d'un segment, étroite sur un petit écran : un chiffre plus large que sa colonne la déborde, et le
   dernier passe à la ligne, plutôt que de se chevaucher. Sinon, les mêmes trois colonnes d'une carte à l'autre. */
.duo__main .seg .facts { display: flex; flex-wrap: wrap; }
.duo__main .seg .fact { flex: 1 1 0; min-width: max-content; max-width: calc((100% - 24px) / 3); }
/* La liste des segments : liste ou carte, et dans quel ordre. Sur un téléphone, sur une même ligne. */
.list-tools { display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; flex-wrap: wrap; margin-bottom: 14px; }
.list-tools .tabs { margin: 0; }
.list-tools__sort { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 0.9rem; }
.list-tools__sort .select { width: auto; }
/* La carte des segments : un tracé par segment ; celui que l'on touche passe devant, sa bulle mène à sa page. */
.segments-map { margin-bottom: 18px; }
.segments-map__card { display: grid; gap: 3px; min-width: 160px; font: inherit; }
.segments-map__card a { margin-top: 4px; color: var(--text); font-weight: 600; }
/* La bulle prend les couleurs du thème : Leaflet la peint en blanc, où le texte du thème sombre ne se lirait pas. */
.segments-map .leaflet-popup-content-wrapper, .segments-map .leaflet-popup-tip { background: var(--surface); color: var(--text); }
/* Chercher dans la liste (contrôleur `search`). */
.search { display: flex; align-items: center; gap: 8px; max-width: 420px; margin-bottom: 14px; padding: 0 12px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--surface); color: var(--muted); }
.search:focus-within { outline: 2px solid var(--text); outline-offset: 1px; }
.search__input { flex: 1; min-width: 0; min-height: 40px; border: 0; background: transparent; color: var(--text); font: inherit; outline: none; }
@media (max-width: 640px) { .search { max-width: none; } .search__input { font-size: 16px; } } /* en deçà, iOS grossit la page au toucher */
/* Les bulles : qui est passé sur le segment. Une pastille par coureur, à sa couleur, avec ses initiales ; elles se
   chevauchent un peu, cernées de la couleur de la carte pour rester lisibles. */
.bubbles { display: flex; margin-top: 4px; padding-left: 4px; }
.bubble { display: inline-grid; place-items: center; width: 26px; height: 26px; margin-left: -4px; border-radius: 50%; box-shadow: 0 0 0 2px var(--surface); font-size: 0.68rem; font-weight: 700; letter-spacing: -0.01em; flex: none; }
/* Une photo à la place des initiales : cernée de la couleur du coureur, qui garde son identité. */
.bubble--photo { padding: 2px; overflow: hidden; }
.bubble--photo img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
.chip__photo { width: 18px; height: 18px; border-radius: 50%; object-fit: cover; padding: 2px; flex: none; }
.bubble--more { background: var(--surface-2); color: var(--muted); font-variant-numeric: tabular-nums; }
/* Passés sur home trainer (ou sur tapis) seulement : la bulle est creuse, un anneau à la couleur du coureur. La forme
   le dit, pas la couleur ; la ligne d'à côté et l'infobulle l'écrivent. */
.bubble--indoor { background: var(--surface); box-shadow: inset 0 0 0 2px currentColor, 0 0 0 2px var(--surface); }
.bubble--indoor > span { color: var(--text); }

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.stat { background: var(--surface); padding: 12px 16px; display: grid; gap: 2px; align-content: start; } /* une tuile sans note ne s'étire pas à la hauteur de sa voisine */
.stat__label { color: var(--muted); font-size: 0.82rem; }
.stat__value { font-size: 1.45rem; font-weight: 750; letter-spacing: -0.035em; line-height: 1.2; }
.stat__note { color: var(--muted); font-size: 0.82rem; }
/* Quatre chiffres : en ligne sur un écran large, deux par deux sur un écran étroit, jamais trois et un orphelin. */
.stats--quad { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 760px) { .stats--quad { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.stat__note a { color: inherit; }
/* Une tuile qui mène, dans la page, à ce qu'elle compte. */
a.stat { color: inherit; text-decoration: none; }
a.stat:hover .stat__label, a.stat:focus-visible .stat__label { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
/* Sur un téléphone, deux par ligne ; une dernière tuile seule prend toute la largeur, plutôt qu'une case vide. */
@media (max-width: 640px) {
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stats > .stat:last-child:nth-child(odd) { grid-column: 1 / -1; }
  /* Trois chiffres courts restent sur une ligne. */
  .stats--trio { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .stats--trio > .stat:last-child:nth-child(odd) { grid-column: auto; }
  .stats--trio .stat { padding: 10px 12px; }
}

/* Le tableau de bord. */
.dash-tabs { margin-bottom: 20px; }
/* Administration : les activités arrivées jour après jour. */
.daybars { display: block; width: 100%; }
.daybars__bar { fill: var(--text); }
.daybars__bar--none { fill: var(--line-strong); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.feed { list-style: none; margin: 0; padding: 0; }
.feed__row { display: flex; justify-content: space-between; gap: 14px; padding: 10px 20px; }
.feed__row + .feed__row { border-top: 1px solid var(--line); }
.feed__row a { text-decoration: none; font-weight: 550; }
.feed__row a:hover { text-decoration: underline; }
/* Une ligne qui dit quoi (`feed__what` : un nom, puis ce qu'il faut en savoir) et porte son geste à droite. */
.feed__what { display: grid; gap: 2px; min-width: 0; }
.feed__row:has(> .feed__what) { align-items: center; }
.feed__value { text-align: right; white-space: nowrap; }
.spark { display: block; }
.spark__line { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.spark__end { fill: currentColor; stroke: var(--surface); stroke-width: 2; }
/* Le calendrier de la régularité : une case par jour, d'autant plus pleine que la journée a été longue. */
.heat { display: block; width: 100%; max-width: 440px; height: auto; }
.heat__day { fill: currentColor; }
.heat__day--0 { fill: var(--surface-2); }
.heat__day--1 { opacity: 0.3; }
.heat__day--2 { opacity: 0.55; }
.heat__day--3 { opacity: 0.8; }
.heat__month { fill: var(--muted); font-size: 9px; }
.heat__key { font-size: 0.86rem; }
.stats--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.gauge { display: block; }
.gauge__track { fill: var(--surface-2); }
.gauge__fill { fill: currentColor; }
.radar-wrap { margin: 0; padding: 8px 16px 16px; display: grid; justify-items: center; gap: 4px; }
.radar { width: 100%; max-width: 340px; height: auto; overflow: visible; }
.radar__ring { fill: none; stroke: var(--line); stroke-width: 1; }
.radar__axis { stroke: var(--line); stroke-width: 1; }
.radar__label { fill: var(--text); font-size: 11px; font-weight: 600; }
.radar__value { fill: var(--muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.radar__disc { fill: var(--surface-2); stroke: none; }
.radar__shape { fill: currentColor; fill-opacity: .22; stroke: currentColor; stroke-width: 2.5; stroke-linejoin: round; }
.radar__reference { fill: none; stroke: var(--muted); stroke-width: 1.5; stroke-dasharray: 4 3; stroke-linejoin: round; }
.radar__legend { display: inline-flex; align-items: center; gap: 6px; margin: 0 8px; color: var(--text); }
.radar__swatch { width: 18px; height: 0; border-top: 3px solid currentColor; }
.radar__swatch--reference { border-top: 2px dashed var(--muted); }
.card__filters { padding: 14px 20px 0; margin-bottom: 0; }
.radar__dot { fill: currentColor; stroke: var(--surface); stroke-width: 1.5; }
.radar-wrap figcaption { font-size: .85rem; text-align: center; max-width: 46ch; }
.chart-wrap { margin: 0; padding: 8px 16px 16px; display: grid; gap: 6px; }
.chart-wrap figcaption { font-size: .85rem; }
/* L'objectif, en tête de l'onglet Potentiel : ce qu'il est, l'estimation du jour, et sa progression (`goal_trajectory`,
   `goal_long_rides`). Plus haut, plus rapide ; les temps sont écrits sur l'axe et dans l'étiquette du dessin. */
.goal__kicker { margin: 0 0 2px; color: var(--accent); font-size: 0.85rem; font-weight: 650; }
.goal__verdict { display: grid; gap: 4px; }
.goal__verdict p { margin: 0; }
.goal__today { margin: 0; font-size: 1.1rem; }
.goal__today strong { font-size: 1.55rem; font-weight: 750; letter-spacing: -0.025em; }
.goal__legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0; font-size: 0.85rem; }
.goal__key { display: inline-flex; align-items: center; gap: 6px; }
.goal__swatch { width: 18px; border-top: 2.5px solid currentColor; }
.goal__swatch--path { border-top: 2px dotted var(--muted); }
.goal__swatch--target { border-top: 2px dashed var(--text); }
.goal__course { display: grid; gap: 4px; }
.goal__course p { margin: 0; }
.goal__relief .relief { width: 100%; height: 72px; }
.trajectory, .long-rides { display: block; width: 100%; height: auto; overflow: visible; }
.trajectory__grid { stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 4; }
.trajectory__axis { stroke: var(--line); stroke-width: 1; }
.trajectory__tick { fill: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.trajectory__today { stroke: var(--line-strong); stroke-width: 1; }
.trajectory__target { stroke: var(--text); stroke-width: 1.5; stroke-dasharray: 6 4; }
.trajectory__path { stroke: var(--muted); stroke-width: 2; stroke-dasharray: 1 5; stroke-linecap: round; }
.trajectory__line { fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.trajectory__dot { fill: currentColor; stroke: var(--surface); stroke-width: 1.5; }
.long-rides__bar { fill: currentColor; fill-opacity: 0.8; }
.trajectory--narrow { display: none; }
@media (max-width: 640px) {
  .trajectory--wide { display: none; }
  .trajectory--narrow { display: block; }
}
.goal-form__custom .fields { margin-top: 10px; }
/* Les grandes courses du calendrier, une case chacune, visibles d'emblée ; la dernière case ouvre le menu des distances
   et des segments. La case cochée prend la teinte de l'accent. */
.goal-form__choice { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; min-width: 0; margin: 0; padding: 0; border: 0; }
.goal-form__choice legend { margin-bottom: 6px; padding: 0; }
.goal-form__group { margin: 0; font-size: 0.88rem; }
.race-picks { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr)); gap: 8px; }
.race-pick { display: grid; grid-template-columns: auto 1fr; align-items: center; column-gap: 10px; row-gap: 2px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); cursor: pointer; }
.race-pick input { grid-row: span 2; margin: 0; accent-color: var(--accent); }
.race-pick__name { font-weight: 650; line-height: 1.3; }
.race-pick__facts { font-size: 0.85rem; }
.race-pick:hover { border-color: var(--line-strong); }
.race-pick:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.race-pick:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.goal-form__other { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.goal-form__other .race-pick { grid-template-columns: auto auto; }
.goal-form__other .race-pick input { grid-row: auto; }
.goal-form__other .select { width: auto; min-width: 0; max-width: 100%; }
.goal-form__custom > p { margin: 8px 0 0; font-size: 0.88rem; }
.curve, .bars-h { width: 100%; height: auto; overflow: visible; }
.curve__grid { stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 4; }
.curve__axis { stroke: var(--line); stroke-width: 1; }
.curve__area { fill: currentColor; fill-opacity: .14; }
.curve__line { fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linejoin: round; }
.curve__dot { fill: currentColor; stroke: var(--surface); stroke-width: 1.5; }
.curve__value { fill: var(--text); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.curve__label { fill: var(--muted); font-size: 12px; }
.bars-h__name { fill: var(--text); font-size: 13px; font-weight: 600; }
.bars-h__note { fill: var(--muted); font-size: 11px; }
/* Puissance et cœur (onglet Progression) : un petit dessin par durée et un pour le cœur, côte à côte tant qu'il y a
   la place, l'un sous l'autre sur un téléphone. Survoler une période montre son trait et sa bulle. */
.pw-body { padding: 14px 20px 6px; display: grid; gap: 12px; }
.pw-verdict { margin: 0; font-weight: 550; max-width: 72ch; }
.pw-note { margin: 0; font-size: .85rem; max-width: 76ch; }
.pw-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px 24px; }
.pw { margin: 0; display: grid; gap: 4px; align-content: start; min-width: 0; }
.pw__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.pw__name { font-weight: 600; }
.pw__value { font-weight: 650; font-variant-numeric: tabular-nums; }
.pw__note { color: var(--muted); font-size: .85rem; }
.pw__chart { display: block; width: 100%; height: auto; overflow: visible; }
.pw__grid { stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 4; }
.pw__axis { fill: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.pw__line { fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.pw__dot { fill: currentColor; stroke: var(--surface); stroke-width: 1.5; }
.pw__dot--top { stroke-width: 2; }
.pw__label { fill: var(--text); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.pw__range { stroke: currentColor; stroke-opacity: .28; stroke-width: 6; stroke-linecap: round; }
.pw__band { fill: #000; fill-opacity: 0; }
.pw__rule { stroke: var(--muted); stroke-width: 1; stroke-dasharray: 2 3; }
.pw__tip, .pw__rule { visibility: hidden; pointer-events: none; }
.pw__hit:hover .pw__tip, .pw__hit:hover .pw__rule { visibility: visible; }
.pw__box { fill: var(--surface); stroke: var(--line); }
.pw__tip-when { fill: var(--muted); font-size: 11px; }
.pw__tip-what { fill: var(--text); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.pw__legend { font-size: .82rem; }
.pw__key { display: inline-block; flex: none; background: currentColor; }
.pw__key--mean { width: 9px; height: 9px; border-radius: 50%; }
.pw__key--range { width: 6px; height: 16px; border-radius: 3px; opacity: .28; }
/* Empilé, le cœur pendant l'effort passe sous ses watts, sans le point qui les sépare sur une ligne. */
@media (max-width: 700px) {
  .pw-table__bpm { display: block; }
  .pw-table__dot { display: none; }
}
.bars-h__value { fill: var(--text); font-size: 12px; font-variant-numeric: tabular-nums; }
/* La même jauge sur toute la largeur de son bloc (`meter`) : ce qui est fait d'une quantité prévue. */
svg.meter { display: block; width: 100%; height: 8px; border-radius: 4px; overflow: hidden; }
/* Une évolution précédée de sa flèche (`trend`). */
.trend { display: inline-flex; align-items: center; gap: 3px; }
/* « Cette semaine », en tête du résumé : ce qui est fait du volume prévu, puis les séances de la semaine. */
.thisweek__progress { display: grid; gap: 6px; }
.thisweek__done { font-size: 1.25rem; letter-spacing: -0.01em; }
.thisweek .sessions--compact .session:first-child { padding-top: 0; }
.thisweek .sessions--compact .session:last-child { padding-bottom: 0; }
/* La semaine jour par jour : sept colonnes, le jour, une pastille à la couleur du coureur quand il est sorti, la
   durée écrite dessous. Aujourd'hui en gras ; les jours à venir, en pointillé. */
.week-days { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; max-width: 520px; margin: 0; padding: 0; list-style: none; }
.week-days__day { display: grid; justify-items: center; gap: 5px; padding: 6px 2px; border-radius: 8px; text-align: center; }
.week-days__day.is-today { background: var(--surface-2); }
.week-days__day.is-today .week-days__name { color: var(--text); font-weight: 700; }
.week-days__name { color: var(--muted); font-size: 0.78rem; text-transform: capitalize; }
.week-days__day .dot { width: 14px; height: 14px; }
.week-days__none { background: none; box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.week-days__day.is-ahead .week-days__none { box-shadow: none; border: 1.5px dashed var(--line); }
.week-days__time { min-height: 1.2em; font-size: 0.8rem; font-weight: 600; white-space: nowrap; }
/* Les derniers records, de toutes sortes : ce qu'ils mesurent en petit au-dessus. */
.feats__kind { font-size: 0.74rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.key--target { background: var(--text); }
.callout { padding: 12px 16px; border-radius: var(--radius); background: var(--surface-2); border-left: 3px solid var(--line-strong); }
/* Ce qui demande un coup d'œil (l'administration) : le filet le dit, les mots aussi. */
.callout--warn { border-left-color: var(--danger); }
/* Les altitudes d'un segment, au pied de son profil : le doute, puis leur correction d'après le relief des cartes. */
.heights__doubt { margin-top: 14px; }
.heights__doubt p { margin: 0; }
.card--pad > .heights { margin: 16px -20px -18px; border-top: 1px solid var(--line); }
.callout .icon { vertical-align: -2px; margin-right: 4px; }
.outing__you { font-weight: 550; }
/* Les réglages de l'installation : le nom en petit, ce qu'il vaut, ce que cela change. */
.settings-list { margin: 0; }
.settings-list__item { padding: 12px 20px; display: grid; gap: 2px; }
.settings-list__item + .settings-list__item { border-top: 1px solid var(--line); }
.settings-list dt { color: var(--muted); font-size: 0.82rem; overflow-wrap: anywhere; }
.settings-list dd { margin: 0; }
.settings-list dd strong { font-weight: 600; }
/* Le champ de recherche d'une liste rangée dans une carte : sans marge sous lui, le tableau suit. */
.card__search { padding-bottom: 4px; }
.card__search .search { margin-bottom: 0; }
.sessions { list-style: none; margin: 0; padding: 0; counter-reset: session; }
.session { counter-increment: session; display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 2px 12px; padding: 12px 20px; }
.session + .session { border-top: 1px solid var(--line); }
.session::before { content: counter(session); grid-row: span 2; display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--surface-2); font-weight: 700; font-size: 0.82rem; }
.session--quality::before, .session--race::before { background: var(--primary); color: var(--primary-text); }
.session__title { font-weight: 650; }
.session__detail { grid-column: 2; color: var(--muted); font-size: 0.92rem; }
.sessions--compact .session { padding: 8px 0; }
.session__ride { grid-column: 2; justify-self: start; font-size: 0.9rem; }
/* Les défis de la semaine des groupes, en tête de la liste des segments : une tuile par groupe. */
.challenges { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; margin-bottom: 18px; }
.challenge-tile { display: grid; gap: 3px; padding: 12px 16px; color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent; }
.challenge h3 { margin-top: 6px; }
/* Le défi sur la page du groupe : les trois premiers, et soi-même plus loin ; le reste est sur la page du défi. */
.challenge__top { margin: 0; }
.challenge__top .feed__row { align-items: center; padding-block: 8px; }
.challenge__top .is-me { background: var(--surface-2); }
.challenge__rank { min-width: 1.4em; color: var(--muted); font-weight: 600; }
.challenge .card__foot { display: flex; justify-content: space-between; align-items: baseline; gap: 4px 14px; flex-wrap: wrap; }
.challenge .card__foot a { font-weight: 550; }
/* La page du défi : où l'on en est, les défis d'avant et qui les a gagnés. */
.challenge__you { font-weight: 550; }
.challenge__wins { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin-top: 4px; }
.challenge__missing { margin: 0 2px; font-size: 0.92rem; }
/* Le défi fermé jusqu'au lundi, et son édition du lundi (`challenges/_sealed`, `_edition`, `course`). */
.challenge__left { color: var(--text); }
.challenge__turn { margin-top: 6px; font-size: 1.08rem; }
.challenge__privacy { display: flex; gap: 8px; align-items: flex-start; margin: 0 2px; font-size: 0.92rem; }
.challenge__privacy .icon { margin-top: 3px; }
.challenge__poster { display: flex; justify-content: space-between; align-items: center; gap: 10px 16px; flex-wrap: wrap; }
.moments { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; }
.moments li { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.podium { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.podium__step { display: grid; gap: 4px; align-content: start; padding: 12px 14px; }
.podium__step.is-first { border-color: var(--line-strong); background: var(--surface-2); }
.podium__step.is-me { box-shadow: inset 0 0 0 2px var(--accent-line); }
.podium__rank { color: var(--muted); font-size: 0.82rem; font-weight: 600; }
.podium__time { font-size: 1.35rem; font-weight: 750; letter-spacing: -0.035em; line-height: 1.15; }
.podium .chip { min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 420px) { .podium { gap: 6px; } .podium__step { padding: 10px; } .podium__time { font-size: 1.15rem; } }
.card__fold { border-top: 1px solid var(--line); }
.card__fold > summary { padding: 12px 20px; }
.challenge__unveil .podium { margin-top: 2px; }
/* Le programme d'une entreprise : la carte du bureau et des segments à venir, puis leur liste. */
.programme__map { height: 260px; border: 0; border-radius: 0; border-bottom: 1px solid var(--line); }
.programme { margin: 0; }
.programme .is-current { background: var(--surface-2); }
.programme__no { display: inline-grid; place-items: center; min-width: 22px; height: 22px; border-radius: 11px; font-size: 0.76rem; font-weight: 700;
                 box-shadow: inset 0 0 0 1.5px var(--line-strong); font-variant-numeric: tabular-nums; flex: none; }
.programme__no--now { background: var(--text); color: var(--bg); box-shadow: none; }
.office__map { height: 280px; }
.kinds { border: 0; margin: 0; padding: 0; display: grid; gap: 8px; }
.kinds .toggle { align-items: flex-start; color: var(--text); }
.kinds .toggle .check { margin-top: 2px; }
.stats--duo { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Un duel (`duels/show`, `duels/_card`) : où l'on en est, les deux temps, le formulaire sous la liste des duels. */
.duel__you { font-weight: 550; }
.duel__sides .is-me { background: var(--surface-2); }
.duels__form { border-top: 1px solid var(--line); }
#defis .feed__row.is-current { background: var(--surface-2); }
#defis .feed__where a[aria-current] { text-decoration: none; }
/* La salle d'attente d'un rendez-vous en direct : qui vient, et s'il est prêt. */
.crew { list-style: none; margin: 10px 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 18px; }
.crew li { display: flex; align-items: center; gap: 8px; }
.crew__state { font-size: 0.88rem; }
/* Une séance guidée dans une liste (« Séances guidées ») : son dessin, son nom, ce qu'elle demande. */
.workout { display: flex; flex-direction: column; gap: 3px; padding: 14px 16px; color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent; }
/* Une séance de la bibliothèque et son étoile, posée dans le coin de la carte : un bouton ne se met pas dans un lien. */
.workout-cell { position: relative; display: grid; }
.workout__star { position: absolute; top: 6px; right: 6px; }
.workout__star form { margin: 0; }
.workout-cell .workout__art { margin-right: 36px; }
.star { display: grid; place-items: center; width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--muted); cursor: pointer; }
.star svg { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linejoin: round; }
.star:hover, .star:focus-visible { color: var(--accent); background: var(--accent-soft); }
.star.is-on { color: var(--accent); }
.star.is-on svg { fill: currentColor; }
.workout__art { display: block; height: 56px; margin-bottom: 8px; }
.workout-art { display: block; width: 100%; height: 100%; }
.power-zone--1 { --power-zone: var(--power-zone-1); fill: var(--power-zone); }
.power-zone--2 { --power-zone: var(--power-zone-2); fill: var(--power-zone); }
.power-zone--3 { --power-zone: var(--power-zone-3); fill: var(--power-zone); }
.power-zone--4 { --power-zone: var(--power-zone-4); fill: var(--power-zone); }
.power-zone--5 { --power-zone: var(--power-zone-5); fill: var(--power-zone); }
.power-zone--6 { --power-zone: var(--power-zone-6); fill: var(--power-zone); }
.power-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; padding: 0; margin: 12px 0; list-style: none; font-size: .75rem; color: var(--muted); }
.power-legend li { display: inline-flex; align-items: center; gap: 5px; }
.power-legend__swatch { width: 10px; height: 10px; flex: none; border-radius: 2px; background: var(--power-zone); }
.ridebar > .power-legend { margin: 0; padding: 0 16px 8px; }
.workout-art__ftp { stroke: var(--text); stroke-width: 1; stroke-dasharray: 3 3; vector-effect: non-scaling-stroke; }
.workout__name { font-weight: 650; }
.workout__summary { font-size: 0.92rem; }
.workout__tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
.workout-filters { display: grid; gap: 14px; margin: 14px 0 8px; padding: 16px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.workout-filters__main { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.workout-filters__extra { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-top: 12px; }
.workout-filters .field { min-width: 0; }
.workout-filters select { width: 100%; min-width: 0; }
.workout-filters .field__hint { margin: 0; }
.workout-results { margin: 16px 0 10px; font-weight: 600; }
.workout-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.workout-chips .filter { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
@media (max-width: 900px) {
  .workout-filters__main, .workout-filters__extra { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 540px) {
  .workout-filters__main, .workout-filters__extra { grid-template-columns: minmax(0, 1fr); }
}
/* Le seuil de l'entraînement, en une ligne : sa valeur, d'où elle vient, et le test qui la mesure. */
.threshold { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; }
.threshold__line { margin: 0; }
details.more.threshold__more { flex-basis: 100%; margin-top: 0; }
.workout .seg__cta { align-self: flex-start; margin: 8px 0 0; }
.week > summary { cursor: pointer; }
.week[open] > summary { margin-bottom: 4px; font-weight: 550; }
.plan tr.is-current td { background: var(--surface-2); }
/* Sur un téléphone, une semaine du plan tient en trois lignes : son numéro et sa phase, le prévu et le fait, puis
   ses séances à déplier. */
@media (max-width: 700px) {
  /* (`.table--stack.plan` : ces règles passent avant celles, plus bas, de tous les tableaux qui s'empilent.) */
  .table--stack.plan tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 3px 14px; }
  .table--stack.plan tr.is-current { background: var(--surface-2); }
  .table--stack.plan td.plan__week { grid-column: 1; }
  .table--stack.plan td.plan__phase { grid-column: 2; display: block; justify-self: end; color: var(--muted); font-weight: 400; }
  .table--stack.plan td.plan__phase::before { content: none; }
  .table--stack.plan td.plan__amount { display: block; font-weight: 400; }
  .table--stack.plan td.plan__amount::before { content: attr(data-label) " "; font-size: inherit; }
  .table--stack.plan td.plan__amount + td.plan__amount { justify-self: end; }
  .table--stack.plan td.plan__sessions { grid-column: 1 / -1; }
}
/* Sur un téléphone, un record tient en peu de lignes : ce qu'il mesure et sa valeur face à face, sa jauge dessous,
   puis quand et pendant quelle sortie, en petit. */
@media (max-width: 700px) {
  .table--stack.records tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 12px; }
  .table--stack.records td:first-child { grid-column: 1; }
  .table--stack.records td:nth-child(2) { grid-column: 2; grid-row: 1; display: block; font-size: 1.05rem; text-align: right; }
  .table--stack.records td:nth-child(2)::before { content: none; }
  .table--stack.records td:nth-child(n + 3) { grid-column: 1 / -1; }
  .table--stack.records td[data-label]:nth-child(n + 3) { display: block; color: var(--muted); font-size: 0.88rem; font-weight: 400; white-space: normal; }
  .table--stack.records td[data-label]:nth-child(n + 3)::before { content: attr(data-label) " "; font-size: inherit; }
}
/* Les membres d'un groupe : une ligne chacun (`.setting`), son nom, son rôle en étiquette, et en petit ce qu'il a
   fait sur les segments du groupe. Ce qu'un administrateur peut faire de lui est replié sous « Gérer ». */
.member > summary, .member .setting__row { padding: 11px 20px; }
.member .setting__what { flex: 1 1 160px; }
.member__name { display: flex; align-items: center; gap: 4px 6px; flex-wrap: wrap; }
.member .setting__value { font-size: 0.88rem; overflow-wrap: normal; }
.member .setting__body .muted { font-size: 0.88rem; }
.leave > p { font-size: 0.88rem; }
.leave form { margin: 10px 0 2px; }
/* Les comptes de l'administration, sur un téléphone : le compte, ses deux dates face à face, ses quatre chiffres
   sur une ligne, puis son lien avec intervals.icu. Toutes les fiches ont la même forme. */
@media (max-width: 700px) {
  .table--stack.accounts tr { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px 12px; }
  .table--stack.accounts td:nth-child(1), .table--stack.accounts td:nth-child(8) { grid-column: 1 / -1; }
  .table--stack.accounts td:nth-child(2) { grid-column: 1 / 3; grid-row: 2; }
  .table--stack.accounts td:nth-child(6) { grid-column: 3 / 5; grid-row: 2; }
  .table--stack.accounts td:nth-child(3), .table--stack.accounts td:nth-child(4),
  .table--stack.accounts td:nth-child(5), .table--stack.accounts td:nth-child(7) { grid-row: 3; }
  .table--stack.accounts td:nth-child(8) { grid-row: 4; }
}
/* Un tableau de trois colonnes courtes reste un tableau sur un téléphone : on y resserre les marges, et son
   intitulé peut passer à la ligne. */
@media (max-width: 640px) {
  .table--fit th, .table--fit td { padding: 9px 8px; }
  .table--fit th { white-space: normal; }
  .table--fit th:first-child, .table--fit td:first-child { padding-left: 16px; }
  .table--fit th:last-child, .table--fit td:last-child { padding-right: 16px; }
}

.table-wrap { overflow-x: auto; }
.table-wrap--ruled { border-top: 1px solid var(--line); }
.table { width: 100%; border-collapse: collapse; font-size: 0.93rem; }
.table th { text-align: left; font-weight: 550; color: var(--muted); font-size: 0.82rem; padding: 9px 12px; border-bottom: 1px solid var(--line); white-space: nowrap; }
.table td { padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.table th[scope="row"] { white-space: normal; } /* un intitulé de ligne peut passer à la ligne sur un écran étroit */
.table tr:last-child td, .table tbody tr:last-child th { border-bottom: 0; }
.table .right { text-align: right; }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.table a { text-decoration: none; font-weight: 550; }
.table a:hover { text-decoration: underline; }
.table__actions { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }
.table__actions form { margin: 0; }
/* Un tableau qui se lit en travers (un tronçon par ligne, une mesure par colonne) ne s'empile pas : quand il défile
   de côté, sa première colonne reste en place. */
.table--pinned th:first-child, .table--pinned td:first-child { position: sticky; left: 0; z-index: 1; background: var(--surface); }
@media (max-width: 640px) {
  .table--pinned th, .table--pinned td { padding: 8px; }
  .table--pinned th:first-child, .table--pinned td:first-child { padding-left: 12px; }
}
/* Un intertitre dans un tableau (le mois, dans la liste des activités), et ce que le mois pèse, en face. */
.table__group th { padding: 8px 12px; background: var(--surface-2); color: var(--muted); font-size: 0.82rem; font-weight: 600; }
.table__month { display: flex; justify-content: space-between; align-items: baseline; gap: 2px 14px; flex-wrap: wrap; }
.table__month > span:first-child { color: var(--text); }
.table__sum { font-weight: 400; }
/* Les repères de la liste des activités. */
.acts__name .badge { margin-left: 2px; }
.badge--line { background: none; box-shadow: inset 0 0 0 1px var(--line-strong); }
/* Le meilleur d'une sortie : ce qu'elle vaut, et le record du coureur en face. */
#records .card__head > div { flex: 1 1 280px; min-width: 0; } /* le texte se replie, le bouton reste à sa droite */
.feats td:nth-child(2) .muted { margin-left: 6px; font-weight: 400; font-size: 0.88rem; }
.feats td:last-child { color: var(--muted); }
.feats td:last-child a { color: inherit; font-weight: inherit; }
/* Les activités voisines, au pied d'une activité : la plus récente à gauche, la plus ancienne à droite. */
.neighbours { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.neighbour { display: grid; gap: 1px; padding: 12px 16px; text-decoration: none; min-width: 0; }
.neighbour:hover { border-color: var(--line-strong); }
.neighbour--next { text-align: right; }
.neighbour__way { color: var(--muted); font-size: 0.78rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.neighbour__way::before { content: "← "; }
.neighbour--next .neighbour__way::before { content: none; }
.neighbour--next .neighbour__way::after { content: " →"; }
.neighbour__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.neighbour .muted { font-size: 0.86rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 640px) {
  /* Sur un téléphone, l'une sous l'autre : leurs noms se lisent en entier. */
  .neighbours { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .neighbours > span:empty { display: none; }
  .neighbour--next { text-align: left; }
}
/* Le classement d'un segment : la ligne du coureur du compte se repère, et tous les passages sont repliés dessous. */
.ranks tr.is-me { background: var(--surface-2); }
.ranks__who .badge { margin-left: 4px; }
.ranks__time .badge { white-space: normal; } /* « record personnel » : plus large qu'une colonne sur un petit écran */
.passes { border-top: 1px solid var(--line); }
.passes > summary { padding: 12px 20px; cursor: pointer; color: var(--muted); font-weight: 550; }
.passes > summary:hover { color: var(--text); }
.passes[open] > summary { border-bottom: 1px solid var(--line); }
/* Le niveau d'un passage : une icône, et son nom caché. `position: relative` garde ce nom dans le tableau, qui défile de
   côté sur un téléphone : sinon, il élargirait toute la page. Le dessin dit le niveau, la couleur n'y ajoute qu'un accent. */
.level { position: relative; display: inline-flex; margin-left: 6px; color: var(--muted); vertical-align: -2px; }
.level--alien, .level--patron, .level--lieutenant { color: var(--primary); }
.level-value { display: inline-flex; align-items: center; gap: 6px; }
.levels { padding: 14px 20px 16px; }
.levels > p { margin: 0; font-size: 0.88rem; }
.levels__list { display: grid; gap: 8px; margin: 12px 0 0; padding: 0; list-style: none; }
.levels__row { display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; align-items: center; gap: 8px; }
.levels__row .level { margin-left: 0; }
.levels__name { font-weight: 550; }
/* Sur une tablette, un classement garde ses colonnes sans défiler de côté : ses intitulés, ses dates et ce qui suit un
   temps passent à la ligne, et ses marges se resserrent. */
@media (min-width: 701px) and (max-width: 1100px) {
  .ranks { font-size: 0.88rem; }
  .ranks th, .ranks td { padding-inline: 8px; }
  .ranks th, .ranks th.num, .ranks td.ranks__date, .ranks td.ranks__time { white-space: normal; }
}
.stat__note .chip { font-size: inherit; }
/* Avant une séance : face à qui l'on roule, et de quoi en décider autrement. */
.rivals > div { display: grid; gap: 4px; min-width: 0; }
.rivals__line { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; }
.rivals__label { font-weight: 600; }
.rivals__one { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.rivals__more, .rivals__best { font-size: 0.9rem; }
.rivals__best strong { color: var(--text); }
/* Les touches qui commandent la lecture, dites sous le lecteur. */
.transport__keys { font-size: 0.82rem; }
.transport__keys kbd { padding: 1px 5px; border: 1px solid var(--line-strong); border-radius: 5px; background: var(--surface-2); font: inherit; font-size: 0.78rem; white-space: nowrap; }
/* Le verdict d'une comparaison, sous son titre : qui devance qui, et de combien. */
.verdict { margin-top: 8px; line-height: 1.9; }
.verdict .chip { vertical-align: baseline; }
.verdict strong { font-weight: 650; }
/* Chercher dans ses activités : un nom, une année. */
.finder { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 0 0 12px; }
.finder .search { flex: 1 1 180px; min-width: 0; max-width: 420px; margin-bottom: 0; }
.finder .select { flex: none; width: 7.4rem; min-height: 42px; } /* « Année », « 2026 » : pas la plus longue de ses lignes */
/* Ce que pèse la liste que l'on regarde, et de quoi revenir à tout. */
.tally { display: flex; justify-content: space-between; align-items: baseline; gap: 4px 14px; flex-wrap: wrap; margin: 0 2px 10px; color: var(--muted); font-size: 0.92rem; }
.tally strong { color: var(--text); }
/* Sur un téléphone, un tableau large se lisait par une lucarne, ses colonnes coupées : le temps d'un classement
   sortait de l'écran. `.table--stack` fait de chaque ligne une fiche : ce qui la nomme en tête, puis chaque
   chiffre sous son intitulé (`data-label`). Les en-têtes restent pour un lecteur d'écran, et les rôles écrits
   dans la vue gardent au tableau son sens quand sa mise en page change. */
@media (max-width: 700px) {
  .table--stack, .table--stack tbody { display: block; }
  .table--stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  /* Les chiffres se suivent et passent à la ligne, chacun à sa largeur : une date ne déborde pas sur sa voisine. */
  .table--stack tr { position: relative; display: flex; flex-wrap: wrap; gap: 6px 14px; padding: 12px 16px; border-bottom: 1px solid var(--line); }
  .table--stack tbody tr:last-child { border-bottom: 0; }
  .table--stack td { display: block; min-width: 0; padding: 0; border: 0; }
  .table--stack td.num { text-align: left; }
  .table--stack td:not([data-label]) { flex: 1 1 100%; grid-column: 1 / -1; }
  .table--stack td[data-label] { flex: 1 0 28%; min-width: auto; display: grid; align-content: start; font-weight: 600; white-space: nowrap; }
  .acts td[data-label], .ranks td[data-label] { min-width: 0; }
  .table--stack td[data-label]::before { content: attr(data-label); color: var(--muted); font-size: 0.74rem; font-weight: 400; }
  .table--stack td[data-label] strong { font-weight: inherit; }
  .table--stack td[data-label] br { display: none; }
  .table--stack td[data-label] > .badge { justify-self: start; }
  .table--stack td[data-label] .muted { font-weight: 400; font-size: 0.86rem; }
  /* Une cellule de texte (le nom d'une activité, une phrase) : sous son intitulé, sur toute la largeur. */
  .table--stack td[data-wide] { flex: 1 1 100%; font-weight: 400; white-space: normal; }
  .table--stack .table__group { display: block; padding: 0; }
  .table--stack .table__group th { display: block; padding: 8px 16px; border: 0; }
  .table--stack .stretch::after { content: ""; position: absolute; inset: 0; } /* toute la fiche ouvre l'activité */
  .table--stack .table__actions { justify-content: flex-start; }
  .table--stack .share__cell { min-width: 0; }
  .table--stack .share__cell .copy:not(.copy--share) .input { flex: 1; }

  /* Une activité : son nom, puis la date, puis ses chiffres, alignés d'une fiche à l'autre. */
  .acts tr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr) minmax(0, 1.25fr) minmax(0, 0.85fr); gap: 3px 8px; }
  .acts td[data-label] { font-size: 0.95rem; }
  .table--stack td.acts__name { order: -2; font-size: 1rem; }
  .table--stack td.acts__date { order: -1; grid-column: 1 / -1; color: var(--muted); font-size: 0.86rem; }

  /* Un classement : le rang, le coureur et son temps sur la première ligne, la date dessous, puis les mesures. */
  .ranks tr { display: grid; grid-template-columns: 22px repeat(6, minmax(0, 1fr)); gap: 4px 12px; }
  .ranks td[data-label] { grid-column: span 2; }
  .ranks td[data-label]::before { white-space: normal; } /* « Puissance moy. » : plus large que sa colonne à 320 px */
  .table--stack td.ranks__rank { grid-column: 1; grid-row: 1 / span 4; color: var(--muted); font-weight: 600; }
  .table--stack td.ranks__who { grid-column: 2 / span 3; grid-row: 1; }
  .table--stack td.ranks__time { grid-column: 5 / span 3; grid-row: 1; display: grid; justify-items: end; gap: 2px; font-size: 1.05rem; text-align: right; }
  .ranks__time strong { order: -1; }
  .ranks__time br { display: none; }
  .ranks__time .muted, .ranks__time .badge { font-size: 0.76rem; }
  .table--stack td.ranks__date { grid-column: 2 / -1; grid-row: 2; color: var(--muted); font-size: 0.86rem; }
  .table--stack td.ranks__actions { grid-column: 2 / -1; margin-top: 4px; }
}

/* Les segments parcourus pendant une activité : une ligne par passage, qui s'ouvre sur ce que les capteurs y ont
   mesuré. Les chiffres de la ligne (temps, vitesse, fréquence cardiaque, puissance) tombent en colonnes. */
.passage + .passage { border-top: 1px solid var(--line); }
.passage > summary { display: grid; grid-template-columns: 12px minmax(0, 1fr) 64px 100px 76px 64px; align-items: center; gap: 4px 14px; padding: 11px 20px; cursor: pointer; list-style: none; }
.passage > summary::-webkit-details-marker { display: none; }
.passage > summary::before { content: ""; width: 7px; height: 7px; border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted); transform: rotate(-45deg); }
.passage[open] > summary::before { transform: translateY(-2px) rotate(45deg); }
.passage > summary:hover { background: var(--surface-2); }
.passage > summary:focus-visible { outline-offset: -2px; }
.passage:last-child:not([open]) > summary { border-radius: 0 0 var(--radius) var(--radius); }
.passage[open] > summary { border-bottom: 1px solid var(--line); }
.passage__name { display: grid; gap: 1px; min-width: 0; font-size: 0.93rem; }
.passage__name a { font-weight: 550; text-decoration: none; }
.passage__name a:hover { text-decoration: underline; }
.passage__name .muted { font-size: 0.85rem; }
.passage__fact { text-align: right; white-space: nowrap; font-size: 0.93rem; font-variant-numeric: tabular-nums; }
.passage__wait { padding: 16px 20px; }
.passage__body { padding: 16px 20px 20px; display: grid; gap: 20px; grid-template-columns: minmax(0, 1fr); }
.passage__body h3 { margin-bottom: 4px; }
/* Jusqu'à neuf chiffres, sur plusieurs lignes : chaque case trace elle-même ses filets, pour que la fin de la
   dernière ligne reste vide plutôt que grise. */
.passage__body .stats { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0; background: var(--surface); }
.passage__body .stat { align-content: start; box-shadow: 1px 0 0 var(--line), 0 1px 0 var(--line); }
.passage__body .table-wrap { margin: 0 -12px; }
.passage__standing { display: flex; align-items: center; justify-content: space-between; gap: 10px 20px; flex-wrap: wrap; }
.passage__standing p { flex: 1; min-width: min(100%, 320px); }
@media (max-width: 700px) {
  .passage > summary { grid-template-columns: 12px repeat(4, auto) minmax(0, 1fr); }
  .passage__name { grid-column: 2 / -1; }
  .passage__name + .passage__fact { grid-column: 2; }
  .passage__fact { text-align: left; }
}
/* Les courbes d'un passage, empilées : même échelle de distance, un titre et son unité au-dessus de chacune. */
.telemetry { display: grid; gap: 14px; grid-template-columns: minmax(0, 1fr); }
.chart__unit { color: var(--muted); font-weight: 400; }
.chart__tabs { margin-bottom: 8px; }

.empty { text-align: center; padding: 40px 24px; display: grid; gap: 10px; justify-items: center; }
.empty p { color: var(--muted); max-width: 52ch; }
.steps { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); text-align: left; margin: 10px 0; width: 100%; padding: 0; list-style: none; counter-reset: step; }
.steps li { counter-increment: step; padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius); display: grid; gap: 4px; }
.steps li::before { content: counter(step); display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: var(--primary); color: var(--primary-text); font-weight: 700; font-size: 0.8rem; }
.steps span { color: var(--muted); font-size: 0.9rem; }

/* Premiers pas : les trois étapes d'un nouveau compte, l'une sous l'autre. Celle en cours porte ses actions et un
   repère plein ; une étape faite, une coche. */
.start { list-style: none; margin: 0; padding: 0; }
.start__step { position: relative; display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 14px; padding: 14px 20px; }
/* Le fil qui relie une étape à la suivante : plus marqué une fois l'étape faite. */
.start__step:not(:last-child)::after { content: ""; position: absolute; left: 33px; top: 46px; bottom: -10px; width: 2px; border-radius: 1px; background: var(--line); }
.start__step.is-done:not(:last-child)::after { background: var(--line-strong); }
.start__mark { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; border: 1px solid var(--line-strong); color: var(--muted); font-weight: 700; font-size: 0.85rem; font-variant-numeric: tabular-nums; }
.start__step.is-current .start__mark { background: var(--primary); border-color: var(--primary); color: var(--primary-text); }
.start__step.is-done .start__mark { background: var(--surface-2); border-color: transparent; color: var(--text); }
.start__body { display: grid; gap: 4px; padding-top: 3px; justify-items: start; }
.start__title { font-size: 1rem; }
.start__step:not(.is-current) .start__title { color: var(--muted); font-weight: 550; }
.start__text { color: var(--muted); max-width: 70ch; }
.start__hint { color: var(--muted); font-size: 0.9rem; }
.start__actions { display: flex; gap: 8px; flex-wrap: wrap; margin: 8px 0 4px; }
/* Sous l'action d'une étape : les autres chemins, en une phrase. */
.start__alts { flex: 1 1 100%; color: var(--muted); font-size: 0.9rem; max-width: 70ch; }
/* Le lien d'une étape faite, pour y revenir. */
.start__again { white-space: nowrap; }
/* L'avancement : un trait par étape, plein quand elle est faite. */
.steps-bar { display: flex; gap: 4px; width: 100%; max-width: 200px; margin-top: 8px; }
.steps-bar span { flex: 1; height: 4px; border-radius: 2px; background: var(--line-strong); }
.steps-bar .is-done { background: var(--text); }
@media (max-width: 640px) {
  .start__actions .btn { min-width: 0; white-space: normal; text-align: center; } /* un libellé long passe à la ligne, il ne sort pas de la carte */
  .start__actions .btn--primary { flex: 1 1 100%; } /* l'action de l'étape, sous le pouce */
}
.start-card { margin-bottom: 22px; }
.start-card .card__head form { margin: 0; }
/* Le rappel de l'étape en cours, sur les pages qui y mènent. */
.nextstep { display: flex; align-items: baseline; gap: 6px 12px; flex-wrap: wrap; padding: 10px 14px; margin-bottom: 18px; border: 1px solid var(--line-strong); border-radius: var(--radius); background: var(--surface); }
.nextstep__tag { text-decoration: none; background: var(--primary); color: var(--primary-text); }
/* Ce que Sillage permet d'autre : des liens en pavés. `div`, pour ne pas ranger aussi en colonnes une explication
   repliée (`details.more`, plus bas), dont le texte partait à droite de sa question. */
div.more { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.more__item { display: flex; gap: 12px; align-items: flex-start; padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); text-decoration: none; }
.more__item:hover { border-color: var(--line-strong); }
.more__text { display: grid; gap: 4px; min-width: 0; }
.more__text span { color: var(--muted); font-size: 0.9rem; }
/* La page qui accueille un nouveau compte : trois coureurs sur un même tronçon, à leur couleur et à leur numéro. */
.welcome { display: grid; gap: 8px; justify-items: center; text-align: center; margin: 4px 0 24px; }
.welcome p { max-width: 58ch; }
.welcome__art { display: block; width: 100%; max-width: 340px; height: auto; margin-bottom: 4px; }
.welcome__road { fill: none; stroke: var(--line-strong); stroke-width: 3; stroke-linecap: round; }
.welcome__end { fill: var(--bg); stroke: var(--text); stroke-width: 2; }
.welcome__flag { fill: var(--text); stroke: var(--text); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.welcome__runner circle { fill: currentColor; stroke: var(--bg); stroke-width: 2; }
.welcome__runner text { font-size: 11px; font-weight: 700; }
.welcome__runner.ink--1 text { fill: var(--athlete-1-ink); }
.welcome__runner.ink--2 text { fill: var(--athlete-2-ink); }
.welcome__runner.ink--3 text { fill: var(--athlete-3-ink); }

/* Les étapes d'un guide, numérotées, l'une sous l'autre. */
.guide { margin: 0; padding: 0; list-style: none; counter-reset: step; display: grid; gap: 10px; }
.guide li { counter-increment: step; display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 12px; align-items: start; }
.guide li::before { content: counter(step); display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--surface-2); font-weight: 700; font-size: 0.82rem; font-variant-numeric: tabular-nums; }
.guide li > span { padding-top: 2px; }
a.tab { text-decoration: none; }
section[id], turbo-frame[id], details[id] { scroll-margin-top: 16px; }

.hint { margin-top: 14px; }
.pager { display: flex; justify-content: space-between; align-items: center; margin-top: 14px; color: var(--muted); }

.filters { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
/* `position: relative` : le texte caché d'un filtre (`.sr-only`, `.filter__count--secondary`) se place dans le filtre.
   Sans cela, il échappe à la rangée qui défile, et sa place hors de l'écran élargit toute la page. */
.filter { position: relative; display: inline-flex; align-items: center; gap: 8px; min-height: 40px; padding: 7px 14px; border: 1px solid var(--line); border-radius: 999px; text-decoration: none; font-size: 0.9rem; background: var(--surface); }
.filter.is-current { background: var(--primary); border-color: var(--primary); color: var(--primary-text); }
.filter__count { color: var(--muted); font-size: 0.82rem; }
.filter.is-current .filter__count { color: inherit; opacity: 0.75; }
/* Sur un écran étroit, une rangée de filtres ou d'onglets ne passe plus à la ligne : elle défile de côté, d'un
   doigt, jusqu'au bord de l'écran, et l'élément en cours est amené en vue (contrôleur `rail`). */
@media (max-width: 640px) {
  .filters, .page-head__actions { flex-wrap: nowrap; overflow-x: auto; margin-inline: -20px; padding-inline: 20px; scrollbar-width: none; }
  .page-head__actions { width: calc(100% + 40px); padding-block: 3px; } /* la place du contour de mise au point */
  .page-head__actions::-webkit-scrollbar { display: none; }
  .page-head__actions > * { flex: none; }
  .page-head__actions > .btn--primary { order: -1; } /* l'action principale d'abord, sans attendre que l'on fasse défiler */
  /* Des boutons en ligne ailleurs dans la page (`row--rail`) : la même rangée qui défile, dans la marge de sa carte. */
  .row--rail { flex: 1 1 100%; min-width: 0; flex-wrap: nowrap; overflow-x: auto; margin-inline: -20px; padding: 3px 20px; scrollbar-width: none; }
  .row--rail::-webkit-scrollbar { display: none; }
  .row--rail > * { flex: none; }
  .filters::-webkit-scrollbar { display: none; }
  .filter { flex: none; min-height: 36px; white-space: nowrap; }
  .btn--small { min-height: 36px; }
}
/* Le sport : son pictogramme et son nom, d'un seul tenant, dans la couleur du texte pour ressortir d'une ligne grisée. */
.sport { display: inline-flex; align-items: center; gap: 5px; color: var(--text); font-weight: 550; white-space: nowrap; vertical-align: bottom; }
.sport-icon { flex: none; }
.badge--sport { display: inline-flex; align-items: center; gap: 4px; vertical-align: middle; }
/* Avec qui l'on est sorti, dans la liste des activités : des noms, qui passent à la ligne s'il le faut. */
.acts__with { display: inline-flex; align-items: center; gap: 4px; vertical-align: middle; white-space: normal; }
.acts__with svg { flex: none; }

/* --- Import -------------------------------------------------------------- */

/* La page d'import : d'où repartir, ce qui vient d'arriver, et ce qui dispense d'importer. */
.import__since { margin: 0; font-size: 0.95rem; }
.import__auto-head { display: flex; align-items: flex-start; gap: 14px; }
.import__auto-head h2 { margin-bottom: 4px; }
.import__auto-head .menu__icon { flex: none; }
.arrivals .feed__who { display: grid; gap: 2px; min-width: 0; }
.arrivals__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.arrivals .feed__value { flex: none; text-align: right; font-size: 0.86rem; }
.drop { display: grid; gap: 8px; justify-items: center; text-align: center; padding: 30px 20px; border: 1.5px dashed var(--line-strong); border-radius: var(--radius); background: var(--surface-2); cursor: pointer; }
.drop.is-over { border-color: var(--text); background: var(--surface); }
/* Des fichiers sont choisis : la zone n'invite plus, elle dit ce qu'elle tient. */
.drop.is-chosen { border-style: solid; padding-top: 20px; padding-bottom: 20px; }
.drop.is-chosen .drop__files { color: var(--text); font-weight: 650; font-size: 1rem; overflow-wrap: anywhere; }
.drop__change { display: none; color: var(--muted); font-size: 0.88rem; text-decoration: underline; text-underline-offset: 3px; }
.drop.is-chosen .drop__invite { display: none; }
.drop.is-chosen .drop__change { display: inline; }
/* Ce que l'on a choisi, nommé : un fichier par ligne, son poids, ou pourquoi il sera écarté. */
.drop__list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: var(--radius); font-size: 0.92rem; }
.drop__list[hidden] { display: none; }
.drop__list li { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 8px 12px; }
.drop__list li + li { border-top: 1px solid var(--line); }
.drop__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.drop__note { color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.drop__list .is-ignored .drop__name { color: var(--muted); text-decoration: line-through; }
.drop__list .is-ignored .drop__note { color: var(--danger); }
.drop__rest { color: var(--muted); }
/* Ce que dit la zone selon ce avec quoi on la touche : une souris dépose et clique, un doigt touche. */
.touch-only { display: none; }
@media (hover: none) and (pointer: coarse) {
  .touch-only { display: inline; }
  .mouse-only { display: none; }
}
@media (max-width: 640px) { .drop__go .btn--primary { flex: 1 1 100%; } } /* l'action, sous le pouce */
.drop input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.drop:focus-within { outline: 2px solid var(--text); outline-offset: 2px; }
.drop__files { color: var(--muted); font-size: 0.9rem; max-width: 60ch; }
/* L'avancement d'un import par lots, puis son compte rendu. */
.upload-progress { display: grid; gap: 6px; }
.upload-progress progress { width: 100%; height: 8px; accent-color: var(--primary); }
.report { display: grid; gap: 4px; margin-bottom: 0; }
.report[hidden] { display: none; }
.report a { font-weight: 550; }

/* Le choix d'une couleur : huit pastilles sur une ligne, chacune au milieu d'une case de 44 px, la taille d'un
   doigt. Celle que l'on a choisie est cernée et cochée : la coche se lit sans distinguer les couleurs. */
.swatches { display: grid; grid-template-columns: repeat(8, minmax(0, 44px)); }
.swatch { position: relative; display: grid; place-items: center; height: 44px; }
.swatch input { position: absolute; opacity: 0; inset: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.swatch span { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%; border: 2px solid var(--surface); box-shadow: 0 0 0 1px var(--line-strong); }
.swatch input:checked + span { box-shadow: 0 0 0 2px var(--text); }
.swatch input:checked + span::after { content: ""; width: 6px; height: 11px; margin-top: -2px; border: solid currentColor; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.swatch input:focus-visible + span { outline: 2px solid var(--text); outline-offset: 3px; }

/* Le profil : le coureur tel que les autres le voient. Sa pastille en grand, à sa couleur et avec ses initiales. */
.profile__head { justify-content: flex-start; align-items: center; flex-wrap: nowrap; gap: 16px; }
.profile__head > div { min-width: 0; }
.profile__head h1 { overflow-wrap: anywhere; }
.profile__face { display: grid; place-items: center; width: 64px; height: 64px; border-radius: 50%; font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; flex: none; }
/* Elle prend la couleur que l'on coche, avant même d'enregistrer : on voit ce que l'on choisit. La pastille de la
   ligne « Nom et couleur », juste au-dessus des couleurs, fait de même. */
.profile:has(.swatch input[value="1"]:checked) :is(.profile__face, .profile__dot) { background: var(--athlete-1); color: var(--athlete-1-ink); }
.profile:has(.swatch input[value="2"]:checked) :is(.profile__face, .profile__dot) { background: var(--athlete-2); color: var(--athlete-2-ink); }
.profile:has(.swatch input[value="3"]:checked) :is(.profile__face, .profile__dot) { background: var(--athlete-3); color: var(--athlete-3-ink); }
.profile:has(.swatch input[value="4"]:checked) :is(.profile__face, .profile__dot) { background: var(--athlete-4); color: var(--athlete-4-ink); }
.profile:has(.swatch input[value="5"]:checked) :is(.profile__face, .profile__dot) { background: var(--athlete-5); color: var(--athlete-5-ink); }
.profile:has(.swatch input[value="6"]:checked) :is(.profile__face, .profile__dot) { background: var(--athlete-6); color: var(--athlete-6-ink); }
.profile:has(.swatch input[value="7"]:checked) :is(.profile__face, .profile__dot) { background: var(--athlete-7); color: var(--athlete-7-ink); }
.profile:has(.swatch input[value="8"]:checked) :is(.profile__face, .profile__dot) { background: var(--athlete-8); color: var(--athlete-8-ink); }
/* Deux champs courts restent côte à côte, même sur un téléphone, et ne s'étirent pas sur un écran large. */
.fields--pair { grid-template-columns: repeat(2, minmax(0, 200px)); }
@media (max-width: 640px) {
  .profile__face { width: 56px; height: 56px; font-size: 1.3rem; }
  .profile .input { font-size: 16px; } /* en deçà, iOS grossit la page au toucher */
}

/* --- Cartes géographiques ------------------------------------------------- */

.map { height: 380px; border-radius: var(--radius); border: 1px solid var(--line); overflow: hidden; background: var(--surface-2); z-index: 0; }
.map--tall { height: 460px; }
@media (max-width: 640px) { .map--tall { height: clamp(260px, 46vh, 440px); } } /* la carte et ce qui la suit tiennent à l'écran */
.map--small { height: 220px; }
.leaflet-container { font: inherit; background: var(--surface-2); }
.leaflet-control-attribution { font-size: 11px; }

/* Sélecteur de fond et logo Google : même allure que les boutons de zoom de la carte. */
.map-layers { appearance: none; padding: 6px 28px 6px 10px; border: 2px solid rgb(0 0 0 / 20%); border-radius: 4px; background-color: #ffffff; background-clip: padding-box; background-image: linear-gradient(45deg, transparent 50%, #52514e 50%), linear-gradient(135deg, #52514e 50%, transparent 50%); background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%; background-size: 5px 5px; background-repeat: no-repeat; color: #17191d; font: 550 13px/1.2 var(--sans); cursor: pointer; }
.map-layers:focus-visible { outline: 2px solid #17191d; outline-offset: 1px; }
.map-google { display: block; height: 18px; width: auto; }

.route-casing { stroke: #ffffff; stroke-width: 7; stroke-opacity: 0.9; fill: none; }
.route-line { stroke: #17191d; stroke-width: 3; stroke-opacity: 0.85; fill: none; }
.route-line--muted { stroke: #6b6a66; stroke-opacity: 0.7; }
.route-line--selected { stroke: #17191d; stroke-width: 5; stroke-opacity: 1; }

.pin { display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: #17191d; color: #ffffff; border: 2px solid #ffffff; font-size: 11px; font-weight: 700; box-shadow: 0 1px 4px rgb(0 0 0 / 35%); }
.pin--finish { background: #ffffff; color: #17191d; border-color: #17191d; }
.pin--loop { width: 34px; border-radius: 12px; }
.pin--office { border-radius: 7px; background: #0866ff; } /* le bureau d'une entreprise (`office_map_controller.js`) */
.office-radius { stroke: #0866ff; stroke-width: 2; stroke-dasharray: 6 6; fill: #0866ff; fill-opacity: 0.06; }
.pin--drag { cursor: grab; width: 28px; height: 28px; touch-action: none; } /* le doigt posé dessus le déplace, sans faire défiler la page */
/* Un doigt sur la carte fait défiler la page, la carte se déplace à deux (`spare`, dans `lib/map.js`) : on rend
   le geste au navigateur, que Leaflet lui retire (trois classes, d'où les quatre), et le rappel. */
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom.is-yielding { touch-action: pan-x pan-y; }
.map-reminder { position: absolute; z-index: 900; inset: 50% auto auto 50%; transform: translate(-50%, -50%); width: max-content; max-width: calc(100% - 32px); margin: 0; padding: 9px 16px; border-radius: 999px; background: rgb(15 17 20 / 88%); color: #ffffff; font-size: 0.95rem; font-weight: 600; text-align: center; pointer-events: none; }
.map-reminder[hidden] { display: none; }

.runner { position: relative; display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; border: 2px solid #ffffff; font-size: 12px; font-weight: 700; box-shadow: 0 1px 5px rgb(0 0 0 / 40%); font-variant-numeric: tabular-nums; }
/* Silhouettes (cycliste, coureur) : le repère garde sa boîte de 26 px centrée sur le point de la route ; le dessin
   la déborde vers le haut, pieds ou roues posés sur ce point, et le numéro passe dans une étiquette. */
.runner--figure { background: none; border-color: transparent; box-shadow: none; }
.runner__figure { position: absolute; left: 50%; bottom: 50%; transform: translateX(-50%); line-height: 0; filter: drop-shadow(0 1px 2px rgb(0 0 0 / 35%)); }
.runner__figure.is-flipped { transform: translateX(-50%) scaleX(-1); }
.runner__figure svg { display: block; }
.runner__tag { position: absolute; left: calc(50% + 6px); bottom: calc(50% + 25px); display: grid; place-items: center; min-width: 15px; height: 15px; padding: 0 3px; border: 1.5px solid #17191d; border-radius: 8px; background: #ffffff; color: #17191d; font-size: 10px; font-weight: 700; line-height: 1; }
.runner--figure.is-beating::after { inset: 4px; background: currentColor; }

/* Le halo d'un coureur bat à sa fréquence cardiaque : --beat est la durée d'un battement. */
.runner.is-beating::after { content: ""; position: absolute; inset: -2px; border-radius: 50%; background: inherit; z-index: -1; animation: halo var(--beat, 1s) ease-out infinite; }
@keyframes halo {
  0% { transform: scale(1); opacity: 0.55; }
  70%, 100% { transform: scale(2.3); opacity: 0; }
}

/* --- Sélection d'un tronçon ----------------------------------------------- */

.range2 { position: relative; height: 34px; }
.range2__track { position: absolute; left: 0; right: 0; top: 15px; height: 4px; border-radius: 2px; background: var(--line-strong); }
.range2__fill { position: absolute; top: 15px; height: 4px; border-radius: 2px; background: var(--text); }
.range2 input { position: absolute; inset: 0; width: 100%; margin: 0; background: none; pointer-events: none; appearance: none; -webkit-appearance: none; height: 34px; }
.range2 input::-webkit-slider-runnable-track { background: none; height: 4px; }
.range2 input::-moz-range-track { background: none; height: 4px; }
.range2 input::-webkit-slider-thumb { -webkit-appearance: none; pointer-events: auto; width: 20px; height: 20px; margin-top: -8px; border-radius: 50%; background: var(--surface); border: 2px solid var(--text); cursor: grab; }
.range2 input::-moz-range-thumb { pointer-events: auto; width: 16px; height: 16px; border-radius: 50%; background: var(--surface); border: 2px solid var(--text); cursor: grab; }
.range2 input:focus-visible { outline: none; }
.range2 input:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--text); outline-offset: 2px; }
.range2 input:focus-visible::-moz-range-thumb { outline: 2px solid var(--text); outline-offset: 2px; }

.nudge { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.nudge__group { display: flex; align-items: center; gap: 6px; color: var(--muted); font-size: 0.9rem; }
/* L'outil de tracé d'un segment : un volet au pied du profil d'une activité, sur toute la largeur de sa carte.
   Replié, il tient en un titre et une phrase ; déplié, il montre les curseurs, les chiffres du tronçon et de quoi
   créer le segment. */
.tracer { margin: 0 -20px -16px; border-top: 1px solid var(--line); }
.tracer > summary { position: relative; display: grid; gap: 2px; padding: 12px 48px 12px 20px; cursor: pointer; list-style: none; }
.tracer > summary::-webkit-details-marker { display: none; }
.tracer > summary::after { content: "›"; position: absolute; top: 10px; right: 20px; color: var(--muted); font-size: 1.4rem; line-height: 1; transition: transform 0.15s; }
.tracer[open] > summary::after { transform: rotate(90deg); }
.tracer > summary:hover { background: var(--surface-2); }
.tracer > summary:focus-visible { outline-offset: -2px; }
.tracer:not([open]) > summary { border-radius: 0 0 var(--radius) var(--radius); }
.tracer > summary .muted { font-size: 0.9rem; }
.tracer__title { display: inline-flex; align-items: center; gap: 7px; font-weight: 650; }
.tracer > .stack { padding: 6px 20px 18px; }
/* Des tuiles plus serrées, pour les chiffres d'un tronçon : trois par ligne sur un téléphone. */
/* Leur nombre varie avec les capteurs : chaque tuile porte son filet, et une ligne incomplète reste blanche. */
.stats--compact { gap: 0; background: var(--surface); }
.stats--compact .stat { padding: 9px 12px; box-shadow: 1px 0 0 var(--line), 0 1px 0 var(--line); }
.stats--compact .stat__value { font-size: 1.05rem; }
@media (max-width: 640px) {
  .stats--compact { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .stats--compact > .stat:last-child:nth-child(odd) { grid-column: auto; }
  .stats--compact .stat { padding: 8px 10px; align-content: start; }
  .stats--compact .stat__label { font-size: 0.74rem; }
  .stats--compact .stat__value { font-size: 0.98rem; white-space: nowrap; }
  /* Le départ et l'arrivée côte à côte, chacun sous son nom. */
  .nudge { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 14px; }
  .nudge__group { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 4px 6px; }
  .nudge__group > span { grid-column: 1 / -1; }
  .nudge__group strong { text-align: center; white-space: nowrap; }
}

/* --- Graphiques ---------------------------------------------------------- */

.chart { position: relative; }
.chart__title { font-size: 0.92rem; font-weight: 650; }
.chart__sub { color: var(--muted); font-size: 0.85rem; margin-bottom: 6px; }
.chart canvas { display: block; width: 100%; touch-action: pan-y; border-radius: 6px; }
.chart canvas:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
.chart__tip { position: absolute; top: 0; left: 0; z-index: 5; pointer-events: none; min-width: 150px; padding: 8px 10px; border-radius: 9px; background: var(--surface); border: 1px solid var(--line-strong); box-shadow: var(--shadow); font-size: 0.85rem; display: grid; gap: 3px; }
.chart__tip-head { color: var(--muted); font-size: 0.8rem; margin-bottom: 2px; }
.chart__tip-row { display: flex; align-items: center; gap: 7px; white-space: nowrap; }
.chart__tip-row strong { font-variant-numeric: tabular-nums; }
.chart__tip-row span:last-child { color: var(--muted); }
.key { display: inline-block; width: 12px; height: 3px; border-radius: 2px; flex: none; background: var(--faint); }
.key--1 { background: var(--athlete-1); } .key--2 { background: var(--athlete-2); } .key--3 { background: var(--athlete-3); }
.key--4 { background: var(--athlete-4); } .key--5 { background: var(--athlete-5); } .key--6 { background: var(--athlete-6); }
.key--7 { background: var(--athlete-7); } .key--8 { background: var(--athlete-8); }

.legend { display: flex; gap: 6px 18px; flex-wrap: wrap; margin-bottom: 8px; font-size: 0.88rem; color: var(--muted); }
.legend__item { display: inline-flex; align-items: center; gap: 7px; }
/* Les deux formes de point d'une courbe de progression : plein (record battu), creux (autre passage). */
.mark { display: inline-block; width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--muted); }
.mark--hollow { background: transparent; box-shadow: inset 0 0 0 2px var(--muted); }
.chart__tip-note { color: var(--muted); font-size: 0.8rem; white-space: nowrap; }

/* La pente (lib/grade.js) : une pastille carrée à la couleur de sa classe, et l'échelle posée sous un profil, les
   paliers écrits entre les cases. Un filet cerne chaque case : les couleurs sont les mêmes dans les deux thèmes,
   et la plus pâle se perdrait sur un fond clair, la plus sombre sur un fond sombre. */
.grade { display: inline-block; width: 10px; height: 10px; border-radius: 2px; flex: none; box-shadow: inset 0 0 0 1px var(--line-strong); }
/* `fill` : la même couleur en aplat d'un dessin SVG (le profil d'un col sur sa carte, `col_profile_svg`). */
.grade--flat { background: var(--grade-flat); fill: var(--grade-flat); }
.grade--up-1 { background: var(--grade-up-1); fill: var(--grade-up-1); } .grade--up-2 { background: var(--grade-up-2); fill: var(--grade-up-2); }
.grade--up-3 { background: var(--grade-up-3); fill: var(--grade-up-3); } .grade--up-4 { background: var(--grade-up-4); fill: var(--grade-up-4); }
.grade--up-5 { background: var(--grade-up-5); fill: var(--grade-up-5); } .grade--up-6 { background: var(--grade-up-6); fill: var(--grade-up-6); }
.grade--up-7 { background: var(--grade-up-7); fill: var(--grade-up-7); } .grade--up-8 { background: var(--grade-up-8); fill: var(--grade-up-8); }
.grade--up-9 { background: var(--grade-up-9); fill: var(--grade-up-9); }
.grade--down-1 { background: var(--grade-down-1); fill: var(--grade-down-1); } .grade--down-2 { background: var(--grade-down-2); fill: var(--grade-down-2); }
.grade--down-3 { background: var(--grade-down-3); fill: var(--grade-down-3); } .grade--down-4 { background: var(--grade-down-4); fill: var(--grade-down-4); }
/* Une route en relief (lib/ribbon.js). `touch-action` : glisser de côté la tourne, le doigt fait toujours défiler la page. */
.ribbon__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.ribbon__switch { display: flex; justify-content: flex-end; margin-bottom: 10px; }
.ribbon__view { display: block; width: 100%; max-width: 760px; height: auto; margin: 8px auto 0; cursor: grab; touch-action: pan-y; user-select: none; }
.ribbon__view:active { cursor: grabbing; }
.ribbon__grid, .ribbon__trace, .ribbon__road { fill: none; vector-effect: non-scaling-stroke; }
.ribbon__grid { stroke: var(--line-strong); stroke-width: 1; }
.ribbon__trace { stroke: var(--faint); stroke-width: 1; }
.ribbon__road { stroke: var(--text); stroke-width: 1.5; stroke-linecap: round; }
/* Ses tailles sont celles du dessin, qui rétrécit avec la page : sur un téléphone, les altitudes doublent. */
.ribbon__label { fill: var(--text); stroke: var(--surface); stroke-width: 4px; paint-order: stroke; font-size: 14px; font-weight: 600; }
@media (max-width: 520px) { .ribbon__label { stroke-width: 7px; font-size: 27px; } }
.grade-scale { display: flex; align-items: flex-start; gap: 10px; margin-top: 8px; color: var(--muted); font-size: 0.78rem; line-height: 12px; }
.grade-scale__steps { display: inline-flex; gap: 2px; padding-bottom: 15px; }
.grade-scale__step { position: relative; width: 24px; height: 12px; border-radius: 2px; box-shadow: inset 0 0 0 1px var(--line-strong); }
@media (max-width: 520px) { .grade-scale__step { width: 16px; } .grade-scale__mark { font-size: 0.68rem; } }
.grade-scale__mark { position: absolute; top: 15px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.grade-scale__mark--before { left: -1px; transform: translateX(-50%); }
.grade-scale__mark--after { right: -1px; transform: translateX(50%); }

.tabs { display: inline-flex; max-width: 100%; padding: 3px; border-radius: 12px; background: var(--accent-line); gap: 3px; flex-wrap: wrap; }
.tab { padding: 9px 14px; border: 0; border-radius: 10px; background: transparent; color: var(--muted); font: inherit; font-weight: 550; font-size: 0.9rem; cursor: pointer; }
.tab:hover { color: var(--text); }
.tab.is-current, .tab[aria-pressed="true"] { background: var(--primary); color: var(--primary-text); box-shadow: none; }
/* Sur un écran étroit, des onglets ne passent pas à la ligne : ils défilent de côté dans leur rangée. */
@media (max-width: 640px) {
  .tabs { display: flex; flex-wrap: nowrap; overflow-x: auto; width: fit-content; max-width: 100%; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { flex: none; display: inline-flex; align-items: center; justify-content: center; min-height: 36px; white-space: nowrap; }
}
/* Un libellé qui se raccourcit quand la place manque : la version longue, ou la courte. */
.narrow-only { display: none; }
@media (max-width: 640px) { .narrow-only { display: inline; } }

/* --- Comparaison --------------------------------------------------------- */

.compare__row { display: grid; grid-template-columns: auto minmax(120px, 1fr) minmax(220px, 2fr) auto; gap: 10px 12px; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--line); }
.compare__row:last-of-type { border-bottom: 0; }
.compare__row.is-off .chip, .compare__row.is-off .select { opacity: 0.45; }
/* Sur un téléphone, la liste des coureurs est plus haute que l'écran : les boutons qui lancent la comparaison
   restent collés au pied de la fenêtre tant que l'on choisit les passages. `--foot` les tient au-dessus de ce qui
   couvre le bas de la fenêtre : les onglets du site, ou ceux de l'application iOS, qui en dit la hauteur à la
   page (contrôleur `native`). */
@media (max-width: 640px) {
  .compare__go { position: sticky; bottom: var(--foot); z-index: 5; margin: 6px -20px -16px; padding: 10px 20px; border-top: 1px solid var(--line); border-radius: 0 0 var(--radius) var(--radius); background: var(--surface); }
  .compare__go .btn { flex: 1; }
  .is-overlaid .compare__go { position: static; } /* une application iOS qui ne dit pas cette hauteur : ils passeraient sous ses onglets */
  .wide-only { display: none; }
}
/* Une explication de détail, repliée : elle reste sur la page, à un geste. */
.more { margin-top: 6px; }
.more > summary { width: fit-content; cursor: pointer; color: var(--muted); font-size: 0.9rem; font-weight: 550; text-decoration: underline; text-underline-offset: 3px; list-style: none; }
.more > summary::-webkit-details-marker { display: none; }
.more[open] > summary { margin-bottom: 4px; }
.check { width: 18px; height: 18px; accent-color: var(--primary); }
@media (max-width: 640px) {
  /* Deux lignes par coureur : sa case, son nom et « Autre date » ; puis la date choisie, sur toute la largeur. */
  .compare__row { grid-template-columns: auto 1fr auto; }
  .compare__row .select { grid-column: 1 / -1; }
  .compare__row > :last-child { grid-row: 1; grid-column: 3; }
}

/* Le lecteur d'une course : la carte et, juste dessous, ce qui la commande (`.transport`) ; le classement en direct
   à côté, sur toute leur hauteur, ou dessous sur un écran étroit. */
.race { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 14px; align-items: stretch; }
.race__main { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; align-content: start; }
.race__map { height: 520px; }
.race__stage { min-width: 0; }

/* La scène en perspective (MapLibre) : mêmes pastilles que la carte, zoom et mentions par-dessus. */
.scene { position: relative; background: #eef3f5; } /* la couleur de l'horizon : rien ne tranche au-dessus de la ligne de crête */
.scene--maquette { background: #f4f4f1; } /* le monde maquette : son horizon est blanc cassé... */
.scene--night { background: #1b1c1e; }    /* ...ou sombre, la nuit */
/* Un coureur dans la scène : son repère, et au-dessus de lui ce que la séance en dit (son écart). */
.scene__body { position: relative; display: block; }
/* La brume et le voile de la pluie (lib/scene.js, `mist`) : rien au pied de l'image, de plus en plus dense vers
   l'horizon, à la couleur du ciel (`--haze`). Il ne retient ni le doigt ni la souris. */
.scene__haze { position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, transparent 0%, color-mix(in srgb, var(--haze) 30%, transparent) 30%, color-mix(in srgb, var(--haze) 78%, transparent) 55%, var(--haze) 72%); }
.scene__note { position: absolute; left: 50%; bottom: calc(50% + 20px); transform: translateX(-50%); padding: 0 6px; border: 1.5px solid #17191d; border-radius: 9px; background: #ffffff; color: #17191d; font-size: 11px; font-weight: 700; line-height: 1.45; white-space: nowrap; font-variant-numeric: tabular-nums; }
.scene__body:has(.runner--figure) .scene__note { bottom: calc(50% + 46px); }
/* Un cycliste en volume : son numéro et ce qui s'écrit de lui se tiennent au-dessus du casque (--lift, que règle la scène). */
.runner--volume .runner__tag { left: 50%; bottom: calc(50% + var(--lift, 36px) + 5px); transform: translateX(-50%); }
.scene__body:has(.runner--volume) .scene__note { bottom: calc(50% + var(--lift, 36px) + 26px); }
.runner--volume.is-bibbed .runner__tag { visibility: hidden; } /* le dossard se lit dans son dos : pas de doublon */
.scene__body:has(.is-bibbed) .scene__note { bottom: calc(50% + var(--lift, 36px) + 6px); }
.scene__loading { position: absolute; left: 50%; bottom: 34px; z-index: 2; transform: translateX(-50%); margin: 0; padding: 5px 14px; border-radius: 999px; background: rgb(255 255 255 / 88%); color: #17191d; font-size: 0.88rem; font-weight: 550; box-shadow: 0 1px 4px rgb(0 0 0 / 25%); white-space: nowrap; }
/* Les sommets nommés d'un grand col (lib/mountain.js) : leur nom et leur altitude dans le ciel, au-dessus de leur
   cime, sur un trait, comme sur une table d'orientation. Ils viennent et s'effacent en fondu, sans retenir le doigt. */
.scene__peaks { position: absolute; inset: 0; z-index: 1; overflow: hidden; pointer-events: none; }
.peak { position: absolute; top: 0; left: 0; opacity: 0; transition: opacity 0.6s ease; will-change: transform; }
.peak.is-shown { opacity: 1; }
.peak__tag { position: absolute; left: 0; bottom: 0; display: flex; flex-direction: column; align-items: center; padding-bottom: 22px; transform: translateX(-50%);
  color: #ffffff; font-size: 12px; font-weight: 700; line-height: 1.2; letter-spacing: 0.02em; white-space: nowrap;
  text-shadow: 0 0 3px rgb(23 25 29 / 85%), 0 1px 2px rgb(23 25 29 / 65%); }
.peak__tag::after { content: ""; position: absolute; left: 50%; bottom: 2px; width: 1.5px; height: 18px; background: rgb(255 255 255 / 85%); box-shadow: 0 0 2px rgb(23 25 29 / 65%); }
.peak__height { font-size: 10.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) { .peak { transition: none; } }
.scene__marker { position: absolute; top: 0; left: 0; will-change: transform; }
.scene__marker.is-out { visibility: hidden; } /* sous la caméra, ou derrière elle */
/* Les jalons de la route (arches, bornes, panneaux) : le pied du dessin est posé sur le point de la carte, et le
   dessin grandit ou rapetisse autour de ce pied selon son éloignement. */
.sign { position: absolute; left: 0; bottom: 0; transform-origin: 0 100%; line-height: 0; filter: drop-shadow(0 1px 2px rgb(0 0 0 / 35%)); }
.sign svg { display: block; transform: translateX(-50%); font-family: var(--sans); }
.scene__zoom { position: absolute; top: 10px; left: 10px; z-index: 2; display: grid; border: 2px solid rgb(0 0 0 / 20%); border-radius: 4px; background-clip: padding-box; overflow: hidden; }
.scene__zoom button { width: 30px; height: 30px; border: 0; background: #ffffff; color: #17191d; font: 700 18px/1 var(--sans); cursor: pointer; }
.scene__zoom button + button { border-top: 1px solid #cfcdc6; }
.scene__zoom button:hover { background: #f4f4f1; }
.scene__credit { position: absolute; right: 0; bottom: 0; z-index: 2; padding: 1px 6px; background: rgb(255 255 255 / 80%); color: #333333; font-size: 11px; }
.scene__credit a { color: #0078a8; text-decoration: none; }
.scene__logo { position: absolute; left: 10px; bottom: 10px; z-index: 2; }
.race__side { display: flex; flex-direction: column; min-height: 0; }
.board { list-style: none; margin: 0; padding: 6px 0; overflow-y: auto; flex: 1; }
.board__row { display: grid; grid-template-columns: 18px auto minmax(0, 1fr) auto; gap: 4px 10px; align-items: center; padding: 9px 16px; }
.board__row + .board__row { border-top: 1px solid var(--line); }
.board__rank { color: var(--faint); font-weight: 650; font-variant-numeric: tabular-nums; }
.board__name { font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board__pick { max-width: 100%; padding: 0; border: 0; background: none; color: inherit; font: inherit; font-weight: 650; text-align: left; cursor: pointer; }
.board__pick:hover { text-decoration: underline; }
.board__row.is-focus .board__pick::after { content: " · caméra"; color: var(--muted); font-weight: 500; font-size: 0.82rem; }
/* Un mot écrit par la feuille de styles se traduit par la langue de la page (`<html lang>`). */
:lang(en) .board__row.is-focus .board__pick::after { content: " · camera"; }
.board__hint { padding: 8px 16px 0; font-size: 0.85rem; }
.board__date { color: var(--muted); font-size: 0.82rem; }
/* Un rendez-vous en direct : les maillots du moment à côté du nom de leur porteur, et de quoi l'encourager. */
.board__jerseys { display: inline-flex; gap: 2px; margin-left: 4px; vertical-align: -3px; }
.board__jerseys:empty { display: none; }
.board__cheer { display: block; margin-top: 4px; padding: 2px 8px; font-size: 0.78rem; min-height: 0; }
/* Un maillot et qui le porte, sur une ligne. */
.worn { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.watch__news { display: grid; gap: 4px; }
.watch__news p { margin: 0; }
.board__speed { text-align: right; font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap; }
.board__gap { text-align: right; color: var(--muted); font-size: 0.82rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pulse { grid-column: 3 / -1; display: flex; align-items: center; gap: 5px; font-size: 0.82rem; font-variant-numeric: tabular-nums; }
.pulse__heart { display: inline-grid; }
.pulse__heart.is-beating { animation: beat var(--beat, 1s) ease-in-out infinite; }
.pulse__value { font-size: 0.95rem; min-width: 3ch; text-align: right; }
.pulse__unit { color: var(--muted); white-space: nowrap; }
.pulse__meter { flex: 1; height: 6px; margin-left: 6px; border-radius: 3px; background: var(--surface-2); overflow: hidden; }
.pulse__fill { display: block; width: 0; height: 100%; border-radius: 3px; transition: width 0.25s linear; }
@keyframes beat {
  0%, 42%, 100% { transform: scale(1); }
  12% { transform: scale(1.3); }
  24% { transform: scale(1.02); }
  33% { transform: scale(1.15); }
}
@media (prefers-reduced-motion: reduce) {
  .pulse__heart.is-beating { animation: none; }
  .runner.is-beating::after { content: none; }
}

.board__extra { grid-column: 3 / -1; color: var(--muted); font-size: 0.82rem; font-variant-numeric: tabular-nums; display: flex; gap: 12px; flex-wrap: wrap; }

.transport { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; padding: 14px 18px; }
.transport__bar { display: flex; align-items: center; gap: 12px 16px; flex-wrap: wrap; min-width: 0; }
.transport__clock { font-size: 1.5rem; font-weight: 650; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; min-width: 5.2ch; }
.transport__total { color: var(--muted); font-variant-numeric: tabular-nums; }
.transport__time { display: flex; align-items: baseline; gap: 6px; }
.transport__rates { margin-left: auto; }
/* Les réglages d'affichage, repliés sous les commandes : des cases que le navigateur retient. */
.options > summary { display: inline-flex; align-items: center; gap: 7px; width: fit-content; cursor: pointer; color: var(--muted); font-size: 0.9rem; font-weight: 550; list-style: none; }
.options > summary::-webkit-details-marker { display: none; }
.options > summary::after { content: "›"; font-size: 1.1rem; line-height: 1; transition: transform 0.15s; }
.options[open] > summary { color: var(--text); margin-bottom: 10px; }
.options[open] > summary::after { transform: rotate(90deg); }
.options__list { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; }
/* Les temps de passage : un coureur par colonne, son nom en tête et la date dessous ; la colonne des repères
   reste en place quand le tableau défile de côté. */
.splits th.num { vertical-align: bottom; }
.splits__date { display: block; color: var(--muted); font-size: 0.78rem; font-weight: 400; }
.splits th:first-child, .splits td:first-child { position: sticky; left: 0; z-index: 1; background: var(--surface); }
.play { width: 44px; height: 44px; border-radius: 50%; border: 0; background: var(--primary); color: var(--primary-text); display: grid; place-items: center; cursor: pointer; flex: none; }
.play:hover { opacity: 0.88; }
.play:disabled { opacity: 0.4; cursor: progress; }
.scrub { width: 100%; accent-color: var(--primary); margin: 0; }
.toggle { display: inline-flex; align-items: center; gap: 7px; font-size: 0.9rem; color: var(--muted); cursor: pointer; }

@media (max-width: 900px) {
  .race { grid-template-columns: 1fr; }
  .race__map { height: 56vh; min-height: 320px; }
  .board { overflow-y: visible; } /* le classement s'allonge avec la page : pas de défilement dans le défilement */
}
/* Sur un téléphone, la carte et ses commandes tiennent ensemble à l'écran : lecture et chrono, puis le curseur,
   les vitesses sur toute la largeur, les vues, et les réglages repliés. */
@media (max-width: 640px) {
  .race__map { height: clamp(260px, 46vh, 440px); min-height: 0; }
  .transport { padding: 12px 14px; }
  .transport__restart { margin-left: auto; }
  .transport__rates { order: 3; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); width: 100%; max-width: none; margin-left: 0; }
  .transport__rates .tab { padding-inline: 0; }
  .transport__views .tabs { flex: 1; min-width: 0; width: auto; }
  .options__list { display: grid; gap: 4px; }
  .options .toggle { min-height: 36px; }
  /* Quatre coureurs tiennent dans la largeur : le nom sous la pastille, le retard sous le temps. */
  .splits th, .splits td { padding: 8px 6px; }
  .splits th:first-child, .splits td:first-child { padding-left: 14px; }
  .splits th:last-child, .splits td:last-child { padding-right: 14px; }
  .splits td .faint { display: block; font-size: 0.78rem; }
  .splits__name { display: block; max-width: 68px; margin-left: auto; overflow: hidden; text-overflow: ellipsis; }
  .splits__date { display: none; }
}

details.more { margin-top: 16px; }
details.more > summary { cursor: pointer; color: var(--muted); font-weight: 550; padding: 4px 0; }
details.more[open] > summary { margin-bottom: 10px; }
details.more > p + p { margin-top: 6px; }
.stack > details.more.card { margin-top: 0; } /* une carte parmi d'autres : l'écart est celui de la pile */

/* --- Séance sur home trainer ------------------------------------------------ */

.ride__devices { display: grid; gap: 10px; }
.ride__device { display: grid; grid-template-columns: minmax(230px, auto) minmax(0, 1fr) auto; gap: 8px 14px; align-items: center; }
.ride__device .btn { justify-content: center; }
/* Les cases des appareils d'une séance (`.slots`) : une marque dit l'état de chaque mesure, et le texte dessous le dit
   aussi (la marque ne porte pas seule l'information). Pleine : reçue ; creuse : attendue ; en tirets : perdue ; un
   trait : rien pour la donner. */
.slot__mark { display: inline-block; width: 8px; height: 8px; margin-right: 6px; border: 1.5px solid var(--muted); border-radius: 50%; vertical-align: 1px; }
.slot[data-state="live"] .slot__mark { background: var(--text); border-color: var(--text); }
.slot[data-state="lost"] .slot__mark { border-style: dashed; }
.slot[data-state="none"] .slot__mark, .slot[data-state="off"] .slot__mark { height: 0; border-width: 1.5px 0 0; border-radius: 0; vertical-align: 0.3em; }
.slot[data-state="none"] .stat__value, .slot[data-state="off"] .stat__value { color: var(--muted); }
.slots__check { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.slots__check[hidden], .slots__ask[hidden] { display: none; }
.slots__ask { display: inline-flex; flex-wrap: wrap; gap: 8px; }
.diag__box { margin-top: 12px; }
.diag { font: 0.78rem/1.45 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: pre; overflow-x: auto; resize: vertical; }
@media (max-width: 640px) { .ride__device { grid-template-columns: 1fr; } }
/* Sur la ligne (`.lineup`), l'écran d'avant le départ : une ligne par choix, chacune repliée sur ce qu'elle vaut
   (`details.setting`), en blocs séparés d'un filet (les appareils, face à qui et les conditions, le reste). Sur un
   téléphone, le départ reste collé au pied de la fenêtre pendant que l'on prépare (`prep__go`). */
.lineup > .settings + .settings, .lineup > .settings + .card__body { border-top: 1px solid var(--line); }
.lineup > [data-ride-target="pending"] { border-bottom: 1px solid var(--line); }
.lineup .setting__value.rivals__line { gap: 4px 10px; }
.lineup .setting > summary { padding-top: 11px; padding-bottom: 11px; }
.setting__value--clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; overflow-wrap: normal; }
/* Ce que dit la ligne « Appareils » repliée : chacun avec sa marque, pleine quand il envoie, en tirets quand la
   liaison a sauté (la même que celle des cases). */
.gear { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 12px; }
.gear__item { display: inline-flex; align-items: center; gap: 6px; color: var(--text); }
.gear__mark { width: 8px; height: 8px; border: 1.5px solid var(--text); border-radius: 50%; background: var(--text); flex: none; }
.gear__item[data-state="lost"] .gear__mark { background: none; border-style: dashed; }
.gear__item[data-state="none"] { color: var(--muted); }
.gear__item[data-state="none"] .gear__mark { background: none; border-color: var(--faint); border-style: dashed; }
/* Face à qui : une case par passage, la pastille du coureur, son nom, son temps et sa date. */
.picks { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.pick { display: flex; align-items: center; gap: 9px; min-height: 40px; cursor: pointer; flex-wrap: wrap; }
.pick__who { font-weight: 600; }
.pick__what { font-size: 0.9rem; }
.prep__go { padding: 12px 20px 16px; border-top: 1px solid var(--line); }
/* L'accueil de Rouler : la barre des appareils (`.gearbar`, ou l'invitation à commencer par eux), ce qu'il y a à
   rouler maintenant (`.next`), puis les modes, en tuiles (`.mode`). */
.gearbar__bar { display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; padding-top: 12px; padding-bottom: 12px; }
.gearbar__bar .gear { min-width: 0; }
.gearbar__first { display: flex; align-items: center; justify-content: space-between; gap: 14px 24px; flex-wrap: wrap; }
.gearbar__first h2 { font-size: 1.05rem; }
.gearbar__first .stack { flex: 1 1 320px; gap: 4px; }
.next__body { display: grid; gap: 6px; justify-items: start; }
.next__kicker { font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
.next__title { font-size: 1.15rem; text-wrap: balance; }
.next__go { margin-top: 6px; }
.modes { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
.mode { display: grid; gap: 4px; align-content: start; padding: 16px 18px; text-decoration: none; color: var(--text); }
.mode:hover { border-color: var(--line-strong); }
/* Événements prend toute la largeur quand un rendez-vous roule ou part bientôt. */
.mode--wide { grid-column: 1 / -1; }
.mode__hint .bubbles { display: inline-flex; vertical-align: middle; margin: 0 0 0 4px; }
.mode__icon { display: grid; place-items: center; width: 38px; height: 38px; border-radius: 10px; background: var(--surface-2); margin-bottom: 6px; }
.mode__name { font-weight: 650; font-size: 1.02rem; }
.mode__hint { color: var(--muted); font-size: 0.9rem; }
.pending { display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; flex-wrap: wrap; }
.devices__go { justify-content: flex-start; }
/* Rouler : une entrée illustrée, puis les envies faciles à parcourir au pouce.
   Les accents des modes restent décoratifs : chaque destination porte son nom. */
.ride-home { gap: 20px; }
.ride-home__welcome { position: relative; isolation: isolate; overflow: hidden; display: flex; align-items: center; min-height: 188px; padding: 28px; border-radius: 22px; background: #143e46; color: #fff9e9; }
.ride-home__heading { position: relative; z-index: 1; max-width: 56%; }
.ride-home__eyebrow { display: block; margin-bottom: 8px; color: #ffdc91; font-size: 0.75rem; font-weight: 650; letter-spacing: 0.08em; text-transform: uppercase; }
.ride-home__heading h1 { font-size: clamp(2rem, 5vw, 2.7rem); line-height: 1.1; letter-spacing: -0.04em; }
.ride-home__heading p { margin-top: 10px; max-width: 34ch; color: #e0ece6; line-height: 1.5; }
.ride-home__landscape { position: absolute; right: 0; bottom: 0; width: 46%; height: 100%; object-fit: cover; opacity: 0.95; }
.ride-home__section { margin-bottom: -4px; font-size: 1.12rem; letter-spacing: -0.02em; }
.ride-home .next { border-color: var(--accent-line); background: linear-gradient(115deg, var(--accent-soft), var(--surface)); }
.ride-home .next__body { padding: 22px; }
.ride-home .next__kicker { display: inline-flex; align-items: center; gap: 6px; color: var(--accent); }
.ride-home .next__title { font-size: 1.3rem; }
.ride-home .next__go { min-height: 44px; }
.ride-home .modes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ride-home .mode { position: relative; min-width: 0; gap: 6px; padding: 18px; border-radius: 18px; transition: border-color 150ms, box-shadow 150ms; }
.ride-home .mode::after { content: "›"; position: absolute; top: 22px; right: 16px; color: var(--muted); font-size: 1.3rem; line-height: 1; }
.ride-home .mode:hover { border-color: var(--accent); box-shadow: 0 4px 16px color-mix(in srgb, var(--accent) 12%, transparent); }
.ride-home .mode:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.ride-home .mode__icon { width: 46px; height: 46px; border-radius: 14px; margin-bottom: 5px; background: color-mix(in srgb, var(--mode-color) 13%, var(--surface)); color: var(--mode-color); }
.ride-home .mode__name { line-height: 1.3; overflow-wrap: anywhere; }
.ride-home .mode__hint { line-height: 1.45; overflow-wrap: anywhere; }
.mode--segment { --mode-color: var(--accent); }
.mode--training { --mode-color: light-dark(#a64d16, #ffba82); }
.mode--free { --mode-color: light-dark(#23775b, #79d8b7); }
.mode--cols { --mode-color: light-dark(#687b23, #c8dc89); }
.mode--track { --mode-color: light-dark(#7b4bb3, #c9a4ff); }
.mode--games { --mode-color: light-dark(#b13868, #ff9bc3); }
.mode--events { --mode-color: light-dark(#217389, #8bd5e8); }
.ride-home__relay .card__head { align-items: center; }
@media (max-width: 640px) {
  .ride-home { gap: 16px; }
  .ride-home__welcome { min-height: 176px; padding: 22px 20px; border-radius: 20px; }
  .ride-home__heading { max-width: 68%; }
  .ride-home__heading p { font-size: 0.9rem; }
  .ride-home__eyebrow { font-size: 0.65rem; letter-spacing: 0.06em; }
  .ride-home__landscape { right: -60px; width: 240px; height: 154px; opacity: 0.85; z-index: 0; mask-image: linear-gradient(to right, transparent, #000 60%); }
  .ride-home .gearbar__first { padding: 16px; gap: 12px; }
  .ride-home .gearbar__first h2 { font-size: 0.95rem; }
  .ride-home .gearbar__first p { font-size: 0.85rem; }
  .ride-home .gearbar__first .row { width: 100%; }
  .ride-home .gearbar__first .btn--primary { flex: 1; justify-content: center; }
  .ride-home .gearbar .btn { min-height: 44px; }
  .ride-home .next__body { padding: 18px; }
  .ride-home .next__title { font-size: 1.15rem; }
  .ride-home .next__go { width: 100%; justify-content: center; }
  .ride-home .modes { gap: 10px; }
  .ride-home .mode { padding: 15px 13px; }
  .ride-home .mode__name { font-size: 0.98rem; }
  .ride-home .mode__hint { font-size: 0.8rem; }
  .ride-home .mode::after { right: 12px; top: 20px; }
  .ride-home .duo { gap: 20px; }
}
@media (prefers-reduced-motion: reduce) {
  .ride-home .mode { transition: none; }
}
/* Le catalogue des cols reprend l'invitation de Rouler et garde les profils mesurés au premier plan. */
.cols-catalog { gap: 22px; }
.cols-catalog__welcome { background: #233f50; min-height: 210px; }
.cols-catalog__total { display: inline-flex; align-items: center; gap: 7px; margin-top: 16px; padding: 6px 11px; border: 1px solid #6b888d; border-radius: 999px; color: #fff0c8; font-size: 0.8rem; }
.cols-catalog__finder { display: grid; gap: 10px; padding: 18px; min-width: 0; }
.cols-catalog__finder .search { max-width: none; margin: 0 0 4px; border-radius: 12px; background: var(--bg); }
.cols-catalog__finder .search__input { min-height: 46px; }
.cols-catalog__label { color: var(--muted); font-size: 0.75rem; font-weight: 650; }
.cols-catalog__finder .filters { margin: 0; gap: 8px; }
.cols-catalog__finder .filter { min-height: 44px; }
.cols-catalog__finder .filter.is-current { font-weight: 650; }
.cols-catalog__results { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.cols-catalog__results h2 { font-size: 1.12rem; letter-spacing: -0.02em; }
.cols-catalog__count { display: grid; place-items: center; min-width: 34px; min-height: 28px; padding: 2px 9px; border-radius: 999px; background: var(--surface-2); color: var(--accent); font-size: 0.85rem; font-weight: 650; }
.cols-catalog .grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); gap: 18px; }
.cols-catalog .col-card { --col-tone: var(--accent); padding: 0; gap: 0; border-radius: 20px; overflow: hidden; transition: border-color 150ms, box-shadow 150ms; }
.cols-catalog .col-card:hover { border-color: var(--col-tone); box-shadow: 0 6px 22px color-mix(in srgb, var(--col-tone) 14%, transparent); }
.cols-catalog .col-card:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.cols-catalog .col-card--alpes { --col-tone: light-dark(#286f99, #91ccea); }
.cols-catalog .col-card--pyrenees { --col-tone: light-dark(#437666, #97d4b5); }
.cols-catalog .col-card--provence { --col-tone: light-dark(#946c24, #f2ce8c); }
.cols-catalog .col-card--massif-central { --col-tone: light-dark(#686c34, #c2d090); }
.cols-catalog .col-card--vosges { --col-tone: light-dark(#47784d, #a2dba2); }
.cols-catalog .col-card--jura { --col-tone: light-dark(#5b6193, #b8bdea); }
.cols-catalog .col-card--toscane { --col-tone: light-dark(#a26748, #edbe9e); }
.cols-catalog .col-card--ardennes-flamandes { --col-tone: light-dark(#6f6a3a, #d6cf96); }
.cols-catalog .col-card--ardennes { --col-tone: light-dark(#5a6b45, #b9cf9e); }
.cols-catalog .col-card--ligurie { --col-tone: light-dark(#2d7480, #93d3dc); }
.cols-catalog .col-card--prealpes-lombardes { --col-tone: light-dark(#a0566b, #eeb4c5); }
.cols-catalog .col-card .seg__shape { isolation: isolate; padding: 14px 14px 4px; border-radius: 0; background: linear-gradient(160deg, color-mix(in srgb, var(--col-tone) 17%, var(--surface)), var(--surface)); }
.col-card__scenery { position: absolute; z-index: -1; inset: 18% 0 0; background: var(--col-tone); opacity: 0.07; clip-path: polygon(0 80%, 22% 14%, 40% 67%, 64% 0, 100% 76%, 100% 100%, 0 100%); }
.cols-catalog .col-card .cat-picto { top: 14px; left: 16px; }
.cols-catalog .col-card .seg__body { padding: 14px 18px 18px; gap: 8px; }
.cols-catalog .col-card .seg__kicker { color: var(--col-tone); }
.cols-catalog .col-card .seg__name { font-size: 1.12rem; letter-spacing: -0.02em; }
.cols-catalog .col-card .facts { margin: 4px 0; gap: 6px; }
.cols-catalog .col-card .fact { padding: 8px; border-radius: 10px; background: var(--surface-2); gap: 2px; }
.cols-catalog .col-card .seg__foot { margin-top: auto; padding-top: 8px; border-top: 1px solid var(--line); font-size: 0.8rem; }
.cols-catalog .col-card .seg__cta { background: var(--accent-soft); color: var(--accent); min-height: 36px; }
.cols-catalog__about { font-size: 0.9rem; }
@media (max-width: 640px) {
  .cols-catalog { gap: 16px; }
  .cols-catalog__welcome { min-height: 218px; }
  .cols-catalog__welcome .ride-home__heading { max-width: 80%; }
  .cols-catalog__welcome h1 { font-size: clamp(1.75rem, 8vw, 2.2rem); }
  .cols-catalog__welcome .ride-home__landscape { opacity: 0.6; }
  .cols-catalog__total { margin-top: 12px; font-size: 0.75rem; }
  .cols-catalog__finder { padding: 16px; gap: 8px; }
  .cols-catalog__finder .filters { margin-inline: -16px; padding: 2px 16px; scroll-padding-inline: 16px; }
  .cols-catalog__finder .filter { padding-inline: 12px; font-size: 0.85rem; }
  .cols-catalog .grid { gap: 14px; }
  .cols-catalog .col-card .seg__body { padding: 12px 16px 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .cols-catalog .col-card { transition: none; }
}
/* La piste (Velodrome) : ses épreuves, puis la séance, le vélodrome vu de dessus. */
.velo-event { display: grid; gap: 4px; align-content: start; padding: 16px 18px; }
.velo-event__art { display: grid; place-items: center; width: 38px; height: 38px; border-radius: 10px; background: var(--surface-2); margin-bottom: 6px; }
.velo-event__name { margin: 0; font-size: 1.05rem; }
.velo-event__name a { color: inherit; text-decoration: none; }
.velo-event__name a:hover { text-decoration: underline; }
.velo-event__facts, .velo-event__summary { margin: 0; }
.velo-event__summary { font-size: 0.92rem; }
.velo-event__marks { display: grid; gap: 4px; margin: 8px 0 0; padding: 10px 0 0; border-top: 1px solid var(--line); font-size: 0.9rem; }
.velo-event__marks div { display: flex; justify-content: space-between; gap: 12px; }
.velo-event__marks dt { color: var(--muted); }
.velo-event__marks dd { margin: 0; text-align: right; font-weight: 600; }
.velo-event__go { margin-top: 10px; }
.velo__stage { overflow: hidden; }
.velo__stage:fullscreen { display: flex; flex-direction: column; overflow-y: auto; border-radius: 0; }
.velo__cockpit { border-bottom: 1px solid var(--line); }
/* Des compteurs qui remplissent chaque rangée, quel que soit leur nombre (l'écart s'efface quand on roule seul). */
.velo__cockpit .cockpit__grid { display: flex; flex-wrap: wrap; }
.velo__cockpit .cockpit__tile { flex: 1 1 140px; }
.velo__track { position: relative; background: var(--surface-2); }
.velo__track canvas { display: block; width: 100%; }
.velo__track .velo__arena { aspect-ratio: 16 / 9; max-height: 68vh; }
.velo__stage:fullscreen .velo__arena { aspect-ratio: auto; height: 62vh; max-height: none; }
.velo__views { position: absolute; right: 10px; bottom: 10px; box-shadow: 0 1px 3px rgb(0 0 0 / 0.25); }
@media (max-width: 640px) { .velo__track .velo__arena { aspect-ratio: 4 / 3; } }
/* Ce que la séance annonce se pose au milieu de la piste, sur la pelouse, là où rien ne roule. */
.velo__note { position: absolute; top: 50%; left: 18%; right: 18%; transform: translateY(-50%); display: flex; justify-content: center; pointer-events: none; }
.velo__note .moment { padding: 7px 16px; font-size: 0.95rem; }
@media (max-width: 640px) { .velo__note { left: 12%; right: 12%; } .velo__note .moment { padding: 5px 12px; font-size: 0.82rem; } }
.velo__board { list-style: none; margin: 0; padding: 4px 0; columns: 2 260px; column-gap: 0; }
.velo__board:empty { display: none; }
.velo__board .board__row { grid-template-columns: auto minmax(0, 1fr) auto; break-inside: avoid; padding: 7px 16px; }
.velo__board .board__row + .board__row { border-top: 0; }
.velo__board .board__row.is-me { background: var(--surface-2); }
.velo__board .board__value { white-space: nowrap; }
.velo__controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; padding: 12px 16px; border-top: 1px solid var(--line); }

/* Les jeux (Game) : la liste des jeux, une tuile chacun, sa vignette en couleur ; puis la partie, sa scène, ce qui s'y
   lit d'un coup d'œil (l'objet, le bord de l'écran, l'annonce) et ses commandes à la taille d'un pouce. */
.games { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); gap: 14px; }
@media (max-width: 640px) { .games { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; } }
.game-tile { display: grid; grid-template-rows: auto 1fr; overflow: hidden; color: var(--text); text-decoration: none; }
.game-tile:hover { border-color: var(--line-strong); }
.game-tile:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
.game-tile__art { position: relative; display: block; }
/* Un jeu qui se joue aussi en direct le dit sur le coin de sa vignette. */
.game-tile__live { position: absolute; top: 8px; left: 8px; padding: 1px 8px; border-radius: 999px; background: var(--surface); color: var(--text);
                   font-size: 0.75rem; font-weight: 650; box-shadow: 0 1px 3px rgb(0 0 0 / 0.25); }
.game-tile__body { display: grid; align-content: start; gap: 3px; padding: 10px 12px 12px; }
.game-tile__name { margin: 0; font-size: 1.05rem; }
.game-tile__line { margin: 0; color: var(--muted); font-size: 0.86rem; line-height: 1.35; }
@media (max-width: 640px) {
  .game-tile__body { padding: 8px 10px 10px; }
  .game-tile__name { font-size: 0.95rem; }
  .game-tile__line { font-size: 0.8rem; }
}

/* Les vignettes des jeux ont leurs couleurs (2026-10-22, demandé tel quel : « Ajouter de la couleur ») : de petites
   scènes, comme le monde maquette, chacune avec son fond. Les mêmes en thème clair et en thème sombre ; le reste de la
   page reste en noir, blanc et gris. */
.game-art {
  display: block; width: 100%; height: auto; aspect-ratio: 2 / 1;
  --grass: #8cc66f; --bush: #5e9e4b; --field: #c7df8c; --field-2: #e9d27a; --meadow: #bfdc7e; --sky: #cfe8f6;
  --hill: #a7d18a; --dusk: #2f5b52; --tree: #234a42; --road: #4d535c; --paint: #fbfaf6; --ink: #24262b;
  --red: #e5484d; --blue: #3b82f6; --yellow: #f6c344; --orange: #f08a24; --teal: #129e9e; --cyan: #3fd0e0;
  --green: #22a06b; --purple: #8b5cf6; --pack: #a3abb5; --mud: #7a5a3a; --mud-2: #5f4229; --rope: #c8a46a;
  --wood: #d6a46a; --grain: #c39157; --track: #f5ecd6; --cereal: #e39a3a; --sun: #ffd166;
}
.game-art .grass { fill: var(--grass); }
.game-art .bush { fill: var(--bush); }
.game-art .field { fill: var(--field); }
.game-art .field-2 { fill: var(--field-2); }
.game-art .meadow { fill: var(--meadow); }
.game-art .sky { fill: var(--sky); }
.game-art .hill { fill: var(--hill); }
.game-art .dusk { fill: var(--dusk); }
.game-art .tree { fill: var(--tree); }
.game-art .sun { fill: var(--sun); }
.game-art .road, .game-art .kerb, .game-art .kerb-base, .game-art .lane { fill: none; stroke-linecap: round; }
.game-art .kerb-base { stroke: var(--paint); stroke-width: 24; }
.game-art .kerb { stroke: var(--red); stroke-width: 24; stroke-dasharray: 7 7; stroke-linecap: butt; }
.game-art .road { stroke: var(--road); stroke-width: 18; }
.game-art .lane { stroke: var(--paint); stroke-width: 1.5; stroke-dasharray: 6 6; opacity: 0.8; }
.game-art .flag { fill: var(--ink); }
.game-art .line-white { fill: var(--paint); }
.game-art .item { fill: var(--yellow); stroke: var(--ink); stroke-width: 2; }
.game-art .item-mark { fill: var(--ink); font: 800 16px system-ui, sans-serif; }
.game-art .peel { fill: var(--yellow); stroke: #8a6a12; stroke-width: 1.5; }
.game-art .rider { stroke: var(--paint); stroke-width: 2; }
.game-art .red { fill: var(--red); }
.game-art .blue { fill: var(--blue); }
.game-art .yellow { fill: var(--yellow); }
.game-art .orange { fill: var(--orange); }
.game-art .teal { fill: var(--teal); }
.game-art .cyan { fill: var(--cyan); }
.game-art .green { fill: var(--green); }
.game-art .purple { fill: var(--purple); }
.game-art .pack { fill: var(--pack); }
.game-art .slate { fill: var(--ink); stroke: var(--paint); stroke-width: 1.5; }
.game-art .slate-text { fill: var(--paint); font: 700 13px system-ui, sans-serif; }
.game-art .cone { fill: var(--orange); }
.game-art .cone-band { stroke: var(--paint); stroke-width: 2; }
.game-art .van { fill: var(--paint); stroke: var(--ink); stroke-width: 2; }
.game-art .van-glass { fill: #9fc6e0; }
.game-art .broom-stick { stroke: #8a5a2b; stroke-width: 2.5; stroke-linecap: round; }
.game-art .broom-head { fill: var(--yellow); stroke: #8a6a12; stroke-width: 1; }
.game-art .chase { fill: none; stroke: var(--paint); stroke-width: 2; stroke-dasharray: 3 5; stroke-linecap: round; opacity: 0.85; }
.game-art .radar { fill: none; stroke: var(--cyan); stroke-width: 1.5; opacity: 0.55; }
.game-art .mud { fill: var(--mud); }
.game-art .mud-2 { fill: var(--mud-2); }
.game-art .post { stroke: var(--paint); stroke-width: 3; stroke-linecap: round; }
.game-art .rope { fill: none; stroke: var(--rope); stroke-width: 3; stroke-linecap: round; }
.game-art .ribbon { fill: var(--red); }
.game-art .bike { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linejoin: round; }
.game-art .body, .game-art .arm { fill: none; stroke-linecap: round; }
.game-art .body { stroke-width: 7; }
.game-art .arm { stroke-width: 3; }
.game-art .body.red, .game-art .arm.red { stroke: var(--red); }
.game-art .body.blue, .game-art .arm.blue { stroke: var(--blue); }
.game-art .head { fill: #f0c9a4; stroke: var(--ink); stroke-width: 1; }
.game-art .wood { fill: var(--wood); }
.game-art .grain { stroke: var(--grain); stroke-width: 1.5; }
.game-art .track { fill: none; stroke: var(--track); stroke-width: 14; }
.game-art .cereal { fill: none; stroke: var(--cereal); stroke-width: 20; stroke-dasharray: 2 4; stroke-linecap: round; opacity: 0.85; }
.game-art .bowl { fill: var(--paint); stroke: var(--blue); stroke-width: 3; }
.game-art .milk { fill: #fffdf7; }
.game-art .mug { fill: var(--red); stroke: var(--ink); stroke-width: 1.5; }
.game-art .mug-handle { fill: none; stroke: var(--red); stroke-width: 3; }
.game-art .coffee { fill: #6b3f22; }
.game-art .jam { fill: #b3243a; }
.game-art .stage { fill: #262a45; }
.game-art .staff { stroke: rgb(255 255 255 / 0.14); stroke-width: 1; }
.game-art .beat-easy { fill: #3fbf7f; }
.game-art .beat-steady { fill: #f2b33d; }
.game-art .beat-hard { fill: #ef5a5a; }
.game-art .now { stroke: var(--paint); stroke-width: 2; opacity: 0.8; }
.game-art .trail { fill: none; stroke: var(--yellow); stroke-width: 4; stroke-linecap: round; }
.game-art .note { fill: none; stroke: var(--paint); stroke-width: 2.5; stroke-linejoin: round; }
.game-art .note-head { fill: var(--paint); }
.game-art .butter { fill: #f7e27a; stroke: #c9a83a; stroke-width: 1; }

.arcade__stage { overflow: hidden; }
.arcade__stage:fullscreen { display: flex; flex-direction: column; overflow-y: auto; border-radius: 0; }
.arcade__cockpit { border-bottom: 1px solid var(--line); }
.arcade__cockpit .cockpit__grid { display: flex; flex-wrap: wrap; }
.arcade__cockpit .cockpit__tile { flex: 1 1 120px; }
.arcade__cockpit .arcade__score { flex: 1.6 1 170px; } /* Rythme : un score de cinq chiffres et sa série */
.arcade__screen { position: relative; background: var(--surface-2); }
/* La scène et ce qui s'y pose ; les vues se tiennent dans son coin, ou dessous sur un téléphone. */
.arcade__frame { position: relative; }
.arcade__screen canvas { display: block; width: 100%; }
.arcade__world { aspect-ratio: 16 / 9; max-height: 70vh; }
.arcade__map { aspect-ratio: 16 / 10; max-height: 70vh; }
/* Au kart, en volume : le plan du circuit dans un coin. */
.arcade__screen .arcade__map--mini { position: absolute; top: 10px; right: 10px; width: 28%; max-width: 230px; aspect-ratio: 4 / 3; border: 1px solid var(--line-strong);
                     border-radius: 10px; box-shadow: 0 1px 4px rgb(0 0 0 / 0.25); pointer-events: none; }
.arcade__stage:fullscreen .arcade__world { aspect-ratio: auto; height: 68vh; max-height: none; }
.arcade__stage:fullscreen .arcade__map:not(.arcade__map--mini) { aspect-ratio: auto; height: 68vh; max-height: none; }
.arcade__views { position: absolute; right: 10px; bottom: 10px; box-shadow: 0 1px 3px rgb(0 0 0 / 0.25); }
.arcade__hud { position: absolute; inset: 0; pointer-events: none; }
.arcade__moment { position: absolute; top: 12px; left: 50%; transform: translateX(-50%); max-width: 70%; margin: 0; padding: 7px 16px; font-size: 0.95rem; text-align: center; }
.arcade__item { position: absolute; left: 10px; bottom: 10px; display: flex; align-items: center; gap: 10px; padding: 8px 12px 8px 8px;
                border: 1px solid var(--line-strong); border-radius: 12px; background: var(--surface); box-shadow: 0 1px 3px rgb(0 0 0 / 0.25); }
.arcade__item-art svg { display: block; width: 38px; height: 38px; fill: none; stroke: var(--muted); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.arcade__item.is-held .arcade__item-art svg { stroke: var(--text); stroke-width: 2.2; }
.arcade__item-name { font-weight: 650; font-size: 0.95rem; }
.arcade__item:not(.is-held) .arcade__item-name { color: var(--muted); font-weight: 500; }
/* La table : où l'on en est de l'écran. La jauge se vide à mesure qu'on s'en laisse distancer. */
.arcade__edge { position: absolute; left: 10px; bottom: 10px; display: grid; gap: 4px; min-width: min(60%, 300px); padding: 8px 12px;
                border: 1px solid var(--line-strong); border-radius: 12px; background: var(--surface); box-shadow: 0 1px 3px rgb(0 0 0 / 0.25); font-size: 0.88rem; }
.arcade__edge-bar { display: block; height: 8px; border-radius: 4px; background: var(--surface-2); overflow: hidden; border: 1px solid var(--line); }
.arcade__edge-bar span { display: block; height: 100%; width: 100%; background: var(--text); transition: width 0.2s linear; }
.arcade__edge.is-near .arcade__edge-bar span { background: var(--muted); }
.arcade__edge.is-near { border-style: dashed; }
.arcade__pad { display: grid; grid-template-columns: 1fr auto 1fr; gap: 10px; padding: 12px 16px; border-top: 1px solid var(--line); }
.arcade__pad .btn { min-height: 56px; justify-content: center; font-size: 1.02rem; }
.arcade__pad:not(:has(.arcade__use)) { grid-template-columns: 1fr 1fr; }
.arcade__use { min-width: 130px; }
.arcade__board { border-top: 1px solid var(--line); }
.arcade__keys { margin: 0; padding: 0 16px 12px; font-size: 0.85rem; }
@media (max-width: 640px) {
  .arcade__world { aspect-ratio: 4 / 3; }
  .arcade__map:not(.arcade__map--mini) { aspect-ratio: 1 / 1; }
  .arcade__screen .arcade__map--mini { width: 34%; }
  /* Sur un téléphone, la scène d'abord : des compteurs serrés, trois par rangée, et les vues sous la scène. */
  .arcade__cockpit .cockpit__tile { flex: 1 1 30%; padding: 8px 10px; }
  .arcade__cockpit .cockpit__tile .cockpit__value { font-size: 1.45rem; }
  .arcade__cockpit .cockpit__tile--main .cockpit__value { font-size: 1.9rem; }
  .arcade__cockpit .cockpit__label { font-size: 0.72rem; }
  .arcade__views { position: static; display: flex; width: max-content; margin: 8px 10px 8px auto; box-shadow: none; }
  /* L'annonce se range à gauche du plan du circuit, au-dessus de l'horizon : au milieu, elle cachait le coureur. */
  .arcade__moment { top: 10px; left: 10px; transform: none; max-width: calc(66% - 30px); width: max-content; padding: 5px 14px; justify-content: start; text-align: left; border-radius: 16px; }
  .arcade__hud .arcade__moment strong { font-size: 1.02rem; }
  .arcade__hud .arcade__moment span { font-size: 0.86rem; }
  .arcade__item { padding: 6px 10px 6px 6px; }
  .arcade__item-art svg { width: 30px; height: 30px; }
  .arcade__use { min-width: 0; }
}
@media (prefers-reduced-motion: reduce) { .arcade__edge-bar span { transition: none; } }
@media (max-width: 640px) {
  .modes { grid-template-columns: 1fr 1fr; gap: 10px; }
  .mode { padding: 14px; }
  .mode:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .next__go { width: 100%; justify-content: center; }
  .gearbar__first .btn--primary { flex: 1 1 100%; justify-content: center; }
  .devices__go .btn--primary { flex: 1 1 100%; justify-content: center; }
}
@media (max-width: 640px) {
  .prep__go { position: sticky; bottom: var(--foot); z-index: 5; padding: 10px 20px; border-radius: 0 0 var(--radius) var(--radius); background: var(--surface); }
  .prep__go .btn--primary { flex: 1 1 100%; }
  .prep__go .muted { font-size: 0.86rem; line-height: 1.35; }
  /* Prêt à partir, le bouton suffit : la consigne s'efface, la puissance reçue tient sur la ligne de l'essai. */
  .prep__go { gap: 6px 12px; padding-top: 8px; padding-bottom: 8px; }
  .prep__go:has([data-ride-target="start"]:not([disabled])) .prep__note { display: none; }
  .prep__go [data-ride-target="reading"] { font-size: 0.9rem; margin-left: auto; }
  .is-overlaid .prep__go { position: static; } /* une application iOS qui ne dit pas la hauteur de ses onglets */
}

/* Les compteurs : de gros chiffres, lisibles depuis le vélo, à un ou deux mètres de l'écran. */
.cockpit { overflow: hidden; }
.cockpit__banner { margin: 0; padding: 12px 20px; background: var(--primary); color: var(--primary-text); font-weight: 600; font-size: 1.1rem; }
/* Huit compteurs : quatre par ligne sur un écran large, deux sur un téléphone, jamais de case vide. */
.cockpit__grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px; background: var(--line); }
.cockpit__tile { background: var(--surface); padding: 12px 18px 14px; display: grid; grid-template-columns: auto 1fr; align-content: start; align-items: baseline; gap: 0 6px; min-width: 0; }
.cockpit__label { grid-column: 1 / -1; color: var(--muted); font-size: 0.85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cockpit__value { font-size: 2.6rem; line-height: 1.1; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cockpit__tile--main .cockpit__value { font-size: 3.4rem; }
.cockpit__unit { color: var(--muted); font-size: 0.95rem; white-space: nowrap; }
@media (max-width: 760px) {
  .cockpit__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cockpit__value { font-size: 2rem; }
  .cockpit__tile--main .cockpit__value { font-size: 2.6rem; }
}

/* Les compteurs et la route vue de côté prennent place dans le bloc de la course, au-dessus et au-dessous de la scène. */
.race__hud, .race__strip { grid-column: 1 / -1; min-width: 0; }
/* Un moment de la séance (une côte qui commence, l'écart à une borne) : annoncé quelques secondes. */
.moment { grid-column: 1 / -1; justify-self: center; display: flex; align-items: baseline; justify-content: center; gap: 2px 14px; flex-wrap: wrap; margin: 0; padding: 9px 24px; border-radius: 999px; background: var(--primary); color: var(--primary-text); text-align: center; animation: moment 0.35s ease-out; }
.moment[hidden] { display: none; }
.moment strong { font-size: 1.35rem; font-weight: 700; }
.moment span { font-size: 1.05rem; }
.moment span:empty { display: none; }
@keyframes moment { from { opacity: 0; transform: translateY(-8px); } }
@media (prefers-reduced-motion: reduce) { .moment { animation: none; } }
/* Les vitesses virtuelles (lib/gears.js) : le braquet du moment, et de quoi en changer, au doigt. Sous les compteurs
   dans la page ; en plein écran, au bord de la scène (voir plus bas). Le plus dur est en haut, ou à droite. */
.gearing { display: grid; gap: 8px; }
.gearing .fields { grid-template-columns: repeat(2, minmax(0, 9rem)); }
.gearbox { grid-column: 1 / -1; display: flex; flex-direction: row-reverse; justify-content: center; align-items: center; gap: 14px; }
.gearbox[hidden] { display: none; }
.gearbox__shift { display: grid; place-items: center; width: 56px; height: 56px; padding: 0; border: 1px solid var(--line-strong); border-radius: 50%; background: var(--surface); color: var(--text); font: 700 1.9rem/1 var(--sans); cursor: pointer; touch-action: manipulation; }
.gearbox__shift:active:not(:disabled) { background: var(--primary); color: var(--primary-text); }
.gearbox__shift:disabled { opacity: 0.35; cursor: default; }
.gearbox__gear { display: grid; justify-items: center; min-width: 76px; margin: 0; }
.gearbox__label, .gearbox__words { color: var(--muted); font-size: 0.8rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.gearbox__number { font-size: 2.2rem; line-height: 1.05; font-variant-numeric: tabular-nums; }
/* La résistance d'une sortie libre : la boîte du braquet, et ses trois modes (la route, une pente, une puissance).
   Le mode en cours se lit plein, et son nom est écrit : la couleur n'y est pas. */
.resist__modes { display: flex; gap: 4px; }
.resist__mode, .steer__skip { padding: 7px 11px; border: 1px solid var(--line-strong); border-radius: 999px; background: var(--surface); color: var(--text); font: 600 0.85rem/1 var(--sans); cursor: pointer; touch-action: manipulation; }
.steer__skip:active { background: var(--primary); border-color: var(--primary); color: var(--primary-text); }
.resist__mode.is-current { background: var(--primary); border-color: var(--primary); color: var(--primary-text); }
.resist__mode:disabled { opacity: 0.35; cursor: default; }
/* L'arrivée d'une séance, posée sur la scène restée en plein écran : le temps en grand, ce qu'il vaut, la suite.
   Elle entre en scène après la caméra, qui passe d'abord devant le coureur. Dans la page, le résultat a sa carte. */
.finale { display: none; }
.race.is-immersive .finale:not([hidden]) { grid-area: 1 / 1 / 3 / 2; z-index: 4; align-self: end; justify-self: center; display: grid; justify-items: center; gap: 3px; width: min(540px, calc(100% - 28px)); margin: 0 0 16px; padding: 16px 24px 18px; border: 1px solid var(--line); border-radius: 16px; background: color-mix(in srgb, var(--surface) 90%, transparent); backdrop-filter: blur(10px); box-shadow: 0 6px 24px rgb(0 0 0 / 25%); text-align: center; animation: finale 0.6s 1.6s ease-out both; }
.finale p, .finale dl, .finale dd { margin: 0; }
.finale__title { color: var(--muted); font-size: 0.9rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; }
.finale__time { font-size: clamp(2.6rem, 7vw, 4.4rem); line-height: 1.05; font-weight: 750; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.finale__verdict { font-size: 1.15rem; font-weight: 650; }
.finale__best { color: var(--muted); }
/* Les segments franchis au fil d'un parcours, à l'arrivée d'une séance : un par ligne, son temps en regard. */
.crossed { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.finale__best:empty, .finale__status:empty { display: none; }
.finale__facts { display: flex; justify-content: center; gap: 6px 26px; flex-wrap: wrap; margin-top: 8px; }
.finale__facts dt { color: var(--muted); font-size: 0.8rem; }
.finale__facts dd { font-size: 1.15rem; font-weight: 650; font-variant-numeric: tabular-nums; }
.finale__status { margin-top: 6px; color: var(--muted); font-size: 0.88rem; }
.finale__actions { display: flex; justify-content: center; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
@keyframes finale { from { opacity: 0; transform: translateY(14px); } }
/* La photo d'arrivée : sa vignette, et de quoi la partager ou l'enregistrer. */
.photo { display: grid; gap: 8px; justify-items: center; margin-top: 10px; }
.photo[hidden] { display: none; }
.photo__image { width: min(100%, 360px); aspect-ratio: 16 / 9; border-radius: 10px; border: 1px solid var(--line); object-fit: cover; background: var(--surface-2, var(--line)); }
.photo__image--tall { width: auto; height: min(300px, 34vh); aspect-ratio: 4 / 5; } /* prise sur un téléphone tenu droit */
.finale .photo__image--tall { height: min(170px, 20vh); } /* le tableau d'arrivée doit tenir sous le coureur */
.photo__actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.card .photo { justify-items: start; }
.card .photo__actions { justify-content: start; }
@media (prefers-reduced-motion: reduce) { .race.is-immersive .finale:not([hidden]) { animation: none; } }
/* Dans une fenêtre large, ou basse (un téléphone couché), le tableau se range sur le côté gauche, le classement
   restant à droite : le coureur garde le milieu de la scène. Ailleurs il s'étale au pied de la scène, et la
   caméra cadre le coureur au-dessus de lui (voir `shade`, dans le contrôleur `ride`). */
@media (min-width: 900px), (max-height: 520px) {
  .race.is-immersive .finale:not([hidden]) { align-self: center; justify-self: start; width: min(340px, 44%); margin: 0 0 0 max(16px, env(safe-area-inset-left)); }
}
@media (max-height: 520px) {
  .race.is-immersive .finale:not([hidden]) { padding: 10px 14px 12px; }
  .finale__time { font-size: 2.2rem; }
  .finale__verdict { font-size: 1rem; }
  .finale__facts { display: none; }
  .finale .photo__image { display: none; }
}
.ridebar { overflow: hidden; }
.ridebar__head { display: flex; align-items: baseline; justify-content: space-between; gap: 2px 16px; flex-wrap: wrap; padding: 9px 16px 0; font-size: 0.88rem; }
.ridebar__controls { display: flex; align-items: center; justify-content: flex-end; gap: 8px 14px; flex-wrap: wrap; padding: 9px 16px; border-top: 1px solid var(--line); }
.ridebar__tryout { display: grid; gap: 4px; flex: 1; min-width: 220px; margin-right: auto; font-size: 0.9rem; color: var(--muted); }
.race:not(.is-immersive) .ridebar__controls .tabs { display: none; } /* dans la page, les vues se choisissent juste dessous */

/* La route vue de côté (lib/sideview.js) : le relief sur un canevas, les coureurs posés dessus. Le point de la
   route est l'origine de chaque coureur ; son écart s'écrit dessous. */
.sideview { position: relative; height: 150px; overflow: hidden; }
.sideview canvas { display: block; width: 100%; height: 100%; }
.sideview__rider { position: absolute; top: 0; left: 0; width: 0; height: 0; will-change: transform; }
.sideview__rider .runner { position: absolute; top: -13px; left: -13px; }
.sideview__rider.is-away { opacity: 0.7; }
.sideview__note { position: absolute; top: 7px; left: 0; transform: translateX(-50%); padding: 0 6px; border: 1px solid var(--line-strong); border-radius: 9px; background: var(--surface); font-size: 0.78rem; font-weight: 650; line-height: 1.5; white-space: nowrap; font-variant-numeric: tabular-nums; }
.sideview__note--left { left: -12px; transform: none; }
.sideview__note--right { left: 12px; transform: translateX(-100%); }

/* Pendant qu'on roule, la course occupe toute la fenêtre : la scène, les compteurs posés sur son ciel, le classement
   sur son côté, la route vue de côté à son pied. Les commandes de la carte se rangent sous les compteurs, dont
   la séance donne la hauteur (--hud). */
html.is-riding { overflow: hidden; }
.race.is-immersive { position: fixed; inset: 0; z-index: 1000; gap: 0; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) auto; background: var(--bg); }
.race.is-immersive .race__stage { grid-area: 1 / 1 / 3 / 2; display: grid; min-height: 0; }
.race.is-immersive .race__map { height: auto; min-height: 0; border: 0; border-radius: 0; }
.race.is-immersive .race__hud { grid-area: 1 / 1; z-index: 2; border: 0; border-radius: 0; box-shadow: none; background: color-mix(in srgb, var(--surface) 78%, transparent); backdrop-filter: blur(8px); }
.race.is-immersive .race__side { grid-area: 2 / 1; z-index: 2; justify-self: end; align-self: start; width: 290px; max-height: calc(100% - 46px); margin: 10px; background: color-mix(in srgb, var(--surface) 86%, transparent); backdrop-filter: blur(8px); }
.race.is-immersive .board__hint { display: none; }
/* Dans l'application, la séance prend tout l'écran : la scène file sous l'encoche et les bords arrondis, les
   compteurs, le classement et les commandes restent en deçà. */
.is-native .race.is-immersive .race__hud { padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left); }
.is-native .race.is-immersive .race__strip { padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); }
.is-native .race.is-immersive .race__side { margin-right: calc(10px + env(safe-area-inset-right)); }
.race.is-immersive .race__main:has(.leaflet-container:not([hidden])) ~ .race__side { margin-top: 54px; } /* sous le sélecteur de fond */
/* En plein écran, la carte redevient une case de la grille, et les commandes de lecture s'effacent : la séance a les siennes. */
.race.is-immersive .race__main { display: contents; }
.race.is-immersive .transport { display: none; }
.race.is-immersive .moment { grid-area: 2 / 1; z-index: 3; align-self: start; margin-top: 14px; max-width: calc(100% - 28px); box-shadow: 0 2px 10px rgb(0 0 0 / 30%); }
/* Les vitesses virtuelles, à portée de pouce : dans le coin en bas à gauche de la scène, le seul où rien ne se pose
   (les annonces sont en haut, les commandes des cartes en haut à gauche, leurs mentions en bas à droite, le
   classement à droite). Au milieu du bord, une annonce cachait le bouton + sur un téléphone tenu droit. */
.race.is-immersive .gearbox { grid-area: 2 / 1; z-index: 3; justify-self: start; align-self: end; flex-direction: column; gap: 8px; margin: 0 0 12px 12px; padding: 10px 8px; border-radius: 999px; background: color-mix(in srgb, var(--surface) 82%, transparent); backdrop-filter: blur(8px); box-shadow: 0 2px 10px rgb(0 0 0 / 25%); }
.is-native .race.is-immersive .gearbox { margin-left: calc(12px + env(safe-area-inset-left)); }
/* Le profil de toute la route, en surimpression au pied de la scène pendant qu'on roule, comme sur un replay
   (lib/route_strip.js) : ce qui reste à rouler voilé, ce qui est roulé plus franc, chacun à sa place. Rien ne s'y
   touche. Au-dessus de la mention de la carte, à droite des vitesses virtuelles quand on les a ; effacé à
   l'arrivée, sous le tableau. La caméra cadre le coureur au-dessus de lui (`shade`, contrôleur `ride`). */
.routestrip { display: none; }
.race.is-immersive .routestrip:not([hidden]) { grid-area: 2 / 1; z-index: 2; align-self: end; position: relative; isolation: isolate; display: block; height: 52px; margin: 0 16px 28px; border-radius: 12px; background: color-mix(in srgb, var(--surface) 55%, transparent); backdrop-filter: blur(6px); box-shadow: 0 2px 10px rgb(0 0 0 / 18%); pointer-events: none; }
.race.is-immersive:has(.finale:not([hidden])) .routestrip { display: none; }
.race.is-immersive:has(.gearbox:not([hidden])) .routestrip { margin-left: 120px; }
.is-native .race.is-immersive .routestrip { margin-inline: calc(16px + env(safe-area-inset-left)) calc(16px + env(safe-area-inset-right)); }
.race.is-immersive:has(.routestrip:not([hidden])) .scene__loading { bottom: 96px; }
.race.is-immersive:has(.routestrip:not([hidden])) .race__side { max-height: calc(100% - 100px); } /* le classement s'arrête au-dessus */
.routestrip__relief { position: absolute; inset: 0; width: 100%; height: 100%; fill: color-mix(in srgb, var(--text) 20%, transparent); }
.routestrip__relief--ridden { fill: color-mix(in srgb, var(--text) 52%, transparent); }
.routestrip__dot { position: absolute; min-width: 19px; height: 19px; padding: 0 3px; border-radius: 10px; font-size: 0.68rem; transform: translate(-50%, -50%); box-shadow: 0 0 0 1.5px var(--surface); }
.race.is-immersive .resist, .race.is-immersive .steer { border-radius: 22px; }
.race.is-immersive .resist__modes { flex-direction: column; }
.race.is-immersive .race__strip { grid-area: 3 / 1; border: 0; border-top: 1px solid var(--line); border-radius: 0; box-shadow: none; }
.race.is-immersive .leaflet-top { top: var(--hud, 0); }
.race.is-immersive .scene__zoom { top: calc(var(--hud, 0px) + 10px); }
.race.is-immersive .sideview { height: clamp(112px, 19vh, 180px); }
/* Une séance guidée, au pied de la scène à la place de la route vue de côté : un bloc par palier, le trait du
   seuil, ce qui est fait en plus sombre jusqu'au curseur (lib/workout.js), dans les couleurs des zones de puissance. */
.planstrip { height: 96px; padding: 8px 16px 10px; }
.planstrip__svg { display: block; width: 100%; height: 100%; }
.planstrip__done { fill: #000; fill-opacity: .22; }
.planstrip__ftp { stroke: var(--text); stroke-width: 1; stroke-dasharray: 4 4; vector-effect: non-scaling-stroke; }
.planstrip__cursor { stroke: var(--text); stroke-width: 2; vector-effect: non-scaling-stroke; }
/* La puissance tenue, par-dessus ce qui était demandé. */
.planstrip__held { fill: none; stroke: var(--text); stroke-width: 2; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
/* Les paliers d'une séance guidée, sous la scène : celui qu'on roule, et ceux qui sont faits. */
.workout-steps tr[aria-current] td { background: var(--surface-2); font-weight: 600; }
.workout-steps tr.is-done td { color: var(--muted); }
.race.is-immersive .planstrip { height: clamp(80px, 14vh, 130px); }
.race.is-immersive .cockpit__banner { font-size: 1.35rem; text-align: center; }
/* Huit compteurs sur une ligne ; le dernier, plus large, loge le nom de celui à qui l'on se mesure. */
.race.is-immersive .cockpit__grid { grid-template-columns: repeat(7, minmax(0, 1fr)) minmax(0, 1.5fr); gap: 0; background: none; }
@media (min-width: 901px) {
  .race.is-immersive .cockpit__grid:has([data-ride-target="shelterTile"]:not([hidden])) { grid-template-columns: repeat(8, minmax(0, 1fr)) minmax(0, 1.5fr); } /* un compteur de plus : l'abri */
  .race.is-immersive .cockpit__grid:has([data-ride-target="windTile"]) { grid-template-columns: repeat(8, minmax(0, 1fr)) minmax(0, 1.5fr); } /* ou le vent */
  .race.is-immersive .cockpit__grid:has([data-ride-target="windTile"]):has([data-ride-target="shelterTile"]:not([hidden])) { grid-template-columns: repeat(9, minmax(0, 1fr)) minmax(0, 1.5fr); } /* ou les deux */
}
.race.is-immersive .cockpit__tile { padding: 8px 12px 10px; background: none; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.race.is-immersive .cockpit__label { font-size: 0.8rem; }
.race.is-immersive .cockpit__value { font-size: clamp(1.5rem, 2.9vw, 2.9rem); }
.race.is-immersive .cockpit__tile--main .cockpit__value { font-size: clamp(1.8rem, 3.6vw, 3.6rem); }
@media (max-width: 900px) {
  .race.is-immersive .race__side { display: none; }
  .race.is-immersive .cockpit__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .race.is-immersive .cockpit__tile { padding: 6px 10px 8px; }
  .race.is-immersive .cockpit__value { font-size: clamp(1.25rem, 5.6vw, 2.2rem); }
  .race.is-immersive .cockpit__tile--main .cockpit__value { font-size: clamp(1.4rem, 6.4vw, 2.6rem); }
  .race.is-immersive .cockpit__unit { font-size: 0.8rem; }
}
/* Sur un téléphone, la légende de la route vue de côté laisse sa place à la scène : on la lit avant de partir. */
@media (max-width: 900px) {
  .race.is-immersive .ridebar__head [data-ride-target="caption"] { display: none; }
}
/* Un téléphone couché : peu de hauteur. Les compteurs tiennent sur une ligne, la route vue de côté se tasse et les
   commandes tiennent sur une rangée, pour laisser la scène se voir. Les boutons « Réduire » et « Arrêter » restent
   à l'écran : ce sont les vues qui défilent. Avant, les compteurs recouvraient toute la scène, et ces boutons
   sortaient de l'écran. */
@media (max-height: 520px) and (orientation: landscape) {
  .race.is-immersive .cockpit__grid { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .race.is-immersive .cockpit__tile { padding: 4px 8px 5px; }
  .race.is-immersive .cockpit__label { font-size: 0.68rem; }
  .race.is-immersive .cockpit__value, .race.is-immersive .cockpit__tile--main .cockpit__value { font-size: clamp(1.05rem, 3vw, 1.7rem); }
  .race.is-immersive .cockpit__unit { font-size: 0.68rem; }
  .race.is-immersive .cockpit__banner { padding: 4px 12px; font-size: 1rem; }
  .race.is-immersive .moment { margin-top: 6px; padding: 5px 16px; }
  .race.is-immersive .moment strong { font-size: 1.05rem; }
  .race.is-immersive .moment span { font-size: 0.9rem; }
  .race.is-immersive .sideview { height: 68px; }
  .race.is-immersive .gearbox { flex-direction: row-reverse; gap: 6px; margin-bottom: 8px; padding: 5px; } /* couchée : sous le zoom des cartes */
  .race.is-immersive .routestrip:not([hidden]) { height: 38px; margin-bottom: 22px; }
  .race.is-immersive:has(.routestrip:not([hidden])) .race__side { max-height: calc(100% - 80px); }
  .race.is-immersive:has(.gearbox:not([hidden])) .routestrip { margin-left: 212px; }
  .race.is-immersive .resist__modes { flex-direction: row; }
  .race.is-immersive .gearbox__shift { width: 46px; height: 46px; font-size: 1.6rem; }
  .race.is-immersive .gearbox__number { font-size: 1.5rem; }
  .race.is-immersive .gearbox__label { display: none; }
  .race.is-immersive .ridebar__head { padding: 3px 12px 0; font-size: 0.8rem; }
  .race.is-immersive .ridebar__controls { flex-wrap: nowrap; justify-content: flex-start; padding: 5px 12px; }
  .race.is-immersive .ridebar__controls > * { flex: none; }
  .race.is-immersive .ridebar__controls .tabs { flex: 0 1 auto; flex-wrap: nowrap; min-width: 110px; margin-left: auto; overflow-x: auto; scrollbar-width: none; }
  .race.is-immersive .ridebar__controls .tabs::-webkit-scrollbar { display: none; }
  .race.is-immersive .ridebar__controls .tab { flex: none; white-space: nowrap; }
  .race.is-immersive .ridebar__tryout { flex: 0 1 190px; min-width: 120px; margin-right: 0; }
}

/* La rencontre : se comparer à ceux qui sont là, en rapprochant les téléphones. Les ondes disent que le téléphone
   se signale autour de lui ; la liste, qui est là ; le code QR reste noir sur blanc quel que soit le thème, sans
   quoi un appareil photo ne le lit pas. */
.meet { display: grid; gap: 8px; justify-items: center; text-align: center; padding-top: 24px; }
.meet__waves { position: relative; display: grid; place-items: center; width: 60px; height: 60px; margin-bottom: 4px; }
.meet__waves::after { content: ""; width: 12px; height: 12px; border-radius: 50%; background: var(--text); }
.meet__waves span { position: absolute; inset: 0; border: 2px solid var(--text); border-radius: 50%; opacity: 0; animation: ripple 2.4s ease-out infinite; }
.meet__waves span:nth-child(2) { animation-delay: 0.8s; }
.meet__waves span:nth-child(3) { animation-delay: 1.6s; }
@keyframes ripple {
  0% { transform: scale(0.2); opacity: 0.7; }
  100% { transform: scale(1); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .meet__waves span { animation: none; opacity: 0.22; }
  .meet__waves span:nth-child(2) { inset: 10px; }
  .meet__waves span:nth-child(3) { inset: 19px; }
}
.meet__list { list-style: none; margin: 0; padding: 0; display: grid; }
.meet__list + .card__body { border-top: 1px solid var(--line); }
.meet__who { display: flex; align-items: center; gap: 6px 10px; flex-wrap: wrap; min-height: 50px; padding: 8px 20px; }
.meet__who + .meet__who { border-top: 1px solid var(--line); }
.meet__act { margin: 0 0 0 auto; }
.meet__list--near { width: 100%; margin-top: 8px; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; text-align: left; }
.meet__list--near .meet__who { padding: 8px 12px; }
.meet__who.is-close { background: var(--surface-2); }
/* Le code à montrer : le QR et les six caractères côte à côte, ce qu'il faut en savoir dessous. */
.meet__pass { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 14px 22px; align-items: center; }
.meet__id { display: grid; gap: 6px; }
.meet__ask { font-size: 1rem; font-weight: 650; line-height: 1.35; }
.meet__about { grid-column: 1 / -1; display: grid; gap: 10px; }
.qr { flex: none; border-radius: 8px; }
.meet__code { font-size: 2rem; font-weight: 700; letter-spacing: 0.12em; line-height: 1.1; }
/* Seul sur l'écran : on attend qu'un autre arrive. Le point bat doucement ; rien ne bouge si le système demande
   moins d'animations. */
.meet__waiting { display: flex; align-items: baseline; gap: 8px; padding-top: 10px; border-top: 1px solid var(--line); font-size: 0.92rem; text-align: left; }
.meet__pulse { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--text); animation: waiting 1.6s ease-in-out infinite; }
@keyframes waiting { 50% { opacity: 0.25; } }
/* Le téléphone en relais (lib/relay.js) : sur la page de séance, ce qu'il en est et comment le mettre en service ;
   sur le téléphone, sa page (à qui il sert, ce qu'il fait passer, la demande d'un appareil à choisir). */
.relay { display: grid; gap: 8px; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius); }
.relay[hidden] { display: none; }
.relay.is-on { border-color: var(--text); }
.relay__status { display: flex; align-items: center; gap: 8px; margin: 0; }
.relay .row:not(:has(.btn:not([hidden]))) { display: none; }
.relay__how { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; padding-top: 8px; }
.relay__how > div { flex: 1 1 16rem; }
.relay__state { display: flex; align-items: center; gap: 10px; margin: 0 0 6px; font-size: 1.15rem; }
.relay__mark { flex: none; width: 12px; height: 12px; border: 2px solid var(--muted); border-radius: 50%; }
.relay__mark[data-state="ready"] { border-color: var(--text); }
.relay__mark[data-state="on"] { border-color: var(--text); background: var(--text); animation: waiting 1.6s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .relay__mark[data-state="on"] { animation: none; } }
.relay__ask { display: grid; gap: 10px; margin-top: 14px; padding: 14px; border-radius: var(--radius); background: var(--surface-2); }
.relay__ask[hidden] { display: none; }
.relay__ask p { margin: 0; }
.relay__devices { display: grid; margin: 14px 0 0; padding: 0; list-style: none; }
.relay__devices[hidden] { display: none; }
.relay__device { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 12px; padding: 10px 0; border-top: 1px solid var(--line); }
.relay__steps { display: grid; gap: 8px; margin: 0 0 12px; padding-left: 20px; }
@media (prefers-reduced-motion: reduce) { .meet__pulse { animation: none; } }
.meet__entry { text-transform: uppercase; letter-spacing: 0.1em; font-weight: 600; }
.meet__entry::placeholder { font-weight: 400; }
.meet__times { list-style: none; margin: 4px 0 2px; padding: 0; display: grid; gap: 3px; max-width: 300px; font-size: 0.92rem; }
.meet__times li { display: flex; align-items: center; gap: 8px; }
.meet__times strong { margin-left: auto; }
/* L'écart au premier, en petit, dans une colonne de même largeur pour que les temps restent alignés. */
.meet__gap { min-width: 4.6em; color: var(--muted); font-size: 0.82rem; text-align: right; }
/* Le bilan d'une rencontre : une ligne par présent, le nombre de segments gagnés en face. */
.tally-board { margin: 0; }
.tally-board .feed__row { align-items: center; }
progress.meter { display: block; width: 100%; height: 6px; accent-color: var(--primary); }
@media (max-width: 640px) {
  .meet__pass { gap: 12px 16px; }
  .meet__pass .qr { width: 148px; height: 148px; }
  .meet__pass .meet__code { font-size: 1.6rem; letter-spacing: 0.08em; }
  .meet__entry { font-size: 16px; } /* en deçà, iOS grossit la page au toucher */
}

/* --- Sorties à plusieurs --------------------------------------------------- */

/* Les maillots : un dessin cerné de la couleur du texte, pour se détacher d'une carte claire comme d'une carte
   sombre. Ils se distinguent sans leur couleur (uni, à pois) et leur nom est toujours écrit à côté. */
.jersey { display: block; flex: none; }
.jersey__cloth { fill: var(--jersey-white); stroke: var(--text); stroke-width: 1.2; stroke-linejoin: round; }
.jersey--yellow .jersey__cloth { fill: var(--jersey-yellow); }
.jersey__dot { fill: var(--jersey-dots); }
.badge--jersey { display: inline-flex; align-items: center; gap: 4px; vertical-align: middle; }
.jersey-head { display: flex; align-items: center; gap: 12px; }

/* Les deux maillots de la sortie, et qui les porte. */
.jerseys { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.jerseys__card { display: flex; align-items: center; gap: 14px; padding: 16px 18px; text-decoration: none; -webkit-tap-highlight-color: transparent; }
.jerseys__card:hover { border-color: var(--line-strong); }
.jerseys__text { display: grid; gap: 1px; min-width: 0; }
.jerseys__name { font-size: 0.82rem; font-weight: 650; text-transform: uppercase; letter-spacing: 0.04em; }
.jerseys__text > .muted { font-size: 0.88rem; }
.jerseys__who { display: flex; flex-wrap: wrap; gap: 2px 12px; margin-top: 5px; font-size: 1.1rem; }
@media (max-width: 760px) {
  .jerseys { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .jerseys__card { padding: 12px 16px; }
}

/* Une sortie dans une liste : quand, qui, et qui porte chaque maillot. Toute la carte se touche. */
.outing { display: flex; align-items: center; gap: 12px 18px; padding: 14px 16px; text-decoration: none; -webkit-tap-highlight-color: transparent; }
.outing:hover { border-color: var(--line-strong); }
.outing:active { background: var(--surface-2); }
.outing__body { flex: 1 1 240px; min-width: 0; display: grid; gap: 3px; }
.outing__title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-weight: 650; line-height: 1.3; }
.outing__mine { font-size: 0.92rem; font-weight: 550; }
.outing__jerseys { flex: 0 1 190px; display: grid; gap: 4px; min-width: 0; margin: 0; padding: 0; list-style: none; font-size: 0.92rem; font-weight: 550; }
.outing__jerseys li { display: flex; align-items: center; gap: 8px; min-width: 0; }
.outing__jerseys li > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* La liste des sorties d'un groupe : un intertitre par mois, avec le nombre de sorties du mois. */
.list__month { display: flex; justify-content: space-between; align-items: baseline; gap: 2px 14px; flex-wrap: wrap; margin: 0 2px -4px; color: var(--muted); font-size: 0.86rem; font-weight: 600; letter-spacing: 0; }
.list__month > span:first-child { color: var(--text); }
.list__month:not(:first-child) { margin-top: 10px; }
/* Le palmarès : une ligne par coureur, ses maillots et ses sorties en colonnes étroites, qui tiennent dans la
   largeur d'un téléphone. Le tableau replié dessous garde les mêmes colonnes. */
.honours__table { table-layout: fixed; }
.honours__col { width: 3.4em; }
.honours__col--rank { width: 2.8em; }
.honours__col--wide { width: 4.8em; }
.honours__table th, .honours__table td { padding-inline: 8px; }
.honours__table th:first-child, .honours__table td:first-child { padding-left: 20px; }
.honours__table th:last-child, .honours__table td:last-child { padding-right: 20px; }
.honours__table th .jersey { vertical-align: middle; }
.honours__table tr.is-me { background: var(--surface-2); }
.honours__rank { color: var(--muted); font-weight: 600; }
.honours__who { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.honours__who .chip { display: inline-flex; max-width: 100%; vertical-align: middle; }
.honours__who .chip > span { overflow: hidden; text-overflow: ellipsis; }
.honours .card__foot { font-size: 0.86rem; }
@media (max-width: 640px) {
  .honours__table th:first-child, .honours__table td:first-child { padding-left: 16px; }
  .honours__table th:last-child, .honours__table td:last-child { padding-right: 16px; }
}
.feed .outing { border: 0; border-radius: 0; box-shadow: none; background: none; padding: 12px 20px; }
.feed li + li .outing { border-top: 1px solid var(--line); }
@media (max-width: 640px) {
  .outing { flex-wrap: wrap; position: relative; padding-right: 36px; }
  .outing__jerseys { flex: 1 1 100%; grid-auto-flow: column; grid-auto-columns: minmax(0, max-content); gap: 4px 14px; justify-content: start; }
  .outing > .seg__go { position: absolute; top: 16px; right: 12px; }
  .feed .outing { padding-right: 40px; }
}

/* Un segment de la sortie : ce qu'il est, puis le temps de chacun, le plus rapide d'abord, avec ce qu'il y gagne. */
.leg { padding: 14px 20px 12px; }
.leg + .leg { border-top: 1px solid var(--line); }
.leg__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px 16px; }
.leg__head h3 a { text-decoration: none; }
.leg__head h3 a:hover { text-decoration: underline; }
.leg__head p { margin-top: 2px; font-size: 0.9rem; }
.leg__rows { list-style: none; margin: 10px 0 0; padding: 0; display: grid; }
.leg__row { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto 64px 84px; align-items: center; gap: 4px 12px; padding: 6px 0; }
.leg__row + .leg__row { border-top: 1px solid var(--line); }
.leg__rank { color: var(--muted); font-weight: 600; }
.leg__who { display: flex; align-items: center; gap: 8px; min-width: 0; }
.leg__prizes { grid-column: 3; display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.leg__time, .leg__gap { text-align: right; white-space: nowrap; }
.leg__time { grid-column: 4; }
.leg__gap { grid-column: 5; font-size: 0.88rem; }
/* Sur un téléphone, deux lignes par coureur : son rang, son nom et son temps ; puis ce qu'il gagne, et son écart. */
@media (max-width: 640px) {
  .leg { padding: 12px 16px 10px; }
  .leg__row { grid-template-columns: 22px minmax(0, 1fr) auto; }
  .leg__time { grid-column: 3; grid-row: 1; }
  .leg__prizes { grid-column: 2; grid-row: 2; justify-content: flex-start; }
  .leg__gap { grid-column: 3; grid-row: 2; }
}

/* La photo finish d'un segment pris à plusieurs : la route vue de côté à l'instant où le premier passe la ligne, un
   couloir par coureur. Les silhouettes prennent la couleur du coureur (`ink--N`) ; ses initiales et son nom le disent
   aussi. La bande grisée : une seconde de course devant la ligne, où les montres ne départagent pas. */
.photo { margin: 14px 0 4px; padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); display: grid; gap: 8px; }
.photo__caption { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; font-size: 0.92rem; }
.photo__strip { width: 100%; height: auto; display: block; }
.photo__strip--wide { max-width: 760px; }
.photo__strip--narrow { display: none; }
@media (max-width: 640px) { .photo__strip--wide { display: none; } .photo__strip--narrow { display: block; } }
.photo__blur { fill: var(--surface-2); }
.photo__lane { stroke: var(--line); stroke-width: 1; }
.photo__line { stroke: var(--text); stroke-width: 3; }
.photo__tick { stroke: var(--muted); stroke-width: 1; }
.photo__label { fill: var(--muted); font-size: 11px; }
.photo__rider path { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.photo__wheel { fill: none; stroke: currentColor; stroke-width: 2; }
.photo__head { fill: currentColor; }
.photo__tag circle { fill: currentColor; }
.photo__tag text { font-size: 10px; font-weight: 700; }
.photo__tag.ink--1 text { fill: var(--athlete-1-ink); }
.photo__tag.ink--2 text { fill: var(--athlete-2-ink); }
.photo__tag.ink--3 text { fill: var(--athlete-3-ink); }
.photo__tag.ink--4 text { fill: var(--athlete-4-ink); }
.photo__tag.ink--5 text { fill: var(--athlete-5-ink); }
.photo__tag.ink--6 text { fill: var(--athlete-6-ink); }
.photo__tag.ink--7 text { fill: var(--athlete-7-ink); }
.photo__tag.ink--8 text { fill: var(--athlete-8-ink); }
.photo__order { list-style: none; margin: 0; padding: 0; display: grid; }
.photo__place { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; align-items: center; gap: 4px 12px; padding: 4px 0; }
.photo__place + .photo__place { border-top: 1px solid var(--line); }
.photo__gap { text-align: right; white-space: nowrap; font-size: 0.88rem; }
.photo__note { font-size: 0.82rem; }
@media (max-width: 640px) { .photo { padding: 10px; } }

/* Ce que récompense chaque maillot. */
.rules { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.rules li { display: flex; align-items: center; gap: 12px; }

/* Les badges (`Badges`, `medal`) : des médaillons en noir et gris, la couleur restant aux coureurs et aux maillots.
 * Gagné : plein et cerné ; à gagner : en pointillé. Le niveau se lit au nombre de liserés, et s'écrit à côté. */
.medal { --ring: 2px; display: inline-flex; align-items: center; justify-content: center; gap: 1px; width: 48px; height: 48px; margin: 7px; border: var(--ring) solid var(--text); border-radius: 50%; background: var(--surface-2); color: var(--text); font-size: 1.05rem; font-weight: 750; letter-spacing: -0.03em; flex: none; }
.medal--l2 { box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--text); }
.medal--l3 { box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--text), 0 0 0 5px var(--surface), 0 0 0 6.5px var(--text); }
.medal--l4 { box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--text), 0 0 0 5px var(--surface), 0 0 0 6.5px var(--text), 0 0 0 8px var(--surface), 0 0 0 9.5px var(--text); margin: 10px; }
.medal.is-locked { border-style: dashed; border-color: var(--line-strong); background: transparent; color: var(--muted); }
.medal.is-locked .jersey { opacity: 0.4; filter: grayscale(1); }
.medal--small { --ring: 1.5px; width: 28px; height: 28px; margin: 5px; font-size: 0.68rem; }
.medal--small.medal--l2 { box-shadow: 0 0 0 1.5px var(--surface), 0 0 0 2.5px var(--text); }
.medal--small.medal--l3 { box-shadow: 0 0 0 1.5px var(--surface), 0 0 0 2.5px var(--text), 0 0 0 4px var(--surface), 0 0 0 5px var(--text); }
.medal--small.medal--l4 { box-shadow: 0 0 0 1.5px var(--surface), 0 0 0 2.5px var(--text), 0 0 0 4px var(--surface), 0 0 0 5px var(--text), 0 0 0 6.5px var(--surface), 0 0 0 7.5px var(--text); margin: 8px; }
.awards { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 16px 24px; margin: 0; padding: 16px 14px; list-style: none; }
.award { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.award__text { display: grid; gap: 2px; min-width: 0; flex: 1; padding-top: 6px; }
.award__name { font-weight: 650; line-height: 1.3; }
.award__state, .award__left { color: var(--muted); font-size: 0.86rem; }
.award__deed { font-size: 0.92rem; }
.award.is-locked .award__name { font-weight: 550; }
.medal-meter { display: block; width: 100%; height: 6px; margin-top: 6px; border-radius: 3px; color: var(--text); }
/* La page des badges : la part gagnée, sous le titre ; les badges pas encore commencés, repliés en fin de carte,
   une ligne chacun, leur médaillon en petit. */
.medal-meter--head { max-width: 320px; margin-top: 10px; }
.card__count { margin-left: 6px; color: var(--muted); font-size: 0.86rem; font-weight: 500; letter-spacing: 0; }
.card__head + .card__foot { border-top: 0; padding-top: 8px; } /* rien entre l'en-tête et le pied : un seul filet */
.awards__later > summary { margin-left: 0; }
.awards--compact { gap: 6px 24px; padding: 8px 0 4px; }
.awards--compact .award { align-items: center; }
.awards--compact .award__text { padding-top: 0; gap: 0; }
.awards--compact .award__deed { color: var(--muted); font-size: 0.86rem; }
.medals-brief { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px 28px; padding-left: 14px; padding-right: 14px; }
.medals-brief__title { margin: 0 0 4px 7px; color: var(--muted); font-size: 0.78rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.medal-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.medal-list li { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.medal-list--wide { grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 12px 24px; padding-left: 14px; padding-right: 14px; }
.medal-row { align-items: center; }
.medal-row > span:first-child { flex: none; }
.medal-strip { display: flex; flex-wrap: wrap; justify-content: flex-end; margin: 0; padding: 0; list-style: none; }
turbo-frame:empty { display: none; } /* un cadre qui n'a rien à montrer ne prend pas de place dans une pile */
/* L'annonce d'un badge juste gagné (`badge_announcement`), en tête de page. */
.news { display: grid; gap: 6px; margin-bottom: 18px; padding: 12px 14px 12px 10px; border: 1px solid var(--line-strong); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); }
.news__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-left: 7px; }
.news__title { font-size: 0.78rem; font-weight: 650; letter-spacing: 0.04em; text-transform: uppercase; }
.news__list { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 4px 20px; }
.news__foot { margin: 0; padding-left: 7px; font-size: 0.9rem; }
.news__losses { display: grid; gap: 4px; margin: 0; padding: 2px 0 2px 7px; list-style: none; font-size: 0.95rem; }
.news__losses .chip { vertical-align: baseline; font-weight: 600; }
/* L'annonce des duels (`duel_announcement`) : une ligne par duel, ses boutons à droite, dessous sur un téléphone. */
.news__items { display: grid; gap: 8px; margin: 0; padding: 2px 0 2px 7px; list-style: none; font-size: 0.95rem; }
.news__items li { display: flex; justify-content: space-between; align-items: center; gap: 6px 14px; flex-wrap: wrap; }
.news__items .chip { vertical-align: baseline; font-weight: 600; }
.news__actions { display: inline-flex; gap: 6px; flex: none; }
.news__actions form { margin: 0; }
.news__text { margin: 0; padding-left: 7px; font-size: 0.95rem; }
.news__row { padding-left: 7px; }
.news__row form { margin: 0; }
/* Le fil des groupes (`feeds/show`) : une carte par sortie, et ses « Yay! ». */
.acts-tabs { margin-bottom: 18px; }
.feed__mine { margin: 0 2px 14px; font-size: 0.92rem; }
.posts { display: grid; gap: 16px; }
.post { display: grid; gap: 10px; padding: 14px 18px 12px; }
.post__head { display: flex; align-items: center; gap: 10px; margin: 0 0 4px; }
.post__face { width: 34px; height: 34px; margin: 0; box-shadow: none; font-size: 0.8rem; }
.post__who { display: grid; gap: 1px; min-width: 0; }
.post__title { display: flex; align-items: baseline; gap: 4px 8px; flex-wrap: wrap; margin: 0; font-size: 1.08rem; }
.post__title a { color: inherit; text-decoration: none; }
.post__title a:hover { text-decoration: underline; }
.post .facts { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.map--post { height: 220px; }
.post__passages { margin: 0; font-size: 0.9rem; }
.yays { display: flex; align-items: center; gap: 6px 10px; flex-wrap: wrap; }
.yays form { margin: 0; }
.yay.is-on { background: var(--text); border-color: var(--text); color: var(--surface); }
.yays__count { display: inline-flex; align-items: center; gap: 5px; font-weight: 600; font-size: 0.92rem; }
.yays__who { font-size: 0.9rem; }
.yays-strip { border-top: 1px solid var(--line); }
/* La page « Notifications » : une famille par ligne, sa case devant. */
.notify-kind { display: flex; align-items: flex-start; gap: 10px; }
.notify-kind .check { flex: none; margin-top: 2px; }

/* Le carnet d’activités : un mois et un seul bilan, puis les sorties. */
.activity-journal { max-width: 900px; margin-inline: auto; }
.activity-journal .page-head { margin-bottom: 18px; }
.activity-journal h1 { font-size: clamp(2rem, 5vw, 2.6rem); letter-spacing: -0.045em; line-height: 1.15; }
.activity-journal__toolbar { display: flex; flex-direction: column; align-items: flex-start; gap: 18px; margin-bottom: 18px; }
.activity-journal .acts-tabs { display: flex; width: 100%; max-width: none; margin: 0; padding: 0; border: 0; border-radius: 12px; background: var(--accent-line); gap: 0; }
.activity-journal .acts-tabs .tab { display: flex; flex: 1; justify-content: center; padding: 12px; border: 0; border-radius: 12px; font-size: 1rem; text-decoration: none; color: var(--text); }
.activity-journal .acts-tabs .tab.is-current { color: #fff; background: var(--primary); box-shadow: none; font-weight: 700; }
.activity-card summary::-webkit-details-marker { display: none; }
.activity-journal .finder { flex-wrap: nowrap; gap: 10px; margin-bottom: 14px; }
.activity-journal .finder .select { width: 7rem; min-height: 48px; border-color: var(--line); border-radius: 10px; background-color: var(--surface); }
.activity-journal__filters { display: flex; flex-wrap: nowrap; gap: 9px; margin-bottom: 18px; overflow-x: auto; scrollbar-width: none; }
.activity-journal__filters .filter { flex: 1 0 auto; justify-content: center; min-height: 42px; padding: 7px 14px; gap: 10px; border-radius: 999px; border-color: var(--line); font-size: 0.95rem; }
.activity-journal__filters .filter.is-current { background: var(--primary); color: #fff; border-color: var(--primary); font-weight: 650; }
.activity-journal__filters .filter.is-current .filter__count { color: inherit; }
.activity-journal__filters .filter__count { font-size: 0.95rem; color: var(--muted); opacity: 1; font-weight: 400; }
.activity-month-panel { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 16px 18px 20px; margin: 20px 0 18px; }
.activity-month { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin: 0 0 18px; }
.activity-month h2 { margin: 0; font-size: 1.2rem; letter-spacing: -0.025em; text-align: center; }
.activity-month__arrow { display: grid; place-items: center; flex: 0 0 40px; height: 40px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface); color: var(--text); }
.activity-month__arrow--older svg { transform: rotate(180deg); }
span.activity-month__arrow { opacity: 0.3; }
a.activity-month__arrow:hover { border-color: var(--accent); color: var(--accent); }
.activity-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin: 0; padding: 0; background: transparent; }
.activity-summary > div { display: flex; flex-direction: column; align-items: center; min-width: 0; padding-inline: 8px; }
.activity-summary > div:first-child { order: 3; }
.activity-summary > div:nth-child(2) { order: 1; border-right: 1px solid var(--line); }
.activity-summary > div:nth-child(3) { order: 2; border-right: 1px solid var(--line); }
.activity-summary dt { display: contents; }
.activity-summary dt span { order: 3; margin-top: 4px; color: var(--muted); font-size: 0.85rem; }
.activity-summary svg { order: 1; box-sizing: content-box; color: var(--accent); background: var(--accent-soft); padding: 11px; border-radius: 50%; margin-bottom: 8px; }
.activity-summary dd { order: 2; margin: 0; font-size: clamp(1.1rem, 3vw, 1.65rem); font-weight: 750; line-height: 1.2; letter-spacing: -0.035em; white-space: nowrap; }
.activity-cards { display: grid; gap: 12px; }
.activity-cards__month { margin: 12px 0 0; color: var(--muted); font-size: 0.95rem; font-weight: 650; letter-spacing: -0.01em; }
.activity-cards__month:first-child { margin-top: 0; }
.activity-card { border: 1px solid var(--line); border-radius: 12px; padding: 16px 20px; background: var(--surface); }
.activity-card__head { display: flex; align-items: flex-start; gap: 14px; border-radius: 6px; }
.activity-card__sport { display: grid; place-items: center; flex: 0 0 48px; height: 48px; background: var(--accent-soft); color: var(--accent); border-radius: 12px; }
.activity-card__heading { flex: 1; min-width: 0; padding-top: 2px; }
.activity-card__name { display: block; font-size: 1.15rem; line-height: 1.3; font-weight: 750; letter-spacing: -0.035em; overflow-wrap: anywhere; }
.activity-card__name a { text-decoration: none; }
.activity-card__name a:hover { text-decoration: underline; text-underline-offset: 3px; }
.activity-card__heading time { display: block; margin-top: 5px; color: var(--muted); font-size: 0.95rem; }
.activity-card__heading .badge { margin-top: 6px; }
.activity-card__metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin: 18px 0 0; }
.activity-card__metrics > div { min-width: 0; }
.activity-card__metrics > div + div { border-left: 1px solid var(--line); padding-left: 10px; }
.activity-card__metrics dt { color: var(--muted); font-size: 0.8rem; margin-bottom: 3px; }
.activity-card__metrics dd { margin: 0; font-size: 1.15rem; line-height: 1.3; font-weight: 700; letter-spacing: -0.025em; white-space: nowrap; }
.activity-card__map { height: 200px; margin-top: 14px; }
.activity-card .post__passages { margin-top: 12px; }
/* Les passages d'une sortie, en vignettes au pied de sa fiche : la forme du segment, son nom, le temps et sa place. Un
   nom trop long s'abrège plutôt que d'élargir la fiche (d'où le `min-width` de la fiche, élément d'une grille). */
.activity-card { min-width: 0; }
.pass-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0 0; padding: 0; list-style: none; }
.pass-chip { display: inline-flex; align-items: center; gap: 9px; max-width: 100%; min-width: 0; padding: 4px 14px 4px 4px; border-radius: 999px; background: var(--accent-soft); font-size: 0.92rem; }
.pass-chip__shape { display: grid; place-items: center; flex: none; width: 32px; height: 32px; border-radius: 50%; background: var(--surface); }
.pass-chip__shape .shape__line { stroke: var(--accent); stroke-width: 1.8; }
.pass-chip__shape .shape__start { fill: var(--surface); stroke: var(--accent); stroke-width: 1.6; }
.pass-chip__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pass-chip__name a { text-decoration: none; }
.pass-chip__name a:hover { text-decoration: underline; text-underline-offset: 3px; }
.pass-chip__time { flex: none; font-weight: 750; }
.pass-chip .badge { flex: none; }
.pass-chip--more { padding-left: 14px; }
.activity-card__source, .activity-card__companions { display: flex; align-items: center; gap: 10px; margin: 14px 2px 0; color: var(--muted); font-size: 0.85rem; }
@media (max-width: 480px) {
  .activity-journal .acts-tabs .tab { font-size: 0.9rem; padding: 11px 8px; }
  .activity-journal__toolbar { gap: 12px; }
  .activity-journal__filters .filter { padding-inline: 10px; gap: 8px; font-size: 0.85rem; }
  .activity-journal__filters .filter__count { font-size: 0.85rem; }
  .activity-journal__filters .filter__count--secondary { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .activity-month-panel { padding: 14px 10px 18px; }
  .activity-summary { padding: 0; }
  .activity-summary > div { padding-inline: 4px; }
  .activity-summary svg { width: 20px; height: 20px; padding: 9px; }
  .activity-summary dt span { font-size: 0.7rem; }
  .activity-card { padding: 14px; }
  .activity-card__head { gap: 10px; }
  .activity-card__name { font-size: 1rem; }
  .activity-card__sport { flex-basis: 42px; height: 42px; }
  .activity-card__metrics { gap: 6px; }
  .activity-card__metrics > div + div { padding-left: 6px; }
  .activity-card__metrics dt { font-size: 0.7rem; }
  .activity-card__metrics dd { font-size: clamp(0.7rem, 3.2vw, 0.95rem); }
}

/* La photo privée du compte, de son formulaire au menu du bas. */
.profile__face, .profile-photo__preview, .tabbar__photo { object-fit: cover; border-radius: 50%; flex: none; }
.tabbar__photo { width: 24px; height: 24px; }
.tabbar__link.is-current .tabbar__photo { outline: 2px solid var(--accent); outline-offset: 2px; }
#photo input[type=file] { max-width: 100%; font: inherit; }
#photo .field { min-width: 0; flex: 1 1 180px; }

/* La carte que l'on choisit de partager, avec le même aperçu que dans une messagerie. */
.result-card { display: grid; gap: 14px; margin-block: 18px; }
.result-card .btn--icon { width: 44px; height: 44px; padding: 8px; }
.result-card .btn--whatsapp { background: #fff; border-color: #25d366; }
.result-card .btn--telegram { background: #fff; border-color: #229ed9; }
.result-card .btn--whatsapp:hover { background: #edfff3; }
.result-card .btn--telegram:hover { background: #eaf7ff; }
.result-card__preview summary { cursor: pointer; color: var(--accent); font-weight: 600; }
.result-card__preview img { display: block; width: 100%; max-width: 720px; height: auto; border-radius: 16px; margin-top: 12px; }

/* Départ rapide : une séance principale et deux alternatives, avant la bibliothèque repliée. */
.workout-page-head { margin: 0 auto 20px; width: 100%; max-width: 720px; }
#depart { display: block; max-width: 720px; width: 100%; margin-inline: auto; }
.quick-workout { display: grid; gap: 16px; }
.quick-workout__choices { border: 0; padding: 0; margin: 0; min-width: 0; }
.quick-workout__choices legend { font-weight: 650; margin-bottom: 8px; padding: 0; }
.quick-workout__segments { display: flex; gap: 6px; }
.quick-workout__segments label { flex: 1; min-width: 0; position: relative; }
.quick-workout__segments input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.quick-workout__segments span { display: flex; align-items: center; justify-content: center; min-height: 44px; padding: 10px 6px; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; white-space: nowrap; }
.quick-workout__segments input:checked + span { background: var(--text); color: var(--surface); border-color: var(--text); }
.quick-workout__segments input:focus-visible + span { outline: 3px solid var(--primary); outline-offset: 3px; }
.quick-workout__refine summary { padding-block: 6px; }
.quick-workout__fields { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
.quick-workout__fields .field { min-width: 0; }
.quick-workout__heading { margin-top: 22px; }
.quick-workout__heading h2 { font-size: 1rem; }
.quick-workout__hero { padding: 20px; }
.quick-workout__meta { justify-content: space-between; font-size: .85rem; }
.quick-workout__hero h2 { font-size: 1.3rem; margin: 10px 0 0; }
.quick-workout__profile { height: 74px; margin: 16px 0; }
.quick-workout__facts { display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap; }
.quick-workout__facts strong { font-size: 1.5rem; letter-spacing: -.03em; }
.quick-workout__reason { font-size: .85rem; margin: 9px 0 16px; }
.quick-workout__ride { display: flex; width: 100%; min-height: 44px; justify-content: center; }
.quick-workout__alternatives { margin-top: 24px; }
.quick-workout__alternatives .section-title { gap: 8px; }
.quick-workout__alternatives .section-title h3 { font-size: .95rem; margin: 0; }
.quick-workout__alternatives .section-title > a { font-size: .85rem; padding-block: 10px; }
.quick-workout__alternative { display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 14px 0; border-bottom: 1px solid var(--line); }
.quick-workout__mini { height: 32px; }
.quick-workout__alternative h3 { font-size: .9rem; margin: 0; }
.quick-workout__alternative p { font-size: .8rem; margin: 4px 0 0; }
.quick-workout__alternative .btn { min-height: 44px; }
.quick-workout__explain { margin-top: 18px; }
.workout-fold > summary { font-weight: 650; padding: 14px 0; min-height: 44px; }
.workout-fold[open] > summary { margin-bottom: 14px; }
.workout-fold.card { padding: 0 18px; }
@media (max-width: 420px) {
  .quick-workout__hero { padding: 16px; }
  .quick-workout__fields { grid-template-columns: 1fr; }
  .quick-workout__alternative { grid-template-columns: minmax(0, 1fr) auto; }
  .quick-workout__mini { display: none; }
  .quick-workout__segments span { font-size: .9rem; }
}

/* Le carnet d'accomplissements : des collections personnelles, lisibles même avant la première arrivée. */
.achievements__welcome { display: flex; align-items: center; gap: 20px; padding: 24px; background: #193f45; border-color: #456566; color: #fff8e9; }
.achievements__welcome h2 { margin: 4px 0 8px; font-size: 1.7rem; letter-spacing: -0.03em; }
.achievements__welcome p { color: #d7e7df; max-width: 65ch; line-height: 1.5; }
.achievements__eyebrow { color: #ffdc91; text-transform: uppercase; font-size: 0.7rem; font-weight: 650; letter-spacing: 0.07em; }
.achievements__emblem { display: grid; place-items: center; flex: none; width: 66px; height: 66px; border-radius: 22px; background: #305456; color: #ffdc91; }
.achievements__stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.achievements__stat { display: grid; gap: 8px; align-content: start; padding: 18px; }
.achievements__symbol { color: var(--accent); }
.achievements__number { display: flex; align-items: baseline; gap: 4px; }
.achievements__number strong { font-size: 2rem; letter-spacing: -0.04em; line-height: 1; }
.achievements__number > span { color: var(--muted); font-size: 0.95rem; }
.achievements__label { color: var(--muted); font-size: 0.85rem; }
.achievements .card__head { align-items: center; }
.achievements .card__head h2 { display: flex; align-items: center; gap: 8px; }
.achievements .card__head p { max-width: 68ch; margin-top: 5px; font-size: 0.9rem; }
.achievements__counts { display: flex; flex-wrap: wrap; gap: 8px; }
.achievements__counts .chip { gap: 6px; background: var(--surface-2); padding: 6px 10px; font-size: 0.85rem; }
.achievements__invitation { border-radius: 12px; padding: 14px 16px; background: var(--accent-soft); color: var(--text); font-size: 0.9rem; }
.achievements__ranges { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 24px; }
.achievements__range { display: grid; gap: 8px; padding: 10px 0; text-decoration: none; color: var(--text); }
.achievements__range-head { display: flex; justify-content: space-between; gap: 12px; font-size: 0.9rem; }
.achievements__range-head > span { color: var(--muted); white-space: nowrap; }
.achievements progress { display: block; width: 100%; height: 8px; border: 0; border-radius: 999px; overflow: hidden; background: var(--surface-2); color: var(--accent); accent-color: var(--accent); }
.achievements progress::-webkit-progress-bar { background: var(--surface-2); border-radius: 999px; }
.achievements progress::-webkit-progress-value { background: var(--accent); border-radius: 999px; }
.achievements progress::-moz-progress-bar { background: var(--accent); border-radius: 999px; }
.achievements__summits { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.achievements__summit { display: flex; align-items: center; gap: 12px; padding: 14px; border: 1px solid var(--line); border-radius: 14px; text-decoration: none; color: var(--text); }
.achievements__summit > span:nth-child(2) { flex: 1; min-width: 0; }
.achievements__summit strong { display: block; font-size: 0.95rem; }
.achievements__summit-mark { display: grid; place-items: center; flex: none; width: 40px; height: 40px; border-radius: 12px; background: var(--surface-2); color: var(--muted); }
.achievements__summit-state { display: block; margin-top: 3px; font-size: 0.78rem; color: var(--muted); }
.achievements__summit.is-done { border-color: color-mix(in srgb, var(--ok) 35%, var(--line)); }
.achievements__summit.is-done .achievements__summit-mark { color: var(--ok); background: var(--ok-soft); }
.achievements__summit:hover, .achievements__race-type:hover { border-color: var(--accent); }
.achievements__summit:focus-visible, .achievements__range:focus-visible, .achievements__race-type:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.achievements__subheading { font-size: 0.95rem; }
.achievements__latest { list-style: none; margin: 0; padding: 0; }
.achievements__latest li { display: grid; gap: 4px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.achievements__latest li:last-child { border-bottom: 0; padding-bottom: 0; }
.achievements__latest li > a { font-weight: 600; color: var(--text); }
.achievements__latest .muted { font-size: 0.82rem; }
.achievements__race-types { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.achievements__race-type { display: grid; gap: 8px; padding: 16px; border: 1px solid var(--line); border-radius: 14px; color: var(--text); text-decoration: none; }
.achievements__race-type > svg { color: var(--accent); }
.achievements__race-type strong { font-size: 1.7rem; }
.achievements__race-type > span { color: var(--muted); font-size: 0.85rem; }
.achievements__method { color: var(--muted); font-size: 0.85rem; }
@media (max-width: 640px) {
  .achievements__welcome { position: relative; display: block; padding: 20px; }
  .achievements__emblem { position: absolute; top: 16px; right: 16px; width: 34px; height: 34px; border-radius: 12px; }
  .achievements__eyebrow { display: block; padding-right: 40px; min-height: 24px; }
  .achievements__emblem svg { width: 24px; height: 24px; }
  .achievements__welcome h2 { font-size: 1.35rem; }
  .achievements__welcome p { font-size: 0.88rem; }
  .achievements__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .achievements__stat { padding: 16px; }
  .achievements__ranges, .achievements__summits { grid-template-columns: minmax(0, 1fr); }
  .achievements__race-types { grid-template-columns: minmax(0, 1fr); }
  .achievements__race-type { grid-template-columns: 26px 40px minmax(0, 1fr); align-items: center; }
  .achievements__race-type strong { font-size: 1.4rem; }
}

/* Les autres catalogues de Rouler : un univers par couleur, les dessins utiles en tête des cartes. */
.ride-catalog { --catalog-color: var(--accent); --catalog-bg: #233f50; gap: 22px; }
.ride-catalog--workouts { --catalog-color: light-dark(#a64d16, #ffba82); --catalog-bg: #4b3835; }
.ride-catalog--track { --catalog-color: light-dark(#7b4bb3, #c9a4ff); --catalog-bg: #373650; }
.ride-catalog--games { --catalog-color: light-dark(#b13868, #ff9bc3); --catalog-bg: #4b3447; }
.ride-catalog__head { position: relative; isolation: isolate; overflow: hidden; margin: 0; min-height: 180px; padding: 26px; border-radius: 22px; background: var(--catalog-bg); color: #fff8e9; align-items: center; }
.ride-catalog__heading { max-width: 72%; }
.ride-catalog__eyebrow { display: block; margin-bottom: 8px; font-size: 0.7rem; font-weight: 650; letter-spacing: 0.07em; text-transform: uppercase; color: #ffdc91; }
.ride-catalog__heading h1 { font-size: clamp(1.9rem, 4vw, 2.6rem); line-height: 1.15; letter-spacing: -0.04em; }
.ride-catalog__heading p { max-width: 58ch; color: #e4e8e3; font-size: 0.95rem; line-height: 1.5; margin-top: 10px; }
.ride-catalog__art { position: absolute; right: 46px; top: 50%; transform: translateY(-50%); display: grid; place-items: center; width: 136px; height: 136px; border: 1px solid #ffffff29; border-radius: 50%; color: #ffdc91; background: #ffffff08; }
.ride-catalog__art::after { content: ""; position: absolute; inset: -16px; border: 1px dashed #ffffff20; border-radius: 50%; }
.ride-catalog .grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 310px), 1fr)); gap: 18px; }
.ride-catalog .section-title h2 { font-size: 1.15rem; letter-spacing: -0.02em; }
.ride-catalog .filters { margin-bottom: 0; }
.ride-catalog .filter { min-height: 44px; }
.ride-catalog .search { border-radius: 12px; }
.ride-catalog .search__input { min-height: 46px; }
.ride-catalog .gearbar__first { padding: 16px 18px; gap: 12px; }
.ride-catalog .gearbar__first h2 { font-size: 0.95rem; }
.ride-catalog .gearbar__first p { font-size: 0.88rem; }
.ride-catalog .gearbar .btn { min-height: 44px; }
.ride-catalog .route-card, .ride-catalog .workout, .ride-catalog .velo-event, .ride-catalog .game-tile { border-radius: 20px; transition: border-color 150ms, box-shadow 150ms; }
.ride-catalog .route-card:hover, .ride-catalog .workout:hover, .ride-catalog .velo-event:focus-within, .ride-catalog .game-tile:hover { border-color: var(--catalog-color); box-shadow: 0 6px 20px color-mix(in srgb, var(--catalog-color) 12%, transparent); }
.ride-catalog .route-card:focus-visible, .ride-catalog .workout:focus-visible, .ride-catalog .game-tile:focus-visible { outline: 3px solid var(--catalog-color); outline-offset: 3px; }
.ride-catalog .route-card { flex-direction: column; align-items: stretch; padding: 0; gap: 0; overflow: hidden; }
.ride-catalog .route-card .seg__shape { width: 100%; height: 128px; border-radius: 0; padding: 14px 18px; background: linear-gradient(150deg, color-mix(in srgb, var(--catalog-color) 15%, var(--surface)), var(--surface)); }
.ride-catalog .route-card .seg__shape > svg { display: block; width: 100%; height: 100%; }
.ride-catalog .route-card .relief__area { fill: var(--catalog-color); opacity: 0.2; }
.ride-catalog .route-card .relief__line { stroke: var(--catalog-color); }
.ride-catalog .route-card .seg__body { gap: 10px; padding: 16px 18px 18px; }
.ride-catalog .route-card .seg__name { font-size: 1.12rem; letter-spacing: -0.02em; }
.ride-catalog .route-card .seg__kicker { color: var(--catalog-color); }
.ride-catalog .route-card .facts { gap: 6px; margin: 0; }
.ride-catalog .route-card .fact { padding: 8px; border-radius: 10px; background: var(--surface-2); }
.ride-catalog .route-card .seg__rivals { font-size: 0.82rem; }
.ride-catalog .route-card .seg__foot { padding-top: 12px; border-top: 1px solid var(--line); font-size: 0.82rem; }
.ride-catalog .route-card .seg__cta { min-height: 40px; justify-content: center; }
.ride-catalog .route-card.seg--lead { border-color: var(--accent-line); background: linear-gradient(120deg, var(--surface), var(--accent-soft)); }
.ride-catalog .workout { overflow: hidden; gap: 8px; padding: 0 0 16px; }
.ride-catalog .workout > :not(.workout__art) { margin-inline: 18px; }
.ride-catalog .workout .workout__art { height: 110px; padding: 22px 48px 18px 16px; margin: 0 0 6px; background: linear-gradient(150deg, color-mix(in srgb, var(--catalog-color) 12%, var(--surface)), var(--surface)); }
.ride-catalog .workout__name { font-size: 1.1rem; letter-spacing: -0.02em; }
.ride-catalog .workout__facts { font-size: 0.88rem; color: var(--text); font-weight: 600; }
.ride-catalog .workout__stress { font-size: 0.8rem; }
.ride-catalog .workout__summary { flex: 1; font-size: 0.88rem; line-height: 1.5; }
.ride-catalog .workout .seg__cta { align-self: stretch; justify-content: center; min-height: 44px; margin-top: 8px; border-radius: 12px; }
.ride-catalog .workout__star { top: 12px; right: 12px; }
.ride-catalog .workout__star .star { background: var(--surface); border: 1px solid var(--line); }
.ride-catalog .quick-workout { padding: 18px; border: 1px solid var(--line); border-radius: 18px; background: var(--surface); }
.ride-catalog .quick-workout__hero { border-radius: 20px; border-color: color-mix(in srgb, var(--catalog-color) 35%, var(--line)); background: linear-gradient(130deg, color-mix(in srgb, var(--catalog-color) 8%, var(--surface)), var(--surface)); }
.ride-catalog .quick-workout__alternative { padding: 14px; margin-top: 10px; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); }
.ride-catalog .workout-fold > summary { min-height: 48px; padding-block: 14px; }
.ride-catalog .velo-event { display: flex; flex-direction: column; overflow: hidden; padding: 18px; gap: 8px; }
.ride-catalog .velo-event__art { position: relative; width: calc(100% + 36px); height: 136px; margin: -18px -18px 8px; border-radius: 0; background: linear-gradient(150deg, color-mix(in srgb, var(--catalog-color) 15%, var(--surface)), var(--surface)); color: var(--catalog-color); }
.ride-catalog .velo-event__art > .icon { position: absolute; top: 12px; left: 14px; width: 30px; height: 30px; padding: 5px; border-radius: 9px; background: var(--surface); }
.track-art { display: block; width: 100%; height: 100%; padding: 12px; }
.track-art__infield { fill: var(--surface-2); stroke: var(--catalog-color); stroke-width: 2; }
.track-art__lanes { stroke: var(--catalog-color); opacity: 0.35; }
.track-art__finish { stroke: var(--text); stroke-width: 2; }
.track-art__line { stroke: var(--catalog-color); stroke-width: 2; stroke-dasharray: 4 5; }
.track-art__rider { fill: var(--catalog-color); stroke: var(--surface); stroke-width: 2; }
.track-art__rider--other { fill: var(--text); }
.velo-event--bunch .track-art__rider--other { r: 5; }
.ride-catalog .velo-event__name { font-size: 1.12rem; letter-spacing: -0.02em; }
.ride-catalog .velo-event__facts { font-size: 0.85rem; color: var(--catalog-color); font-weight: 600; }
.ride-catalog .velo-event__summary { flex: 1; font-size: 0.88rem; line-height: 1.5; }
.ride-catalog .velo-event__marks { padding: 12px; margin-top: 4px; border: 0; border-radius: 12px; background: var(--surface-2); font-size: 0.82rem; }
.ride-catalog .velo-event__go { margin-top: 6px; }
.ride-catalog .velo-event__go .btn { min-height: 44px; }
.ride-catalog .velo-event__go .btn--primary { flex: 1; justify-content: center; }
.ride-catalog .game-tile__body { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; padding: 18px; }
.ride-catalog .game-tile__name { font-size: 1.2rem; letter-spacing: -0.02em; }
.ride-catalog .game-tile__line { font-size: 0.88rem; line-height: 1.5; }
.game-tile__go { display: flex; justify-content: space-between; align-items: center; gap: 16px; width: 100%; min-height: 44px; padding-top: 12px; margin-top: auto; border-top: 1px solid var(--line); color: var(--catalog-color); font-size: 0.85rem; font-weight: 650; }
@media (max-width: 640px) {
  .ride-catalog { gap: 18px; }
  .ride-catalog__head { min-height: 164px; padding: 22px 20px; border-radius: 20px; }
  .ride-catalog__heading { max-width: 100%; }
  .ride-catalog__heading h1 { padding-right: 62px; font-size: 1.8rem; }
  .ride-catalog__eyebrow { max-width: calc(100% - 66px); font-size: 0.63rem; }
  .ride-catalog__heading p { font-size: 0.88rem; }
  .ride-catalog__art { right: 18px; top: 30px; transform: none; width: 54px; height: 54px; }
  .ride-catalog__art > svg { width: 32px; height: 32px; }
  .ride-catalog__art::after { inset: -7px; }
  .ride-catalog .grid { gap: 14px; }
  .ride-catalog .game-tile__body { padding: 14px 12px; }
  .ride-catalog .game-tile__name { font-size: 1.05rem; }
  .ride-catalog .game-tile__line { font-size: 0.8rem; }
  .ride-catalog .game-tile__go { gap: 8px; font-size: 0.8rem; }
  .ride-catalog .gearbar__first .row { width: 100%; }
  .ride-catalog .gearbar__first .btn--primary { flex: 1; justify-content: center; }
  .ride-catalog .route-card .seg__body { padding: 14px 16px 16px; }
  .ride-catalog .route-card.seg--lead .seg__cta { flex: 0 0 auto; margin-left: auto; padding: 5px 12px; }
  .ride-catalog .quick-workout { padding: 16px; }
  .ride-catalog .quick-workout__alternative { grid-template-columns: 42px minmax(0, 1fr) auto; padding: 12px; gap: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .ride-catalog .route-card, .ride-catalog .workout, .ride-catalog .velo-event, .ride-catalog .game-tile { transition: none; }
}

@media (max-width: 420px) {
  .ride-catalog .quick-workout__alternative { grid-template-columns: minmax(0, 1fr) auto; }
}

/* Le carnet à gratter (`dashboards/_scratch`) : un ticket par massif, une case par sommet. Le gris de la couche à
 * gratter est lu par le contrôleur `scratch` : c'est lui qui la dessine. Montée ou non se dit aussi par le texte.
 * Le home trainer garde son bleu une fois découvert, sauf si la route y est passée aussi (`is-indoor` ne se pose pas). */
.tickets { --scratch: #a9a8a0; --scratch-line: #c9c8c0; --scratch-ink: #2b2b28; --scratch-indoor: #7f8fd6; display: grid; gap: 18px; }
.scratch--indoor { --scratch: var(--scratch-indoor); --scratch-line: #a3b0e6; --scratch-ink: #141b3f; }
.ticket__head { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.ticket__cases { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; margin: 0; padding: 0; list-style: none; }
.scratch { position: relative; display: grid; gap: 1px; align-content: start; min-height: 74px; padding: 9px 11px; border: 1px dashed var(--line-strong); border-radius: 10px; overflow: hidden; font-size: 0.88rem; text-decoration: none; }
.scratch__name { font-weight: 600; line-height: 1.25; overflow-wrap: anywhere; }
.scratch__note { color: var(--muted); font-size: 0.78rem; }
/* La silhouette du versant : sa bande à elle, sous le texte, qu'elle brouillerait si elle passait derrière. */
.scratch__shape { display: block; width: 100%; height: 46px; margin-top: 6px; color: var(--text); }
.scratch__shape path { fill: currentColor; fill-opacity: 0.16; }
.scratch__shape .scratch__road { fill: none; stroke: currentColor; stroke-opacity: 0.75; stroke-width: 1.3; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.scratch.is-climbed { border: 1px solid var(--text); background: var(--surface-2); }
.scratch.is-climbed.is-indoor { border-color: var(--scratch-indoor); background: color-mix(in srgb, var(--scratch-indoor) 40%, var(--surface)); }
.scratch.is-indoor .scratch__note { color: var(--text); }
.scratch:not(.is-climbed) .scratch__name { color: var(--muted); font-weight: 500; }
.scratch__cover { position: absolute; inset: 0; width: 100%; height: 100%; touch-action: none; cursor: crosshair; }
.scratch__form { position: absolute; right: 6px; bottom: 6px; }
.scratch__button { padding: 2px 8px; border: 1px solid var(--line-strong); border-radius: 999px; background: var(--surface); color: var(--text); font: inherit; font-size: 0.74rem; cursor: pointer; }
.scratch.is-revealed .scratch__cover, .scratch.is-revealed .scratch__form { display: none; }
.scratch__hidden { position: relative; }
.col-card__climbed { display: inline-flex; align-items: center; gap: 5px; font-size: 0.82rem; font-weight: 600; }

/* Le replay d'un lien partagé (contrôleur `replay`) : il s'ouvre comme une vidéo. La scène prend toute la fenêtre, ce
   qui se pose dessus a ses propres couleurs, quel que soit le thème du visiteur, et n'apparaît qu'à son moment
   (`data-moment` : preparing, counting, waiting, running, done). `svh` plutôt que `dvh` : la barre d'adresse d'un
   téléphone qui se replie en faisant défiler le détail ne fait pas redessiner la scène. */
.container--bare, .is-native .container--bare { max-width: none; padding: 0; }
.stack.replay { gap: 0; }
.race.race--replay {
  --on-scene: #ffffff;
  --on-scene-soft: rgb(255 255 255 / 82%);
  --veil: rgb(10 17 32 / 72%);
  --veil-strong: rgb(11 19 34 / 92%);
  --veil-line: rgb(255 255 255 / 16%);
  --bright: #2f62e6;
  position: relative;
  isolation: isolate;
  display: block;
  height: 100vh;
  height: calc(100svh - var(--foot, 0px));
  overflow: hidden;
  background: #0b1322;
  color: var(--on-scene);
}
.race--replay::after { content: ""; position: absolute; inset: auto 0 0; z-index: 1; height: 300px; background: linear-gradient(to top, rgb(8 14 28 / 92%) 18%, rgb(8 14 28 / 0)); pointer-events: none; }
.race--replay[data-moment="running"]::after { height: 170px; }
.race--replay[data-moment="done"]::after { display: none; }
.race--replay .race__main { display: contents; }
.race--replay .race__stage { position: absolute; inset: 0; z-index: 0; cursor: pointer; }
.race--replay .race__map { height: 100%; border: 0; border-radius: 0; }
.race--replay[data-moment="preparing"] .leaflet-container { visibility: hidden; }
.race--replay .scene__zoom, .race--replay .scene__loading, .race--replay .leaflet-top { display: none; }
.race--replay .scene__credit { top: 8px; right: 8px; bottom: auto; border-radius: 4px; font-size: 0.6rem; background: rgb(255 255 255 / 58%); }
.race--replay .leaflet-bottom { top: 8px; right: 8px; bottom: auto; }

.replay__head { position: absolute; inset: 0 0 auto; z-index: 3; display: flex; align-items: center; gap: 16px; padding: 12px 14px; background: linear-gradient(to bottom, rgb(8 14 28 / 50%), rgb(8 14 28 / 0)); pointer-events: none; }
.replay__head .brand { color: var(--on-scene); text-shadow: 0 1px 3px rgb(0 0 0 / 45%); pointer-events: auto; }
.replay__name { display: none; margin: 0; color: var(--on-scene-soft); text-shadow: 0 1px 3px rgb(0 0 0 / 45%); }
.replay__name strong { color: var(--on-scene); }

.replay__lead { position: absolute; inset: auto 16px calc(22px + env(safe-area-inset-bottom)); z-index: 3; pointer-events: none; }
.replay__lead h1 { margin: 0; color: var(--on-scene); font-size: 1.7rem; line-height: 1.15; font-weight: 800; }
.replay__lead p { margin: 4px 0 0; color: var(--on-scene-soft); }
.race--replay p.replay__riders { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.replay__riders .chip { padding: 4px 11px 4px 4px; border-radius: 99px; background: rgb(255 255 255 / 14%); color: var(--on-scene); font-weight: 600; }
.race--replay .source-note { color: var(--on-scene-soft); font-size: 0.8rem; }
.race--replay[data-moment="running"] .replay__lead, .race--replay[data-moment="done"] .replay__lead { display: none; }

.replay__status, .replay__count { position: absolute; top: 84px; left: 50%; z-index: 3; display: none; margin: 0; transform: translateX(-50%); text-align: center; white-space: nowrap; pointer-events: none; }
.replay__status { top: 120px; padding: 6px 14px; border-radius: 99px; background: var(--veil); font-size: 0.92rem; font-weight: 600; }
.replay__count strong { display: grid; place-items: center; width: 78px; height: 78px; margin: 0 auto; border: 3px solid rgb(255 255 255 / 92%); border-radius: 50%; background: rgb(8 14 28 / 56%); font-size: 2.5rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.replay__count span { display: inline-block; margin-top: 8px; padding: 4px 12px; border-radius: 99px; background: var(--veil); font-size: 0.85rem; font-weight: 600; }
.race--replay[data-moment="preparing"] .replay__status, .race--replay[data-moment="counting"] .replay__count { display: block; }
.play.replay__start { position: absolute; top: 34%; left: 50%; z-index: 3; display: none; width: 84px; height: 84px; margin: -42px 0 0 -42px; background: var(--bright); box-shadow: 0 4px 18px rgb(0 0 0 / 40%); }
.race--replay[data-moment="waiting"] .replay__start { display: grid; place-items: center; }

/* Le classement, posé sur la scène : sa pastille, son nom, son écart. Toucher un nom place la caméra derrière lui. */
.race--replay .race__side { position: absolute; top: 12px; left: 12px; z-index: 3; display: none; width: 204px; max-height: calc(100% - 150px); padding: 5px 10px; overflow: hidden; border: 0; border-radius: 12px; background: var(--veil); box-shadow: none; backdrop-filter: blur(8px); }
/* Le classement en direct ne se pose plus sur la scène d'un replay : le bandeau des écarts dit la course (`replay#gaps`).
   Ses lignes restent dans la page, la course les tient à jour. */
.replay__band { position: absolute; top: 12px; left: 12px; z-index: 3; display: none; width: 204px; max-height: calc(100% - 150px); padding: 2px 10px; overflow: hidden; border-radius: 12px; background: var(--veil); color: var(--on-scene); backdrop-filter: blur(8px); }
.race--replay[data-moment="running"] .replay__band:not(:empty) { display: block; }
.band__group { padding: 7px 0 8px; }
.band__group + .band__group { border-top: 1px solid var(--veil-line); }
.band__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0; }
.band__kind { min-width: 0; overflow: hidden; color: var(--on-scene-soft); font-size: 0.62rem; font-weight: 700; letter-spacing: 0.05em; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
.band__gap { flex: none; font-size: 0.76rem; font-weight: 700; white-space: nowrap; }
.band__riders { display: flex; flex-wrap: wrap; gap: 5px 10px; margin: 6px 0 0; }
.band__rider { display: inline-flex; align-items: center; gap: 6px; min-width: 0; min-height: 24px; padding: 0; border: 0; background: none; color: inherit; font: inherit; font-size: 0.9rem; font-weight: 700; cursor: pointer; }
.band__rider:focus-visible { border-radius: 12px; outline: 2px solid var(--on-scene); outline-offset: 2px; }
.band__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Replié : le premier et son poursuivant, sur une ligne. */
.replay__band--line { width: auto; max-width: calc(100% - 150px); padding: 5px 12px 5px 6px; border-radius: 99px; }
.band__line { display: flex; align-items: center; gap: 8px; margin: 0; min-width: 0; }
.band__soft { min-width: 0; overflow: hidden; color: var(--on-scene-soft); font-size: 0.82rem; font-weight: 500; text-overflow: ellipsis; white-space: nowrap; }
.race--replay .race__side .card__head, .race--replay .board__hint, .race--replay .board__rank, .race--replay .board__date, .race--replay .board__speed, .race--replay .board__extra, .race--replay .board__row .pulse, .race--replay .board__row br { display: none; }
.race--replay .board { padding: 0; overflow: visible; }
.race--replay .board__row { display: flex; align-items: center; gap: 7px; padding: 3px 0; border: 0; background: none; }
.race--replay .board__row > span:nth-of-type(3) { min-width: 0; }
.race--replay .board__row > span:nth-of-type(4) { margin-left: auto; white-space: nowrap; }
.race--replay .board__pick { color: var(--on-scene); font-size: 0.9rem; }
.race--replay .board__row.is-focus .board__pick::after { content: none; }
.race--replay .board__gap { color: var(--on-scene-soft); font-size: 0.8rem; }

.race--replay .transport { position: absolute; inset: auto 12px calc(14px + env(safe-area-inset-bottom)); z-index: 3; display: block; max-width: 860px; margin-inline: auto; padding: 0; visibility: hidden; }
.race--replay[data-moment="running"] .transport { visibility: visible; }
.race--replay .transport__bar { flex-wrap: nowrap; gap: 10px; margin-top: 8px; }
.race--replay .play { width: 46px; height: 46px; flex: none; background: var(--bright); box-shadow: 0 2px 10px rgb(0 0 0 / 35%); }
.race--replay .transport__clock { min-width: 0; color: var(--on-scene); font-size: 1.25rem; font-weight: 700; }
.race--replay .transport__total { color: var(--on-scene-soft); font-size: 0.9rem; }
.replay__camera { display: inline-flex; align-items: center; gap: 7px; min-height: 44px; margin-left: auto; padding: 0 14px; border: 1px solid rgb(255 255 255 / 26%); border-radius: 99px; background: rgb(255 255 255 / 16%); color: var(--on-scene); font: inherit; font-weight: 600; white-space: nowrap; cursor: pointer; backdrop-filter: blur(6px); }
.replay__camera:hover { background: rgb(255 255 255 / 24%); }
.replay__camera-word { color: var(--on-scene-soft); font-weight: 500; }
.replay__camera strong { font-weight: 650; }
.replay__note:empty { display: none; }
.replay__note { display: block; margin-top: 6px; color: var(--on-scene-soft); font-size: 0.85rem; }

/* Le profil de la route : le curseur de la lecture est dessous, seulement pour le clavier et les lecteurs d'écran ; à la
   souris et au doigt, on touche la route (`replay#grab`). */
.replay__strip { position: relative; isolation: isolate; height: 48px; cursor: pointer; touch-action: none; }
.replay__strip:focus-within { border-radius: 6px; outline: 2px solid var(--on-scene); outline-offset: 2px; }
.replay__relief { position: absolute; inset: 0; width: 100%; height: 100%; fill: rgb(255 255 255 / 22%); }
.replay__relief--ridden { fill: rgb(255 255 255 / 55%); }
.replay__dot { position: absolute; min-width: 19px; height: 19px; padding: 0 3px; border-radius: 10px; font-size: 0.68rem; transform: translate(-50%, -50%); box-shadow: 0 0 0 1.5px var(--on-scene); }
.replay__strip .scrub { position: absolute; inset: 0; z-index: 2000; height: 100%; opacity: 0; pointer-events: none; }

.replay__finish { position: absolute; inset: auto 10px calc(10px + env(safe-area-inset-bottom)); z-index: 4; max-height: calc(100% - 20px); padding: 16px; overflow-y: auto; border: 1px solid var(--veil-line); border-radius: 18px; background: var(--veil-strong); backdrop-filter: blur(10px); }
.replay__verdict { margin: 0 0 8px; color: var(--on-scene); font-size: 1.3rem; line-height: 1.3; font-weight: 800; }
.replay__verdict .chip { font-weight: inherit; vertical-align: baseline; }
.replay__verdict strong { font-weight: inherit; white-space: nowrap; }
.replay__ranks { margin: 0; padding: 0; list-style: none; }
.replay__ranks li { display: flex; align-items: center; gap: 9px; padding: 6px 0; border-top: 1px solid var(--veil-line); font-weight: 600; }
.replay__rank { width: 16px; color: var(--on-scene-soft); }
.replay__who { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.replay__gap { width: 76px; color: var(--on-scene-soft); font-size: 0.85rem; font-weight: 500; text-align: right; }
.replay__more { margin: 0; padding-top: 6px; border-top: 1px solid var(--veil-line); color: var(--on-scene-soft); font-size: 0.85rem; }
.replay__stretch { margin: 8px 0 0; color: var(--on-scene-soft); font-size: 0.9rem; }
.replay__actions { display: flex; gap: 8px; margin-top: 12px; }
.replay__actions .btn { flex: 1; justify-content: center; min-height: 46px; }
.replay__actions .btn:not(.btn--primary) { border-color: transparent; background: rgb(255 255 255 / 12%); color: var(--on-scene); }
.replay__actions .btn--primary { border-color: var(--bright); background: var(--bright); }
.replay__join { margin: 10px 0 0; color: var(--on-scene-soft); font-size: 0.85rem; text-align: center; }
.replay__join a { color: var(--on-scene); }

/* Le synthé d'un replay : le fait de course à l'antenne, au-dessus du profil (`replay#caption`). Il est dans les
   commandes : il paraît et s'efface avec elles, et ne prend pas les touchers destinés à la scène. */
.replay__synth { max-width: 460px; margin-bottom: 10px; padding: 10px 13px 11px; border: 1px solid var(--veil-line); border-radius: 14px; background: var(--veil-strong); backdrop-filter: blur(10px); color: var(--on-scene); pointer-events: none; }
.replay__synth[hidden] { display: none; }
.replay__synth p { margin: 0; }
.replay__synth-top { display: flex; align-items: center; gap: 8px; min-width: 0; }
.replay__synth-top strong { font-size: 1.05rem; font-weight: 800; white-space: nowrap; }
.replay__synth-date { min-width: 0; overflow: hidden; color: var(--on-scene-soft); font-size: 0.82rem; text-overflow: ellipsis; white-space: nowrap; }
.replay__synth-kind { margin-left: auto; padding: 2px 8px; border-radius: 99px; background: rgb(255 255 255 / 14%); font-size: 0.66rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap; }
.replay__synth .replay__synth-line { margin-top: 6px; font-size: 1.2rem; line-height: 1.2; font-weight: 800; letter-spacing: -0.015em; }
.replay__synth .replay__synth-detail { margin-top: 3px; color: var(--on-scene-soft); font-size: 0.85rem; }
/* La jauge d'un duel : pendant le dépassement de l'arrivée, à la place du synthé (`replay#spar`). */
.replay__duel { max-width: 460px; margin-bottom: 10px; padding: 9px 13px 10px; border: 1px solid var(--veil-line); border-radius: 14px; background: var(--veil-strong); backdrop-filter: blur(10px); color: var(--on-scene); pointer-events: none; }
.replay__duel[hidden] { display: none; }
.replay__duel p { margin: 0; }
.replay__duel-row { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; }
.replay__duel-who { display: flex; align-items: center; gap: 7px; min-width: 0; }
.replay__duel-who strong { overflow: hidden; font-size: 0.98rem; font-weight: 750; text-overflow: ellipsis; white-space: nowrap; }
.replay__duel-who + .replay__duel-gap + .replay__duel-who { justify-content: flex-end; }
.replay__duel-gap { display: grid; justify-items: center; line-height: 1.05; }
.replay__duel-gap strong { font-size: 1.7rem; font-weight: 800; letter-spacing: -0.02em; }
.replay__duel-gap span { color: var(--on-scene-soft); font-size: 0.68rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; }
.replay__duel-more { display: flex; align-items: center; gap: 10px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--veil-line); color: var(--on-scene-soft); font-size: 0.78rem; line-height: 1.3; }
.replay__duel .replay__duel-more { margin-top: 8px; }
.replay__duel-more:has(> span:last-child:empty) { display: none; }
.replay__duel-curve { flex: none; width: 110px; }
.replay__duel-curve svg { display: block; width: 100%; height: auto; overflow: visible; }
.replay__duel-curve polyline { fill: none; stroke: var(--on-scene); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.replay__duel-curve line { stroke: rgb(255 255 255 / 30%); stroke-width: 1; }
/* Les chapitres sur le profil : une pastille numérotée au-dessus de la route, pleine une fois le chapitre passé. */
.replay__mark { position: absolute; top: -6px; z-index: 1500; display: grid; place-items: center; width: 15px; height: 15px; border: 1.3px solid rgb(255 255 255 / 85%); border-radius: 8px; color: var(--on-scene); font-size: 0.56rem; font-weight: 800; transform: translateX(-50%); pointer-events: none; }
.replay__mark.is-past { background: var(--on-scene); color: #0b1322; }
.replay__mark.is-on { box-shadow: 0 0 0 3px rgb(255 255 255 / 32%); }

/* La pente en incrustation (`replay#incline`, lib/sideview.js) : sombre sur la scène, quel que soit le thème (ses
   couleurs se lisent sur elle). Sur un téléphone, pendant un plan rapproché seulement (`data-close`), sous le bandeau
   replié ; sur un grand écran, toujours, en haut à droite ; jamais sur un téléphone couché. */
.replay__side { --text: #f0f5ff; --surface: #101a2c; --line-strong: rgb(255 255 255 / 24%); position: absolute; top: 58px; left: 12px; right: 12px; z-index: 3; display: none; height: 132px; border: 1px solid var(--veil-line); border-radius: 14px; background: var(--veil-strong); color: var(--on-scene); pointer-events: none; }
.race--replay[data-moment="running"][data-close="true"] .replay__side { display: block; }

/* L'écran partagé (`replay#divide`) : la seconde scène prend une moitié, la tête toujours à gauche (`data-split` : le côté
   de la seconde scène). Elle se construit cachée, à sa taille (`data-twin`). Un filet clair sépare les deux images ;
   chacune a son étiquette contre lui, en haut, où le nom du segment s'efface. */
.replay__twin { position: absolute; inset: 0 50% 0 0; z-index: 0; display: none; height: auto; border: 0; border-radius: 0; cursor: pointer; }
.race--replay[data-twin="loading"] .replay__twin { display: block; visibility: hidden; }
.race--replay[data-split] .replay__twin { display: block; }
.race--replay[data-split="head"] .replay__twin { box-shadow: 2px 0 0 rgb(255 255 255 / 85%); }
.race--replay[data-split="chase"] .replay__twin { inset: 0 0 0 50%; box-shadow: -2px 0 0 rgb(255 255 255 / 85%); }
.race--replay[data-split="head"] .race__stage { left: calc(50% + 2px); }
.race--replay[data-split="chase"] .race__stage { right: calc(50% + 2px); }
.race--replay[data-split] .replay__name { visibility: hidden; }
.replay__twin .scene__credit { display: none; } /* le crédit de la première scène vaut pour tout l'écran : les mêmes fonds */
.replay__half { position: absolute; top: 18px; z-index: 3; display: none; align-items: center; gap: 7px; margin: 0; padding: 4px 13px 4px 5px; border-radius: 99px; background: var(--veil); color: var(--on-scene); font-size: 0.95rem; white-space: nowrap; pointer-events: none; backdrop-filter: blur(8px); }
.race--replay[data-moment="running"][data-split] .replay__half { display: inline-flex; }
.replay__half--head { right: calc(50% + 14px); }
.replay__half--chase { left: calc(50% + 14px); }
.replay__half strong { font-weight: 750; }
.replay__half-soft { color: var(--on-scene-soft); font-weight: 500; }
/* Un téléphone tenu droit : l'une sur l'autre, la tête en haut, chaque étiquette contre le filet ; la pente s'efface,
   les deux images disent déjà où chacun en est. La seconde scène se construit cachée à sa taille, en haut. */
@media (max-width: 899px) and (min-height: 481px) {
  .replay__twin, .race--replay[data-split="head"] .replay__twin { inset: 0 0 50% 0; box-shadow: 0 2px 0 rgb(255 255 255 / 85%); }
  .race--replay[data-split="chase"] .replay__twin { inset: 50% 0 0 0; box-shadow: 0 -2px 0 rgb(255 255 255 / 85%); }
  .race--replay[data-split="head"] .race__stage { left: 0; top: calc(50% + 2px); }
  .race--replay[data-split="chase"] .race__stage { right: 0; bottom: calc(50% + 2px); }
  .replay__half { top: auto; font-size: 0.88rem; }
  .replay__half--head { right: auto; left: 12px; bottom: calc(50% + 12px); }
  .replay__half--chase { left: 12px; top: calc(50% + 12px); }
  .race--replay[data-moment="running"][data-split][data-close] .replay__side { display: none; }
}

/* Les encouragements d'un replay, pour un membre du groupe (`replay#encourage`) : ceux que le groupe a laissés paraissent
   quand leur coureur passe à cet endroit, et le bouton « Allez ! » nomme celui qu'il encourage. L'ensemble se tient
   au-dessus de la plus haute des légendes (`--cheer-lift`, posé par `replay#fit`) : rien n'y bouge sous le doigt. */
.replay__cheering { position: absolute; inset: auto 12px var(--cheer-lift, 250px); z-index: 3; display: none; flex-direction: column; align-items: flex-start; gap: 6px; max-width: 860px; margin-inline: auto; pointer-events: none; }
.race--replay[data-moment="running"] .replay__cheering { display: flex; }
.replay__cheers { display: grid; gap: 6px; justify-items: start; }
.replay__cheer { max-width: 100%; margin: 0; padding: 5px 13px 5px 12px; border-radius: 99px; background: var(--veil); color: var(--on-scene-soft); font-size: 0.84rem; font-weight: 500; line-height: 1.5; backdrop-filter: blur(8px); }
.replay__cheer strong { color: var(--on-scene); font-weight: 700; }
.replay__cheer .chip { gap: 5px; color: var(--on-scene); font-weight: 700; vertical-align: baseline; }
.replay__cheer .lane { min-width: 19px; height: 19px; padding: 0 5px; font-size: 0.7rem; }
/* Ce que dit le bouton après un toucher : pour un lecteur d'écran ; écrit pour tous quand l'encouragement n'est pas parti. */
.replay__cheer-note { position: absolute; width: 1px; height: 1px; margin: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.replay__cheer-note.is-failed:not(:empty) { position: static; width: auto; height: auto; padding: 5px 13px; border-radius: 99px; background: var(--veil-strong); color: var(--on-scene); font-size: 0.84rem; font-weight: 600; clip-path: none; white-space: normal; }
.replay__allez-form { align-self: flex-end; margin: 0; pointer-events: auto; }
/* Sur un écran large, les encouragements à gauche et le bouton à droite, au même niveau : rien ne monte vers le bandeau. */
@media (min-width: 600px) {
  .replay__cheering { flex-direction: row; align-items: flex-end; gap: 12px; }
  .replay__allez-form { margin-left: auto; }
}
.replay__allez { display: inline-flex; align-items: center; gap: 8px; max-width: min(260px, 100vw - 24px); min-height: 48px; padding: 0 18px 0 10px; border: 0; border-radius: 99px; background: var(--bright); color: #ffffff; font: inherit; font-size: 1.02rem; font-weight: 800; white-space: nowrap; box-shadow: 0 6px 22px rgb(0 0 0 / 45%); cursor: pointer; }
.replay__allez[hidden] { display: none; }
.replay__allez > span:last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.replay__allez .lane { box-shadow: 0 0 0 1.5px #ffffff; }
.replay__allez:hover { filter: brightness(1.08); }
.replay__allez:active { transform: scale(0.96); }
.replay__allez:focus-visible { outline: 2px solid var(--on-scene); outline-offset: 3px; }
/* Déjà encouragé : le bouton le dit par un liseré et une coche, pas par la seule couleur ; le toucher déplace
   l'encouragement. Son fond reste sombre : il se lit sur une route claire comme sur la carte. */
.replay__allez.is-given { padding-right: 14px; background: var(--veil-strong); box-shadow: inset 0 0 0 1.5px rgb(255 255 255 / 75%), 0 6px 22px rgb(0 0 0 / 35%); backdrop-filter: blur(8px); }
.replay__allez.is-given::after { content: ""; flex: none; width: 6px; height: 11px; margin: -3px 2px 0 2px; border: solid #ffffff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
/* Sur le profil : un repère au ras de la route, là où un encouragement est resté. Sous les coureurs. */
.replay__pin { position: absolute; z-index: 0; width: 0; height: 0; border-top: 7px solid var(--on-scene); border-right: 5px solid transparent; border-left: 5px solid transparent; filter: drop-shadow(0 0 1.5px rgb(8 14 28 / 80%)); transform: translate(-50%, calc(-100% - 2px)); pointer-events: none; }
/* Dans le film, le compte des encouragements d'un chapitre, sous son endroit. */
.film__tally { display: block; color: var(--on-scene); font-size: 0.78rem; font-weight: 700; text-align: right; }
.film__tally[hidden] { display: none; }
/* La liste des encouragements, sous la scène (`cheers/_list`) : qui encourage qui, où, et « Retirer » pour le sien. */
.cheers { margin: 0; padding: 0; list-style: none; }
.cheers__row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 1px 12px; padding: 9px 0; border-top: 1px solid var(--line); }
.cheers__row:first-child { padding-top: 0; border-top: 0; }
.cheers__row:last-child { padding-bottom: 0; }
.cheers__line { grid-column: 1; }
.cheers__line strong { font-weight: 650; }
.cheers__line .chip { align-items: baseline; vertical-align: baseline; }
.cheers__where { grid-column: 1; color: var(--muted); font-size: 0.9rem; }
.cheers__undo { grid-area: 1 / 2 / span 2; margin: 0; }
.cheers__none { margin: 0; }

/* Le film de la course : ses faits, numérotés (`segments/_film`). Sur la feuille de fin d'un replay, sans leurs phrases. */
.film { margin: 0; padding: 0; list-style: none; }
.film__fact { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; gap: 3px 10px; align-items: center; padding: 9px 0; border-top: 1px solid var(--line); }
.film__fact:first-child { border-top: 0; padding-top: 0; }
.film__n { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 11px; background: var(--text); color: var(--surface); font-size: 0.76rem; font-weight: 700; }
.film__title { font-weight: 650; }
.film .chip { align-items: baseline; }
.film__title .chip { font-weight: inherit; vertical-align: baseline; }
.film__where { color: var(--muted); font-size: 0.9rem; white-space: nowrap; }
.film__line { grid-column: 2 / -1; color: var(--muted); font-size: 0.92rem; }
.film__line .chip { vertical-align: baseline; }
.film__line strong { color: var(--text); font-weight: 650; white-space: nowrap; }
.film-box { border-bottom: 1px solid var(--line); }
.film-box h3 { margin-bottom: 10px; font-size: 1rem; }
.film-box .film__fact:last-child { padding-bottom: 0; }
.replay__finish .film__fact { padding: 7px 0; border-color: var(--veil-line); }
.replay__finish .film__fact:first-child { padding-top: 7px; border-top: 1px solid var(--veil-line); }
.replay__finish .film__n { width: 20px; height: 20px; background: var(--on-scene); color: #0b1322; font-size: 0.7rem; }
.replay__finish .film__title { font-size: 0.95rem; font-weight: 600; }
.replay__finish .film__where { color: var(--on-scene-soft); font-size: 0.82rem; }
/* Sur la feuille de fin, chaque chapitre est un bouton : il se revoit d'un toucher. */
.replay__finish .film__fact--go { display: block; padding: 0; }
.replay__finish .film__fact--go:first-child { padding-top: 0; }
.film__go { display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; gap: 3px 10px; align-items: center; width: 100%; min-height: 40px; padding: 5px 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.film__go:focus-visible { border-radius: 6px; outline: 2px solid var(--on-scene); outline-offset: 2px; }
.film__go.is-picked .film__n { box-shadow: 0 0 0 3px rgb(255 255 255 / 32%); }

/* Le détail, sous la scène. */
.replay__detail, .replay > .card, .replay > .source-note { width: min(1120px, 100% - 40px); margin-inline: auto; }
.replay__detail { margin-block: 28px 12px; }
.replay > .card + .card { margin-top: 14px; }
/* Les encouragements du groupe viennent avant le détail, juste sous la scène. */
.replay > .cheers-card { margin-top: 22px; }

@media (max-width: 899px) {
  .race--replay[data-moment="running"] .replay__head { display: none; }
}
@media (max-width: 380px) {
  .race--replay .scene__credit { max-width: 110px; }
}
@media (max-height: 480px) {
  .race--replay[data-moment="running"][data-close] .replay__side { display: none; }
  /* Couché, côte à côte : les étiquettes en haut, contre le filet, à la place du bandeau. */
  .replay__half { top: 10px; font-size: 0.85rem; }
  .race--replay[data-split] .replay__band { visibility: hidden; }
  .replay__allez { min-height: 40px; font-size: 0.95rem; }
  .replay__duel { margin-bottom: 6px; padding: 5px 10px 6px; }
  .replay__duel-gap strong { font-size: 1.25rem; }
  .replay__duel-more { display: none; }
  .replay__synth { margin-bottom: 6px; padding: 6px 10px 7px; }
  .replay__synth .replay__synth-line { margin-top: 3px; font-size: 1rem; }
  .replay__synth .replay__synth-detail { display: none; }
  .replay__finish { inset: 10px 10px 10px auto; width: min(380px, 100% - 20px); }
  .replay__strip { height: 34px; }
  .race--replay .transport__bar { margin-top: 4px; }
  .race--replay::after { height: 200px; }
  .replay__lead h1 { font-size: 1.3rem; }
  .replay__count, .replay__status { top: 50px; }
}
@media (min-width: 900px) {
  .replay__head { padding: 18px 24px; }
  .replay__name { display: block; flex: 1; padding-right: 100px; font-size: 1.05rem; text-align: center; }
  .replay__lead { right: auto; left: 24px; width: min(560px, 100% - 48px); bottom: 30px; }
  .replay__lead h1 { font-size: 2.3rem; }
  .race--replay .race__side { top: 70px; left: 24px; width: 262px; padding: 8px 14px; }
  .replay__band { top: 70px; left: 24px; width: 262px; padding: 4px 14px; }
  .replay__side { top: 70px; left: auto; right: 24px; width: 400px; height: 150px; }
  .replay__band--line { width: auto; padding: 6px 14px 6px 8px; }
  .race--replay .board__pick { font-size: 1rem; }
  .race--replay .board__gap { font-size: 0.9rem; }
  .replay__strip { height: 60px; }
  .replay__finish { inset: 50% 24px auto auto; width: 400px; max-height: calc(100% - 48px); transform: translateY(-50%); }
}

/* Un grand écran, assez haut : la pente reste à l'image tout le replay. Un grand téléphone couché n'en est pas un. */
@media (min-width: 900px) and (min-height: 481px) {
  .race--replay[data-moment="running"][data-close] .replay__side { display: block; }
}

/* --- L'affiche d'un passage ----------------------------------------------- */

.passage-poster { display: grid; gap: 12px; justify-items: center; }
.passage-poster__sheet { position: relative; display: grid; place-items: center; width: min(100%, 540px); aspect-ratio: 4 / 5; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius); background: #0b1322; } /* l'affiche est sombre, quel que soit le thème */
.passage-poster__image { display: block; width: 100%; height: 100%; }
.passage-poster__status { padding: 0 24px; color: #a9bad8; text-align: center; }
.passage-poster__tools { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.passage-poster__note { max-width: 540px; font-size: 0.88rem; text-align: center; }

/* --- Le passage idéal (segment_ideals/show, contrôleur `ideal`) ------------- */

/* Le temps, posé sur le relief : sur un grand écran, le dessin occupe toute la bande et la route se pose à droite du
   texte, qu'un voile garde lisible ; sur un téléphone, le dessin passe sous le texte. Le relief s'estompe vers les
   bords dans la couleur de la page : la bande n'a pas de cadre. */
.ideal-hero { position: relative; display: grid; grid-template-columns: minmax(0, 24rem) minmax(0, 1fr); min-height: 33rem; isolation: isolate; }
.ideal-hero__art { position: absolute; inset: 0; z-index: -1; overflow: hidden; }
.ideal-hero__art::after { content: ""; position: absolute; inset: 0 auto 0 0; width: min(34rem, 60%); background: linear-gradient(90deg, var(--relief-paper) 45%, transparent); pointer-events: none; }
.ideal-hero__relief, .ideal-route { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.ideal-hero__relief { opacity: 0; transition: opacity 0.6s ease; }
.ideal-hero__relief.is-shown { opacity: 1; }
.ideal-route { z-index: 1; overflow: visible; }
.ideal-hero__text { display: grid; align-content: center; justify-items: start; gap: 12px; padding: 28px 0; }
.ideal-hero__kicker { color: var(--accent); font-weight: 650; font-size: 0.93rem; }
.ideal-hero__time { font-size: clamp(3.5rem, 8vw, 5.75rem); font-weight: 800; letter-spacing: -0.055em; line-height: 1; }
.ideal-hero__claim { max-width: 22rem; font-size: clamp(1.15rem, 2.2vw, 1.38rem); font-weight: 700; letter-spacing: -0.03em; line-height: 1.22; }
.ideal-hero__gap { color: var(--muted); }
.ideal-hero__text .row { margin-top: 4px; }
.ideal-hero__credit { position: absolute; right: 12px; bottom: 8px; margin: 0; font-size: 0.72rem; }
@media (max-width: 760px) {
  .ideal-hero { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .ideal-hero__art { position: relative; inset: auto; z-index: 0; order: 2; height: 21rem; margin: 0 -16px; }
  .ideal-hero__art::after { display: none; }
  .ideal-hero__text { padding: 4px 0 0; }
  .ideal-hero__credit { right: 0; bottom: 4px; }
}

.ideal-route__casing { fill: none; stroke: var(--relief-paper); stroke-width: 8; stroke-linecap: round; stroke-linejoin: round; opacity: 0.85; }
.ideal-route__run { fill: none; stroke-width: 3.6; stroke-linecap: round; stroke-linejoin: round; }
.ideal-route__end { fill: var(--text); stroke: var(--relief-paper); stroke-width: 2; }
.ideal-route__words { font: 12px var(--sans); fill: var(--muted); paint-order: stroke; stroke: var(--relief-paper); stroke-width: 3.5px; stroke-linejoin: round; }
.ideal-route__pill circle { stroke: var(--relief-paper); stroke-width: 1.5; }
.ideal-route__pill text { font: 750 12px var(--sans); }
.ideal-route__run--1 { stroke: var(--athlete-1); } .ideal-route__pill--1 circle { fill: var(--athlete-1); } .ideal-route__pill--1 text { fill: var(--athlete-1-ink); }
.ideal-route__run--2 { stroke: var(--athlete-2); } .ideal-route__pill--2 circle { fill: var(--athlete-2); } .ideal-route__pill--2 text { fill: var(--athlete-2-ink); }
.ideal-route__run--3 { stroke: var(--athlete-3); } .ideal-route__pill--3 circle { fill: var(--athlete-3); } .ideal-route__pill--3 text { fill: var(--athlete-3-ink); }
.ideal-route__run--4 { stroke: var(--athlete-4); } .ideal-route__pill--4 circle { fill: var(--athlete-4); } .ideal-route__pill--4 text { fill: var(--athlete-4-ink); }
.ideal-route__run--5 { stroke: var(--athlete-5); } .ideal-route__pill--5 circle { fill: var(--athlete-5); } .ideal-route__pill--5 text { fill: var(--athlete-5-ink); }
.ideal-route__run--6 { stroke: var(--athlete-6); } .ideal-route__pill--6 circle { fill: var(--athlete-6); } .ideal-route__pill--6 text { fill: var(--athlete-6-ink); }
.ideal-route__run--7 { stroke: var(--athlete-7); } .ideal-route__pill--7 circle { fill: var(--athlete-7); } .ideal-route__pill--7 text { fill: var(--athlete-7-ink); }
.ideal-route__run--8 { stroke: var(--athlete-8); } .ideal-route__pill--8 circle { fill: var(--athlete-8); } .ideal-route__pill--8 text { fill: var(--athlete-8-ink); }

/* Le passage idéal et le record, de part et d'autre du temps rond qui les sépare. */
.ideal-gauge { display: block; width: 100%; max-width: 21rem; height: auto; overflow: visible; font: 11.5px var(--sans); }
.ideal-gauge__base { stroke: var(--line-strong); stroke-width: 2; }
.ideal-gauge__span { stroke: var(--accent); stroke-width: 4; stroke-linecap: round; }
.ideal-gauge__barrier { stroke: var(--text); stroke-width: 1.5; }
.ideal-gauge__time { fill: var(--text); font-weight: 650; font-variant-numeric: tabular-nums; }
.ideal-gauge__ideal { fill: var(--accent); }
.ideal-gauge__record { fill: var(--relief-paper); stroke: var(--accent); stroke-width: 2; }
.ideal-gauge__name { fill: var(--muted); }
.ideal-gauge__name--ideal { fill: var(--accent); font-weight: 600; }

/* La grille : une ligne par passage, une case par tronçon, de la largeur du tronçon. */
.ideal-key { display: flex; flex-wrap: wrap; gap: 6px 18px; color: var(--muted); font-size: 0.8rem; }
.ideal-key__item { display: inline-flex; align-items: center; gap: 7px; }
.ideal-key__best { width: 14px; height: 14px; border-radius: 3px; }
.ideal-key__ramp { width: 60px; height: 14px; border-radius: 3px; background: linear-gradient(90deg, var(--ideal-gap-0), var(--ideal-gap-5)); box-shadow: inset 0 0 0 1px var(--line); }
.ideal-grid { display: grid; grid-template-columns: minmax(7rem, 10rem) minmax(0, 1fr) 2.6rem; column-gap: 12px; row-gap: 4px; align-items: center; }
.ideal-grid__label { color: var(--faint); font-size: 0.78rem; text-align: right; }
.ideal-grid__label--end { text-align: left; }
.ideal-grid__track { position: relative; height: 2.1rem; }
.ideal-grid__track--marks { height: 1.2rem; }
.ideal-grid__track--road { height: 2.3rem; }
.ideal-grid__track--ideal { height: 2.1rem; }
.ideal-grid__mark { position: absolute; top: 0; transform: translateX(-50%); color: var(--muted); font-size: 0.72rem; font-variant-numeric: tabular-nums; }
.ideal-grid__profile { position: absolute; inset: 0; width: 100%; height: 100%; }
.ideal-grid__cell { position: absolute; top: 0; bottom: 0; display: grid; place-items: center; overflow: hidden; border-radius: 3px; font-size: 0.72rem; font-weight: 750; font-variant-numeric: tabular-nums; cursor: default; }
.ideal-grid__cell--best { box-shadow: inset 0 0 0 1.5px rgb(255 255 255 / 35%); }
.ideal-grid__cell--gap-0 { background: var(--ideal-gap-0); } .ideal-grid__cell--gap-1 { background: var(--ideal-gap-1); }
.ideal-grid__cell--gap-2 { background: var(--ideal-gap-2); } .ideal-grid__cell--gap-3 { background: var(--ideal-gap-3); }
.ideal-grid__cell--gap-4 { background: var(--ideal-gap-4); } .ideal-grid__cell--gap-5 { background: var(--ideal-gap-5); }
.ideal-grid__who { display: grid; justify-items: end; min-width: 0; line-height: 1.25; }
.ideal-grid__chip { gap: 6px; min-width: 0; max-width: 100%; }
.ideal-grid__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: 0.82rem; font-weight: 500; }
.ideal-grid__time { font-size: 0.86rem; font-weight: 600; white-space: nowrap; }
.ideal-grid__record { padding: 0 6px; font-size: 0.7rem; }
.ideal-grid__held { color: var(--muted); font-size: 0.86rem; }
.ideal-grid__rule { grid-column: 1 / -1; height: 1px; margin: 4px 0; background: var(--line); }
.ideal-grid__bar { position: absolute; bottom: 0; height: 5px; border-radius: 2px; }
.ideal-grid__pill { position: absolute; top: 3px; transform: translateX(-50%); }
.ideal-grid__track--ideal + .ideal-grid__held, .ideal-grid__track--ideal ~ .ideal-grid__held { color: var(--text); font-weight: 650; }
.ideal-grid__detail { min-height: 1.5em; font-size: 0.88rem; }
@media (max-width: 640px) {
  .ideal-grid { grid-template-columns: 5.4rem minmax(0, 1fr) 1.6rem; column-gap: 8px; }
  .ideal-grid__track { height: 1.9rem; }
  .ideal-grid__name { font-size: 0.76rem; }
  .ideal-grid__time { font-size: 0.8rem; }
  .ideal-grid__record { display: none; }
  .ideal-grid__label--end { justify-self: end; white-space: nowrap; font-size: 0.7rem; }
}

/* Ce que la grille dit, en phrases, puis le détail en tableau. */
.ideal-notes { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 16px; }
.ideal-note--wide { grid-column: 1 / -1; }
.ideal-note { display: grid; align-content: start; gap: 8px; }
.ideal-note__kicker { color: var(--accent); font-size: 0.85rem; font-weight: 650; }
.ideal-note__what { display: flex; flex-wrap: wrap; gap: 6px 12px; font-size: 1.05rem; font-weight: 700; letter-spacing: -0.01em; }
.ideal-detail { overflow: hidden; }
.ideal-detail__summary { padding: 14px 20px; cursor: pointer; font-weight: 650; }
.ideal-detail[open] .ideal-detail__summary { border-bottom: 1px solid var(--line); }
