/*!
 * ═══════════════════════════════════════════════════════════════════════════
 *  ADMINISPHÈRE — Site vitrine
 *  Assistante administrative & RH externalisée pour TPE/PME
 * ───────────────────────────────────────────────────────────────────────────
 *  Fichier        : assets/css/tokens.v1.9.0.3.css
 *  Rôle           : Source unique de vérité du design system.
 *                   AUCUNE règle de mise en page ici : uniquement des
 *                   variables. Modifier une valeur ici la propage à
 *                   l'intégralité du site.
 *  Développé par  : Adminisphère
 *  Version        : 1.9.0.3 (tablette portrait : mises au point des
 *                   photos des services, de la FAQ et du contact en
 *                   bandeau, format 21:9 du bandeau de la FAQ)
 *                   1.9.0.2 : (tablette portrait : format et mises au point
 *                   des photos en bandeau, hauteur du héros ; libellé
 *                   court de la pastille d'en-tête ; décalage du trait du
 *                   sur-titre ; téléphone : apparitions de 28 et 36 px,
 *                   cible du résumé repliable --fold-summary-min-height)
 *                   1.9.0 : (version mobile de l'accueil : rythme compact,
 *                   photos recadrées ou en médaillon, carrousels à points,
 *                   typographie téléphone — titres 30/24 px, interligne 1,5)
 *                   1.8.0.2 : (ronds flottants plus transparents : voile
 *                   propre --glass-bg-frosted-sm, la carte garde le sien)
 *                   1.8.0.1 : (verre toujours clair : voile givré commun à la
 *                   carte et aux ronds --glass-bg-frosted, AA sur tout
 *                   fond, et intervalle blanc de l'anneau de focus
 *                   --focus-ring-gap-color)
 *                   1.8.0 : (recette de verre commune --glass-*, @property
 *                   --glass-tone, variantes -sm des ronds, pile --quick-*)
 *                   1.7.0 : (carte d'invitation aux Conseils : bloc --invite-*,
 *                   verre « liquid glass » adaptatif, clair ou fumé)
 *                   1.6.0 : (page « Conseils » : illustrations des articles,
 *                   cartes repliables, signature d'Ana)
 *                   1.5.0 : barre d'appel collante, hauteur du héros compact
 * ═══════════════════════════════════════════════════════════════════════════
 *
 *  SOMMAIRE
 *  ├── 1. Palette de marque .......... couleurs brutes, non contextuelles
 *  ├── 2. Rôles sémantiques .......... à quoi sert chaque couleur
 *  ├── 3. Typographie ................ familles, échelle, graisses
 *  ├── 4. Espacements ................ échelle d'espacement + rythme vertical
 *  ├── 5. Formes ..................... rayons, traits, ombres
 *  ├── 6. Mouvement .................. durées, courbes, décalages, échelles
 *  ├── 7. Structure .................. largeurs, seuils de grille, z-index
 *  ├── 8. Composants ................. variables propres à chaque composant
 *  └── 9. Variables animées .......... déclarations @property
 *
 *  RÈGLE D'OR
 *  Une couleur, une durée ou une taille ne doit JAMAIS être écrite en dur
 *  dans `adminisphere.v1.9.0.3.css`. Tout passe par une variable définie ci-dessous.
 *  C'est ici, et seulement ici, que des valeurs littérales sont autorisées.
 */

:root {
  /* ═══════════════════════════════════════════════════════════════════════
     1. PALETTE DE MARQUE
     Les teintes brutes de l'identité Adminisphère.
     On ne les utilise pas directement dans les composants : on passe par
     les rôles sémantiques (section 2). Cela permet de retoucher la marque
     sans relire tout le CSS.
     ═══════════════════════════════════════════════════════════════════════ */

  /* --- Vert d'eau : couleur d'accentuation de la marque ------------------ */
  --brand-mint-050: #eaf6f3;  /* fonds très clairs, survols discrets        */
  --brand-mint-100: #d3ece6;  /* bordures douces, séparateurs teintés       */
  --brand-mint-300: #8fd3c4;  /* décor, dégradés                            */
  --brand-mint-500: #4ab8a4;  /* ★ VERT DE MARQUE — boutons, icônes, traits */
  --brand-mint-600: #3aa08d;  /* survol des surfaces vert de marque         */
  --brand-mint-800: #206b5e;  /* ★ texte vert sur fond clair (contraste AA) */

  /* --- Bleu nuit : couleur structurante de la marque --------------------- */
  --brand-navy-900: #001025;  /* pied de page, fonds les plus profonds      */
  --brand-navy-800: #011633;  /* ★ BLEU DE MARQUE — titres, barre haute     */
  --brand-navy-700: #0b2545;  /* cartes sombres, survols sur fond sombre    */
  --brand-navy-500: #0e2137;  /* texte courant                              */

  /* --- Neutres ----------------------------------------------------------- */
  --brand-grey-050: #f6f9f9;  /* fonds de section alternés                  */
  --brand-grey-100: #eef2f4;  /* fonds de champs, aplats                    */
  --brand-grey-200: #e3e8ec;  /* ★ filets décoratifs (jamais un contour     */
                              /*   de champ : trop clair, voir §2)          */
  --brand-grey-400: #7d8b99;  /* ★ contour des champs et boutons (AA 1.4.11)*/
  --brand-grey-450: #66737f;  /* ★ texte indicatif : plus clair que le texte */
                              /*   secondaire, mais lisible (AA, voir §2)    */
  --brand-grey-500: #5d6b7a;  /* ★ texte secondaire                         */
  --brand-white: #ffffff;
  --brand-black: #000000;     /* masques et impression uniquement           */

  /* --- Couleurs d'état (formulaires, messages) ---------------------------
     Ces trois tons sont en réserve, mais destinés à porter du texte : ils
     sont donc tenus au seuil AA sur les deux fonds où un message peut
     apparaître.

       brand-success sur surface-page .............  5.24:1  (AA)
       brand-success sur surface-alt ..............  4.95:1  (AA)
       brand-warning sur surface-page .............  5.18:1  (AA)
       brand-warning sur surface-alt ..............  4.89:1  (AA)
       brand-error sur surface-page ...............  6.54:1  (AA)
       brand-error sur surface-alt ................  6.17:1  (AA)

     L'ancien ton d'avertissement (#b26a00) plafonnait à 4.24:1 sur blanc,
     sous le seuil AA. Il a été assombri avant d'être utilisé nulle part. */
  --brand-success: #1e7a5f;
  --brand-warning: #9e5e00;
  --brand-error: #b3261e;

  /* ═══════════════════════════════════════════════════════════════════════
     2. RÔLES SÉMANTIQUES
     C'est CE QUE les composants consomment. On nomme l'usage, pas la teinte.
     Repeindre le site = réaffecter ces quelques lignes.
     ═══════════════════════════════════════════════════════════════════════ */

  /* --- Surfaces (fonds) --------------------------------------------------- */
  --surface-page: var(--brand-white);         /* fond général               */
  --surface-alt: var(--brand-grey-050);       /* section alternée           */
  --surface-raised: var(--brand-white);       /* cartes posées sur le fond  */
  /* Réserve, volontairement sans usage. L'intention d'origine était d'en
     faire le fond des champs de saisie : elle a été écartée. Les champs sont
     posés sur le gris du formulaire, et un champ plus SOMBRE que son cadre
     se lit comme désactivé. Ils restent donc blancs (--surface-raised).
     Ne pas rebrancher ce token sur .field__control. */
  --surface-sunken: var(--brand-grey-100);
  --surface-inverse: var(--brand-navy-800);   /* blocs sombres              */
  --surface-inverse-deep: var(--brand-navy-900);
  --surface-accent: var(--brand-mint-500);    /* aplats verts               */
  --surface-accent-soft: var(--brand-mint-050);

  /* --- Voiles blancs ------------------------------------------------------
     Sur un fond sombre ou photographique, un voile translucide s'adapte à
     ce qu'il recouvre là où une teinte figée jurerait. Quatre paliers
     suffisent à couvrir tous les états du site. */
  --overlay-white-faint: rgba(255, 255, 255, 0.1);   /* aplat au repos      */
  --overlay-white-soft: rgba(255, 255, 255, 0.12);   /* survol discret      */
  --overlay-white-hover: rgba(255, 255, 255, 0.14);  /* survol appuyé       */
  --overlay-white-sheen: rgba(255, 255, 255, 0.28);  /* reflet de balayage  */

  /* --- Textes -------------------------------------------------------------
     Contrastes calculés selon la formule WCAG 2.1, jamais estimés à l'œil.
     Les couleurs translucides sont composées sur leur fond AVANT mesure :
     c'est la teinte réellement affichée qui compte.

     IMPORTANT : FORMAT CONTRACTUEL — `tests/contrastes.js` relit ces lignes et refait
     chaque calcul. La grammaire « rôle sur surface .... N.NN:1 » ne doit pas
     changer sans adapter le banc, qui compte aussi les lignes reconnues et
     échoue si elles se mettent à lui échapper.

       text-strong sur surface-page ............... 18.04:1  (AAA)
       text-strong sur surface-alt ................ 17.04:1  (AAA)
       text-body sur surface-page ................. 16.26:1  (AAA)
       text-body sur surface-alt .................. 15.36:1  (AAA)
       text-muted sur surface-page ................  5.46:1  (AA)
       text-muted sur surface-alt .................  5.15:1  (AA)
       text-muted sur surface-accent-soft .........  4.93:1  (AA)
       text-placeholder sur surface-raised ........  4.86:1  (AA)
       text-accent sur surface-page ...............  6.31:1  (AA)
       text-accent sur surface-alt ................  5.96:1  (AA)
       text-accent sur surface-accent-soft ........  5.70:1  (AA)
       text-on-accent sur surface-accent ..........  7.46:1  (AAA)
       text-on-dark sur surface-inverse ........... 18.04:1  (AAA)
       text-on-dark sur surface-inverse-deep ...... 19.08:1  (AAA)
       text-on-dark-muted sur surface-inverse ..... 10.11:1  (AAA)
       text-on-dark-muted sur surface-inverse-deep .. 10.53:1  (AAA)
       brand-mint-300 sur surface-inverse ......... 10.55:1  (AAA)
       brand-mint-300 sur surface-inverse-deep .... 11.16:1  (AAA)
     ---------------------------------------------------------------------- */
  --text-strong: var(--brand-navy-800);       /* titres                     */
  --text-body: var(--brand-navy-500);         /* paragraphes                */
  --text-muted: var(--brand-grey-500);        /* légendes, texte secondaire */
  --text-accent: var(--brand-mint-800);       /* liens et sur-titres verts  */
  /* Réserve depuis la suppression du formulaire de contact : plus aucun
     champ de saisie dans la page. Conservé — avec son ratio vérifié — pour
     le jour où un champ réapparaîtra, et parce que la table de contrastes
     ci-dessus reste vraie et continue d'être contrôlée par le banc. */
  --text-placeholder: var(--brand-grey-450);
  --text-on-dark: var(--brand-white);
  --text-on-dark-muted: rgba(255, 255, 255, 0.74);
  --text-on-accent: var(--brand-navy-800);    /* texte posé sur le vert     */

  /* --- Traits et bordures ---------------------------------------------------
     Deux familles à ne pas confondre.

     `--border-subtle` DÉCORE : séparateurs, filets entre étapes, contour des
     cartes et des encadrés. Rien de ce qu'il délimite n'a besoin d'être vu
     pour comprendre la page, le critère de contraste ne s'y applique donc pas.

     `--border-control` DÉLIMITE UN COMMANDE : champ de saisie, bouton menu,
     bouton à contour. Là, le trait est la SEULE chose qui dit « on écrit
     ici » ou « ceci se clique ». WCAG 2.1 SC 1.4.11 impose 3:1 minimum.
     Contrastes sur les deux fonds où ces contours apparaissent réellement :

       border-control sur surface-page ............  3.49:1  (SC 1.4.11)
       border-control sur surface-alt .............  3.29:1  (SC 1.4.11)

       · surface-page : le champ de saisie, dont le fond est surface-raised
         donc blanc, et le bouton du menu posé sur l'en-tête blanc
       · surface-alt  : CAS LE PLUS DÉFAVORABLE — le bouton à contour de la
         colonne des services, et le pourtour du formulaire
     C'est la marge de 0.29 du second cas qu'il faut protéger : éclaircir
     --brand-grey-400 la consommerait avant même de toucher le premier.
     ---------------------------------------------------------------------- */
  --border-subtle: var(--brand-grey-200);
  --border-control: var(--brand-grey-400);
  --border-accent: var(--brand-mint-500);
  --border-on-dark: rgba(255, 255, 255, 0.16);

  /* --- États de survol dérivés --------------------------------------------
     Le survol se CALCULE depuis la couleur de marque au lieu d'être une
     seconde teinte figée : retoucher le vert retouche automatiquement son
     survol, et l'écart perçu reste constant. Repli explicite en fin de
     fichier pour les navigateurs sans color-mix(). */
  --surface-accent-hover: color-mix(in srgb, var(--brand-mint-500) 86%, var(--brand-navy-900));
  --surface-inverse-hover: color-mix(in srgb, var(--brand-navy-800) 88%, var(--brand-mint-300));

  /* --- Anneau de focus (accessibilité clavier) ----------------------------
     Un indicateur de focus est un objet graphique porteur d'information :
     WCAG 2.1 SC 1.4.11 lui impose 3:1 sur ce qui l'entoure. Le vert foncé
     tient largement sur fond clair, mais tombait à 2.86:1 sur le bleu nuit
     du héros, du bandeau d'appel et du pied de page — autant dire invisible
     là où il compte. D'où DEUX tons, et non un seul.
     Les blocs sombres réaffectent --focus-ring-color au ton clair : tous
     leurs descendants en héritent, sans qu'aucun composant n'ait à savoir
     sur quel fond il a été posé.

     CE QUI DÉCIDE DU TON, C'EST L'ARRIÈRE-PLAN, PAS L'ÉLÉMENT.
     --focus-ring-offset étant positif, l'anneau se pose HORS de l'élément :
     il touche ce qu'il y a DERRIÈRE lui, jamais son propre aplat. Un bouton
     sombre posé sur la page claire garde donc le ton foncé (l'anneau est
     peint sur du blanc) — le basculer le ferait tomber à 1.71:1. La bascule
     ne concerne que ce qui est posé SUR du sombre.

       focus-ring-color sur surface-page ..........  6.31:1  (SC 1.4.11)
       focus-ring-color sur surface-alt ...........  5.96:1  (SC 1.4.11)
       focus-ring-color sur surface-inverse-deep ..  3.02:1  (SC 1.4.11)
       focus-ring-color-on-dark sur surface-inverse .. 10.55:1  (SC 1.4.11)
       focus-ring-color-on-dark sur surface-inverse-deep .. 11.16:1  (SC 1.4.11)
       border-control-focus sur surface-page ......  6.31:1  (SC 1.4.11)
       border-control-focus sur surface-alt .......  5.96:1  (SC 1.4.11)

     La troisième ligne est LA MARGE LA PLUS MINCE DE TOUT LE SYSTÈME : 0.02
     au-dessus du seuil. C'est le bouton « retour en haut », fixé en bas de
     l'écran, quand le défilement l'amène par-dessus le bandeau d'appel ou le
     pied de page. Il est le seul élément focalisable à survoler ainsi des
     fonds de clarté opposée, donc le seul dont l'anneau ne peut pas être
     choisi une fois pour toutes. Assombrir --brand-mint-800 ou éclaircir
     --brand-navy-900, même d'un cran, consomme cette marge.

     Depuis 1.8.0.1 (verre toujours clair), les ronds flottants ne
     choisissent plus de ton : leur anneau vert foncé est doublé, côté
     intérieur, d'un intervalle blanc opaque qui remplit l'écart de
     --focus-ring-offset (de même pour les commandes de la carte, dont
     l'anneau déborde de ses coins arrondis). L'un des deux traits
     contraste toujours avec la page : le vert foncé avec un fond clair (6.31 contre 1 sur le blanc),
     le blanc avec un fond sombre (19.08 contre 1 sur le bleu nuit profond,
     21 sur du noir) ; et les deux contrastent entre eux à 6.31 contre 1,
     quel que soit ce qui passe dessous.
     ---------------------------------------------------------------------- */
  --focus-ring-color: var(--brand-mint-800);
  --focus-ring-color-on-dark: var(--brand-mint-300);
  --focus-ring-width: 3px;
  --focus-ring-offset: 3px;
  /* Intervalle de l'anneau double des ronds flottants (voir ci-dessus) */
  --focus-ring-gap-color: var(--brand-white);
  /* Halo vert des champs de saisie : un anneau qui ne déplace rien */
  --focus-ring-glow: rgba(74, 184, 164, 0.22);
  /* Réserve avec le formulaire : ce halo n'habillait que le focus d'un champ
     de saisie. Il reste défini, ainsi que --focus-ring-glow dont il dépend. */
  --focus-glow: 0 0 0 var(--focus-ring-width) var(--focus-ring-glow);
  /* Bordure du champ au moment de la saisie. Le vert de marque n'atteint
     que 2.42:1 : il signalait le focus par une teinte que l'œil distingue
     mal du gris au repos. Le vert foncé, lui, tranche nettement. */
  /* Également passé en réserve avec le formulaire. --border-control, lui,
     reste bien en service : il délimite le bouton du menu et le bouton à
     contour. Ne pas les confondre au moment d'un nettoyage. */
  --border-control-focus: var(--brand-mint-800);

  /* --- Impression ---------------------------------------------------------- */
  --print-ink: var(--brand-black);
  --print-paper: var(--brand-white);

  /* ═══════════════════════════════════════════════════════════════════════
     3. TYPOGRAPHIE
     Une seule famille : Inter (variable, auto-hébergée, sous-ensemble latin).
     L'échelle est fluide : chaque taille s'adapte seule entre mobile et
     grand écran via clamp(). Aucun media query typographique nécessaire.
     ═══════════════════════════════════════════════════════════════════════ */

  --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, sans-serif;

  /* Graisses */
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-black: 800;

  /* Échelle fluide — min à 360px de large, max à 1280px */
  --text-xs: 0.78rem;                            /* mentions légales        */
  --text-sm: 0.875rem;                           /* légendes, méta          */
  --text-base: 1rem;                             /* corps de texte          */
  --text-lg: clamp(1rem, 0.95rem + 0.3vw, 1.15rem);      /* chapô           */
  --text-xl: clamp(1.15rem, 1.05rem + 0.5vw, 1.4rem);    /* titre de carte  */
  --text-2xl: clamp(1.4rem, 1.2rem + 1vw, 1.9rem);       /* h3 de section   */
  --text-3xl: clamp(1.75rem, 1.35rem + 1.9vw, 2.75rem);  /* h2              */
  /* Le plafond du h1 est dicté par la seule contrainte que le titre du héros
     ne peut pas négocier : tenir sur les deux lignes voulues, à l'intérieur
     de --width-hero-content (44rem, soit 704 px).
     À 3.6rem, « sans embaucher personne. » réclamait 741 px pour 704
     disponibles. Le titre repassait donc à trois lignes dès 1024 px de large
     — « personne. » seul sur la dernière — et aucun découpage n'y pouvait
     rien : les deux moitiés réunies mesurent 1421 px, soit plus que deux
     fois 704. Ce n'était pas le <br> qui échouait, c'était la taille.
     À 3.3rem la ligne la plus longue mesure 679 px : deux lignes tenues de
     640 px à 1920 px, avec 25 px de marge et un écart entre lignes de 8 %. */
  --text-4xl: clamp(2.1rem, 1.4rem + 3.2vw, 3.3rem);     /* h1              */
  --text-display: clamp(2.4rem, 1.6rem + 3.8vw, 3.4rem); /* grands chiffres */

  /* Interlignes */
  --leading-tight: 1.15;   /* titres          */
  --leading-snug: 1.4;     /* sous-titres     */
  --leading-normal: 1.65;  /* corps de texte  */

  /* Interlettrages */
  --tracking-tight: -0.02em;  /* titres : resserre pour une allure premium */
  --tracking-wide: 0.06em;    /* sur-titres en capitales                   */

  /* Longueur de ligne confortable (~70 caractères) */
  --measure: 65ch;
  --measure-narrow: 46ch;

  /* ═══════════════════════════════════════════════════════════════════════
     4. ESPACEMENTS
     Échelle géométrique basée sur 4px. Les composants n'utilisent QUE
     ces paliers : la cohérence verticale du site en découle.
     ═══════════════════════════════════════════════════════════════════════ */

  --space-3xs: 0.25rem;   /*  4px */
  --space-2xs: 0.5rem;    /*  8px */
  --space-xs: 0.75rem;    /* 12px */
  --space-sm: 1rem;       /* 16px */
  --space-md: 1.5rem;     /* 24px */
  --space-lg: 2rem;       /* 32px */
  --space-xl: 3rem;       /* 48px */
  --space-2xl: 4rem;      /* 64px */
  --space-3xl: 6rem;      /* 96px */

  /* Respiration verticale d'une section, fluide selon la largeur d'écran */
  --space-section: clamp(3.5rem, 2rem + 6vw, 7rem);
  /* Marge intérieure latérale de la page */
  --space-gutter: clamp(1.25rem, 0.5rem + 3vw, 2.5rem);

  /* --- Espacements fluides -------------------------------------------------
     Gouttières et marges intérieures qui grandissent avec l'écran, bornées
     par deux paliers de l'échelle ci-dessus. Les avoir nommés ici évite de
     semer des vitesses de croissance différentes dans chaque composant. */
  --space-fluid-sm: clamp(var(--space-2xs), 1.6vw, var(--space-md));   /* menu principal        */
  --space-fluid-md: clamp(var(--space-md), 3.5vw, var(--space-lg));    /* intérieur d'un bloc   */
  /* LA GOUTTIÈRE DE TOUTES LES PAIRES COLONNE-TEXTE / COLONNE-IMAGE.
     C'était la gouttière interne de la section « Méthode ». Elle est
     devenue celle de toutes les mises en colonnes de la page — division
     principale, services, FAQ, contact — qui employaient jusqu'ici trois
     valeurs différentes : 64 px, 48 px et 32 px, sans qu'aucune règle ne
     dise laquelle pour quoi. Le client voyait « trop de blanc entre les
     deux blocs » : il voyait les deux premières.
     32 px EST UN PLANCHER TENU, PAS UNE VALEUR CHOISIE. L'interligne du
     texte courant mesure 26,4 px (16 px × 1,65) ; une gouttière doit rester
     au-dessus, faute de quoi l'œil saute d'une colonne à l'autre au lieu de
     revenir à la ligne. 32 px passe donc, et 24 px ne passerait qu'entre
     un texte et une IMAGE, dont le bord est déjà une frontière — ce n'est
     pas le cas de toutes les paires, on ne descend pas. */
  --space-fluid-lg: clamp(var(--space-md), 4vw, var(--space-lg));      /* gouttière de colonnes */
  /* Réserve : plus aucune mise en colonnes ne l'emploie depuis que la
     gouttière a été unifiée. Conservé — il reste le palier au-dessus, le
     jour où une division devra franchement se distinguer des autres. */
  --space-fluid-xl: clamp(var(--space-md), 4vw, var(--space-xl));
  --space-fluid-2xl: clamp(var(--space-lg), 4vw, var(--space-xl));     /* intérieur de bandeau  */
  /* Réserve, comme --space-fluid-xl : la division principale a rejoint la
     gouttière commune. C'était le plus large des trois écarts (64 px), et
     donc le premier que le client a désigné. */
  --space-fluid-3xl: clamp(var(--space-lg), 5vw, var(--space-2xl));
  --space-band-y: clamp(var(--space-2xl), 9vw, var(--space-3xl));      /* bandeau d'appel       */
  --space-footer-y: clamp(var(--space-xl), 6vw, var(--space-2xl));     /* haut du pied de page  */
  /* Respiration resserrée des sections de l'accueil sur téléphone (sous
     48 rem). --space-section y vaut déjà son plancher, 56 px : c'est le
     plancher lui-même qui était trop large pour un écran de 667 px de haut,
     où deux bords de section consommaient 112 px de blanc. 40 px gardent
     une respiration nette au-dessus de l'interligne du texte courant
     (26,4 px), sans laisser l'écran entier à une transition. */
  --space-section-compact: 2.5rem;     /* 40px */

  /* ═══════════════════════════════════════════════════════════════════════
     5. FORMES — rayons, traits, ombres
     La signature visuelle d'Adminisphère : des angles asymétriques
     (un coin très arrondi en diagonale) repris du logo.
     ═══════════════════════════════════════════════════════════════════════ */

  --radius-xs: 6px;
  --radius-sm: 10px;
  --radius-md: 18px;
  --radius-lg: 32px;
  --radius-xl: 64px;
  --radius-pill: 999px;
  /* Grande courbe des bandeaux pleine largeur */
  --radius-sweep: clamp(48px, 12vw, 160px);

  /* Combinaison asymétrique signature — à appliquer telle quelle */
  --radius-signature: var(--radius-sm) var(--radius-lg) var(--radius-sm) var(--radius-lg);
  --radius-signature-lg: var(--radius-lg) var(--radius-xl) var(--radius-lg) var(--radius-xl);

  /* --- Épaisseurs de trait ------------------------------------------------
     Une échelle unique pour TOUS les filets du site : bordures, soulignés,
     barres du menu, contours de chiffres. Épaissir la marque d'un cran se
     fait ici. */
  --stroke-hairline: 1px;    /* bordures et séparateurs discrets           */
  --stroke-thin: 1.5px;      /* contour des grands chiffres d'étape        */
  --stroke-base: 2px;        /* traits de marque : soulignés, burger, chevron */
  --stroke-thick: 4px;       /* barre latérale de citation                 */
  --icon-stroke-width: 1.75; /* épaisseur des tracés du sprite SVG         */

  /* Halo vert commun aux effets d'arrivée et de survol. Un dégradé radial
     plutôt qu'un aplat : il s'éteint sur ses bords et ne laisse pas de
     contour net en s'agrandissant. */
  --halo-accent: radial-gradient(circle, var(--surface-accent) 0%, transparent 68%);

  /* Ombres — teintées bleu nuit plutôt que noires, plus douces à l'œil */
  --shadow-xs: 0 2px 6px -2px rgba(1, 22, 51, 0.12);
  --shadow-sm: 0 8px 20px -12px rgba(1, 22, 51, 0.22);
  --shadow-md: 0 18px 45px -22px rgba(1, 22, 51, 0.28);
  --shadow-lg: 0 32px 70px -30px rgba(1, 22, 51, 0.4);
  --shadow-accent: 0 14px 30px -14px rgba(74, 184, 164, 0.65);

  /* ═══════════════════════════════════════════════════════════════════════
     6. MOUVEMENT
     Toutes les animations du site puisent ici. Ralentir ou accélérer
     l'ensemble du site = changer --motion-scale.
     ═══════════════════════════════════════════════════════════════════════ */

  --motion-scale: 1;  /* multiplicateur global (0.5 = deux fois plus vif)   */

  --duration-instant: calc(120ms * var(--motion-scale));  /* micro-retours  */
  --duration-fast: calc(220ms * var(--motion-scale));     /* survols        */
  --duration-base: calc(380ms * var(--motion-scale));     /* transitions UI */
  --duration-slow: calc(650ms * var(--motion-scale));     /* apparitions    */
  --duration-slower: calc(950ms * var(--motion-scale));   /* entrées héros  */

  /* Durées d'apparition — le temps qu'un élément met à « arriver ».
     Plus longues que les durées d'interaction : on regarde une arrivée,
     on ne l'actionne pas. */
  --duration-reveal: calc(760ms * var(--motion-scale));  /* arrivée d'un bloc */
  --duration-sweep: calc(900ms * var(--motion-scale));   /* balayage de titre */
  --duration-trace: calc(820ms * var(--motion-scale));   /* filet qui se trace */

  /* Durées longues composées — décor uniquement, jamais d'interaction */
  --duration-hero-zoom: calc(var(--duration-slower) * 22); /* zoom du héros */
  --duration-pulse: calc(var(--duration-slower) * 3);      /* battement     */

  /* Courbes d'accélération */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);        /* sortie franche      */
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);     /* aller-retour        */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);  /* léger rebond        */
  --ease-linear: linear;  /* jauges et boucles : progression proportionnelle */

  /* Décalage entre deux éléments d'une même série (effet cascade) */
  --stagger-step: calc(90ms * var(--motion-scale));

  /* --- Amortissement de la cascade -----------------------------------------
     Le script pose un retard proportionnel au rang de l'élément (90 ms par
     cran). Sur une série courte c'est juste ; sur six questions de FAQ la
     dernière attendait 450 ms avant même de commencer à paraître, et n'était
     lisible qu'au bout de trois quarts de seconde. Un retard strictement
     proportionnel finit toujours par produire un traînard.
     On le comprime, puis on le plafonne : le rythme du début est conservé,
     la queue de la série ne décroche plus. */
  --reveal-delay-damping: 0.7;
  --reveal-delay-max: calc(300ms * var(--motion-scale));

  /* --- Amplitude des apparitions au défilement -----------------------------
     Un élément ne doit pas se contenter d'apparaître : il vient de quelque
     part. D'où une amplitude franche, une légère bascule dans la profondeur
     et un retrait d'échelle. Tout retombe à l'identité en mouvement réduit,
     et l'opacité, elle, ne dépend d'aucune de ces valeurs : le texte reste
     lisible quoi qu'il arrive. */
  --reveal-shift: 52px;         /* montée ou descente                       */
  --reveal-shift-x: 76px;       /* glissement latéral                       */
  --reveal-zoom: 0.9;           /* variante « zoom »                        */
  --reveal-zoom-soft: 0.97;     /* retrait discret des autres variantes     */
  --reveal-tilt: 6deg;          /* bascule dans la profondeur               */
  --reveal-perspective: 1200px; /* profondeur du point de fuite             */

  /* --- Découpes animées ----------------------------------------------------
     `clip-path` permet de dévoiler un titre ou un visuel sans toucher à la
     mise en page : rien ne bouge autour, seul le masque se déplace.
     Le débord en em évite de rogner les jambages et les accents. */
  --clip-title-hidden: inset(0 105% 0 -0.14em);
  --clip-title-shown: inset(0 -0.14em 0 -0.14em);
  --clip-wipe-hidden: inset(0 100% 0 0);
  --clip-wipe-shown: inset(0 0 0 0);

  /* --- Micro-déplacements --------------------------------------------------
     L'échelle des petits décalages d'interface (survols, entrées, bascules).
     Les avoir groupés ici évite les « 3px ici, 5px là » qui font vieillir
     une interface. */
  --shift-3xs: 2px;   /* remontée des pastilles sociales          */
  --shift-xs: 4px;    /* flèches, liens qui avancent au survol    */
  --shift-md: 12px;   /* état initial du bouton retour en haut    */
  --shift-lg: 16px;   /* entrée de la modale                      */
  --shift-xl: 24px;   /* montée d'entrée du héros                 */

  /* --- Facteurs d'échelle ---------------------------------------------------
     Regroupés pour que l'intensité des effets reste homogène d'un
     composant à l'autre. */
  --scale-press: 0.985;    /* enfoncement au clic                        */
  --scale-enter: 0.96;     /* état initial d'une entrée douce            */
  --scale-enter-deep: 0.9; /* état initial d'une entrée marquée          */
  --scale-hover: 1.04;     /* zoom de survol des visuels                 */
  --scale-tilt: 1.06;      /* pastille icône qui s'anime avec sa carte   */
  --scale-pulse: 1.07;     /* battement d'attention                      */
  --scale-zoom-from: 1.1;  /* point de départ du zoom arrière du héros   */
  --scale-cover: 1.12;     /* marge de recadrage pour la parallaxe       */
  --tilt-angle: -6deg;     /* inclinaison complice des pastilles         */

  /* Amplitude du défilement différentiel du bandeau d'appel.
     En réserve : l'animation CSS qui le consommait a été retirée (elle ne
     progressait pas et neutralisait la parallaxe du script). Le déplacement
     est aujourd'hui poussé en pixels par le JavaScript via --parallax. */
  --parallax-range: 8%;

  /* Transitions prêtes à l'emploi */
  --transition-colors: color var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
  --transition-transform: transform var(--duration-fast) var(--ease-out);
  --transition-shadow: box-shadow var(--duration-fast) var(--ease-out);

  /* ═══════════════════════════════════════════════════════════════════════
     7. STRUCTURE
     ═══════════════════════════════════════════════════════════════════════ */

  --width-page: 1180px;         /* largeur maximale du contenu             */
  --width-prose: 720px;         /* blocs de texte centrés (FAQ, chapô)     */
  --width-card-min: 250px;      /* seuil de repli des grilles de cartes    */

  /* --- Seuils de repli des grilles ----------------------------------------
     En dessous de ces largeurs, la colonne passe à la ligne d'elle-même.
     C'est ce qui permet au site de s'adapter presque sans media query. */
  --grid-min-2xs: 180px;   /* bandeau de chiffres                          */
  --grid-min-xs: 210px;    /* piliers, colonnes du pied de page            */
  --grid-min-sm: 220px;    /* comparatif avant / après                     */
  --grid-min-md: 260px;    /* étapes, colonne des services, mises en avant */
  --grid-min-lg: 300px;    /* réserve — servait à la grille du bloc contact,
                              remplacée par la pile de canaux (.channels)   */
  --grid-min-xl: 320px;    /* division principale en deux colonnes         */

  /* --- Répartition des paires « colonne de texte + colonne d'appui » -------
     Deux rapports, et deux seulement. Ils ne se choisissent pas à l'œil :
     c'est le RÔLE de la colonne étroite qui les départage.

     0.85 CONTRE 2 — LA COLONNE D'APPUI SECONDE UN BLOC DE HAUTEUR COMPARABLE.
     C'est l'introduction collante des services, et la photo de la division
     « une interlocutrice ». Les deux colonnes se répondent déjà par leur
     hauteur : la colonne étroite n'a pas besoin de largeur pour exister.

     1.15 CONTRE 2 — LA COLONNE D'APPUI PORTE UNE PHOTO FACE À UNE COLONNE
     TROIS FOIS PLUS HAUTE QU'ELLE. C'est la FAQ, et le rapport est mesuré,
     pas estimé. À 0.85, la piste image tombait à 342 px pour une colonne de
     questions de 806 : la photo mesurait 342 × 457, couvrait 80 % de la
     colonne repliée et 51 % dès qu'une question s'ouvrait. Elle se lisait
     comme une vignette posée en haut d'une grande colonne — ce que le
     client a formulé en « l'image est un peu petite à droite ». La
     neuvième question, la plus longue de la section, n'a pas créé l'écart :
     elle l'a rendu visible.
     À 1.15, la piste image mesure 419 px à la largeur de page maximale,
     soit EXACTEMENT le plafond de --width-figure-solo. Ce plafond
     redevient ainsi la borne qu'il était censé être, au lieu d'un plafond
     que plus rien n'atteignait : la figure ne le dépassera jamais, et la
     géométrie de la section n'a pas de valeur qui lui soit propre.
     La photo passe alors à 419 × 559 et couvre 98 % de la hauteur de la
     colonne repliée.

     LA COLONNE DE TEXTE N'Y PERD RIEN, ELLE Y GAGNE. Elle passe de 806 à
     729 px, soit de 121 à 109 signes par ligne : au-dessus de la mesure
     confortable (--measure, 65 signes) dans les deux cas, mais moins loin.
     Aucun intitulé de question ne passe sur deux lignes, et la marge est
     connue : le plus long des neuf en fait 53, et la ligne en tient 79 à
     partir de 1280 px, 61 à 1001 px — la fenêtre la plus étroite où la
     page tient encore deux colonnes. Un intitulé de FAQ dispose donc de
     61 signes avant de se dédoubler ; c'est ce chiffre qu'il faut donner
     au rédacteur, pas la largeur en pixels.
     ---------------------------------------------------------------------- */
  --side-cols-text: 2fr;
  --side-cols-media: 0.85fr;
  --side-cols-media-tall: 1.15fr;

  /* --- Largeurs de blocs particuliers -------------------------------------- */
  --width-hero-content: 44rem;
  --width-hero-card: 660px;
  --width-faq: 820px;
  --width-figure-overlay: 310px;
  --width-pull-quote: 320px;

  --header-height: 74px;        /* sert aussi d'ancre de défilement        */
  --topbar-height: 42px;

  /* Réserve de place des sections rendues à la demande (content-visibility) */
  --intrinsic-section-size: auto 640px;

  /* Empilement — une seule échelle pour tout le site, pas de z-index: 9999 */
  --layer-base: 1;
  --layer-raised: 10;
  --layer-sticky: 100;
  --layer-overlay: 200;
  --layer-modal: 300;
  --layer-skip-link: 400;

  /* ═══════════════════════════════════════════════════════════════════════
     8. VARIABLES DE COMPOSANTS
     Réglages fins, regroupés par composant pour les retrouver d'un coup d'œil.
     ═══════════════════════════════════════════════════════════════════════ */

  /* Bouton */
  --button-padding-y: 0.95rem;
  --button-padding-x: 1.6rem;
  --button-padding-y-sm: 0.8rem;     /* déclinaison compacte de l'en-tête  */
  --button-padding-x-sm: 1.3rem;
  --button-font-size: 0.97rem;
  --button-border-width: var(--stroke-base);
  --button-lift: -5px;               /* décollement au survol              */
  --button-hover-scale: 1.03;        /* le bouton vient à la rencontre     */
  /* Reflet qui balaie le bouton au survol */
  --button-sheen: linear-gradient(
    110deg,
    transparent 20%,
    var(--overlay-white-sheen) 50%,
    transparent 80%
  );

  /* Carte */
  --card-padding: var(--space-md);
  --card-lift: -14px;
  --card-hover-scale: 1.02;
  --card-radius: var(--radius-md) var(--radius-lg) var(--radius-md) var(--radius-lg);
  --card-bullet-size: 6px;
  /* Alignement optique de la puce sur la première ligne : ce n'est pas un
     réglage libre mais le centrage vertical de la puce dans la hauteur de
     ligne. Le poser en calcul évite qu'il se décale en silence le jour où
     l'interligne ou la taille de la puce changera. Le `1em` se résout sur
     la police de la liste. */
  --card-bullet-offset: calc((1em * var(--leading-normal) - var(--card-bullet-size)) / 2);
  --card-bullet-hover-scale: 1.5;
  /* Halo vert du survol : porté par un calque en fondu, jamais par une
     ombre animée — c'est l'opacité qui bouge, pas la géométrie.

     La géométrie est éclatée en trois variables, et ce n'est pas une
     coquetterie : un conteneur qui ROGNE doit pouvoir réserver la place du
     halo sans recopier ses chiffres. C'est le cas de la bande de
     témoignages, qui défile horizontalement et coupe donc tout ce qui
     dépasse d'elle. Tant que la portée n'était pas nommée, la réserve était
     une valeur choisie à l'œil — et elle était trop courte. */
  --card-glow-offset-y: 30px;
  --card-glow-blur: 70px;
  --card-glow-spread: -30px;
  --card-glow: 0 0 0 var(--stroke-hairline) var(--border-accent),
    0 var(--card-glow-offset-y) var(--card-glow-blur) var(--card-glow-spread)
      var(--brand-mint-500);
  /* Distance sous la carte à laquelle le halo est retombé au fond.
     Mesurée au pixel sur la bande de témoignages à 1280 px : à cette
     distance la teinte ne s'écarte plus du blanc que de 3 valeurs sur 765
     (somme des trois canaux), soit une marche invisible si l'on rogne là.
     C'est la réserve que doit prendre tout conteneur qui rogne ses cartes ;
     voir .quote-track dans la couche `sections`. */
  --card-glow-reach-block-end: calc(
    var(--card-glow-offset-y) + var(--card-glow-spread) + var(--card-glow-blur));
  --card-list-shift: 6px;                          /* décalage des puces    */
  --card-list-stagger: calc(45ms * var(--motion-scale));

  /* Canal de contact
     Le composant de conversion de la page depuis la suppression du
     formulaire : trois liens empilés, pleine largeur de la colonne de texte.
     La hauteur minimale place la cible tactile très au-dessus du plancher
     de 44 px recommandé — ce sont des liens que l'on vise au doigt.
     Contrastes (voir la table du §2 pour les rôles employés) :
       contour au repos ......... border-control sur surface-page ... 3.49:1
       titre secondaire ......... text-strong sur surface-raised .... 18.04:1
       note secondaire .......... text-muted sur surface-raised ...... 5.46:1
       titre au survol .......... text-strong sur surface-accent-soft  16.30:1
       note au survol ........... text-muted sur surface-accent-soft .. 4.93:1
       flèche secondaire ........ text-accent sur surface-page ....... 6.31:1
       titre principal .......... text-on-dark sur surface-inverse ... 18.04:1
       note principale .......... text-on-dark-muted sur idem ........ 10.11:1
       flèche principale ........ brand-mint-300 sur idem ............ 10.55:1
     Le canal principal au survol s'assombrit vers surface-inverse-hover :
     titre 14.18:1, note 8.42:1, flèche 8.30:1. Tout reste au-dessus d'AA. */
  --channel-min-height: 76px;
  --channel-padding-y: var(--space-sm);
  --channel-padding-x: var(--space-md);
  --channel-radius: var(--radius-md) var(--radius-lg) var(--radius-md) var(--radius-lg);
  --channel-lift: -6px;
  --channel-arrow-shift: 8px;      /* plus franc que la flèche d'un bouton */

  /* Sur-titre */
  --eyebrow-rule-width: 32px;
  /* Trait calé sur la PREMIÈRE ligne du sur-titre, pas au milieu du bloc :
     un sur-titre long passe sur deux lignes à 375 px (« Conseils ·
     Gestion administrative ») et le trait se retrouvait entre les deux.
     Centrage du trait dans une hauteur de ligne, même idiome que
     --value-list-icon-offset ; sur une ligne, la position est inchangée. */
  --eyebrow-rule-offset: calc((1em * var(--leading-normal) - var(--stroke-base)) / 2);

  /* Icônes et pastilles */
  --icon-size: 1.25em;               /* taille courante, relative au texte */
  --icon-size-inline: 1em;           /* flèche accolée à un libellé        */
  --icon-inline-baseline: -0.18em;   /* recalage optique dans un paragraphe */
  --icon-size-xs: 16px;
  --icon-size-sm: 22px;
  --icon-badge-size: 52px;
  --icon-badge-size-sm: 44px;
  --icon-badge-size-lg: 64px;
  --icon-badge-glyph-ratio: 55%;     /* part de la pastille occupée        */
  /* Anneau qui s'échappe de la pastille au survol de la carte */
  --icon-badge-ring-scale: 1.7;
  --icon-badge-ring-opacity: 0.5;

  /* En-tête */
  --header-blur: 14px;
  --header-saturate: 180%;
  /* Opacité de la barre collante — LE PLAFOND EST MESURÉ, PAS CHOISI.
     Cette barre laisse passer ce qui défile dessous, et ce qui défile
     comprend deux aplats bleu nuit pleine largeur (bandeau d'appel, pied de
     page) ainsi que la photo du héros. Le banc de contrastes ne peut pas le
     voir : il compare des couleurs à plat, or ici la couleur du fond dépend
     de la position de l'ascenseur. Elle a donc été relevée sur des captures,
     pixel par pixel, sous le texte du menu.

     Contraste du lien de menu SURVOLÉ ou COURANT (--text-accent), au-dessus
     du bandeau d'appel — le fond le plus sombre que la barre traverse :
       opacité 0.90 ....... 5.18:1        opacité 0.84 ....... 4.55:1
       opacité 0.88 ....... 4.92:1        opacité 0.82 ....... 4.36:1  ✗
       opacité 0.85 ....... 4.65:1        opacité 0.70 ....... 3.27:1  ✗
     Le lien AU REPOS (--text-body) tient jusqu'à 0.70 (8.43:1) : c'est
     l'état vert qui commande, et c'est lui qui fixe le plancher à 0.85.

     Augmenter --header-blur ne rachète RIEN ici : un flou étale ce qui est
     autour, or un aplat uni n'a rien à étaler. Mesuré à opacité 0.82, le
     lien vert passe de 4.36 à 4.46 puis 4.54 pour un flou de 14, 24 puis
     40 px — trois fois le flou pour 0.18 de contraste, et toujours sur le
     fil. Le flou n'aide que sous la photo du héros, qui n'est pas le cas
     défavorable. */
  --header-bg: rgba(255, 255, 255, 0.85);
  /* Le logo n'a QUE des largeurs : sa hauteur est une conséquence du ratio
     du fichier (420 × 155), pas une décision de charte. Le `height: auto`
     du reset la calcule ; la recopier à la main rouvrirait l'écart qui a
     déjà déformé le logo du pied de page (rendu 150 × 155 au lieu de
     150 × 55). Une valeur qui se déduit ne s'écrit pas. */
  --logo-width: 180px;
  --logo-width-sm: 150px;            /* petit mobile et pied de page       */

  /* Menu déroulant mobile
     --burger-bar-gap est un VRAI écart (le bouton est une grille, l'écart
     est posé par `gap`). Il valait autrefois une demi-valeur appliquée en
     marge haute ET basse, ce qui doublait l'espacement sans qu'on le voie
     dans le token — et les rangées de la grille s'étiraient par-dessus.
     L'écart réel atteignait 12 px pour des traits de 2 px, six fois leur
     épaisseur : l'icône se lisait comme trois traits séparés.
     Rapport retenu : une fois et demie l'épaisseur du trait.

     --burger-bar-shift n'est PAS un réglage libre : c'est la distance entre
     deux axes de traits, donc une conséquence de l'épaisseur et de l'écart.
     L'exprimer en calcul garantit que la croix reste juste quel que soit
     l'espacement choisi. Comme toute géométrie, il échappe à la
     neutralisation du mouvement réduit. */
  --burger-size: 44px;               /* cible tactile minimale recommandée */
  /* Le bouton d'appel à l'action de l'en-tête, réduit à son icône sous
     1001 px. Dérivé du burger et non recopié : les deux répondent à la
     même exigence — la cible tactile minimale — et doivent bouger
     ensemble le jour où elle change. Ils se retrouvent côte à côte sous
     861 px, où deux tailles différentes se verraient. */
  --header-cta-compact-size: var(--burger-size);
  /* Libellé court de la pastille, posé à côté de l'icône là où la barre
     le loge (500 à 980 px, puis 1080 à 1216 px : voir la feuille de
     styles). Affiché par du contenu généré à texte de remplacement vide :
     le nom accessible reste le libellé complet du balisage, « Réserver un
     appel découverte ». Un mot, choisi pour tenir : 122 px de pastille,
     icône comprise. L'allonger, c'est remesurer les deux paliers — et
     c'est une question pour le rédacteur avant d'en être une de style. */
  --header-cta-short-label: 'Réserver';
  --burger-bar-width: 20px;
  --burger-bar-gap: 3px;
  --burger-bar-shift: calc(var(--stroke-base) + var(--burger-bar-gap));

  /* Héros */
  --hero-min-height: clamp(460px, 70vh, 680px);
  /* Tablette portrait (48 rem à 1000 px) : le plafond de 680 px, atteint
     dès 972 px de haut, laissait à 768 × 1024 186 px de vide au-dessus du
     sur-titre pour un contenu de 449 px centré. Plafond ramené à 560 px :
     le bandeau de chiffres et le début de « À propos » remontent dans le
     premier écran. Appliqué par le palier tablette en fin de fichier. */
  --hero-min-height-tablet: clamp(440px, 56vh, 560px);
  --hero-focal-point: 50% 32%;       /* point d'intérêt de la photo        */
  --hero-card-overlap: clamp(-4rem, -6vw, -2.5rem);
  --hero-claim-min: 240px;
  --hero-overlay: linear-gradient(
    100deg,
    rgba(1, 16, 37, 0.92) 0%,
    rgba(1, 16, 37, 0.74) 44%,
    rgba(1, 16, 37, 0.22) 100%
  );

  /* Héros compact (page des questions fréquentes, 1.4.0)
     Le titre y court sur toute la largeur en mobile, jusqu'au bord où le
     voile de l'accueil ne tient plus que 22 % : sur le mur blanc de la
     photo du bureau, le texte clair y devenait illisible. Le voile compact
     ne descend jamais sous 72 %. Pire cas calculé, fond blanc pur sous le
     voile : luminance composée 0,084, soit 7,8:1 pour le texte clair et
     5,2:1 pour le chapô (blanc à 74 %) — AA tenu partout, sans dépendre
     de la photo. L'écart à l'accueil est voulu : ici la photo n'est
     qu'une ambiance, et sa source (900 px) est agrandie à 1280. */
  --hero-compact-overlay: linear-gradient(
    100deg,
    rgba(1, 16, 37, 0.94) 0%,
    rgba(1, 16, 37, 0.86) 50%,
    rgba(1, 16, 37, 0.72) 100%
  );
  /* Marges du héros compact et de la section qui le suit, mesurées le
     18/10/2026 : à 375 × 667, la première question doit tenir entière
     au-dessus de la ligne de flottaison. Avec 32 px (--space-fluid-2xl)
     elle finissait à 686 px ; avec 24 px et le chapô resserré (voir
     .hero--compact), à 654. Le rythme de section
     entier (56 à 112 px) la repoussait bien plus bas encore. */
  --hero-compact-padding-y: clamp(var(--space-md), 3vw, var(--space-lg));
  --hero-compact-focal-point: 50% 30%; /* le visage, dans une bande basse */
  --hero-compact-follow-gap: clamp(var(--space-md), 3vw, var(--space-xl));
  /* Hauteur du héros compact en bureau (≥ 861 px, 1.5.0) — piste A retenue
     par Greg. Ramené à sa seule hauteur de contenu (environ 300 px à 1280),
     le bandeau se lisait comme une barre de titre. 440 à 500 px lui rendent
     une présence de héros sans repousser la première question au-delà du
     premier écran. Sans effet sous 861 px : le mobile garde `min-height: 0`
     et ses 13 px de marge mesurés. */
  --hero-compact-min-height: clamp(440px, 56vh, 500px);

  /* Sommaire des thèmes
     Pastilles : la hauteur est la cible tactile minimale, dérivée du
     burger comme --header-cta-compact-size, pour bouger avec elle. */
  --theme-nav-link-height: var(--burger-size);
  --theme-nav-gap: var(--space-2xs);

  /* Carte « votre question n'y est pas » (carte d'Ana)
     Photo et texte côte à côte tant que le texte garde plus de la moitié
     de la carte ; en deçà, la photo passe au-dessus, en pleine largeur. */
  --ask-card-media-basis: 14rem;
  --ask-card-body-min: 55%;
  --ask-card-media-ratio: 4 / 3;
  --ask-card-focus: 50% 35%;

  /* Rubrique « Conseils » (1.6.0) — vitrine et pages d'articles
     Cartes-liens : deux par ligne dans la colonne de la vitrine (alignée
     sur --width-faq), une seule sur téléphone. Le seuil est la largeur
     minimale d'une carte, pas celle de l'écran. */
  --article-card-min: 20rem;
  --article-card-min-compact: 13rem;
  --article-card-gap: var(--space-md);
  --article-card-title-size: var(--text-xl);
  --article-card-title-size-compact: var(--text-lg);
  --article-theme-size: var(--text-xs);
  /* Carte compacte (grille à une seule colonne, donc téléphone) :
     l'illustration devient une vignette posée à côté du thème et du
     titre. Sa largeur suit celle de la grille (cqi), bornée entre 72
     et 96 px pour rester lisible sans reprendre la place du texte. */
  --article-thumb-size: clamp(4.5rem, 24cqi, 6rem);
  --article-thumb-gap: var(--space-sm);
  --article-thumb-marge: var(--space-3xs);
  --article-thumb-rayon: var(--radius-sm);
  /* Page d'article. Le corps garde la taille du texte courant du site :
     un article se lit en entier, il n'est pas un pavé de notes. */
  --article-body-size: var(--text-base);
  --article-body-width: var(--width-prose);
  --article-h1-size: var(--text-3xl);
  --article-h2-size: var(--text-2xl);
  --article-heading-gap: var(--space-xl);
  --article-header-pad-top: clamp(var(--space-lg), 4vw, var(--space-2xl));
  --article-list-indent: var(--space-md);
  --article-link-underline-offset: 0.2em;
  --article-link-underline-thickness: var(--stroke-thin);
  --article-back-height: var(--burger-size);   /* cible tactile minimale */
  --article-signature-photo: 4rem;
  --article-signature-photo-lg: 5.5rem;
  --article-signature-focus: 50% 30%;
  --article-notice-bg: var(--surface-alt);

  /* Illustrations des articles (prototype validé par Greg, 18/10/2026)
     Aucune couleur n'est écrite dans les SVG : chaque groupe reçoit son
     rôle ici. Le fond du cadre est le vert clair de l'image de partage ;
     l'aplat « actif » monte donc d'un cran (mint-100) pour rester lisible
     dessus. Les dessins sont décoratifs (aria-hidden) : leurs contrastes
     ne relèvent d'aucun seuil, le texte voisin porte tout le sens. */
  --illustration-trait: var(--text-strong);          /* contours principaux    */
  --illustration-eteint: var(--brand-grey-400);      /* ce qui ne sert plus    */
  --illustration-sol: var(--brand-mint-100);         /* ligne d'horizon        */
  --illustration-accent: var(--brand-mint-500);      /* le bon chemin          */
  --illustration-aplat: var(--brand-mint-100);       /* remplissage doux       */
  --illustration-aplat-fort: var(--brand-mint-300);  /* puce, sceau            */
  --illustration-aplat-clair: var(--surface-raised); /* papier du document     */
  --illustration-alerte: var(--brand-error);         /* l'échec, l'oubli       */
  --illustration-trait-largeur: 3;                   /* unités du viewBox 480  */
  --illustration-ratio: 16 / 9;
  --illustration-fond: var(--surface-accent-soft);
  --illustration-rayon: var(--radius-md);
  --illustration-marge: var(--space-2xs);

  /* Chiffre mis en avant
     Le nombre lui-même est compté par le script ; l'animation porte sur ce
     qui l'entoure — un ressort à l'arrivée et un halo qui s'ouvre une fois. */
  --metric-suffix-scale: 0.5em;
  --metric-pop-from: 0.72;
  /* Diamètre du halo, exprimé en em : il suit la taille du chiffre au lieu
     de s'étirer sur toute la largeur du bloc. Posé en `inset: 0`, l'ellipse
     obtenue faisait toute la largeur de la colonne — les trois halos du
     bandeau se rejoignaient en un aplat vert continu qui se lisait comme un
     défaut d'affichage, pas comme un accent. */
  --metric-halo-size: 2.2em;
  --metric-halo-scale: 1.9;
  --metric-halo-opacity: 0.42;
  --duration-metric-halo: calc(1500ms * var(--motion-scale));

  /* Photo encadrée et citation */
  --figure-ratio: 4 / 4.4;
  /* Mise au point de la photo « À propos » quand elle s'étire sur la
     hauteur de sa colonne de texte (916 px à 1280 px de fenêtre) : le
     recadrage ne garde alors qu'environ 63 % de la largeur de la source.
     Le visage d'Ana occupe 52 à 69 % de cette largeur ; à 62 %, la bande
     conservée va d'environ 22 à 85 % et le garde entier, téléphone compris.
     Cas le plus serré mesuré : 1024 px, photo de 457 × 1009, 45 % de la
     source conservée (30 à 79 %) — le visage reste entier. */
  --figure-about-focus: 62% 50%;

  /* Image d'appui — LE SECOND GABARIT DE FIGURE
     Le site n'en avait qu'un, celui des figures PORTEUSES : la photo de la
     section « À propos » et celle de « Une interlocutrice ». Elles occupent
     une colonne entière parce qu'elles portent un argument, posé dessus
     dans un cartouche à fond plein. Une image d'appui, elle, n'a rien à
     porter de tel — à la même échelle, elle pèse autant qu'un argument sans
     en être un, et se lit comme une photo plantée au milieu du flux.
     D'où une seconde échelle, et une seule.

     UN PLAFOND, PAS UNE COURBE — et c'est une correction mesurée.
     Une largeur fluide en `vw` avait été essayée : elle donnait 261 px à
     768 px de fenêtre, où le cartouche à fond plein occupait alors 72 % de
     la hauteur de l'image. La photo avait disparu derrière son propre
     texte. Un plafond fixe, borné par `min(100%, …)` du côté de la feuille
     de styles, se comporte juste partout sans un seul media query : la
     figure remplit sa colonne tant que celle-ci est étroite (téléphone,
     colonne d'introduction des services), et se fige à 420 px dès que la
     page est large — soit 36 % de la largeur de page, contre 100 %
     auparavant, c'est-à-dire dix fois moins de surface.
     Le carré épouse exactement les sources (900 × 900) : contrairement au
     format des figures porteuses, il ne recadre rien, donc ne coupe aucun
     visage. */
  --width-figure-solo: 420px;
  --figure-solo-ratio: 1 / 1;
  /* Format portrait, pour l'image qui accompagne une colonne beaucoup plus
     haute qu'elle (la liste de la FAQ). 3/4 retire 12,5 % de chaque côté
     d'une source carrée : assez pour tenir debout à côté d'une colonne de
     texte, pas assez pour perdre le sujet. */
  --figure-solo-ratio-tall: 3 / 4;
  /* Hauteur de l'image de la FAQ en mise en page large : celle de la liste
     des questions REPLIÉES. Depuis octobre 2026 l'accueil n'en garde que
     quatre (les autres vivent sur questions-frequentes.html) : mesurée en
     offsetHeight à 252 px à 1002 px de fenêtre, 253 px à 1024, 1280 et
     1440 px — chaque question tient sur une ligne. 15,8125 rem = 253 px.
     Une hauteur figée plutôt qu'un étirement sur la colonne : à
     l'ouverture d'une question, la liste grandit et la photo ne bouge pas.
     En rem, pour suivre le texte si le visiteur agrandit la police.
     ⚠ À REMESURER si l'on ajoute, retire ou allonge une question : c'est
     l'oubli de ce geste qui a laissé, au passage à quatre questions, une
     photo de 762 px face à une liste de 253.
     Mise au point : la colonne (326 à 419 px) est plus large que haute, la
     source carrée n'est donc plus recadrée qu'en HAUTEUR — 60 % conservés
     à 1280 px. Le visage d'Ana occupe 23 à 45 % de la hauteur de la
     source ; à 40 %, la bande gardée va de 16 à 76 % : chevelure entière,
     mains et ordinateur visibles. */
  --figure-solo-height-tall: 15.8125rem;
  --figure-solo-focus-tall: 50% 40%;
  /* Un cartouche posé sur une image d'appui ne peut pas garder la largeur
     de celui d'une image porteuse.

     DEUX BORNES, ET CHACUNE RATTRAPE UNE ERREUR DE L'AUTRE.
     La proportion commande tant que l'image est petite ; le plafond en
     pixels prend le relais quand elle est grande. C'est la leçon d'un
     défaut mesuré : le plafond avait d'abord été posé seul, calculé pour
     une image de 420 px. La colonne s'est ensuite resserrée à 338 px, le
     plafond n'a pas bougé, et le cartouche s'est mis à couvrir 78 % de la
     largeur et 44 % de la SURFACE de la photo — « on ne voit quasiment pas
     l'image », et c'était exact au pixel près. Une borne en pixels ne
     protège rien lorsqu'elle est calculée sur une taille qui change.
     72 % est le point d'équilibre mesuré : au-dessous, le cartouche
     s'étrangle et son texte gagne des lignes — donc de la hauteur, donc de
     la surface, ce qu'on cherchait justement à réduire. À 72 % il reste
     ~30 signes par ligne, et une mention de trois lignes couvre 25 % de la
     photo au lieu de 44 %. */
  --figure-solo-overlay-part: 72%;
  --width-figure-solo-overlay: 264px;

  /* Photo des services en mise en page large (1250 px et plus) : elle
     prend la hauteur que les cartes laissent sous l'introduction, pour que
     la colonne de gauche finisse au ras de la grille. Le cadre devient plus
     haut que large à 1280 px : la source n'est plus recadrée qu'en
     LARGEUR, d'où une mise au point surtout horizontale. Valeur de l'étude
     d'équilibre des services, vérifiée sur captures de 1250 à 1920 px :
     le visage reste entier. */
  --services-figure-focus: 57% 40%;

  /* ── Photos sur téléphone (sous 48 rem) : un traitement par rôle ──────
     Sept photos d'Ana, toutes carrées et pleine largeur, faisaient sur
     téléphone sept écrans de visage. Chacune reçoit désormais le format de
     son rôle (prototype B, validé par Greg) :
       présence (À propos, Contact) .... bandeau 4:3, un quart de hauteur
                                         en moins qu'un carré ;
       vignette (Pourquoi, FAQ) ........ portrait rond, à côté de la
                                         signature ou dans l'invitation.
     Mises au point : la source carrée n'est recadrée qu'en hauteur par le
     4:3, seule la seconde valeur travaille. */
  --photo-ratio-phone: 4 / 3;
  --figure-about-focus-phone: 62% 30%;
  --figure-contact-focus-phone: 66% 45%;

  /* ── Photos sur tablette portrait (48 rem à 1000 px) : en bandeau ──────
     « À propos » et « La différence » passent en une colonne : la photo
     traverse toute la largeur du contenu, le texte vient dessous. Avant,
     à 768 px, la photo d'« À propos » mesurait 338 × 1 253 px à côté d'une
     colonne de texte de 338 px.
     16:9 et non 21:9 : à 768 px le bandeau fait 397 px de haut en 16:9,
     302 en 21:9 — où la citation signée (179 px) et le cartouche de
     valeurs (148 px) couvriraient la moitié de la hauteur.
     La source carrée n'est recadrée qu'en hauteur (56 % conservés) : seule
     la seconde valeur de chaque mise au point travaille. Choisies sur
     captures à 768 et 1000 px, pas déduites des fichiers :
       À propos ..... celle du téléphone (30 %) : chevelure, visage et
                      téléphone entiers, le cartouche de valeurs sous le
                      menton ;
       Pourquoi ..... 25 % : le haut de la chevelure et le menton tiennent
                      tous deux dans le bandeau. Le point du médaillon
                      (40 %) coupait le front ; 15 % coupait le menton. */
  --photo-ratio-band: 16 / 9;
  --figure-about-focus-band: var(--figure-about-focus-phone);
  --figure-why-focus-band: 50% 25%;
  /* Les trois autres photos de la page passent en bandeau (1.9.0.3) : les
     services, la FAQ et le contact restaient des carrés de 420 px centrés
     dans la plage, seuls de leur espèce entre deux bandeaux. Mêmes
     principes : recadrage en hauteur seulement, seconde valeur choisie
     sur captures à 768, 820 et 1000 px.
       Services ..... 40 % : visage et téléphone entiers, le cartouche
                      « fondatrice » sur l'épaule, à droite du menton.
                      20 % laissait le menton au ras du bas du bandeau,
                      et le cartouche mordait sur la joue ;
       FAQ .......... 18 % : chevelure et menton entiers en 21:9 (voir
                      ci-dessous), le visage au-dessus de la carte ;
       Contact ...... 30 % : la lampe à gauche, le visage et le téléphone
                      à droite, le cartouche sur l'ordinateur. */
  --figure-services-focus-band: 50% 40%;
  --figure-faq-focus-band: 50% 18%;
  --figure-contact-focus-band: 50% 30%;
  /* Bandeau bas de la FAQ : 21:9 et non 16:9. La photo n'y escorte que
     quatre questions repliées (250 px environ) ; en 16:9 elle mesurerait
     397 px à 768, plus haute que le contenu qu'elle accompagne, et la
     section se lirait comme une photo légendée. En 21:9 : 302 px, l'ordre
     de grandeur de la liste — la règle du bureau, où la photo prend la
     hauteur des questions repliées. */
  --photo-ratio-band-short: 21 / 9;
  /* Vignettes. 56 px : la hauteur de la signature, nom et fonction.
     72 px : un visage reconnaissable, dans une carte qui n'a qu'une phrase. */
  --avatar-size-quote: 3.5rem;
  --avatar-size-card: 4.5rem;
  /* Recadrage du rond : l'image est agrandie autour du visage, puis
     découpée en disque. Le point (x, y) est la position du visage dans la
     source ; l'origine de l'agrandissement s'en déduit, voir la feuille de
     styles. 2,4 : le visage remplit le disque sans que les cheveux soient
     coupés. */
  --avatar-zoom: 2.4;
  --avatar-face-why-x: 43%;
  --avatar-face-why-y: 40%;
  --avatar-face-bureau-x: 51%;
  --avatar-face-bureau-y: 36%;

  /* Liste à cocher des cartouches — alignement optique de la coche sur la
     PREMIÈRE ligne, et non sur le milieu du bloc. Ce n'est pas un réglage
     libre mais le centrage vertical de l'icône dans une hauteur de ligne :
     le poser en calcul évite qu'il se décale en silence le jour où
     l'interligne ou la taille d'icône changera. Même idiome que
     --card-bullet-offset. Sans lui, une entrée qui passe sur deux lignes
     voyait sa coche glisser entre les deux — ce qui est arrivé dès que les
     cartouches ont porté des phrases au lieu d'un seul mot. */
  --value-list-icon-offset: calc((1em * var(--leading-normal) - var(--icon-size-xs)) / 2);
  --pull-quote-inset-block: 8%;
  /* --pull-quote-offset : RETIRÉ. Il faisait déborder le cartouche de
     12 px hors du cadre photo — sauf que .figure porte `overflow: clip`,
     qui rognait ce débord depuis toujours. Personne ne l'a jamais vu.
     Un token qui décrit un effet inexistant est pire qu'un token inutile :
     la personne suivante l'ajuste et ne comprend pas pourquoi rien ne
     bouge. Le cartouche est désormais aligné franchement sur le bord de
     la photo, et il y gagne les 12 px qui étaient coupés. */

  /* Bandeau de témoignages
     Une bande de six citations qui avance d'elle-même, lentement, et que
     l'on peut aussi parcourir à la main.

     LARGEUR DE CARTE — FIXE, ET C'EST CE QUI FAIT LE RYTHME.
     Le rédacteur a tranché de ne pas homogénéiser la longueur des citations
     (102 à 170 signes) : l'écart est absorbé en blanc. Cela n'est tenable
     que si la largeur, elle, ne varie pas d'une carte à l'autre — sans quoi
     le défilement avancerait par à-coups. La borne haute (340 px) est la
     largeur de lecture visée ; la borne basse (280 px) est ce qui laisse
     encore paraître un morceau de la carte suivante sur un téléphone de
     390 px, sans quoi plus rien ne dirait que la bande continue.
     Le `cqw` se mesure sur la bande elle-même, déclarée conteneur : aucun
     media query n'intervient dans ce composant.

     DISTANCE DE BOUCLE — DÉDUITE, PAS CHOISIE.
     C'est exactement un jeu de six cartes, gouttière comprise. La bande
     avance de cette distance puis reprend à zéro ; comme le jeu suivant est
     identique, la reprise ne se voit pas. L'écrire en calcul garantit que
     la boucle reste sans couture le jour où la largeur d'une carte change.

     DURÉE — MESURÉE SUR LA LECTURE, PAS SUR L'ŒIL.
     54 s pour les 2 184 px d'un jeu à 1 180 px de bande, soit 40 px par
     seconde. Une carte met alors 8,5 s à parcourir sa seule largeur, là où
     une citation de 134 signes se lit en cinq à six secondes : la lecture a
     le temps, et le mouvement reste franchement perceptible (120 px en
     trois secondes). En mouvement réduit, c'est l'AMPLITUDE qui retombe à
     zéro, jamais la durée : une durée écrasée par --motion-scale ferait
     défiler la bande cent fois plus vite au lieu de l'immobiliser. */
  --quote-card-width: clamp(280px, 34cqw, 340px);
  --quote-gap: var(--space-md);
  --quote-loop-shift: calc((var(--quote-card-width) + var(--quote-gap)) * 6);
  --quote-loop-duration: calc(54s * var(--motion-scale));
  /* Départ et fin du filet vert de la carte, mesurés depuis ses bords : le
     plus grand rayon du contour signature, pour que le filet commence là où
     le bord redevient droit. Dérivé, il suit le contour s'il change. */
  --quote-rule-inset: var(--radius-lg);

  /* Bandeau d'outils (#outils) — même mécanisme que les témoignages.
     AUCUNE VALEUR PROPRE : tout est emprunté aux échelles existantes, qui
     sont déjà fluides. Le bandeau suit donc le reste du site d'un format à
     l'autre, sans point de rupture à lui.

     HAUTEUR DE RÉFÉRENCE : --space-fluid-md, de 24 px (téléphone) à
     32 px (dès 914 px de fenêtre). C'est la hauteur d'un logo dont le
     rapport largeur / hauteur vaut --tool-logo-pivot ; les autres s'en
     écartent selon leur forme (voir « surface égale » ci-dessous).
     Le nom écrit prend --text-xl (18,4 à 22,4 px) : sa capitale
     (0,73 em pour Inter) rejoint la hauteur de lettre des mots-marques
     dessinés, ce qui lui donne le même poids visuel qu'un logo.
     La gouttière suit l'échelle des bandeaux, 32 à 64 px.

     DISTANCE DE BOUCLE — LUE SUR LE RAIL, PAS COMPTÉE.
     Le rail porte deux jeux identiques séparés par une gouttière : un jeu
     vaut donc la moitié de sa largeur, plus une demi-gouttière. Le
     pourcentage se résout sur le rail lui-même, qui est l'élément animé.

     DURÉE — MESURÉE, COMME CELLE DES TÉMOIGNAGES : environ 40 px par
     seconde à 1 280 px de fenêtre, où un jeu mesure 4 980 px (118 s,
     remesuré en 1.3.3 après l'ajout d'Indy : 42 px/s).
     En mouvement réduit, c'est l'amplitude qui tombe, jamais la durée. */
  --tool-logo-height: var(--space-fluid-md);

  /* SURFACE ÉGALE — la méthode dite du « logo soup ».
     À hauteur commune, un mot-symbole de rapport 5 (Docusign, 159 px de
     large à 1 280 px) occupait cinq fois la surface d'un symbole carré
     (Notion, 31 px) : les longs écrasaient les courts. La hauteur suit
     donc le rapport r = largeur / hauteur du cadre :

         hauteur = référence × (pivot / r) ^ exposant, bornée

     Un exposant de 0,5 égaliserait exactement la surface du cadre
     (hauteur × largeur constante). Essayé sur la planche : les mots-
     symboles en bas de casse et maigres (pennylane, docusign, youtrust)
     tombaient trop bas, car un cadre large est plus vide qu'un carré
     plein. 0,4 garde l'essentiel de la correction — Docusign passe de
     159 à 111 px de large à 1 280 px, Notion de 31 à 35 — sans ce
     surcoût. Le pivot 2,5 est la médiane des mots-symboles seuls : Odoo
     et PayFit gardent la hauteur de référence, les longs descendent, les
     carrés montent.
     BORNES. Le plancher de 20 px garde un mot en bas de casse lisible au
     téléphone : à 390 px, pennylane serait à 18 px, sa hauteur d'œil à
     peine au-dessus de 6. Le plafond de 1,125 × la référence (27 à 36 px)
     retient les symboles carrés, que la formule porterait à 1,47 × : à
     côté d'un nom en --text-xl, un symbole trop grand prend le pas sur le
     nom qu'il accompagne. */
  --tool-logo-exponent: 0.4;
  --tool-logo-pivot: 2.5;
  --tool-logo-height-min: 20px;
  --tool-logo-height-max: calc(var(--tool-logo-height) * 1.125);

  /* Rapport largeur / hauteur de chaque logo, lu sur le viewBox de son
     symbole (logos.v1.0.4.svg, cadré au tracé). Seuls figurent ceux qui
     s'écartent du carré : le composant prend 1 par défaut. À recalculer
     si un symbole est recadré — le viewBox recopié dans index.html en
     donne les deux termes. */
  --logo-ratio-payfit: 2.441;         /*   68,36 × 28     */
  --logo-ratio-pennylane: 5.023;      /*  160,73 × 32     */
  --logo-ratio-qonto: 3.417;          /*      82 × 24     */
  --logo-ratio-tiime: 4.119;          /* 1659,09 × 402,77 */
  --logo-ratio-indy: 1.964;           /*     108 × 55     */
  --logo-ratio-notion: 0.96;          /*   23,04 × 24     */
  --logo-ratio-swile: 3.084;          /*  813,01 × 263,65 */
  --logo-ratio-odoo: 2.526;           /*      24 × 9,5    */
  --logo-ratio-alan: 4.717;           /*  669,87 × 142    */
  --logo-ratio-boondmanager: 5.219;   /*     167 × 32     */
  --logo-ratio-docusign: 4.971;       /*    1200 × 241,4  */
  --logo-ratio-youtrust: 4.368;       /*   98,02 × 22,44  */
  --logo-ratio-hiway: 4.25;           /*     102 × 24     */
  --logo-ratio-stripe: 0.714;         /*   17,14 × 24     */
  --logo-ratio-openai: 0.963;         /*   39,48 × 41     */

  --tool-name-size: var(--text-xl);
  --tool-inner-gap: var(--space-2xs);
  --tool-gap: var(--space-fluid-3xl);
  --tool-color: var(--text-muted);
  --tool-loop-shift: calc(50% + var(--tool-gap) / 2);
  --tool-loop-duration: calc(118s * var(--motion-scale));

  /* Bouton pause / lecture des deux bandes. Même cible tactile que le
     burger et la loupe : 44 px, au-delà des 24 px du critère WCAG 2.5.8. */
  --track-toggle-size: var(--burger-size);

  /* Carrousels sur téléphone — services et témoignages
     Sous 48 rem, les deux grilles deviennent des rangées qu'on fait défiler
     au doigt, carte après carte, avec une rangée de pastilles dessous.

     LARGEUR D'UNE CARTE : 82 % DE LA BANDE, ET C'EST L'AMORCE QUI DÉCIDE.
     Le reste de la largeur montre le bord de la carte suivante : c'est le
     seul signal, sans script, qui dise « ça continue ». Mesuré à 375 px :
     carte de 275 px, 44 px de la suivante visibles dans la colonne (64 px
     jusqu'au bord de l'écran), soit 16 à 23 % de sa largeur. En `cqi` :
     la rangée est déclarée conteneur, la mesure se prend sur sa largeur
     utile, gouttières retirées.

     PASTILLES : UN DISQUE DESSINÉ À 12 PX, RÉDUIT PAR ÉCHELLE.
     Trois tailles (6, 9 et 12 px) obtenues par `transform: scale()` sur un
     même disque : la transition ne touche que `transform` et `opacity`,
     jamais la largeur. La cible tactile, elle, ne bouge pas : 44 px, comme
     le burger et la loupe, quelle que soit la taille dessinée.
     Une pastille se repère d'abord par sa TAILLE, la couleur ne fait que la
     confirmer (SC 1.4.1). Les deux tons restent néanmoins tenus au 3:1 des
     éléments graphiques, sur les deux fonds où une rangée peut se poser :
       carousel-dot-color sur surface-page ........  3.49:1  (SC 1.4.11)
       carousel-dot-color sur surface-alt .........  3.29:1  (SC 1.4.11)
       carousel-dot-color-active sur surface-page ..  3.19:1  (SC 1.4.11)
       carousel-dot-color-active sur surface-alt ...  3.01:1  (SC 1.4.11)
     Le vert de marque (--brand-mint-500) n'atteint que 2.28:1 sur le fond
     alterné des services : c'est donc le ton de survol, un cran plus
     sombre, qui porte la pastille active. Marge très mince sur le fond
     alterné, comme celle de l'anneau de focus du retour en haut :
     éclaircir --brand-mint-600 ou assombrir --brand-grey-050 la consomme.
     Repli tout prêt si elle devait tomber : --brand-mint-800 (5.96:1). */
  --carousel-item-width: 82cqi;
  --carousel-gap: var(--space-sm);
  --carousel-dot-size: 12px;
  --carousel-dot-scale-near: 0.75;    /* voisines : 9 px  */
  --carousel-dot-scale-rest: 0.5;     /* les autres : 6 px */
  --carousel-dot-hit: var(--burger-size);
  --carousel-dot-color: var(--brand-grey-400);
  --carousel-dot-color-active: var(--brand-mint-600);

  /* Liens du pied de page sur téléphone : rangés sur deux colonnes, chacun
     tient la cible tactile minimale, dérivée du burger comme les autres. */
  --footer-link-min-height: var(--burger-size);

  /* Méthode : les grands numéros en contour */
  --step-number-size: 3.2rem;
  /* Le filet doit passer à mi-hauteur du grand numéro (interligne 1) :
     c'est donc exactement la moitié de sa taille, pas une valeur à retenir. */
  --step-rule-offset-block: calc(var(--step-number-size) / 2);
  --step-rule-offset-inline: 5.5rem; /* départ du filet, après le numéro    */
  --step-number-shift: 32px;         /* le numéro glisse depuis la gauche   */
  --step-number-hover-scale: 1.08;

  /* FAQ — le recalage du chevron compense sa rotation à 45°, il est
     géométrique et ne doit pas être neutralisé par le mouvement réduit */
  --faq-chevron-size: 11px;
  /* Recentrage optique du chevron après sa rotation à 45°. Il dépend de la
     taille du chevron : un quart de son côté replace le sommet du « V » sur
     l'axe du texte. Dérivé, il ne peut plus diverger de la taille. */
  --faq-chevron-nudge: calc(var(--faq-chevron-size) / 4);
  /* Résumé d'un repli propre au téléphone (« Mon parcours », 1.9.0.2) :
     la cible tactile minimale, dérivée du burger comme les autres. */
  --fold-summary-min-height: var(--burger-size);
  --faq-chevron-hover-scale: 1.3;

  /* Champs de formulaire */
  /* Réserve — plus aucun champ dans la page (formulaire supprimé) */
  --field-textarea-min-height: 140px;

  /* Motif de points décoratif */
  --dots-size: 22px;         /* pas de la trame                            */
  --dots-radius: 1px;        /* grosseur d'un point                        */
  --dots-opacity: 0.14;
  --dots-drift-duration: calc(28s * var(--motion-scale));
  --dots-enter-scale: 1.3;   /* la trame se resserre quand la section arrive */
  /* La trame elle-même, puis son fondu sur les bords (concentré en haut
     à gauche) : les deux dégradés sont des décisions graphiques, ils
     appartiennent donc au design system et non à la feuille de styles. */
  --dots-pattern: radial-gradient(
    var(--brand-mint-500) var(--dots-radius),
    transparent var(--dots-radius)
  );
  --dots-mask: radial-gradient(120% 90% at 15% 40%, var(--brand-black) 0%, transparent 68%);

  /* Barre de progression de lecture */
  --progress-height: 3px;

  /* Bouton retour en haut — et son ancrage, que la pile de raccourcis
     reprend pour s'aligner sur lui sans recopier aucun nombre. */
  --to-top-size: 46px;
  --to-top-offset: var(--space-md);
  --to-top-icon-size: 1.25rem;            /* 20 px, suit la taille de texte choisie */
  /* Survol des ronds (retour en haut et raccourcis) : léger grossissement. */
  --round-hover-scale: 1.06;

  /* Raccourcis flottants (Conseils, rendez-vous), empilés au-dessus du
     bouton retour en haut : même rond, même axe, et une seule gouttière,
     entre les ronds comme entre la pile et le bouton.
     LIBELLÉS — capacité mesurée. Pastille sur une ligne, à gauche du rond,
     en --text-sm semi-gras : « Réserver un appel » (17 signes) mesure
     environ 135 px ; la pastille tient jusqu'à --quick-label-max (16rem,
     soit une trentaine de signes) avant de passer à la ligne. À 390 px de
     large, la place à gauche du rond est de 390 − 24 − 46 − 8 = 312 px. */
  --quick-gap: var(--space-xs);
  --quick-stack-offset: calc(var(--to-top-offset) + var(--to-top-size) + var(--quick-gap));
  --quick-stagger: var(--stagger-step);   /* le rond du haut arrive après */
  /* Fondu de la pile. Hors --motion-scale en mouvement réduit (voir plus
     bas) : la pile y paraît en vrai fondu, sur place, au lieu d'un éclair. */
  --quick-duration: var(--duration-base);
  --quick-label-gap: var(--space-2xs);
  --quick-label-height: 2.25rem;          /* 36 px, centré sur le rond   */
  --quick-label-padding-x: var(--space-xs);
  --quick-label-max: 16rem;
  --quick-label-shift: var(--space-2xs);  /* glisse depuis le rond       */
  /* Masquée, la pastille est découpée à rien ; affichée, la découpe
     déborde de cette portée pour laisser passer son ombre portée. */
  --quick-label-clip-reach: var(--space-lg);

  /* Barre d'appel collante (téléphone, 1.5.0)
     Sa hauteur est FIXÉE ici plutôt que subie : c'est elle que réservent
     `scroll-padding-bottom` (le focus clavier ne passe jamais dessous,
     WCAG 2.4.11) et la remontée du bouton retour en haut. Bouton de 48 px
     (au-dessus de la cible tactile de 44 px) + 2 × 8 px + le filet du haut
     = 65 px, auxquels
     s'ajoute la zone sûre du bas d'écran (0 sans `viewport-fit=cover`).
     Limite assumée : à un zoom de texte qui ferait passer le libellé sur
     deux lignes, la barre grandit au-delà de la hauteur réservée. */
  --cta-bar-padding-y: var(--space-2xs);
  --cta-bar-button-height: 3rem;
  --cta-bar-height: calc(var(--cta-bar-button-height) + var(--cta-bar-padding-y) * 2
    + var(--stroke-hairline));
  --cta-bar-max-width: 26rem;          /* le bouton ne s'étire pas sur une tablette */
  --cta-bar-bg: var(--surface-raised);
  --cta-bar-border: var(--border-subtle);
  /* Ombre portée VERS LE HAUT : la barre flotte sur le contenu qui défile. */
  --cta-bar-shadow: 0 -10px 28px -14px rgba(1, 22, 51, 0.28);
  --cta-bar-enter-shift: 100%;         /* entre depuis le bas de l'écran   */
  --cta-bar-to-top-gap: var(--space-sm); /* écart entre la barre et .to-top */

  /* Réseaux sociaux */
  --social-size: 32px;
  --social-size-lg: 36px;

  /* Bandeau d'appel */
  --cta-image-opacity: 0.32;

  /* Modale */
  /* Le battement de l'icône appelle l'œil à l'ouverture puis s'arrête : une
     pulsation sans fin bougerait sous les yeux pendant qu'on lit le message. */
  --modal-icon-pulses: 3;
  --modal-width: 440px;
  --modal-backdrop: rgba(1, 16, 37, 0.62);
  --modal-backdrop-blur: 3px;

  /* Verre « liquid glass » — matériau partagé (1.7.0)
     ─────────────────────────────────────────────────────────────────────────
     TON ADAPTATIF DÉSACTIVÉ LE 21/10/2026 (darkZones vide) ; le mécanisme
     reste en place, réactivable en remplissant `invite.darkZones`. Le ton
     reste donc à 0 : seul l'état clair ci-dessous est affiché, et la carte
     comme les ronds survolent aussi les fonds sombres (bandeau photo,
     contact, pied de page) — d'où le voile givré commun
     (--glass-bg-frosted) et l'intervalle blanc de l'anneau de focus
     (--focus-ring-gap-color), mesurés pour ce cas.

     UNE SEULE RECETTE pour tout ce qui flotte au-dessus de la page : la
     carte « À lire ensuite », les raccourcis ronds et le bouton retour en
     haut. Les tokens --glass-* décrivent la matière ; la feuille de styles
     l'applique par une seule règle (« Matériau verre », couche
     components). Mise au point sur la carte, dont les mesures suivent ;
     les ronds reprennent les mêmes teintes, donc les mêmes contrastes, et
     seuls les reflets et les ombres changent d'échelle (variantes -sm).

     LA MATIÈRE SE LIT PAR LA LUMIÈRE, PAS PAR UNE TEINTE. Le voile blanc
     est faible ; sur une section blanche, ce sont le liseré spéculaire, le
     reflet de bord, l'ombre interne basse et l'ombre portée qui détachent
     la carte. Le flou fort et la saturation font le reste dès que quelque
     chose de coloré passe dessous.

     DEUX ÉTATS, UN PASSAGE PROGRESSIF. Le script écrit le ton, de 0 à 1
     (--invite-tone sur la carte, --glass-tone sur les ronds) : la part de
     l'élément entrée dans une zone sombre (bandeau
     d'appel en photo, pied de page), rampée sur environ 120 px de
     défilement. Le verre se fume d'une couche marine dont l'opacité est
     ce ton ; les teintes de texte basculent sur une plage courte autour
     de 0.5 (--glass-ink-switch-*). Au
     repos, le script « finit » le ton à 0 ou à 1 : seuls ces deux états
     sont mesurés ci-dessous, les intermédiaires ne sont que traversés.
     Sans color-mix(), repli sur la bascule `.is-on-dark` (ton ≥ 0.5).

     LES OPACITÉS SONT MESURÉES, PAS CHOISIES. Méthode : couleur du fond,
     puis voile blanc à N % composé par-dessus, puis (état sombre) fumée
     marine à M % ; ratio WCAG du texte le plus fragile de chaque état.
     Le flou ne fait que moyenner le fond : il ne sort jamais de l'intervalle
     entre le plus clair et le plus sombre de ce qui passe dessous.

     · État clair. Texte le plus fragile : le vert foncé du sur-titre et
       du lien (--brand-mint-800). Voile blanc à 40 % :
         sur blanc : vert foncé 6.31 contre 1, bleu nuit 18.04 contre 1
         sur section alternée : vert foncé 6.10 contre 1, bleu nuit 17.44
         fond le plus sombre encore AA pour le vert foncé : un gris
         uniforme de valeur 193 sur 255 (4.51 contre 1). Une section
         blanche ou alternée floutée, texte compris, reste très au-dessus.
       À 30 % le seuil remonte à 202 sur 255 ; 40 % garde de la marge
       pour les cartes grisées et les filets des sections claires.
       La luminosité du flou (au-dessus de 1) ne peut qu'éclaircir le fond,
       donc aider le texte foncé : elle n'entre pas dans le calcul.
     · État sombre. Texte le plus fragile : le vert pâle (--brand-mint-300).
       Fumée bleu nuit profond (--brand-navy-900) à 75 % sur le voile :
         sur blanc pur : vert pâle 5.13 contre 1, blanc 8.76 contre 1
         sur noir pur : vert pâle 9.00 contre 1, blanc 15.38 contre 1
       Le blanc pur est compté parce que le ton suit le défilement : une
       carte finie à 1 peut encore survoler, sur quelques pixels, la
       section claire qui la précède. 74 % ne laissait que
       0.44 de marge sur le vert pâle ; 75 % en laisse 0.63.
     · Focus. L'anneau prend le ton du texte accentué de l'état : vert foncé
       en clair, vert pâle en sombre ; il se pose sur le verre et hérite
       des mêmes ratios, au-dessus des 3 de SC 1.4.11. Le bouton garde le
       vert de marque, libellé bleu nuit indépendant du fond (7.46 contre 1).
     · Verre clair permanent (1.8.0.1). Le voile à 40 % ne vaut plus que
       sur fond clair : sur du noir pur, il laisse un gris de valeur 102
       sur 255 — vert foncé de la carte à 1.10 contre 1, icône bleu nuit
       des ronds à 3.14, et des ronds gris-bleu sur le pied de page. Carte
       et ronds prennent donc un voile givré : --glass-bg-frosted pour la
       carte, --glass-bg-frosted-sm pour les ronds (1.8.0.2).

     LES REFLETS NE TOUCHENT AUCUN TEXTE. Le lustre et le halo intérieur
     s'éteignent dans la marge intérieure (--glass-gloss-depth), avant la
     première ligne. En clair, une lumière blanche ne peut qu'aider le texte
     foncé ; en sombre, la fumée passe PAR-DESSUS le lustre et le halo, et
     seul un filet de 1 px est repeint au-dessus d'elle.

     PAS DE RÉFRACTION. Une déformation de lentille demanderait un filtre
     SVG en backdrop-filter: url(#…), compris par Chromium seul. Aucune
     requête @supports ne le distingue : Safari accepte la syntaxe puis
     abandonne tout le flou, y compris celui de l'iPhone, premier lecteur
     du site. Et sous un flou de 30 px, quelques pixels de déplacement
     sur le bord ne se voient plus. Le volume est rendu par la lumière.

     Sans backdrop-filter, le verre devient un aplat opaque : blanc en état
     clair (vert foncé 6.31, bleu nuit 18.04 contre 1), bleu nuit profond en
     état sombre (vert pâle 11.16, blanc 19.08 contre 1). */
  /* Verre : voile blanc faible, flou fort, couleurs ravivées */
  --glass-bg: rgba(255, 255, 255, 0.4);
  /* Voile givré : celui de la carte « À lire ensuite » et des ronds
     flottants, qui restent clairs sur tous les fonds, même les plus
     sombres. Dosé sur le texte le plus exigeant, celui de la carte.
     Méthode : page recouverte d'un aplat noir (le pire fond possible pour
     une encre foncée : le flou, la saturation et la luminosité ne peuvent
     que l'éclaircir), textes rendus transparents, puis lecture du pixel le
     plus sombre dans la boîte de chaque ligne de texte (soulignement
     compris), à 360, 390, 768, 1280 et 1600 px de large.
       voile à 86 % : lien vert foncé à 4.42 contre 1, sous l'AA ;
       voile à 87 % : sur-titre vert foncé à 4.69, lien à 4.55 (la lueur
       verte du bouton et l'ombre interne basse passent sous lui),
       accroche bleu nuit à 13.0 au plus bas.
     87 % est donc le minimum. Les ronds ont leur propre voile, plus
     léger (--glass-bg-frosted-sm, ci-dessous). Le liseré, le lustre et
     les ombres -sm restent lisibles : c'est la lumière qui fait le verre,
     pas la transparence.
     Sur une section blanche, le rendu ne change pas : un voile blanc sur
     du blanc reste du blanc (vert foncé à 6.31 contre 1, comme avant). Le
     liseré, le lustre, les ombres et le flou restent ceux de la recette :
     carte et ronds demeurent un verre givré. */
  --glass-bg-frosted: rgba(255, 255, 255, 0.87);
  /* Voile des ronds flottants (1.8.0.2) : plus transparent que celui de
     la carte, pour qu'on devine la page dessous (logos, photos). Un rond
     ne porte qu'une icône, composant graphique jugé à 3 contre 1
     (SC 1.4.11), pas un texte à 4.5. Même méthode que la carte (aplat
     noir sous les ronds, icône rendue transparente, pixel le plus sombre
     du carré de l'icône, Chromium, 1280 px), bleu nuit contre le fond :
       voile à 40 % : 3.14 contre 1, sans marge, et rond gris-bleu terne
       sur le pied de page ;
       voile à 55 % : 5.37 contre 1 ;
       voile à 60 % : 6.33 contre 1, retenu (deux fois le seuil).
     60 % est le haut de la fourchette visée : c'est sur le pied de page
     bleu nuit que le rond doit rester clair, et chaque point de voile en
     moins l'y rapproche du gris. Flou, saturation, liseré, lustre et
     anneau de focus doublé sont inchangés. */
  --glass-bg-frosted-sm: rgba(255, 255, 255, 0.6);
  --glass-bg-fallback: var(--surface-raised);       /* sans backdrop-filter */
  --glass-blur: 30px;
  --glass-saturate: 190%;
  --glass-brightness: 1.06;
  /* Fumée marine de l'état sombre, posée sur le voile */
  --glass-smoke: rgba(0, 16, 37, 0.75);
  --glass-smoke-fallback: var(--surface-inverse-deep);

  /* Ombres portées, hors du verre :
     · contour fantôme d'un pixel, qui dessine le bord sur un fond blanc ;
     · ombre de contact, courte et dense ;
     · ombre d'élévation, large et diffuse. */
  --glass-shadow: 0 0 0 1px rgba(1, 22, 51, 0.07),
    0 2px 6px -2px rgba(1, 22, 51, 0.14),
    0 26px 52px -20px rgba(1, 22, 51, 0.32);
  /* Lumière dans l'épaisseur du verre :
     · arête spéculaire haut-gauche, nette ;
     · contre-reflet bas-droit, plus discret ;
     · halo de lentille sur le pourtour, éteint dans la marge intérieure ;
     · ombre interne basse, qui donne le poids du verre. */
  --glass-sheen: inset 1px 1px 0 rgba(255, 255, 255, 0.85),
    inset -1px -1px 0 rgba(255, 255, 255, 0.32),
    inset 0 0 14px rgba(255, 255, 255, 0.45),
    inset 0 -12px 22px -16px rgba(1, 22, 51, 0.16);
  /* Même lumière, repeinte au-dessus de la fumée de l'état sombre : arêtes
     seules (aucun halo, qui éclaircirait le verre sous le texte clair) et
     ombre basse plus dense, qui ne peut qu'aider le texte clair. */
  --glass-sheen-dark: inset 1px 1px 0 rgba(255, 255, 255, 0.55),
    inset -1px -1px 0 rgba(255, 255, 255, 0.18),
    inset 0 -14px 24px -16px rgba(0, 6, 18, 0.6);
  /* Liseré : lumière franche en haut à gauche, qui s'éteint vers le milieu
     et revient, plus faible, en bas à droite. Peint par un calque masqué
     d'un pixel, au-dessus de tout le reste du verre. */
  --glass-rim: linear-gradient(
    135deg,
    rgba(255, 255, 255, 0.95) 0%,
    rgba(255, 255, 255, 0.35) 22%,
    rgba(255, 255, 255, 0) 48%,
    rgba(255, 255, 255, 0) 62%,
    rgba(255, 255, 255, 0.6) 100%
  );
  /* Lustre du bord haut, éteint avant la première ligne de texte */
  --glass-gloss-depth: var(--invite-padding);
  --glass-gloss: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.45) 0,
    rgba(255, 255, 255, 0) var(--glass-gloss-depth)
  );

  /* Échelle « rond » (~46 px) et pastilles de libellé. Sur un rond, le
     halo de 14 px de la carte blanchirait tout le disque jusqu'à l'icône,
     l'ombre d'élévation de 26 px en ferait une tache plus grande que lui,
     et un liseré à 95 % cernerait le disque d'un trait dur. On garde
     l'ordre des calques et les teintes ; on divise les portées par deux
     environ et on adoucit les arêtes d'un quart. Le lustre s'éteint à
     12 px, avant l'icône (qui commence à 13 px du bord). */
  --glass-shadow-sm: 0 0 0 1px rgba(1, 22, 51, 0.07),
    0 1px 3px -1px rgba(1, 22, 51, 0.16),
    0 10px 22px -10px rgba(1, 22, 51, 0.34);
  --glass-sheen-sm: inset 1px 1px 0 rgba(255, 255, 255, 0.7),
    inset -1px -1px 0 rgba(255, 255, 255, 0.26),
    inset 0 0 6px rgba(255, 255, 255, 0.4),
    inset 0 -6px 10px -7px rgba(1, 22, 51, 0.16);
  --glass-sheen-dark-sm: inset 1px 1px 0 rgba(255, 255, 255, 0.45),
    inset -1px -1px 0 rgba(255, 255, 255, 0.15),
    inset 0 -7px 12px -8px rgba(0, 6, 18, 0.6);
  --glass-rim-sm: linear-gradient(
    135deg,
    rgba(255, 255, 255, 0.75) 0%,
    rgba(255, 255, 255, 0.28) 22%,
    rgba(255, 255, 255, 0) 48%,
    rgba(255, 255, 255, 0) 62%,
    rgba(255, 255, 255, 0.45) 100%
  );
  --glass-gloss-depth-sm: var(--space-xs);
  --glass-gloss-sm: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.4) 0,
    rgba(255, 255, 255, 0) var(--glass-gloss-depth-sm)
  );

  /* Passage d'un état à l'autre : il suit le défilement. Le script écrit
     le ton (0 = clair, 1 = fumé) à chaque image ; cette durée ne fait que
     lisser les sauts entre deux images et animer la « finition » au
     repos. Courte, pour coller au doigt ; seule transition du ton (les
     couleurs en dérivent, elles ne s'animent pas en plus).
     Hors --motion-scale : rien ne se déplace. */
  --glass-tone-duration: 140ms;
  --glass-tone-easing: linear;
  /* Bascule des teintes de texte : la fumée suit le ton de 0 à 1, mais le
     texte ne change qu'entre 0.375 et 0.625, soit 30 px sur une rampe de
     120 px. Un texte à mi-chemin sur un verre à mi-chemin n'est lisible
     par personne : on raccourcit ce moment au lieu de l'étaler. */
  --glass-ink-switch-start: 0.375;
  --glass-ink-switch-span: 0.25;
  /* Repli sans color-mix() : bascule franche `.is-on-dark`, en fondu */
  --glass-tone-fallback-duration: 300ms;

  /* Invitation à lire les Conseils (carte flottante de l'accueil)
     Carte NON bloquante, dans le verre ci-dessus, posée dans un coin :
     aucun voile, rien n'empêche de lire ni de défiler. Elle paraît une
     fois, sous le header et la barre d'appel, au-dessus du contenu, sous
     les fenêtres. */
  --invite-width: 360px;
  --invite-offset: clamp(var(--space-sm), 2vw, var(--space-md)); /* 16 → 24 px */
  --invite-padding: var(--space-md);
  --invite-radius: var(--radius-signature-lg);

  /* Pastille du sur-titre et son halo statique, teinte de chaque état */
  --invite-dot-size: 8px;
  --invite-dot-halo-spread: 4px;
  --invite-dot-halo-color: rgba(74, 184, 164, 0.22);
  --invite-dot-halo-color-dark: rgba(143, 211, 196, 0.22);
  --invite-close-size: var(--burger-size);  /* cible tactile de 44 px    */
  --invite-close-hover: rgba(1, 22, 51, 0.07);
  --invite-close-hover-dark: var(--overlay-white-soft);
  /* Entrée : un peu plus lente qu'une transition d'interface, plus vive
     qu'une apparition de bloc. Déplacement et échelle reprennent les
     micro-réglages existants, déjà neutralisés en mouvement réduit. */
  --invite-duration: calc(460ms * var(--motion-scale));
  --invite-shift: var(--shift-lg);
  --invite-scale: var(--scale-enter);
  /* Juste sous l'en-tête, la barre d'appel et le menu (--layer-sticky) :
     le panneau du menu mobile doit recouvrir la carte, pas l'inverse. */
  --layer-floating: calc(var(--layer-sticky) - 1);

  /* Recherche
     ─────────────────────────────────────────────────────────────────────────
     LA LOUPE EST DÉRIVÉE DU BURGER, ELLE N'EST PAS RECOPIÉE. Les trois
     commandes de l'en-tête — burger, loupe, pastille d'appel — répondent à
     la même exigence, la cible tactile minimale, et doivent bouger ensemble
     le jour où elle change. C'est déjà la règle de
     --header-cta-compact-size ; la loupe la rejoint.

     LARGEUR DE LA FENÊTRE — DICTÉE PAR L'EXTRAIT, PAS PAR L'ÉCRAN.
     Le moteur découpe des extraits de 150 signes (`search.extraitLongueur`
     dans config.v1.3.0.js) et n'affiche jamais plus de 8 résultats. 640 px de
     fenêtre laissent 568 px de texte, soit 87 signes par ligne, mesurés :
     un extrait de 150 signes tient donc sur DEUX lignes, et un intitulé de
     résultat sur UNE jusqu'à 75 signes.
     Élargir ne rapporterait rien — l'extrait ne dépasse jamais 150 signes.
     Étrécir ferait passer les extraits à trois lignes puis quatre, donc la
     liste de huit résultats hors de l'écran : c'est ce qui arrive sur un
     téléphone, où l'on ne peut pas faire autrement.

     HAUT DANS L'ÉCRAN, PAS AU MILIEU. On tape, puis on lit vers le bas :
     la fenêtre est ancrée près du bord haut et grandit vers le bas. Le
     décalage est fluide et borné — assez d'air pour que le voile reste
     visible et cliquable (c'est la SEULE façon de refermer au doigt : le
     balisage ne prévoit pas de bouton de fermeture), assez peu pour que la
     fenêtre occupe la quasi-totalité d'un écran de téléphone.
     Mesuré sur un 390 × 844 : 358 px de large (92 % de l'écran) et 760 px
     de haut (90 %). */
  --header-search-size: var(--burger-size);
  --search-modal-width: 640px;
  --search-modal-offset-block: clamp(var(--space-sm), 5vh, var(--space-xl));
  --search-clear-size: var(--burger-size);
  --search-clear-glyph: 13px;      /* côté de chaque barre de la croix     */
  /* Épaisseur du repère de l'option active. C'est le seul indice qui dise
     « Entrée m'emmène là » : il est tenu à la teinte de l'anneau de focus,
     dont le contraste est déjà mesuré et surveillé par le banc. */
  --search-active-bar: var(--stroke-thick);
}

/* ═════════════════════════════════════════════════════════════════════════
   REPLI — navigateurs sans color-mix()
   Les états dérivés retrouvent leur teinte figée d'origine. Le site est
   strictement identique à l'œil ; seule la façon de calculer change.
   ═════════════════════════════════════════════════════════════════════════ */
@supports not (color: color-mix(in srgb, red, blue)) {
  :root {
    --surface-accent-hover: var(--brand-mint-600);
    --surface-inverse-hover: var(--brand-navy-700);
  }
}

/* ═════════════════════════════════════════════════════════════════════════
   9. VARIABLES ANIMÉES — @property
   Déclarer le type d'une variable change deux choses : le navigateur sait
   l'interpoler (au lieu de la faire sauter d'une valeur à l'autre), et une
   valeur invalide poussée par le script retombe sur l'initiale plutôt que
   d'invalider toute la règle. Les variables ci-dessous sont pilotées
   depuis le JavaScript : c'est exactement le cas d'usage.
   ═════════════════════════════════════════════════════════════════════════ */

/* Progression de lecture, de 0 à 1 — jauge en haut de page */
@property --progress {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

/* Décalage vertical du défilement différentiel */
@property --parallax {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}

/* Retard d'apparition d'un élément dans une cascade */
@property --reveal-delay {
  syntax: '<time>';
  inherits: true;
  initial-value: 0ms;
}

/* Ton de la carte d'invitation, de 0 (verre clair) à 1 (verre fumé) :
   part de la carte entrée dans une zone sombre. Typée pour s'interpoler
   et pour que les couleurs qui en dérivent suivent image par image. */
@property --invite-tone {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

/* Ton du verre des boutons ronds (.to-top, .quick__btn), même sens : 0 =
   verre clair, 1 = verre fumé. La carte y verse son --invite-tone, pour
   que la règle commune du matériau ne lise qu'une variable. */
@property --glass-tone {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

/* ═════════════════════════════════════════════════════════════════════════
   TÉLÉPHONE — échelle des titres et interligne (sous 48 rem)
   Décidé par Greg pour le lot « accueil mobile » (octobre 2026). L'échelle
   fluide ci-dessus touche son plancher dès 360 px : sur un téléphone, ce
   sont donc les PLANCHERS qui font la page, et ils étaient pensés pour une
   lecture d'écran large. Mesuré à 375 px : titre de section 28,7 px, titre
   du héros 34,4 px — un intertitre de deux lignes occupait le dixième de
   l'écran. Les titres descendent d'un cran, en gardant entre eux le rapport
   d'origine (h2 ≈ 0,8 × h1) :
     titre du héros (h1) ........ 34,4 → 30 px
     titres de section (h2) ..... 28,7 → 24 px
     titre d'article ............ 28,7 → 26 px
     intertitres d'article ...... 22,95 → 21 px (plancher : sous 21 px, un
       intertitre ne se détache plus assez d'un texte courant de 16 px)
   Le corps de texte NE BOUGE PAS : 16 px. C'est l'interligne qui se
   resserre, 1,65 → 1,5 (choix explicite de Greg) : à 16 px, 24 px de ligne
   restent confortables sur une colonne de 335 px, qui ne porte qu'une
   quarantaine de signes par ligne — l'interligne large sert les lignes
   longues, que le téléphone n'a pas.
   Les mentions de thème des cartes d'articles (12,48 px, text-xs) passent
   au corps des légendes, 14 px : c'était le plus petit texte lu de la
   rubrique, et le seul sous 14 px hors mention de copyright.
   Le seuil est un littéral : une condition de @media ne lit pas de
   variable. Il est celui de tout le lot (47.9375rem = 767 px).
   ═════════════════════════════════════════════════════════════════════════ */
@media (max-width: 47.9375rem) {
  :root {
    --text-4xl: 1.875rem;        /* 30px */
    --text-3xl: 1.5rem;          /* 24px */
    --article-h1-size: 1.625rem; /* 26px */
    --article-h2-size: 1.3125rem; /* 21px */
    --leading-normal: 1.5;
    --article-theme-size: var(--text-sm);
    /* Apparitions moins amples : 52 et 76 px parcourus sur un écran de
       375 px, c'était un sixième de sa largeur pour un glissement latéral.
       Les durées ne bougent pas. Le mouvement réduit, déclaré plus bas,
       les remet à zéro par-dessus. */
    --reveal-shift: 28px;
    --reveal-shift-x: 36px;
  }
}

/* ═════════════════════════════════════════════════════════════════════════
   TABLETTE PORTRAIT — 48 rem à 1000 px (1.9.0.2)
   Même plage que le palier tablette de la feuille de styles : le héros n'y
   prend plus la hauteur pensée pour un bureau. Seuils en littéraux, pour
   la même raison qu'au-dessus.
   ═════════════════════════════════════════════════════════════════════════ */
@media (min-width: 48rem) and (max-width: 1000px) {
  :root {
    --hero-min-height: var(--hero-min-height-tablet);
  }
}

/* ═════════════════════════════════════════════════════════════════════════
   ACCESSIBILITÉ — mouvement réduit
   Si la personne a demandé à son système de limiter les animations, on
   neutralise le mouvement à la source plutôt que composant par composant :
   durées, déplacements et facteurs d'échelle retombent tous à l'identité.
   ═════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-scale: 0.01;
    --stagger-step: 0ms;
    --dots-drift-duration: 0s;

    /* Apparitions : plus aucun déplacement, plus aucune découpe. Le
       contenu est simplement là. */
    --reveal-shift: 0px;
    --reveal-shift-x: 0px;
    --reveal-zoom: 1;
    --reveal-zoom-soft: 1;
    --reveal-tilt: 0deg;
    --clip-title-hidden: var(--clip-title-shown);
    --clip-wipe-hidden: var(--clip-wipe-shown);

    /* Survols et effets de composants */
    --button-lift: 0px;
    --button-hover-scale: 1;
    --card-lift: 0px;
    --card-hover-scale: 1;
    --channel-lift: 0px;
    --channel-arrow-shift: 0px;
    --card-bullet-hover-scale: 1;
    --card-list-shift: 0px;
    --card-list-stagger: 0ms;
    --icon-badge-ring-scale: 1;
    --icon-badge-ring-opacity: 0;
    --metric-pop-from: 1;
    --metric-halo-scale: 1;
    --metric-halo-opacity: 0;
    --step-number-shift: 0px;
    --step-number-hover-scale: 1;
    --faq-chevron-hover-scale: 1;
    --dots-enter-scale: 1;

    --shift-3xs: 0px;
    --shift-xs: 0px;
    --shift-md: 0px;
    --shift-lg: 0px;
    --shift-xl: 0px;

    --scale-press: 1;
    --scale-enter: 1;
    --scale-enter-deep: 1;
    --scale-hover: 1;
    --scale-tilt: 1;
    --scale-pulse: 1;
    --scale-zoom-from: 1;
    --reveal-delay-max: 0ms;
    --scale-cover: 1;
    --tilt-angle: 0deg;

    /* Bandeau de témoignages : c'est l'amplitude qui tombe, pas la durée.
       La bande reste exactement là où elle démarre — première carte
       entière — et se parcourt à la main comme avant. */
    --quote-loop-shift: 0px;
    --tool-loop-shift: 0px;

    --parallax-range: 0%;

    /* Barre d'appel : elle paraît en fondu, sur place, sans glisser. */
    --cta-bar-enter-shift: 0%;

    /* Invitation aux Conseils : un vrai fondu, sur place. La durée ne
       suit pas --motion-scale (elle tomberait à 5 ms, soit une apparition
       brutale) : sans aucun déplacement, un fondu court ne gêne personne. */
    --invite-duration: 240ms;
    /* Le changement de ton n'est pas un mouvement : il reste, un peu
       plus doux, pour qu'un passage rapide ne clignote pas. */
    --glass-tone-duration: 200ms;
    /* Raccourcis : la cascade tombe, la pile paraît d'un seul fondu. */
    --quick-stagger: 0ms;
    --round-hover-scale: 1;
    --quick-duration: 240ms;
    --quick-label-shift: 0px;
  }
}
