/* ============================================================================
   DOPR — DESIGN SYSTEM v2.0
   Transposition du DS livré (`dopr-design-system.html`), aligné sur le CdC §5.2.
   **Dark-first : l'écran caméra impose sa loi.**

   RÈGLE ABSOLUE (§2.3) : aucun hexadécimal hors de ce fichier. Les CSS de page,
   les gabarits et le JS ne consomment que des `var(--ds-*)`.
   `scripts/audit_ds.sh` échoue si la règle est violée.

   Un partial = une classe racine (§5.3). Les noms de classes sont ceux du DS,
   à la lettre : `.btn--primaire`, `.champ`, `.carte-choix`, `.compteur-reps`…
   Les renommer, ce serait couper le lien entre le DS et le code.
   ========================================================================== */

@layer tokens, base, composants, utilitaires;

/* ─────────────────────────────────────────────────────────────── TOKENS ── */
@layer tokens {
  :root {
    /* Sombre = défaut (CdC §5.2, canonique) */
    --ds-bg: #0b0e14;
    --ds-surface: #131826;
    --ds-surface-2: #1b2233;
    --ds-border: #273049;
    --ds-text: #f2f5fa;
    --ds-text-2: #9aa6c0;
    --ds-text-3: #5f6b85;

    --ds-accent: #2e5bff;
    --ds-accent-press: #244ad6;
    --ds-accent-soft: #2e5bff24;
    --ds-on-accent: #ffffff;

    /* ── LE SEUL AJOUT AU DS ────────────────────────────────────────────────
       `--ds-accent` en **texte** donne 3,73:1 sur le fond et 3,42:1 sur une
       carte : sous le seuil AA de 4,5:1 que le CdC exige (gate P1). Les
       *surfaces* (boutons, arc de jauge, FAB, bordures) gardent la couleur du
       DS, à l'identique. Seul le **texte** accent prend cette déclinaison —
       qui passe à 6,29:1. Le gate l'emporte sur le nuancier ; l'écart est
       additif, jamais substitutif. Voir DECISIONS.md (A9).
       ─────────────────────────────────────────────────────────────────────── */
    --ds-accent-texte: #6c8cff;

    --ds-energy: #ffb020;
    --ds-energy-soft: #ffb02021;
    --ds-success: #2fbf71;
    --ds-success-soft: #2fbf7121;
    --ds-danger: #ff5c5c;
    --ds-danger-soft: #ff5c5c21;
    --ds-ring-track: #273049;
    --ds-scrim: rgb(0 0 0 / 0.55);

    --ds-font-display: "Archivo", system-ui, sans-serif;
    --ds-font-body: "Instrument Sans", system-ui, sans-serif;
    --ds-font-mono: "JetBrains Mono", ui-monospace, monospace;

    --ds-fs-xs: 0.8125rem;
    --ds-fs-sm: 0.9375rem;
    --ds-fs-md: 1rem;
    --ds-fs-lg: 1.1875rem;
    --ds-fs-xl: 1.5rem;
    --ds-fs-2xl: 2rem;
    --ds-fs-hero: clamp(4.5rem, 28vw, 9rem);
    --ds-lh-body: 1.5;
    --ds-lh-tight: 1.1;

    --ds-sp-1: 4px;
    --ds-sp-2: 8px;
    --ds-sp-3: 12px;
    --ds-sp-4: 16px;
    --ds-sp-5: 24px;
    --ds-sp-6: 32px;
    --ds-sp-7: 48px;
    --ds-sp-8: 64px;

    --ds-r-sm: 10px;
    --ds-r-md: 16px;
    --ds-r-lg: 24px;
    --ds-r-full: 999px;
    --ds-shadow-1: 0 1px 2px rgb(0 0 0 / 0.4);
    --ds-shadow-2: 0 8px 24px rgb(0 0 0 / 0.45);

    --ds-tap-min: 48px;
    --ds-safe-top: env(safe-area-inset-top, 0px);
    --ds-safe-bottom: env(safe-area-inset-bottom, 0px);
    --ds-tabbar-h: calc(64px + var(--ds-safe-bottom));

    --ds-t-fast: 120ms;
    --ds-t-base: 200ms;
    --ds-t-slow: 320ms;
    --ds-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
    --ds-ease-pop: cubic-bezier(0.34, 1.56, 0.64, 1);

    --ds-z-content: 1;
    --ds-z-tabbar: 40;
    --ds-z-drawer: 50;
    --ds-z-toast: 60;
    --ds-z-camera: 70;

    color-scheme: dark;
  }

  /* Clair = thème **dérivé**, jamais le défaut. */
  [data-theme="light"] {
    --ds-bg: #f6f8fc;
    --ds-surface: #ffffff;
    --ds-surface-2: #edf1f9;
    --ds-border: #d8dfec;
    --ds-text: #0b0e14;
    --ds-text-2: #4a566e;
    --ds-accent-soft: #2e5bff14;
    --ds-accent-texte: #244ad6; /* sur fond clair, c'est `accent-press` qui passe AA */

    /* ── Le DS ne redéfinissait pas ces quatre-là. Sur fond blanc, l'ambre du sombre
         (#FFB020) tombe à **1,72:1** — illisible. Un thème « dérivé » doit dériver TOUTES
         ses couleurs de texte, pas seulement son fond. Le gate P1 exige l'AA dans les deux
         thèmes : voici les déclinaisons claires. Additif, jamais substitutif. ── */
    --ds-energy: #8f5200;
    --ds-success: #0f6b46;
    --ds-danger: #c62a2f;
    --ds-text-3: #6b7690;

    --ds-energy-soft: #ffb02026;
    --ds-success-soft: #2fbf7124;
    --ds-danger-soft: #ff5c5c1f;
    --ds-ring-track: #d8dfec;
    --ds-shadow-1: 0 1px 2px rgb(11 14 20 / 0.08);
    --ds-shadow-2: 0 8px 24px rgb(11 14 20 / 0.12);

    color-scheme: light;
  }

  @media (prefers-reduced-motion: reduce) {
    :root {
      --ds-t-fast: 1ms;
      --ds-t-base: 1ms;
      --ds-t-slow: 1ms;
    }
  }
}

/* ───────────────────────────────────────────────────────────────── BASE ── */
@layer base {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
  }

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

  body {
    font: 400 var(--ds-fs-md) / var(--ds-lh-body) var(--ds-font-body);
    background: var(--ds-bg);
    color: var(--ds-text);
    -webkit-font-smoothing: antialiased;
    touch-action: manipulation; /* pas de délai de 300 ms, pas de double-tap zoom */
    overscroll-behavior-y: none;
    transition:
      background var(--ds-t-base) var(--ds-ease),
      color var(--ds-t-base) var(--ds-ease);
  }

  h1,
  h2,
  h3,
  h4 {
    font-family: var(--ds-font-display);
    font-weight: 800;
    line-height: var(--ds-lh-tight);
    letter-spacing: -0.02em;
  }

  /* Le focus visible ne se supprime pas. Jamais. */
  :focus-visible {
    outline: 2px solid var(--ds-accent);
    outline-offset: 2px;
    border-radius: var(--ds-r-sm);
  }

  img,
  svg,
  video,
  canvas {
    display: block;
    max-width: 100%;
  }

  button {
    font: inherit;
    color: inherit;
    cursor: pointer;
    background: none;
    border: 0;
  }

  a {
    color: var(--ds-accent-texte);
    text-underline-offset: 3px;
  }

  ::placeholder {
    color: var(--ds-text-3);
  }

  [hidden] {
    display: none !important;
  }

  /* Le sprite d'icônes ne doit occuper aucune place dans le flux. */
  .sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
  }

  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* Icônes Lucide via sprite `<use>` — jamais d'emoji-icône (DS §04). */
  .ico {
    width: 24px;
    height: 24px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  .ico--sm {
    width: 18px;
    height: 18px;
  }
  .ico--lg {
    width: 28px;
    height: 28px;
  }
  .ico--fill {
    fill: currentColor;
    stroke: none;
  }
}

/* ─────────────────────────────────────────────────────────── COMPOSANTS ── */
@layer composants {
  /* ── Boutons : 52 px, retour < 150 ms, chargement = spinner + inerte ── */
  .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ds-sp-2);
    min-height: 52px;
    padding: 0 var(--ds-sp-5);
    border-radius: var(--ds-r-full);
    font: 600 var(--ds-fs-md) var(--ds-font-body);
    text-decoration: none;
    background: var(--ds-surface-2);
    color: var(--ds-text);
    border: 1px solid var(--ds-border);
    transition:
      opacity 100ms var(--ds-ease),
      transform 100ms var(--ds-ease);
  }
  .btn:active {
    opacity: 0.85;
    transform: scale(0.98);
  }
  .btn--primaire {
    background: var(--ds-accent);
    border-color: transparent;
    color: var(--ds-on-accent);
    box-shadow: var(--ds-shadow-2);
  }
  .btn--primaire:active {
    background: var(--ds-accent-press);
  }
  .btn--fantome {
    background: transparent;
    border-color: transparent;
    color: var(--ds-text-2);
  }
  .btn--destructif {
    background: var(--ds-danger-soft);
    border-color: transparent;
    color: var(--ds-danger);
  }
  .btn--sm {
    min-height: 40px;
    padding: 0 var(--ds-sp-4);
    font-size: var(--ds-fs-sm);
  }
  .btn--bloc {
    width: 100%;
  }
  .btn[disabled],
  .btn[aria-disabled="true"] {
    opacity: 0.4;
    pointer-events: none;
  }

  /* htmx pose `.htmx-request` pendant l'appel : le bouton devient inerte et tourne. */
  .btn.htmx-request {
    pointer-events: none;
  }
  .btn.htmx-request::before {
    content: "";
    width: 18px;
    height: 18px;
    flex: none;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: ds-spin 700ms linear infinite;
  }
  @keyframes ds-spin {
    to {
      transform: rotate(1turn);
    }
  }

  /* ── Chips de statut ── */
  .chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 32px;
    padding: 4px var(--ds-sp-3);
    border-radius: var(--ds-r-full);
    font: 600 var(--ds-fs-xs) var(--ds-font-body);
    background: var(--ds-surface-2);
    color: var(--ds-text-2);
  }
  .chip--accent {
    background: var(--ds-accent-soft);
    color: var(--ds-accent-texte);
  }
  .chip--succes {
    background: var(--ds-success-soft);
    color: var(--ds-success);
  }
  .chip--danger {
    background: var(--ds-danger-soft);
    color: var(--ds-danger);
  }
  .chip--energy {
    background: var(--ds-energy-soft);
    color: var(--ds-energy);
  }

  /* ── Formulaires : label visible, erreur texte + icône, champ 52 px / 16 px ── */
  .champ {
    display: grid;
    gap: var(--ds-sp-2);
  }
  .champ + .champ {
    margin-top: var(--ds-sp-4);
  }
  .champ__label {
    font: 600 var(--ds-fs-sm) var(--ds-font-body);
  }
  .champ__aide {
    display: flex;
    gap: 6px;
    align-items: center;
    font-size: var(--ds-fs-xs);
    color: var(--ds-text-3);
  }
  .champ__input,
  .champ input[type="text"],
  .champ input[type="email"],
  .champ input[type="number"],
  .champ input[type="password"],
  .champ select {
    min-height: 52px;
    padding: 0 var(--ds-sp-4);
    width: 100%;
    border: 1.5px solid var(--ds-border);
    border-radius: var(--ds-r-sm);
    background: var(--ds-surface-2);
    color: var(--ds-text);
    font: 500 16px var(--ds-font-body); /* 16 px pile : iOS ne zoome pas */
    transition: border-color var(--ds-t-fast) var(--ds-ease);
  }
  .champ__input:focus,
  .champ input:focus,
  .champ select:focus {
    border-color: var(--ds-accent);
    outline: none;
  }
  .champ--erreur .champ__input,
  .champ--erreur input {
    border-color: var(--ds-danger);
  }
  .champ--erreur .champ__aide,
  .champ__aide--erreur {
    color: var(--ds-danger);
  }

  .ligne-reglage {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-sp-4);
    min-height: var(--ds-tap-min);
  }

  .curseur {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 44px;
    background: none;
  }
  .curseur::-webkit-slider-runnable-track {
    height: 8px;
    border-radius: var(--ds-r-full);
    background: linear-gradient(90deg, var(--ds-accent) var(--val, 50%), var(--ds-ring-track) var(--val, 50%));
  }
  .curseur::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 28px;
    height: 28px;
    margin-top: -10px;
    border-radius: 50%;
    background: var(--ds-surface);
    border: 3px solid var(--ds-accent);
    box-shadow: var(--ds-shadow-1);
  }
  .curseur::-moz-range-track {
    height: 8px;
    border-radius: var(--ds-r-full);
    background: var(--ds-ring-track);
  }
  .curseur::-moz-range-progress {
    height: 8px;
    border-radius: var(--ds-r-full);
    background: var(--ds-accent);
  }
  .curseur::-moz-range-thumb {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--ds-surface);
    border: 3px solid var(--ds-accent);
  }

  /* ── Réponses du wizard : carte (choix unique) / puce (choix multiple) ── */
  .carte-choix {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--ds-sp-3);
    width: 100%;
    min-height: 64px;
    padding: var(--ds-sp-3) var(--ds-sp-4);
    border: 1.5px solid var(--ds-border);
    border-radius: var(--ds-r-md);
    background: var(--ds-surface);
    text-align: left;
    cursor: pointer;
    transition:
      border-color var(--ds-t-fast) var(--ds-ease),
      background var(--ds-t-fast) var(--ds-ease),
      transform 100ms var(--ds-ease);
  }
  .carte-choix:active {
    transform: scale(0.98);
  }
  .carte-choix:has(input:checked),
  .carte-choix[aria-pressed="true"] {
    border-color: var(--ds-accent);
    background: var(--ds-accent-soft);
  }
  .carte-choix .ico {
    color: var(--ds-text-2);
  }
  .carte-choix:has(input:checked) .ico,
  .carte-choix[aria-pressed="true"] .ico {
    color: var(--ds-accent-texte);
  }
  .carte-choix input {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
  }
  .carte-choix__titre {
    font-weight: 600;
  }
  .carte-choix__sous {
    display: block;
    font-size: var(--ds-fs-xs);
    color: var(--ds-text-2);
    font-weight: 400;
  }

  .puce-choix {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--ds-sp-2);
    min-height: var(--ds-tap-min);
    padding: 0 var(--ds-sp-4);
    border: 1.5px solid var(--ds-border);
    border-radius: var(--ds-r-full);
    background: var(--ds-surface);
    font-weight: 600;
    font-size: var(--ds-fs-sm);
    color: var(--ds-text);
    cursor: pointer;
    transition:
      border-color var(--ds-t-fast) var(--ds-ease),
      background var(--ds-t-fast) var(--ds-ease);
  }
  .puce-choix .ico {
    width: 18px;
    height: 18px;
    color: var(--ds-text-3);
  }
  .puce-choix input {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
  }
  .puce-choix:has(input:checked),
  .puce-choix[aria-pressed="true"] {
    border-color: var(--ds-accent);
    background: var(--ds-accent-soft);
  }
  .puce-choix:has(input:checked) .ico,
  .puce-choix[aria-pressed="true"] .ico {
    color: var(--ds-accent-texte);
  }

  /* ── Cartes ── */
  .carte {
    background: var(--ds-surface);
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-r-lg);
    padding: var(--ds-sp-5);
  }
  .carte + .carte {
    margin-top: var(--ds-sp-3);
  }
  .carte--accent {
    border-color: var(--ds-accent);
  }
  .carte__sur-titre {
    display: flex;
    align-items: center;
    gap: var(--ds-sp-2);
    font: 700 var(--ds-fs-xs) var(--ds-font-mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ds-accent-texte);
  }
  .carte__sur-titre .ico {
    width: 16px;
    height: 16px;
  }
  .carte__titre {
    font: 700 var(--ds-fs-lg) / 1.25 var(--ds-font-display);
    margin-top: var(--ds-sp-2);
  }
  .carte__sous {
    color: var(--ds-text-2);
    margin-top: var(--ds-sp-2);
    font-size: var(--ds-fs-sm);
  }

  .carte-stat {
    display: grid;
    gap: 2px;
    border-radius: var(--ds-r-md);
  }
  .carte-stat__valeur {
    font: 700 var(--ds-fs-2xl) / 1 var(--ds-font-display);
    font-variant-numeric: tabular-nums;
  }
  .carte-stat__label {
    font-size: var(--ds-fs-xs);
    color: var(--ds-text-2);
  }

  .carte-temoin {
    display: grid;
    gap: var(--ds-sp-4);
  }
  .carte-temoin__auteur {
    display: flex;
    align-items: center;
    gap: var(--ds-sp-3);
  }
  .carte-temoin__nom {
    font-weight: 700;
    font-size: var(--ds-fs-sm);
  }
  .carte-temoin__role {
    font-size: var(--ds-fs-xs);
    color: var(--ds-text-3);
  }

  .carte-tarif {
    position: relative;
    display: grid;
    gap: var(--ds-sp-4);
  }
  .carte-tarif--populaire {
    border-color: var(--ds-accent);
    box-shadow: var(--ds-shadow-2);
  }
  .carte-tarif__ruban {
    position: absolute;
    top: -14px;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
  }
  .carte-tarif__prix {
    font: 700 var(--ds-fs-2xl) var(--ds-font-display);
  }
  .carte-tarif__prix small {
    font: 500 var(--ds-fs-sm) var(--ds-font-body);
    color: var(--ds-text-3);
  }

  .avatar {
    width: 44px;
    height: 44px;
    flex: none;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--ds-accent-soft);
    color: var(--ds-accent-texte);
    font: 700 var(--ds-fs-sm) var(--ds-font-display);
  }
  .avatar--energy {
    background: var(--ds-energy-soft);
    color: var(--ds-energy);
  }

  .carte-temoin {
    display: grid;
    gap: var(--ds-sp-4);
  }
  .carte-temoin__auteur {
    display: flex;
    align-items: center;
    gap: var(--ds-sp-3);
  }
  .carte-temoin__nom {
    font-weight: 700;
    font-size: var(--ds-fs-sm);
  }
  .carte-temoin__role {
    font-size: var(--ds-fs-xs);
    color: var(--ds-text-3);
  }

  .carte-tarif {
    position: relative;
    display: grid;
    gap: var(--ds-sp-4);
    align-content: start;
  }
  .carte-tarif--populaire {
    border-color: var(--ds-accent);
    box-shadow: var(--ds-shadow-2);
  }
  .carte-tarif__ruban {
    position: absolute;
    top: -14px;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
  }
  .carte-tarif__prix {
    font: 700 var(--ds-fs-2xl) var(--ds-font-display);
  }
  .carte-tarif__prix small {
    font: 500 var(--ds-fs-sm) var(--ds-font-body);
    color: var(--ds-text-3);
  }

  .liste-coches {
    display: grid;
    gap: var(--ds-sp-2);
    list-style: none;
    font-size: var(--ds-fs-sm);
    color: var(--ds-text-2);
  }
  .liste-coches li {
    display: flex;
    gap: var(--ds-sp-2);
    align-items: baseline;
  }
  .liste-coches .ico {
    width: 16px;
    height: 16px;
    transform: translateY(2px);
    color: var(--ds-success);
  }
  .liste-coches .ico--non {
    color: var(--ds-danger);
  }

  /* ── Jauge de minutes (topbar 40 px + grand anneau) ── */
  .jauge {
    position: relative;
    flex: none;
  }
  .jauge svg {
    transform: rotate(-90deg);
    width: 100%;
    height: 100%;
  }
  .jauge__piste {
    fill: none;
    stroke: var(--ds-ring-track);
  }
  .jauge__arc {
    fill: none;
    stroke: var(--ds-accent);
    stroke-linecap: round;
    transition: stroke-dashoffset var(--ds-t-slow) var(--ds-ease);
  }
  .jauge__centre {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    align-content: center;
  }
  .jauge--topbar {
    width: 40px;
    height: 40px;
  }
  .jauge--topbar .jauge__piste,
  .jauge--topbar .jauge__arc {
    stroke-width: 3.5;
  }
  .jauge--topbar .jauge__centre {
    font: 700 11px var(--ds-font-mono);
  }
  .jauge--large {
    width: 148px;
    height: 148px;
  }
  .jauge--large .jauge__piste,
  .jauge--large .jauge__arc {
    stroke-width: 8;
  }
  .jauge__nombre {
    font: 700 2.2rem / 1 var(--ds-font-mono);
    font-variant-numeric: tabular-nums;
  }
  .jauge__unite {
    font-size: var(--ds-fs-xs);
    color: var(--ds-text-2);
  }

  /* ══ LA SIGNATURE : le compteur de reps ══
     Archivo s'étire (wdth 62 → 125) à mesure qu'on approche de l'objectif.
     Une seule audace dans tout le produit ; tout le reste est discipliné autour. */
  .compteur-reps {
    text-align: center;
  }
  .compteur-reps__nombre {
    font-family: var(--ds-font-display);
    font-weight: 800;
    font-size: var(--ds-fs-hero);
    line-height: 1;
    font-variant-numeric: tabular-nums;
    font-variation-settings: "wdth" var(--wdth, 62);
    display: inline-block;
    transition: font-variation-settings var(--ds-t-base) var(--ds-ease);
  }
  .compteur-reps__nombre.est-tick {
    animation: rep-tick var(--ds-t-fast) var(--ds-ease-pop);
    text-shadow: 0 0 32px var(--ds-energy);
  }
  @keyframes rep-tick {
    50% {
      transform: scale(1.06);
    }
  }
  /* Une rep refusée doit se VOIR : rejetée en silence, elle passe pour un bug. */
  .compteur-reps__nombre.est-refus {
    animation: rep-refus var(--ds-t-base) var(--ds-ease);
  }
  @keyframes rep-refus {
    50% {
      opacity: 0.35;
      transform: translateX(-5px);
    }
  }
  .compteur-reps__objectif {
    font: 600 var(--ds-fs-sm) var(--ds-font-mono);
    color: var(--ds-text-2);
  }
  .compteur-reps--fait .compteur-reps__nombre {
    color: var(--ds-energy);
  }

  /* ── Barre, toast, streak, accordéon, étape, vide ── */
  .barre {
    height: 8px;
    border-radius: var(--ds-r-full);
    background: var(--ds-ring-track);
    overflow: hidden;
  }
  .barre__valeur {
    height: 100%;
    width: calc(var(--pct, 0) * 1%);
    border-radius: inherit;
    background: var(--ds-accent);
    transition: width var(--ds-t-slow) var(--ds-ease);
  }
  .barre__valeur--energy {
    background: var(--ds-energy);
  }

  .toasts {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(var(--ds-tabbar-h) + var(--ds-sp-3));
    z-index: var(--ds-z-toast);
    display: grid;
    gap: var(--ds-sp-2);
    justify-items: center;
    max-width: calc(100vw - var(--ds-sp-6));
    pointer-events: none;
  }
  .toast {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-sp-3);
    padding: var(--ds-sp-3) var(--ds-sp-4);
    border-radius: var(--ds-r-md);
    background: var(--ds-surface-2);
    border: 1px solid var(--ds-border);
    color: var(--ds-text);
    box-shadow: var(--ds-shadow-2);
    font-size: var(--ds-fs-sm);
    font-weight: 600;
    pointer-events: auto;
    animation: toast-in var(--ds-t-base) var(--ds-ease);
  }
  .toast .ico {
    color: var(--ds-success);
  }
  .toast--erreur .ico {
    color: var(--ds-danger);
  }
  .toast--info .ico {
    color: var(--ds-accent-texte);
  }
  .toast--sortie {
    opacity: 0;
    transform: translateY(8px);
    transition:
      opacity var(--ds-t-base) var(--ds-ease),
      transform var(--ds-t-base) var(--ds-ease);
  }
  @keyframes toast-in {
    from {
      opacity: 0;
      transform: translateY(12px);
    }
  }

  .streak {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-sp-2);
    font: 700 var(--ds-fs-lg) var(--ds-font-mono);
  }
  .streak .ico {
    color: var(--ds-energy);
    fill: var(--ds-energy-soft);
  }

  .accordeon {
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-r-md);
    background: var(--ds-surface);
  }
  .accordeon + .accordeon {
    margin-top: var(--ds-sp-3);
  }
  .accordeon summary {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--ds-sp-4);
    min-height: var(--ds-tap-min);
    padding: var(--ds-sp-3) var(--ds-sp-4);
    font-weight: 600;
    cursor: pointer;
    list-style: none;
  }
  .accordeon summary::-webkit-details-marker {
    display: none;
  }
  .accordeon summary .ico {
    color: var(--ds-text-3);
    transition: transform var(--ds-t-base) var(--ds-ease);
  }
  .accordeon[open] summary .ico {
    transform: rotate(180deg);
  }
  .accordeon__corps {
    padding: 0 var(--ds-sp-4) var(--ds-sp-4);
    color: var(--ds-text-2);
    font-size: var(--ds-fs-sm);
  }

  .etape {
    display: grid;
    grid-template-columns: 44px 1fr;
    gap: var(--ds-sp-4);
    align-items: start;
  }
  .etape__num {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--ds-accent-soft);
    color: var(--ds-accent-texte);
    font: 700 var(--ds-fs-lg) var(--ds-font-mono);
  }
  .etape__titre {
    font: 700 var(--ds-fs-md) var(--ds-font-display);
  }
  .etape__texte {
    color: var(--ds-text-2);
    font-size: var(--ds-fs-sm);
  }

  /* États vides — jamais un écran mort, toujours une invitation. */
  .vide {
    display: grid;
    justify-items: center;
    gap: var(--ds-sp-3);
    text-align: center;
    padding: var(--ds-sp-6) var(--ds-sp-4);
    color: var(--ds-text-2);
  }
  .vide .ico--lg {
    color: var(--ds-text-3);
  }

  /* ── Coquille : topbar, tab bar, drawer (§2.2 — jamais swappée) ── */
  .shell {
    min-height: 100dvh; /* jamais 100vh : la barre d'URL mobile mentirait */
    display: flex;
    flex-direction: column;
  }

  .topbar-app {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-sp-3);
    padding: calc(var(--ds-sp-3) + var(--ds-safe-top)) var(--ds-sp-4) var(--ds-sp-3);
    background: var(--ds-bg);
    border-bottom: 1px solid var(--ds-border);
  }
  .topbar-app__titre {
    font: 800 var(--ds-fs-lg) var(--ds-font-display);
    letter-spacing: -0.01em;
  }

  .contenu {
    flex: 1;
    padding: var(--ds-sp-4) var(--ds-sp-4) calc(var(--ds-tabbar-h) + var(--ds-sp-5));
    display: grid;
    gap: var(--ds-sp-4);
    align-content: start;
  }
  /* Fondu 120 ms au swap — jamais de slide horizontal (conflit avec le swipe-back). */
  .contenu.htmx-swapping {
    opacity: 0;
    transition: opacity var(--ds-t-fast) var(--ds-ease);
  }

  .tabbar {
    position: fixed;
    inset: auto 0 0 0;
    z-index: var(--ds-z-tabbar);
    display: flex;
    align-items: stretch;
    background: var(--ds-surface);
    border-top: 1px solid var(--ds-border);
    padding-bottom: var(--ds-safe-bottom);
    height: var(--ds-tabbar-h);
  }
  .tabbar__item {
    flex: 1;
    display: grid;
    place-items: center;
    align-content: center;
    gap: 2px;
    font: 600 var(--ds-fs-xs) var(--ds-font-body);
    color: var(--ds-text-3);
    min-height: 64px;
    text-decoration: none;
  }
  .tabbar__item[aria-current="page"] {
    color: var(--ds-accent-texte);
  }
  .tabbar__fab {
    flex: none;
    align-self: center;
    width: 64px;
    height: 64px;
    margin: 0 var(--ds-sp-2);
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--ds-accent);
    color: var(--ds-on-accent);
    box-shadow: var(--ds-shadow-2);
    transform: translateY(-14px);
    transition: transform 100ms var(--ds-ease);
  }
  .tabbar__fab:active {
    transform: translateY(-14px) scale(0.94);
  }

  /* ≥ 1024 px : la tab bar devient un rail latéral. Même partial, CSS seule. */
  @media (min-width: 1024px) {
    .shell {
      padding-left: 96px;
    }
    .tabbar {
      inset: 0 auto 0 0;
      flex-direction: column;
      justify-content: center;
      gap: var(--ds-sp-4);
      width: 96px;
      height: 100dvh;
      border-top: none;
      border-right: 1px solid var(--ds-border);
      padding: var(--ds-sp-4) 0;
    }
    .tabbar__fab {
      transform: none;
    }
    .tabbar__fab:active {
      transform: scale(0.94);
    }
    .contenu {
      max-width: 720px;
      margin: 0 auto;
      width: 100%;
      padding-bottom: var(--ds-sp-8);
    }
  }

  .drawer-scrim {
    position: fixed;
    inset: 0;
    background: var(--ds-scrim);
    z-index: var(--ds-z-drawer);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--ds-t-slow) var(--ds-ease);
  }
  .drawer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: calc(var(--ds-z-drawer) + 1);
    max-height: 85dvh;
    overflow-y: auto;
    background: var(--ds-surface);
    border-radius: var(--ds-r-lg) var(--ds-r-lg) 0 0;
    border: 1px solid var(--ds-border);
    border-bottom: 0;
    padding: 0 var(--ds-sp-5) calc(var(--ds-sp-5) + var(--ds-safe-bottom));
    transform: translateY(105%);
    transition: transform var(--ds-t-slow) var(--ds-ease);
  }
  .est-ouvert .drawer {
    transform: none;
  }
  .est-ouvert .drawer-scrim {
    opacity: 1;
    pointer-events: auto;
  }
  .drawer__poignee {
    display: grid;
    place-items: center;
    min-height: var(--ds-tap-min);
    width: 100%;
  }
  .drawer__poignee::before {
    content: "";
    width: 44px;
    height: 5px;
    border-radius: var(--ds-r-full);
    background: var(--ds-border);
  }

  /* Bandeau de session scroll — singleton de la coquille. */
  .bandeau {
    display: flex;
    align-items: center;
    gap: var(--ds-sp-3);
    padding: var(--ds-sp-2) var(--ds-sp-4);
    background: var(--ds-energy-soft);
    color: var(--ds-energy);
    font: 600 var(--ds-fs-sm) var(--ds-font-body);
    border-bottom: 1px solid var(--ds-border);
  }
  .bandeau__chrono {
    margin-left: auto;
    font: 700 var(--ds-fs-sm) var(--ds-font-mono);
    font-variant-numeric: tabular-nums;
  }
}

/* ─────────────────────────────────────────────────────────── UTILITAIRES ── */
@layer utilitaires {
  .pile {
    display: grid;
    gap: var(--ds-sp-3);
  }
  .pile--serree {
    gap: var(--ds-sp-2);
  }
  .pile--large {
    gap: var(--ds-sp-5);
  }
  .rangee {
    display: flex;
    align-items: center;
    gap: var(--ds-sp-2);
  }
  .rangee--entre {
    justify-content: space-between;
  }
  .rangee--enroule {
    flex-wrap: wrap;
  }
  .grille-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ds-sp-3);
  }
  .mono {
    font-family: var(--ds-font-mono);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
  }
  .display {
    font-family: var(--ds-font-display);
    font-weight: 800;
    letter-spacing: -0.02em;
  }
  .texte-2 {
    color: var(--ds-text-2);
  }
  .texte-3 {
    color: var(--ds-text-3);
  }
  .accent {
    color: var(--ds-accent-texte);
  }
  .energy {
    color: var(--ds-energy);
  }
  .petit {
    font-size: var(--ds-fs-xs);
  }
  .titre-section {
    margin-top: var(--ds-sp-3);
    font: 700 var(--ds-fs-md) var(--ds-font-display);
  }
  .centre {
    text-align: center;
  }
  .pousse-droite {
    margin-left: auto;
  }
  .pleine-largeur {
    width: 100%;
  }
  .sans-marge {
    margin: 0;
    list-style: none;
  }
}
