/* =========================================================
   TCM × Jopitech — feuille de style principale
   Tokens + composants, conformes au design system (docs/02).
   Le thème actif est porté par data-theme sur <html> :
   "prive" (défaut, chaud) ou "pro" (froid).
   ========================================================= */

/* =========================================================
   0. POLICE LEXEND — AUTO-HÉBERGÉE (docs/21 §4 exigence 2)
   Fichier variable (axe wght 100→900) servi depuis notre propre
   domaine : plus aucune requête vers fonts.googleapis.com ni
   fonts.gstatic.com, donc plus aucun transfert d’adresse IP vers
   Google au chargement d’une page.
   Deux sous-ensembles seulement (latin, latin-ext) : ce sont les
   seuls que le texte du site utilise. `font-display: swap` conserve
   le comportement de rendu qu’avait la feuille Google Fonts.
   Source : Google Fonts, Lexend v26, licence SIL OFL 1.1.
   ========================================================= */
@font-face {
  font-family: "Lexend";
  font-style: normal;
  font-weight: 300 700;          /* les 5 graisses employées : 300/400/500/600/700 */
  font-display: swap;
  src: url("../assets/fonts/lexend-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: "Lexend";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("../assets/fonts/lexend-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;
}

/* =========================================================
   1. TOKENS (docs/02 §1 — repris tels quels)
   Couleurs officielles (interdiction de les altérer) :
   orange #F58B24 · rose #EC2475 · bleu foncé #4165AF · bleu clair #3EC6F2
   ========================================================= */

:root {
  /* ---------- Couleurs de marque (fixes, hors thème) ---------- */
  --brand-orange: #F58B24;
  --brand-pink:   #EC2475;
  --brand-blue:   #4165AF;
  --brand-cyan:   #3EC6F2;

  /* ---------- Neutres (communs aux 2 univers) ---------- */
  --ink:        #171A21;
  --ink-muted:  #5A6172;
  --paper:      #FFFFFF;
  --line:       #E4E7EE;
  --dark:       #14161C;
  --on-dark:        #FFFFFF;
  --on-dark-muted:  #A9B0BF;

  /* ---------- Typo ---------- */
  --font: "Lexend", system-ui, sans-serif;

  --fs-hero:  clamp(2.25rem, 1.2rem + 4.5vw, 4rem);
  --fs-h2:    clamp(1.625rem, 1.1rem + 2.2vw, 2.5rem);
  --fs-h3:    clamp(1.25rem, 1.05rem + 0.8vw, 1.5rem);
  --fs-h4:    1.125rem;
  --fs-body:  1rem;
  --fs-small: 0.875rem;
  --fs-tiny:  0.75rem;
  --fs-price: clamp(2rem, 1.5rem + 1.5vw, 2.75rem);

  --fw-light: 300; --fw-regular: 400; --fw-medium: 500;
  --fw-semibold: 600; --fw-bold: 700;

  --lh-tight: 1.1;
  --lh-heading: 1.2;
  --lh-body: 1.6;

  --ls-hero: 0.01em;
  --ls-heading: 0.03em;
  --ls-label: 0.08em;

  /* ---------- Espacements (échelle 4px) ----------
     L'échelle elle-même ne change pas (docs/02 §1). Ce qui change en v15
     (docs/45) c'est son EMPLOI : à chaque rôle une valeur, et une seule.

       4  --sp-1   calage optique, rien d'autre
       8  --sp-2   étiquette ↔ valeur, icône ↔ texte, espace sous un h4
      12  --sp-3   espace sous un h3
      16  --sp-4   entre éléments d'un même groupe
      24  --sp-5   sous un h1/h2 ; entre deux paragraphes ; GOUTTIÈRE entre blocs
      32  --sp-6   REMBOURRAGE d'un bloc ; au-dessus et sous un .cta-group
      48  --sp-7   titre de section ↔ contenu de la section
      64  --sp-8   séparation de deux articles ; rythme de section sur mobile
      96  --sp-9   rythme de section sur grand écran

     Règle de rapport (docs/45 §2) : le rembourrage d'un bloc (32) est TOUJOURS
     plus grand que la gouttière qui le sépare de son voisin (24). Un bloc plus
     serré dedans que dehors paraît étriqué quelle que soit la page. Rapport
     retenu pour le site public : 4/3. */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;
  --sp-4: 1rem;     --sp-5: 1.5rem;   --sp-6: 2rem;
  --sp-7: 3rem;     --sp-8: 4rem;     --sp-9: 6rem;
  --section-y: clamp(var(--sp-8), 10vw, var(--sp-9));
  --container: 72rem;
  --container-pad: clamp(1rem, 4vw, 2rem);
  /* Badges partenaires (§13.1, docs/62). 3 rem et non 1.75 rem : les deux
     badges livrés sont des verrouillages « marque + statut » dont le mot de
     statut occupe ~21 % de la hauteur ; à 28 px il serait rendu à 5,8 px. */
  --partner-logo-h:  3rem;    /* 48 px — hauteur commune des badges */
  --partner-plate-h: 5rem;    /* 80 px — hauteur commune des plaques */

  /* Largeur de lecture du texte courant à 16 px (docs/45 §4).
     JAMAIS en `ch` : en CSS 1ch = la largeur du glyphe « 0 », nettement plus
     large que le caractère moyen d'un texte français composé en Lexend.
     Mesuré au canvas sur le texte réel du site, `max-width: 65ch` rendait 80 à
     90 caractères par ligne — bien au-delà du maximum lisible de 75.
     32 rem = 512 px = 69 caractères mesurés. */
  --measure-body: 32rem;

  /* ---------- Gabarits harmonisés (spec 17 §1.3 et §4.3) ---------- */
  --hero-h-page:        18rem;   /* 288 px — hauteur standard des pages hors accueil */
  --hero-h-page-mobile: 15rem;   /* 240 px — idem < 768 px */
  --btn-w-hero:         17rem;   /* 272 px — gabarit commun des CTA de hero, les deux univers */

  /* ---------- Rayons (écho des pales du logo) ---------- */
  --r-pill: 999px;
  --r-lg:   1.5rem;
  --r-md:   1rem;
  --r-cut:  0.25rem;
  --r-hero: 2rem;   /* v2 : rayon de la carte hero */

  /* ---------- Ombres ---------- */
  --shadow-card:  0 1px 2px rgb(23 26 33 / .06), 0 8px 24px rgb(23 26 33 / .07);
  --shadow-hover: 0 2px 4px rgb(23 26 33 / .07), 0 16px 40px rgb(23 26 33 / .12);
  --shadow-header: 0 1px 0 var(--line);

  /* ---------- Motion ---------- */
  --ease: cubic-bezier(.4, 0, .2, 1);
  --t-fast: 150ms;
  --t-med:  250ms;
  --t-theme: 600ms;

  --focus-ring: 0 0 0 3px var(--paper), 0 0 0 6px var(--accent);

  /* v3 : fond de la modale — dérivé de --ink, jamais de noir pur */
  --overlay: rgb(23 26 33 / .55);

  /* --- v7 : gabarit de page légale (spec 15 §8) — les seuls tokens ajoutés --- */
  --fs-legal:      1.0625rem;  /* 17px — corps de lecture longue, pages légales uniquement */
  --lh-legal:      1.75;       /* 29.75px de pas de ligne */
  --measure:       35.5rem;    /* 568px = 70 caractères réels en Lexend 17px (mesuré, 15 §1.3) */
  --legal-toc-w:   17.5rem;    /* 280px — colonne de sommaire */
  --scroll-offset: 6.5rem;     /* 104px = header 80 + 24 de respiration */
  --note-bg:       #FDF6E9;    /* encadré attention, hors thème */
  --note-rail:     #8F5A00;    /* rail + titre de l'encadré attention, hors thème */
}
@media (max-width: 1023px) { :root { --scroll-offset: 5.5rem; } }   /* header 64 + 24 */

/* ---------- THÈME PRIVÉ (chaud) — défaut ---------- */
:root, [data-theme="prive"] {
  --accent:        var(--brand-pink);
  --accent-2:      var(--brand-orange);   /* JAMAIS en texte sur blanc ni sous texte blanc */
  --accent-text:   #C9155F;
  --accent-alt-text: #B35300;

  --grad: linear-gradient(105deg, var(--brand-orange), var(--brand-pink));
  --grad-cta: linear-gradient(105deg, #E0186B, #C9155F);

  --hero-bg:    #240A12;
  --hero-blob-a: var(--brand-pink);
  --hero-blob-b: var(--brand-orange);
  --hero-blob-c: #FF5A3C;
  --hero-ink:   #FFFFFF;
  --hero-ink-soft: #FFD9B0;

  --surface-tint: #FFF4EA;
  --chip-bg:  #FDE3D2; --chip-text: #8A3D05;
  --btn2-border: var(--accent-text); --btn2-text: var(--accent-text);
  --link: var(--accent-text);

  /* Fil moulinet : ordre chaud→froid en univers Privé (designer §5) */
  --fil-1: var(--brand-orange); --fil-2: var(--brand-pink);
  --fil-3: var(--brand-blue);   --fil-4: var(--brand-cyan);

  --footer-titre: #FF8FBC; /* intitulés footer, version claire de l'univers actif */

  /* v2 §3.2 : voile de l'univers sur la photo du split proximité */
  --img-wash: linear-gradient(200deg, rgb(236 36 117 / .16), rgb(245 139 36 / .10) 45%, transparent 70%);
}

/* ---------- THÈME ENTREPRISE (froid) ---------- */
[data-theme="pro"] {
  --accent:        var(--brand-blue);
  --accent-2:      var(--brand-cyan);
  --accent-text:   var(--brand-blue);
  --accent-alt-text: #0C779C;

  --grad: linear-gradient(105deg, var(--brand-cyan), var(--brand-blue));
  --grad-cta: linear-gradient(105deg, #35528F, var(--brand-blue));

  --hero-bg:    #071630;
  --hero-blob-a: var(--brand-blue);
  --hero-blob-b: var(--brand-cyan);
  --hero-blob-c: #2E8FE0;
  --hero-ink:   #FFFFFF;
  --hero-ink-soft: #BFE6FF;

  --surface-tint: #EDF3FC;
  --chip-bg:  #D9E4F7; --chip-text: #2E4A85;
  --btn2-border: var(--accent-text); --btn2-text: var(--accent-text);
  --link: var(--accent-text);

  /* Fil moulinet : ordre inversé (froid→chaud) en univers Entreprise */
  --fil-1: var(--brand-cyan); --fil-2: var(--brand-blue);
  --fil-3: var(--brand-pink); --fil-4: var(--brand-orange);

  --footer-titre: #8FC9F5;

  --img-wash: linear-gradient(200deg, rgb(65 101 175 / .20), rgb(62 198 242 / .10) 45%, transparent 70%);
}

/* ---------- JETONS D’ÉTAT (LOT-DESIGN-18, repris de la maquette des cours)
   Cinq paires fond / texte, hors thème : un état ne change pas de sens quand
   on passe de Privé à Entreprise. Chaque paire a été mesurée, le rapport de
   contraste est écrit en commentaire — tous au-dessus de 4,5:1 (AA). ---------- */
:root {
  --etat-ok-bg:        #DCEFE3; --etat-ok-text:        #14603A;  /* 6,33:1 */
  --etat-attention-bg: #FDE3D2; --etat-attention-text: #8A3D05;  /* 6,22:1 */
  --etat-alerte-bg:    #FBE0E6; --etat-alerte-text:    #9E1239;  /* 6,50:1 */
  --etat-info-bg:      #D9E4F7; --etat-info-text:      #2E4A85;  /* 6,73:1 */
  --etat-neutre-bg:    #F0F2F6; --etat-neutre-text:    #5A6172;  /* 5,53:1 */
}

/* =========================================================
   2. BASE & TYPOGRAPHIE (règles globales non négociables)
   ========================================================= */

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

html {
  font-family: var(--font);
  color: var(--ink);
  background: var(--paper);
  scroll-behavior: smooth;
}
body {
  margin: 0;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-regular);
}

/* Capitales portées par text-transform, JAMAIS tapées en dur (a11y) */
h1, h2, h3, h4, .heading {
  text-transform: uppercase;
  letter-spacing: var(--ls-heading);
  line-height: var(--lh-heading);
  font-weight: var(--fw-semibold);
  text-wrap: balance;
  margin: 0 0 var(--sp-3);
}
/* v15 (docs/45 §5) — l'espace sous un titre suit le RANG du titre.
   Avant : 16 px sous tous les niveaux. Un h2 de 40 px et un h4 de 18 px
   recevaient donc le même blanc : le h2 paraissait collé à son texte et le h4
   détaché du sien. La hiérarchie se lisait dans le corps mais pas dans le
   blanc, alors que c'est le blanc qui la donne à voir en premier. */
h1 { font-size: var(--fs-hero); font-weight: var(--fw-bold); letter-spacing: var(--ls-hero); line-height: var(--lh-tight); margin-bottom: var(--sp-5); }
h2 { font-size: var(--fs-h2); margin-bottom: var(--sp-5); }
h3 { font-size: var(--fs-h3); margin-bottom: var(--sp-3); }
h4 { font-size: var(--fs-h4); margin-bottom: var(--sp-2); }

/* v15 (docs/45 §5) — le site n'avait AUCUNE règle sur <p> : la marge venait de
   l'agent utilisateur (1 em = 16 px), soit MOINS que l'interligne du corps
   (1,6 × 16 = 25,6 px). Le blanc entre deux paragraphes était plus petit que
   le blanc entre deux lignes : rien ne signalait la fin d'un paragraphe.
   24 px = 0,94 × l'interligne : la coupure redevient visible. */
p { margin: 0 0 var(--sp-5); }

a { color: var(--link); }
img { max-width: 100%; display: block; }

.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

/* Masqué visuellement mais lu par les lecteurs d'écran */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* Eyebrow (surtitre de section) */
.eyebrow {
  font-size: var(--fs-tiny);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--accent-text);
  margin: 0 0 var(--sp-2);
}

/* Fondu ambiant lors de la bascule d'univers (designer §3).
   Les custom properties ne s'interpolent pas : on transitionne
   les propriétés consommatrices pendant 600 ms. */
html.theming, html.theming *, html.theming *::before, html.theming *::after {
  transition: background-color var(--t-theme) var(--ease),
              border-color var(--t-theme) var(--ease),
              color var(--t-theme) var(--ease),
              fill var(--t-theme) var(--ease) !important;
  /* audit 26 §2 : box-shadow RETIRÉ de cette liste. Les trois tokens d'ombre
     (--shadow-card, --shadow-hover, --shadow-header) sont définis une seule
     fois dans :root et ne dépendent d'aucun thème : la transition ne pouvait
     donc rien interpoler, mais elle demandait au moteur de repeindre l'ombre
     de CHAQUE élément de la page pendant les 600 ms de la bascule. */
}

/* =========================================================
   3. BANNIÈRE D'ANNONCE (designer §4.5 — hors thème)
   ========================================================= */

/* Wrapper grid : permet la fermeture animée height→0 sans mesure JS */
#banner-slot { display: grid; grid-template-rows: 1fr; transition: grid-template-rows var(--t-med) var(--ease); }
#banner-slot.banner-fermee { grid-template-rows: 0fr; }
#banner-slot > .banner { overflow: hidden; }

.banner {
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: 44px;
  padding: var(--sp-3) var(--container-pad);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
}
.banner__icone { flex: none; width: 20px; height: 20px; }
.banner__message { margin: 0; }
.banner__fermer {
  margin-left: auto; flex: none;
  width: 32px; height: 32px;
  border: 0; background: transparent; color: inherit;
  font: inherit; font-size: 1rem; line-height: 1;
  border-radius: var(--r-md); cursor: pointer;
}
.banner__fermer:hover { background: rgb(0 0 0 / .12); }
.banner__fermer:focus-visible { box-shadow: var(--focus-ring); outline: none; }

/* Variante info : fond bleu clair, texte bleu foncé (AA 7.2:1) */
.banner--info  { background: #D9E4F7; color: #2E4A85; }
/* Variante alerte : ambre foncé, texte blanc (AA 5.8:1) */
.banner--alerte { background: #8F5A00; color: #FFFFFF; }

/* =========================================================
   4. HEADER (designer §4.1)
   ========================================================= */

.header {
  position: sticky; top: 0; z-index: 50;
  background: #FFFFFF; /* fallback si pas de backdrop-filter */
  box-shadow: var(--shadow-header);
}
@supports (backdrop-filter: blur(12px)) {
  .header { background: rgb(255 255 255 / .85); backdrop-filter: blur(12px); }
}
/* v2 §1.2 — grille 3 zones : logo | menu centré | switcher tout à droite */
.header__inner {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--container-pad);
  height: 80px;
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: var(--sp-5);
}
.header__logo { display: flex; align-items: center; }
.header__logo-full { height: 56px; width: auto; }
.header__logo-icon { display: none; height: 40px; width: auto; }
/* v2 §1.1 : aucune animation sur le logo (pivot v1 supprimé) */

.header__nav { justify-self: center; }
.header__nav-group { display: flex; align-items: center; gap: var(--sp-5); }
/* Un seul menu visible : celui de l'univers actif */
[data-theme="prive"] [data-univers-nav="pro"],
[data-theme="pro"] [data-univers-nav="prive"] { display: none; }

.header__link {
  font-size: var(--fs-small); font-weight: var(--fw-medium);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  color: var(--ink); text-decoration: none;
  transition: color var(--t-fast) var(--ease);
}
.header__link:hover, .header__link:focus-visible {
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--accent);
  text-underline-offset: 6px;
}
/* Liens des futures pages (v2 §1.3) : gris AA, pas de hover, pas de clic */
.header__link[aria-disabled="true"],
.menu-mobile__link[aria-disabled="true"] {
  color: var(--ink-muted);
  cursor: default;
}
.header__link[aria-disabled="true"]:hover,
.header__link[aria-disabled="true"]:focus-visible,
.menu-mobile__link[aria-disabled="true"]:hover {
  color: var(--ink-muted);
  text-decoration: none;
}

/* Zone droite : switcher (+ burger sous 1024px) */
.header__right { display: flex; align-items: center; gap: var(--sp-3); justify-self: end; }

/* Burger (mobile uniquement) */
.burger {
  display: none;
  flex-direction: column; justify-content: center; gap: 5px;
  width: 44px; height: 44px;
  border: 0; background: transparent; cursor: pointer;
  border-radius: var(--r-md);
}
.burger__bar { display: block; width: 22px; height: 2px; background: var(--ink); margin-inline: auto; }
.burger:focus-visible { box-shadow: var(--focus-ring); outline: none; }

/* Panneau mobile plein écran */
.menu-mobile {
  position: fixed; inset: 0; z-index: 40;
  background: var(--paper);
  padding: calc(64px + var(--sp-6)) var(--container-pad) var(--sp-6);
}
.menu-mobile nav { display: flex; flex-direction: column; gap: var(--sp-5); }
.menu-mobile__group { display: flex; flex-direction: column; gap: var(--sp-5); }
.menu-mobile__link {
  font-size: var(--fs-h3); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-heading);
  color: var(--ink); text-decoration: none;
}
.menu-mobile__link:hover { color: var(--accent-text); }

/* =========================================================
   5. SWITCHER PRIVÉ / ENTREPRISE (designer §3)
   ========================================================= */

.switcher {
  position: relative;
  display: grid; grid-template-columns: 1fr 1fr;
  background: #F0F2F6;
  border-radius: var(--r-pill);
  padding: 4px;
  height: 40px;
}
/* Indicateur actif : pilule qui GLISSE (translate, pas left) */
.switcher::before {
  content: "";
  position: absolute;
  top: 4px; left: 4px; bottom: 4px;
  width: calc(50% - 4px);
  background: var(--grad-cta);
  border-radius: var(--r-pill);
  transition: translate var(--t-med) var(--ease);
}
.switcher[data-actif="pro"]::before { translate: 100% 0; }

.switcher__seg {
  position: relative; z-index: 1;
  border: 0; background: transparent; cursor: pointer;
  font-family: var(--font);
  font-size: var(--fs-small); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  color: var(--ink);
  padding-inline: var(--sp-4);
  border-radius: var(--r-pill);
  transition: color var(--t-fast) var(--ease);
}
.switcher__seg:hover[aria-checked="false"] { background: rgb(23 26 33 / .06); }
.switcher__seg[aria-checked="true"] { color: #FFFFFF; font-weight: var(--fw-bold); }
.switcher__seg:focus-visible { box-shadow: var(--focus-ring); outline: none; }
.switcher__label-short { display: none; }

/* Version XL dans le hero : fond légèrement translucide sur le sombre */
.switcher--xl {
  height: 48px;
  max-width: 22rem;
  background: rgb(255 255 255 / .92);
  margin-top: var(--sp-6);
}

/* v2 §1.4 — version compacte du header : 32px, tout à droite */
.switcher--compact {
  height: 32px;
  padding: 3px;
  background: #F4F6F9;
  border: 1px solid var(--line);
}
.switcher--compact::before {
  top: 3px; left: 3px; bottom: 3px;
  width: calc(50% - 3px);
}
.switcher--compact .switcher__seg {
  height: 26px;
  font-size: var(--fs-tiny);
  padding-inline: var(--sp-3);
  display: inline-flex; align-items: center; justify-content: center;
}
.switcher--compact .switcher__seg[aria-checked="true"] { font-weight: var(--fw-semibold); }
/* Labels courts PRIVÉ / PRO sous 1280px (v2 §1.4) */
@media (max-width: 1279px) {
  .switcher--compact .switcher__label-long { display: none; }
  .switcher--compact .switcher__label-short { display: inline; }
}

/* =========================================================
   6. HERO v2 — carte encapsulée + aurora conique (spec v2 §2)
   ========================================================= */

.hero {
  position: relative;
  overflow: clip;                /* l'animation vit DANS le cadre arrondi */
  isolation: isolate;
  background: var(--hero-bg);
  color: var(--hero-ink);
  /* Carte insérée dans le conteneur, plus un bandeau pleine largeur */
  width: min(var(--container), 100% - 2 * var(--container-pad));
  margin-inline: auto;
  margin-top: var(--sp-4);
  border-radius: var(--r-hero) var(--r-hero) var(--r-hero) 0.5rem; /* coin bas-gauche coupé */
  min-height: clamp(30rem, 72vh, 46rem);
  padding: clamp(3rem, 8vw, 5rem) clamp(1.5rem, 5vw, 4rem);
  display: flex; align-items: center;
}

/* Aurora (spec 17 §2.3) : rotation 32 s + dérive 13 s non harmonique. La rotation
   seule produisait un déplacement nul au centre du hero — là où vit le texte —
   et le flou de 96 px effaçait tout contour à suivre : l'effet était imperceptible
   (Δ 2,30/255 sur 1 s). Rotation accélérée + translation réelle + flou plus fin. */
.hero::before {
  content: "";
  position: absolute; z-index: -2;
  left: 50%; top: 50%;
  translate: -50% -50%;
  width: max(165%, 68rem); aspect-ratio: 1;
  background: conic-gradient(from 215deg,
      var(--hero-bg) 0deg,
      var(--hero-blob-a) 65deg,
      var(--hero-blob-c) 130deg,
      var(--hero-bg) 200deg,
      var(--hero-blob-b) 265deg,
      var(--hero-bg) 330deg);
  filter: blur(clamp(36px, 4vw, 56px)) saturate(1.3);
  opacity: .72;
  animation: aurora-spin 32s linear infinite,
             aurora-drift 13s linear infinite alternate;
  will-change: transform;
}
@keyframes aurora-spin { to { rotate: 360deg; } }
/* Dérive : ±6 % / ±4 % de la largeur du disque (±114 / ±76 px à 1440).
   Couverture vérifiée : 950 − 137 = 813 px > 661 px de demi-diagonale du hero. */
@keyframes aurora-drift {
  from { translate: calc(-50% - 6%) calc(-50% + 4%); }
  to   { translate: calc(-50% + 6%) calc(-50% - 4%); }
}

/* Grain anti-banding (feTurbulence inline, recommandé v2 §2.2) */
.hero__grain {
  position: absolute; inset: 0; z-index: -1;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: .05;
  pointer-events: none;
}

/* Scrim OBLIGATOIRE (inchangé v1) : contraste du texte garanti */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg,
      rgb(0 0 0 / .10), rgb(0 0 0 / .38) 45%, rgb(0 0 0 / .55));
}

.hero__content {
  position: relative; z-index: 1;
  width: 100%;
}
/* v5 SEO (07-seo.md §2.2 pt 7) : le hero pro porte désormais un h2 pour qu'il
   n'y ait qu'un seul h1 par page. Rendu visuel strictement identique. */
.hero__content h1,
.hero__content h2 { color: var(--hero-ink); max-width: 18ch; }
.hero__content h2 {
  font-size: var(--fs-hero); font-weight: var(--fw-bold);
  letter-spacing: var(--ls-hero); line-height: var(--lh-tight);
}
.hero__sub {
  color: var(--hero-ink-soft);
  font-size: var(--fs-h4);
  font-weight: var(--fw-light);
  max-width: 46ch;
  margin: 0 0 var(--sp-6);
}
/* CTA de hero (spec 17 §4.3) : les deux univers permutent à la même position,
   leurs boutons doivent donc avoir la même boîte. min-width en token, jamais
   width : un libellé plus long élargit le bouton au lieu d'être tronqué. */
.hero__ctas {
  display: flex; flex-wrap: wrap;
  gap: var(--sp-4);
  margin-block: var(--sp-6) 0;            /* 32 px sous le sous-titre, cf. §3 */
}
.hero__ctas .btn { min-width: var(--btn-w-hero); }
@media (max-width: 479px) {
  .hero__ctas .btn { min-width: 0; width: 100%; }   /* empilés, égaux par construction */
}

/* ---- Hero standard des 7 pages hors accueil (spec 17 §1.3) ----
   Hauteur en rem, jamais en vh : une hauteur qui dépend de la fenêtre du
   visiteur n'est pas une valeur de design system. 34ch / 68ch sont les deux
   plus petites largeurs qui ramènent les 7 pages à 288 px exactement. */
.hero.hero--page {
  /* spec 17 invariant §5.7 : sélecteur DOUBLE obligatoire. Le bloc mobile
     « v2 §2.1 » (§15.1) porte .hero { min-height: clamp(26rem,66vh,40rem) } et
     est écrit PLUS BAS dans la feuille : à spécificité égale (0,1,0) il
     l'emporterait et le hero mobile retomberait à 557 px. C'est précisément
     l'erreur qui a rendu .hero--legal inopérant. */
  min-height: var(--hero-h-page);
  padding-block: var(--sp-7);                 /* 48 px */
}
.hero--page .hero__content h1,
.hero--page .hero__content h2 {
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  max-width: 34ch;
}
.hero--page .hero__sub {
  font-size: var(--fs-body);
  max-width: 68ch;
  margin-bottom: 0;
}
@media (max-width: 767px) {
  .hero.hero--page {
    min-height: var(--hero-h-page-mobile);
    padding-block: var(--sp-6);               /* 32 px */
  }
}

/* =========================================================
   7. BOUTONS (designer §4.4)
   ========================================================= */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 48px; padding-inline: var(--sp-5);
  min-width: 44px;
  border: 0; border-radius: var(--r-pill);
  font-family: var(--font);
  font-size: var(--fs-small); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  text-decoration: none; cursor: pointer;
  /* audit 26 §2 : plus aucun `filter` animé. Le voile de survol est porté par
     ::before en opacity (compositable), le reste est translate. */
  position: relative; z-index: 0;
  transition: translate var(--t-fast) var(--ease),
              background-color var(--t-fast) var(--ease);
}
/* Voile de survol des boutons pleins : opacity uniquement (audit 26 §2).
   Il remplace `filter: brightness()` à rendu équivalent (6 % / 8 % de noir). */
.btn--primary::before,
.btn--on-dark::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  background: #000;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
  pointer-events: none;
}
.btn--primary:hover::before { opacity: .06; }
.btn--on-dark:hover::before { opacity: .08; }
.btn:focus-visible { box-shadow: var(--focus-ring); outline: none; }
/* spec 17 §4.5 : .btn--s supprimé (1 seul usage). Une seule hauteur : 48 px. */
.btn--block { width: 100%; }

.btn--primary { background: var(--grad-cta); color: #FFFFFF; }
.btn--primary:hover { translate: 0 -1px; }

.btn--secondary {
  background: transparent; color: var(--btn2-text);
  border: 1.5px solid var(--btn2-border);
}
.btn--secondary:hover { background: var(--chip-bg); }

/* Sur fond sombre (hero) : bouton blanc, texte de la couleur du fond */
.btn--on-dark { background: #FFFFFF; color: var(--hero-bg); }
/* .btn--on-dark n'a pas de règle :hover propre : le voile ::before suffit,
   rendu identique à l'ancien filter: brightness(.92). */

/* Ghost sombre (2e CTA du hero) */
.btn--ghost-dark {
  background: transparent; color: #FFFFFF;
  border: 1px solid rgb(255 255 255 / .5);
  transition: border-color var(--t-fast) var(--ease);
}
.btn--ghost-dark:hover { border-color: #FFFFFF; }

/* ---- Groupe de CTA (spec 17 §3.3) ----
   Tout bouton en flux vertical vit dans un .cta-group, même seul. C'est la
   règle UNIQUE de marge autour des boutons : 32 px au-dessus, 16 px entre les
   éléments du groupe, 32 px en dessous. Interdit de poser une marge sur un
   .btn ou d'ajouter une rustine du type « X + .btn { margin-top: … } ». */
.cta-group {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-4);                       /* 16 px : bouton↔bouton ET bouton↔mention */
  margin-block: var(--sp-6);              /* 32 px au-dessus et en dessous */
}
.cta-group:last-child { margin-block-end: 0; }
.cta-group__mention {
  flex-basis: 100%;                       /* la mention prend sa propre ligne */
  margin: 0;
  max-width: var(--measure-body);         /* v15 : mesurée à 88 caractères sur support.html */
  font-size: var(--fs-small);
  color: var(--ink-muted);
}
.cta-group .btn--block { flex: 1 0 100%; }  /* bouton pleine largeur (cartes d'abonnement) */

/* =========================================================
   8. SECTIONS, GRILLES, FIL MOULINET
   ========================================================= */

.section { padding-block: var(--section-y); background: var(--paper); }
.section--tint { background: var(--surface-tint); }
/* v10 : une ancre visée depuis une AUTRE page (#bronze … #platinium, #tarifs,
   #prix-fixes) arrivait sous l'en-tête collant. Même offset que les ancres de
   cg.html (§20.x, .legal [id]) : header + 24 px de respiration. */
.section[id], .pricing__card[id] { scroll-margin-top: var(--scroll-offset); }
/* v15 (docs/45 §4) — le sous-titre de section n'avait AUCUNE largeur maximale :
   il occupait les 1088 px du conteneur, soit 139 à 148 caractères par ligne
   mesurés sur gaming, vente et cybersécurité. C'était le pire défaut de
   lisibilité du site. Il rentre dans la mesure commune. */
.section__sous-titre { color: var(--ink-muted); margin: 0 0 var(--sp-6); max-width: var(--measure-body); }
.section__texte { max-width: var(--measure-body); }   /* 65ch valait 80 à 90 caractères */
/* Filet de sécurité : un paragraphe posé DIRECTEMENT dans le conteneur d'une
   section, sans classe, occupait toute la largeur (150 caractères sur
   404.html). La mesure s'applique donc aussi par la structure, pour que la
   règle tienne sans dépendre d'une classe posée à la main dans le HTML. */
.section > .container > p { max-width: var(--measure-body); }

.grid { display: grid; gap: var(--sp-5); margin-top: var(--sp-7); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }

/* Fil moulinet (signature n°1) : 4 capsules, proportions 3/2/2/3 */
.fil {
  display: flex; gap: var(--sp-2);
  width: 96px; height: 6px;
  margin-bottom: var(--sp-4);
}
.fil i { height: 6px; border-radius: var(--r-pill); }
.fil i:nth-child(1) { flex: 3; background: var(--fil-1); }
.fil i:nth-child(2) { flex: 2; background: var(--fil-2); }
.fil i:nth-child(3) { flex: 2; background: var(--fil-3); }
.fil i:nth-child(4) { flex: 3; background: var(--fil-4); }
.fil--full { width: 100%; margin: 0; }

/* Univers inactif : caché (un seul h1 visible à la fois) */
[data-theme="prive"] .univers[data-univers-panel="pro"],
[data-theme="pro"] .univers[data-univers-panel="prive"] { display: none; }

/* =========================================================
   9. CARTES SERVICE (designer §4.2)
   ========================================================= */

/* v15 (docs/45 §6) — l'OMBRE DE REPOS est supprimée. Une carte blanche sur un
   fond blanc portait à la fois un filet gris de 1 px ET un halo d'ombre : deux
   délimitations pour une seule frontière, et un gris de plus dans la page.
   Le filet suffit ; l'ombre reste, mais seulement au survol (::before), où
   elle dit quelque chose. Aucun pixel de hauteur n'est ajouté ni retiré. */
.card {
  background: var(--paper);
  border: 1px solid var(--line);
  padding: var(--sp-6);
  /* Radius signature : 3 coins --r-lg, 1 coin coupé --r-cut */
  border-radius: var(--r-lg) var(--r-lg) var(--r-lg) var(--r-cut);
  /* audit 26 §2 : box-shadow n'est plus transitionné (propriété peinte à
     chaque frame sur toute la surface de la carte). L'ombre de survol est
     posée sur ::before et révélée en opacity — composité, coût nul. */
  position: relative; z-index: 0;
  transition: translate var(--t-med) var(--ease);
  display: flex; flex-direction: column;
  /* LOT-DESIGN-20 — sans cette ligne, la carte à média débordait de 15 px à
     320 px dans l'univers pro (accueil). Cause : .card__media est en plein
     format, `width: calc(100% + 2 * var(--sp-6))`, ce qui porte le contenu
     minimal de la carte à 319 px ; un enfant de grille a `min-width: auto`
     par défaut et refuse alors de descendre sous cette valeur, au lieu de
     suivre sa colonne 1fr de 288 px. C'est le seul débordement horizontal
     trouvé sur 19 pages × 7 largeurs × 2 univers. */
  min-width: 0;
}
.card::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  box-shadow: var(--shadow-hover);
  opacity: 0;
  transition: opacity var(--t-med) var(--ease);
  pointer-events: none;
}
/* Rotation du coin coupé, comme les pales du moulinet */
.cards .card:nth-child(3n+2) { border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg); }
.cards .card:nth-child(3n)   { border-radius: var(--r-cut) var(--r-lg) var(--r-lg) var(--r-lg); }
.card:hover { translate: 0 -4px; }
.card:hover::before { opacity: 1; }

.card__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px;
  background: var(--chip-bg); color: var(--chip-text);
  border-radius: var(--r-md);
  margin-bottom: var(--sp-4);
  transition: rotate var(--t-fast) var(--ease);
}
.card__icon svg { width: 24px; height: 24px; }
.card:hover .card__icon { rotate: 8deg; }   /* le pivot, en micro (signature n°3) */

/* Le h3 de carte suit la règle générale (12 px) : l'exception à 8 px est levée. */
.card p { color: var(--ink-muted); margin: 0 0 var(--sp-4); }

.card__link {
  margin-top: auto;
  color: var(--link);
  font-weight: var(--fw-medium);
  text-decoration: none;
}
.card__link span { display: inline-block; transition: translate var(--t-fast) var(--ease); }
.card__link:hover span { translate: 4px 0; }
.card__link:hover { text-decoration: underline; }

/* Carte sans photo dans une rangée de cartes média : marges auto en haut de
   l'icône ET du lien → le bloc icône+texte se centre dans l'espace libre,
   le lien reste ancré en bas. Cartes empilées (mobile) : pas d'espace libre,
   les marges auto valent 0 → aucun effet. */
.cards .card:not(.card--media) .card__icon { margin-top: auto; }

/* v2 §3.1 — carte média : photo en tête, pleine largeur (compense le padding) */
.card__media {
  height: auto;                  /* neutralise l'attribut height (anti-CLS) */
  aspect-ratio: 16 / 10;
  object-fit: cover;
  margin: calc(-1 * var(--sp-6)) calc(-1 * var(--sp-6)) var(--sp-5);
  width: calc(100% + 2 * var(--sp-6));
  max-width: none;
  /* Coins hauts = coins hauts de la carte porteuse (bordure 1px déduite) */
  border-radius: calc(var(--r-lg) - 1px) calc(var(--r-lg) - 1px) 0 0;
}
/* Quand la rotation :nth-child place le coin coupé en haut à gauche */
.cards .card:nth-child(3n) .card__media {
  border-radius: var(--r-cut) calc(var(--r-lg) - 1px) 0 0;
}
.card__media--technicien { object-position: 50% 32%; } /* cadre technicien + rack */

/* Prestations à prix fixes (liste compacte) */
.prix-fixes {
  list-style: none; margin: var(--sp-7) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-4);
}
/* v15 : rembourrage 24 > gouttière 16 (docs/45 §2). Auparavant les deux
   valaient 16 : la vignette était aussi serrée dedans que dehors. */
.prix-fixes li {
  display: flex; flex-direction: column; gap: var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--sp-5);
}
.prix-fixes .heading { font-size: var(--fs-small); margin: 0; }
.prix-fixes span { color: var(--accent-text); font-weight: var(--fw-semibold); }
/* v10 : renvoi vers le détail des prestations (services.html), même registre
   typographique que le renvoi NAP de .contact-adresse. */
.prix-fixes__lien { font-size: var(--fs-small); margin: var(--sp-4) 0 0; }
.prix-fixes__lien a { color: var(--link); text-decoration: underline; text-underline-offset: 3px; }
.prix-fixes__lien a span { display: inline-block; transition: translate var(--t-fast) var(--ease); }
.prix-fixes__lien a:hover span { translate: 4px 0; }

/* =========================================================
   10. PREUVE SOCIALE (chiffres + encart)
   ========================================================= */

/* v2 §3.2 — split proximité : texte à gauche, figure montagnes à droite */
.split {
  display: grid;
  grid-template-areas: "haut" "figure" "bas"; /* mobile : figure entre texte et suite */
  gap: var(--sp-6);
}
.split__haut { grid-area: haut; }
.split__haut .section__texte,
.split__haut p:last-child { margin-bottom: 0; }
.split__bas { grid-area: bas; }
.split__bas .chiffres { margin-top: 0; }
.split__bas .encart { margin-top: 0; }
.split__figure {
  grid-area: figure;
  position: relative;
  margin: 0;
}
.split__figure img {
  width: 100%;
  height: auto;                          /* neutralise l'attribut height (anti-CLS) */
  aspect-ratio: 16 / 10;                 /* mobile : économie de hauteur */
  object-fit: cover;
  /* Radius signature, coin coupé bas-droit */
  border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg);
}
/* Voile de l'univers actif (seul overlay photo du site) */
.split__figure::after {
  content: ""; position: absolute; inset: 0;
  background: var(--img-wash);
  border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg);
  pointer-events: none;
}
@media (min-width: 1024px) {
  .split {
    grid-template-columns: 7fr 5fr;
    grid-template-areas: "haut figure" "bas figure";
    gap: var(--sp-5) var(--sp-7);
    align-items: center;
  }
  .split__figure img { aspect-ratio: 4 / 3; }
}

/* ---- 10.1 EMPLACEMENT PHOTO RÉSERVÉ (a-propos.html, arbitrage client v11 :
   « le client n'a pas encore fourni de photo de l'équipe → prévoir
   l'emplacement, comme pour les logos partenaires »).
   Même principe que la zone partenaires du pied de page (audit 26 §4.3) :
   - rien n'est fabriqué, rien n'est emprunté à une banque d'images : la plaque
     porte le NOM et l'ADRESSE de la maison, composés dans la typo du site.
     C'est une mention nominative, licite, qui a l'air voulue plutôt que
     manquante — exactement comme les plaques ESET / Infomaniak / Acer ;
   - la plaque occupe EXACTEMENT la boîte de la future photo (mêmes proportions
     que .split__figure img : 16/10 puis 4/3 dès 1024 px), donc le jour où la
     photo arrive, aucun décalage de mise en page ;
   - remplacement = décommenter la balise <img> et supprimer le <p>, rien
     d'autre. Mode d'emploi : site/assets/img/equipe/LISEZMOI.txt. */
.figure-reserve {
  display: grid; place-items: center;
  aspect-ratio: 16 / 10;
  padding: var(--sp-6);
  text-align: center;
  background: var(--surface-tint);
  border: 1px solid var(--line);
  /* Radius signature, même coin coupé que .split__figure img */
  border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg);
}
/* Le voile d'univers de .split__figure n'a pas lieu d'être ici : il n'y a
   aucune image à teinter, et il recouvrirait la mention. */
.figure-reserve::after { content: none; }
.figure-reserve__nom {
  margin: 0;
  display: grid; gap: var(--sp-2);
  font-size: var(--fs-small); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  color: var(--ink);
}
.figure-reserve__nom span {
  font-weight: var(--fw-regular); letter-spacing: normal;
  text-transform: none; color: var(--ink-muted);
}
@media (min-width: 1024px) {
  .figure-reserve { aspect-ratio: 4 / 3; }
}

/* v8 §1.2 — variante SANS figure (gaming, section « Moins cher en ligne, et
   après ? »). Sans image, la colonne de droite du split resterait vide sur
   grand écran : les chiffres et l'encart d'appel viennent l'occuper.
   Mobile : empilement inchangé (haut puis bas). */
@media (min-width: 1024px) {
  .split--sans-figure {
    grid-template-areas: "haut bas";
    align-items: start;
  }
}

.chiffres { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-block: var(--sp-5); }
.chiffres__item {
  margin: 0;
  background: var(--chip-bg); color: var(--chip-text);
  font-size: var(--fs-small);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--r-pill);
}
.encart {
  margin-top: var(--sp-6);
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: var(--r-lg) var(--r-lg) var(--r-lg) var(--r-cut);
  padding: var(--sp-6);
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4);
  justify-content: space-between;
}
.encart__titre { margin: 0; font-size: var(--fs-h4); }
.encart p { max-width: var(--measure-body); }   /* v15 : 1022 px mesurés sur a-propos.html */
/* v5 §2.2 : le téléphone de l'encart passe en bouton secondaire (registre ACTION) */
.encart__appel { gap: var(--sp-2); }   /* bouton secondaire v1 §4.4, inchangé par ailleurs */
.encart__appel svg { width: 20px; height: 20px; }

/* =========================================================
   11. CARTES ABONNEMENT (designer §4.3)
   ========================================================= */

.pricing__card {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--line);
  /* v15 (docs/45 §6) : ombre de repos supprimée, comme sur .card. */
  padding: var(--sp-6);
  display: flex; flex-direction: column;
  z-index: 0;                                   /* contexte d'empilement pour ::before */
  transition: translate var(--t-med) var(--ease);   /* audit 26 §2, cf. .card */
}
.pricing__card::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  box-shadow: var(--shadow-hover);
  opacity: 0;
  transition: opacity var(--t-med) var(--ease);
  pointer-events: none;
}
/* Les 4 coins coupés forment le moulinet complet */
.pricing .pricing__card:nth-child(1) { border-radius: var(--r-lg) var(--r-lg) var(--r-lg) var(--r-cut); }
.pricing .pricing__card:nth-child(2) { border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg); }
.pricing .pricing__card:nth-child(3) { border-radius: var(--r-lg) var(--r-cut) var(--r-lg) var(--r-lg); }
.pricing .pricing__card:nth-child(4) { border-radius: var(--r-cut) var(--r-lg) var(--r-lg) var(--r-lg); }
.pricing__card:hover { translate: 0 -4px; }
.pricing__card:hover::before { opacity: 1; }

.pricing__card--reco { border: 2px solid var(--accent); }
.pricing__badge {
  position: absolute; top: 0; left: 50%;
  translate: -50% -50%;
  background: var(--chip-bg); color: var(--chip-text);
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  padding: var(--sp-1) var(--sp-4);
  border-radius: var(--r-pill);
  white-space: nowrap;
}

.pricing__prix {
  font-size: var(--fs-price); font-weight: var(--fw-bold);
  line-height: var(--lh-tight); color: var(--ink);
  margin: 0;
}
.pricing__prix span { font-size: var(--fs-small); font-weight: var(--fw-regular); color: var(--ink-muted); }
.pricing__mensuel { font-size: var(--fs-small); color: var(--ink-muted); margin: var(--sp-1) 0 0; }

/* v5 §1.2 : le nom de formule descend en --fs-h4 (le prix est l'ancre de lecture) */
.pricing__card h3 { font-size: var(--fs-h4); margin: 0 0 var(--sp-3); }

/* v5 §1.3 — matrice inclus / non inclus.
   L'état passe par 4 canaux, dont 3 non chromatiques : forme du glyphe
   (coche vs tiret), remplissage de la pastille, graisse du libellé, texte
   lecteur d'écran. Interdits ici : opacity, line-through, vert/rouge. */
.pricing__inclus {
  list-style: none;
  margin: var(--sp-5) 0 0;              /* spec 17 §3.5 : les 32 px viennent de .cta-group */
  padding: var(--sp-5) 0 0;
  border-top: 1px solid var(--line);
  display: grid; gap: var(--sp-4);   /* v15 : 12 → 16, l'interligne d'une ligne vaut 22,4 px */
}
.pricing__inclus li {
  display: grid; grid-template-columns: 20px 1fr;
  align-items: start; gap: var(--sp-3);
  font-size: var(--fs-small); line-height: var(--lh-body);
  margin: 0;
}
.pricing__puce {
  width: 20px; height: 20px;
  border-radius: var(--r-pill);
  display: grid; place-items: center;
  margin-top: 1px;                 /* calage optique sur une ligne de 22.4px */
}
.pricing__puce svg { width: 12px; height: 12px; display: block; }
.is-in .pricing__puce  { background: var(--accent); color: #FFFFFF; }
.is-in  { color: var(--ink); font-weight: var(--fw-medium); }
.is-out .pricing__puce { background: var(--line); color: var(--ink-muted); }
.is-out { color: var(--ink-muted); font-weight: var(--fw-regular); }

/* CTA collés en bas des 4 cartes + texte sur une seule ligne (§1.6) */
/* v10 : à quatre colonnes, la carte n'offre que 188 px utiles. Un libellé
   nommant la formule (« Choisir Platinium ») débordait de la boîte de 48 px.
   Le CTA de carte d'abonnement passe donc au corps d'étiquette (--fs-tiny),
   comme le badge et l'eyebrow. La hauteur de bouton, elle, ne bouge pas. */
.pricing .btn--block {
  margin-top: auto;
  padding-inline: var(--sp-3);
  font-size: var(--fs-tiny);
}
/* La carte recommandée porte 2px de bordure : on retire 1px de padding pour que
   les lignes de la matrice restent alignées d'une carte à l'autre (§1.5). */
.pricing__card--reco { padding: calc(var(--sp-6) - 1px); }

.pricing__mention { margin-top: var(--sp-6); color: var(--ink-muted); font-size: var(--fs-small); }

/* =========================================================
   12. CONTACT
   ========================================================= */

/* v5 §2.3 : les lignes .contact / .contact__ligne (adresse + horaires + zone,
   doublon exact du footer) sont supprimées de la home au profit de 3 tuiles
   d'action. Le composant .card est réutilisé tel quel, coin coupé compris. */
.contact-actions {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-5); margin-top: var(--sp-7);
}
/* v15 : rembourrage 32 > gouttière 24 (docs/45 §2) ; les deux valaient 24. */
.contact-tuile { position: relative; padding: var(--sp-6); }
.contact-tuile__icone {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  background: var(--chip-bg); color: var(--chip-text);
  border-radius: var(--r-md);
  margin-bottom: var(--sp-4);
}
.contact-tuile__icone svg { width: 20px; height: 20px; }
.contact-tuile h3 { font-size: var(--fs-h4); }   /* v15 : espace hérité de la règle h3 (12 px) */
.contact-tuile__valeur {
  margin: 0;
  font-size: var(--fs-body); font-weight: var(--fw-semibold);
  color: var(--link);
}
.contact-tuile__valeur a { text-decoration: none; }
/* Toute la tuile est cliquable : une seule cible tactile, un seul lien a11y */
.contact-tuile__valeur a::after { content: ""; position: absolute; inset: 0; }
.contact-tuile__valeur a:hover { text-decoration: underline; }
.contact-tuile__valeur span { display: inline-block; transition: translate var(--t-fast) var(--ease); }
.contact-tuile:hover .contact-tuile__valeur span { translate: 4px 0; }

/* =========================================================
   13. FOOTER (designer §4.6)
   ========================================================= */

.footer { background: var(--dark); color: var(--on-dark); }
.footer a { color: var(--on-dark-muted); text-decoration: none; transition: color var(--t-fast) var(--ease); }
.footer a:hover { color: var(--on-dark); }
.footer__grid {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-6);
  padding-block: var(--sp-8);
}
.footer__col p { margin: 0 0 var(--sp-2); color: var(--on-dark-muted); font-size: var(--fs-small); }
.footer__baseline { margin-top: var(--sp-4); }
/* Le titre de colonne est passé de <h4> à <h3> (Lighthouse "heading-order" :
   les pages légales enchaînaient un h2 d'article puis un h4 de footer, soit un
   niveau sauté). font-size explicite : le rendu visuel reste rigoureusement
   identique à l'ancien h4, seule la sémantique change. */
.footer__titre { color: var(--footer-titre); margin-bottom: var(--sp-3); font-size: var(--fs-h4); }
/* doc 45 §8.4 : la mention de pied est une ÉNUMÉRATION (© · pages · crédits),
   pas une phrase. En <ul>, elle se replie élément par élément au lieu de tenir
   sur 192 caractères d'un seul trait, et le séparateur « · » redevient de la
   présentation : il est posé en ::before entre deux éléments, donc jamais lu
   par un lecteur d'écran et jamais copié avec le texte. */
.footer__mention {
  font-size: var(--fs-tiny); color: var(--on-dark-muted);
  padding-block: 0 var(--sp-6); margin: 0 auto;
  list-style: none;
  display: flex; flex-wrap: wrap; align-items: baseline;
  column-gap: var(--sp-2); row-gap: var(--sp-1);
}
.footer__mention li { display: flex; align-items: center; gap: var(--sp-2); }
.footer__mention li + li::before { content: "·"; color: var(--on-dark-muted); }
/* LOT-DESIGN-20 — SEULE violation relevée par axe-core sur les 19 pages
   (target-size, WCAG 2.2 AA 2.5.8, 114 nœuds) : ces liens faisaient 19,2 px
   de haut, sous le minimum de 24. Le rembourrage vertical les porte à 35 px
   sans changer leur apparence ; sous 1024 px, où l'on est au doigt, ils
   passent à 44. Le row-gap tombe à 0 : c'est le rembourrage qui espace, sinon
   on compte deux fois. */
.footer__mention a { display: inline-flex; align-items: center; padding-block: var(--sp-2); }
@media (max-width: 1023px) {
  /* Le point médian appartient au <li> : quand la ligne passe, il part avec
     son lien et la ligne suivante COMMENCE par un point. Sous 1024 px la
     ligne se plie trois ou quatre fois — on retire donc les points et on
     laisse l'espacement séparer, ce que la hauteur de 44 px permet. */
  .footer__mention { row-gap: 0; column-gap: var(--sp-5); }
  .footer__mention li + li::before { content: none; }
  .footer__mention a { min-height: 2.75rem; }
}

/* ---- 13.1 ZONE PARTENAIRES (demande v11 §9 / audit 26 §4 / docs/62) -------
   LOT-DESIGN-20 — la zone accueille désormais DEUX REGISTRES, et c'est tout
   le problème de conception :

   · REGISTRE 1, les plaques (`.partenaires__liste`). Trois partenariats
     établis — ESET, Infomaniak, Acer (docs/60 §4.2). Deux d'entre eux ont
     livré un BADGE OFFICIEL, le troisième n'a pas encore son fichier de
     portail. Un badge en image et une plaque composée dans la typo du site
     doivent donc cohabiter sur la même rangée sans que le mélange se voie.
   · REGISTRE 2, la mention de revente (`.partenaires-revente`). Microsoft
     n'a aucun logo à concéder à un CSP (docs/60 §4.2, Logo Builder) et n'est
     pas « partenaire » au sens de son programme. Une plaque typographique
     alignée avec deux badges suggérerait une désignation qui n'existe pas
     (art. 3 al. 1 let. c LCD). La mention sort donc de la rangée ET du titre
     « Nos partenaires » : c'est une PHRASE, hors <section>, qui se suffit.

   Ce qui fait tenir le mélange badge / typographie, en trois décisions :

   1. LA PLAQUE EST LE COMPOSANT, PAS LE LOGO. Fond blanc, hauteur fixe,
      rayon identique. C'est elle qui donne le rythme ; ce qu'elle contient
      est libre. Un badge et deux lignes de texte y ont le même poids.
   2. MÊME STRUCTURE INTERNE : marque au-dessus, statut en dessous. Les deux
      badges livrés sont des verrouillages « marque + statut » (« ESET Bronze
      Partner », « infomaniak Partners »). La plaque Acer reprend cette
      structure — « ACER » en corps de marque, « Partenaire » en statut. Le
      parallèle sémantique fait passer la différence de rendu.
   3. AUCUN FILTRE, AUCUNE RECOLORATION, AUCUNE DÉFORMATION. Les chartes ESET
      et Acer l'interdisent ; le fond blanc est le seul sur lequel n'importe
      quel logo reste conforme (le pied de page est sombre, #14161C).

   Hauteur des badges : 3 rem (48 px) et non plus 1.75 rem. 28 px suffisait à
   un logotype nu ; ici le mot de statut occupe 21 % de la hauteur du badge
   ESET — à 28 px il serait rendu à 5,8 px, illisible. À 48 px il fait 10 px.
   La plaque suit à 5 rem pour garder le rapport dedans/dehors de docs/45. */
.partenaires {
  border-top: 1px solid rgb(255 255 255 / .10);
  padding-block: var(--sp-6) 0;
}
.partenaires__titre {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  color: var(--on-dark-muted);
}
.partenaires__liste {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
}
.partenaires__item {
  flex: 0 1 auto;
  display: flex; align-items: center; justify-content: center;
  min-width: 8.75rem;                      /* 140 px : la plaque la plus courte */
  height: var(--partner-plate-h);
  padding-inline: var(--sp-5);
  background: #FFFFFF;
  border-radius: var(--r-md);
}
/* Badge officiel remis par la marque. Hauteur normalisée, largeur libre :
   c'est la hauteur, pas la largeur, qui donne un poids visuel comparable à
   des badges de proportions différentes (ESET 2,18:1 · Infomaniak 2,76:1). */
.partenaires__logo {
  height: var(--partner-logo-h);
  width: auto; max-width: 100%;
  object-fit: contain;
}
/* Plaque composée : la marque nommée dans la typographie du site, plus son
   statut. Ce n'est pas un logo dessiné — c'est une mention nominative,
   licite (docs/60 §4.3), et remplaçable par le badge officiel du portail
   sans toucher au CSS. Aucune couleur de marque n'est empruntée. */
.partenaires__plaque {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-1);
  text-align: center;
}
.partenaires__nom {
  font-size: 1.375rem; line-height: var(--lh-tight);
  font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-heading);
  color: var(--ink);
  white-space: nowrap;
}
.partenaires__statut {
  font-size: var(--fs-tiny); line-height: 1.2;
  font-weight: var(--fw-medium);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  color: var(--ink-muted);
  white-space: nowrap;
}
/* Registre 2 — revente Microsoft. Hors <section aria-labelledby>, hors
   rangée : le titre « Nos partenaires » ne la gouverne pas, et elle ne peut
   pas se lire comme un badge. Formulation verrouillée par docs/60 §4.2. */
.partenaires-revente {
  margin: var(--sp-5) 0 var(--sp-6);
  max-width: var(--measure-body);
  text-wrap: pretty;
  font-size: var(--fs-tiny); line-height: var(--lh-body);
  color: var(--on-dark-muted);
}
@media (max-width: 767px) {
  .partenaires__liste { gap: var(--sp-3); }
  .partenaires__item { padding-inline: var(--sp-4); min-width: 0; }
}

/* =========================================================
   14. RESPONSIVE (mobile-first : ces règles réduisent le desktop)
   ========================================================= */

@media (max-width: 1023px) {
  /* v2 §1.5 : le burger monte à 1024px (menu plus fourni).
     Restent visibles : logo-icon 40px | switcher compact | burger. */
  .header__inner {
    height: 64px;
    display: flex; gap: var(--sp-3);
  }
  .header__logo-full { display: none; }
  .header__logo-icon { display: block; }
  /* LOT-DESIGN-20 — le lien du logo mesurait 40x40 (la taille de l'icône).
     La zone cliquable passe à 44x44, l'icône reste à 40 et reste calée à
     gauche : rien ne bouge à l'écran, la cible grandit. */
  .header__logo { min-width: 44px; min-height: 44px; justify-content: flex-start; }
  .header__nav { display: none; }          /* remplacée par le burger */
  .header__right { margin-left: auto; }
  .burger { display: flex; }

  .grid--4 { grid-template-columns: repeat(2, 1fr); } /* pricing 2×2 tablette */
  .grid--3 { grid-template-columns: repeat(2, 1fr); }
  .prix-fixes { grid-template-columns: repeat(2, 1fr); }
  .footer__grid { grid-template-columns: repeat(2, 1fr); }

  /* v5 §2.3 : 2 tuiles d'action puis la 3ᵉ sur toute la largeur */
  .contact-actions { grid-template-columns: repeat(2, 1fr); }
  .contact-actions .contact-tuile:nth-child(3) { grid-column: 1 / -1; }
}

/* v5 §1.6 : entre 1024 et 1199px, padding de carte réduit pour que
   « Logiciel bureautique » tienne sur une ligne (esthétique seule). */
@media (min-width: 1024px) and (max-width: 1199px) {
  .pricing__card { padding: var(--sp-5); }
  .pricing__card--reco { padding: calc(var(--sp-5) - 1px); }
}

@media (max-width: 767px) {
  /* v2 §2.1 : carte hero plus compacte sur mobile */
  .hero {
    min-height: clamp(26rem, 66vh, 40rem);
    border-radius: 1.5rem 1.5rem 1.5rem 0.375rem; /* coin coupé 6px */
  }

  .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }
  .prix-fixes { grid-template-columns: 1fr; }
  .footer__grid { grid-template-columns: 1fr; }
  /* v5 §2.3 : tuiles d'action empilées */
  .contact-actions { grid-template-columns: 1fr; gap: var(--sp-4); }
}

/* =========================================================
   15. V3 — PILULE SUPPORT, PAGE SUPPORT, MODALE (docs/04)
   ========================================================= */

/* ---- 15.1 Pilule SUPPORT du header (v3 §1) ---- */
.btn-support {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2);
  height: 32px; padding-inline: var(--sp-4);
  border: 1.5px solid var(--btn2-border);
  border-radius: var(--r-pill);
  background: transparent; color: var(--btn2-text);
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  text-decoration: none;
  transition: background-color var(--t-fast) var(--ease);
}
.btn-support svg { width: 16px; height: 16px; flex: none; }
/* Hover sur --surface-tint (PAS --chip-bg : 4.45:1 en pro, refusé v3 §1.4) */
.btn-support:hover { background: var(--surface-tint); }
.btn-support:focus-visible { box-shadow: var(--focus-ring); outline: none; }
/* Page courante (support.html) : fond permanent + aria-current (v3 §1.4) */
.btn-support[aria-current="page"] { background: var(--surface-tint); }

/* < 1024px : icône seule 40×40, entre le switcher et le burger (v3 §1.5) */
@media (max-width: 1023px) {
  /* LOT-DESIGN-20 — 44 px et non 40 : sous 1024 px on est au doigt, et 40 px
     est la seule taille du site qui passait sous le seuil. L'en-tête fait
     64 px de haut, la place existait. L'icône ne bouge pas. */
  .btn-support { width: 44px; height: 44px; padding: 0; }
  .btn-support svg { width: 20px; height: 20px; }
  /* Label masqué visuellement mais conservé pour le nom accessible */
  .btn-support__label {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    clip-path: inset(50%); overflow: hidden; white-space: nowrap;
  }
  .switcher--compact { order: 1; }
  .btn-support { order: 2; }
  .burger { order: 3; }
}

/* SUPPORT en tête du panneau burger (v3 §1.5) */
.menu-mobile__support { margin-bottom: var(--sp-5); }

/* ---- 15.2 Hero compact ---- SUPPRIMÉ (spec 17 §1.2) : remplacé par le hero
   standard .hero--page, défini en §6 avec les autres règles de hero. ---- */

/* ---- 15.3 Section téléchargement (v3 §2.3) ---- */
.card__media--reparation { object-position: 50% 55%; }
.card__media--aide { object-position: 50% 40%; }
.split__figure--aide img { object-position: 50% 40%; }

/* v4 §4 : CTA aéré — respiration au-dessus et en dessous (échelle --sp-*) */
/* spec 17 §3.5 : la marge du CTA vient désormais de .cta-group. */
.btn-dl svg { width: 20px; height: 20px; flex: none; margin-right: var(--sp-2); }
@media (max-width: 479px) {
  /* Le label passe sur 2 lignes, jamais raccourci (v3 §2.3) */
  .btn-dl {
    height: auto; min-height: 48px;
    padding-block: var(--sp-3);
    text-align: center; white-space: normal;
  }
}
/* .dl-mention SUPPRIMÉ (spec 17 §3.5) : remplacé par .cta-group__mention. */

/* ---- 15.4 Modale de confirmation (v3 §2.4) ---- */
html.modal-open { overflow: hidden; }

.modale {
  width: min(30rem, 100vw - 2rem);
  border: 0; padding: var(--sp-6);
  background: var(--paper); color: var(--ink);
  border-radius: var(--r-lg) var(--r-lg) var(--r-lg) var(--r-cut);
  box-shadow: var(--shadow-hover);
}
.modale::backdrop { background: var(--overlay); }        /* aucun blur (v3 §2.4) */
.modale[open] { animation: modale-in var(--t-med) var(--ease); }
.modale[open]::backdrop { animation: modale-fondu var(--t-med) var(--ease); }
@keyframes modale-in { from { opacity: 0; translate: 0 8px; } }
@keyframes modale-fondu { from { opacity: 0; } }

.modale__fermer-x {
  position: absolute; top: var(--sp-4); right: var(--sp-4);
  width: 32px; height: 32px;
  border: 0; background: transparent; cursor: pointer;
  color: var(--ink-muted);
  border-radius: var(--r-pill);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--t-fast) var(--ease);
}
.modale__fermer-x svg { width: 16px; height: 16px; }
.modale__fermer-x:hover { background: rgb(23 26 33 / .06); }
.modale__fermer-x:focus-visible { box-shadow: var(--focus-ring); outline: none; }

.modale__pastille {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px;
  background: var(--chip-bg); color: var(--chip-text);
  border-radius: var(--r-md);
}
.modale__pastille svg { width: 24px; height: 24px; }

.modale h2 { font-size: var(--fs-h3); margin: var(--sp-4) 0 0; }
.modale__confirmation { font-size: var(--fs-body); color: var(--ink); margin: var(--sp-2) 0 0; }

.modale__etapes {
  list-style: none; margin: var(--sp-5) 0 0; padding: 0;
  display: grid; gap: var(--sp-3);
  counter-reset: etape;
}
.modale__etapes li {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  font-size: var(--fs-small); color: var(--ink);
}
.modale__etapes li::before {
  counter-increment: etape;
  content: counter(etape);
  flex: none;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--chip-bg); color: var(--chip-text);
  font-size: var(--fs-small); font-weight: var(--fw-semibold);
  border-radius: var(--r-pill);
}
.modale__pied { margin-top: var(--sp-6); display: grid; gap: var(--sp-3); justify-items: center; }
.modale__reessayer { font-size: var(--fs-small); color: var(--link); text-decoration: underline; }

/* ---- 15.5 Cartes contact support (v3 §2.5) ---- */
/* v15 : gouttière ramenée à 24, comme toutes les autres grilles de blocs
   (le rembourrage des cartes vaut 32 : rapport 4/3, docs/45 §2). */
.contact-cards {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: var(--sp-5); margin-top: var(--sp-7);
}
/* Carte 2 : coin coupé bas-droit (miroir de la carte 1) */
.contact-cards .card:nth-child(2) { border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg); }
.contact-card p { color: var(--ink); margin: 0 0 var(--sp-2); }
.contact-card p strong { font-weight: var(--fw-semibold); }
/* Seul marquage d'univers de la page (CSS pur, v3 §2.5) */
[data-theme="prive"] .contact-card--prive,
[data-theme="pro"] .contact-card--pro { border: 2px solid var(--accent); }
.contact-adresse {
  font-size: var(--fs-small); color: var(--ink-muted);
  margin: var(--sp-6) 0 0;
}
/* v5 §2.4 : renvoi unique vers contact.html à la place du doublon NAP */
.contact-adresse__lien {
  color: var(--link);
  text-decoration: underline; text-underline-offset: 3px;
}
.contact-adresse__lien span { display: inline-block; transition: translate var(--t-fast) var(--ease); }
.contact-adresse__lien:hover span { translate: 4px 0; }
@media (max-width: 767px) {
  .contact-cards { grid-template-columns: 1fr; }
}

/* ---- 15.6 Bloc conditions minimal (v4 §3 — remplace le gabarit juridique v3) ---- */
.conditions-note { margin: var(--sp-6) 0 0; }
/* Annotation discrète vers les CG (à rédiger) — lien inerte comme les liens data-soon du menu */
.conditions-cg {
  font-size: var(--fs-small); color: var(--ink-muted);
  margin: var(--sp-5) 0 0;
}
.conditions-cg a[aria-disabled="true"] {
  color: var(--ink-muted);
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  cursor: default;
}

/* =========================================================
   16. V4 — PAGE CONTACT (docs/06)
   ========================================================= */

/* ---- 16.1 Lien de menu actif (v1 §4.1, via aria-current="page") ---- */
.header__link[aria-current="page"],
.menu-mobile__link[aria-current="page"] {
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--accent);
  text-underline-offset: 6px;
}

/* ---- 16.2 Split contact (v4 §3) : pas de zone "bas", la carte s'étire
        sur toute la hauteur des coordonnées (align-items: stretch) ---- */
.split--contact { grid-template-areas: "haut" "figure"; }
@media (min-width: 1024px) {
  .split--contact {
    grid-template-areas: "haut figure";
    align-items: stretch;
  }
}

/* ---- 16.3 Groupes de coordonnées (v4 §3.1 — que de la typo, pas de cartes) ---- */
.coords {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: var(--sp-6);
  margin-top: var(--sp-5);
}
@media (max-width: 559px) {
  .coords { grid-template-columns: 1fr; gap: var(--sp-5); }
}
.coord {
  border-left: 3px solid var(--line);
  padding-left: var(--sp-4);
}
.coord h3 { font-size: var(--fs-h4); margin-bottom: var(--sp-2); }
.coord p { margin: 0 0 var(--sp-1); }
.coord p strong { font-weight: var(--fw-semibold); }
/* Marquage de l'univers actif : seule la couleur du filet change (CSS pur, zéro JS) */
[data-theme="prive"] .coord--prive,
[data-theme="pro"] .coord--pro { border-left-color: var(--accent); }

/* ---- 16.4 Adresse & horaires (v4 §3.1) ---- */
.adresse { margin-top: var(--sp-6); }
.adresse h3 { font-size: var(--fs-h4); margin-bottom: var(--sp-2); }
.adresse address { font-style: normal; }
.adresse__zone { font-size: var(--fs-small); color: var(--ink-muted); margin: var(--sp-1) 0 0; }

.horaires { margin-top: var(--sp-6); }
.horaires h3 { font-size: var(--fs-h4); margin-bottom: var(--sp-2); }
.horaires__mention {
  font-size: var(--fs-tiny); font-weight: var(--fw-regular);
  letter-spacing: normal; text-transform: none;
  color: var(--ink-muted);
}
.horaires dl {
  margin: 0;
  display: grid; grid-template-columns: max-content 1fr;
  column-gap: var(--sp-5); row-gap: var(--sp-2);
}
.horaires dt { font-weight: var(--fw-semibold); }
.horaires dd { margin: 0; }

/* ---- 16.5 Carte OSM (v4 §3.2 — radius signature, AUCUN overlay) ---- */
.map {
  grid-area: figure;
  display: flex; flex-direction: column;
  margin: 0;
}
.map iframe {
  width: 100%;
  flex: 1;
  min-height: 24rem;
  border: 1px solid var(--line);
  /* Coin coupé bas-droit, miroir du bloc hero (même règle que les figures de split) */
  border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg);
}
@media (max-width: 1023px) {
  /* Mobile : carte portrait sous les coordonnées, min-height s'efface */
  .map iframe { min-height: 0; aspect-ratio: 4 / 5; }
}
/* ---- Aperçu local de la carte (v11, docs/21 §4 exigence 3) ----
   Aucun pixel distant : un aplat teinté de l'univers actif, une trame
   discrète en dégradés CSS, le pictogramme d'adresse et le bouton.
   Mêmes dimensions et même découpe que l'iframe qu'il remplace, pour
   qu'aucune hauteur ne bouge au moment du clic (zéro CLS). */
.map__apercu {
  position: relative;
  width: 100%; flex: 1;
  min-height: 24rem;
  display: grid; place-items: center;
  overflow: hidden;
  background: var(--surface-tint);
  border: 1px solid var(--line);
  border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg);
}
@media (max-width: 1023px) {
  .map__apercu { min-height: 0; aspect-ratio: 4 / 5; }
}
.map__apercu-fond {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 3rem 3rem;
  opacity: .55;
}
.map__apercu-contenu {
  position: relative;
  display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-6);
  text-align: center;
  max-width: 26rem;
}
.map__apercu-pin { width: 40px; height: 40px; color: var(--accent-text); }
.map__apercu-mention {
  margin: 0;
  font-size: var(--fs-tiny); line-height: 1.5; color: var(--ink-muted);
}
.map__apercu-mention a { color: var(--link); text-decoration: underline; }
.map iframe:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

.map__liens {
  margin-top: var(--sp-3);
  font-size: var(--fs-small);
  display: flex; gap: var(--sp-2); align-items: baseline;
}
.map__liens a { color: var(--link); text-decoration: underline; }
.map__liens span { color: var(--ink-muted); }

/* =========================================================
   17. V6 — PAGES ENTREPRISE (docs/09) : liste à coches, étapes, FAQ.
   Aucun token nouveau : couleurs (chips + accent de l'univers actif),
   rayons et espacements sortent tous du §1. Titres en casse normale
   dans le HTML, capitales portées par les règles h1-h4/.heading.
   ========================================================= */

/* ---- 17.1 Liste à coches (.liste-check) ---- */
.liste-check {
  list-style: none;
  margin: var(--sp-6) 0 0;
  padding: 0;
  display: grid; gap: var(--sp-5);        /* v15 : 16 → 24, l'interligne vaut 25,6 px */
  max-width: var(--measure-body);
}
.liste-check li {
  position: relative;
  padding-inline-start: calc(28px + var(--sp-4));
  color: var(--ink-muted);
}
/* Desktop : 2 colonnes — une colonne unique de 65ch laissait la moitié droite
   de la section vide, et allongeait la page pour rien. */
@media (min-width: 1024px) {
  .liste-check {
    grid-template-columns: 1fr 1fr;
    column-gap: var(--sp-7);
    max-width: none;
  }
}
/* Pastille de l'univers actif (même gabarit 28px que .modale__etapes) */
.liste-check li::before {
  content: "";
  position: absolute; inset-inline-start: 0; top: 0;
  width: 28px; height: 28px;
  background: var(--chip-bg);
  border-radius: var(--r-pill);
}
/* Coche dessinée en CSS : ni image, ni police d'icônes, ni emoji */
.liste-check li::after {
  content: "";
  position: absolute; inset-inline-start: 10px; top: 8px;
  width: 6px; height: 11px;
  border: solid var(--chip-text);
  border-width: 0 2px 2px 0;
  rotate: 45deg;
}

/* ---- 17.2 Étapes (.etapes) ----
   Par défaut : rail coloré, la numérotation vit dans l'intitulé rédigé
   (« 1. On vient voir »). Variante .etapes--numerotee : les intitulés ne
   portent pas de numéro, la CSS le pose en pastille (compteur). */
.etapes {
  list-style: none;
  margin: var(--sp-6) 0 0;
  padding: 0;
  display: grid; gap: var(--sp-5);
  counter-reset: etape;
}
.etapes li {
  position: relative;
  display: grid; gap: var(--sp-2);        /* v15 : 4 → 8 entre l'intitulé et son texte */
  max-width: var(--measure-body);
  padding-inline-start: var(--sp-5);
  border-inline-start: 2px solid var(--chip-bg);
}
.etapes .heading { font-size: var(--fs-small); color: var(--accent-text); margin: 0; }
.etapes span { color: var(--ink-muted); }
/* .etapes + .btn SUPPRIMÉ (spec 17 §3.5) : rustine ponctuelle, remplacée par .cta-group. */

.etapes--numerotee li {
  padding-inline-start: calc(28px + var(--sp-4));
  border-inline-start: 0;
}
.etapes--numerotee li::before {
  counter-increment: etape;
  content: counter(etape);
  position: absolute; inset-inline-start: 0; top: 0;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--chip-bg); color: var(--chip-text);
  font-size: var(--fs-small); font-weight: var(--fw-semibold);
  border-radius: var(--r-pill);
}

/* ---- 17.3 FAQ : <details>/<summary> natifs (clavier natif, zéro JS) ---- */
.faq { display: grid; gap: var(--sp-4); margin-top: var(--sp-7); }
.faq__item {
  background: var(--paper);
  border: 1px solid var(--line);
  padding: var(--sp-6);       /* v15 : rembourrage uniforme 32 (gouttière 16) */
  /* Radius signature : 3 coins --r-lg, 1 coin coupé, en rotation (détail n°2) */
  border-radius: var(--r-lg) var(--r-lg) var(--r-lg) var(--r-cut);
}
.faq__item:nth-child(3n+2) { border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg); }
.faq__item:nth-child(3n)   { border-radius: var(--r-cut) var(--r-lg) var(--r-lg) var(--r-lg); }

.faq__item summary {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-5);
  cursor: pointer;
  list-style: none;                     /* masque le triangle natif (Firefox) */
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:focus-visible {
  box-shadow: var(--focus-ring); outline: none;
  border-radius: var(--r-md);
}
.faq__item summary h3 { font-size: var(--fs-h4); color: var(--ink); margin: 0; }
/* Chevron dessiné en CSS, pivote à l'ouverture (le pivot, détail n°3) */
.faq__item summary::after {
  content: "";
  flex: none;
  width: 10px; height: 10px;
  margin-top: var(--sp-1);
  border: solid var(--accent-text);
  border-width: 0 2px 2px 0;
  rotate: 45deg;
  transition: rotate var(--t-fast) var(--ease);
}
.faq__item[open] summary::after { rotate: -135deg; }
.faq__item p { margin: var(--sp-5) 0 0; color: var(--ink-muted); max-width: var(--measure-body); }

/* ---- 17.4 Liste interne à une carte (comparatif contrat, 09 §1.2 §5) ---- */
.card > ul {
  margin: 0 0 var(--sp-4);
  padding-inline-start: var(--sp-5);
  color: var(--ink-muted);
  display: grid; gap: var(--sp-3);        /* v15 : 8 → 12 */
}
.card > ul strong { color: var(--ink); font-weight: var(--fw-semibold); }

@media (max-width: 767px) {
  .faq__item { padding: var(--sp-5); }
}

/* =========================================================
   18. PREFERS-REDUCED-MOTION
   ========================================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero::before { animation: none; }           /* aurora figée (v2 §2.2) */
  .switcher::before { transition: none; }      /* l'indicateur ne glisse pas */
  #banner-slot { transition: none; }
  .card, .card::before, .pricing__card, .pricing__card::before,
  .card__icon, .card__link span, .btn, .btn::before { transition: none; }
  /* audit 26 §2 : les trois flèches « → » qui glissaient de 4 px au survol
     n'étaient couvertes par aucune règle de ce bloc. */
  .contact-tuile__valeur span,
  .contact-adresse__lien span,
  .prix-fixes__lien a span { transition: none; }
  .modale[open], .modale[open]::backdrop { animation: none; }  /* v3 §2.4 */
  .faq__item summary::after { transition: none; }               /* v6 §17.3 */
  /* La transition entre PAGES est traitée au §23 : il ne suffit pas d'y
     couper les animations, il faut retirer l'adhésion à l'API. */
}

/* =========================================================
   19. SKIP LINK (spec 15 §6.1) — bénéfice site-wide
   ========================================================= */

.skip-link {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
  background: var(--paper); color: var(--ink);
  font-size: var(--fs-small); font-weight: var(--fw-semibold);
  text-decoration: none;
}
.skip-link:focus {
  position: fixed; z-index: 60;
  inset-block-start: var(--sp-3); inset-inline-start: var(--sp-3);
  width: auto; height: auto; margin: 0;
  clip-path: none; overflow: visible;
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--r-pill);
  box-shadow: var(--focus-ring);
}
main:focus { outline: none; }

/* =========================================================
   20. GABARIT DE PAGE LÉGALE (spec 15 — cg.html, mentions, confidentialité)
   Tout est scopé sous .legal : aucune règle globale n'est touchée.
   ========================================================= */

/* ---- 20.1 Hero légal ---- SUPPRIMÉ (spec 17 §1.2) : géométrie morte
   (.hero.hero--compact, spécificité 0,2,0, l'emportait sur .hero--legal, 0,1,0)
   et 3e registre d'aurora. cg.html utilise désormais .hero--page. ---- */

.hero__ariane {
  font-size: var(--fs-small); color: var(--hero-ink-soft);
  margin: 0 0 var(--sp-3);
}
.hero__ariane a { color: inherit; text-decoration: none; }
.hero__ariane a:hover { text-decoration: underline; }
.hero__ariane a:focus-visible { box-shadow: var(--focus-ring); outline: none; border-radius: 2px; }
.hero__ariane span { margin-inline: var(--sp-2); }

/* ---- 20.1 bis Fil d'Ariane des pages de contenu (audit 25 D-07) ----
   Même composant que .hero__ariane (même graisse, même corps, même séparateur),
   mais posé AU-DESSUS de la carte de hero, pas dedans.
   Pourquoi pas dans le hero, comme sur les pages légales : la spec 17 §1.3 fixe
   la hauteur du hero de page secondaire à 288 px pile sur les 11 pages, et cette
   valeur est verrouillée par test. Il reste 192 px de contenu ; sur
   services.html et vente.html, h1 + sous-titre en occupent déjà 181, et la
   ligne d'Ariane (34 px) ferait passer le hero à 311 px. Raccourcir ces deux
   textes est une décision éditoriale, pas une décision de développement : le fil
   sort donc du hero au lieu de casser l'invariant. */
.fil-ariane {
  width: min(var(--container), 100% - 2 * var(--container-pad));
  margin: var(--sp-4) auto 0;
  font-size: var(--fs-small);
  color: var(--ink-muted);
}
.fil-ariane a { color: inherit; text-decoration: none; }
.fil-ariane a:hover { text-decoration: underline; }
.fil-ariane a:focus-visible { box-shadow: var(--focus-ring); outline: none; border-radius: 2px; }
.fil-ariane__sep { margin-inline: var(--sp-2); }
.fil-ariane__ici { color: var(--ink); }

.legal__maj {
  font-size: var(--fs-small); color: var(--hero-ink-soft);
  margin: var(--sp-3) 0 0;
}

/* ---- 20.2 Zone de contenu, grille et mesure (§1.4) ---- */
.legal { padding-block: var(--sp-8) var(--sp-9); background: var(--paper); }

.legal__layout {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--container-pad);
  display: grid;
  /* audit 25 D-02 — la colonne unique (sous 1120 px) était en `auto` : sa
     largeur minimale valait donc le min-content de son contenu. Le tableau
     « Combien de temps nous gardons quoi » de confidentialite.html, dont la
     dernière colonne est en `white-space: nowrap` (§20.9, colonne de montants),
     imposait 479 px et faisait déborder toute la page à 320/375/390 px —
     `.legal__table-wrap { overflow-x: auto }` ne protège rien tant que la piste
     est dimensionnée sur le contenu. minmax(0, 1fr) rend la piste élastique et
     rend au conteneur de tableau son rôle d'amortisseur.
     Les deux autres gabarits de grille (≥ 1120 px et .legal--court) utilisaient
     déjà minmax(0, …) : c'est la même règle, appliquée au cas manquant. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-5);
}
@media (min-width: 1120px) {
  .legal__layout {
    grid-template-columns: var(--legal-toc-w) minmax(0, var(--measure));
    column-gap: var(--sp-8);
    justify-content: center;
    align-items: start;
  }
}
.legal__prose { max-width: var(--measure); }
@media (min-width: 768px) and (max-width: 1119px) {
  .legal__prose { margin-inline: auto; }
}
/* Variante courte (≤ 4 articles : mentions légales) — §9 */
.legal--court .legal__layout { grid-template-columns: minmax(0, var(--measure)); justify-content: center; }

.legal [id] { scroll-margin-top: var(--scroll-offset); }

/* ---- 20.3 Sommaire (§2.3, §2.4) ---- */
.legal__toc-titre {
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label); text-transform: uppercase;
  color: var(--accent-text); margin: 0 0 var(--sp-3);
}
.legal__toc-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.legal__toc-liste[hidden] { display: none; }   /* le display auteur l'emporte sur [hidden] */
.legal__toc-liste a {
  /* LOT-DESIGN-20 — 2.5rem et non 1.5rem : un seul repère du site n'est pas
     un nombre, « 2 bis » (l'article ajouté aux CG et à la confidentialité).
     Dans 24 px il passait à la ligne, dans la colonne des numéros. La colonne
     est fixe et non `auto` pour que les intitulés restent alignés d'une
     entrée à l'autre — c'est l'alignement qui fait lire un sommaire. */
  display: grid; grid-template-columns: 2.5rem 1fr; column-gap: var(--sp-2);
  align-items: baseline;
  min-height: 44px;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  border-inline-start: 2px solid transparent;
  font-size: var(--fs-small); line-height: 1.4;
  color: var(--ink-muted); text-decoration: none;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.legal__toc-num { color: var(--ink-muted); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; white-space: nowrap; }
.legal__toc-liste a:hover { background: rgb(23 26 33 / .06); color: var(--ink); }
.legal__toc-liste a:focus-visible { box-shadow: var(--focus-ring); outline: none; }

/* Article en cours de lecture : 4 marqueurs, jamais la couleur seule.
   LOT-DESIGN-20 — le marqueur de GRAISSE ne passe plus par `font-weight`.
   Lexend est une fonte variable : passer de 400 à 600 élargit le texte, un
   intitulé long repasse alors sur deux lignes, l'entrée grandit de 11 px et
   pousse toute la suite du sommaire. C'était le seul décalage de mise en page
   mesuré du site (CLS 0,0012 sur confidentialite.html, à 1440 px, pendant le
   défilement — le repérage de lecture change d'entrée à chaque article).
   `-webkit-text-stroke` épaissit le tracé SANS toucher aux chasses : même
   effet à l'œil, zéro reflux. Là où il n'est pas connu, les trois autres
   marqueurs restent (couleur, fond, rail). */
.legal__toc-liste a[aria-current] {
  color: var(--accent-text);
  -webkit-text-stroke: 0.3px currentColor;
  background: var(--surface-tint);
  border-inline-start-color: var(--accent);
}
.legal__toc-liste a[aria-current] .legal__toc-num { color: var(--accent-text); }

.legal__toc-toggle { display: none; }

/* ≥ 1120px : colonne latérale collante */
@media (min-width: 1120px) {
  .legal__toc {
    position: sticky;
    top: calc(80px + var(--sp-5));
    align-self: start;
    max-height: calc(100vh - 104px - var(--sp-6));
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }
}
/* < 1120px : carte en tête de contenu (coin coupé signature) */
@media (max-width: 1119px) {
  .legal__toc {
    position: static; width: auto;
    margin-bottom: var(--sp-8);
    padding: var(--sp-5);
    border: 1px solid var(--line);
    border-radius: var(--r-lg) var(--r-lg) var(--r-lg) var(--r-cut);
  }
}
@media (min-width: 768px) and (max-width: 1119px) {
  .legal__toc-liste { grid-template-columns: 1fr 1fr; column-gap: var(--sp-5); }
}
/* < 768px : carte repliable */
@media (max-width: 767px) {
  /* CLS — le repli du sommaire etait pose par legal.js (defer), donc APRES la
     premiere peinture : la liste des 27 articles disparaissait sous les yeux du
     visiteur et decalait toute la page (score CLS mesure 0,55 sur cg.html).
     La classe .js-legal est posee par le script d'amorcage du <head>, donc
     AVANT tout rendu ; legal.js la retire aussitot et reprend la main via
     l'attribut [hidden]. Sans JavaScript la classe n'existe pas : le sommaire
     reste deplie et toutes les ancres restent utilisables. */
  .js-legal .legal__toc-liste:not([hidden]) { display: none; }
  .legal__toc-toggle {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-3);
    width: 100%; height: 44px;
    padding: 0 var(--sp-3);
    background: none; border: 0; border-radius: var(--r-md);
    color: var(--ink); cursor: pointer;
    font-family: var(--font); font-size: var(--fs-small); font-weight: var(--fw-semibold);
    text-transform: uppercase; letter-spacing: var(--ls-label);
  }
  .legal__toc-toggle:focus-visible { box-shadow: var(--focus-ring); outline: none; }
  .legal__toc-toggle::after {
    content: "";
    flex: none;
    width: 10px; height: 10px;
    border: solid var(--accent-text);
    border-width: 0 2px 2px 0;
    rotate: 45deg;
    transition: rotate var(--t-fast) var(--ease);
  }
  .legal__toc-toggle[aria-expanded="true"]::after { rotate: -135deg; }
  .legal__toc-toggle + .legal__toc-liste { margin-top: var(--sp-3); }
}

/* ---- 20.4 Bouton d'impression (§4.6) ---- */
.legal__actions { }   /* spec 17 §3.5 : flex, gap et marges viennent de .cta-group */
.legal__actions[hidden] { display: none; }
/* CLS — le bouton « Imprimer » est révélé par legal.js (defer), donc APRÈS le
   premier rendu : il apparaissait au-dessus du sommaire et poussait toute la
   page vers le bas (0,079 mesuré sur cg.html). La classe .js-legal, posée par
   le script d’amorçage du <head> avant tout rendu, réserve la place dès la
   première peinture ; legal.js retire ensuite la classe et enlève [hidden],
   sans aucun changement visuel. Sans JavaScript, la classe n’existe pas : le
   bouton reste absent, il n’y a donc jamais de bouton mort. */
.js-legal .legal__actions[hidden] { display: flex; }
.legal__actions .btn svg { width: 16px; height: 16px; margin-inline-end: var(--sp-2); }
/* ≥ 1120px : le bouton vit dans la colonne du sommaire. Il est posé AU-DESSUS
   de la liste et non en dessous (spec §4.6) : avec 27 articles, la liste
   remplit la colonne collante et tout ce qui la suit sort du champ. */
@media (min-width: 1120px) {
  .legal__layout { grid-template-areas: "actions prose" "toc prose"; grid-template-rows: auto 1fr; }
  .legal__actions { grid-area: actions; }
  .legal__toc { grid-area: toc; }
  .legal__prose { grid-area: prose; }
}

/* ---- 20.5 Retour en haut de page (§2.6) ---- */
.legal__totop {
  position: fixed; z-index: 40;
  inset-inline-end: var(--sp-4);
  inset-block-end: max(var(--sp-4), env(safe-area-inset-bottom));
  display: flex; align-items: center; justify-content: center;
  width: 48px; height: 48px;
  border-radius: var(--r-pill);
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card);
  transition: opacity var(--t-med) var(--ease), translate var(--t-med) var(--ease);
}
.legal__totop[hidden] { display: none; }
.legal__totop svg { width: 20px; height: 20px; }
.legal__totop:hover { background: var(--surface-tint); }
.legal__totop:focus-visible { box-shadow: var(--focus-ring); outline: none; }
.legal__totop.is-in { opacity: 1; translate: 0 0; }
.legal__totop:not(.is-in) { opacity: 0; translate: 0 8px; }

/* ---- 20.6 Typographie du texte long (§3) ---- */
.legal__prose {
  font-size: var(--fs-legal); line-height: var(--lh-legal); color: var(--ink);
  hyphens: auto;
  /* audit 25 D-02 : `break-word` coupe un mot trop long À L'AFFICHAGE mais ne
     réduit PAS sa contribution min-content. La colonne de grille de
     .legal__layout se dimensionnait donc sur le plus long jeton insécable de la
     page — les marqueurs du juriste, p. ex.
     « [ADRESSE DE CONTACT « DONNÉES » À COMPLÉTER, p. ex. donnees@tech-center.ch] » —
     et confidentialite.html mesurait 491 px de large pour un écran de 320 px.
     `anywhere` autorise la même coupure ET la répercute sur le calcul de la
     largeur minimale : la colonne redevient élastique. Rendu identique pour tout
     texte qui tient déjà dans la mesure ; les marqueurs restent VISIBLES (ils
     doivent l'être tant que le client n'a pas fourni ses informations), ils sont
     seulement césurés. */
  overflow-wrap: anywhere;
}
/* v15 (docs/45 §5) — 16 px entre deux paragraphes pour un interligne de
   29,75 px (17 px × 1,75) : le blanc entre paragraphes était deux fois plus
   petit que le blanc entre lignes, et vingt-sept articles de CG se lisaient
   comme un seul pavé. 24 px = 0,81 × l'interligne.
   L'interligne, lui, ne bouge PAS : 29,75 px est verrouillé par test
   (test_site.py l. 1379) et reste la bonne valeur pour du texte long. */
.legal__prose p { margin: 0 0 var(--sp-5); }
.legal__prose p:last-child { margin-bottom: 0; }

.legal__prose ul, .legal__prose ol { margin: var(--sp-5) 0; padding-inline-start: var(--sp-5); }
.legal__prose li + li { margin-top: var(--sp-3); }
.legal__prose li::marker { color: var(--accent-text); font-weight: var(--fw-semibold); }
.legal__prose ul ul, .legal__prose ol ol { margin: var(--sp-2) 0; }

.legal__prose strong { font-weight: var(--fw-semibold); color: var(--ink); }
.legal__prose em { font-style: italic; }
.legal__prose a { color: var(--link); text-decoration: underline; text-underline-offset: 2px; }
.legal__prose a:hover { text-decoration-thickness: 2px; }
.legal__prose a:focus-visible { box-shadow: var(--focus-ring); outline: none; border-radius: 2px; }
.legal__prose abbr[title] { text-decoration: underline dotted; cursor: help; }

/* Titre d'article — la numérotation EST l'ancre (§3.1) */
.legal h2 {
  font-size: var(--fs-h3);
  display: grid; grid-template-columns: 2rem 1fr; column-gap: var(--sp-3);
  align-items: center;
  margin: 0 0 var(--sp-5);
  color: var(--ink);
}
.legal__titre { text-wrap: balance; }
.legal__num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border-radius: var(--r-pill);
  background: var(--chip-bg); color: var(--chip-text);
  font-size: var(--fs-small); font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}
.legal__ancre {
  font-size: var(--fs-small); color: var(--ink-muted);
  margin-inline-start: var(--sp-2);
  text-decoration: none;
}
.legal__ancre:focus-visible { box-shadow: var(--focus-ring); outline: none; border-radius: 2px; }
@media (hover: hover) {
  .legal__ancre { opacity: 0; transition: opacity var(--t-fast) var(--ease); }
  .legal h2:hover .legal__ancre, .legal h2:focus-within .legal__ancre { opacity: 1; }
}
/* LOT-DESIGN-20 — sur un écran tactile l'ancre est toujours visible (pas de
   survol pour la révéler) et elle ne fait que 11x18 px. On lui donne une zone
   de contact de 44x44 EN SURCOUCHE, sans rien changer à la mise en page : le
   glyphe garde sa taille et la ligne du titre garde sa hauteur. */
@media (hover: none) {
  .legal__ancre { opacity: 1; position: relative; }
  .legal__ancre::after {
    content: ""; position: absolute;
    inset-block-start: 50%; inset-inline-start: 50%;
    inline-size: 2.75rem; block-size: 2.75rem;
    transform: translate(-50%, -50%);
  }
}

/* v15 (docs/45 §6) — le FILET entre deux articles est supprimé, et les
   48 + 48 px qui l'encadraient deviennent 64 px de blanc franc. Un numéro
   d'article en pastille, un titre en capitales et 64 px de vide séparent déjà
   deux articles sans équivoque : le filet était un quatrième signal, et il
   ajoutait vingt-six lignes grises sur cg.html. Bénéfice de hauteur :
   −32 px × 26 = −832 px sur cg.html, qui compensent le blanc rendu aux
   paragraphes. */
.legal__article + .legal__article {
  margin-top: var(--sp-8);
}

/* Sous-section (§3.2) */
.legal h3 {
  font-size: var(--fs-h4);
  line-height: 1.25;
  margin: var(--sp-6) 0 var(--sp-3);
  color: var(--ink);
}
.legal__subnum {
  color: var(--accent-text); font-weight: var(--fw-semibold);
  margin-inline-end: var(--sp-2);
  font-variant-numeric: tabular-nums;
}

/* ---- 20.7 Bloc « en résumé » (§4.1) ---- */
.legal__resume {
  margin: 0 0 var(--sp-6);
  padding: var(--sp-6) var(--sp-5);
  background: var(--surface-tint);
  border-inline-start: 3px solid var(--accent);
  border-radius: var(--r-md) var(--r-lg) var(--r-lg) var(--r-md);
  font-size: var(--fs-legal); line-height: 1.6; color: var(--ink);
}
.legal__resume p { margin: 0; }
.legal__resume::before {
  content: "En résumé";
  display: block; margin-bottom: var(--sp-2);
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label); text-transform: uppercase;
  color: var(--accent-text);
}

/* ---- 20.8 Encadré d'information importante (§4.2) ---- */
/* v15 (docs/45 §6) : le filet gris périphérique est supprimé. L'encadré portait
   trois marqueurs pour une seule idée — aplat teinté, rail coloré, filet gris.
   Restent l'aplat et le rail, qui, eux, disent quelque chose. */
.legal__note {
  margin: var(--sp-6) 0;
  padding: var(--sp-6) var(--sp-5);
  border-inline-start: 4px solid var(--accent);
  border-radius: var(--r-md) var(--r-lg) var(--r-lg) var(--r-md);
  background: var(--surface-tint);
}
.legal__note-titre {
  display: flex; align-items: center; gap: var(--sp-2);
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label); text-transform: uppercase;
  color: var(--accent-text);
}
.legal__note-titre svg { flex: none; width: 20px; height: 20px; }
.legal__note p:last-child { margin: 0; }
/* Variante ATTENTION — hors thème : une clause à risque reste à risque partout */
.legal__note--attention { background: var(--note-bg); border-inline-start-color: var(--note-rail); }
.legal__note--attention .legal__note-titre { color: var(--note-rail); }
/* Placé en tête d'article (juste sous le h2), il ne double pas la marge du titre */
.legal h2 + .legal__note { margin-top: 0; }

/* ---- 20.9 Tableau de barème (§4.3) ---- */
.legal__table { width: 100%; border-collapse: collapse; margin: var(--sp-6) 0; font-size: 1rem; line-height: 1.5; }
.legal__table caption {
  caption-side: top; text-align: start; margin-bottom: var(--sp-3);
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--accent-text);
}
.legal__table th, .legal__table td { padding: var(--sp-3) var(--sp-4); text-align: start; vertical-align: top; }
.legal__table thead th {
  background: var(--chip-bg); color: var(--chip-text);
  font-weight: var(--fw-semibold); font-size: var(--fs-small);
  letter-spacing: var(--ls-label); text-transform: uppercase;
}
.legal__table thead th:first-child { border-start-start-radius: var(--r-md); }
.legal__table thead th:last-child  { border-start-end-radius: var(--r-md); }
.legal__table tbody tr { border-bottom: 1px solid var(--line); }
/* v15 (docs/45 §6) : le ZÉBRAGE est supprimé. Chaque ligne porte déjà un filet
   inférieur ; l'aplat une ligne sur deux était un second guide pour le même
   œil, et un gris de plus dans une page qui en comptait déjà quatre.
   Le jeton --zebra, qui n'avait plus aucun usage, est supprimé avec elle. */
.legal__table td:last-child { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* v10 (20 §0.5) : le composant sert aussi de tableau générique hors page légale.
   Le conteneur absorbe le débordement d'un tableau large (comparatif à 5
   colonnes) entre 560 px et la largeur de confort, sans casser cg.html. */
.legal__table-wrap { overflow-x: auto; }
/* Variante comparatif : la dernière colonne n'est pas une colonne de prix.
   Elle ne doit ni passer en gras ni refuser le retour à la ligne. */
.legal__table--compare td:last-child { font-weight: inherit; white-space: normal; }
/* v11 : variante EMPILÉE, à toutes les largeurs. La spec 15 §4.3 plafonne un
   tableau légal à 3 colonnes ; le tableau « Ce qui est enregistré sur votre
   appareil » livré par le juriste en compte 5. Plutôt que de réécrire son
   texte, on lui applique la présentation empilée déjà spécifiée pour le mobile :
   chaque cellule devient « intitulé / valeur », sans scroll horizontal.
   Le générateur pose la classe automatiquement au-delà de 3 colonnes. */
.legal__table--empile thead { position: absolute; width: 1px; height: 1px; clip-path: inset(50%); overflow: hidden; }
.legal__table--empile tr { display: block; padding: var(--sp-4) 0; border-bottom: 1px solid var(--line); }
.legal__table--empile td { display: grid; gap: var(--sp-1); padding: var(--sp-2) 0; }
.legal__table--empile td:last-child { font-weight: inherit; white-space: normal; }
.legal__table--empile td::before {
  content: attr(data-label);
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--ink-muted);
}

@media (max-width: 559px) {
  .legal__table thead { position: absolute; width: 1px; height: 1px; clip-path: inset(50%); overflow: hidden; }
  .legal__table tr { display: block; padding: var(--sp-4) 0; border-bottom: 1px solid var(--line); }
  /* v10 (20 §0.5 note 2) : le comparatif porte des <th scope="row"> dans le
     <tbody> ; la règle mobile ne ciblait que les <td>. */
  .legal__table tbody th { display: block; text-align: start; padding: var(--sp-2) 0 0; }
  .legal__table td { display: grid; gap: var(--sp-1); padding: var(--sp-2) 0; }
  /* audit 25 D-02 : `white-space: nowrap` sur td:last-child (§20.9) sert à garder
     un montant sur une ligne dans un tableau à colonnes. Une fois le tableau
     empilé, chaque cellule occupe déjà toute la largeur : le nowrap n'y protège
     plus rien et rend au contraire la cellule insécable — « [DURÉE À COMPLÉTER,
     RECOMMANDÉ : 25 MOIS AU PLUS] » imposait 479 px et le tableau se lisait au
     défilement horizontal. */
  .legal__table td:last-child { white-space: normal; }
  .legal__table td::before {
    content: attr(data-label);
    font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
    letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--ink-muted);
  }
}

/* ---- 20.10 Capsule d'audience (§4.4) ---- */
.legal__audience {
  display: inline-flex; align-items: center;
  margin-inline-start: var(--sp-3);
  padding: 2px var(--sp-3);
  border-radius: var(--r-pill);
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label); text-transform: uppercase;
  white-space: nowrap;
}
/* Couleurs FIXES, indépendantes de data-theme : elles désignent une audience */
.legal__audience--prive { background: #FDE3D2; color: #8A3D05; }
.legal__audience--pro   { background: #D9E4F7; color: #2E4A85; }

/* ---- 20.11 Pied de document (§4.5) ---- */
.legal__pied {
  margin-top: var(--sp-8);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
  font-size: var(--fs-small); color: var(--ink-muted);
}
.legal__pied p { margin: 0 0 var(--sp-2); }
.legal__pied p:last-child { margin-bottom: 0; }

/* En-tête de document réservé à l'impression (§6.3) */
.legal__print-entete { display: none; }

@media (prefers-reduced-motion: reduce) {
  .legal__totop { transition: none; }
  .legal__toc-toggle::after { transition: none; }
  .legal__ancre { transition: none; }
}

/* =========================================================
   21. IMPRESSION (spec 15 §6.3) — le site n'en avait aucune
   ========================================================= */

@media print {
  @page { size: A4; margin: 20mm 22mm 22mm; }

  /* 1. Ce qui disparaît */
  #banner-slot, .header, .menu-mobile, .skip-link, .fil-ariane,
  .legal__toc, .legal__totop, .legal__actions, .no-print,
  .footer, .hero__grain { display: none !important; }

  /* 2. Le hero redevient un simple titre (spec 17 §1.5). */
  .hero, .hero--page {
                        min-height: 0; padding: 0; margin: 0; border-radius: 0;
                        background: none !important; color: #000 !important; overflow: visible; }
  .hero::before, .hero::after { display: none !important; }
  .hero--page h1 { font-size: 18pt; }
  .hero__ariane { display: none; }
  .hero__content h1, .hero__content h2 { color: #000 !important; }
  .legal__maj { color: #000 !important; }

  /* 3. En-tête de document imprimé (masqué à l'écran) */
  .legal__print-entete { display: block !important; margin-bottom: 8mm; font-size: 9pt; color: #000; }
  .legal__print-entete img { width: 28mm; height: auto; margin-bottom: 3mm; }
  .legal__print-entete p { margin: 0 0 1mm; }

  /* 4. Corps : une colonne, mesure conservée */
  html { background: #fff; }
  body { font-size: 10.5pt; line-height: 1.45; color: #000; }
  .legal { padding: 0; }
  .legal__layout { display: block; max-width: none; padding: 0; }
  .legal__prose { max-width: 150mm; margin-inline: 0; font-size: 10.5pt; line-height: 1.45; }
  .legal__prose p { margin-bottom: 3mm; }

  /* 5. Hiérarchie */
  .legal__article + .legal__article { margin-top: 8mm; padding-top: 8mm; border-top: .3pt solid #999; }
  .legal h2 { font-size: 13pt; }
  .legal h3 { font-size: 10.5pt; }
  .legal__num { background: none !important; color: #000 !important;
                width: auto; height: auto; padding: 0 1.5mm; border-radius: 0;
                border: .5pt solid #000; }
  .legal__subnum { color: #000 !important; }
  .legal__ancre { display: none; }

  /* 6. Encadrés et tableaux : pas d'aplat (encre), le sens passe par le filet */
  .legal__resume, .legal__note {
    background: none !important; border: .5pt solid #999;
    border-inline-start: 2pt solid #000; padding: 3mm; border-radius: 0;
  }
  .legal__resume::before, .legal__note-titre { color: #000 !important; }
  .legal__table thead th { background: none !important; color: #000 !important; border-bottom: 1pt solid #000; }
  .legal__table, .legal__table th, .legal__table td { border-color: #999; }
  .legal__table caption { color: #000 !important; }
  .legal__audience { background: none !important; color: #000 !important; border: .5pt solid #000; }
  .legal__pied { color: #000 !important; }

  /* 7. Sauts de page */
  .legal h2, .legal h3 { break-after: avoid-page; break-inside: avoid; }
  .legal__article { break-before: auto; }
  p, li, tr, .legal__resume, .legal__note, .legal__table { break-inside: avoid; }
  p, li { orphans: 3; widows: 3; }

  /* 8. Liens : l'URL des liens externes est imprimée, pas celle des ancres */
  .legal__prose li::marker { color: #000; }
  .legal__prose a { color: #000; text-decoration: underline; }
  .legal__prose a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 8.5pt; word-break: break-all; }
  .legal__prose a[href^="#"]::after, .legal__prose a[href^="mailto"]::after,
  .legal__prose a[href^="tel"]::after { content: ""; }
}

/* =========================================================
   22. AMÉLIORATION PROGRESSIVE ET CIBLES TACTILES
   (audit QA docs/25 — défauts D-03, D-04, D-08, D-09)
   ========================================================= */

/* ---- 22.1 Ce qui se passe quand JavaScript est absent ----
   Contrainte de départ : la CSP de production (.htaccess §6.1) n'autorise ni
   style ni script en ligne hors empreintes déjà générées. Aucun de ces replis
   n'ajoute donc de <script> ni de <style> en ligne : ils reposent uniquement
   sur :target (piloté par l'URL) et sur l'attribut [hidden] posé dans le HTML,
   comme le fait déjà legal.js pour le bouton d'impression (§20.4).

   Menu mobile (D-03) — le burger est un <a href="#menu-mobile"> : sans script,
   le fragment ouvre le panneau et la navigation d'en-tête reste accessible.
   Avec JavaScript, main.js neutralise le lien (preventDefault) et nettoie un
   éventuel #menu-mobile d'arrivée : le hash ne vaut alors JAMAIS #menu-mobile,
   :target ne s'active pas, et c'est l'attribut [hidden] qui fait foi.
   Sous 1024 px seulement : au-dessus, le burger n'existe pas. */
@media (max-width: 1023px) {
  .menu-mobile:target { display: block; }
}

/* Fermeture du panneau sans script. Avec JS, main.js pose [hidden] dessus
   (le burger et Échap font le travail) : pas de propriété `display` ici, pour
   que [hidden] suffise à le masquer. */
.menu-mobile__fermer {
  margin-top: var(--sp-6);
  font-size: var(--fs-small); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  color: var(--ink-muted); text-decoration: underline;
  text-underline-offset: 4px;
}
.menu-mobile__fermer:focus-visible { box-shadow: var(--focus-ring); outline: none; }

/* Carte de contact (D-04) — le bouton « Afficher la carte » ne peut rien
   injecter sans script : il est [hidden] dans le HTML et c'est carte.js qui le
   révèle, en masquant du même geste le lien OpenStreetMap qui tient le rôle
   sans JavaScript. Les deux sont des .btn de 48 px dans le même emplacement de
   la colonne : l'échange ne déplace rien (aucun décalage de mise en page).
   `.btn` impose display:inline-flex, qui l'emporterait sur le display:none de
   l'agent utilisateur : il faut rendre [hidden] explicite. */
.btn[hidden], .map__apercu-osm[hidden] { display: none; }

/* ---- 22.2 Verrou de défilement du menu mobile (D-08) ----
   Même mécanisme que .modal-open (§15.4) : le panneau est en position fixed et
   couvre tout l'écran ; la page ne doit pas défiler derrière lui, sans quoi le
   visiteur perd sa place à la fermeture. */
html.menu-ouvert { overflow: hidden; }

/* ---- 22.3 Cibles tactiles de l'en-tête (D-09, WCAG 2.5.5) ----
   Mesuré à 320 px avant correction : segments du switcher 68×26 et 59×26,
   pilule Support 38×40, fermeture de bannière 32×32, burger 42×44. */
@media (max-width: 1023px) {
  .switcher--compact { height: 52px; padding: 4px; }
  .switcher--compact::before { top: 4px; left: 4px; bottom: 4px; width: calc(50% - 4px); }
  .switcher--compact .switcher__seg { height: 44px; min-width: 44px; }
  .banner__fermer { width: 44px; height: 44px; }
  .burger { flex: none; }               /* 44 px pleins, plus de compression */
}

@media (max-width: 374px) {
  /* À 320 px l'en-tête est saturé (289 px de contenu pour 288 disponibles) :
     la place se récupère sur les gouttières et le rembourrage des segments,
     jamais en rognant les cibles. */
  .header__inner { gap: var(--sp-2); }
  .switcher--compact .switcher__seg { padding-inline: var(--sp-2); }
  .header__logo-icon { flex: none; }
  .btn-support { flex: none; }           /* sinon la pilule est compressée à 43,9 px */
  /* CONFLIT DE SPÉCIFICATION assumé et scopé : la spec v3 §1.5 fixe la pilule
     Support à 40×40 sous 1024 px et test_site.py verrouille cette valeur à
     390 px (l. 559 et 726) ; WCAG 2.5.5 en demande 44. La cible est portée à
     44×44 aux largeurs où l'audit a mesuré le défaut (≤ 374 px) ; l'élargir
     partout est un arbitrage de design, pas de développement. */
  .btn-support { width: 44px; height: 44px; }
}

/* ---- 22.4 Formule retenue sur abonnements.html (audit 25 D-15) ----
   Les quatre CTA « Choisir X » visaient tous #souscrire : le choix se perdait
   en chemin. Chaque carte vise désormais #souscrire-<formule>.

   Les quatre ancres sont hors flux, collées au bord haut de la section : le
   cadrage après le clic est donc exactement celui de #souscrire (même
   scroll-margin-top, même respiration au-dessus du titre), et rien n'est
   ajouté à la mise en page.

   La reconnaissance du choix est faite en CSS pur, par :target. Pas de
   JavaScript : le lien reste partageable, il survit au rechargement, et il
   fonctionne script absent — cohérent avec le §22.1. Il n'y a toujours aucune
   vente en ligne : la phrase renvoie au téléphone et au magasin. */
#souscrire { position: relative; }
.ancre-formule {
  position: absolute; inset-block-start: 0; inset-inline-start: 0;
  width: 1px; height: 1px;
  scroll-margin-top: var(--scroll-offset);
}

/* Rien n'est annoncé tant qu'aucune formule n'est demandée. */
.souscrire__choix { display: none; }
.souscrire__choix-nom { display: none; }

#souscrire-bronze:target    ~ .container .souscrire__choix,
#souscrire-silver:target    ~ .container .souscrire__choix,
#souscrire-gold:target      ~ .container .souscrire__choix,
#souscrire-platinium:target ~ .container .souscrire__choix {
  display: block;
  margin-block: var(--sp-4) 0;
  padding: var(--sp-3) var(--sp-4);
  border-inline-start: 3px solid var(--accent);
  background: var(--surface-tint);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  font-size: var(--fs-small); color: var(--ink);
}
#souscrire-bronze:target    ~ .container .souscrire__choix-nom[data-formule="bronze"],
#souscrire-silver:target    ~ .container .souscrire__choix-nom[data-formule="silver"],
#souscrire-gold:target      ~ .container .souscrire__choix-nom[data-formule="gold"],
#souscrire-platinium:target ~ .container .souscrire__choix-nom[data-formule="platinium"] {
  display: inline;
}

/* =========================================================
   23. TRANSITION ENTRE PAGES (v13 — docs/32)

   Le site est multi-pages : par défaut, changer de page est une coupure
   nette, l'écran blanchit puis la page suivante apparaît d'un bloc. L'API
   « View Transitions inter-documents » demande au navigateur d'enchaîner
   les deux images lui-même, sans routeur JavaScript ni librairie.

   AMÉLIORATION PROGRESSIVE, sans condition : un navigateur qui ne connaît
   pas @view-transition ignore la règle inconnue et TOUT ce bloc (règle
   d'analyse CSS : un sélecteur ou une @-règle non reconnus sont écartés).
   La navigation y reste exactement celle d'aujourd'hui, sans erreur.
   Couverture au 27.08.2026 : Chrome/Edge 126+, Safari 18.2+ (macOS et iOS),
   Samsung Internet. Firefox ne l'implémente pas encore (retenu dans
   Interop 2026) : il affiche la coupure nette d'aujourd'hui.

   Le mouvement respecte le design system : rien d'autre qu'opacity et
   translate, et les jetons de durée et de courbe existants (--t-fast,
   --t-med, --ease), qui sont hérités par l'arbre ::view-transition.
   ========================================================= */

@view-transition { navigation: auto; }

/* L'en-tête est le seul élément identique et à la même place sur les deux
   pages (position: sticky, collé en haut). En le nommant, on le sort de
   l'image de la page : il ne fond plus avec le reste, il RESTE — c'est ce
   qui donne l'impression de continuité plutôt que de rechargement.
   Le pied de page, lui, n'est PAS nommé volontairement : sa position dépend
   de la hauteur de la page, donc d'une page à l'autre il glisserait en
   travers de l'écran. Il reste dans l'image de la page, où il ne bouge pas. */
.header { view-transition-name: tcm-entete; }

@keyframes tcm-page-sortie { to   { opacity: 0; } }
@keyframes tcm-page-entree { from { opacity: 0; translate: 0 10px; } }

/* Sortie courte, entrée un peu plus longue avec une légère montée : l'œil
   lit une continuité, pas un effet. */
::view-transition-old(root) { animation: tcm-page-sortie var(--t-fast) var(--ease) both; }
::view-transition-new(root) { animation: tcm-page-entree  var(--t-med)  var(--ease) both; }

/* En-tête : fondu par défaut raccourci au minimum. Le contenu y est le même
   d'une page à l'autre (seul le lien courant change), donc il paraît fixe. */
::view-transition-old(tcm-entete),
::view-transition-new(tcm-entete) { animation-duration: var(--t-fast); }

/* Mouvement réduit : on ne se contente pas de neutraliser les animations
   (le fondu croisé par défaut, lui, resterait) — on retire l'adhésion à
   l'API. Le navigateur reprend la navigation instantanée. */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* =========================================================
   24. SOUS-MENU DE NAVIGATION (LOT-DESIGN-18 — docs/55 ·
       repris au LOT-DESIGN-19 — docs/59)

   Le menu comptait cinq entrées en Privé et quatre en Entreprise. « Cours »
   posé à plat aurait fait six. Les prestations d’accompagnement — ce que nous
   FAISONS pour vous — sont regroupées sous une seule entrée SERVICES ; ce que
   le visiteur vient chercher par son nom (Gaming, Vente, Infogérance,
   Cybersécurité) reste au premier niveau.

   LE CRITÈRE N’EST PAS LA LARGEUR, C’EST LE POINTEUR (docs/59 §1, défaut 1).
   La v18 basculait sur `min-width: 1024px` en supposant qu’au-delà « il n’y a
   plus de doigt ». C’est faux : un iPad en paysage fait exactement 1024 px, une
   Surface 1368. Sur ces appareils la barre de bureau s’affichait, le survol
   n’existait pas, et un doigt posé sur « SERVICES ▾ » NAVIGUAIT au lieu
   d’ouvrir — Abonnements et Cours devenaient inatteignables depuis l’en-tête
   (services.html ne lie pas cours.html). Le déroulant est donc conditionné à
   `(hover: hover)`, et `(hover: none)` rend le burger à toutes les largeurs :
   le panneau y affiche le groupe DÉJÀ DÉPLIÉ, sans rien à ouvrir.

   Trois contextes, trois mécaniques :

   a) Pointeur grossier (doigt, stylet), quelle que soit la largeur : pas de
      sous-menu du tout. Le panneau du burger est une liste verticale plein
      écran ; le groupe s’y écrit en clair, un libellé non cliquable suivi de
      ses liens. Rien à ouvrir, donc rien qui puisse rester fermé sans script,
      et aucune cible de moins de 44 px (D-09). Le panneau lui-même s’ouvre en
      :target (D-03).

   b) Sous 1024 px : idem, le burger tient déjà le rôle.

   c) À partir de 1024 px AVEC un vrai survol : le sous-menu est révélé au
      survol ET à :focus-within. C’est :focus-within qui le rend utilisable au
      clavier sans une ligne de script — la tête du groupe est un vrai lien,
      donc focusable ; dès qu’elle prend le focus, la liste devient visible, et
      la tabulation continue naturellement dedans puis en sort. Aucun piège à
      focus : Tab avance toujours, Maj+Tab recule toujours. Échap referme le
      panneau quand JavaScript est là (attribut data-sousmenu, §24 bis) ; sans
      script, il se referme dès que le focus quitte le groupe.

   Pourquoi opacity et pointer-events, et JAMAIS visibility: hidden — un
   élément en visibility: hidden sort de l’arbre d’accessibilité ET de l’ordre
   de tabulation : le sous-menu serait alors introuvable au lecteur d’écran en
   mode navigation, et :focus-within ne pourrait jamais se déclencher puisque
   rien de caché ne peut prendre le focus. Ici la liste reste dans le document ;
   seule sa peinture est différée. Mouvement : opacity + translate, 150 ms.

   INTÉGRATION VISUELLE (docs/59 §2). Le panneau était une carte flottante —
   fond propre, bordure sur les quatre côtés, rayon 16 px partout, ombre portée
   --shadow-hover — ancrée au MILIEU de l’en-tête (mesuré : bas de la tête à
   107 px, bas de l’en-tête à 136 px), donc posée EN TRAVERS du filet de
   l’en-tête qu’elle interrompait. Trois décisions :

   1. Le panneau n’est plus posé sur l’en-tête, il en descend. Le groupe occupe
      toute la hauteur de la barre (align-self: stretch), donc `top: 100%` tombe
      exactement sur le bord bas de l’en-tête : le filet --shadow-header devient
      le bord haut du panneau. Plus de bordure haute, plus d’ombre portée — un
      panneau qui a besoin d’une ombre pour se détacher est mal posé. Il reste
      un filet --line sur trois côtés et le coin coupé --r-cut en bas à gauche,
      qui est la signature de forme du site (hero, cartes).
   2. Le texte du sous-menu s’aligne sur celui de la tête. Le décalage latéral
      (-20 px = rembourrage du panneau + rembourrage de la rangée) met la
      première lettre de « Dépannage » exactement sous celle de « SERVICES ».
   3. Un seul vocabulaire de survol dans tout l’en-tête. La rangée survolée
      reprend mot pour mot la signature de .header__link — couleur --accent-text
      et soulignement 2 px --accent à 6 px — au lieu du pavé --surface-tint,
      qui est un jeton de SECTION (crème en Privé, bleu pâle en Entreprise) et
      qui plaquait un bloc coloré dans un panneau blanc, discrètement en Privé
      et lourdement en Entreprise, juste à côté du switcher bleu.
   ========================================================= */

.nav-groupe { position: relative; display: flex; align-items: center; }
.nav-groupe__tete { display: inline-flex; align-items: center; gap: var(--sp-2); }
/* Chevron : marqueur de groupe, pas commande. Allégé (10 px, trait 1.75 au lieu
   de 2.25 posé en attribut HTML) et estompé au repos, il cesse de peser autant
   que le mot qu’il accompagne. */
.nav-groupe__chevron {
  width: 10px; height: 10px; flex: none;
  stroke-width: 1.75;
  opacity: .55;
  transition: rotate var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}

/* La page courante est marquée sur le lien précis du sous-menu ; la tête du
   groupe reprend la même signature visuelle pour que le visiteur sache dans
   quelle famille il se trouve, sans dupliquer aria-current dans la page. */
.nav-groupe:has([aria-current="page"]) > .nav-groupe__tete {
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--accent);
  text-underline-offset: 6px;
}

@media (min-width: 1024px) and (hover: hover) {
  /* La barre de navigation occupe toute la hauteur de l’en-tête, et le GROUPE
     aussi : sans align-self, `align-items: center` du parent le laissait haut
     de 22 px (v18), ce qui plaçait le panneau 29 px au-dessus du bord bas de
     l’en-tête et réduisait la zone de survol à la hauteur du texte. */
  .header__nav { align-self: stretch; display: flex; align-items: center; }
  .header__nav-group { height: 100%; }
  .nav-groupe { align-self: stretch; }
  .nav-groupe__tete { align-self: stretch; }

  .nav-groupe__liste {
    position: absolute; top: 100%; z-index: 60;
    /* décalage = filet + rembourrage du panneau + rembourrage de la rangée :
       le texte des sous-liens tombe pile sous le texte de la tête. C’est le
       TEXTE qui est aligné, pas la boîte — la liste prolonge le mot SERVICES,
       et le panneau déborde donc de 21 px à sa gauche. */
    left: calc(-1px - var(--sp-2) - var(--sp-3));
    min-width: 18rem;               /* « Tous nos services aux entreprises » tient sur une ligne */
    margin: 0; padding: var(--sp-2); list-style: none;
    background: var(--paper);
    border: 1px solid var(--line); border-top: 0;
    border-radius: 0 0 var(--r-md) var(--r-cut);
    opacity: 0; translate: 0 -4px; pointer-events: none;
    transition: opacity var(--t-fast) var(--ease), translate var(--t-fast) var(--ease);
  }
  /* ÉCARTÉ, essayé et mesuré : donner au panneau le verre translucide et flou
     de .header (§4) pour qu’il soit fait de la même matière que la barre. Le
     texte de la page traverse alors la liste et se mélange aux libellés (relevé
     à 1440 px sur abonnements.html défilée). Une barre peut être en verre — on
     ne lit rien à travers ; un panneau de navigation doit rester opaque. */
  .nav-groupe:hover > .nav-groupe__liste,
  .nav-groupe:focus-within > .nav-groupe__liste {
    opacity: 1; translate: 0 0; pointer-events: auto;
  }
  .nav-groupe:hover > .nav-groupe__tete .nav-groupe__chevron,
  .nav-groupe:focus-within > .nav-groupe__tete .nav-groupe__chevron { rotate: 180deg; opacity: 1; }

  /* §24 bis — Échap. Sans script, le panneau se referme quand le focus quitte
     le groupe, et c’est déjà correct. Avec script, main.js §5 pose
     data-sousmenu="ferme" : le panneau se referme SANS déplacer le focus, qui
     reste sur la tête (ARIA APG). L’attribut est retiré au premier Tab, au
     changement de focus ou au survol. */
  .nav-groupe[data-sousmenu="ferme"] > .nav-groupe__liste {
    opacity: 0; translate: 0 -4px; pointer-events: none;
  }
  .nav-groupe[data-sousmenu="ferme"] > .nav-groupe__tete .nav-groupe__chevron {
    rotate: none; opacity: .55;
  }
}

.nav-groupe__lien {
  display: flex; align-items: center; min-height: 44px;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-cut);
  font-size: var(--fs-small); font-weight: var(--fw-medium);
  color: var(--ink); text-decoration: none;
  text-wrap: balance;
  transition: color var(--t-fast) var(--ease);
}
.nav-groupe__lien:hover {
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--accent);
  text-underline-offset: 6px;
}
.nav-groupe__lien:focus-visible { box-shadow: var(--focus-ring); outline: none; }
/* Page courante : graisse + couleur, sans soulignement — le soulignement est
   réservé au survol, pour que les deux états ne se confondent pas. */
.nav-groupe__lien[aria-current="page"] { color: var(--accent-text); font-weight: var(--fw-semibold); }

/* ---- Pointeur grossier : le burger reprend la main, à TOUTE largeur ----
   docs/59 §1 défaut 1. Rien d’autre n’est déplacé : l’en-tête garde sa hauteur
   de 80 px et son logo complet au-dessus de 1024 px, seule la barre de liens
   cède la place au burger, dont le panneau affiche le groupe déjà déplié. */
@media (hover: none) {
  .header__nav { display: none; }
  .burger { display: flex; }
  .menu-mobile:target { display: block; }
}
@media (hover: none) and (min-width: 1024px) {
  /* l’en-tête fait 80 px ici, pas 64 : le panneau doit dégager davantage */
  .menu-mobile { padding-top: calc(80px + var(--sp-6)); }
  /* Sur une tablette en paysage, la liste ne doit pas s’étaler sur 1 200 px :
     une colonne, comme partout ailleurs sur le site. Le bouton Support, en
     .btn--block, s’y range du même coup. */
  .menu-mobile nav { max-width: 34rem; }
  .burger { flex: none; }
  /* cibles tactiles (D-09) : le switcher et la pilule Support gardent 44 px
     comme sous 1024 px, sans passer à l’icône seule — la place ne manque pas. */
  .switcher--compact { height: 52px; padding: 4px; }
  .switcher--compact::before { top: 4px; left: 4px; bottom: 4px; width: calc(50% - 4px); }
  .switcher--compact .switcher__seg { height: 44px; min-width: 44px; }
  .btn-support { height: 44px; }
  .banner__fermer { width: 44px; height: 44px; }
}

/* ---- Le même groupe dans le panneau mobile : déplié, sans commande ----
   docs/59 §2, décision 4 : « SERVICES » y était écrit exactement comme GAMING,
   VENTE ou CONTACT — même corps, même graisse, même casse — alors qu’il n’est
   PAS cliquable. Un libellé qui ressemble à un lien mort. Il devient une
   étiquette de section discrète (--fs-tiny, --ink-muted), et le filet vertical
   + le retrait de 24 px disparaissent : la hiérarchie est portée par le type
   (capitales 20 px pour le premier niveau, bas de casse 16 px pour le second),
   plus par du décor, et tout l’alignement gauche redevient unique. */
.menu-mobile__titre {
  margin: 0;
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  color: var(--ink-muted);
}
.menu-mobile__sous {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column;
  /* l’étiquette et sa liste forment UN bloc : 8 px entre elles ; la gouttière
     de 24 px du panneau (--sp-5) reste entre les blocs. */
  margin-top: calc(var(--sp-2) - var(--sp-5));
}
.menu-mobile__sous-lien {
  display: flex; align-items: center; min-height: 44px;
  font-size: var(--fs-body); font-weight: var(--fw-medium);
  color: var(--ink); text-decoration: none;
}
.menu-mobile__sous-lien:hover { color: var(--accent-text); }
.menu-mobile__sous-lien[aria-current="page"] {
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--accent);
  text-underline-offset: 6px;
}
/* Le panneau gagne trois lignes : sur un écran court (paysage, 320×568) la
   liste doit pouvoir défiler à l’intérieur du panneau plutôt que d’être
   coupée. Le verrou de défilement de la page (html.menu-ouvert, §22.2) reste
   entier : c’est le panneau qui défile, pas la page derrière. */
.menu-mobile { overflow-y: auto; overscroll-behavior: contain; }

/* Le panneau est en position: fixed, inset: 0 — il part donc du HAUT DE LA
   FENÊTRE, pendant que l’en-tête (z-index 50, au-dessus de lui) est poussé vers
   le bas par la bannière d’annonce. Son rembourrage haut, écrit en dur à
   64 + 32 px, ne dégageait alors que l’en-tête SANS bannière : mesuré à 390 px
   avec la bannière livrée, le bouton « Support » du panneau (96→144 px) passait
   sous l’en-tête (69→133 px) et devenait moitié inatteignable (docs/59 §1,
   défaut 5). Sans JavaScript il n’y a pas de bannière du tout — c’est
   banniere.js qui la dessine — donc la valeur en dur reste juste dans ce cas ;
   avec JavaScript, main.js §3 mesure le bas réel de l’en-tête à l’ouverture. */

/* =========================================================
   25. COURS — PAGE DE SURVOL ET FICHES (LOT-DESIGN-18 — docs/55)

   Composants repris de la maquette validée (maquettes-backoffice/css/
   vitrine-cours.css §8 à §12) et versés ici sans changement de valeurs :
   la maquette était déjà écrite sur les jetons du design system.

   `.cours-carte` : la carte de SURVOL. Sept informations au maximum. Tout ce
   qui sert à DÉCIDER vit sur la fiche du cours, jamais ici.
   `.fiche-*`, `.sessions`, `.places` : les blocs de la fiche d’un cours.
   ========================================================= */

/* ---- 25.0 Utilitaires et variantes de section utilisés par ces pages ---- */
.section--court { padding-block: var(--sp-7); }
.muted { color: var(--ink-muted); }
.fs-small { font-size: var(--fs-small); }
.nowrap { white-space: nowrap; }
.mt-5 { margin-top: var(--sp-5); }
.mb-0 { margin-bottom: 0; }
/* Largeur de lecture appliquée au TEXTE et pas au bloc (docs/45 §4) : le
   conteneur garde le MÊME bord gauche que le reste de la page, et borne ses
   enfants à une longueur de ligne lisible. */
.container.mesure :is(p, li) { max-width: var(--measure-body); }
.container.mesure > * { max-width: 46rem; }

/* ---- 25.1 La liste de survol ---- */
.cours-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-5); }
.cours-carte {
  position: relative;
  background: var(--paper); border: 1px solid var(--line);
  padding: var(--sp-6);
  display: flex; flex-direction: column; gap: var(--sp-4);
  border-radius: var(--r-lg) var(--r-lg) var(--r-lg) var(--r-cut);
  z-index: 0;
  transition: translate var(--t-med) var(--ease);
}
/* L’ombre de survol est posée sur ::before et révélée en opacity — composité,
   coût nul. Même écriture que .card (§9). */
.cours-carte::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  box-shadow: var(--shadow-hover);
  opacity: 0;
  transition: opacity var(--t-med) var(--ease);
  pointer-events: none;
}
/* Coin coupé en rotation, comme les pales du moulinet (docs/02 §5) */
.cours-carte:nth-child(4n+2) { border-radius: var(--r-lg) var(--r-lg) var(--r-cut) var(--r-lg); }
.cours-carte:nth-child(4n+3) { border-radius: var(--r-lg) var(--r-cut) var(--r-lg) var(--r-lg); }
.cours-carte:nth-child(4n)   { border-radius: var(--r-cut) var(--r-lg) var(--r-lg) var(--r-lg); }
.cours-carte:hover { translate: 0 -4px; }
.cours-carte:hover::before { opacity: 1; }
.cours-carte:has(a:focus-visible) { box-shadow: var(--focus-ring); }

.cours-carte__ref {
  margin: 0; font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--accent-text);
}
.cours-carte__titre { margin: 0; font-size: var(--fs-h3); }
/* Le titre EST le lien : une seule ancre par carte, et elle est descriptive
   (docs/07 §6 point 9 — jamais « en savoir plus » répété quatre fois). */
.cours-carte__titre a { color: var(--ink); text-decoration: none; }
.cours-carte__titre a::after { content: ""; position: absolute; inset: 0; }
.cours-carte:hover .cours-carte__titre a { color: var(--accent-text); }
.cours-carte__resume { margin: 0; color: var(--ink-muted); max-width: var(--measure-body); }

/* Ligne de faits : du texte, pas des étiquettes. Public visé · durée · prix. */
.faits {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: var(--sp-1) var(--sp-2);
  font-size: var(--fs-small); color: var(--ink-muted);
}
/* Le point médian termine l’élément qu’il suit : en repli mobile, une ligne ne
   commence jamais par un séparateur orphelin. */
.faits li:not(:last-child)::after { content: "·"; margin-left: var(--sp-2); }
.faits .faits__prix { color: var(--ink); font-weight: var(--fw-semibold); white-space: nowrap; }

.cours-carte__bas { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin: var(--sp-2) 0 0; }
.cours-liste + p { margin-top: var(--sp-6); }
.cours-carte__suite {
  margin-left: auto; font-size: var(--fs-small); font-weight: var(--fw-semibold);
  color: var(--link); display: inline-flex; align-items: center; gap: var(--sp-2);
}
.cours-carte__suite span { display: inline-block; transition: translate var(--t-fast) var(--ease); }
.cours-carte:hover .cours-carte__suite span { translate: 4px 0; }

/* ---- 25.2 La fiche d’un cours ---- */
.fiche-cle {
  display: grid; gap: var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-lg) var(--r-lg) var(--r-lg) var(--r-cut);
  background: var(--paper); padding: var(--sp-6);
}
.fiche-cle__faits { display: grid; gap: var(--sp-4); margin: 0; }
.fiche-cle__faits > div { display: grid; gap: var(--sp-1); }
.fiche-cle__faits dt {
  font-size: var(--fs-tiny); text-transform: uppercase;
  letter-spacing: var(--ls-label); color: var(--ink-muted);
}
.fiche-cle__faits dd { margin: 0; font-weight: var(--fw-medium); }

.duo { display: grid; gap: var(--sp-6); }
/* Les deux titres du duo sont des h2 : il n'y a pas de h2 au-dessus d'eux dans
   la section, et un h3 y ferait un saut de niveau (audit 25 D-13). Ils gardent
   la taille d'un titre de rang 3. */
.duo :is(h2, h3) { font-size: var(--fs-h4); margin-bottom: var(--sp-3); }
.duo ul { margin: 0; padding-left: var(--sp-5); color: var(--ink-muted); }
.duo li + li { margin-top: var(--sp-3); }

/* Objectifs d’apprentissage (docs/39 §4.6). Ce bloc n’est pas décoratif : il
   porte le troisième critère de l’AFC pour que le cours reste exclu du champ
   de la TVA (Info TVA 20, ch. 1.6). */
.objectifs { border-left: 2px solid var(--accent); padding-left: var(--sp-5); }

/* ---- 25.3 Séances et places restantes ---- */
.sessions { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }
.session {
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--paper); padding: var(--sp-5);
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
}
.session__quand { flex: 1 1 14rem; display: grid; gap: var(--sp-1); }
.session__date { font-weight: var(--fw-semibold); color: var(--ink); }
.session__lieu { font-size: var(--fs-small); color: var(--ink-muted); }
.session__action { margin-left: auto; }
.session--complete { background: var(--etat-neutre-bg); border-color: var(--line); }
.session--annulee { background: var(--etat-neutre-bg); }
.session--annulee .session__date { text-decoration: line-through; }

/* Compteur de places : pastille + libellé écrit, jamais la couleur seule */
.places {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3); border-radius: var(--r-pill);
  font-size: var(--fs-tiny); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-label);
  background: var(--etat-neutre-bg); color: var(--etat-neutre-text);
  white-space: normal; text-wrap: balance;
}
.places::before { content: ""; width: 8px; height: 8px; border-radius: var(--r-pill); background: currentColor; flex: none; }
.places--libre    { background: var(--etat-ok-bg);        color: var(--etat-ok-text); }
.places--derniere { background: var(--etat-attention-bg); color: var(--etat-attention-text); }
.places--derniere::before { border-radius: var(--r-cut); }   /* forme + couleur */
.places--complet  { background: var(--etat-neutre-bg);   color: var(--etat-neutre-text); }
.places--annulee  { background: var(--etat-alerte-bg);   color: var(--etat-alerte-text); }

/* ---- 25.4 Messages et encart ---- */
.message {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-5); border-radius: var(--r-md); font-size: var(--fs-small);
  background: var(--etat-info-bg); color: var(--etat-info-text);
  margin: 0 0 var(--sp-5);
}
.message svg { width: 20px; height: 20px; flex: none; margin-top: 2px; }
.message p { margin: 0 0 var(--sp-2); max-width: var(--measure-body); }
.message p:last-child { margin-bottom: 0; }
.message strong { font-weight: var(--fw-semibold); }
.message a { color: inherit; text-decoration: underline; text-underline-offset: 3px; font-weight: var(--fw-semibold); }
.message--attention { background: var(--etat-attention-bg); color: var(--etat-attention-text); }
.message--succes    { background: var(--etat-ok-bg);        color: var(--etat-ok-text); }

.encart--cours {
  border: 1px solid var(--line); border-left: 4px solid var(--accent);
  border-radius: var(--r-cut) var(--r-md) var(--r-md) var(--r-cut);
  background: var(--surface-tint); padding: var(--sp-5);
}
.encart--cours h2 { font-size: var(--fs-h4); }
.encart--cours p { margin: 0 0 var(--sp-4); color: var(--ink-muted); font-size: var(--fs-small); max-width: var(--measure-body); }
.encart--cours p:last-child { margin-bottom: 0; }

/* ---- 25.5 Récapitulatif « informations pratiques » ---- */
.recap { margin: 0; padding: 0; display: grid; gap: var(--sp-5); }
.recap > div { display: grid; grid-template-columns: 1fr; gap: var(--sp-1); }
.recap dt { font-size: var(--fs-tiny); text-transform: uppercase; letter-spacing: var(--ls-label); color: var(--ink-muted); }
.recap dd { margin: 0; font-weight: var(--fw-medium); }

/* ---- 25.6 Carte d’appel « Cours » de la page d’accueil ----
   Elle ferme la grille de services sur toute sa largeur : une septième carte
   d’un tiers de largeur aurait laissé deux trous dans la dernière rangée. */
.card--pleine { grid-column: 1 / -1; }
/* Elle n'a pas de photo : la règle « carte sans photo dans une rangée de cartes
   média » (§9) pousse son icône vers le bas par un margin-top: auto. Ici l'icône
   OUVRE la carte. Le sélecteur reprend la même spécificité (4 classes) que la
   règle qu'il annule, et il est écrit après elle. */
.cards .card--pleine:not(.card--media) .card__icon { margin-top: 0; }
@media (min-width: 768px) {
  .card--pleine { flex-direction: row; align-items: center; gap: var(--sp-6); }
  /* L'icône s'aligne sur la PREMIÈRE ligne de texte, pas sur le centre du bloc :
     centrée, elle tombait entre le titre et le paragraphe et paraissait basse. */
  .cards .card--pleine:not(.card--media) .card__icon { margin: 0; align-self: flex-start; }
  .card--pleine .card__corps { flex: 1 1 auto; }
  .card--pleine .card__link { margin-top: 0; flex: none; }
}
.card--pleine .card__corps h3 { margin-bottom: var(--sp-2); }
.card--pleine .card__corps p { margin-bottom: 0; }

/* ---- 25.7 Responsive ---- */
@media (min-width: 600px) {
  .recap > div { grid-template-columns: 12rem 1fr; gap: var(--sp-4); align-items: baseline; }
  .fiche-cle__faits { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-5); }
}
@media (min-width: 900px) {
  /* Deux cours par rangée : les quatre cours tiennent dans un écran et demi. */
  .cours-liste { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .duo { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-7); }
  .fiche-cle { grid-template-columns: 1fr auto; align-items: center; }
  .fiche-cle__faits { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .fiche-cle .cta-group { margin-block: 0; }
}

/* ---- 25.8 Mouvement réduit ---- */
@media (prefers-reduced-motion: reduce) {
  .cours-carte, .cours-carte::before, .cours-carte__suite span,
  .nav-groupe__liste, .nav-groupe__chevron { transition: none; }
  .cours-carte:hover { translate: none; }
  .nav-groupe__liste { translate: none; }
  .nav-groupe:hover > .nav-groupe__liste,
  .nav-groupe:focus-within > .nav-groupe__liste { translate: none; }
  .nav-groupe:hover > .nav-groupe__tete .nav-groupe__chevron,
  .nav-groupe:focus-within > .nav-groupe__tete .nav-groupe__chevron { rotate: none; }
  /* fermeture par Échap : elle non plus ne doit rien déplacer */
  .nav-groupe[data-sousmenu="ferme"] > .nav-groupe__liste { translate: none; }
}
