/* ============================================================================
   Atherys — site vitrine
   ----------------------------------------------------------------------------
   Les couleurs et les polices viennent de l'application, pas d'une palette
   inventée pour l'occasion : `docs/design-reference/tokens.jsx` fait foi. Toute
   dérive ici se voit immédiatement à l'écran, côte à côte avec l'app.

   Les polices sont AUTO-HÉBERGÉES (assets/fonts). Un site qui vend « tes
   données restent en Europe » ne peut pas envoyer l'adresse IP de ses
   visiteurs à Google Fonts à chaque chargement.

   Ordre du fichier : polices · tokens · base · primitives · en-tête · motion ·
   maquettes d'app · sections · pied de page · responsive · accessibilité.
   ========================================================================== */

/* ── 1. Polices ─────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/geist-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/geist-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('../fonts/geist-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('../fonts/geist-mono-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── 2. Tokens ──────────────────────────────────────────────────────────────
   DEUX COUCHES depuis la refonte « Aube » (2026-09-24) :

   1. Les jetons de L'APPLICATION (ce bloc-ci, inchangé) : ils dessinent les
      pièces conservées telles quelles — la carte des muscles, le faisceau, les
      écrans de l'app dans les téléphones, la courbe des charges. Leurs valeurs
      ne bougent pas, donc leur rendu non plus. Ne pas « corriger » un contraste
      ici : ce serait changer le dessin de l'app.
   2. Les jetons DU SITE (bloc suivant) : le ciel, le verre, le texte des
      sections, les espacements, les rayons, les courbes. Tout ce qui entoure
      les pièces conservées vient de là.

   Chaque couleur de l'app est déclarée deux fois : hex d'abord, oklch ensuite.
   Un navigateur qui ne connaît pas oklch garde le hex et la page reste juste.

   ⚠️ LE SITE EST EN SOMBRE, UN POINT C'EST TOUT (décision user, 2026-09-11).
   Il n'y a plus de thème clair, plus de `prefers-color-scheme`, plus de bouton
   pour basculer, et plus rien à stocker dans le navigateur du visiteur. Ajouter
   un second jeu de tokens ici, c'est réintroduire un choix que personne n'a
   demandé — et le `color-scheme: dark` ci-dessous dit au navigateur de peindre
   ses propres surfaces (barres de défilement, champs) dans le même registre.
   ------------------------------------------------------------------------- */

:root {
  --bg: #0b0d11;              --bg: oklch(0.16 0.008 260);
  --bg-subtle: #101215;       --bg-subtle: oklch(0.18 0.008 260);
  --surface: #16181c;         --surface: oklch(0.21 0.008 260);
  --surface-2: #1e2124;       --surface-2: oklch(0.245 0.008 260);
  --surface-3: #282a2e;       --surface-3: oklch(0.285 0.008 260);
  --border: #27292d;          --border: oklch(0.28 0.008 260);
  --border-strong: #3b3d41;   --border-strong: oklch(0.36 0.008 260);
  --text: #f7f8fb;            --text: oklch(0.98 0.004 260);
  --text-mid: #b5b7bb;        --text-mid: oklch(0.78 0.006 260);
  --text-muted: #787a7f;      --text-muted: oklch(0.58 0.008 260);
  --text-faint: #4a4d52;      --text-faint: oklch(0.42 0.008 260);
  --accent: #e6e245;          --accent: oklch(0.89 0.17 108);
  --accent-ink: #1e1c00;      --accent-ink: oklch(0.22 0.06 108);
  --accent-subtle: #373500;   --accent-subtle: oklch(0.32 0.07 108);
  --ai-a: #e6e245;            --ai-a: oklch(0.89 0.17 108);
  --ai-b: #bea4ff;            --ai-b: oklch(0.78 0.14 295);
  --ai-c: #58e5ed;            --ai-c: oklch(0.85 0.12 200);
  --success: #67e18f;         --success: oklch(0.82 0.16 152);
  --warn: #ffab55;            --warn: oklch(0.82 0.15 60);
  --danger: #ff6f69;          --danger: oklch(0.72 0.18 25);

  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.4);
  --shadow-2: 0 1px 2px rgb(0 0 0 / 0.4), 0 10px 30px rgb(0 0 0 / 0.32);
  --shadow-3: 0 2px 6px rgb(0 0 0 / 0.45), 0 30px 70px rgb(0 0 0 / 0.45);
  --glow: 0.24;              /* intensité du halo citrine du décor */

  --r-sm: 9px;
  --r-md: 13px;
  --r-lg: 18px;
  --r-xl: 26px;
  --r-full: 999px;

  --wrap: 1180px;
  --gutter: 20px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --dur: 620ms;

  color-scheme: dark;
}

/* Les jetons DU SITE — direction « Aube » (choix user, 2026-09-24).
   Le ciel et le verre sont ceux de l'écran d'entrée de l'application
   (`Atherys-mobile/src/ui/entry/palette.ts`, objet NUIT) : même nuit, même
   aube, même feuille de verre. Qui arrive du site ouvre l'app sur le même ciel.
   La citrine reste rare : l'action principale, et ce que la décision cite. */
:root {
  /* Le ciel, du haut vers le bas */
  --night-0: #030409;
  --night-1: #060912;
  --night-2: #0a1222;
  /* L'aube : cœur bleu froid, voile violet, bande claire sur l'horizon */
  --dawn: #6c96ff;
  --dawn-deep: #4e76f0;
  --dawn-far: #3c5ac8;
  --veil: #9270ff;
  --band: #a8c4ff;
  --halo: #96baff;
  --line-light: #d6e4ff;
  /* Le lever : une touche chaude, seulement à la fin de la page */
  --lever: #ffe2c4;

  /* Le texte des sections : trois niveaux, tous au-dessus de 4,5:1 même sur
     le verre posé devant le cœur de l'aube (le pire cas, calculé). */
  --ink: #f7f8fb;
  --ink-2: #b5b7bb;
  --ink-3: #a9adb4;

  /* Le verre : la feuille de l'entrée de l'app */
  --glass-top: rgba(24, 28, 38, 0.6);
  --glass-bottom: rgba(10, 12, 18, 0.84);
  --glass-edge-top: rgba(255, 255, 255, 0.16);
  --glass-edge-bottom: rgba(255, 255, 255, 0.04);
  --glass-light: rgba(150, 186, 255, 0.14);
  --glass-blur: 18px;
  --glass-shadow: 0 34px 60px -34px rgba(2, 5, 16, 0.95);
  --glass-fill: rgba(255, 255, 255, 0.07);
  --glass-line: rgba(255, 255, 255, 0.18);

  /* Espacements et rayons */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 24px;
  --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px; --s-10: 128px;
  --radius-s: 12px;
  --radius-m: 16px;
  --radius-l: 24px;
  --radius-xl: 32px;
  --radius-pill: 999px;

  /* Les courbes. La sortie franche de l'app (`COURBE`), et deux ressorts
     calculés — raideur 120 / amortissement 16 (3,5 % de dépassement, 700 ms)
     et 320 / 28 (1,9 %, 450 ms). Le repli en cubic-bezier sert aux
     navigateurs qui ne connaissent pas `linear()`. */
  --ease-out: cubic-bezier(0.19, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.2, 1.1, 0.3, 1);
  --dur-spring: 700ms;
  --ease-snap: cubic-bezier(0.2, 1.05, 0.3, 1);
  --dur-snap: 450ms;
}
@supports (transition-timing-function: linear(0, 1)) {
  :root {
    --ease-spring: linear(0, 0.029, 0.101, 0.2, 0.311, 0.425, 0.535, 0.636, 0.725, 0.801, 0.864, 0.915, 0.955, 0.985, 1.006, 1.02, 1.029, 1.034, 1.035, 1.034, 1.031, 1.028, 1.024, 1.02, 1.016, 1.013, 1.01, 1.007, 1.005, 1.003, 1);
    --ease-snap: linear(0, 0.032, 0.109, 0.213, 0.327, 0.441, 0.55, 0.647, 0.732, 0.803, 0.861, 0.908, 0.944, 0.971, 0.99, 1.003, 1.012, 1.017, 1.019, 1.019, 1.018, 1.017, 1.015, 1.012, 1.01, 1.008, 1.006, 1.005, 1.003, 1.002, 1);
  }
}

/* ── 3. Base ────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* L'en-tête flotte : une ancre doit s'arrêter sous lui. */
  scroll-padding-top: 96px;
  /* Le fond du document est la nuit du ciel : c'est lui qu'on voit si le ciel
     n'est pas encore peint, et c'est lui que le navigateur étire au rebond. */
  background: var(--night-0);
}

body {
  margin: 0;
  /* Transparent : le ciel (fixe, sous le contenu) doit se voir à travers. */
  background: transparent;
  color: var(--text);
  font-family: Geist, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg { max-width: 100%; }
svg { display: block; }

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.035em;
  text-wrap: balance;
}
/* L'échelle « Aube » : un titre de premier écran plus grand et plus serré, les
   titres de section un cran au-dessus d'avant — ce sont eux qui rythment la
   page, pas des filets. */
h1 { font-size: clamp(2.7rem, 7.4vw, 5.6rem); letter-spacing: -0.048em; line-height: 0.98; }
h2 { font-size: clamp(2rem, 4.8vw, 3.35rem); letter-spacing: -0.045em; line-height: 1.02; }
h3 { font-size: clamp(1.12rem, 2.1vw, 1.32rem); letter-spacing: -0.02em; line-height: 1.25; }

p { margin: 0; }
a { color: inherit; }

::selection { background: var(--accent); color: var(--accent-ink); }

/* Le contour suit la forme de l'élément (pilule, carte) : pas de rayon imposé
   ici, qui arrondissait une pilule en rectangle au moment du focus. */
:focus-visible {
  outline: 2px solid var(--band);
  outline-offset: 3px;
}

/* ── 4. Primitives ──────────────────────────────────────────────────────── */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  position: relative;
  padding-block: clamp(72px, 9vw, 120px);
}

.eyebrow {
  font-family: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--band);
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.eyebrow::before {
  content: '';
  width: 16px;
  height: 1.5px;
  background: currentColor;
  flex: none;
}

.lede {
  font-size: clamp(1.02rem, 1.5vw, 1.2rem);
  color: var(--ink-2);
  max-width: 56ch;
  line-height: 1.55;
}

/* Les titres de section alternent trois mises en page au lieu d'en répéter
   une seule huit fois : à gauche (défaut), centrée, et partagée (le titre à
   gauche, la phrase à droite). */
.head {
  max-width: 38rem;
  margin-bottom: clamp(38px, 5vw, 62px);
}
.head .lede { margin-top: 18px; }
.head--center { max-width: 30ch; margin-inline: auto; text-align: center; }
.head--center .eyebrow { justify-content: center; }
.head--center .lede { margin-inline: auto; }
.head--split {
  max-width: none;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: 18px clamp(32px, 6vw, 96px);
  align-items: end;
}
.head--split .eyebrow { grid-column: 1 / -1; margin-bottom: 0; }
.head--split .lede { margin-top: 0; padding-bottom: 6px; }
/* Un titre de section réduit à son libellé — « Ton suivi » (demande user,
   2026-09-16) : ce sont ses chapitres qui titrent. */
.head--bare { margin-bottom: clamp(30px, 4vw, 44px); }
.head--bare .eyebrow { margin-bottom: 0; }

/* Le titre qui se lève : le texte glisse depuis sous sa propre ligne. Le
   masque est le titre lui-même (`overflow: hidden`), la marge compense le
   dépassement du ressort et les jambages. Transformation seulement. */
.rise { display: block; overflow: hidden; padding: 0.08em 0.04em 0.1em; margin: -0.08em -0.04em -0.1em; }
.rise > span { display: block; }

.mono {
  font-family: 'Geist Mono', ui-monospace, Menlo, monospace;
  font-variant-numeric: tabular-nums;
}

/* Le verre ------------------------------------------------------------------
   La feuille de l'entrée de l'app : un dégradé sombre et translucide, un liseré
   plus clair en haut, et une lumière froide qui suit le pointeur.

   Le flou d'arrière-plan n'est posé QUE sur ordinateur, là où la souris existe
   et où la carte gpu l'encaisse : sur téléphone, derrière une carte il n'y a
   que le ciel, un dégradé lisse, et le flou ne changerait rien à l'œil tout en
   coûtant une image à chaque défilement. L'en-tête et le menu, eux, gardent
   leur flou partout : du texte passe dessous. */
.glass {
  position: relative;
  isolation: isolate;
  background: linear-gradient(180deg, var(--glass-top), var(--glass-bottom));
  border-radius: var(--radius-l);
  box-shadow: var(--glass-shadow);
}
/* Le liseré : un contour intérieur et un filet plus clair en haut. Des ombres
   intérieures plutôt qu'un bord dégradé découpé par masque : un masque par
   carte coûtait une surface de composition à chaque image d'animation. */
.glass::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 1px 0 var(--glass-edge-top), inset 0 0 0 1px rgb(255 255 255 / 0.07);
  pointer-events: none;
  z-index: -1;
}
.glass::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(360px circle at var(--mx, 50%) var(--my, -40%), var(--glass-light), transparent 62%);
  opacity: 0;
  transition: opacity 500ms var(--ease-out);
  pointer-events: none;
  z-index: -1;
}
@media (hover: hover) and (pointer: fine) {
  .glass:hover::after { opacity: 1; }
}
@media (hover: hover) and (pointer: fine) and (min-width: 900px) {
  .glass {
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(150%);
    backdrop-filter: blur(var(--glass-blur)) saturate(150%);
  }
}
/* Une pièce conservée garde le fond sur lequel elle a été dessinée (la courbe
   des charges cercle ses points de la couleur de sa carte) : le verre ne lui
   prête que son liseré, sa lumière et son ombre. */
.glass--solid { background: var(--surface); }
@media (hover: hover) and (pointer: fine) and (min-width: 900px) {
  .glass--solid { -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* Boutons -------------------------------------------------------------------
   Trois boutons, pas plus. Le principal, en citrine, est rare : une action par
   écran. Le verre sert à tout le reste ; sa variante citrine au trait sert à
   « Télécharger » dans l'en-tête, pour ne jamais avoir deux citrines pleines
   à l'écran. Au survol un reflet traverse le principal ; à l'appui, tous
   s'enfoncent sur un ressort ; au clavier, un contour clair suit leur forme. */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 14px 24px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  transition: transform var(--dur-snap) var(--ease-snap), background-color 250ms var(--ease-out),
    border-color 250ms var(--ease-out), box-shadow 300ms var(--ease-out), color 250ms var(--ease-out);
}
.btn svg { width: 16px; height: 16px; flex: none; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform var(--dur-snap) var(--ease-snap); }
@media (hover: hover) and (pointer: fine) {
  .btn:hover { transform: translateY(-1px); }
  .btn:hover svg { transform: translateY(2px); }
}
.btn:active { transform: scale(0.96); transition-duration: 90ms; }

.btn--accent {
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.55), inset 0 -1px 0 rgb(0 0 0 / 0.14),
    0 14px 34px -14px rgb(230 226 69 / 0.55);
}
.btn--accent::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 30%, rgb(255 255 255 / 0.55) 50%, transparent 70%);
  transform: translateX(-130%);
  transition: transform 900ms var(--ease-out);
  pointer-events: none;
}
@media (hover: hover) and (pointer: fine) {
  .btn--accent:hover::after { transform: translateX(130%); }
}

.btn--glass, .btn--ghost {
  color: var(--ink);
  background: var(--glass-fill);
  border-color: var(--glass-line);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}
@media (hover: hover) and (pointer: fine) {
  .btn--glass:hover, .btn--ghost:hover { background: rgb(255 255 255 / 0.12); border-color: rgb(255 255 255 / 0.3); }
}
.btn--line { color: var(--accent); border-color: rgb(230 226 69 / 0.45); }
@media (hover: hover) and (pointer: fine) {
  .btn--line:hover { border-color: rgb(230 226 69 / 0.8); }
}

.btn--sm { padding: 10px 16px; font-size: 0.86rem; }

/* L'état « en cours » : le libellé s'efface, un anneau tourne à sa place. */
.btn[aria-busy='true'] { color: transparent; pointer-events: none; }
.btn[aria-busy='true']::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border-radius: 50%;
  border: 2px solid var(--accent-ink);
  border-right-color: transparent;
  animation: spin 700ms linear infinite;
}
.btn--glass[aria-busy='true']::before { border-color: var(--ink); border-right-color: transparent; }
@keyframes spin { to { transform: rotate(1turn); } }

/* Badge de magasin ----------------------------------------------------------
   L'application n'est pas encore publiée : le badge est une ANNONCE (trait
   pointillé, pas de relief), pas un bouton qui promettrait un téléchargement.
   Le jour de la publication (voir README) : remplacer le `href` des deux
   `data-store`, « Bientôt sur » par « Télécharger sur », et ajouter la classe
   `store--live` — Apple demande alors son badge officiel, sans retouche. */

.stores {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.store {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 11px 20px 11px 16px;
  border-radius: 16px;
  border: 1px dashed rgb(255 255 255 / 0.3);
  background: rgb(255 255 255 / 0.04);
  color: var(--ink);
  text-decoration: none;
  transition: border-color 250ms var(--ease-out), background-color 250ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .store:hover { border-color: rgb(255 255 255 / 0.5); background: rgb(255 255 255 / 0.07); }
}
.store svg { width: 24px; height: 24px; flex: none; fill: currentColor; }
.store__txt { display: grid; gap: 3px; text-align: left; }
.store__small {
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.store b {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.store--live { border-style: solid; background: #fff; color: #000; border-color: #fff; }
.store--live .store__small { color: #3a3d44; }

/* Le ciel ---------------------------------------------------------------------
   Celui de l'écran d'entrée de l'application, posé une fois sous toute la page
   (`position: fixed`, derrière le contenu). Trois mouvements, tous en
   `transform` et `opacity`, sans aucun flou — comme dans l'app :
   - l'aube RESPIRE : dix secondes, quatre pour monter, six pour redescendre,
     le rythme d'une respiration calme — celle que l'app mesure ;
   - un voile violet DÉRIVE, très lentement ;
   - l'horizon MONTE avec la lecture (`--hz`, posé par le script) : bas au
     premier écran, haut à « Commencer », où la touche chaude du lever
     apparaît (`--lever`). La bande claire de l'horizon ne se montre qu'au
     début et à la fin (`--band-o`) : au milieu de la page, un trait net
     derrière le texte gênerait la lecture.
   Sous `prefers-reduced-motion`, rien ne respire ni ne dérive, l'horizon est
   posé une fois pour toutes. */

.sky {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  contain: strict;
  background: linear-gradient(180deg, var(--night-0) 0%, var(--night-1) 52%, var(--night-2) 100%);
}
.sky i { position: absolute; display: block; }
.sky__hz {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 0;
  transform: translate3d(calc(var(--px, 0) * 10px), var(--hz, 84vh), 0);
  /* Pas de transition sur la position : l'horizon parcourt ~40 % de l'écran sur
     toute la page, il suit la lecture sans à-coup, et une transition relancée à
     chaque image coûtait du travail au défilement. */
  transition: opacity 1200ms var(--ease-out);
  will-change: transform;
}
/* Le ciel se tait pendant qu'on défile (comme l'entrée de l'app pendant qu'on
   écrit) : la respiration et le voile reprennent 400 ms après l'arrêt. */
.sky.is-scrolling .sky__dawn,
.sky.is-scrolling .sky__veil { animation-play-state: paused; }
.sky[data-calm='true'] .sky__hz { opacity: 0.55; }
.sky__dawn {
  left: -30%;
  right: -30%;
  top: -44vh;
  height: 88vh;
  background: radial-gradient(closest-side, rgb(108 150 255 / 0.6), rgb(78 118 240 / 0.32) 36%, rgb(60 90 200 / 0.13) 62%, transparent 80%);
  animation: dawn-breathe 10s ease-in-out infinite;
}
.sky__veil {
  left: 4%;
  width: 72%;
  top: -40vh;
  height: 56vh;
  background: radial-gradient(closest-side, rgb(146 112 255 / 0.26), transparent 75%);
  animation: veil-drift 26s ease-in-out infinite alternate;
}
.sky__lever {
  left: 18%;
  right: 18%;
  top: -34vh;
  height: 56vh;
  background: radial-gradient(closest-side, rgb(255 226 196 / 0.4), rgb(255 226 196 / 0.12) 55%, transparent 80%);
  opacity: var(--lever, 0);
  transition: opacity 1200ms var(--ease-out);
}
.sky__glow {
  left: 8%;
  right: 8%;
  top: -48px;
  height: 96px;
  background: radial-gradient(closest-side, rgb(150 186 255 / 0.32), transparent 80%);
  opacity: var(--band-o, 1);
  transition: opacity 800ms var(--ease-out);
}
.sky__band {
  left: 0;
  right: 0;
  top: -1px;
  height: 2px;
  background: linear-gradient(90deg, transparent 4%, rgb(168 196 255 / 0.5) 30%, rgb(214 228 255 / 0.9) 50%, rgb(168 196 255 / 0.5) 70%, transparent 96%);
  opacity: var(--band-o, 1);
  transition: opacity 800ms var(--ease-out);
}
.sky__ground {
  left: 0;
  right: 0;
  top: 0;
  height: 200vh;
  /* Part de zéro sur l'horizon : une opacité non nulle au départ y dessinait
     une marche. */
  background: linear-gradient(180deg, transparent 0, rgb(3 4 9 / 0.22) 8vh, rgb(3 4 9 / 0.86) 40vh);
}
/* Le grain : un bruit très fin qui empêche les dégradés sombres de marcher
   en escalier sur les écrans 8 bits. Fusion normale : un mode « overlay » sur
   tout l'écran se recalculait à chaque image de la respiration. */
.sky__grain {
  inset: 0;
  opacity: 0.03;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
@keyframes dawn-breathe {
  0%, 100% { opacity: 0.72; transform: scale(1, 1); }
  40%      { opacity: 1;    transform: scale(1.04, 1.12); }
}
@keyframes veil-drift {
  from { transform: translate3d(-6%, 0, 0); }
  to   { transform: translate3d(18%, -3vh, 0); }
}
/* Sur un téléphone, l'aube doit rester large par rapport à l'écran. */
@media (max-width: 700px) {
  .sky__dawn { left: -70%; right: -70%; }
  .sky__veil { left: -10%; width: 110%; }
}
/* Les pages de texte (légales, 404) : le même ciel, figé et plus bas. */
.sky--still .sky__hz { transform: translate3d(0, 92vh, 0); transition: none; }
.sky--still .sky__dawn, .sky--still .sky__veil { animation: none; }
.sky--still .sky__dawn { opacity: 0.6; }

/* ── 5. En-tête ─────────────────────────────────────────────────────────────
   Une pilule de verre qui flotte à 12 px du haut, et se resserre dès qu'on
   défile. Sous le lien de la section en cours, un repère glisse sur un
   ressort (posé par le script). Sous 1000 px, les liens partent dans une
   feuille de verre qui monte du bas de l'écran, comme celle de l'entrée de
   l'application.

   Le flou est porté par un pseudo-élément, pas par la barre elle-même : un
   `backdrop-filter` sur la barre ferait d'elle le repère de la feuille mobile
   (`position: fixed`), qui ne couvrirait plus l'écran. */

.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  padding: 12px var(--gutter) 0;
  pointer-events: none;
}
.site-header__bar {
  pointer-events: auto;
  position: relative;
  z-index: 2;
  isolation: isolate;
  display: flex;
  align-items: center;
  gap: 14px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 8px 8px 8px 20px;
  border-radius: var(--radius-pill);
  transition: max-width 700ms var(--ease-out), padding 500ms var(--ease-out);
}
.site-header__bar::before,
.nav::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: linear-gradient(180deg, rgb(24 28 38 / 0.62), rgb(10 12 18 / 0.78));
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  backdrop-filter: blur(18px) saturate(160%);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.1), inset 0 0 0 1px rgb(255 255 255 / 0.07), 0 14px 34px -18px rgb(0 0 0 / 0.9);
}
.site-header[data-stuck='true'] .site-header__bar { max-width: 1010px; padding-block: 6px; }

.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--ink);
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.045em;
  line-height: 1;
}
.brand svg { width: 16px; height: 14px; fill: currentColor; }

.nav {
  position: relative;
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: auto;
}
.nav a {
  position: relative;
  z-index: 1;
  padding: 9px 13px;
  border-radius: var(--radius-pill);
  text-decoration: none;
  font-size: 0.9rem;
  color: var(--ink-2);
  white-space: nowrap;
  transition: color 250ms var(--ease-out), background-color 250ms var(--ease-out);
}
.nav a:hover, .nav a[aria-current='true'] { color: var(--ink); }
.nav a:nth-of-type(1) { --i: 0; }
.nav a:nth-of-type(2) { --i: 1; }
.nav a:nth-of-type(3) { --i: 2; }
.nav a:nth-of-type(4) { --i: 3; }
.nav a:nth-of-type(5) { --i: 4; }
.nav a:nth-of-type(6) { --i: 5; }
.nav__ind {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: var(--w, 0px);
  transform: translateX(var(--x, 0px));
  border-radius: var(--radius-pill);
  background: rgb(255 255 255 / 0.08);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.1);
  opacity: var(--o, 0);
  pointer-events: none;
  transition: transform var(--dur-spring) var(--ease-spring), width var(--dur-spring) var(--ease-spring), opacity 300ms var(--ease-out);
}
.nav::before { display: none; }

.header-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
/* Sur grand écran, la navigation porte déjà la marge qui pousse à droite. Sous
   1000 px elle sort du flux (feuille mobile) : les boutons reprennent la marge.
   C'était le défaut de l'ancien en-tête : le bouton collé au logo. */
@media (min-width: 1000px) {
  .nav ~ .header-actions { margin-left: 0; }
}

.burger {
  display: none;
  width: 42px;
  height: 42px;
  flex: none;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--glass-line);
  background: var(--glass-fill);
  color: var(--ink);
  cursor: pointer;
  transition: transform var(--dur-snap) var(--ease-snap), background-color 250ms var(--ease-out);
}
.burger:active { transform: scale(0.94); }
.burger span,
.burger span::before,
.burger span::after {
  display: block;
  width: 16px;
  height: 1.5px;
  background: currentColor;
  border-radius: 1px;
  transition: transform var(--dur-snap) var(--ease-snap), background-color 200ms;
}
.burger span { position: relative; }
.burger span::before, .burger span::after { content: ''; position: absolute; left: 0; }
.burger span::before { transform: translateY(-5px); }
.burger span::after { transform: translateY(5px); }
.burger[aria-expanded='true'] span { background: transparent; }
.burger[aria-expanded='true'] span::before { transform: rotate(45deg); }
.burger[aria-expanded='true'] span::after { transform: rotate(-45deg); }

/* Le voile derrière la feuille mobile : un toucher dessus referme le menu. */
.site-header::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 1;
  background: rgb(3 4 9 / 0.62);
  opacity: 0;
  visibility: hidden;
  pointer-events: auto;
  transition: opacity 350ms var(--ease-out), visibility 0s linear 350ms;
}
.site-header.is-open::after { opacity: 1; visibility: visible; transition-delay: 0s; }
html.menu-open { overflow: hidden; }

@media (max-width: 999px) {
  .burger { display: grid; }
  .nav__ind { display: none; }
  .nav {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    z-index: 3;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    margin: 0;
    padding: 16px 10px 10px;
    border-radius: 30px;
    visibility: hidden;
    opacity: 0;
    transform: translate3d(0, 28px, 0) scale(0.98);
    transform-origin: 50% 100%;
    transition: transform var(--dur-spring) var(--ease-spring), opacity 300ms var(--ease-out), visibility 0s linear 300ms;
  }
  .nav::before { display: block; }
  .nav a {
    padding: 13px 16px;
    border-radius: 16px;
    font-size: 1.5rem;
    font-weight: 600;
    letter-spacing: -0.03em;
    color: var(--ink);
    opacity: 0;
    transform: translate3d(0, 12px, 0);
    transition: opacity 400ms var(--ease-out), transform var(--dur-spring) var(--ease-spring), background-color 200ms;
  }
  .nav a[aria-current='true'] { background: rgb(255 255 255 / 0.07); }
  .site-header.is-open .nav { visibility: visible; opacity: 1; transform: none; transition-delay: 0s; }
  .site-header.is-open .nav a { opacity: 1; transform: none; transition-delay: calc(90ms + var(--i) * 40ms); }
}

/* ── 6. Motion ──────────────────────────────────────────────────────────────
   Le geste de référence : opacité 0 → 1 et une montée de 24 px portée par le
   ressort doux (3,5 % de dépassement), 70 ms de décalage entre voisins. Les
   cartes de verre arrivent de plus loin, avec une légère mise à l'échelle.
   Les titres de section « se lèvent » : le texte glisse depuis sous sa propre
   ligne (`.rise`). Chaque élément n'entre QU'UNE FOIS — on ne rejoue rien en
   remontant.

   `.js` n'est posé sur <html> que si le script tourne : sans JavaScript, rien
   n'est masqué et la page reste entièrement lisible.
   ------------------------------------------------------------------------- */

.js .reveal {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  transition: opacity 700ms var(--ease-out), transform var(--dur-spring) var(--ease-spring);
  transition-delay: var(--d, 0ms);
}
.js .reveal.is-in {
  opacity: 1;
  transform: none;
}
.js .glass.reveal { transform: translate3d(0, 34px, 0) scale(0.975); transition-duration: 800ms, 900ms; }
.js .glass.reveal.is-in { transform: none; }
/* Le titre qui se lève : le titre reste en place, son texte monte. */
.js .reveal--rise { opacity: 1; transform: none; }
.js .reveal--rise .rise > span {
  transform: translate3d(0, 112%, 0);
  transition: transform 1000ms var(--ease-spring);
  transition-delay: var(--d, 0ms);
}
.js .reveal--rise.is-in .rise > span { transform: none; }

/* Les transitions de page : un fondu croisé natif entre l'accueil et les pages
   légales (Chrome et Safari ; ailleurs, la navigation reste normale). Rien en
   mouvement réduit. */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 380ms; animation-timing-function: cubic-bezier(0.19, 1, 0.3, 1); }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* Ce que le script masque lui-même (la pastille « je retiens » attend la fin de
   la frappe). Posée en JS : sans script, elle reste visible. */
.js-hidden { opacity: 0; transform: translate3d(0, 10px, 0); }
[data-type-after] { transition: opacity 480ms var(--ease), transform 480ms var(--ease); }

/* ── 7. Maquettes d'application ─────────────────────────────────────────────
   Le téléphone et son contenu sont dessinés, pas photographiés : ce sont les
   vrais tokens, les vraies formes et les vraies phrases de l'app.
   ------------------------------------------------------------------------- */

/* Le cadre (refonte « Aube ») : un liseré froid et une lumière d'aube sous le
   téléphone. Les cotes ne bougent pas — 7 px de marge et 1 px de bord — pour
   que l'écran garde exactement sa taille, donc son dessin. */
.phone {
  --screen: 288px;
  width: var(--screen);
  flex: none;
  aspect-ratio: 9 / 19.3;
  border-radius: 42px;
  padding: 7px;
  background: linear-gradient(160deg, #2b3140, #0c0f16 60%);
  border: 1px solid rgb(255 255 255 / 0.1);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.14), 0 50px 90px -40px rgb(60 100 230 / 0.5),
    0 30px 60px -30px rgb(0 0 0 / 0.9);
  position: relative;
}
.phone::after {
  /* Reflet très bas : le téléphone est un objet posé. */
  content: '';
  position: absolute;
  inset: 1px;
  border-radius: 41px;
  background: linear-gradient(150deg, rgb(255 255 255 / 0.09), transparent 42%);
  pointer-events: none;
}
/* Le reflet qui traverse l'écran une fois, à l'arrivée. */
.phone__glare { position: absolute; inset: 8px; z-index: 3; border-radius: 34px; overflow: hidden; pointer-events: none; }
.phone__glare::before {
  content: '';
  position: absolute;
  top: -10%;
  bottom: -10%;
  left: 0;
  width: 55%;
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.12) 50%, transparent);
  transform: translate3d(-130%, 0, 0) skewX(-14deg);
}
/* L'inclinaison vers la souris (ordinateur seulement, posée par le script). */
[data-tilt] {
  transform: perspective(1400px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform 1100ms var(--ease-spring);
}
.phone__screen {
  height: 100%;
  border-radius: 35px;
  overflow: hidden;
  background: var(--bg);
  position: relative;
  display: flex;
  flex-direction: column;
}

/* Pile de scènes : sur téléphone une seule scène, empilée normalement ; sur
   grand écran les quatre se superposent (voir § scènes épinglées). */
.pane-stack { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.pane { flex: 1; min-height: 0; display: flex; flex-direction: column; }

.abar {
  height: 5px;
  border-radius: var(--r-full);
  background: var(--surface-3);
  overflow: hidden;
}
.abar > i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--accent);
  transform-origin: left center;
}

.amacros { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 9px; }
.amacro span {
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  display: block;
  margin-bottom: 5px;
}
.amacro b { font-size: 11px; font-weight: 500; display: block; margin-bottom: 4px; }
.amacro .abar > i { background: var(--ai-a); }
.amacro:nth-child(2) .abar > i { background: var(--ai-b); }
.amacro:nth-child(3) .abar > i { background: var(--warn); }

/* ── 8. Premier écran ───────────────────────────────────────────────────────
   Nuit profonde, aube basse. L'entrée est en CSS pur, gardée derrière
   `prefers-reduced-motion: no-preference` : sans animation, tout est déjà à
   sa place. Le titre n'est jamais caché par une opacité nulle — ses lignes
   glissent depuis sous leur propre masque, donc le plus grand élément de la
   page est peint dès la première image. */

.hero {
  position: relative;
  padding-top: clamp(128px, 17vh, 184px);
  padding-bottom: clamp(64px, 9vw, 112px);
}
.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}
.hero h1 { margin-bottom: 24px; }
/* Deux lignes, toujours : « Une décision. » puis « Une évolution. », comme
   l'écran d'arrivée de l'app. Chaque ligne est son propre masque. */
.hero__line { display: block; overflow: hidden; padding: 0.06em 0.05em 0.1em; margin: -0.06em -0.05em -0.1em; }
.hero__line > span { display: block; }
.hero h1 em { font-style: normal; }
/* « Une évolution. » prend la lumière de l'aube. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero__em > span {
    background: linear-gradient(180deg, #f1f5ff 8%, #9fbdff 92%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}
@media (forced-colors: active) {
  .hero__em > span { background: none; color: CanvasText; }
}
.hero .lede { max-width: 46ch; }
.hero__cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 36px;
}
.hero__stage { justify-self: end; }

/* Trois couches pour le téléphone : l'entrée (ici), la parallaxe au
   défilement (`.float`, script) et l'inclinaison vers la souris
   (`[data-tilt]`, script). */
/* La couche .float reçoit sa translation du script, directement (une
   variable héritée ferait recalculer tout l'écran du téléphone à chaque image). */

@media (prefers-reduced-motion: no-preference) {
  .hero__in { animation: hero-in 900ms var(--ease-out) both; animation-delay: calc(80ms + var(--k) * 110ms); }
  .hero__line > span { animation: hero-line 1000ms var(--ease-spring) both; animation-delay: calc(120ms + var(--k) * 110ms); }
  .hero__stage { animation: hero-phone 1400ms var(--ease-spring) both; animation-delay: 60ms; }
  .phone--hero .phone__glare::before { animation: glare 1500ms var(--ease-out) 1500ms both; }
}
@keyframes hero-in { from { opacity: 0; transform: translate3d(0, 18px, 0); } }
@keyframes hero-line { from { transform: translate3d(0, 112%, 0); } }
/* Sans opacité : le téléphone (et sa photo, le plus grand élément de la page
   sur ordinateur) est peint dès la première image, il ne fait que se poser. */
@keyframes hero-phone { from { transform: perspective(1400px) translate3d(0, 80px, 0) rotateX(22deg) scale(0.94); } }
@keyframes glare {
  from { transform: translate3d(-130%, 0, 0) skewX(-14deg); }
  to   { transform: translate3d(280%, 0, 0) skewX(-14deg); }
}

/* ── 10. Sections épinglées ─────────────────────────────────────────────────
   Deux moments dans toute la page, pas cinq. La scène reste fixe pendant que
   son contenu progresse ; sous 900 px, tout se remet à plat et se lit
   normalement (une scène collée sur un téléphone, c'est une page qui coince).
   ------------------------------------------------------------------------- */

.pin__stage { position: relative; }
.pin__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(32px, 5vw, 78px);
  align-items: center;
}

/* Les quatre étapes sont des feuilles de verre. Sur grand écran, pendant la
   scène épinglée, seule l'étape en cours garde sa feuille ; les autres restent
   lisibles (texte à plus de 7:1 — l'ancienne opacité de 34 % tombait à 2,1:1),
   et un rail à gauche suit la progression (`--pin-p`, posé par le script). */
.steps { position: relative; display: grid; gap: 8px; }
.step {
  position: relative;
  padding: 16px 20px 17px;
  border-radius: var(--radius-m);
  background: linear-gradient(180deg, var(--glass-top), var(--glass-bottom));
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.08);
  transition: background-color 500ms var(--ease-out), box-shadow 500ms var(--ease-out);
}
.step h3 { margin-bottom: 6px; font-size: 1.16rem; transition: color 400ms var(--ease-out); }
.step p { color: var(--ink-2); font-size: 0.97rem; max-width: 46ch; transition: color 400ms var(--ease-out); }
.step__n {
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10.5px;
  letter-spacing: 0.12em;
  color: var(--ink-3);
  display: block;
  margin-bottom: 4px;
  transition: color 400ms var(--ease-out);
}

@media (min-width: 900px) {
  .pin__track { position: relative; }
  .pin__stage {
    position: sticky;
    top: 0;
    min-height: 100vh;
    display: flex;
    align-items: center;
    padding-block: 92px 36px;
  }
  .pin .head { max-width: 36rem; }
  .pin h2 { font-size: clamp(2rem, 3.6vw, 2.9rem); }
  .pin .steps { max-width: 580px; }
  .pin .step { padding: 13px 20px 14px; }
  .pin .step h3 { font-size: 1.08rem; margin-bottom: 4px; }
  .pin .step p { font-size: 0.93rem; line-height: 1.5; }
  /* Le rail et sa part remplie. */
  .js .pin .steps { padding-left: 22px; }
  .js .pin .steps::before,
  .js .pin .steps::after {
    content: '';
    position: absolute;
    left: 0;
    top: 10px;
    bottom: 10px;
    width: 2px;
    border-radius: 2px;
    background: rgb(255 255 255 / 0.1);
  }
  .js .pin .steps::after {
    background: linear-gradient(180deg, var(--accent), var(--band));
    transform-origin: 50% 0;
    transform: scaleY(var(--pin-p, 0));
  }
  /* L'étape en retrait perd sa feuille, pas sa lisibilité. Sans JavaScript,
     aucune étape n'est en retrait : tout se lit. */
  .js .pin .step:not(.is-active) { background: transparent; box-shadow: none; }
  .js .pin .step:not(.is-active) h3 { color: var(--ink-2); }
  .js .pin .step:not(.is-active) p { color: var(--ink-3); }
  .js .pin .step.is-active { box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.1), var(--glass-shadow); }
  .js .pin .step.is-active .step__n { color: var(--accent); }
  /* L'écran change d'état en glissant : l'état suivant monte de 18 px sur le
     ressort doux pendant que le précédent s'efface. */
  .js .pin .pane-stack { position: relative; flex: 1; min-height: 0; }
  .js .pin .pane {
    position: absolute;
    inset: 0;
    opacity: 0;
    transform: translate3d(0, 18px, 0) scale(0.985);
    transition: opacity 420ms var(--ease-out), transform var(--dur-spring) var(--ease-spring);
  }
  .js .pin .pane.is-active { opacity: 1; transform: none; }
}

/* Sans script, les quatre états du même écran ne peuvent pas se relayer : on
   n'en montre qu'un, au lieu de les empiler ou d'en masquer trois à l'opacité
   (du contenu invisible est du contenu perdu). */
html:not(.js) .pin .pane + .pane { display: none; }

/* ── 11. Ce que dit ton corps ───────────────────────────────────────────── */

.body-grid {
  display: grid;
  grid-template-columns: auto minmax(0, 620px);
  justify-content: space-between;
  gap: clamp(32px, 5vw, 78px);
  align-items: start;
}
/* La scène de la carte : un cadre de verre, et dedans le noir d'origine — la
   couleur de trait qui sépare les muscles (voir index.html). */
.body-grid__visual { position: sticky; top: 104px; }
.stage { padding: 12px; }
.stage__in { background: var(--bg); border-radius: calc(var(--radius-l) - 8px); padding: 24px 16px 26px; }
.body-blocks { display: grid; gap: 14px; }
.body-block { padding: 24px 26px 22px; }
.body-block h3 { margin-bottom: 8px; }
.body-block p { color: var(--ink-2); max-width: 52ch; font-size: 0.98rem; }

/* Les chiffres : le compteur, et sous lui ses graduations qui s'allument (une
   par signal, une par jour). Le masque dessine les graduations, une barre
   glisse dessous : l'allumage est une translation. */
.stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-top: 4px;
}
.stat { padding: 18px 16px 16px; display: grid; gap: 10px; align-content: start; border-radius: var(--radius-m); }
.stat__num { display: flex; align-items: baseline; gap: 6px; }
.stat b {
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.6rem, 3.2vw, 2.1rem);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1;
}
.stat u {
  text-decoration: none;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 0.72rem;
  color: var(--ink-3);
}
.stat span {
  font-size: 0.83rem;
  color: var(--ink-3);
  line-height: 1.4;
}
.ticks {
  position: relative;
  display: block;
  height: 7px;
  margin-top: 4px;
  overflow: hidden;
  background: rgb(255 255 255 / 0.12);
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 calc(100% / var(--n) - 3px), transparent 0 calc(100% / var(--n)));
  mask: repeating-linear-gradient(90deg, #000 0 calc(100% / var(--n) - 3px), transparent 0 calc(100% / var(--n)));
}
.ticks::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--band);
}
.js .ticks::after { transform: translate3d(-101%, 0, 0); transition: transform 1400ms var(--ease-out) 400ms; }
.js .stat.is-in .ticks::after { transform: none; }

/* Silhouette : chaque groupe se colore à son entrée, une seule fois.
   Dans un cadre, avec sa légende à côté : posée nue au milieu d'une colonne de
   texte, elle ressemblait à un décor, pas à un écran de l'application. */
.muscle-scale {
  height: 7px;
  border-radius: var(--r-full);
  background: linear-gradient(90deg, var(--fresh-1), var(--fresh-2), var(--fresh-3), var(--fresh-4));
}
.muscle-scale__ends {
  display: flex;
  justify-content: space-between;
  margin-top: 6px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ── 12. Manger sans compter ────────────────────────────────────────────── */

.list { display: grid; gap: 20px; margin: 0; padding: 0; list-style: none; }
.list li { display: grid; grid-template-columns: 30px minmax(0, 1fr); gap: 14px; align-items: start; }
.list li svg { width: 19px; height: 19px; stroke: var(--accent); fill: none; stroke-width: 1.6; margin-top: 3px; }
.list b { display: block; font-weight: 600; letter-spacing: -0.015em; margin-bottom: 3px; }
.list p { color: var(--ink-2); font-size: 0.96rem; max-width: 52ch; }
/* Les listes à pictogrammes deviennent des cartes de verre (mêmes textes). Le
   pictogramme se pose dans une tuile ; au survol, il se soulève d'un rien. */
.list--cards { gap: 12px; }
.list--cards li { grid-template-columns: 40px minmax(0, 1fr); gap: 16px; padding: 20px 22px 20px 20px; border-radius: var(--radius-m); }
.list--cards li svg {
  width: 40px;
  height: 40px;
  margin-top: 0;
  padding: 10px;
  border-radius: 12px;
  stroke: var(--band);
  background: rgb(255 255 255 / 0.06);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.1);
  transition: transform var(--dur-snap) var(--ease-snap);
}
@media (hover: hover) and (pointer: fine) {
  .list--cards li:hover svg { transform: translateY(-2px) rotate(-4deg); }
}
.list--cards b { font-size: 1.02rem; margin: 2px 0 5px; }

/* ── 13. Le coach — la conversation, le moment de voix ──────────────────────
   La mise en page de la section (deux rangées en quinconce) est au bloc G,
   avec l'écran de séance. Ici : la conversation elle-même. */

.voice { position: relative; }
/* Le filet IA, en ligne d'horizon irisée : les trois teintes IA de l'app et
   une lueur qui les prolonge. */
.ai-rule {
  position: relative;
  height: 2px;
  width: 190px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--ai-a), var(--ai-b), var(--ai-c));
  box-shadow: 0 0 18px rgb(190 164 255 / 0.55);
  margin-bottom: 26px;
}
.caret {
  display: inline-block;
  width: 2px;
  height: 1em;
  background: var(--accent);
  vertical-align: -2px;
  margin-left: 1px;
  animation: blink 1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }
/* ── 14. Bilan de la semaine ────────────────────────────────────────────── */

.review__line {
  display: flex;
  gap: 12px;
  padding: 13px 0;
  border-top: 1px solid rgb(255 255 255 / 0.08);
  font-size: 0.94rem;
  color: var(--ink-2);
}
.review__line:first-of-type { border-top: 0; }
.review__line svg { width: 16px; height: 16px; flex: none; margin-top: 3px; stroke-width: 1.8; fill: none; }
.review__line b { color: var(--text); font-weight: 500; }

/* ── 15. Confidentialité — la section qui ne bouge presque pas ─────────────
   Même fond que le reste de la page (la bande plus claire d'avant cassait la
   continuité). Six cartes sobres ; elles entrent en simple fondu, sans
   mouvement : le sérieux ne s'anime pas. */

.trust__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.trust__item { padding: 22px 22px 21px; border-radius: var(--radius-m); }
.trust__item h3 { font-size: 1.02rem; margin-bottom: 7px; }
.trust__item p { color: var(--ink-2); font-size: 0.94rem; }
.trust__item svg {
  width: 40px;
  height: 40px;
  padding: 10px;
  border-radius: 12px;
  stroke: var(--band);
  fill: none;
  stroke-width: 1.6;
  background: rgb(255 255 255 / 0.06);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.1);
  margin-bottom: 16px;
}
/* Le fondu seul : ni montée, ni mise à l'échelle. */
.js .reveal.reveal--fade,
.js .glass.reveal.reveal--fade { transform: none; transition: opacity 900ms var(--ease-out); transition-delay: var(--d, 0ms); }

/* ── 16. Questions fréquentes ───────────────────────────────────────────────
   Le titre à gauche, collé pendant la lecture ; les questions à droite, dans
   des cartes de verre qui s'ouvrent et se referment en hauteur (script : le
   `<details>` natif reste la base, il marche sans lui et au clavier). */

.faq-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: clamp(32px, 6vw, 96px);
  align-items: start;
}
.faq-layout .head { position: sticky; top: 120px; margin-bottom: 0; }
.faq { display: grid; gap: 10px; }
.faq details { border-radius: var(--radius-m); padding: 0 24px; }
.faq summary {
  list-style: none;
  cursor: pointer;
  padding: 21px 48px 21px 0;
  position: relative;
  font-size: 1.03rem;
  font-weight: 500;
  letter-spacing: -0.018em;
  color: var(--ink);
  transition: color 200ms var(--ease-out);
}
.faq summary::-webkit-details-marker { display: none; }
@media (hover: hover) and (pointer: fine) {
  .faq summary:hover { color: var(--band); }
}
/* Le signe + dans son cercle ; il pivote en × à l'ouverture. */
.faq summary::before,
.faq summary::after {
  content: '';
  position: absolute;
  right: 0;
  top: 50%;
  width: 28px;
  height: 28px;
  margin-top: -14px;
  border-radius: 50%;
}
.faq summary::before { box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.2); transition: background-color 300ms var(--ease-out); }
.faq summary::after {
  background:
    linear-gradient(currentColor 0 0) center / 11px 1.5px no-repeat,
    linear-gradient(currentColor 0 0) center / 1.5px 11px no-repeat;
  transition: transform var(--dur-snap) var(--ease-snap);
}
.faq details[open]:not(.is-closing) summary::before { background: rgb(255 255 255 / 0.08); }
.faq details[open]:not(.is-closing) summary::after { transform: rotate(135deg); }
.faq__body p {
  padding-bottom: 22px;
  color: var(--ink-2);
  max-width: 62ch;
  font-size: 0.98rem;
}

/* ── 17. Fin + pied de page ─────────────────────────────────────────────── */

/* La fin : une grande feuille de verre, au moment où le jour se lève (le ciel
   y est haut, et sa touche chaude apparaît). */
.end { text-align: center; }
.end__sheet {
  max-width: 880px;
  margin: 0 auto;
  padding: clamp(44px, 7vw, 88px) clamp(20px, 5vw, 64px);
  border-radius: var(--radius-xl);
  display: grid;
  justify-items: center;
  box-shadow: var(--glass-shadow), 0 70px 140px -70px rgb(255 226 196 / 0.35);
}
.end__sheet .eyebrow { justify-content: center; }
.end h2 { max-width: 16ch; margin-inline: auto; }
.end .lede { margin: 20px auto 34px; }
.end .stores { justify-content: center; }
.end__note { margin-top: 20px; font-size: 0.92rem; color: var(--ink-3); }

.site-footer {
  padding-block: 8px 28px;
  font-size: 0.9rem;
  color: var(--ink-3);
}
.site-footer__card { padding: clamp(24px, 4vw, 40px); border-radius: var(--radius-l); }
.site-footer__top {
  display: flex;
  flex-wrap: wrap;
  gap: 24px 40px;
  justify-content: space-between;
  align-items: flex-start;
}
.site-footer nav {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 26px;
}
.site-footer a {
  color: var(--ink-2);
  text-decoration: none;
  text-underline-offset: 4px;
  transition: color 200ms var(--ease-out);
}
.site-footer a:hover { color: var(--ink); text-decoration: underline; }
/* Les attributions Ciqual et Open Food Facts : leur licence en exige
   l'affichage, elles passent donc au contraste AA (2,3:1 avant). */
.site-footer__legal {
  margin-top: 28px;
  padding-top: 20px;
  border-top: 1px solid rgb(255 255 255 / 0.08);
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
  justify-content: space-between;
  font-size: 0.82rem;
  color: var(--ink-3);
  line-height: 1.5;
}
.site-footer__legal p { max-width: 62ch; }

/* ── 9 bis. Les pièces animées ─────────────────────────────────────────────
   Quatre moments de la page ne montrent pas un téléphone posé mais le
   mécanisme lui-même, en mouvement : les signaux qui convergent vers un
   verdict, l'assiette qui se décompose, la courbe des charges qui se trace,
   la semaine qui se dessine. (La frise de la journée a existé ici ; la section
   a été retirée le 2026-09-15 à la demande du user.)

   RÈGLE TENUE PARTOUT ICI : rien n'est masqué sans le préfixe `.js`. Les
   enfants attendent le `.is-in` de leur PARENT (posé par l'observateur sur le
   conteneur `.reveal`), et leur cascade est écrite en `transition-delay` — pas
   une ligne de JavaScript de plus.

   Deux exceptions assumées à « transform et opacity seulement » : le tracé des
   fils et de l'anneau se fait en `stroke-dashoffset`, et la couleur des muscles
   en `fill`. Ce sont des animations d'ENTRÉE, jouées une fois, hors défilement,
   sur des éléments qui ne provoquent pas de recalcul de mise en page — la règle
   visait le défilement continu, pas ça.
   ------------------------------------------------------------------------- */

/* ═══ B · Le faisceau : six signaux, un verdict ════════════════════════════ */

.hub {
  position: relative;
  margin-bottom: clamp(56px, 8vw, 96px);
  padding-top: 8px;
  /* Une couleur par signal (demande user, 2026-09-15) : les six sont allumés,
     pastille, fil et impulsion de la même teinte. Violet et cyan sont les
     teintes IA de l'application (aiB, aiC des tokens), vert et orange ses
     couleurs sémantiques ; la charge garde la citrine, c'est elle que la
     décision cite. */
  --sig-1: #b4a1f2;  --sig-1: oklch(0.78 0.14 295);  /* sommeil */
  --sig-2: #f47c8c;  --sig-2: oklch(0.74 0.17 15);   /* cœur au repos */
  --sig-3: #7edbe9;  --sig-3: oklch(0.85 0.12 200);  /* respiration */
  --sig-4: #f8a054;  --sig-4: oklch(0.8 0.15 55);    /* température */
  --sig-5: #67e18f;  --sig-5: oklch(0.82 0.16 152);  /* séances */
  --sig-6: var(--accent);                            /* charge */
}
.signal:nth-child(1), .hub__wires path:nth-child(1), .pulse:nth-child(1) { --sig: var(--sig-1); }
.signal:nth-child(2), .hub__wires path:nth-child(2), .pulse:nth-child(2) { --sig: var(--sig-2); }
.signal:nth-child(3), .hub__wires path:nth-child(3), .pulse:nth-child(3) { --sig: var(--sig-3); }
.signal:nth-child(4), .hub__wires path:nth-child(4), .pulse:nth-child(4) { --sig: var(--sig-4); }
.signal:nth-child(5), .hub__wires path:nth-child(5), .pulse:nth-child(5) { --sig: var(--sig-5); }
.signal:nth-child(6), .hub__wires path:nth-child(6), .pulse:nth-child(6) { --sig: var(--sig-6); }

.hub__signals { position: relative; height: 74px; }
.signal {
  position: absolute;
  left: var(--x);
  top: 0;
  width: 150px;
  margin-left: -75px;
  text-align: center;
}
.signal__name {
  display: block;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-mid);
}
.signal__val {
  display: block;
  font-size: 11.5px;
  color: var(--text-muted);
  margin-top: 4px;
}
.signal__dot {
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--sig);
  box-shadow: 0 0 14px color-mix(in srgb, var(--sig) 70%, transparent);
  margin: 12px auto 0;
}
.signal--on .signal__name { color: var(--text); }
.signal--on .signal__val { color: var(--text-mid); }

.hub__wires { display: block; width: 100%; height: clamp(150px, 19vw, 230px); }
.hub__wires path {
  fill: none;
  stroke: var(--sig);
  stroke-opacity: 0.7;
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
}
.hub__wires .wire--on { stroke-opacity: 1; stroke-width: 1.5; }
.js .hub__wires path {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset 1000ms var(--ease);
  transition-delay: calc(220ms + var(--i) * 90ms);
}
.js .hub.is-in .hub__wires path { stroke-dashoffset: 0; }

.hub__core { text-align: center; margin-top: -10px; position: relative; }
/* L'hexagone (demande user, 2026-09-24) remplace l'anneau : un halo large et
   pâle, le fond sombre teinté de citrine, un hexagone intérieur en filigrane,
   et le contour qui se trace depuis l'arrivée des fils. Le halo de fond mêle
   la citrine à l'aube. */
.core {
  position: relative;
  width: 168px;
  height: 147px;
  margin: 0 auto;
}
.core::before {
  content: '';
  position: absolute;
  inset: -40px;
  border-radius: 50%;
  background: radial-gradient(circle, rgb(230 226 69 / 0.17), rgb(108 150 255 / 0.1) 46%, transparent 70%);
  opacity: 0;
  transition: opacity 900ms var(--ease) 800ms;
}
.js .hub.is-in .core::before { opacity: 1; }
.core__hex { width: 100%; height: 100%; overflow: visible; }
.core__halo { fill: none; stroke: var(--accent); stroke-width: 12; stroke-opacity: 0.09; stroke-linejoin: round; }
.core__fill { fill: url(#core-fill); stroke: var(--surface-3); stroke-width: 4; stroke-linejoin: round; }
.core__inner { fill: none; stroke: rgb(230 226 69 / 0.16); stroke-width: 1; stroke-linejoin: round; }
.core__arc {
  fill: none;
  stroke: var(--accent);
  stroke-width: 3.5;
  stroke-linejoin: round;
  stroke-linecap: round;
  filter: drop-shadow(0 0 6px rgb(230 226 69 / 0.5));
}
.js .core__arc {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset 1100ms var(--ease) 850ms;
}
.js .hub.is-in .core__arc { stroke-dashoffset: 0; }
.core__num {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  line-height: 1;
}
.core__num b {
  font-size: 46px;
  font-weight: 600;
  letter-spacing: -0.04em;
  display: block;
}
.core__num span {
  display: block;
  margin-top: 7px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.core__verdict {
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  margin-top: 18px;
}
.core__normale {
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 6px;
}
.hub__out {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 26px;
  padding: 9px 18px;
  border-radius: var(--r-full);
  border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 11.5px;
  letter-spacing: 0.06em;
  color: var(--accent);
}
.js .hub__out {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition: opacity 700ms var(--ease) 1500ms, transform 700ms var(--ease) 1500ms;
}
.js .hub.is-in .hub__out { opacity: 1; transform: none; }

/* ═══ B bis · Le faisceau, vivant (2026-09-15) ═════════════════════════════
   Le faisceau n'entrait en scène qu'une fois, puis se figeait. Il vit
   désormais en continu, en trois mouvements — tous en `transform` et
   `opacity`, et tous coupés sous `prefers-reduced-motion` :

   1. chaque pastille de signal ÉMET : un anneau part d'elle et s'efface, à
      tour de rôle — c'est le signal qui arrive de la montre ;
   2. des impulsions DESCENDENT les fils jusqu'à l'anneau (posées et déplacées
      par le script, un point SVG dans ce SVG étiré serait une ellipse, et la
      couche qui les porte couvre exactement le SVG) ; chacune a la couleur de
      son signal, celle de la charge est plus grosse ;
   3. le halo de l'anneau RESPIRE, et l'anneau tressaille à chaque impulsion
      reçue.

   Sous 860 px les six fils n'ont plus la place : un seul fil vertical, en CSS,
   porte trois impulsions vers l'anneau. */

.signal__dot { position: relative; }
.signal__dot::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  border: 1.5px solid var(--sig);
  opacity: 0;
  transform: scale(1);
}
.js .hub.is-in .signal__dot::after {
  animation: signal-ping 3s cubic-bezier(0.2, 0.7, 0.3, 1) infinite;
  animation-delay: calc(1.4s + var(--i, 0) * 0.5s);
}
.signal:nth-child(1) { --i: 0; }
.signal:nth-child(2) { --i: 1; }
.signal:nth-child(3) { --i: 2; }
.signal:nth-child(4) { --i: 3; }
.signal:nth-child(5) { --i: 4; }
.signal:nth-child(6) { --i: 5; }
@keyframes signal-ping {
  0%   { opacity: 0.9; transform: scale(1); }
  45%  { opacity: 0; transform: scale(3.2); }
  100% { opacity: 0; transform: scale(3.2); }
}

.hub__beam { position: relative; }
.hub__pulses { position: absolute; inset: 0; pointer-events: none; }
.pulse {
  position: absolute;
  left: 0;
  top: 0;
  width: 7px;
  height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  background: var(--sig);
  box-shadow: 0 0 12px color-mix(in srgb, var(--sig) 80%, transparent);
  opacity: 0;
  will-change: transform, opacity;
}
.pulse--on {
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  box-shadow: 0 0 16px color-mix(in srgb, var(--sig) 90%, transparent);
}

.js .hub.is-in .core::before { animation: core-breathe 4.2s ease-in-out 1.9s infinite; }
@keyframes core-breathe {
  0%, 100% { opacity: 0.72; transform: scale(1); }
  50%      { opacity: 1; transform: scale(1.09); }
}
.core { transition: transform 260ms var(--ease); }
.core.is-hit { transform: scale(1.035); transition-duration: 120ms; }

/* Le fil du téléphone : un trait vertical entre la grille des signaux et
   l'anneau, trois impulsions qui le descendent en décalé. */
.hub__flow { display: none; }
@media (max-width: 860px) {
  .hub__flow {
    display: block;
    position: relative;
    width: 2px;
    height: 64px;
    margin: -18px auto 8px;
    border-radius: 1px;
    background: linear-gradient(180deg, transparent, var(--border-strong) 25%, var(--border-strong) 75%, transparent);
    /* Pas de rognage : les points (6 px) débordent du trait (2 px), ce sont
       les images-clés (opacité 0 aux deux bouts) qui les cachent hors du trait. */
  }
  .hub__flow i {
    position: absolute;
    left: -2px;
    top: -8px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 80%, transparent);
    opacity: 0;
  }
  .js .hub.is-in .hub__flow i { animation: flow-drop 2.7s linear infinite; }
  .hub__flow i:nth-child(2) { animation-delay: 0.9s !important; background: var(--sig-3); box-shadow: 0 0 10px color-mix(in srgb, var(--sig-3) 80%, transparent); }
  .hub__flow i:nth-child(3) { animation-delay: 1.8s !important; background: var(--sig-1); box-shadow: 0 0 10px color-mix(in srgb, var(--sig-1) 80%, transparent); }
  @keyframes flow-drop {
    0%   { opacity: 0; transform: translate3d(0, 0, 0); }
    12%  { opacity: 1; }
    88%  { opacity: 1; }
    100% { opacity: 0; transform: translate3d(0, 72px, 0); }
  }
}

/* ═══ C · Les silhouettes — le corps, animé (2026-09-15) ═══════════════════
   Le dessin de l'application, repris tel quel : `react-native-body-highlighter`
   (MIT, © 2022 ELABBASSI Hicham). Chaque tracé porte son groupe (`data-g`) et
   son palier de fraîcheur (`data-m`, 1 à 4) ; tête, mains, pieds restent
   neutres.

   Trois mouvements, dans l'ordre où on les voit :
   1. À l'entrée, la couleur DESCEND du haut vers le bas — chaque tracé attend
      selon sa hauteur (`--y`, posé par le script depuis sa boîte), pendant
      qu'une bande de lumière balaie la figure. Le balayage repasse ensuite
      toutes les neuf secondes, à peine visible : la figure est vivante, elle
      ne clignote pas.
   2. Les deux groupes les plus chargés RESPIRENT (une lente variation de
      luminosité) : ce sont eux qui décident de la séance du soir.
   3. Au survol (ou au toucher), un groupe s'allume sur les deux vues, les
      autres se retirent, et la ligne au-dessus dit son état.

   Les quatre couleurs sont celles de l'application (`recoveryPalette`, thème
   sombre) : vert = prêt, jaune = presque, orange = chargé, rouge = laisse-le
   tranquille. Sémantiques, pas décoratives — la citrine n'y entre pas. */

:root {
  --fresh-1: #66dc93;  --fresh-1: oklch(0.8 0.15 152);
  --fresh-2: #e0cd52;  --fresh-2: oklch(0.85 0.13 100);
  --fresh-3: #f39c4a;  --fresh-3: oklch(0.78 0.15 55);
  --fresh-4: #ee6152;  --fresh-4: oklch(0.68 0.19 25);
}

.bodies { position: relative; }
.bodies__hint {
  display: flex;
  justify-content: center;
  align-items: baseline;
  gap: 10px;
  min-height: 22px;
  margin-bottom: 12px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-muted);
  transition: opacity 240ms var(--ease);
}
.bodies__hint b { color: var(--text); font-weight: 500; }
.bodies__hint .pct { color: var(--accent); }
.bodies__figures {
  position: relative;
  display: flex;
  gap: clamp(8px, 1.4vw, 18px);
  justify-content: center;
  align-items: flex-start;
  overflow: hidden;
  border-radius: 24px;
}
.body {
  width: clamp(150px, 17vw, 232px);
  height: auto;
  flex: none;
  position: relative;
}
.body path {
  fill: var(--surface-2);
  stroke: var(--bg);
  stroke-width: 3;
  stroke-linejoin: round;
}
.body path[data-m] { cursor: pointer; }
.js .body path {
  transition:
    fill 700ms var(--ease) calc(var(--y, 0) * 900ms),
    opacity 320ms var(--ease),
    stroke 320ms var(--ease);
}
.bodies.is-in [data-m='1'] { fill: var(--fresh-1); }
.bodies.is-in [data-m='2'] { fill: var(--fresh-2); }
.bodies.is-in [data-m='3'] { fill: var(--fresh-3); }
.bodies.is-in [data-m='4'] { fill: var(--fresh-4); }

/* Le survol : le groupe s'allume sur les deux vues, les autres se retirent. */
.bodies.is-dim .body path[data-m] { opacity: 0.45; }
.bodies.is-dim .body path.is-hot { opacity: 1; stroke: var(--text); }

/* La bande de lumière qui balaie la figure : à l'entrée, puis toutes les neuf
   secondes, en `transform` et `opacity` seulement. */
.bodies__scan {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 30%;
  background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--text) 9%, transparent) 50%, transparent);
  opacity: 0;
  transform: translate3d(0, -110%, 0);
  pointer-events: none;
  z-index: 1;
}
.js .bodies.is-in .bodies__scan { animation: body-scan 9s linear 200ms infinite; }
@keyframes body-scan {
  0%   { opacity: 0; transform: translate3d(0, -110%, 0); }
  3%   { opacity: 1; }
  15%  { opacity: 1; transform: translate3d(0, 340%, 0); }
  17%  { opacity: 0; }
  100% { opacity: 0; transform: translate3d(0, 340%, 0); }
}

/* Les deux groupes les plus chargés respirent. `filter` plutôt qu'`opacity` :
   l'opacité sert déjà au retrait des autres groupes au survol, et une animation
   qui la tiendrait l'emporterait sur ce retrait. Quatre tracés au plus, sur une
   figure de 230 px : le coût est nul. Troisième exception assumée à « transform
   et opacité seulement », avec le fil tracé et la couleur des muscles. */
.js .bodies.is-in [data-m='4'],
.js .bodies.is-in [data-m='3'] { animation: muscle-breathe 3400ms ease-in-out 1600ms infinite; }
@keyframes muscle-breathe {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.24); }
}

.bodies__legend { margin-top: 24px; max-width: 330px; margin-inline: auto; }
.bodies__legend p {
  margin-top: 16px;
  font-size: 0.93rem;
  color: var(--text-mid);
  line-height: 1.5;
}
.bodies__note {
  display: block;
  margin-top: 10px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* ═══ C bis · L'écran Accueil, dessiné à l'identique ═══════════════════════
   Le téléphone du premier écran montre l'écran Accueil tel qu'il est dans
   l'application (capture du 2026-09-15). Il est DESSINÉ, pas collé : la
   capture était trop petite pour un écran Retina, et l'application et le site
   ont la même police, Geist — le dessin est net à toute taille et le prénom
   est celui du site. Toutes les cotes sont celles de la capture (380 px de
   large), exprimées en `--u` = un pixel de la capture rapporté à la largeur
   réelle de l'écran ; le dessin suit donc `--screen` à chaque point de
   rupture. Les couleurs sont les tokens ; les trois qui n'en sont pas (bleu du
   sommeil, orange de la charge, violet du coach) sont relevées sur la capture. */

.home {
  /* Largeur de l'écran = cadre moins 7 px de marge et 1 px de bord de chaque côté. */
  --u: calc((var(--screen) - 16px) / 380);
  /* Les deux teintes que l'écran Accueil pose lui-même (DashboardScreen) :
     sommeil et charge. */
  --home-blue: #6f9fe6;    --home-blue: oklch(0.72 0.12 260);
  --home-orange: #e3774f;  --home-orange: oklch(0.7 0.15 40);
  --home-violet: #b4a1f2;
  flex: 1;
  min-height: 0;
  position: relative;
  overflow: hidden;
  padding: 0 calc(20 * var(--u));
  background: var(--bg);
  color: var(--text);
  line-height: 1.2;
}
.home__status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: calc(50 * var(--u));
  padding: calc(14 * var(--u)) calc(8 * var(--u)) 0;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: calc(14 * var(--u));
  font-weight: 600;
}
.home__status i {
  display: inline-block;
  width: calc(21 * var(--u));
  height: calc(11 * var(--u));
  border: calc(1.5 * var(--u)) solid var(--text-muted);
  border-radius: calc(3.5 * var(--u));
  position: relative;
}
.home__status i::after {
  content: '';
  position: absolute;
  inset: calc(2 * var(--u));
  right: calc(5 * var(--u));
  background: var(--text);
  border-radius: calc(1.5 * var(--u));
}
.home__bar { display: flex; align-items: center; gap: calc(8 * var(--u)); height: calc(34 * var(--u)); margin-top: calc(23 * var(--u)); }
.home__brand {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
  margin-right: auto;
  font-size: calc(17 * var(--u));
  font-weight: 600;
  letter-spacing: -0.02em;
}
.home__brand svg { width: calc(20 * var(--u)); height: calc(17 * var(--u)); fill: currentColor; }
.home__bell {
  width: calc(34 * var(--u));
  height: calc(34 * var(--u));
  border-radius: calc(10 * var(--u));
  border: calc(1 * var(--u)) solid var(--border);
  background: var(--bg-subtle);
  display: grid;
  place-items: center;
}
.home__bell svg, .home__streak svg, .tile svg, .home__tabs svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.home__bell svg { width: calc(16 * var(--u)); height: calc(16 * var(--u)); }
.home__me {
  width: calc(34 * var(--u));
  height: calc(34 * var(--u));
  border-radius: 50%;
  background: var(--accent-subtle);
  color: var(--accent);
  display: grid;
  place-items: center;
  font-size: calc(13 * var(--u));
  font-weight: 600;
}
.home__date, .home__coach, .home__kicker {
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: calc(10.5 * var(--u));
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
/* La date est un « label » de l'application (Geist Medium 11 pt, capitales),
   seul le nom du coach est en mono. */
.home__date { margin-top: calc(20 * var(--u)); font-family: 'Geist', system-ui, sans-serif; font-size: calc(9.7 * var(--u)); letter-spacing: calc(0.7 * var(--u)); }
.home__hello { margin-top: calc(5.3 * var(--u)); font-size: calc(26.5 * var(--u)); font-weight: 600; letter-spacing: calc(-0.88 * var(--u)); line-height: calc(28.3 * var(--u)); }
.home__quote {
  margin-top: calc(14 * var(--u));
  padding-left: calc(12 * var(--u));
  border-width: 0 0 0 calc(2 * var(--u));
  border-style: solid;
  border-image: linear-gradient(180deg, var(--accent), var(--home-violet)) 1;
}
.home__coach { display: block; font-size: calc(10 * var(--u)); letter-spacing: 0.12em; }
/* Corps « body » de l'application : Geist Medium 14 pt, interlettrage −0,2,
   sur un écran de 430 pt — la capture (380 px) est à l'échelle 0,884. */
.home__quote p { margin: calc(4 * var(--u)) 0 0; font-size: calc(12.4 * var(--u)); font-weight: 500; letter-spacing: calc(-0.18 * var(--u)); line-height: calc(17.7 * var(--u)); color: var(--text-mid); }
.home__streak { margin-top: calc(14 * var(--u)); display: flex; align-items: center; gap: calc(7 * var(--u)); font-size: calc(12.4 * var(--u)); font-weight: 500; letter-spacing: calc(-0.18 * var(--u)); color: var(--text-mid); }
.home__streak svg { width: calc(15 * var(--u)); height: calc(15 * var(--u)); color: var(--accent); }

.home__card { margin-top: calc(15 * var(--u)); background: var(--surface); border-radius: calc(20 * var(--u)); padding: calc(16 * var(--u)) calc(16 * var(--u)) calc(14 * var(--u)); }
/* « Tes constantes du jour » est un libellé « label » de l'application : Geist
   Medium 11 pt en capitales, pas la mono. */
.home__kicker { font-family: 'Geist', system-ui, sans-serif; font-size: calc(9.7 * var(--u)); letter-spacing: calc(0.7 * var(--u)); }
.home__rings { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-top: calc(12 * var(--u)); }
.ring { display: grid; justify-items: center; position: relative; }
/* Anneau de l'application : 90 pt, trait de 8 ; le chiffre en mono medium 19 pt. */
.ring svg { width: calc(79.6 * var(--u)); height: calc(79.6 * var(--u)); transform: rotate(-90deg); }
.ring__track { fill: none; stroke: var(--surface-3); stroke-width: 8; }
.ring__arc { fill: none; stroke: var(--c); stroke-width: 8; stroke-linecap: round; stroke-dasharray: var(--p) 100; }
.ring b {
  position: absolute;
  top: calc(39.8 * var(--u));
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: calc(16.8 * var(--u));
  font-weight: 500;
  letter-spacing: calc(-0.44 * var(--u));
  white-space: nowrap;
}
.ring b i, .tile b i { font-style: normal; font-size: calc(9.7 * var(--u)); font-weight: 500; letter-spacing: 0; color: var(--text-muted); margin-left: calc(1 * var(--u)); }
.ring span { margin-top: calc(7.1 * var(--u)); font-size: calc(10.6 * var(--u)); font-weight: 500; letter-spacing: calc(-0.18 * var(--u)); color: var(--text-muted); }
/* À l'arrivée, les arcs se tracent — comme dans l'application. */
.js .home .ring__arc { stroke-dasharray: 0 100; transition: stroke-dasharray 1100ms var(--ease) 700ms; }
.js .is-in .home .ring__arc { stroke-dasharray: var(--p) 100; }

.home__tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: calc(8.8 * var(--u)); margin-top: calc(14.1 * var(--u)); }
.tile {
  background: var(--surface-2);
  border: calc(1 * var(--u)) solid var(--border);
  border-radius: calc(14 * var(--u));
  padding: calc(9.7 * var(--u));
  display: grid;
  gap: 0;
}
/* Tuile de l'application : icône 15 pt, valeur en mono medium 16 pt, unité en
   Geist Medium 11 pt, libellé « body » 10 pt. */
.tile svg { width: calc(13.3 * var(--u)); height: calc(13.3 * var(--u)); stroke-width: 1.8; margin-bottom: calc(7.1 * var(--u)); }
.tile b { font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(14.1 * var(--u)); font-weight: 500; letter-spacing: calc(-0.27 * var(--u)); white-space: nowrap; color: var(--text); }
.tile b i { font-family: 'Geist', system-ui, sans-serif; margin-left: calc(3.5 * var(--u)); }
.tile span { margin-top: calc(1.8 * var(--u)); font-size: calc(8.8 * var(--u)); font-weight: 500; color: var(--text-muted); }
.home__advice { margin: calc(10 * var(--u)) 0 0; font-size: calc(12.4 * var(--u)); font-weight: 500; letter-spacing: calc(-0.18 * var(--u)); line-height: calc(16.8 * var(--u)); color: var(--text-mid); }

.home__session {
  position: relative;
  margin: calc(10 * var(--u)) calc(-12 * var(--u)) 0;
  height: calc(230 * var(--u));
  border-radius: calc(20 * var(--u));
  overflow: hidden;
  background: var(--surface);
}
.home__session img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 35%; }
.home__session::before {
  content: '';
  position: absolute;
  inset: 0;
  /* Le voile de l'application : 0,38 en haut, 0,06 à 40 %, 0,86 en bas. */
  background: linear-gradient(180deg, rgb(0 0 0 / 0.38), rgb(0 0 0 / 0.06) 40%, rgb(0 0 0 / 0.86) 100%);
}
.home__session-top {
  position: absolute;
  top: calc(12 * var(--u));
  left: calc(12 * var(--u));
  right: calc(12 * var(--u));
  display: flex;
  justify-content: space-between;
  font-size: calc(9.7 * var(--u));
  font-weight: 600;
  letter-spacing: calc(1.06 * var(--u));
  text-transform: uppercase;
  color: #fff;
}
.home__session-top span + span { font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(11.5 * var(--u)); font-weight: 500; letter-spacing: 0; text-transform: none; opacity: 0.92; }
/* Le titre s'arrête là où l'écran s'arrête, comme sur la capture : la
   deuxième ligne du nom passe sous la barre d'onglets, « 5 exercices » est
   coupé par le bord. */
.home__session-title { position: absolute; left: calc(12 * var(--u)); right: calc(12 * var(--u)); bottom: calc(8 * var(--u)); }
.home__session-title b { display: block; font-size: calc(22 * var(--u)); font-weight: 600; letter-spacing: -0.025em; line-height: calc(26 * var(--u)); }
.home__session-title span { display: block; margin-top: calc(3 * var(--u)); font-size: calc(12 * var(--u)); color: var(--text-mid); }

.home__tabs {
  position: absolute;
  left: calc(22 * var(--u));
  bottom: calc(36 * var(--u));
  width: calc(280 * var(--u));
  height: calc(55 * var(--u));
  border-radius: calc(28 * var(--u));
  background: rgb(39 39 41 / 0.92);
  -webkit-backdrop-filter: blur(calc(12 * var(--u)));
  backdrop-filter: blur(calc(12 * var(--u)));
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 0 calc(8 * var(--u));
}
.home__tabs span { width: calc(40 * var(--u)); height: calc(40 * var(--u)); border-radius: calc(12 * var(--u)); display: grid; place-items: center; color: var(--text-mid); }
.home__tabs span.on { background: #36373b; color: var(--text); }
.home__tabs svg { width: calc(21 * var(--u)); height: calc(21 * var(--u)); stroke-width: 1.6; }
.home__enzo {
  position: absolute;
  right: calc(17 * var(--u));
  bottom: calc(39 * var(--u));
  width: calc(54 * var(--u));
  height: calc(54 * var(--u));
  border-radius: 50%;
  background: rgb(39 39 41 / 0.92);
  display: grid;
  place-items: center;
}
.home__enzo b {
  width: calc(44 * var(--u));
  height: calc(44 * var(--u));
  border-radius: 50%;
  background: linear-gradient(135deg, var(--home-violet), var(--accent));
  color: var(--accent-ink);
  display: grid;
  place-items: center;
  font-size: calc(15 * var(--u));
  font-weight: 600;
}
.home__homebar {
  position: absolute;
  left: 50%;
  bottom: calc(12 * var(--u));
  width: calc(140 * var(--u));
  height: calc(5 * var(--u));
  border-radius: calc(3 * var(--u));
  background: rgb(255 255 255 / 0.9);
  transform: translateX(-50%);
}

/* ═══ C ter · Les écrans de l'application, dessinés (2026-09-25) ═══════════
   Le programme épinglé (quatre états), la conversation du coach et la séance
   montrent de VRAIS écrans de l'application (demande user, 2026-09-24),
   relevés dans son code — ProgramScreen, programPanels, ProgramReviewCard,
   CoachMemoryScreen, ChatScreen, turns, ActionCard, ActiveSessionScreen,
   AtherysTabBar — et comparés à l'application qui tourne. Comme `.home`, ils
   sont DESSINÉS, pas collés : une cote = un point de l'application, et `--u`
   rapporte les 390 points de large d'un iPhone à la largeur réelle de l'écran
   dessiné, donc le dessin suit le cadre à chaque point de rupture. Les
   couleurs sont les jetons de l'app ; les quatre qui manquaient au site (le
   panneau « cockpit » de `ui/Panel` et l'accent doux des charges conseillées)
   sont calculées depuis leur oklch, comme les autres. La typographie est
   celle que l'app REND (`lib/typography`) : insécables ordinaires, apostrophes
   courbes — pas celle du reste du site. */

.scr {
  --u: calc((var(--screen) - 16px) / 390);
  --hair: calc(0.5 * var(--u));   /* `StyleSheet.hairlineWidth` : un pixel de l'écran */
  --glass: rgb(39 39 41 / 0.9);   /* le verre de la barre, relevé sur l'iPhone du user (`.home__tabs`) */
  --panel-top: #1a1d20;     --panel-top: oklch(0.228 0.008 260);
  --panel-bottom: #15171b;  --panel-bottom: oklch(0.205 0.008 260);
  --panel-border: #292b2f;  --panel-border: oklch(0.29 0.008 260);
  --accent-soft: #d0d082;   --accent-soft: oklch(0.84 0.1 108);
  flex: 1;
  min-height: 0;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  /* `body` de l'app : Geist Medium 14, interlettrage −0,2 — hérité partout où
     l'app ne dit rien d'autre, chiffres en mono compris. */
  font-size: calc(14 * var(--u));
  font-weight: 500;
  letter-spacing: calc(-0.2 * var(--u));
  line-height: 1.3;
}
/* Les remises à zéro sont sans poids (`:where`) : une règle à une seule
   classe, comme `.ses__exo`, doit toujours les battre. */
:where(.scr) b, :where(.scr) strong, :where(.scr) small { font-weight: inherit; font-size: inherit; }
:where(.scr) i { font-style: normal; }
:where(.scr) svg {
  flex: none;
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.scr .pane { overflow: hidden; }

.scr__status {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: calc(50 * var(--u));
  padding: calc(14 * var(--u)) calc(28 * var(--u)) 0;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: calc(14 * var(--u));
  font-weight: 600;
  letter-spacing: 0;
}
.scr__status i {
  width: calc(21 * var(--u));
  height: calc(11 * var(--u));
  border: calc(1.5 * var(--u)) solid var(--text-muted);
  border-radius: calc(3.5 * var(--u));
  position: relative;
}
.scr__status i::after {
  content: '';
  position: absolute;
  inset: calc(2 * var(--u));
  right: calc(5 * var(--u));
  background: var(--text);
  border-radius: calc(1.5 * var(--u));
}

/* La page : `Screen` de l'app — gouttière de 18, 20 en haut (Programme) ou 16. */
.scr__page { padding: calc(20 * var(--u)) calc(18 * var(--u)) 0; }
.scr__page--16 { padding-top: calc(16 * var(--u)); }

/* `label` de l'app : Geist Medium 11, interlettrage 0,8, capitales. */
.scr__label {
  display: block;
  font-size: calc(11 * var(--u));
  letter-spacing: calc(0.8 * var(--u));
  text-transform: uppercase;
  color: var(--text-muted);
}
/* Le bouton carré des en-têtes. */
.scr__btn {
  flex: none;
  width: calc(38 * var(--u));
  height: calc(38 * var(--u));
  display: grid;
  place-items: center;
  border-radius: calc(12 * var(--u));
  background: var(--surface);
  border: calc(1 * var(--u)) solid var(--border);
  color: var(--text);
}
.scr__btn svg { width: calc(17 * var(--u)); height: calc(17 * var(--u)); stroke-width: 1.7; }
.scr__btn--40 { width: calc(40 * var(--u)); height: calc(40 * var(--u)); border-radius: calc(14 * var(--u)); }
.scr__btn--40 svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); stroke-width: 1.9; }
/* `Btn` accent, grande taille : 52 de haut, rayon 16, Geist SemiBold 15. */
.scr__cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(8 * var(--u));
  height: calc(52 * var(--u));
  padding: 0 calc(18 * var(--u));
  border-radius: calc(16 * var(--u));
  background: var(--accent);
  color: var(--accent-ink);
  font-size: calc(15 * var(--u));
  font-weight: 600;
  letter-spacing: calc(-0.1 * var(--u));
}
.scr__cta svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); stroke-width: 2.4; }

/* `Card` : la surface de presque tout l'app. */
.scr__card {
  position: relative;
  overflow: hidden;
  background: var(--surface);
  border: var(--hair) solid var(--border);
  border-radius: calc(22 * var(--u));
  box-shadow: 0 calc(2 * var(--u)) calc(6 * var(--u)) rgb(0 0 0 / 0.25);
}
/* `Card ai` : le voile violet → citrine des cartes où le coach propose. */
.scr__card--ai::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(220deg, rgb(190 164 255 / 0.15), transparent 60%, rgb(230 226 69 / 0.13));
}
.scr__card--ai > * { position: relative; }
/* `Panel` : le panneau « cockpit » — plus clair en haut, un liseré sur
   l'arête, l'ombre courte portée vers le bas. */
.scr__panel {
  position: relative;
  border: calc(1 * var(--u)) solid var(--panel-border);
  border-radius: calc(24 * var(--u));
  background: linear-gradient(180deg, var(--panel-top), var(--panel-bottom));
  box-shadow: 0 calc(12 * var(--u)) calc(32 * var(--u)) calc(-20 * var(--u)) rgb(0 0 0 / 0.9);
}
.scr__panel::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(12 * var(--u));
  right: calc(12 * var(--u));
  height: calc(1 * var(--u));
  background: rgb(255 255 255 / 0.07);
}
/* Le bas d'un panneau déjà remonté sous la barre d'état : la page est déroulée. */
.scr__panel--tail {
  height: calc(18 * var(--u));
  border-top: 0;
  border-radius: 0 0 calc(24 * var(--u)) calc(24 * var(--u));
  background: var(--panel-bottom);
}
.scr__panel--tail::before { content: none; }
.scr__panel--tail-s { height: calc(8 * var(--u)); }
/* `Pill`. */
.scr__pill {
  display: inline-flex;
  align-items: center;
  gap: calc(4 * var(--u));
  padding: calc(3 * var(--u)) calc(8 * var(--u));
  border-radius: 999px;
  background: var(--accent-subtle);
  color: var(--accent);
  font-size: calc(11 * var(--u));
  letter-spacing: calc(0.2 * var(--u));
  white-space: nowrap;
}
.scr__pill svg { width: calc(11 * var(--u)); height: calc(11 * var(--u)); stroke-width: 2.5; }
/* Les mesures dans la parole du coach : Geist Mono, un point plus petit,
   resserrées — davantage sur un décimal (`chat/coachText.tsx`). */
.scr__n { font-family: 'Geist Mono', ui-monospace, monospace; font-size: 0.9333em; letter-spacing: calc(-0.6 * var(--u)); }
.scr__n--dec { letter-spacing: calc(-1.1 * var(--u)); }
/* Le curseur de frappe de l'app : « ▍ » en gris, qui ne clignote pas. */
.scr .caret {
  width: 0.36em;
  height: 1.05em;
  margin-left: 0.22em;
  vertical-align: -0.16em;
  background: var(--text-muted);
  animation: none;
}

/* La barre d'onglets (`AtherysTabBar`) : une capsule de verre posée sur le
   contenu — quatre onglets sans étiquettes — et le coach dans son propre
   bouton, à côté. Cotes de l'app : 64 de haut, 16 du bord, 10 entre les deux,
   36 du bas sur un iPhone à encoche. */
.scr__tabs,
.scr__coach {
  position: absolute;
  bottom: calc(36 * var(--u));
  height: calc(64 * var(--u));
  border-radius: calc(32 * var(--u));
  background: linear-gradient(180deg, rgb(255 255 255 / 0.06), transparent calc(32 * var(--u))), var(--glass);
  -webkit-backdrop-filter: blur(calc(12 * var(--u)));
  backdrop-filter: blur(calc(12 * var(--u)));
  box-shadow: inset 0 0 0 calc(1 * var(--u)) rgb(255 255 255 / 0.13), 0 calc(8 * var(--u)) calc(18 * var(--u)) rgb(0 0 0 / 0.5);
}
.scr__tabs {
  left: calc(16 * var(--u));
  width: calc(284 * var(--u));
  display: flex;
  align-items: center;
}
.scr__tabs span {
  flex: 1;
  height: 100%;
  display: grid;
  place-items: center;
  position: relative;
  color: var(--text-mid);
}
/* La plaque de l'onglet actif : sourde, elle situe sans colorer. */
.scr__tabs span::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(48 * var(--u));
  height: calc(44 * var(--u));
  margin: calc(-22 * var(--u)) 0 0 calc(-24 * var(--u));
  border-radius: calc(15 * var(--u));
  background: rgb(255 255 255 / 0.13);
  opacity: 0;
  transform: scale(0.82);
  transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
}
.scr__tabs svg { position: relative; }
.scr__tabs .on { color: var(--text); }
.scr__tabs .on svg { stroke-width: 1.9; }
.scr__tabs .on::before { opacity: 1; transform: none; }
/* Sur « Ce qu'il retient » (pile Profil, qui n'est pas dans la capsule),
   aucun onglet n'est allumé. Sans `:has()`, la plaque reste : sans gravité. */
.pane-stack:has(> .pane--profile.is-active) ~ .scr__tabs .on { color: var(--text-mid); }
.pane-stack:has(> .pane--profile.is-active) ~ .scr__tabs .on svg { stroke-width: 1.6; }
.pane-stack:has(> .pane--profile.is-active) ~ .scr__tabs .on::before { opacity: 0; transform: scale(0.82); }
.scr__coach {
  right: calc(16 * var(--u));
  width: calc(64 * var(--u));
  display: grid;
  place-items: center;
}
/* Sa pastille est pleine, active ou non : c'est une identité, pas un état. */
.scr__coach b {
  width: calc(40 * var(--u));
  height: calc(40 * var(--u));
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--ai-b), var(--ai-a));
  color: var(--accent-ink);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: calc(16 * var(--u));
  letter-spacing: calc(-0.3 * var(--u));
}
/* Chez lui, son verre prend sa teinte et la pastille avance d'un cheveu. */
.scr__coach--on {
  background: linear-gradient(rgb(190 164 255 / 0.18), rgb(190 164 255 / 0.18)),
    linear-gradient(180deg, rgb(255 255 255 / 0.06), transparent calc(32 * var(--u))), var(--glass);
}
.scr__coach--on b { transform: scale(1.08); }
.scr__homebar {
  position: absolute;
  left: 50%;
  bottom: calc(8 * var(--u));
  width: calc(134 * var(--u));
  height: calc(5 * var(--u));
  border-radius: calc(3 * var(--u));
  background: rgb(255 255 255 / 0.9);
  transform: translateX(-50%);
}

/* ── L'écran Programme (ProgramScreen, programPanels) ──────────────────── */
.prg__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: calc(10 * var(--u));
  margin-bottom: calc(14 * var(--u));
}
.prg__head > div { flex: 1; min-width: 0; display: grid; gap: calc(4 * var(--u)); }
.prg__head b { font-size: calc(30 * var(--u)); font-weight: 600; letter-spacing: calc(-1 * var(--u)); line-height: calc(32 * var(--u)); }
.prg__head div span { font-size: calc(12.5 * var(--u)); color: var(--text-muted); }
/* Le héros : la photo sort de la gouttière, seul bloc de l'écran qui touche
   les bords. Le moment en haut, le titre et ses chiffres en bas. */
.prg__hero {
  position: relative;
  height: calc(250 * var(--u));
  margin: 0 calc(-18 * var(--u));
  padding: calc(14 * var(--u)) calc(18 * var(--u)) calc(16 * var(--u));
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden;
  background: var(--surface-2);
  color: #fff;
}
.prg__hero img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.prg__hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgb(0 0 0 / 0.4), rgb(0 0 0 / 0.06) 40%, rgb(0 0 0 / 0.88));
}
.prg__hero > div { position: relative; z-index: 2; }
.prg__kick { display: flex; align-items: center; justify-content: space-between; gap: calc(10 * var(--u)); }
.prg__kick span:first-child { font-size: calc(11 * var(--u)); font-weight: 600; letter-spacing: calc(1.2 * var(--u)); text-transform: uppercase; }
.prg__kick span + span { font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(13 * var(--u)); color: rgb(255 255 255 / 0.92); }
.prg__name b {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  font-size: calc(26 * var(--u));
  font-weight: 600;
  letter-spacing: calc(-0.8 * var(--u));
  line-height: calc(30 * var(--u));
}
.prg__name span {
  display: block;
  margin-top: calc(8 * var(--u));
  font-size: calc(13 * var(--u));
  color: rgb(255 255 255 / 0.8);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prg__cta { margin-top: calc(12 * var(--u)); }
.prg__cal {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
  width: max-content;
  margin: calc(10 * var(--u)) auto 0;
  padding: calc(6 * var(--u)) calc(10 * var(--u));
  font-size: calc(12.5 * var(--u));
  color: var(--text-mid);
}
.prg__cal svg { width: calc(14 * var(--u)); height: calc(14 * var(--u)); stroke-width: 1.8; }
/* « Ce que tu travailles » : la silhouette de l'app, face et dos (tracés de
   react-native-body-highlighter, `tools/generate-seance-muscles.mjs`). */
.prg__muscles { margin-top: calc(14 * var(--u)); padding: calc(16 * var(--u)); display: flex; align-items: center; gap: calc(16 * var(--u)); }
.prg__muscles img { flex: none; width: calc(176 * var(--u)); height: calc(176 * var(--u)); }
.prg__muscles div { flex: 1; min-width: 0; display: grid; gap: calc(6 * var(--u)); }
.prg__muscles span { font-size: calc(12 * var(--u)); letter-spacing: calc(-0.15 * var(--u)); color: var(--text-muted); }
.prg__muscles b { font-size: calc(15 * var(--u)); font-weight: 600; letter-spacing: calc(-0.35 * var(--u)); line-height: calc(19 * var(--u)); }
/* « Au programme » : numéro, nom, charge conseillée, volume, chevron. */
.prg__list { margin-top: calc(12 * var(--u)); }
.prg__in { padding: calc(16 * var(--u)) calc(16 * var(--u)) calc(6 * var(--u)); }
.prg__lhead { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: calc(6 * var(--u)); }
.prg__lhead b { font-size: calc(15 * var(--u)); font-weight: 600; letter-spacing: calc(-0.35 * var(--u)); }
.prg__lhead span { font-size: calc(11.5 * var(--u)); color: var(--text-muted); }
.prg__row { display: flex; align-items: center; gap: calc(10 * var(--u)); padding: calc(11 * var(--u)) 0; border-top: calc(1 * var(--u)) solid var(--border); }
.prg__lhead + .prg__row { border-top: 0; }
.prg__n {
  flex: none;
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  display: grid;
  place-items: center;
  border-radius: calc(8 * var(--u));
  background: var(--surface-2);
  border: calc(1 * var(--u)) solid var(--border);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: calc(11.5 * var(--u));
  color: var(--text-mid);
}
.prg__row b { flex: 1; min-width: 0; font-size: calc(13.5 * var(--u)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prg__kg { font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(12 * var(--u)); font-weight: 400; color: var(--accent-soft); white-space: nowrap; }
.prg__vol { min-width: calc(46 * var(--u)); text-align: right; font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(12.5 * var(--u)); color: var(--text-mid); white-space: nowrap; }
.prg__row svg { width: calc(13 * var(--u)); height: calc(13 * var(--u)); stroke-width: 2; color: var(--text-faint); }
/* Sous la liste, le mot du coach : la forme du jour quand elle a ajusté la séance. */
.prg__note { display: flex; gap: calc(12 * var(--u)); padding: calc(14 * var(--u)) calc(16 * var(--u)); border-top: calc(1 * var(--u)) solid var(--border); }
.prg__note::before { content: ''; flex: none; width: calc(2 * var(--u)); border-radius: calc(1 * var(--u)); background: linear-gradient(180deg, var(--ai-a), var(--ai-b)); }
.prg__note div { flex: 1; min-width: 0; display: grid; gap: calc(4 * var(--u)); }
.prg__note span { font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(10.5 * var(--u)); letter-spacing: calc(0.8 * var(--u)); text-transform: uppercase; color: var(--text-muted); }
.prg__note p { font-size: calc(13 * var(--u)); line-height: calc(18 * var(--u)); color: var(--text-mid); }
.prg__section { display: block; margin: calc(22 * var(--u)) 0 calc(12 * var(--u)); font-size: calc(17 * var(--u)); font-weight: 600; letter-spacing: calc(-0.5 * var(--u)); }
/* Le programme en une ligne, puis Mes charges et le catalogue en jumelles. */
.prg__prog { display: flex; align-items: center; gap: calc(12 * var(--u)); padding: calc(14 * var(--u)); }
.prg__ico {
  flex: none;
  width: calc(38 * var(--u));
  height: calc(38 * var(--u));
  display: grid;
  place-items: center;
  border-radius: calc(12 * var(--u));
  background: var(--surface-2);
  border: calc(1 * var(--u)) solid var(--border);
  color: var(--accent);
}
.prg__ico svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); stroke-width: 1.7; }
.prg__prog > div { flex: 1; min-width: 0; display: grid; gap: calc(4 * var(--u)); }
.prg__prog b, .prg__door b { font-size: calc(14 * var(--u)); font-weight: 600; letter-spacing: calc(-0.3 * var(--u)); }
.prg__prog b { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prg__prog span, .prg__door span { font-size: calc(11.5 * var(--u)); line-height: calc(15 * var(--u)); color: var(--text-muted); }
.prg__prog > svg { width: calc(14 * var(--u)); height: calc(14 * var(--u)); stroke-width: 2; color: var(--text-faint); }
.prg__doors { display: flex; gap: calc(12 * var(--u)); margin-top: calc(12 * var(--u)); }
.prg__door { flex: 1; min-width: 0; padding: calc(14 * var(--u)); display: grid; gap: calc(10 * var(--u)); align-content: start; }
.prg__door div { display: grid; gap: calc(3 * var(--u)); }
.prg__ico--door { width: calc(34 * var(--u)); height: calc(34 * var(--u)); border-radius: calc(11 * var(--u)); }
.prg__ico--door svg { width: calc(16 * var(--u)); height: calc(16 * var(--u)); stroke-width: 1.8; }
.prg__ico--mid { color: var(--text-mid); }
/* La revue de programme à huit semaines (ProgramReviewCard) : la proposition
   vient avec le geste qui l'exécute, et celui qui la remet à plus tard. */
.rev { margin-bottom: calc(14 * var(--u)); padding: calc(18 * var(--u)); }
.rev__head { display: flex; align-items: center; gap: calc(9 * var(--u)); }
.rev__head svg { width: calc(16 * var(--u)); height: calc(16 * var(--u)); stroke-width: 1.9; color: var(--accent); }
.rev__head div { flex: 1; min-width: 0; }
.rev__head span + span { display: block; margin-top: calc(2 * var(--u)); font-size: calc(12 * var(--u)); color: var(--text-muted); }
.rev__text { margin-top: calc(12 * var(--u)); line-height: calc(20 * var(--u)); }
.rev__list { margin-top: calc(12 * var(--u)); }
.rev__list .scr__label { font-size: calc(10 * var(--u)); }
.rev__list p { display: flex; gap: calc(9 * var(--u)); margin-top: calc(6 * var(--u)); font-size: calc(13 * var(--u)); line-height: calc(19 * var(--u)); color: var(--text-mid); }
.rev__list p::before { content: ''; flex: none; width: calc(5 * var(--u)); height: calc(5 * var(--u)); margin-top: calc(7 * var(--u)); border-radius: calc(3 * var(--u)); background: var(--accent); }
.rev__list--body p::before { background: var(--warn); }
.rev__go,
.rev__later {
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(40 * var(--u));
  padding: 0 calc(14 * var(--u));
  border-radius: calc(12 * var(--u));
  font-size: calc(13 * var(--u));
  font-weight: 600;
  letter-spacing: calc(-0.1 * var(--u));
}
.rev__go { margin-top: calc(16 * var(--u)); background: var(--accent); color: var(--accent-ink); }
.rev__later { margin-top: calc(10 * var(--u)); border: calc(1 * var(--u)) solid var(--border); border-top-width: var(--hair); }
.rev__name { display: block; margin-top: calc(8 * var(--u)); font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(10.5 * var(--u)); font-weight: 400; color: var(--text-faint); }

/* ── « Ce qu'il retient » (CoachMemoryScreen) : là où la blessure agit ──── */
.mem__head { display: flex; align-items: center; gap: calc(12 * var(--u)); margin-bottom: calc(18 * var(--u)); }
.mem__head div { flex: 1; min-width: 0; }
.mem__head b { display: block; font-size: calc(26 * var(--u)); font-weight: 600; letter-spacing: calc(-1 * var(--u)); line-height: calc(32 * var(--u)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mem__head div span { display: block; margin-top: calc(4 * var(--u)); font-size: calc(12.5 * var(--u)); color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mem__sect { margin-bottom: calc(18 * var(--u)); }
.mem__sect .scr__label { margin-bottom: calc(5 * var(--u)); font-size: calc(10.5 * var(--u)); }
/* Sous chaque titre, ce que ce type de fait CHANGE. */
.mem__effect { margin-bottom: calc(9 * var(--u)); font-size: calc(11.5 * var(--u)); line-height: calc(16 * var(--u)); color: var(--text-faint); }
.mem__row { display: flex; align-items: flex-start; gap: calc(10 * var(--u)); padding: calc(13 * var(--u)) calc(14 * var(--u)); border-top: var(--hair) solid var(--border); }
.mem__row:first-child { border-top: 0; }
.mem__row div { flex: 1; min-width: 0; }
.mem__row b { display: block; font-size: calc(14.5 * var(--u)); line-height: calc(20 * var(--u)); }
.mem__row span { display: block; margin-top: calc(4 * var(--u)); font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(10.5 * var(--u)); font-weight: 400; color: var(--text-muted); }
.mem__x { flex: none; width: calc(30 * var(--u)); height: calc(30 * var(--u)); display: grid; place-items: center; border-radius: 50%; background: var(--surface-2); color: var(--text-muted); }
.mem__x svg { width: calc(13 * var(--u)); height: calc(13 * var(--u)); stroke-width: 2.2; }
.mem__foot { margin-top: calc(16 * var(--u)); font-size: calc(12 * var(--u)); line-height: calc(18 * var(--u)); color: var(--text-faint); }

/* ── L'écran du coach (ChatScreen, turns, ActionCard) ──────────────────── */
.cht__head {
  flex: none;
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
  padding: 0 calc(18 * var(--u)) calc(14 * var(--u));
  border-bottom: var(--hair) solid var(--border);
}
/* La plaque à l'initiale : le coach est quelqu'un, pas une étoile d'IA. */
.cht__mono {
  flex: none;
  width: calc(42 * var(--u));
  height: calc(42 * var(--u));
  display: grid;
  place-items: center;
  border-radius: calc(14 * var(--u));
  border: var(--hair) solid var(--border-strong);
  background: linear-gradient(135deg, rgb(190 164 255 / 0.22), rgb(230 226 69 / 0.22));
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: calc(18 * var(--u));
  letter-spacing: 0;
}
.cht__who { flex: 1; min-width: 0; }
.cht__who b { display: block; font-size: calc(17.5 * var(--u)); font-weight: 600; letter-spacing: calc(-0.4 * var(--u)); }
.cht__who span { display: block; margin-top: calc(1 * var(--u)); font-size: calc(11.5 * var(--u)); color: var(--text-muted); }
.cht__btn {
  flex: none;
  width: calc(36 * var(--u));
  height: calc(36 * var(--u));
  display: grid;
  place-items: center;
  border-radius: calc(12 * var(--u));
  background: var(--surface);
  border: var(--hair) solid var(--border);
  color: var(--text-mid);
}
.cht__btn svg { width: calc(17 * var(--u)); height: calc(17 * var(--u)); stroke-width: 1.8; }
.cht__turns {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: calc(20 * var(--u));
  padding: calc(20 * var(--u)) calc(18 * var(--u)) calc(24 * var(--u));
}
/* La question : compacte, à droite, en citrine assourdie. */
.cht__me {
  align-self: flex-end;
  max-width: 82%;
  padding: calc(10 * var(--u)) calc(14 * var(--u));
  border-radius: calc(18 * var(--u)) calc(18 * var(--u)) calc(6 * var(--u)) calc(18 * var(--u));
  background: var(--accent-subtle);
  border: var(--hair) solid rgb(230 226 69 / 0.33);
  font-size: calc(14.5 * var(--u));
  line-height: calc(20 * var(--u));
}
/* La réponse ne parle pas dans une bulle : elle coule le long d'un filet,
   sous le nom du coach en marge. */
.cht__coach { display: flex; gap: calc(14 * var(--u)); }
.cht__coach::before { content: ''; flex: none; width: calc(2 * var(--u)); border-radius: calc(1 * var(--u)); background: linear-gradient(180deg, var(--ai-a), var(--ai-b)); }
.cht__coach > div { flex: 1; min-width: 0; }
.cht__name { display: block; margin-bottom: calc(7 * var(--u)); font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(11 * var(--u)); letter-spacing: calc(0.8 * var(--u)); text-transform: uppercase; color: var(--text-muted); }
.cht__text { display: grid; gap: calc(7 * var(--u)); font-size: calc(15 * var(--u)); line-height: calc(23 * var(--u)); }
.cht__text strong { font-weight: 700; }
/* La proposition : le seul bloc de l'app que la citrine cerne tout entier —
   le seul moment où un geste écrit vraiment dans tes données. Elle prend la
   place des raccourcis au-dessus du champ. */
.cht__action { flex: none; padding: 0 calc(14 * var(--u)) calc(10 * var(--u)); }
.act { padding: calc(16 * var(--u)); border-radius: calc(22 * var(--u)); background: var(--surface); border: calc(1 * var(--u)) solid rgb(230 226 69 / 0.4); }
.act__top { display: flex; gap: calc(12 * var(--u)); }
.act__ico {
  flex: none;
  width: calc(34 * var(--u));
  height: calc(34 * var(--u));
  display: grid;
  place-items: center;
  border-radius: calc(11 * var(--u));
  background: rgb(230 226 69 / 0.13);
  border: calc(1 * var(--u)) solid rgb(230 226 69 / 0.27);
  color: var(--accent);
}
.act__ico svg { width: calc(16 * var(--u)); height: calc(16 * var(--u)); stroke-width: 1.9; }
.act__top > div { flex: 1; min-width: 0; padding-top: calc(1 * var(--u)); }
.act__label { display: block; margin-bottom: calc(7 * var(--u)); font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(11 * var(--u)); letter-spacing: calc(0.8 * var(--u)); text-transform: uppercase; color: var(--accent); }
.act__text { font-size: calc(15 * var(--u)); line-height: calc(23 * var(--u)); }
.act__btns { display: flex; gap: calc(10 * var(--u)); margin-top: calc(16 * var(--u)); }
.act__later,
.act__ok {
  height: calc(44 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: calc(14 * var(--u));
  font-size: calc(14 * var(--u));
}
.act__later { flex: 1; border: calc(1 * var(--u)) solid var(--border); color: var(--text-mid); }
.act__ok { flex: 1.4; gap: calc(8 * var(--u)); background: var(--accent); color: var(--accent-ink); font-weight: 600; }
.act__ok svg { width: calc(16 * var(--u)); height: calc(16 * var(--u)); stroke-width: 2.4; }
/* Le champ, remonté au-dessus de la barre d'onglets (36 + 64 + 8, `useTabBarSpace`). */
.cht__compose {
  flex: none;
  display: flex;
  align-items: flex-end;
  gap: calc(10 * var(--u));
  padding: calc(10 * var(--u)) calc(14 * var(--u)) calc(118 * var(--u));
  border-top: var(--hair) solid var(--border);
  background: var(--bg);
}
.cht__input {
  flex: 1;
  min-height: calc(46 * var(--u));
  padding: calc(13 * var(--u)) calc(16 * var(--u));
  border-radius: calc(18 * var(--u));
  background: var(--surface);
  border: var(--hair) solid var(--border);
  font-size: calc(14.5 * var(--u));
  line-height: calc(20 * var(--u));
  color: var(--text-muted);
}
.cht__send {
  flex: none;
  width: calc(46 * var(--u));
  height: calc(46 * var(--u));
  display: grid;
  place-items: center;
  border-radius: calc(15 * var(--u));
  background: var(--surface-2);
  color: var(--text-muted);
  opacity: 0.6;
}
.cht__send svg { width: calc(20 * var(--u)); height: calc(20 * var(--u)); stroke-width: 2.2; }

/* ── L'écran de séance (ActiveSessionScreen) ───────────────────────────── */
.ses__bar { display: flex; align-items: center; justify-content: space-between; margin-bottom: calc(16 * var(--u)); }
.ses__bar .scr__btn { border-width: var(--hair); }
.ses__bar .scr__btn svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); stroke-width: 1.8; }
.ses__clock {
  height: calc(38 * var(--u));
  padding: 0 calc(12 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
  border-radius: calc(12 * var(--u));
  background: var(--surface);
  border: var(--hair) solid var(--border);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: calc(13 * var(--u));
}
.ses__clock i { width: calc(6 * var(--u)); height: calc(6 * var(--u)); border-radius: 50%; background: var(--accent); }
.ses__name { margin-bottom: calc(16 * var(--u)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ses__card { padding: calc(20 * var(--u)); }
.ses__top { display: flex; align-items: center; justify-content: space-between; gap: calc(8 * var(--u)); min-height: calc(20 * var(--u)); }
.ses__exo { display: block; margin-top: calc(10 * var(--u)); font-size: calc(26 * var(--u)); font-weight: 600; letter-spacing: calc(-0.8 * var(--u)); line-height: 1.2; }
.ses__meta { margin-top: calc(5 * var(--u)); line-height: calc(19 * var(--u)); color: var(--text-muted); }
/* Le mot du coach sur cet exercice : le même filet que dans la conversation. */
.ses__note { display: flex; gap: calc(12 * var(--u)); margin-top: calc(16 * var(--u)); font-size: calc(13.5 * var(--u)); line-height: calc(19.5 * var(--u)); }
.ses__note::before { content: ''; flex: none; width: calc(2 * var(--u)); border-radius: calc(1 * var(--u)); background: linear-gradient(180deg, var(--ai-a), var(--ai-b)); }
/* Les deux cadrans, empilés : le libellé, −, le chiffre (mono 32) et son unité, +. */
.ses__dials { margin: calc(22 * var(--u)) 0 calc(20 * var(--u)); }
.ses__dial { display: flex; align-items: center; }
.ses__dial .scr__label { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ses__dial i {
  flex: none;
  width: calc(44 * var(--u));
  height: calc(44 * var(--u));
  display: grid;
  place-items: center;
  border-radius: calc(14 * var(--u));
  background: var(--surface-2);
  border: var(--hair) solid var(--border);
  color: var(--text-mid);
}
.ses__dial i svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); stroke-width: 2; }
.ses__dial b { width: calc(96 * var(--u)); margin: 0 calc(6 * var(--u)); display: grid; justify-items: center; }
.ses__dial strong { height: calc(42 * var(--u)); display: flex; align-items: center; font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(32 * var(--u)); letter-spacing: calc(-1.6 * var(--u)); }
.ses__dial small { margin-top: calc(-2 * var(--u)); font-size: calc(11 * var(--u)); line-height: 1.3; color: var(--text-muted); }
.ses__rule { display: block; height: var(--hair); margin: calc(18 * var(--u)) 0; background: var(--border); }
.ses__hint { margin-top: calc(14 * var(--u)); text-align: center; font-size: calc(11.5 * var(--u)); color: var(--text-faint); }
.ses__card .scr__cta svg { stroke-width: 2.2; }
/* Le dock du coach : présent en permanence, jamais dans le chemin. */
.ses__dock {
  display: flex;
  align-items: center;
  gap: calc(13 * var(--u));
  margin-top: calc(14 * var(--u));
  padding: calc(14 * var(--u));
  border-radius: calc(18 * var(--u));
  background: var(--surface);
  border: var(--hair) solid var(--border);
}
.ses__dock::before { content: ''; flex: none; align-self: stretch; width: calc(2 * var(--u)); border-radius: calc(1 * var(--u)); background: linear-gradient(180deg, var(--ai-a), var(--ai-b)); }
.ses__dock div { flex: 1; min-width: 0; }
.ses__dock span { display: block; margin-bottom: calc(5 * var(--u)); font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(11 * var(--u)); letter-spacing: calc(0.8 * var(--u)); text-transform: uppercase; color: var(--text-muted); }
/* Deux lignes réservées : le dock ne saute pas pendant que le coach écrit. */
.ses__dock p { min-height: calc(38 * var(--u)); font-size: calc(13.5 * var(--u)); line-height: calc(19 * var(--u)); color: var(--text-mid); }
.ses__dock i { flex: none; width: calc(36 * var(--u)); height: calc(36 * var(--u)); display: grid; place-items: center; border-radius: calc(12 * var(--u)); background: var(--accent-subtle); color: var(--accent); }
.ses__dock i svg { width: calc(17 * var(--u)); height: calc(17 * var(--u)); stroke-width: 1.8; }
.ses__list { margin-top: calc(14 * var(--u)); padding: calc(16 * var(--u)); }
.ses__list .scr__label { margin-bottom: calc(4 * var(--u)); }
.ses__row { display: flex; align-items: center; gap: calc(11 * var(--u)); padding: calc(11 * var(--u)) 0; border-top: var(--hair) solid var(--border); }
.ses__list .scr__label + .ses__row { border-top: 0; }
.ses__n {
  flex: none;
  width: calc(26 * var(--u));
  height: calc(26 * var(--u));
  display: grid;
  place-items: center;
  border-radius: calc(8 * var(--u));
  background: var(--surface-2);
  border: var(--hair) solid var(--border);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: calc(12 * var(--u));
  color: var(--text-mid);
}
.ses__n svg { width: calc(14 * var(--u)); height: calc(14 * var(--u)); stroke-width: 2.2; }
.ses__row.is-current .ses__n { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.ses__row.is-done { opacity: 0.45; }
.ses__row b { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ses__row > span:last-child { font-family: 'Geist Mono', ui-monospace, monospace; font-size: calc(12 * var(--u)); font-weight: 400; color: var(--text-muted); }
/* La pastille « Record battu » arrive après l'écran ; le coach écrit ensuite
   sa ligne dans le dock (`data-delay`). */
.js .live__pr {
  opacity: 0;
  transform: scale(0.7);
  transition: opacity 360ms var(--ease) 1000ms, transform 520ms var(--ease) 1000ms;
}
.js .is-in .live__pr { opacity: 1; transform: none; }

/* ═══ D · Le scan de l'assiette ════════════════════════════════════════════ */

.scan {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 52px);
  align-items: center;
  border-radius: var(--radius-xl);
  padding: clamp(20px, 3vw, 34px);
  margin-bottom: clamp(28px, 4vw, 44px);
}
/* Le viseur : un puits sombre éclairé par en dessous, comme un écran. */
.scan__frame {
  position: relative;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background: radial-gradient(90% 70% at 50% 100%, rgb(108 150 255 / 0.12), transparent 70%), #0a0c11;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.07), inset 0 18px 40px -20px rgb(0 0 0 / 0.8);
  border-radius: var(--radius-l);
  overflow: hidden;
}
.scan__corner {
  position: absolute;
  width: 24px;
  height: 24px;
  border: 2px solid var(--accent);
}
.scan__corner--tl { top: 14px; left: 14px; border-right: 0; border-bottom: 0; border-radius: 7px 0 0 0; }
.scan__corner--tr { top: 14px; right: 14px; border-left: 0; border-bottom: 0; border-radius: 0 7px 0 0; }
.scan__corner--bl { bottom: 14px; left: 14px; border-right: 0; border-top: 0; border-radius: 0 0 0 7px; }
.scan__corner--br { bottom: 14px; right: 14px; border-left: 0; border-top: 0; border-radius: 0 0 7px 0; }

.plate { width: 80%; height: auto; overflow: visible; }
.plate .food-base path { fill: var(--surface-3); }
/* Chaque portion prend sa couleur quand sa ligne est reconnue, et son repère
   s'y pose — mêmes délais que les lignes (950, 1210, 1470 ms). Sans
   JavaScript, tout est déjà là. */
.plate .mark text { font: 600 8.5px 'Geist Mono', ui-monospace, monospace; fill: var(--accent-ink); }
.js .plate .food,
.js .plate .mark {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: 50% 50%;
}
.js .plate .food { transform: scale(0.94); transition: opacity 600ms var(--ease-out), transform 800ms var(--ease-spring); }
.js .plate .mark { transform: scale(0.4); transition: opacity 300ms var(--ease-out), transform var(--dur-snap) var(--ease-snap); }
.js .scan.is-in .plate .food,
.js .scan.is-in .plate .mark { opacity: 1; transform: none; }
.js .scan.is-in .plate .food--1 { transition-delay: 950ms; }
.js .scan.is-in .plate .food--2 { transition-delay: 1210ms; }
.js .scan.is-in .plate .food--3 { transition-delay: 1470ms; }
.js .scan.is-in .plate .mark--1 { transition-delay: 1050ms; }
.js .scan.is-in .plate .mark--2 { transition-delay: 1310ms; }
.js .scan.is-in .plate .mark--3 { transition-delay: 1570ms; }
.scan__beam {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 44%, var(--accent) 50%, transparent 56%);
  opacity: 0;
  pointer-events: none;
}
.js .scan.is-in .scan__beam { animation: sweep 1500ms var(--ease) 200ms 1 both; }
@keyframes sweep {
  0% { transform: translate3d(0, -100%, 0); opacity: 0; }
  12% { opacity: 0.85; }
  88% { opacity: 0.85; }
  100% { transform: translate3d(0, 100%, 0); opacity: 0; }
}

.scan__caption {
  position: absolute;
  bottom: 16px;
  left: 0;
  right: 0;
  text-align: center;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.scan__label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}

.scan__line {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 13px 0;
  border-bottom: 1px solid var(--border);
}
.scan__line b { display: block; font-size: 0.98rem; font-weight: 500; letter-spacing: -0.01em; }
.scan__line span { display: block; font-size: 0.82rem; color: var(--text-muted); margin-top: 2px; }
.scan__line .scan__pin { display: grid; margin-top: 0; font-size: 11px; color: var(--accent-ink); }
.scan__line i { margin-left: auto; font-style: normal; font-size: 0.92rem; color: var(--text-mid); }
.scan__line > div { min-width: 0; }
.scan__pin {
  width: 24px;
  height: 24px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 500;
  color: var(--accent-ink);
  background: var(--ai-a);
}
.scan__line:nth-of-type(2) .scan__pin { background: var(--ai-b); }
.scan__line:nth-of-type(3) .scan__pin { background: var(--success); }

.js .scan__line {
  opacity: 0;
  transform: translate3d(14px, 0, 0);
  transition: opacity 560ms var(--ease), transform 560ms var(--ease);
  transition-delay: calc(700ms + var(--n) * 260ms);
}
.js .scan.is-in .scan__line { opacity: 1; transform: none; }

.scan__total { margin-top: 20px; }
.scan__rest {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 16px;
}
.scan__rest > span { font-size: 0.93rem; color: var(--text-mid); }
.scan__rest b { font-size: 1.5rem; font-weight: 500; letter-spacing: -0.03em; color: var(--accent); }
.scan__macros { margin-top: 0; }
.scan__macros .amacro span { font-size: 9.5px; }
.scan__macros .amacro b { font-size: 12.5px; }
.scan__macros .abar { height: 6px; }
.scan__macros .abar > i { width: 100%; transform-origin: left center; }
.js .scan__macros .abar > i {
  transform: scaleX(0);
  transition: transform 900ms var(--ease) 1500ms;
}
.js .scan.is-in .scan__macros .abar > i { transform: scaleX(var(--w)); }

.js .scan__total {
  opacity: 0;
  transition: opacity 700ms var(--ease) 1500ms;
}
.js .scan.is-in .scan__total { opacity: 1; }

.list--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px 42px; }
.list--2.list--cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }

/* ═══ E · La semaine ═══════════════════════════════════════════════════════ */

.week {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 56px);
  align-items: center;
}

.week__chart {
  border-radius: var(--radius-l);
  padding: 24px 24px 20px;
}
.week__read { padding: 26px 28px 20px; border-radius: var(--radius-l); }
.week__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 22px;
}
.week__range { font-size: 11px; letter-spacing: 0.08em; color: var(--ink-3); text-transform: uppercase; }
.week__done { font-size: 0.92rem; color: var(--ink-2); }
.week__done b { color: var(--accent); font-size: 1.05rem; }

.week__days {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px;
  height: 176px;
}
.wday {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 9px;
  min-width: 0;
}
.wbar {
  width: 100%;
  max-width: 46px;
  height: var(--h);
  border-radius: 8px;
  background: rgb(255 255 255 / 0.1);
  transform-origin: bottom center;
}
.js .wbar { transform: scaleY(0); transition: transform 700ms var(--ease); }
.js .week.is-in .wbar { transform: scaleY(1); }
.week__days .wday:nth-child(1) .wbar { transition-delay: 200ms; }
.week__days .wday:nth-child(2) .wbar { transition-delay: 280ms; }
.week__days .wday:nth-child(3) .wbar { transition-delay: 360ms; }
.week__days .wday:nth-child(4) .wbar { transition-delay: 440ms; }
.week__days .wday:nth-child(5) .wbar { transition-delay: 520ms; }
.week__days .wday:nth-child(6) .wbar { transition-delay: 600ms; }
.week__days .wday:nth-child(7) .wbar { transition-delay: 680ms; }
/* Les jours de séance sont éclairés ; au survol, un jour se détache. */
.wday--on .wbar { background: linear-gradient(180deg, #f5f29a, var(--accent)); box-shadow: 0 0 22px rgb(230 226 69 / 0.28); }
.wday { transition: opacity 300ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .week__days:hover .wday { opacity: 0.45; }
  .week__days .wday:hover { opacity: 1; }
  .week__days .wday:hover i { color: var(--ink); }
}
.wday b {
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-mid);
}
.wday i {
  font-style: normal;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 8.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  transition: color 250ms var(--ease-out);
}
.wday--on i { color: var(--accent); }
.week__axis {
  display: block;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid rgb(255 255 255 / 0.08);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.week__read h3 { margin-bottom: 14px; }
.js .week .review__line {
  opacity: 0;
  transform: translate3d(0, 12px, 0);
  transition: opacity 560ms var(--ease), transform 560ms var(--ease);
  transition-delay: calc(500ms + var(--n) * 150ms);
}
.js .week.is-in .review__line { opacity: 1; transform: none; }
.review__line--next {
  margin-top: 6px;
  border-top: 1px solid var(--border);
  border-bottom: 0;
}

/* ═══ G · Le coach : la conversation, puis la séance (2026-09-15 → 16) ═════
   En haut, le titre de la section avec la conversation à sa droite. En
   dessous, une rangée : l'écran de séance à gauche, et à droite une étiquette
   de chapitre, un titre de rang h3 et son texte. Les mêmes étiquettes et
   titres servent aux deux chapitres de la section « Ton suivi ». Sous 900 px,
   le texte passe au-dessus des téléphones (§ 18). */

.coach__top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
  margin-bottom: clamp(64px, 9vw, 120px);
}
.coach__top .head { margin-bottom: 0; }

.chapter__label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
  padding: 7px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid rgb(255 255 255 / 0.14);
  background: rgb(255 255 255 / 0.04);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.chapter__label::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--band);
  box-shadow: 0 0 8px var(--band);
  flex: none;
}
.chapter__title {
  font-size: clamp(1.5rem, 2.8vw, 2rem);
  letter-spacing: -0.03em;
  line-height: 1.12;
}
.chapter { max-width: 52ch; margin-bottom: clamp(30px, 4vw, 44px); }
.chapter__lede {
  margin-top: 14px;
  color: var(--ink-2);
  font-size: 1.02rem;
  line-height: 1.55;
  max-width: 52ch;
}
/* Le second chapitre d'une section : un filet sur toute la largeur, et de
   l'air au-dessus. */
/* Le second chapitre : de l'air, et un filet qui s'efface vers les bords. */
.chapter--next {
  position: relative;
  max-width: none;
  margin-top: clamp(64px, 9vw, 112px);
  padding-top: clamp(44px, 6vw, 64px);
}
.chapter--next::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgb(168 196 255 / 0.3), transparent);
}
.chapter--next > * { max-width: 52ch; }

.duo { display: grid; gap: clamp(64px, 9vw, 120px); }
@media (min-width: 901px) {
  .js .coach__top .phone.reveal.is-in { transform: perspective(1400px) rotateY(-6deg) rotateX(2deg); }
  .js .duo__row .phone.reveal.is-in { transform: perspective(1400px) rotateY(6deg) rotateX(2deg); }
}
@media (min-width: 901px) and (hover: hover) and (pointer: fine) {
  .js .coach__top .phone.reveal.is-in:hover,
  .js .duo__row .phone.reveal.is-in:hover { transform: perspective(1400px) rotateY(0deg) rotateX(0deg); }
}
.duo__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(32px, 5vw, 78px);
  align-items: center;
}
.duo__text .chapter__title { font-size: clamp(1.4rem, 2.4vw, 1.75rem); }
.duo__text { max-width: 640px; }
.duo__text > p:not(.chapter__label) { color: var(--ink-2); font-size: 1rem; max-width: 46ch; }
.duo__text .chapter__title + p { margin-top: 16px; }
.duo__text .list { margin-top: 26px; }

/* ═══ H · Les charges : la courbe d'un exercice (2026-09-15) ═══════════════
   La fiche « Mes charges » de l'application, en mécanisme : huit séances d'un
   exercice, la ligne se trace, les points arrivent dans son sillage avec les
   répétitions de la série la plus lourde, les deux paliers de charge se
   signalent, le record est cerclé — puis les trois cases de la fiche (record,
   dernière, trente jours) et la décision pour la prochaine séance.

   Le tracé est un SVG étiré sur la boîte (`preserveAspectRatio="none"`) et
   les points sont en HTML aux mêmes coordonnées, en pourcentage : la ligne
   suit à toute largeur, le texte garde sa taille (même principe que les fils
   du faisceau). Quatrième exception assumée à « transform et opacity » : le
   tracé se fait en `stroke-dashoffset`, une fois, à l'entrée. */

/* Le cadre est de verre (liseré, lumière, ombre) ; le fond reste celui de la
   fiche, parce que les points de la courbe sont cerclés de cette couleur. */
.lift {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: clamp(24px, 4vw, 52px);
  align-items: center;
  border-radius: var(--radius-xl);
  background: var(--surface);
  padding: clamp(20px, 3vw, 34px);
  margin-bottom: clamp(28px, 4vw, 44px);
}
.lift__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; margin-bottom: 26px; }
.lift__exo { display: block; font-size: 1.05rem; font-weight: 600; letter-spacing: -0.02em; }
.lift__sub { display: block; margin-top: 3px; font-size: 0.82rem; color: var(--text-muted); }
.lift__delta { text-align: right; flex: none; }
.lift__delta b { display: block; font-size: 1.4rem; font-weight: 500; letter-spacing: -0.03em; line-height: 1; color: var(--accent); }
.lift__delta span {
  display: block;
  margin-top: 5px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.lift__plot { position: relative; height: 190px; margin: 0 14px 0 42px; }
.lift__grid { position: absolute; left: 0; right: 0; top: var(--y); height: 1px; background: var(--border); }
.lift__grid i {
  position: absolute;
  right: calc(100% + 12px);
  top: 50%;
  transform: translateY(-50%);
  font-style: normal;
  font-size: 10.5px;
  color: var(--text-muted);
}
.lift__line { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.lift__line path {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.75;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.js .lift__line {
  clip-path: inset(-10% 100% -10% 0);
  transition: clip-path 1600ms var(--ease) 250ms;
}
.js .lift.is-in .lift__line { clip-path: inset(-10% -2% -10% 0); }

.pt { position: absolute; left: var(--x); top: var(--y); width: 0; height: 0; }
.pt i {
  position: absolute;
  left: -5px;
  top: -5px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--surface);
}
.pt b {
  position: absolute;
  top: 11px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 9.5px;
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
}
.pt--record i {
  left: -7px;
  top: -7px;
  width: 14px;
  height: 14px;
  background: var(--surface);
  border: 2px solid var(--accent);
  box-shadow: 0 0 0 3px var(--surface), 0 0 18px color-mix(in srgb, var(--accent) 55%, transparent);
}
.pt--record i::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  border: 1.5px solid var(--accent);
  opacity: 0;
  transform: scale(1);
}
.pt--record b { top: 13px; }
.pt--record em {
  position: absolute;
  bottom: 13px;
  left: 50%;
  transform: translateX(-50%);
  font-style: normal;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  white-space: nowrap;
}
.js .pt {
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 360ms var(--ease), transform 520ms var(--ease);
  transition-delay: calc(300ms + var(--i) * 200ms);
}
.js .lift.is-in .pt { opacity: 1; transform: none; }
/* Le record cerclé émet deux anneaux quand la ligne l'atteint — la même
   image-clé que les pastilles du faisceau. */
.js .lift.is-in .pt--record i::after { animation: signal-ping 2.4s cubic-bezier(0.2, 0.7, 0.3, 1) 2000ms 2; }

/* « +2,5 kg » : posé sur le nouveau palier, juste à gauche du premier point
   qui l'atteint — là où il n'y a rien d'autre. */
.lift__step {
  position: absolute;
  left: var(--x);
  top: var(--y);
  transform: translate(calc(-100% - 12px), -50%);
  padding: 3px 8px;
  border-radius: var(--r-full);
  background: var(--accent-subtle);
  color: var(--accent);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
.js .lift__step {
  opacity: 0;
  transform: translate(calc(-100% - 4px), -50%);
  transition: opacity 420ms var(--ease), transform 520ms var(--ease);
  transition-delay: calc(420ms + var(--i) * 200ms);
}
.js .lift.is-in .lift__step { opacity: 1; transform: translate(calc(-100% - 12px), -50%); }

.lift__axis {
  display: flex;
  justify-content: space-between;
  margin: 24px 14px 0 42px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.lift__legend {
  display: block;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  line-height: 1.5;
}

.lift__cells {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--bg-subtle);
  overflow: hidden;
}
.lift__cell { padding: 14px 12px; border-left: 1px solid var(--border); min-width: 0; }
.lift__cell:first-child { border-left: 0; }
.lift__cell span {
  display: block;
  margin-bottom: 8px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.lift__cell b { display: block; font-size: 1.3rem; font-weight: 500; letter-spacing: -0.03em; line-height: 1; white-space: nowrap; }
.lift__cell b i {
  font-style: normal;
  font-family: Geist, system-ui, sans-serif;
  font-size: 0.6em;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--text-muted);
  margin-left: 3px;
}
.lift__cell small { display: block; margin-top: 7px; font-size: 0.74rem; color: var(--text-muted); line-height: 1.3; }
.lift__cell--up b { color: var(--success); }
.lift__cell:nth-child(1) { --n: 0; }
.lift__cell:nth-child(2) { --n: 1; }
.lift__cell:nth-child(3) { --n: 2; }
.js .lift__cell {
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition: opacity 520ms var(--ease), transform 520ms var(--ease);
  transition-delay: calc(1500ms + var(--n) * 140ms);
}
.js .lift.is-in .lift__cell { opacity: 1; transform: none; }

.lift__next {
  margin-top: 16px;
  padding: 14px 16px;
  border-radius: var(--r-md);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.lift__next span {
  display: block;
  margin-bottom: 6px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}
.lift__next p { font-size: 0.95rem; line-height: 1.5; color: var(--text); }
.js .lift__next {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition: opacity 700ms var(--ease) 2050ms, transform 700ms var(--ease) 2050ms;
}
.js .lift.is-in .lift__next { opacity: 1; transform: none; }

/* ═══ F · Ces pièces sur un écran étroit ═══════════════════════════════════
   Le faisceau perd ses fils (six colonnes sur 390 px, ce n'est plus un
   faisceau, c'est un tas), le scan, la courbe des charges et la semaine
   passent sur une colonne. */

@media (max-width: 960px) {
  .scan { grid-template-columns: minmax(0, 1fr); }
  .scan__frame { max-width: 380px; margin-inline: auto; width: 100%; }
  .lift { grid-template-columns: minmax(0, 1fr); }
  .week { grid-template-columns: minmax(0, 1fr); }
  .week .week__chart { order: -1; }
}

@media (max-width: 860px) {
  .hub__wires { display: none; }
  /* Et les impulsions du bureau avec : posées hors champ, elles élargiraient
     la page (un élément déplacé compte dans le défilement, même invisible). */
  .hub__pulses { display: none; }
  .hub__signals {
    height: auto;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px 14px;
    margin-bottom: 34px;
  }
  /* La pastille passe À GAUCHE du nom : empilée dessous, six signaux
     prenaient 800 px de haut pour ne rien dire de plus. */
  .signal {
    position: static;
    width: auto;
    margin: 0;
    text-align: left;
    padding-left: 12px;
    border-left: 2px solid var(--sig);
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 0 9px;
    align-items: center;
  }
  .signal__dot { margin: 0; grid-row: 1 / span 2; }
  .signal__name { grid-column: 2; }
  .signal__val { grid-column: 2; margin-top: 2px; }
  .hub__core { margin-top: 0; }
}

@media (max-width: 700px) {
  .list--2 { grid-template-columns: minmax(0, 1fr); }
  /* La courbe des charges : moins haute, ses cases plus serrées, l'écart
     sous le nom de l'exercice plutôt qu'à sa droite. */
  .lift__plot { height: 150px; margin-left: 38px; }
  .lift__axis { margin-left: 38px; }
  .lift__head { flex-direction: column; gap: 12px; }
  .lift__delta { text-align: left; }
  .lift__cell { padding: 12px 9px; }
  .lift__cell b { font-size: 1.1rem; }
  .lift__cell small { font-size: 0.68rem; }
  .week__days { height: 140px; gap: 5px; }
  .wday i { display: none; }
  .week__head { flex-direction: column; align-items: flex-start; gap: 6px; }
  .core { width: 144px; height: 126px; }
  .core__num b { font-size: 38px; }
  .hub__out { font-size: 10.5px; padding: 8px 14px; text-align: left; }
  .scan__line i { font-size: 0.86rem; }
}

@media (max-width: 430px) {
  .hub__signals { gap: 14px 10px; }
  .bodies { gap: 6px; }
}

/* ── 18. Responsive ─────────────────────────────────────────────────────────
   Deux ruptures franches : la tablette perd la deuxième colonne, le téléphone
   remonte le visuel sous le texte et rend les scènes épinglées linéaires.
   ------------------------------------------------------------------------- */

@media (max-width: 1080px) {
  .phone { --screen: 262px; }
  /* Les deux téléphones du coach gardent leur taille : à 262 px, le dock de
     la séance — le point de la scène — passait sous la barre d'onglets. */
  .coach__top .phone, .duo__row .phone { --screen: min(288px, 82vw); }
  /* Six entrées dans la pilule : un peu moins d'air avant que la tablette ne
     passe au menu. */
  .nav a { padding-inline: 10px; }
  .body-grid__visual { top: 96px; }
}

@media (max-width: 900px) {
  .hero__grid,
  .pin__grid,
  .body-grid,
  .coach__top,
  .duo__row {
    grid-template-columns: minmax(0, 1fr);
    justify-items: start;
  }
  .hero__stage,
  .pin__grid > .panes,
  .coach__top > .phone { justify-self: center; }
  /* Le texte d'abord, le téléphone dessous — pour la rangée de la séance. */
  .duo__row > .phone { order: 2; justify-self: center; }
  /* Relative, pas static : le liseré de verre (pseudo-élément absolu) se
     calerait sinon sur toute la section. */
  .body-grid__visual { position: relative; top: auto; justify-self: stretch; }
  .pin__stage { padding-block: 0; }
  .pin__track { min-height: 0 !important; }
  .panes { position: static; }
  .pane { position: static; opacity: 1; }
  .pane + .pane { display: none; } /* une seule scène sur téléphone : la première */
  .steps { gap: 26px; }
  .head--split { grid-template-columns: minmax(0, 1fr); }
  .head--split .lede { padding-bottom: 0; }
}

@media (max-width: 700px) {
  :root { --gutter: 18px; }
  body { font-size: 16px; }
  .stats { grid-template-columns: minmax(0, 1fr); }
  .stat { grid-template-columns: auto minmax(0, 1fr); column-gap: 16px; align-items: baseline; }
  .stat .ticks { grid-column: 1 / -1; }
  .site-footer__top { flex-direction: column; }
  .hero__cta { width: 100%; }
  .stores { width: 100%; }
  .store { flex: 1 1 auto; }
  .section { padding-block: 68px; }
}

@media (max-width: 420px) {
  .phone { --screen: min(272px, 82vw); }
  .hero__cta .btn { flex: 1 1 100%; }
}

/* Les mises en page de la refonte « Aube », sur écran moyen puis étroit. */
@media (max-width: 1000px) {
  .trust__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .faq-layout { grid-template-columns: minmax(0, 1fr); }
  .faq-layout .head { position: static; margin-bottom: 30px; }
  .end__sheet { justify-items: stretch; }
}
@media (max-width: 700px) {
  .trust__grid { grid-template-columns: minmax(0, 1fr); }
  .list--2.list--cards { grid-template-columns: minmax(0, 1fr); }
  .faq details { padding: 0 18px; }
  .body-block { padding: 22px 20px 20px; }
  .week__read { padding: 22px 20px 16px; }
  .scan { border-radius: var(--radius-l); }
}

/* ── 19. Accessibilité ──────────────────────────────────────────────────────
   `prefers-reduced-motion` ne dégrade pas l'expérience : il la rend statique
   et entièrement lisible. Ce n'est pas une option de confort.
   ------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .js .home .ring__arc { stroke-dasharray: var(--p) 100; transition: none; }
  /* `.is-in` compris : sans lui, les trois étapes inactives de la scène
     épinglée restaient à 34 % d'opacité — donc illisibles — pour quelqu'un qui
     a justement demandé une page statique. */
  .js .pin .step, .js .pin .step.is-in { opacity: 1; }
  .js .pin .pane { opacity: 1; position: static; }
  .js .pin .pane + .pane { display: none; }
  .body path { transition: none; }
  .js .hub.is-in .signal__dot::after,
  .js .hub.is-in .core::before,
  .js .hub.is-in .hub__flow i { animation: none; }
  .hub__pulses { display: none; }
  .js .bodies.is-in .bodies__scan,
  .js .bodies.is-in [data-m='4'],
  .js .bodies.is-in [data-m='3'] { animation: none; }
  /* L'écran de séance et la courbe des charges, entièrement dessinés d'emblée. */
  .js .live__pr, .js .pt, .js .lift__cell, .js .lift__next { opacity: 1; transform: none; transition: none; }
  .js .lift__step { opacity: 1; transform: translate(calc(-100% - 12px), -50%); transition: none; }
  .js .lift__line { clip-path: none; transition: none; }
  .js .lift.is-in .pt--record i::after { animation: none; }
  .caret { display: none; }
  /* La refonte « Aube » : le ciel ne respire ni ne dérive, les titres, les
     graduations, l'assiette et l'écran du programme sont posés d'emblée. */
  .sky__dawn, .sky__veil { animation: none; }
  .sky__hz { transition: none; }
  .js .reveal--rise .rise > span { transform: none; transition: none; }
  .js .ticks::after { transform: none; transition: none; }
  .js .plate .food, .js .plate .mark { opacity: 1; transform: none; transition: none; }
  .js .pin .pane { transform: none; }
  [data-tilt] { transform: none; transition: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .site-header, .decor, .phone { display: none !important; }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: absolute;
  left: 50%;
  top: 8px;
  transform: translate(-50%, -160%);
  z-index: 100;
  background: var(--accent);
  color: var(--accent-ink);
  padding: 10px 18px;
  border-radius: var(--r-full);
  font-size: 0.9rem;
  font-weight: 500;
  text-decoration: none;
  transition: transform 200ms var(--ease);
}
.skip:focus { transform: translate(-50%, 0); }
