/* ============================================================
   DESIGN SYSTEM Cercles : variables uniques. La direction artistique est Orbite (retenue
   le 25/10/2026) : ses couleurs, sa police et ses boutons sont dans le `:root` de son
   bloc, en fin de feuille, qui complète celui-ci.
   Règle : AUCUNE couleur/taille/police en dur dans le reste du CSS.
   ============================================================ */
:root {
  color-scheme: light;

  /* Couleurs : le blanc de la page ici ; l'encre, le clair et la couleur principale
     (`--couleur-accent`, que l'ORNEMENT suit) dans le `:root` d'Orbite. `npm run
     verif:couleurs` refuse toute autre valeur dans cette feuille. */
  --couleur-fond: #ffffff;

  /* Alias de sens, pour que le code se lise */
  --couleur-texte: var(--couleur-encre);
  --couleur-texte-sur-sombre: var(--couleur-fond);
  /* Le texte qui suit une accroche (la biographie d'une fiche) : l'encre adoucie, AA tenu. */
  --couleur-texte-doux: color-mix(in srgb, var(--couleur-encre) 72%, var(--couleur-fond));
  --couleur-accent-contraste: var(--couleur-fond);
  /* Le texte et le trait d'une capsule survolée (01/11/2026) : la couleur principale, que les
     capsules noires remplacent par le blanc. */
  --couleur-survol: var(--couleur-accent);
  /* Le trait de CONTEXTE : anneau d'un portrait, glyphe d'un état d'écran, contour d'un
     badge, dessin d'un point d'état. Noir partout depuis que le panneau noir de l'accueil
     a disparu (10/10/2026) : le jeton reste, il nomme ce trait. Sa valeur est dans le `:root`
     d'Orbite. */

  /* LE VERRE : deux surfaces seulement sont translucides, et leur opacité n'existe QUE dans ces
     deux jetons (un texte, un fond de page, un filet, une bordure, un contour sont toujours à 1).
     Les capsules, elles, sont des aplats (le fond de la page ou l'encre), cernés du trait
     ci-dessous : plus de verre, d'ombre portée ni de flou sous un bouton depuis le 24/10/2026. */
  /* La bande du header d'Orbite (25/10/2026) : assez claire et peu floutée pour que les orbites
     et les portraits du hero s'y devinent, assez blanche pour qu'un texte qui défile dessous
     ne gêne pas la marque. */
  --verre-entete: rgba(255, 255, 255, 0.6);
  /* Le voile sous la fenêtre d'invitation à créer son compte : la page reste lisible derrière. */
  --verre-voile: rgba(255, 255, 255, 0.55);
  --flou-entete: blur(4px) saturate(160%);
  /* LE TRAIT DES CAPSULES : un contour d'encre de 1,5 px, net et uniforme, le même sur tout
     ce qui se clique (boutons blancs, bleus et noirs, bulle et burger du header, capsule
     segmentée, étiquettes, pilules). Plus aucun reflet depuis le 23/10/2026 (« mets tous les
     boutons en traits noirs simples, comme le menu burger », Matthias) : la bande claire du
     haut effaçait le haut du contour et faisait un faux volume. Rentré dans la boîte
     (`inset`), il ne décale aucun voisin. */
  --trait-capsule: inset 0 0 0 var(--epaisseur-contour) var(--couleur-encre);

  /* Typographie (DESIGN.md §3) : une seule famille, Bricolage Grotesque (`--police`, dans le
     `:root` d'Orbite), trois graisses. Le texte secondaire n'est pas gris : il est de l'encre,
     plus petit, en 400. */
  /* Le texte courant suit la largeur de l'écran au-delà de 1440 px (24/10/2026, Matthias : « sur
     mon écran il y a beaucoup d'espace sur les côtés, il faudrait que ce soit plus rempli ») : 17 px
     jusqu'à 1440, environ 19 px à 1920. Le hero et le header ne bougent pas. */
  --taille-xs: clamp(0.8125rem, 0.4rem + 0.42vw, 1rem);
  --taille-s: clamp(0.9375rem, 0.45rem + 0.5vw, 1.125rem);
  --taille-base: clamp(1.0625rem, 0.55rem + 0.55vw, 1.25rem);
  --taille-m: clamp(1.1875rem, 1.6vw, 1.5rem);
  --taille-l: clamp(1.25rem, 0.6rem + 0.68vw, 1.5rem);
  --taille-xl: clamp(1.5rem, 0.7rem + 0.85vw, 1.875rem);
  --taille-xxl: clamp(2.25rem, 4.2vw, 4.5rem);
  /* Le titre d'une étape du guide « Devenir expert » (26/10/2026, « de gros textes ») : 28 px
     sur téléphone, 37 à 1440, 40 au plafond. Entre le h2 d'un formulaire et le h1. */
  --taille-titre-guide: clamp(1.75rem, 0.9rem + 1.6vw, 2.5rem);
  /* Le titre et l'accroche du hero (et des pages d'état) grandissent le 23/10/2026 (« augmente
     la taille du reste », Matthias) : 48 à 96 px, 20 à 26 px. */
  --taille-hero: clamp(3rem, 6.4vw, 6rem);
  --taille-accroche-hero: clamp(1.25rem, 1.75vw, 1.625rem);
  /* Le besoin auquel répond une durée, sur l'accueil : une phrase de trois mots, grande. */
  --taille-besoin: clamp(2.5rem, 7vw, 5.5rem);
  --taille-marque-texte: 1.375rem;
  --taille-numero: 1.625rem;
  --graisse-normale: 400;
  --graisse-moyenne: 500;
  --graisse-titre: 600;
  /* DESIGN.md §3 donne un interlettrage ET un interligne PAR NIVEAU de titre, et les
     deux échelles ne se suivent pas. La règle `h1, h2, h3` porte les valeurs du h2 et
     chaque niveau reprend plus bas le seul jeton où il s'en écarte : un jeton par valeur
     du tableau, jamais une valeur en dur hors de ce bloc. L'interlettrage serré (titre du
     hero) est dans le `:root` d'Orbite. */
  --interlettrage-titre-h2: -0.02em;
  --interlettrage-titre-h3: -0.01em;
  --interlettrage-marque: -0.02em;
  --interligne-texte: 1.5;
  --interligne-accroche: 1.45;
  --interligne-hero: 0.98;
  --interligne-titre: 1.15;
  --interligne-titre-h1: 1.05;
  --interligne-titre-h3: 1.2;

  /* Espacements */
  --espace-xs: 0.25rem;
  --espace-s: 0.5rem;
  --espace-m: 1rem;
  --espace-l: 2rem;
  --espace-xl: 4rem;
  --espace-xxl: 7rem;
  --espace-section-accueil: clamp(5rem, 10vw, 8.125rem);
  /* La réserve intérieure de la capsule segmentée (6 px dans la maquette), et la réserve
     latérale d'un segment : celle d'un bouton là où la place abonde, et fluide en dessous.
     Mesuré avec les trois durées : à 22 px fixes la capsule demandait 319 px, plus que la
     colonne d'un écran de 320 px (272 px), dont elle débordait. */
  --espace-reserve-segments: 0.375rem;
  --padding-segment: clamp(0.5rem, 4vw, 1.375rem);
  /* Les gouttières fluides du shell : celle du header et du hero (la même, pour que la
     capsule et l'accroche partagent leur colonne), celle du pied de page, celle de la
     colonne des sections de l'accueil ; et l'écart entre deux entrées du header.
     Celle du pied de page ne descend pas sous celle des colonnes de contenu : sur petit
     écran il s'aligne sur elles, au lieu de coller au bord.
     ⚠️ AUCUNE NE DESCEND SOUS 1,5rem (appel d'Abel du 01/11/2026, sur son Samsung Fold : « tout
     est très au bord ») : le header et le hero étaient à 16 px du bord d'un téléphone, les
     sections de l'accueil à 15 à 18 px sur une tablette, contre 24 px aux pages. */
  --gouttiere-shell: clamp(1.5rem, 4vw, 3rem);
  --gouttiere-pied: clamp(1.5rem, 3vw, 2.5rem);
  /* Les colonnes du pied de page : la présentation, puis trois listes de liens. */
  --colonne-pied-presentation: 2fr;
  --colonne-pied-liens: 1fr;
  --largeur-pied-presentation: 22rem;
  /* La gouttière des colonnes de contenu (`.colonne`, `.page`). Sous 48rem elle passe à
     1,5rem (bloc mobile du shell) : avec le texte de 17 px, la colonne de 311 px d'un
     écran de 375 px ne tenait plus « Reporter » et « Annuler le rendez-vous » sur un
     rang (315 px mesurés) ; à 327 px elle les tient. */
  --gouttiere-page: 2rem;
  --gouttiere-accueil: 1.5rem;
  --retrait-etapes: clamp(0.25rem, 2vw, 2rem);
  /* Le champ déplié de la recherche du header : la place que la capsule laisse entre la
     marque et le burger, moins son bouton rond et les écarts (159 px à 375 px de large, où
     l'exemple « Un domaine, un nom… » tient encore), 256 px au plus. */
  --largeur-recherche-nav: clamp(6rem, 100vw - 13.5rem, 16rem);
  /* Le champ des langues de `/expert` : la largeur où « Rechercher une langue » tient entier
     (183 px de texte), sans dépendre de la fenêtre comme celui du header, qui le laissait à
     82 px à 344 px de large (01/11/2026). Une colonne plus étroite le borne d'elle-même. */
  --largeur-recherche-langue: 16rem;
  /* Le panneau du burger, un volet sous la barre. */
  --largeur-panneau-nav: 22rem;
  /* L'EN-TÊTE : la hauteur de sa barre, la marge qui la détache des bords (0, une barre pleine
     largeur), la largeur au plus et la réserve latérale de la barre, son rayon, et la hauteur
     de ses deux bulles. Le trait qui la souligne (`--entete-trait`) est dans le `:root`
     d'Orbite. `--hauteur-entete` est la hauteur EXACTE de l'en-tête : les ancres et les blocs
     collés au défilement la laissent au-dessus d'eux, le hero de l'accueil la retire de la
     fenêtre. */
  --entete-hauteur: 4.5rem;
  --entete-marge: 0rem;
  --entete-largeur: var(--largeur-entete);
  --entete-reserve: var(--gouttiere-shell);
  --entete-rayon: 0;
  --hauteur-bulle-entete: var(--hauteur-bouton);
  /* La loupe de la recherche et la photo du compte, rentrées d'une demi-marge dans leur capsule. */
  --taille-loupe-entete: calc(var(--hauteur-bulle-entete) - var(--espace-s));
  --taille-loupe-entete-etroite: 2.25rem;
  --hauteur-entete: calc(var(--entete-hauteur) + var(--entete-marge) * 2 + var(--entete-trait));
  /* Le glyphe de la marque, en CSS : son trait, son point, de combien il déborde, son halo. */
  --epaisseur-glyphe: 0.25rem;
  --taille-point-glyphe: 0.75rem;
  --debord-point-glyphe: -0.1875rem;
  --halo-point-glyphe: 0.1875rem;

  /* Rayons (DESIGN.md §5) : tout est arrondi, aucun angle vif nulle part. */
  --rayon-carte: 1.5rem;
  --rayon-carte-grande: 2rem;
  --rayon-panneau: clamp(2.5rem, 6.5vw, 6rem);
  --rayon-pilule: 999px;
  --rayon-case: 0.3rem;

  /* Boutons. 52 px de haut et un texte de 18 px depuis le 23/10/2026 (44 et 17 avant) : les
     boutons, la bulle et le burger du header, les champs qui les côtoient. Ce qui n'est
     qu'une cible tactile (une entrée du volet, un lien du pied de page, une pilule, un
     segment, le résumé d'une question) garde ses 44 px : `--hauteur-lien`. */
  --hauteur-bouton: 3.25rem;
  --hauteur-lien: 2.75rem;
  /* Les entrées rangées par rubrique dans le volet du compte : 32 px de cible (40 sous
     48rem) ; leur intitulé PLUS GROS qu'elles, en graisse de titre (25/10/2026). */
  --hauteur-lien-compte: 2rem;
  --taille-intitule-compte: var(--taille-m);
  --padding-bouton: 1.375rem;
  /* La police et la réserve latérale d'un bouton, d'une bulle du header : réduites sous
     48rem (bloc mobile du shell), la hauteur restant la même. */
  --taille-bouton: 1.125rem;
  --reserve-bouton: 1.75rem;
  --reserve-bulle: 1.25rem;
  --taille-bouton-rond: 3.5rem;
  /* De combien le bouton rond au combiné déborde du portrait, en bas à droite. */
  --debord-decrocher: -0.375rem;
  --epaisseur-trait-icone: 2;

  /* Dimensions */
  /* La boîte du logo dans le header. Le dessin de `logo.svg` laisse au halo de son point
     12 unités sur 67 : dans 2rem, l'anneau mesure 26 px, la taille que DESIGN.md §7 lui
     donne (run DA-0, décision 3 ; mesure dans FEATURES.md § Refonte visuelle, run DA-1). */
  --taille-marque: 2rem;
  --taille-case: 1.125rem;
  /* La croix d'une langue choisie, et la hauteur de ses suggestions (huit lignes). */
  --taille-croix: 0.625rem;
  /* Le décalage d'une bulle d'avis sur sa voisine : leur bord ondule sans qu'aucune bouge comme
     sa voisine. */
  --decalage-bulle: -1.1s;
  --hauteur-suggestions: 19rem;
  --taille-pastille: 6rem;
  /* Le portrait de la fiche publique est le plus grand de l'application : c'est la
     page d'une seule personne. Un jeton plutôt qu'une valeur posée sur place, la
     pastille et son anneau étant réglés une fois pour toutes par `--taille-pastille`. */
  --taille-pastille-fiche: 9rem;
  /* Le portrait d'un expert sur l'accueil : les 148 px de la maquette, qu'il garde à
     partir de 360 px de large. En dessous il suit la fenêtre : la grille du cadre des experts
     passe à deux colonnes de 112 px sur un écran de 320 px, et deux disques de 148 px
     s'y chevauchaient, le bouton rond du second sortant du cadre (mesuré au run DA-2).
     À 50vw moins 2rem, deux disques de 128 px y tiennent côte à côte sans se toucher. */
  --taille-portrait-accueil: min(9.25rem, 50vw - 2rem);
  --taille-portrait-prochain: 3.25rem;
  /* Le portrait du bloc profil, en bas du volet : 64 px, la hauteur du nom et de l'adresse. */
  --taille-portrait-compte: 4rem;
  /* Le portrait de l'auteur d'un avis : 56 px. */
  --taille-portrait-avis: 3.5rem;
  /* Les avis de l'accueil en bulles : le cercle qu'elles dessinent, et le portrait de la
     carte de l'avis choisi. */
  --largeur-bulles-avis: 30rem;
  /* Trois formes de goutte (rayons horizontaux / verticaux). */
  --goutte-a: 58% 42% 47% 53% / 52% 46% 54% 48%;
  --goutte-b: 44% 56% 61% 39% / 47% 58% 42% 53%;
  --goutte-c: 52% 48% 38% 62% / 60% 44% 56% 40%;
  --duree-goutte: 6s;
  --taille-portrait-carte-avis: 5rem;
  /* Le point d'état et ses quatre dessins (DESIGN.md §4) : 12 px. */
  --taille-point: 0.75rem;
  /* Les cinq points de la moyenne des avis (fiche publique, `/avis`) : 20 px. Le jeton avait
     disparu au run des trois DA (v109), et les points retombaient à leur taille de notation. */
  --taille-point-moyenne: 1.25rem;
  --taille-point-moyenne-carte: 0.875rem;
  /* Le nom de la fiche publique, un cran sous le h1 des pages (30/10/2026 : il écrasait le
     reste de l'en-tête). */
  --taille-nom-fiche: clamp(2rem, 1.2rem + 2vw, 3rem);
  /* La largeur sous laquelle l'identité de la fiche passe sous le portrait. */
  --largeur-identite-fiche: 18rem;
  /* Le disque d'un numéro : les quatre étapes de l'accueil, les cinq du guide « Devenir
     expert ». */
  --taille-numero-etape: 4rem;
  /* Le signe rond d'une question de la FAQ. */
  --taille-signe-question: 2rem;
  /* La colonne des pages s'élargit avec l'écran (24/10/2026) : 1240 px jusqu'à 1460 px de
     large, puis 85 % de la fenêtre, 1920 px au plus. Le header garde sa largeur. */
  --largeur-max: clamp(77.5rem, 85vw, 120rem);
  --largeur-entete: 77.5rem;
  --largeur-texte: clamp(38rem, 36vw, 50rem);
  /* Une page de formulaire : assez étroite pour que les libellés restent au-dessus de
     leur champ plutôt qu'à l'autre bout de l'écran. Elle s'élargit avec l'écran d'ordinateur
     (demande de Matthias du 27/10/2026, « prend plus de place sur le côté ») : 544 px
     jusqu'à 1210 px de large, puis 45 % de la fenêtre, 896 px au plus. */
  --largeur-page: clamp(34rem, 45vw, 56rem);
  /* Un cran plus large, pour les pages de listes : jamais plus étroite que la page de
     formulaire, que le grand écran élargit plus vite que la largeur de lecture. */
  --largeur-page-liste: max(var(--largeur-texte), var(--largeur-page));
  /* En `em` : elles suivent la taille du texte qu'elles bornent. */
  --largeur-accroche: 30em;
  --largeur-titre-hero: 11em;
  --largeur-titre-carte-bleue: 13em;
  --largeur-carte-bleue: 57.5rem;
  /* La colonne d'un portrait de « Ils décrochent » tient le portrait ET son bouton rond qui
     déborde : à 140 px, une colonne de 144 px laissait le bouton du dernier portrait à 15 px
     du bord d'une tablette (884 px, 01/11/2026). */
  --largeur-portrait-min: min(var(--taille-portrait-accueil) - var(--debord-decrocher), 42%);
  /* La carte de réservation de la fiche publique (DESIGN.md §6). C'est elle qui
     décide du moment où la fiche passe sur une seule colonne : la largeur de lecture
     plus cette carte plus leur gouttière, et pas une taille d'écran devinée. */
  --largeur-reservation: 20rem;
  /* L'avis mis en avant, replié, dans cette carte. */
  --lignes-avis-en-avant: 4;
  /* La biographie repliée de la fiche : son accroche, ou à défaut son seul paragraphe. */
  --lignes-accroche: 2;
  --lignes-biographie: 3;
  /* La biographie de la fiche, plus étroite que la lecture courante : une soixantaine de
     caractères par ligne. */
  --largeur-biographie: 36rem;
  /* La fiche publique : l'identité et la biographie gardent à côté de la carte une largeur
     de lecture. */
  --largeur-fiche: 64rem;
  /* La carte d'une demande de certification (feature 9, run 92) : deux colonnes qui se
     replient par leurs propres largeurs, comme la fiche publique. À gauche les pièces et
     leurs trois commandes, à droite le panneau d'aperçu, assez large pour lire un PDF.
     Côte à côte dès que la colonne les tient, l'une sous l'autre en dessous, sans point
     de rupture. */
  --largeur-examen: 30rem;
  --largeur-apercu: 30rem;
  /* L'image de partage d'une fiche sous le portrait de `/expert` (feature 25) : la largeur
     d'une carte d'aperçu de lien dans une conversation, 300 px, pour qu'elle se lise comme
     ce qu'elle est, et qui tient dans la colonne la plus étroite. */
  --largeur-image-partage: 18.75rem;
  /* La hauteur du cadre d'aperçu : assez pour lire une page, jamais plus que la fenêtre,
     pour que le panneau collé au défilement tienne entier à l'écran. */
  --hauteur-apercu: min(70dvh, 48rem);
  --hauteur-apercu-email: 40rem;
  --largeur-fenetre: 44rem;
  --largeur-apercu-email: 38rem;
  /* La largeur sous laquelle le nom d'un expert ne tient plus à côté de son
     portrait : en dessous, l'identité passe sous la pastille. */
  --largeur-identite: 15rem;
  /* La colonne de gauche d'une ligne d'avis : la note, l'auteur et les deux dates, sur
     une largeur fixe pour que les textes s'alignent d'une ligne à l'autre. */
  --largeur-avis-tete: 17rem;
  /* Un champ qui n'attend que trois chiffres (le tarif horaire, le délai minimum de
     réservation) : pleine largeur, il promettrait une phrase. */
  --largeur-champ-court: 9rem;
  /* Une heure et une date (feature 13). Deux jetons et non un seul : le champ de date
     porte « 24/12/2026 » et son icône de calendrier, le champ d'heure « 09:00 » et la
     sienne, et le second serré à la largeur du premier coupe le sélecteur de Chrome.
     Remesurés à la refonte (texte de 17 px, contour de 1,5 px) : le sélecteur d'heure
     demande 77 px et en trouve 85, celui de date 132 et en trouve 133, avec la réserve
     latérale propre à ces deux champs écrite plus bas (le champ de date a pris un demi-rem
     pour cela). Les deux bornes d'une plage tiennent sur une ligne dans la colonne la plus
     étroite. */
  --largeur-champ-heure: 7.5rem;
  --largeur-champ-date: 10.5rem;
  /* Les intitulés du récapitulatif de réservation (« Date et heure », « Prix TTC ») :
     la PREMIÈRE PISTE de la grille de chaque ligne (`.recap-ligne`), sinon les quatre
     valeurs ne s'alignent pas d'une ligne à l'autre et la liste se lit en escalier. */
  --largeur-recap-libelle: 8rem;
  /* Les huit compteurs de l'administration : des intitulés de phrase, qui ne tiennent pas
     sur 8rem sans passer à trois lignes ; la part en pour cent les garde lisibles à 375 px. */
  --largeur-recap-admin: min(22rem, 60%);
  /* La barre fixée en bas d'écran qui porte « Réserver » sous 48rem (DESIGN.md §6) :
     la hauteur du bouton, sa réserve et LE FILET qui la sépare de la page, reprise en
     bas de page pour que le pied de page ne finisse jamais sous elle. Le filet en fait
     partie : la barre fait 61 px (8 + 44 + 8, plus son `border-top`), et l'oublier
     laissait la dernière rangée de pixels du pied de page passer dessous. */
  --hauteur-barre-reservation: calc(
    var(--hauteur-bouton) + var(--espace-m) + var(--epaisseur-filet)
  );
  /* La colonne des sept noms de jours. « Mercredi » est le plus long ; en dessous, le nom
     et ses plages se replient l'un sous l'autre. */
  --largeur-jour: 5.5rem;
  /* Ce que le bloc de plages demande pour tenir à côté du nom du jour : deux bornes et
     leur commande. En dessous, il passe sous le nom (aucun point de rupture, feature 11). */
  --largeur-plages: 22rem;
  --hauteur-zone-texte: 10rem;
  /* Une question de la vidéo (`/admin/reglages`) : trois lignes et la réserve de la zone. */
  --hauteur-zone-question: 5.5rem;

  /* États d'écran (feature 7) : les formes du squelette de chargement, et le glyphe du
     logo à l'échelle d'un état vide ou d'une erreur réseau. La forme de titre prend la
     hauteur de ligne EXACTE du h1 qu'elle remplace, fluide comprise : c'est ce qui
     aligne le squelette sur son contenu à toutes les largeurs plutôt qu'à une seule. */
  --hauteur-squelette-ligne: 0.75rem;
  --hauteur-squelette-titre: calc(var(--taille-xxl) * var(--interligne-titre-h1));
  --largeur-squelette-bouton: 11rem;
  --largeur-squelette-prix: 7rem;
  --taille-anneau-etat: 5rem;
  /* Le point bleu du glyphe, et de combien il déborde de l'anneau en haut à droite. */
  --taille-point-etat: 1.4rem;
  --debord-point-etat: calc(var(--taille-point-etat) / -2.5);

  /* Traits */
  --epaisseur-filet: 1px;
  --epaisseur-contour: 1.5px;
  --epaisseur-champ-faute: 3px;
  /* Le trait d'une capsule survolée (01/11/2026). */
  --epaisseur-trait-survol: 3px;
  --epaisseur-anneau-portrait: 2px;
  --epaisseur-logo: 0.4375rem;
  --epaisseur-point-cible: 2px;
  --epaisseur-focus: 2px;
  --epaisseur-marqueur: 2px;
  --decalage-focus: 3px;

  /* Hero de l'accueil et des pages d'état (DESIGN.md §6). Les deux boutons de l'accueil sont
     posés sous l'accroche, la capsule « prochain rendez-vous » aussi, juste dessous. */
  --hero-haut: clamp(3.5rem, 7vw, 5.75rem);
  --hero-ecart-cta: 6.5rem;
  --hero-ecart-prochain: 2rem;
  /* Le bas des pages d'état seulement : celui de l'accueil est `--hero-accueil-bas`. */
  --hero-bas: 12rem;
  --hero-accueil-bas: 3rem;
  /* Les boutons : le trait du principal ; le fond, le texte et le trait du secondaire ; de
     combien ils montent au survol (0 : ils ne bougent pas, et ce `translateY`
     l'emporte sur la descente au clic de `.bouton:active`). Le fond du marqueur « vous êtes
     ici ». Le fond, le texte et le survol du principal, le trait du secondaire et la carte
     « Rejoignez le cercle » sont dans le `:root` d'Orbite. */
  --bouton-principal-trait: 0 0 0 0 transparent;
  --bouton-secondaire-fond: var(--couleur-fond);
  --bouton-secondaire-texte: var(--couleur-encre);
  --bouton-montee: 0px;
  --marqueur-fond: var(--couleur-encre);
  /* Les pages d'état : le pointillé qui double leur grand anneau, le liseré qui détache son
     point. */
  --pointille-etat: 0.625rem;
  --lisere-etat: 0.375rem;
  /* Les orbites du hero : trois ellipses autour du titre et de l'accroche (une largeur,
     un aplatissement), des portraits de plus en plus grands vers l'extérieur, trois vitesses,
     deux sens. Leur centre, dans le hero. L'anneau d'or d'un portrait, détaché par un liseré
     blanc. EMBOÎTÉES, AU MÊME APLATISSEMENT, ELLES NE SE CROISENT JAMAIS (appel d'Abel du
     01/11/2026, « ça fait beaucoup trop de choses ») : chacune est plus large ET plus haute que
     la précédente, d'un même écart (25rem de large, 5rem de haut de chaque côté). La plus
     petite tient le titre, l'accroche et les boutons. */
  /* Le hero remonte derrière le header (25/10/2026) : son centre descend d'une demi-hauteur
     de header, et les orbites restent où elles étaient autour du texte. */
  --orbites-centre-y: calc(50% - 1.125rem + var(--hauteur-entete) / 2);
  --decalage-texte-hero: 2.1875rem;
  --remontee-cta-hero: 1rem;
  /* Un expert réel sur une orbite : le portrait des plus grands (la troisième orbite). */
  --orbite-vedette: var(--orbite-3-portrait);
  /* La carte condensée d'un expert des orbites : sa largeur, son portrait, son écart au
     portrait cliqué et aux bords de la fenêtre. */
  --largeur-orbite-carte: 21rem;
  --taille-portrait-orbite-carte: 4rem;
  --marge-orbite-carte: var(--espace-m);
  --orbite-1-largeur: 100rem;
  --orbite-1-aplati: 0.4;
  --orbite-1-portrait: 4.25rem;
  --orbite-1-depart: -70deg;
  --orbite-2-largeur: 125rem;
  --orbite-2-aplati: 0.4;
  --orbite-2-portrait: 5.25rem;
  --orbite-2-depart: -110deg;
  --orbite-3-largeur: 150rem;
  --orbite-3-aplati: 0.4;
  --orbite-3-portrait: 5.5rem;
  --orbite-3-depart: -60deg;
  /* Les points de couleur qui tournent avec les orbites : trois tailles, plus deux aux extrêmes
     pour les orbites de la fiche (Matthias, 01/11/2026 : « varie plus leur taille »), et trois
     teintes de la couleur principale mêlée au blanc de la page, en plus de la couleur
     principale et de l'encre. Depuis le bleu du pied de page (01/11/2026), la « foncée » se mêle
     au blanc elle aussi : mêlée à l'encre, elle ne se distinguait plus ni de l'une ni de l'autre
     (#0e162c). */
  --astre-minuscule: 0.3125rem;
  --astre-petit: 0.5rem;
  --astre-moyen: 0.8125rem;
  --astre-grand: 1.25rem;
  --astre-tres-grand: 1.75rem;
  --teinte-astre-claire: color-mix(in srgb, var(--couleur-accent) 55%, var(--couleur-fond));
  --teinte-astre-tres-claire: color-mix(in srgb, var(--couleur-accent) 28%, var(--couleur-fond));
  --teinte-astre-foncee: color-mix(in srgb, var(--couleur-accent) 78%, var(--couleur-fond));
  --trait-orbite: 1.5px;
  --duree-orbite-1: 80s;
  --duree-orbite-2: 115s;
  --duree-orbite-3: 160s;
  /* Les orbites de la fiche publique, le long du header (Matthias, 01/11/2026, dessin d'un trait
     d'un coin haut à l'autre, qui descend un peu sous le header au milieu) : la largeur de la
     grande, plus large que la fenêtre, l'écart de la seconde, leur aplatissement, la hauteur où
     descend le bas de la grande, leur trait, plus épais que celui de l'accueil, l'espace qui
     tient la fiche sous elles, et leurs tours, lents (le long d'une si grande orbite, un point
     va vite). */
  --fiche-orbite-largeur: 160vw;
  --fiche-orbite-ecart: 8vw;
  --fiche-orbite-aplati: 0.22;
  --fiche-orbite-bas: 7rem;
  --trait-fiche-orbite: 2.5px;
  --fiche-haut: var(--espace-xxl);
  --duree-fiche-orbite: 260s;
  --duree-fiche-orbite-interieure: 140s;
  /* Les cercles tracés sur la carte « Rejoignez le cercle » (dessin de Matthias du
     25/10/2026) : un grand arc au coin haut gauche, deux anneaux emboîtés au coin bas droit,
     centrés au-delà des coins (le décalage), au trait épais de la couleur principale. Ce sont
     des orbites où tournent des portraits (le même jour) : leur taille, et trois vitesses
     lentes, les deux anneaux en sens contraires. */
  --trait-carte-cercle: 4px;
  --carte-arc-rayon: 27.5rem;
  --carte-arc-centre-x: -3rem;
  --carte-arc-centre-y: -22rem;
  --carte-anneau-rayon: 8rem;
  --carte-anneau-ecart: 4.25rem;
  --carte-anneau-centre: 2rem;
  --carte-orbite-portrait: 3rem;
  --duree-carte-arc: 200s;
  --duree-carte-anneau: 130s;
  --duree-carte-anneau-grand: 170s;
  /* L'anneau du portrait et le liseré blanc qui le détache de la photo. */
  --anneau-portrait: 3px;
  --lisere-portrait: 2px;
  /* LE POINT DU LOGO, EN PROPORTIONS (feature 31, run B1) : celles du point du voile, validé par
     Abel. Son centre à 11,8 % du haut et du bord droit du cercle qui le porte, comme dans le logo
     (`scripts/marque.py`), son diamètre à 22 % de ce cercle, son halo à 30 % de son diamètre. Le
     voile et le point de Cercles sur l'anneau d'un portrait les lisent tous deux. Survolé ou
     focalisé, le point d'un portrait grandit dans son halo. */
  --place-point: 0.118;
  --part-point: 0.22;
  --part-halo: 0.3;
  --survol-point: 1.3;
  /* Où commence la pastille dans la boîte qui porte le point : en haut, sauf dans une ligne de
     liste, où elle est centrée en hauteur (`.carte`). */
  --haut-pastille: 0rem;
  /* Le lecteur d'une vidéo de certification : jamais plus haut que l'écran n'en laisse. */
  --hauteur-lecteur-video: min(60dvh, 36rem);
  /* Le décor des trois pages d'état, en bas à droite. */
  --decor-etat: 60vmin;
  --decor-etat-debord: -14vmin;
  /* Le pied de page serré (25/10/2026) : des liens de 28 px de haut. Son fond est la couleur
     principale elle-même depuis le 01/11/2026. */
  --hauteur-lien-pied: 1.75rem;
  /* Le voile de l'accueil, « Le cercle » (25/10/2026) : le titre sur deux lignes, puis une scène
     carrée où tout se mesure en parts de son côté (l'anneau du logo au centre, son point à
     11,8 % du haut et du bord droit comme dans le logo, trois orbites de trois à cinq portraits),
     puis la phrase. Le côté de la scène est ce que la fenêtre laisse, entre 10rem et 44rem. Sur une
     fenêtre de moins de 26,25rem de haut (un téléphone en paysage), le rythme se resserre : voir
     le `@media (max-height)` du voile, plus bas. */
  --arrivee-titre-min: 2.25rem;
  --arrivee-titre: clamp(var(--arrivee-titre-min), min(6vw, 8.5vh), 5rem);
  --arrivee-ecart: var(--espace-l);
  --arrivee-bas: var(--arrivee-ecart);
  --arrivee-scene-min: 10rem;
  /* La gouttière des pages d'arrivée, celle du shell d'avant le 01/11/2026 : Abel les a
     validées ainsi, et le plancher de 1,5rem du shell réduisait la scène de 16 px. */
  --gouttiere-arrivee: clamp(1rem, 4vw, 3rem);
  --arrivee-scene: max(
    var(--arrivee-scene-min),
    min(
      100vw - 2 * var(--gouttiere-arrivee),
      100dvh - var(--arrivee-bas) - var(--arrivee-titre) * 2 - var(--taille-m) * 1.5 - var(--arrivee-ecart) * 3 -
        var(--espace-s) * 2,
      44rem
    )
  );
  --arrivee-part-cercle: 0.42;
  --arrivee-cercle: calc(var(--arrivee-scene) * var(--arrivee-part-cercle));
  --arrivee-portrait: calc(var(--arrivee-scene) * 0.09);
  --arrivee-trait: calc(var(--arrivee-cercle) * 0.09);
  --arrivee-taille-entrer: min(var(--taille-m), var(--arrivee-cercle) * 0.2);
  --arrivee-point: calc(var(--arrivee-cercle) * var(--part-point));
  --arrivee-halo: calc(var(--arrivee-point) * var(--part-halo));
  --arrivee-point-place: calc(var(--place-point) * 100%);
  /* Le plan du voile : trois orbites en parts du côté de la scène, un seul aplatissement. La
     plus petite (1 × 0,36 = 0,36) est moins haute que l'anneau (0,42) : elle passe derrière lui
     en haut et devant lui en bas, comme une planète devant son soleil ; d'une orbite à l'autre,
     l'écart (0,108) passe un portrait (0,09) : aucun visage n'en touche un autre. */
  --arrivee-largeur-plan-1: 1;
  --arrivee-largeur-plan-2: 1.6;
  --arrivee-largeur-plan-3: 2.2;
  --arrivee-plan-aplati: 0.36;
  --arrivee-inclinaison: 6deg;
  --duree-arrivee-plan-1: 70s;
  --duree-arrivee-plan-2: 110s;
  --duree-arrivee-plan-3: 160s;
  --arrivee-survol-cercle: 1.04;
  --arrivee-ouverture-point: 90;
  --arrivee-montee: 0.35em;
  --arrivee-debord-decoupe: 0.2em;
  /* Sous la souris ou au focus, les rotations vont trois fois plus vite (js/arrivee.js). */
  --arrivee-elan: 3;
  --duree-arrivee: 650ms;
  --courbe-arrivee: cubic-bezier(0.7, 0, 0.84, 0);
  --duree-eclosion: 900ms;
  --courbe-eclosion: cubic-bezier(0.16, 1, 0.3, 1);
  /* Tout apparaît en même temps (25/10/2026, « il faut que tout s'affiche en même temps »). */
  --arrivee-cadence: 0ms;
  --duree-tour-anneau: 20s;
  --duree-elan: 400ms;

  /* Panneaux de l'accueil */
  /* La colonne du titre d'une section en deux colonnes (« Comment ça marche », la FAQ). */
  --largeur-duo-tete: 5fr;
  --largeur-duo-contenu: 7fr;
  --carte-bleue-padding-haut: clamp(3.25rem, 6vw, 4.75rem);

  /* Motion (DESIGN.md §8) */
  --duree-instant: 80ms;
  --duree-courte: 150ms;
  --courbe: ease-out;
  /* Le header de l'accueil qui apparaît au premier défilement, et son logo, plus grand avant. */
  --duree-entete: 450ms;
  --entete-logo-arrivee: 0.85;
  --entete-logo-decalage: calc((min(100vw, var(--largeur-entete)) - 100vw) / 2);
  --debord-decoupe-entete: -0.75rem;
  --debord-suggestions: -100vh;
  /* La capsule à deux portes de l'accueil : sa largeur, et ce que prend la moitié survolée. */
  --largeur-cta-double: 27rem;
  --cta-elan: 1.6;
  --largeur-invitation: 28rem;
  --descente-clic: 1px;
}

/* La police, self-hosted (source et licence SIL OFL dans contenu/polices, fichier écrit par
   scripts/police.py) : Bricolage Grotesque en variable, sous-ensemble latin, un seul fichier
   pour toutes les graisses. Chemin absolu : la feuille est aussi chargée par la page hors
   ligne depuis n'importe quelle URL. */
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("/fonts/bricolage-grotesque-variable.woff2") format("woff2");
  font-weight: 200 800;
  font-stretch: 75% 100%;
  font-style: normal;
  font-display: swap;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* L'attribut `hidden` pilote les états d'une application (écran affiché, bouton
   disponible…). Sans cette règle, la moindre classe qui fixe `display` l'emporte sur
   la feuille du navigateur et l'élément « caché » reste visible, voir PIEGES.md E1.
   C'est la seule justification acceptable d'un `!important` dans nos feuilles. */
[hidden] {
  display: none !important;
}

/* Le header colle en haut de la fenêtre (retouche du 23/10/2026) : une ancre s'arrête sous lui,
   pas dessous. */
html {
  background: var(--couleur-fond);
  scroll-padding-top: var(--hauteur-entete);
}

/* AUCUNE BARRE DE DÉFILEMENT VISIBLE (décision de Matthias du 24/10/2026 : « il ne faut pas
   qu'on voie la barre de défilement à droite »), ni celle de la page, ni celles des zones qui
   défilent à l'intérieur. Seule la barre disparaît : la molette, le doigt et le clavier font
   toujours défiler. */
html,
.suggestions,
.filtres,
.bande-jours,
.grille-experts {
  scrollbar-width: none;
}

html::-webkit-scrollbar,
.suggestions::-webkit-scrollbar,
.filtres::-webkit-scrollbar,
.bande-jours::-webkit-scrollbar,
.grille-experts::-webkit-scrollbar {
  display: none;
}

/* L'accueil seulement : un lien du header ou du hero fait GLISSER la page jusqu'à sa section
   (demande de Matthias du 10/10/2026). Hors de l'accueil une ancre saute, comme avant : les
   mesures de défilement des autres écrans ne changent pas. Sans mouvement réduit seulement. */
@media (prefers-reduced-motion: no-preference) {
  html:has(.hero-accueil) {
    scroll-behavior: smooth;
  }
}

/* La section visée s'arrête un peu sous le bord de la fenêtre, pas collée à lui. */
.accueil-section,
.panneau-bleu {
  scroll-margin-top: var(--espace-l);
}

/* La fenêtre entière, et le pied de page POUSSÉ EN BAS. Sans ces trois lignes, un
   écran court (le squelette de /connexion, l'état vide de /experts) laisse le pied de
   page flotter au milieu de la fenêtre avec une bande vide dessous. Aucun effet sur les
   pages longues, où `min-height` laisse le contenu grandir. C'est aussi ce qui donne
   toute la fenêtre à `main.hero` des pages d'état, qui n'ont que lui.
   `overflow-x: hidden` vient de la maquette : rien ne doit élargir la page, et les décors
   plus larges que la fenêtre sont de toute façon rognés par leur propre conteneur. */
body {
  margin: 0;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font-family: var(--police);
  font-size: var(--taille-base);
  font-weight: var(--graisse-normale);
  line-height: var(--interligne-texte);
  color: var(--couleur-texte);
  background: var(--couleur-fond);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ⚠️ `width: 100%` N'EST PAS DÉCORATIF : `.colonne` et `.page` posent
   `margin-inline: auto` sur ce `main` (la colonne centrée, DESIGN.md §6), et dans
   un conteneur flex une marge automatique sur l'axe transversal ANNULE l'étirement.
   Sans cette ligne, le `main` se réduit à la largeur de son plus large enfant
   et toute la colonne se recroqueville au milieu de l'écran. */
main {
  flex: 1;
  width: 100%;
}

/* L'ÉCHELLE DE DESIGN.md §3, ET PAS CELLE DU NAVIGATEUR : h2 à 24 px, h3 à 20 px, tous
   en 600. Le h1 prend `--taille-xxl` sur la classe de sa colonne (`.colonne`, `.page`),
   le hero ayant la sienne. L'interlettrage suit la taille : chaque niveau a le sien. */
h1, h2, h3 {
  font-weight: var(--graisse-titre);
  line-height: var(--interligne-titre);
  letter-spacing: var(--interlettrage-titre-h2);
  text-wrap: balance;
}

h2 {
  font-size: var(--taille-xl);
}

h3 {
  font-size: var(--taille-l);
  letter-spacing: var(--interlettrage-titre-h3);
  line-height: var(--interligne-titre-h3);
}

p {
  max-width: var(--largeur-texte);
}

/* Un lien nu prend la couleur de son texte, et passe au bleu au survol (DESIGN.md §8).
   ⚠️ `:where()` RAMÈNE CE SURVOL À LA SPÉCIFICITÉ D'UN ÉLÉMENT. Écrit `a:hover`, il
   battait la couleur de toute classe posée sur un lien : un bouton bleu survolé passait
   en texte bleu sur fond bleu, le bouton noir du header en bleu sur noir (1,96:1,
   interdit par DESIGN.md §4), et la pilule courante d'une rangée de filtres perdait son
   texte blanc. Ainsi, toute classe qui fixe sa couleur la garde au survol, et celles
   qui veulent le bleu l'écrivent elles-mêmes. */
a {
  color: inherit;
}

/* ⚠️ TOUT SURVOL DE LA FEUILLE VIT DANS UN `@media (hover: hover)` (01/11/2026), à sa place dans
   la cascade : sur un écran tactile, le navigateur garde `:hover` sur ce qu'on vient de
   toucher, et une question de la FAQ restait soulignée, un bouton discret épaissi, jusqu'au
   toucher suivant. Un survol écrit avec un focus (`:is(:hover, :focus-visible)`) se sépare en
   deux règles : le focus reste dehors, il vaut au clavier sur tous les écrans.
   LE SURVOL D'UN TEXTE QUI SE COMMANDE SE DIT PAR SON SOULIGNEMENT : depuis que le bleu est
   presque l'encre (1,11:1), la couleur seule ne se voit plus. Un lien nu, souligné par le
   navigateur, épaissit et décolle son trait ; une entrée du volet, le nom d'une ligne
   d'annuaire, une question de la FAQ, le résumé d'un dépliant le prennent. Le lien nu garde
   la spécificité d'un élément (`a:where(:hover)`) : une classe qui retire son soulignement à
   un lien en capsule l'emporte encore au survol. */
@media (hover: hover) {
  a:where(:hover),
  .nav-lien:not([aria-current="page"]):hover,
  .carte-lien:hover,
  .question summary:hover .question-texte,
  .depliant summary:hover {
    color: var(--couleur-accent);
    text-decoration-line: underline;
    text-decoration-thickness: var(--epaisseur-marqueur);
    text-underline-offset: var(--decalage-focus);
  }
}

/* Trois graisses seulement (DESIGN.md §3) : le gras du navigateur vaut 700, celui de
   Cercles 600. */
strong {
  font-weight: var(--graisse-titre);
}

/* Une seule famille, jusque dans ce que le navigateur dessine lui-même : un bouton, une
   case, une liste ou une jauge ont leur propre police par défaut, et aucun style calculé
   ne doit en porter une autre que celle de `--police` (DESIGN.md §9). */
button,
input,
select,
textarea,
progress {
  font-family: inherit;
}

img {
  max-width: 100%;
  height: auto;
}

::selection {
  background: var(--couleur-accent);
  color: var(--couleur-accent-contraste);
}

/* ---------- Focus : deux expressions (DESIGN.md §4 et §7) ----------
   Ce qui se commande porte l'anneau, noir sur un fond clair, blanc sur un fond sombre ; ce
   dans quoi on tape n'en porte aucun, il se double d'un second trait (plus bas). Les cases et
   boutons radio restent des commandes, le `<select>` aussi : on ne tape pas dans une
   liste, on l'ouvre. */
:focus-visible {
  outline: var(--epaisseur-focus) solid var(--couleur-encre);
  outline-offset: var(--decalage-focus);
}

input:not([type="checkbox"]):not([type="radio"]):focus-visible,
textarea:focus-visible {
  outline: none;
}

/* ⚠️ LE FOCUS D'UN CHAMP SE DIT PAR UNE FORME, JAMAIS PAR UNE TEINTE (01/11/2026) : sa bordure
   qui passait au bleu ne se voyait plus depuis que le bleu est presque l'encre (1,11:1 entre
   repos et focus). Le champ se double d'un second trait de la couleur principale, détaché de
   sa bordure par un liseré du fond : une bande qui était du fond prend la couleur principale.
   Deux traits fins séparés ne se confondent pas avec le trait plein de 3 px d'un champ en faute,
   qui le garde sous le second trait : c'est quand le focus y saute que l'écran dit pourquoi. */
input.champ:focus-visible,
textarea.champ:focus-visible {
  box-shadow:
    0 0 0 var(--decalage-focus) var(--couleur-fond),
    0 0 0 calc(var(--decalage-focus) + var(--epaisseur-focus)) var(--couleur-accent);
}

/* Sur un fond sombre, l'anneau d'encre ne se voit pas : la case d'une pilule cochée, sur le noir
   de l'inversion (1:1, mesuré au run 27 sur `/expert`), et le pied de page, sur la couleur
   principale (1,1:1). La carte « Rejoignez le cercle », claire depuis Orbite, garde l'encre. */
.choix:has(:checked) :focus-visible,
.site-footer :focus-visible {
  outline-color: var(--couleur-fond);
}

/* ---------- Boutons : les capsules plates au trait d'encre (DESIGN.md §5 et §7) ----------
   Une classe de base, la capsule blanche, et ses variantes : `.bouton-principal` et
   `.bouton-secondaire` (la couleur principale ; le secondaire redevient la capsule blanche dans
   le hero), `.bouton-danger` (la capsule noire, une seule par écran ; c'est aussi « Se connecter »
   dans le panneau du header), `.bouton-discret` (un mot souligné). Le trait d'encre de toutes les
   capsules (`--trait-capsule`) est un `box-shadow` : il n'y a AUCUNE bordure, ni reflet, ni
   ombre portée, et rien ne décale un voisin. 52 px de haut, texte de 18 px (« augmente la
   taille des boutons », Matthias, 23/10/2026).
   ⚠️ TOUTE RÈGLE QUI PEINT UN BOUTON VIT DANS CE BLOC, avant `.bouton:disabled` : à
   spécificité égale c'est l'ordre qui tranche, et le désactivé doit gagner. */

/* Ce que toute capsule cliquable partage : un bouton, et dans le header le burger. */
.bouton,
.nav-toggle {
  display: inline-flex;
  align-items: center;
  border: 0;
  border-radius: var(--rayon-pilule);
  font: inherit;
  font-size: var(--taille-bouton);
  font-weight: var(--graisse-titre);
  cursor: pointer;
}

.bouton {
  justify-content: center;
  gap: var(--espace-s);
  min-height: var(--hauteur-bouton);
  min-width: var(--hauteur-bouton);
  padding: 0 var(--reserve-bouton);
  line-height: 1;
  text-decoration: none;
  color: var(--couleur-encre);
  background: var(--couleur-fond);
  box-shadow: var(--trait-capsule);
}

.bouton:active {
  transform: translateY(var(--descente-clic));
}

/* ⚠️ LE SECONDAIRE EST DE LA COULEUR PRINCIPALE LUI AUSSI depuis le 11/10/2026 (demande de
   Matthias : les pages faisaient trop noir, « mettez les boutons en bleu comme celui de
   l'accueil »). Il reste une classe à part : la capsule blanche lui revient là où il fait la
   paire avec un bouton de la couleur principale (les deux boutons du hero). Ce qui distingue
   l'action principale d'un écran n'est donc plus la couleur, c'est sa place et son libellé. */
.bouton-principal {
  color: var(--bouton-principal-texte);
  background: var(--bouton-principal-fond);
  box-shadow: var(--bouton-principal-trait);
}

.bouton-secondaire {
  color: var(--bouton-secondaire-texte);
  background: var(--bouton-secondaire-fond);
  box-shadow: var(--bouton-secondaire-trait);
}

/* Le danger est une capsule noire : sa gravité vient du noir, la seule masse sombre d'un écran
   de travail. « Se connecter », dans le panneau du header, est la même capsule ; ils ne se
   croisent sur aucun écran. */
.bouton-danger {
  color: var(--couleur-fond);
  background: var(--couleur-encre);
  box-shadow: none;
}

/* Le bouton de la carte bleue (« Rejoindre le cercle ») : blanc plein, sans trait. */
.panneau-bleu .bouton-principal {
  color: var(--panneau-fond);
  background: var(--panneau-texte);
  box-shadow: none;
}

/* Le survol (DESIGN.md §8) : la capsule de la couleur principale s'éclaircit. La capsule noire, la blanche
   (le secondaire) et celle de Google prennent le contour des capsules (plus bas, juste avant
   `.bouton:disabled`) : un noir éclairci de 6 %, un blanc passé au clair (1,10:1) ou un texte
   qui passait à la couleur principale ne se voyaient pas (01/11/2026). */
@media (hover: hover) {
  .bouton-principal:hover {
    background: var(--bouton-principal-survol);
    transform: translateY(var(--bouton-montee));
  }
}

/* Un mot souligné, pas une capsule : annuler, revenir, voir. Il perd le fond, le contour et
   la réserve horizontale, et GARDE la hauteur d'un bouton : c'est sa cible tactile, et
   c'est elle qui tient la hauteur des lignes où il est seul (« Retirer »). */
.bouton-discret {
  min-width: 0;
  padding: 0;
  background: transparent;
  box-shadow: none;
  color: var(--couleur-encre);
  font-weight: var(--graisse-moyenne);
  text-decoration: underline;
  text-decoration-thickness: var(--epaisseur-marqueur);
  text-underline-offset: var(--decalage-focus);
}

/* Le bouton discret est déjà souligné : au survol, son trait double d'épaisseur. LA FORME SEULE
   (relecture du run B1, 02/11/2026) : le mot reste à l'encre, l'état ne se dit jamais par une
   teinte (DESIGN.md §4). */
@media (hover: hover) {
  .bouton-discret:hover {
    text-decoration-thickness: calc(var(--epaisseur-marqueur) * 2);
  }
}

/* LE MÊME BOUTON ROND, PARTOUT : celui qui ferme une barre de recherche (l'annuaire, le
   header), et sur l'accueil le combiné sous un portrait et l'horloge de la capsule
   « prochain rendez-vous ». Un bouton dont le contenu est un pictogramme perd la réserve
   horizontale de `.bouton` et devient carré, donc rond une fois le rayon de capsule
   appliqué. Deux tailles, une règle chacune. */
.recherche-bouton {
  width: var(--hauteur-bouton);
  height: var(--hauteur-bouton);
  padding: 0;
}

.bouton-decrocher,
.prochain-bouton {
  flex: none;
  width: var(--taille-bouton-rond);
  height: var(--taille-bouton-rond);
  min-height: 0;
  padding: 0;
}

/* Le bouton rond noir de la capsule « prochain rendez-vous », son horloge en blanc. */
.prochain-bouton {
  color: var(--couleur-texte-sur-sombre);
  background: var(--couleur-encre);
  box-shadow: var(--trait-capsule);
}

/* Un compte était connecté à la dernière visite (js/amorce-compte.js) : « Se connecter » et
   « Devenir expert » gardent leur place sans se montrer, le temps que « qui suis-je »
   réponde. Sans quoi un compte connecté les voyait passer à chaque page. Le burger, lui,
   est le même connecté ou non : la photo vit dans le volet (29/10/2026). */
[data-compte="connu"] #lien-connexion,
[data-compte="connu"] .nav-devenir-expert {
  visibility: hidden;
}

/* LE SURVOL D'UNE CAPSULE QUI SE COMMANDE : SON TRAIT S'ÉPAISSIT À 3 PX, OU APPARAÎT
   (01/11/2026). Le contour passait de l'encre au bleu, qui en est presque la couleur
   (1,11:1) : il double désormais. La pilule EN BOUTON et EN LIEN, jamais la case qui se coche
   ni la pilule choisie, qui reste inversée (voir le marqueur) ; le segment d'une capsule
   segmentée et le bouton rond qui ferme la carte d'un expert des orbites, qui n'ont pas de
   trait au repos, le prennent, comme la capsule blanche de Google ; le bouton secondaire,
   capsule blanche au trait d'encre, l'épaissit (son fond passé au clair ne se voyait pas).
   Sur une capsule noire (le bouton danger, le bouton rond du prochain rendez-vous), le trait
   est blanc et le texte, déjà blanc, le reste : un trait de la couleur principale ne s'y
   verrait pas.
   ⚠️ ÉCRITE AVANT `.bouton:disabled`, à sa spécificité pour les boutons (0,2,0 ; le `:where()`
   du danger n'y ajoute rien) : un bouton désactivé qu'on survole reste désactivé. Le danger
   choisi, « Se connecter » sur `/connexion`, ne réagit pas au survol, comme tout élément
   choisi (le marqueur, en fin de feuille). */
.bouton-danger,
.prochain-bouton {
  --couleur-survol: var(--couleur-texte-sur-sombre);
}

@media (hover: hover) {
  button.choix:not([aria-current="true"]):hover,
  .filtre:not([aria-current="page"]):hover,
  .segment:not([aria-pressed="true"]):hover,
  .orbite-carte-fermer:hover,
  .bouton-secondaire:hover,
  .bouton-google:hover,
  .bouton-danger:where(:not([aria-current="page"])):hover,
  .prochain-bouton:hover {
    color: var(--couleur-survol);
    box-shadow: inset 0 0 0 var(--epaisseur-trait-survol) var(--couleur-survol);
  }
}

/* ⚠️ UNE SEULE RÈGLE `:disabled`, POUR TOUTES LES VARIANTES, ET ELLE EST LA DERNIÈRE
   RÈGLE DE BOUTONS DE LA FEUILLE (corrections de review du run 92) : à spécificité
   égale (0,2,0) avec chaque `:hover` de variante, c'est l'ORDRE qui tranche, et rien ne
   doit plus se peindre après elle.
   Désactivé se dit par des POINTILLÉS, jamais par une opacité (DESIGN.md §4) : un bouton
   à 55 % est un bouton gris. Fond blanc, texte noir en 400, contour pointillé, et plus
   aucun contour plein. Le pointillé est un `outline` rentré dans la boîte, pas une bordure :
   un bouton n'en a aucune, et lui en donner une l'élargirait de 3 px à chaque fois qu'il
   s'allume ou s'éteint (« Ajouter » d'une exception, « Supprimer définitivement »).
   Un LIEN-bouton désactivé (`aria-disabled`, sans adresse) se dessine de même : le
   « Réserver » de la fiche de démonstration. */
.bouton:disabled,
.bouton[aria-disabled="true"] {
  background: var(--couleur-fond);
  color: var(--couleur-encre);
  font-weight: var(--graisse-normale);
  box-shadow: none;
  outline: var(--epaisseur-contour) dashed var(--couleur-encre);
  outline-offset: calc(var(--epaisseur-contour) * -1);
  cursor: not-allowed;
  transform: none;
}

/* ---------- Marqueur « vous êtes ici » ----------
   ⚠️ IL N'EST PAS ICI, IL EST À LA TOUTE FIN DE LA FEUILLE, alors que c'est ici qu'on
   viendrait spontanément l'écrire (PIEGES.md E27). Voir la dernière section. */

/* ---------- La marque : le logo et « Cercles » (DESIGN.md §7) ---------- */
.marque {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-s);
  font-size: var(--taille-marque-texte);
  font-weight: var(--graisse-titre);
  letter-spacing: var(--interlettrage-marque);
  line-height: 1;
  color: inherit;
  text-decoration: none;
}

/* LE GLYPHE DE LA MARQUE (24/10/2026, à la place de logo.svg dans les headers et les pieds, pour
   prendre la couleur principale) : un anneau au trait de l'encre, le point de
   l'ornement posé sur son bord haut droit, cerclé d'un halo du fond qui le porte
   (`--halo-glyphe`, posé par la barre du header). Le favicon et les icônes PWA le dessinent
   de la même couleur (scripts/marque.py, depuis le figeage du 02/11/2026). */
.marque-glyphe {
  position: relative;
  flex: none;
  width: var(--taille-marque);
  height: var(--taille-marque);
  border: var(--epaisseur-glyphe) solid var(--couleur-encre);
  border-radius: 50%;
}

.marque-glyphe::after {
  content: "";
  position: absolute;
  right: var(--debord-point-glyphe);
  top: var(--debord-point-glyphe);
  width: var(--taille-point-glyphe);
  height: var(--taille-point-glyphe);
  border-radius: 50%;
  background: var(--couleur-ornement);
  box-shadow: 0 0 0 var(--halo-point-glyphe) var(--halo-glyphe, var(--couleur-fond));
}

/* ---------- Header / navigation (DESIGN.md §6) ----------
   TROIS ÉLÉMENTS, À TOUTES LES LARGEURS (retours d'Abel du 18/10/2026) : la marque à gauche, la
   bulle « Trouver mon expert » au centre, le burger à droite. Tout le reste vit dans le panneau
   du burger, un volet posé sous la barre. Collé en haut de la fenêtre au défilement.
   La barre se règle par ses jetons `--entete-*` ; sa bande de verre blanc (la translucide,
   `--verre-entete`) est dans le bloc d'Orbite, en fin de feuille.
   ⚠️ `.nav` EST AU-DESSUS DE CE QUI LA SUIT (`position` et `z-index`) : le volet, qui en
   descend, se peindrait sinon sous la carte de réservation collée au défilement ou sous la
   barre fixée du mobile, venues plus tard dans la page. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 3;
  padding: var(--entete-marge);
  padding-bottom: calc(var(--entete-marge) + var(--entete-trait));
  background: var(--couleur-fond);
  color: var(--couleur-texte);
}

/* La bulle est VRAIMENT centrée : deux colonnes égales de part et d'autre, chacune au moins
   aussi large que le burger. L'ordre du DOM reste marque, recherche, burger, panneau : la
   règle qui replie le panneau dès le premier rendu demande le burger juste avant lui. */
.nav {
  --halo-glyphe: var(--couleur-fond);
  position: relative;
  display: grid;
  grid-template-columns: minmax(var(--hauteur-bulle-entete), 1fr) auto minmax(var(--hauteur-bulle-entete), 1fr);
  grid-template-areas: "marque recherche burger";
  align-items: center;
  gap: var(--espace-s);
  height: var(--entete-hauteur);
  max-width: var(--entete-largeur);
  margin-inline: auto;
  padding-inline: var(--entete-reserve);
  border-radius: var(--entete-rayon);
  font-weight: var(--graisse-moyenne);
}

.nav-logo {
  grid-area: marque;
  justify-self: start;
  min-height: var(--hauteur-bulle-entete);
  border-radius: var(--rayon-pilule);
}

/* LA RECHERCHE DU HEADER, TOUJOURS OUVERTE ET BLANCHE (appel d'Abel du 25/10/2026 : la bulle
   pleine de la couleur principale prenait trop de place ; « partons sur ça, en blanc ») : une
   capsule du fond au trait de l'encre, le champ, puis la loupe dans un rond de la couleur
   principale. Elle envoie à `/experts?q=…`, que l'annuaire sait déjà lire ; un envoi vide ouvre
   l'annuaire entier (js/app.js). Le focus se dit sur la capsule entière, pas sur le champ. */
.nav-recherche {
  grid-area: recherche;
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  width: var(--largeur-recherche-nav);
  min-height: var(--hauteur-bulle-entete);
  padding-inline: var(--reserve-bulle) var(--espace-xs);
  border-radius: var(--rayon-pilule);
  background: var(--couleur-fond);
  box-shadow: var(--trait-capsule);
}

.nav-recherche:focus-within {
  outline: var(--epaisseur-focus) solid var(--couleur-encre);
  outline-offset: var(--decalage-focus);
}

.nav-recherche-champ {
  flex: 1;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--taille-s);
  font-weight: var(--graisse-moyenne);
  color: var(--couleur-encre);
  text-overflow: ellipsis;
  appearance: none;
}

/* ⚠️ SUR TÉLÉPHONE, PAS MOINS DE 16 PX DANS UN CHAMP : en dessous, Safari sur iPhone zoome la
   page entière dès qu'on touche la recherche (01/11/2026). Sur un écran étroit, l'indication
   finit par des points de suspension plutôt que coupée net. */
@media (max-width: 48rem) {
  .nav-recherche-champ {
    font-size: var(--taille-base);
  }
}

.nav-recherche-champ::placeholder {
  color: var(--couleur-encre);
  opacity: 1;
}

/* La croix d'effacement du navigateur, bleue, hors de la palette : le champ se vide au clavier. */
.nav-recherche-champ::-webkit-search-cancel-button {
  display: none;
}

.nav-recherche-envoyer {
  --taille-loupe: var(--taille-loupe-recherche, var(--taille-loupe-entete));
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--taille-loupe);
  height: var(--taille-loupe);
  padding: 0;
  border: 0;
  border-radius: 50%;
  color: var(--bouton-principal-texte);
  background: var(--bouton-principal-fond);
  cursor: pointer;
}

/* SA CIBLE TACTILE FAIT 44 PX (`--hauteur-lien`), quelle que soit la loupe dessinée : 36 px sur
   téléphone, 28 sous 360 px (01/11/2026). Un disque invisible centré sur elle, comme autour
   d'un portrait des orbites (`.orbite-expert::after`) ; il déborde de 8 px au plus, sur la
   réserve de la capsule et l'écart qui la sépare du burger. */
.nav-recherche-envoyer::after {
  content: "";
  position: absolute;
  inset: calc((var(--taille-loupe) - var(--hauteur-lien)) / 2);
  border-radius: 50%;
}

@media (hover: hover) {
  .nav-recherche-envoyer:hover {
    background: var(--bouton-principal-survol);
  }
}

/* Le burger : un rond au trait de l'encre (le reste de la capsule est partagé avec
   `.bouton`). Connecté, il porte la photo ou les initiales du compte (js/session.js), en 600,
   à la place des trois traits. */
.nav-toggle {
  grid-area: burger;
  justify-self: end;
  justify-content: center;
  width: var(--hauteur-bulle-entete);
  height: var(--hauteur-bulle-entete);
  padding: 0;
  color: var(--couleur-encre);
  background: var(--couleur-fond);
  box-shadow: var(--trait-capsule);
}

/* Le volet du burger : un panneau du fond, au trait de l'encre. */
.nav-menu {
  padding: var(--espace-m);
  border-radius: var(--rayon-carte);
  color: var(--couleur-texte);
  background: var(--couleur-fond);
  box-shadow: var(--trait-capsule);
}

/* LE PANNEAU : UN VOLET POSÉ SOUS LA BARRE, aligné à droite, qui ne pousse rien. Il se ferme
   à Échap, au choix d'une entrée et au clic en dehors (js/menu.js). Ses entrées sont des
   liens de texte, puis « Se connecter » ou le compte à plat. Son bord haut se pose
   `--espace-s` sous la séparation du header, qu'il ne recouvre jamais.
   Sa réserve latérale passe celle de la pilule de l'entrée courante (`--espace-m`) : la
   pilule noire s'arrête à `--espace-s` du contour au lieu de le recouvrir. */
.nav-menu {
  position: absolute;
  top: calc(100% + var(--entete-trait) + var(--espace-s));
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--espace-s);
  width: min(100%, var(--largeur-panneau-nav));
  padding-inline: calc(var(--espace-m) + var(--espace-s));
}

/* ⚠️ REPLIÉ DÈS LE PREMIER RENDU, AVANT MÊME QUE app.js N'AIT POSÉ `hidden`. Le HTML
   livre le panneau sans `hidden`, et les scripts sont en fin de page : le navigateur peut
   peindre entre la feuille et eux. Lighthouse mobile relevait alors un décalage de mise en
   page de 0,188 (PIEGES.md E57). Le burger porte `aria-expanded="false"` dans le HTML, et
   js/menu.js tient cet attribut en même temps que `hidden` : la règle dit la même chose
   que le script, une image plus tôt.
   Ce qu'elle coûte : sans JavaScript, le panneau reste replié derrière un burger inerte
   (rien de l'application ne fonctionne sans lui) ; et une page qui oublierait app.js ne se
   trahit plus par un menu déplié (PIEGES.md E40), mais par un burger qui ne répond pas. */
.nav-toggle[aria-expanded="false"] + .nav-menu {
  display: none;
}

/* « Se connecter » prend la largeur du panneau. */
.nav-menu > #lien-connexion {
  align-self: stretch;
}

/* `nowrap` : un lien de deux mots reste sur une ligne. */
.nav-lien {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  min-height: var(--hauteur-lien);
  padding: 0;
  border-radius: var(--rayon-pilule);
  font-size: var(--taille-s);
  font-weight: var(--graisse-moyenne);
  color: var(--couleur-texte);
  text-decoration: none;
}

/* L'entrée courante du volet : un point d'encre devant le mot, en gras, plus de pilule noire
   (demande de Matthias du 27/10/2026, « pourquoi il y a un gros bouton dans le menu »). Le
   point et son écart sont repris en marge : le mot reste aligné sur les autres. La règle
   commune de `aria-current` (fin de feuille) est battue ici par la spécificité. */
.nav-lien[aria-current="page"] {
  gap: var(--espace-xs);
  margin-inline-start: calc((var(--astre-petit) + var(--espace-xs)) * -1);
  background: none;
  color: var(--couleur-texte);
  font-weight: var(--graisse-titre);
}

.nav-lien[aria-current="page"]::before {
  content: "";
  flex: none;
  width: var(--astre-petit);
  height: var(--astre-petit);
  border-radius: 50%;
  background: var(--couleur-encre);
}

/* ---------- Le compte, à plat dans le panneau ----------
   Sous un filet, l'adresse du compte, ses entrées et « Se déconnecter » (js/session.js), à la
   place de « Se connecter ». Jamais l'avatar de better-auth (PIEGES.md A14).
   `display: contents` (25/10/2026) : les enfants du compte sont des entrées du volet. La
   capsule des vues vient TOUT EN HAUT du volet, puis les rubriques (« Tous les experts » et
   la FAQ y sont rangés par js/vue-compte.js), puis le bloc profil sous son filet. */
.compte {
  display: contents;
}

/* LE BLOC PROFIL (appel d'Abel du 25/10/2026, 26:00) : le portrait, puis le nom, l'adresse
   et « Mon profil ». En bas du volet, après les rubriques, sous le SEUL filet du volet
   (Matthias, 29/10/2026 : il était en tête, entre deux filets, et la photo dans le burger). */
.compte-profil {
  display: flex;
  align-items: center;
  gap: var(--espace-m);
  align-self: stretch;
  padding-top: var(--espace-m);
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

.compte-portrait {
  --taille-pastille: var(--taille-portrait-compte);
  flex: none;
}

.compte-identite {
  display: grid;
  justify-items: start;
  gap: var(--espace-xs);
  min-width: 0;
}

.compte-nom {
  margin: 0;
  font-size: var(--taille-base);
  font-weight: var(--graisse-titre);
  overflow-wrap: anywhere;
}

.compte-email {
  margin: 0;
  font-size: var(--taille-xs);
  overflow-wrap: anywhere;
}

/* LA VUE DU COMPTE (run R4, js/vue-compte.js) : les rubriques d'une vue ne se montrent que
   dans la sienne, et aucune tant que le compte n'a pas de vue. Une préférence d'affichage, qui
   n'ouvre rien : les routes refusent exactement comme avant (PIEGES.md E17). */
.compte:not([data-vue="membre"]) .compte-rubriques[data-vue="membre"],
.compte:not([data-vue="expert"]) .compte-rubriques[data-vue="expert"],
.compte:not([data-vue="administration"]) .compte-rubriques[data-vue="administration"] {
  display: none;
}

/* LES ENTRÉES D'UNE VUE, RANGÉES PAR RUBRIQUE (25/10/2026 : le volet d'un administrateur
   prenait tout l'écran du téléphone) : deux colonnes, un intitulé par rubrique (plus gros que ses entrées), des
   entrées plus petites et plus serrées (32 px de cible, 40 sur téléphone). Une rubrique
   dont aucune entrée ne se montre (« Expertise » d'un expert, qui n'a plus à le devenir)
   disparaît avec son intitulé.
   Colonnes à la largeur de leur plus long intitulé, la seconde poussée au bord droit
   (29/10/2026 : « Réservations » touchait « Découvrir » dans deux moitiés égales). Tout le
   reste de la largeur va à l'écart, jamais moins de `--espace-m` : à 360 px, un écart fixe
   plus large faisait déborder la vue Membre. */
.compte-rubriques {
  display: grid;
  grid-template-columns: repeat(2, max-content);
  justify-content: space-between;
  gap: var(--espace-m);
  align-self: stretch;
}

.compte-rubrique {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
}

.compte-rubrique:not(:has(.nav-lien:not([hidden]))) {
  display: none;
}

.compte-intitule {
  margin: 0 0 var(--espace-xs);
  font-size: var(--taille-intitule-compte);
  font-weight: var(--graisse-titre);
  line-height: var(--interligne-titre);
  color: var(--couleur-accent);
}

.compte-rubrique .nav-lien {
  min-height: var(--hauteur-lien-compte);
  font-size: var(--taille-xs);
}

/* La capsule des vues tient dans la largeur du panneau, « Administration » choisi compris :
   ses segments prennent la taille des entrées et une réserve plus courte. */
.compte-vues .segment {
  padding-inline: var(--espace-s);
  font-size: var(--taille-s);
}

/* Le compte d'un membre porte déjà « Devenir expert » : l'entrée du panneau ne se répète
   pas au-dessus. */
.nav-menu:has(.compte) .nav-devenir-expert {
  display: none;
}

/* ---------- Hero : l'accueil et les pages d'état (DESIGN.md §6) ----------
   Une composition centrée sur blanc, que les orbites portent : sans elles elle est le hero
   générique que DESIGN.md §9 interdit. `.hero-accueil` est la première section de
   l'accueil, `.hero-etat` le `main` entier de `/404`, `/acces-refuse` et `/offline`.
   `isolation` : le décor d'une page d'état passe DERRIÈRE son texte (rang négatif), et
   ce rang ne doit pas le faire passer derrière la page. */
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  text-align: center;
}

/* Même gouttière que `.site-header` : l'accroche et la capsule partagent leur colonne. */
.hero-contenu {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-l);
  max-width: var(--largeur-max);
  margin-inline: auto;
  padding: var(--hero-haut) var(--gouttiere-shell) 0;
}

.hero h1 {
  margin: 0;
  max-width: var(--largeur-titre-hero);
  font-size: var(--taille-hero);
  font-weight: var(--graisse-titre);
  line-height: var(--interligne-hero);
  letter-spacing: var(--interlettrage-serre);
}

/* Le point bleu signe la phrase du hero et le titre des trois pages d'état : c'est
   l'écho du point du logo (DESIGN.md §7, composant 2). Il ne termine JAMAIS le titre
   d'un écran de travail (décision du 18/09/2026, inchangée dans son principe) : répété
   sur chaque écran il ne signe plus rien. */
.hero-point {
  color: var(--couleur-ornement);
}

.hero p {
  margin: 0;
  max-width: var(--largeur-accroche);
  font-size: var(--taille-accroche-hero);
  line-height: var(--interligne-accroche);
}

/* L'accroche en une ligne de l'accueil n'est que pour le téléphone (bloc Mobile). */
.hero-accroche-courte {
  display: none;
}

/* LE HERO DE L'ACCUEIL : la fenêtre entière, sa composition centrée en hauteur sous le header.
   Depuis le 25/10/2026 il REMONTE DERRIÈRE LE HEADER collant (marge négative, rendue en
   réserve haute) : les orbites et leurs portraits montent jusqu'en haut de la page, et la
   bande translucide du header les laisse voir, floutées. Le décor est un conteneur sans prise
   sur la souris, sauf ses portraits devenus boutons (js/orbite-experts.js) ; la mise en page
   propre à chaque DA est dans son bloc, en fin de feuille. */
.hero-accueil {
  display: grid;
  align-content: center;
  /* ⚠️ `clip` ET NON `hidden` : un conteneur `hidden` défile encore, et le focus d'un portrait
     à demi hors de l'écran (au clic comme au Tab) décalait tout le hero de côté (PIEGES.md
     E66). Rogné sur les côtés seulement (25/10/2026) : en bas, un portrait de la grande orbite
     était tranché net ; il déborde désormais sur le haut de la section suivante. */
  overflow-x: clip;
  overflow-y: visible;
  min-height: 100svh;
  margin-top: calc(var(--hauteur-entete) * -1);
  padding-top: var(--hauteur-entete);
  padding-bottom: var(--hero-accueil-bas);
}

/* Le texte passe devant le décor, qui vient après lui dans le HTML (le premier Tab va aux
   boutons du hero) ; seuls ses enfants prennent la souris, et un portrait qui passe entre
   deux lignes reste cliquable. */
.hero-accueil .hero-contenu {
  z-index: 1;
  pointer-events: none;
}

.hero-accueil .hero-contenu > * {
  pointer-events: auto;
}

/* Le titre et l accroche au centre de l ellipse intérieure (25/10/2026, « le texte au centre de l ellipse ») : l écart entre leur centre et
   bloc de texte et celui des orbites ne dépend pas de la hauteur de la fenêtre (39 px mesurés),
   on le reprend d'un décalage fixe. Au-dessus de 48rem seulement : le téléphone a ses orbites. */
@media (min-width: 48.0625rem) {
  .hero-accueil .hero-contenu {
    translate: 0 var(--decalage-texte-hero);
  }

  /* La capsule centrée sur le trait bas de l'ellipse intérieure, « Comment ça marche » avec
     elle (demande de Matthias du 27/10/2026 ; 16 px mesurés, eux aussi fixes). Un `translate`
     et non une marge : la marge déplacerait aussi le titre, que le hero recentre. */
  .hero-accueil .hero-actions {
    translate: 0 calc(var(--remontee-cta-hero) * -1);
  }
}

.hero h1 {
  font-weight: var(--graisse-hero);
}

.decor {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.decor > * {
  display: none;
}

:root[data-da="orbite"] .decor-orbites,
:root[data-da="orbite"] .carte-orbites {
  display: block;
}

/* Les deux boutons, des boutons ordinaires, posés 136 px sous l'accroche (l'écart et le
   `gap` du hero) : c'est là que passent les orbites. */
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--espace-m);
  margin-top: var(--hero-ecart-cta);
}

/* LES DEUX PORTES EN UNE CAPSULE (appel d'Abel du 25/10/2026) : « Voir les experts » de la
   couleur principale, « Devenir expert » sur le fond, un seul trait d'encre autour. La moitié
   survolée ou qui a le focus s'élargit et pousse l'autre ; au toucher, rien ne bouge. */
.cta-double {
  position: relative;
  display: flex;
  width: min(100%, var(--largeur-cta-double));
  min-height: var(--hauteur-bouton);
  border-radius: var(--rayon-pilule);
  overflow: clip;
}

/* Le trait passe AU-DESSUS des deux moitiés : posé sur la capsule, leurs fonds le couvraient. */
.cta-double::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: var(--trait-capsule);
  pointer-events: none;
}

.cta-moitie {
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding-inline: var(--reserve-bouton);
  font-size: var(--taille-bouton);
  font-weight: var(--graisse-titre);
  white-space: nowrap;
  text-decoration: none;
  color: var(--couleur-encre);
  background: var(--couleur-fond);
}

.cta-moitie-principale {
  color: var(--bouton-principal-texte);
  background: var(--bouton-principal-fond);
}

.cta-moitie:focus-visible {
  outline-offset: calc(var(--epaisseur-focus) * -2);
  flex-grow: var(--cta-elan);
}

@media (hover: hover) {
  .cta-moitie:hover {
    flex-grow: var(--cta-elan);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .cta-moitie {
    transition: flex-grow var(--duree-entete) var(--courbe-eclosion);
  }
}

/* Les pages d'état : la fenêtre entière, le texte centré, le décor en bas à droite. */
.hero-etat {
  min-height: 100dvh;
  display: grid;
  align-content: center;
  justify-items: center;
  padding: var(--hero-haut) var(--espace-l) var(--hero-bas);
}

.hero-etat p {
  margin-top: var(--espace-m);
}

.hero-etat .bouton {
  margin-top: var(--espace-l);
}

/* ---------- Du bleu dans les pages (demande de Matthias du 11/10/2026) ----------
   Les pages intérieures faisaient « trop noir ». Leurs titres de section (un `h2` sans classe
   dans une colonne de contenu) et les liens de leurs paragraphes passent au bleu ; les
   titres d'état d'écran et les noms d'une liste gardent l'encre. Bleu sur blanc : 9,6:1. */
.page h2:not([class]),
.colonne h2:not([class]),
.page p a:not(.bouton),
.colonne p a:not(.bouton) {
  color: var(--couleur-accent);
}

/* ---------- Footer (DESIGN.md §6) : sur blanc, sans filet, sobre ----------
   Quatre colonnes depuis le 10/10/2026 (il « faisait vide ») : la marque et une phrase,
   puis trois listes de liens titrées (découvrir, votre espace, informations légales). Sur
   petit écran, la présentation prend la largeur et les listes passent à deux colonnes. */
.site-footer {
  --halo-glyphe: var(--couleur-accent);
  font-size: var(--taille-xs);
  background: var(--couleur-accent);
  color: var(--couleur-fond);
}

/* Sur le fond de la couleur principale, le point du logo en prendrait la couleur et
   disparaîtrait : il passe à la teinte claire, l'anneau au blanc. */
.site-footer .marque-glyphe {
  --couleur-ornement: var(--teinte-astre-claire);
  border-color: var(--couleur-fond);
}

.footer-contenu {
  display: grid;
  grid-template-columns:
    minmax(0, var(--colonne-pied-presentation))
    repeat(3, minmax(0, var(--colonne-pied-liens)));
  align-items: start;
  gap: var(--espace-m) var(--espace-l);
  max-width: var(--largeur-max);
  margin-inline: auto;
  padding: var(--espace-l) var(--gouttiere-pied) var(--espace-m);
}

.footer-presentation {
  display: grid;
  gap: var(--espace-m);
}

.footer-presentation p {
  margin: 0;
  max-width: var(--largeur-pied-presentation);
}

/* La marque du pied de page est celle du header, au même écart entre le logo et le mot. */
.footer-marque {
  display: flex;
  align-items: center;
  gap: var(--espace-s);
}

/* Le titre d'une liste a la hauteur d'un de ses liens : les trois colonnes commencent
   sur la même ligne que la marque. */
.footer-titre {
  display: flex;
  align-items: center;
  min-height: var(--hauteur-lien-pied);
  margin: 0;
  font-size: var(--taille-s);
  font-weight: var(--graisse-titre);
}

.footer-liens ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* « CGU » et « CGV » ne faisaient que 31 px de large : la réserve latérale porte la cible
   à 47 px, et la marge négative la reprend, pour que le texte reste aligné sur le titre
   de sa liste (run 27). */
.footer-liens a {
  display: inline-flex;
  align-items: center;
  min-height: var(--hauteur-lien-pied);
  margin-inline: calc(-1 * var(--espace-s));
  padding-inline: var(--espace-s);
  color: inherit;
  text-decoration: none;
}

@media (hover: hover) {
  .footer-liens a:hover {
    text-decoration: underline;
  }
}

/* Sur son propre rang, sous les quatre colonnes. `max-width: none` : c'est un paragraphe,
   et la largeur de lecture de la règle générale le bornerait. */
.footer-copyright {
  grid-column: 1 / -1;
  max-width: none;
  margin: 0;
  font-size: var(--taille-xs);
}

@media (max-width: 48rem) {
  .footer-contenu {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .footer-presentation {
    grid-column: 1 / -1;
  }
}

/* ---------- Colonne de contenu (DESIGN.md §6) ----------
   CENTRÉE dans la fenêtre, jamais collée à gauche : règle d'agence, un écran étroit
   posé à gauche laisse une demi-fenêtre vide sur un grand écran. C'est le bloc qui
   est centré, pas le texte, qui reste aligné à gauche. */
.colonne {
  max-width: var(--largeur-texte);
  margin-inline: auto;
  padding: var(--espace-xl) var(--gouttiere-page);
}

/* Une page de contenu ordinaire (les espaces connectés) : même gouttière que le reste,
   largeur bornée pour que les libellés restent au-dessus de leur champ. */
.page {
  max-width: var(--largeur-page);
  margin: 0 auto;
  padding: var(--espace-xl) var(--gouttiere-page) var(--espace-xxl);
}

/* Le titre d'écran, quelle que soit la colonne qui le porte : les deux largeurs de
   colonne de l'application partagent la même échelle, et l'écrire deux fois
   garantirait qu'elles divergent. Seule la marge basse diffère, la page de formulaire
   ayant besoin de plus d'air sous son titre.
   L'interligne se resserre comme sur `.hero h1` : plus un titre grandit, plus l'espace
   entre ses lignes doit se réduire pour qu'il tienne en bloc. La forme de titre du
   squelette suit le même jeton, faute de quoi l'écran sauterait au chargement. */
.colonne h1,
.page h1 {
  font-size: var(--taille-xxl);
  line-height: var(--interligne-titre-h1);
  letter-spacing: var(--interlettrage-serre);
  margin: 0 0 var(--espace-m);
}

.page h1 {
  margin-bottom: var(--espace-l);
}

.chapeau {
  font-size: var(--taille-m);
  line-height: var(--interligne-accroche);
  margin: 0 0 var(--espace-l);
}

/* ---------- Champs de formulaire (DESIGN.md §4 et §7) ----------
   Une capsule blanche à contour noir. Le champ n'a PAS d'anneau de focus : il se double
   d'un second trait (les deux règles sont plus haut, avec le focus). Une indication trop
   longue pour le champ finit par des points de suspension, jamais coupée au milieu d'une
   lettre. Un `<select>` porte la même classe et reste du côté commandé : il garde son
   anneau et sa flèche native. */
.champ-groupe {
  display: grid;
  gap: var(--espace-xs);
}

.champ-libelle {
  font-size: var(--taille-s);
  font-weight: var(--graisse-moyenne);
}

.champ {
  width: 100%;
  min-height: var(--hauteur-bouton);
  padding: 0 var(--padding-bouton);
  background: var(--couleur-fond);
  border: var(--epaisseur-contour) solid var(--couleur-encre);
  border-radius: var(--rayon-pilule);
  font: inherit;
  color: var(--couleur-texte);
  text-overflow: ellipsis;
}

/* Sans gris, l'exemple d'un champ a la couleur d'une saisie : il s'en distingue par le
   libellé, toujours au-dessus, et par le curseur. `opacity: 1` : Firefox l'éclaircit de
   lui-même, ce qui ferait un gris. */
.champ::placeholder {
  color: var(--couleur-texte);
  opacity: 1;
  font-weight: var(--graisse-normale);
}

/* La biographie. `.champ` est fait pour une ligne : hauteur fixe et réserve horizontale
   seule. Une zone de texte a besoin des deux réserves, de son interligne, du rayon d'un
   bloc (une capsule de dix rems de haut dessinerait deux demi-cercles) et du droit de
   grandir à la main, jamais en largeur. */
.champ-zone {
  min-height: var(--hauteur-zone-texte);
  padding: var(--espace-s) var(--espace-m);
  border-radius: var(--rayon-carte);
  line-height: var(--interligne-texte);
  resize: vertical;
}

.champ-court {
  width: var(--largeur-champ-court);
}

/* Un champ signalé par l'écran ou par le serveur : sa bordure passe de 1,5 à 3 px, et
   la phrase sous le bouton dit pourquoi. La forme ne porte pas l'information seule. */
.champ[aria-invalid="true"] {
  border-width: var(--epaisseur-champ-faute);
}

/* Désactivé : des pointillés, jamais un gris (DESIGN.md §4). Le navigateur grise de
   lui-même le texte d'un champ ou d'une case désactivés, et pâlit une liste : la couleur
   du texte et l'opacité sont donc reposées. */
.champ:disabled {
  border-style: dashed;
  cursor: not-allowed;
}

.champ:disabled,
.case input:disabled,
.choix-case:disabled {
  border-style: dashed;
  color: var(--couleur-texte);
  opacity: 1;
}

.formulaire,
.avis-bloc {
  display: grid;
  gap: var(--espace-m);
}

.formulaire .bouton {
  justify-self: start;
}

/* L'écran de l'expert est bien plus long que celui du membre : ses blocs
   respirent davantage, faute de quoi ses trois listes de pilules, sa biographie et
   son tarif se lisent comme une seule masse. */
.formulaire-fiche {
  gap: var(--espace-l);
}

/* Deux usages d'une même mise hors de l'écran, et ils sont exactement inverses :
   `.piege` est le champ à robots du formulaire de connexion, invisible à tous et
   hors de l'arbre d'accessibilité (hors de l'écran plutôt qu'en `display: none`,
   qu'un automate sait reconnaître ; son `aria-hidden` et son `tabindex` négatif
   font le reste) ; `.hors-ecran` porte au contraire du texte destiné aux seuls
   lecteurs d'écran, comme l'annonce d'un squelette de chargement. La géométrie
   étant la même, l'écrire deux fois en serait une vraie duplication. */
.piege,
.hors-ecran {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Personne ne le voit, mais il existe : sans cette ligne il garde la bordure grise que
   le navigateur donne à un champ nu, la seule teinte hors palette de la page. */
.piege input {
  border: 0;
}

.separateur {
  margin: var(--espace-m) 0;
  font-size: var(--taille-s);
}

.bouton-google {
  gap: var(--espace-s);
}

.case {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--espace-s);
  align-items: start;
  padding-block: var(--espace-s);
  font-size: var(--taille-s);
}

/* LA MÊME CASE, LES DEUX FOIS : celle du consentement de /connexion et celle des
   pilules `.choix` (domaines et durées de l'expert) sont le même objet, une case à
   cocher à la taille et à la teinte de l'application. Seule la boîte AUTOUR de la case
   change d'un contexte à l'autre, et elle se règle sur `.case` et sur `.choix`. */
.case input,
.choix-case {
  appearance: none;
  position: relative;
  flex: none;
  width: var(--taille-case);
  height: var(--taille-case);
  margin: 0;
  border: var(--epaisseur-contour) solid currentColor;
  border-radius: var(--rayon-case);
  background: transparent;
  color: inherit;
}

/* ⚠️ COCHÉE, LA CASE SE REMPLIT, ET LA COCHE SE DESSINE DANS LA COULEUR OPPOSÉE (demande de
   Matthias du 11/10/2026 : « la coche ne se met pas bien »). La coche fine en `currentColor`
   dans une case vide se lisait mal à 18 px, décalée vers le haut et à gauche. La case
   prend la couleur du texte, noire sur le blanc et blanche dans la pilule inversée, et la
   coche celle du fond. Elle est centrée par `inset: 0` et `margin: auto`, puis remontée
   d'un cran : un « L » tourné a son poids dans le bas. */
.case input:checked,
.choix-case:checked {
  background: currentColor;
}

.case input:checked::after,
.choix-case:checked::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 28%;
  height: 52%;
  margin: auto;
  border: solid var(--couleur-fond);
  border-width: 0 var(--epaisseur-point-cible) var(--epaisseur-point-cible) 0;
  transform: translateY(-12%) rotate(45deg);
}

.choix:has(:checked) .choix-case:checked::after {
  border-color: var(--couleur-encre);
}

/* Cochée ET désactivée (un domaine déjà certifié, /certification), la case garde la couleur de
   sa pilule inversée : la couleur du texte que lui donne la règle des cases désactivées la
   rendait noire sur noir, sans coche visible (01/11/2026). */
.choix:has(:checked) .choix-case:disabled {
  color: inherit;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-m);
  margin-top: var(--espace-l);
}

/* ⚠️ UN `.actions` DE TROIS COMMANDES NE WRAP PAS EN DEUX PUIS UNE ORPHELINE
   (corrections de review du run 92) : sur `/admin/certification`, « Certifier »,
   « Demander un complément » et « Refuser la demande » demandent plus que leur colonne
   avec leur gouttière, et la troisième passait seule sur une seconde ligne. Les
   `.actions` à un ou deux boutons (Annuler, Enregistrer…) restent en ligne : seul un
   TROISIÈME enfant fait basculer la disposition, en colonne, chaque bouton gardant sa
   largeur naturelle (`align-items: flex-start`, pas d'étirement comme `.choix-empiles`,
   qui est fait pour des pilules de même famille et non pour un bouton principal, un
   secondaire et un lien discret côte à côte). */
.actions:has(> :nth-child(3)) {
  flex-direction: column;
  align-items: flex-start;
}

/* Le dépliant « L'email n'arrive pas ? ». Il grandit sur place et pousse ce qui le
   suit : rien au-dessus de lui ne doit être centré verticalement, sinon l'ouvrir
   remonterait le résumé qu'on vient de cliquer (PIEGES.md E32). */
.depliant {
  margin-top: var(--espace-l);
  padding-top: var(--espace-m);
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
  font-size: var(--taille-s);
}

/* Le résumé qui se clique : celui du dépliant, celui d'une question de la FAQ de l'accueil
   (dont le dessin est avec l'accueil). `display: flex` lui retire le triangle du
   navigateur. */
.depliant summary,
.question summary {
  display: flex;
  align-items: center;
  min-height: var(--hauteur-lien);
  cursor: pointer;
}

.depliant summary {
  font-weight: var(--graisse-moyenne);
}

.depliant ul {
  margin: 0;
  padding-left: var(--espace-m);
}

.depliant li {
  margin-top: var(--espace-s);
}

/* Le texte d'aide sous un champ : la phrase qui dit POURQUOI, notamment pour
   l'adresse de connexion en lecture seule. Noir, plus petit, en 400 : c'est toute la
   voix secondaire de l'application (DESIGN.md §3). */
.champ-aide {
  font-size: var(--taille-s);
}

/* ⚠️ LA GOUTTIÈRE DE LIGNE EST PLUS COURTE QUE CELLE DE COLONNE, et ce n'est pas
   un détail : cette ligne se replie (les boutons sous le portrait sur petit écran, le
   badge « Expert vérifié » sous le portrait dès que les trois éléments ne tiennent
   plus). Avec une gouttière unique de `--espace-l`, ce qui passe à la ligne se retrouve
   à exactement la même distance du portrait que du bloc SUIVANT du formulaire, qui a
   la même gouttière : il n'appartient alors visuellement à rien. */
.champ-photo {
  display: flex;
  align-items: center;
  gap: var(--espace-m) var(--espace-l);
  flex-wrap: wrap;
}

/* Le bouton qui ouvre le sélecteur de fichier est un `<label>` : sans cette
   ligne il ne montrerait pas qu'il se clique. */
.champ-photo label.bouton {
  cursor: pointer;
}

/* La marge du bloc d'actions est faite pour séparer un formulaire de ses boutons.
   Dans la ligne de la photo, elle décalerait les boutons vers le bas. */
.champ-photo .actions {
  margin-top: 0;
}

/* La zone de suppression de compte. Elle est séparée du formulaire par un filet
   et non par un aplat : le danger est dans le bouton, la seule capsule noire de l'écran,
   pas dans la section. La zone « Mes données » (feature 24), posée juste avant elle,
   se sépare du formulaire de la même façon. */
.zone-donnees,
.zone-danger {
  margin-top: var(--espace-xxl);
  padding-top: var(--espace-l);
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

.zone-donnees h2,
.zone-danger h2 {
  margin-bottom: var(--espace-s);
}

/* La jauge d'un envoi (PIEGES.md E5), le temps que le fichier monte : un `<progress>`
   redessiné, contour noir en pilule, piste blanche, barre bleue, sur toute la largeur
   du bloc. */
.jauge {
  appearance: none;
  width: 100%;
  height: var(--taille-point);
  border: var(--epaisseur-contour) solid var(--couleur-encre);
  border-radius: var(--rayon-pilule);
  overflow: hidden;
  background: var(--couleur-fond);
}

.jauge::-webkit-progress-bar {
  background: var(--couleur-fond);
}

.jauge::-webkit-progress-value {
  background: var(--couleur-accent);
}

/* Deux règles : un sélecteur de moteur inconnu invalide toute la liste qui le porte. */
.jauge::-moz-progress-bar {
  background: var(--couleur-accent);
}

/* ---------- La zone de message ----------
   Elle garde sa place, VIDE COMPRISE : elle parle à presque chaque geste, et une zone
   qui apparaît et disparaît dans le flux fait sauter tout ce qui la suit (PIEGES.md
   E22). Une ligne réservée, en `em` pour suivre la taille du texte, et jamais la
   hauteur du pire message.
   Une erreur se dit en 600, précédée du point « cible » (DESIGN.md §4) : jamais de
   rouge. Un avertissement est une capsule à contour noir. Un succès est du texte. */
.message {
  min-height: calc(var(--interligne-texte) * 1em);
  margin: var(--espace-m) 0 0;
  font-size: var(--taille-s);
}

.message[data-nature="erreur"] {
  font-weight: var(--graisse-titre);
}

.message[data-nature="erreur"]::before {
  content: "";
  display: inline-block;
  vertical-align: middle;
  margin-right: var(--espace-s);
  width: var(--taille-point);
  height: var(--taille-point);
  border-radius: 50%;
  border: var(--epaisseur-point-cible) solid var(--couleur-encre);
  background: var(--couleur-encre);
  box-shadow: inset 0 0 0 var(--epaisseur-point-cible) var(--couleur-fond);
}

/* Le bandeau des pages légales est une capsule à contour, posée au-dessus d'un sommaire
   en capsules à contour : à 8 px de lui, il se lisait comme sa première entrée (balayage
   du run 27). Il reçoit l'écart de deux blocs qui ne se touchent pas (DESIGN.md §6). */
.message[data-nature="attention"] {
  display: inline-block;
  margin-bottom: var(--espace-l);
  padding: var(--espace-s) var(--espace-m);
  border-radius: var(--rayon-pilule);
  box-shadow: var(--trait-capsule);
}

.message[data-nature="attention"]:empty {
  display: block;
  margin-bottom: 0;
  padding: 0;
  box-shadow: none;
}

/* ---------- Motion : uniquement sans préférence de réduction (DESIGN.md §8) ----------
   Ce bloc tient les transitions des états : la couleur des liens ; le fond et le contour
   des pilules, des segments et des boutons (le contour de 3 px du survol compris) ; le
   signe d'une question de la FAQ. Il tient aussi l'ondulation des bulles des avis. Avec la
   préférence de réduction, rien de tout cela ne bouge. */
@media (prefers-reduced-motion: no-preference) {
  a,
  .choix,
  .segment {
    transition:
      color var(--duree-courte) var(--courbe),
      background-color var(--duree-courte) var(--courbe),
      box-shadow var(--duree-courte) var(--courbe);
  }

  .bouton {
    transition:
      background-color var(--duree-courte) var(--courbe),
      box-shadow var(--duree-courte) var(--courbe),
      transform var(--duree-instant);
  }

  /* Le bord des bulles des avis ondule comme une goutte en apesanteur : trois rythmes, trois
     décalages, pour qu'aucune ne bouge comme sa voisine. Leur dérive, elle, est tirée au
     hasard par js/avis-bulles.js. */

  .avis-bulle .photo-pastille {
    animation: goutte var(--duree-goutte) ease-in-out infinite alternate;
  }

  .avis-bulle:nth-child(3n + 2) .photo-pastille {
    animation-duration: calc(var(--duree-goutte) * 1.4);
    animation-delay: calc(var(--decalage-bulle) * 2);
  }

  .avis-bulle:nth-child(3n) .photo-pastille {
    animation-duration: calc(var(--duree-goutte) * 0.8);
    animation-delay: calc(var(--decalage-bulle) * 3);
  }

  @keyframes goutte {
    0% { border-radius: var(--goutte-a); }
    33% { border-radius: var(--goutte-b); }
    66% { border-radius: var(--goutte-c); }
    100% { border-radius: var(--goutte-a); }
  }

  /* Le « plus » d'une question devient un « moins » : sa barre verticale se couche. */
  .question-signe::after {
    transition: transform var(--duree-courte) var(--courbe);
  }

}

/* ---------- Mobile ---------- */
@media (max-width: 48rem) {
  :root {
    /* Boutons et bulles du header un peu plus petits qu'au-dessus (16 px au lieu de 18) ; la
       hauteur ne descend pas. */
    --taille-bouton: 1rem;
    --reserve-bouton: 1.125rem;
    --reserve-bulle: 0.875rem;
    /* Les boutons suivent l'accroche de près (demande de Matthias du 14/10/2026). */
    --hero-ecart-cta: var(--espace-s);
    --hero-bas: 18rem;
    --hero-accueil-bas: var(--espace-xl);
    /* Les orbites de la fiche publique : la fiche commence plus haut, le bas de la grande orbite
       ne fait que passer sous le header. */
    --fiche-orbite-bas: 5rem;
    --fiche-haut: var(--espace-xl);
    /* Les orbites de l'Orbite, à l'échelle du téléphone (Matthias, 01/11/2026 : « met pas le
       texte, laisse la place pour la galaxie, elle peut déborder sur les côtés, comme sur
       ordi ») : sous le titre, sans l'accroche, trois ellipses emboîtées centrées sur le bloc
       des boutons, plus larges que l'écran ; la capsule tient dans la plus petite, « Comment ça
       marche » aussi. `--hero-orbite-haut` laisse entre le titre et les boutons la moitié haute
       de la plus grande, `--hero-orbite-bas` sa moitié basse et ses portraits : la galaxie
       entière tient dans le premier écran. */
    --orbites-centre-y: calc(100% - var(--hero-orbite-bas) - 3.75rem);
    --hero-orbite-haut: 9rem;
    --hero-orbite-bas: 8.75rem;
    --orbite-1-largeur: 21.5rem;
    --orbite-1-aplati: 0.6;
    --orbite-1-portrait: 2.25rem;
    --orbite-2-largeur: 28.75rem;
    --orbite-2-aplati: 0.6;
    --orbite-2-portrait: 2.5rem;
    --orbite-3-largeur: 36rem;
    --orbite-3-aplati: 0.59;
    --orbite-3-portrait: 2.5rem;
    /* Les départs du téléphone (01/11/2026) : pendant les trois premières secondes, aucun portrait
       ne touche le titre, la ligne, les boutons ni un autre portrait, de 344 à 768 px (14 px du
       texte et 21 px d'un autre portrait au plus près, mesurés au rayon d'un expert réel). */
    --orbite-1-depart: -105deg;
    --orbite-2-depart: -120deg;
    --orbite-vedette: 3.25rem;
    --astre-minuscule: 0.25rem;
    --astre-petit: 0.375rem;
    --astre-moyen: 0.5625rem;
    --astre-grand: 0.875rem;
    --astre-tres-grand: 1.25rem;
    --carte-arc-rayon: 13rem;
    --carte-arc-centre-x: -4rem;
    --carte-arc-centre-y: -8rem;
    --carte-anneau-rayon: 3.25rem;
    --carte-anneau-ecart: 2.25rem;
    --carte-anneau-centre: 0.75rem;
    --carte-orbite-portrait: 1.75rem;
    /* La grande orbite de « Le cercle » : bien plus large que l'écran et moins plate, ses
       deux arcs passent au centre dans les deux respirations, au-dessus et au-dessous de la
       porte ; des portraits plus petits. */
    --gouttiere-page: 1.5rem;
    /* L'accueil, dont la gouttière vaut ici celle des autres pages (1,5rem), perd le retrait de
       ses sections en deux colonnes : tous ses titres partent du même bord. */
    --retrait-etapes: 0rem;
    --hauteur-lien-compte: 2.5rem;
    /* Les liens du pied à une hauteur de doigt (28 px au-dessus). */
    --hauteur-lien-pied: 2.5rem;
  }

  /* Le hero à la hauteur de son contenu, le titre juste sous le header (Matthias, 01/11/2026 :
     « enlève l'espace entre le header et le titre ») : les orbites se placent depuis le bas, où
     le bloc des boutons reste toujours à la même distance. */
  :root[data-da="orbite"] .hero-accueil {
    min-height: 0;
    padding-bottom: var(--hero-orbite-bas);
  }

  .hero-accueil .hero-contenu {
    padding-top: var(--espace-m);
  }

  /* Pour un visiteur, dont le header n'est encore que le logo, le titre monte sur la ligne du
     logo (Matthias, 01/11/2026). La règle suit le compte et non l'ouverture du header : le
     header ne s'ouvre qu'une fois le hero passé, et le titre ne bouge jamais sous le doigt.
     Le compte se lit à l'indice de js/amorce-compte.js, puis au compte posé dans le volet par
     js/session.js, qui retire l'indice. */
  :root:not([data-compte="connu"]):not(:has(.nav-menu .compte)) .hero-accueil .hero-contenu {
    margin-top: calc(var(--hauteur-entete) * -1);
  }

  :root[data-da="orbite"] .hero-accueil .hero-actions {
    margin-top: var(--hero-orbite-haut);
  }

  /* Une ligne au lieu de l'accroche : la place va aux orbites (Matthias, 01/11/2026). */
  .hero-accueil .hero-accroche {
    display: none;
  }

  .hero-accroche-courte {
    display: block;
  }

  /* Les deux boutons du hero l'un sous l'autre, à la largeur du plus long : agrandis, ils ne
     tenaient plus côte à côte à 375 px, et passaient à la ligne à certaines largeurs et pas
     à d'autres. Empilés partout sous 48rem, ils gardent la même hauteur, et l'ancrage des
     orbites par le bas reste juste. */
  .hero-actions {
    display: grid;
    justify-content: center;
  }

  .colonne {
    padding-block: var(--espace-l);
  }

  /* La barre laisse à la recherche la place du mot « Cercles » : le lien garde son nom
     accessible (`aria-label`). La recherche prend toute la colonne du milieu, sa loupe
     rapetisse : « Trouver mon expert » se lit entier à 375 px, même à côté de la capsule du
     compte. Le panneau prend toute la largeur de la barre. */
  .nav-logo span:not(.marque-glyphe) {
    display: none;
  }

  .nav {
    --taille-loupe-recherche: var(--taille-loupe-entete-etroite);
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: var(--espace-s);
  }

  .nav-recherche {
    width: auto;
    padding-inline-start: calc(var(--espace-m) - var(--espace-xs));
  }

  /* Le volet décollé des bords de l'écran, où ses coins arrondis butaient (01/11/2026) ; sa
     réserve intérieure resserrée rend la largeur prise : à 320 px, « Administration » tient
     dans la capsule des vues. */
  .nav-menu {
    left: var(--gouttiere-shell);
    right: var(--gouttiere-shell);
    width: auto;
    padding-inline: var(--espace-m);
  }

  /* Les entrées du compte à la taille des autres entrées du volet : à 13 px, on les lisait mal
     sur un téléphone. */
  .compte-rubrique .nav-lien {
    font-size: var(--taille-s);
  }
}

/* Sous 360 px, les boutons passent à 15 px et la recherche du header serre sa réserve ; le titre
   du hero rapetisse d'un cran : sur la ligne du logo, à 48 px, il le touchait à 320 px. Le
   header se resserre AU-DEDANS de ses gouttières de 24 px (01/11/2026) : burger et capsule à
   48 px de haut, loupe à 28, écarts de 4 px, réserve de 8 avant le champ. « Trouver mon expert »
   tient ainsi entier sur le Fold fermé, à 344 px (164 px de place pour 159 de texte), et finit
   par des points de suspension à 320. */
@media (max-width: 22.5rem) {
  :root {
    --taille-bouton: var(--taille-s);
    --reserve-bulle: var(--espace-s);
    --taille-hero: 2.625rem;
    --taille-loupe-entete-etroite: 1.75rem;
    --hauteur-bulle-entete: 3rem;
  }

  .nav {
    gap: var(--espace-xs);
  }

  .nav-recherche {
    padding-inline-start: var(--espace-s);
  }
}

/* ============================================================
   PORTRAITS (feature 6, composant signature 6 de DESIGN.md §7)
   ============================================================ */

/* La pastille de photo, et l'avatar à initiales qui la remplace tant qu'il n'y en
   a pas (EX-PROF-001). Les deux ont exactement la même boîte, sinon la mise en
   page bougerait au moment où la photo arrive.

   Un cercle blanc à initiales noires en 600, cerclé de noir : l'anneau fait le tour des
   deux boîtes en `box-shadow`, pour ne rogner ni la photo ni les initiales et ne décaler
   aucun voisin. Sa couleur est le trait de contexte (`--couleur-anneau-portrait`).

   ⚠️ LA COULEUR PAR FAMILLE DE DOMAINES DU 18/09/2026 A DISPARU avec la refonte
   (DESIGN.md §4) : il n'y a que trois couleurs, et le domaine reste écrit sous chaque
   nom. `js/portrait.js` pose toujours `data-domaine` sur la boîte du portrait ; plus
   aucune règle ne le lit. */
.photo-pastille {
  display: grid;
  place-items: center;
  width: var(--taille-pastille);
  height: var(--taille-pastille);
  border-radius: 50%;
  background: var(--couleur-fond);
  color: var(--couleur-encre);
  box-shadow: 0 0 0 var(--epaisseur-anneau-portrait) var(--couleur-anneau-portrait);
  font-size: var(--taille-l);
  font-weight: var(--graisse-titre);
  letter-spacing: var(--interlettrage-titre-h3);
}

.photo-profil {
  object-fit: cover;
}

/* ---------- LE POINT DE CERCLES SUR L'ANNEAU D'UN PORTRAIT (feature 31, run B1) ----------
   Le palier Vérifié se dit par une FORME (DESIGN.md §4 et §7, composant 11) : l'écho du point du
   logo, posé sur le bord haut droit de l'anneau, aux proportions du voile (`--place-point`,
   `--part-point`, `--part-halo`), et seulement quand la fiche a une vidéo validée
   (js/portrait.js). L'anneau, lui, ne change pas.
   ⚠️ LE HALO EST UN DISQUE À PART, SOUS LE POINT (PIEGES.md E59) : la boîte elle-même, du fond ;
   le point de la couleur principale est son pseudo-élément, par-dessus. Le point est donc
   toujours sur du blanc (17,03:1), quelle que soit la photo dessous.
   ⚠️ IL SE POSE PAR-DESSUS, SANS RIEN DÉCALER : en position absolue dans la boîte du portrait,
   calé sur la pastille par la gauche (`--taille-pastille`), jamais sur la boîte, qui est parfois
   plus large.
   Trois natures : un lien vers la fiche et sa vidéo (`/experts/<id>#video`), frère du lien de
   la carte et jamais dedans ; le bouton qui ouvre la fenêtre de la vidéo, sur la fiche ; un
   décor, là où le portrait n'était déjà qu'un décor ou qu'un bouton (les orbites, le voile). */
.portrait-point {
  --point-portrait: calc(var(--taille-pastille) * var(--part-point));
  --disque-point: calc(var(--point-portrait) * (1 + 2 * var(--part-halo)));
  position: absolute;
  top: calc(var(--haut-pastille) + var(--taille-pastille) * var(--place-point) - var(--disque-point) / 2);
  left: calc(var(--taille-pastille) * (1 - var(--place-point)) - var(--disque-point) / 2);
  z-index: 1;
  width: var(--disque-point);
  height: var(--disque-point);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--couleur-fond);
}

.portrait-point::after {
  content: "";
  position: absolute;
  inset: calc(var(--point-portrait) * var(--part-halo));
  border-radius: 50%;
  background: var(--couleur-accent);
}

/* Un point qui se commande garde une cible de 44 px (DESIGN.md §5), invisible, centrée sur lui,
   comme la loupe du header. */
a.portrait-point,
button.portrait-point {
  cursor: pointer;
}

a.portrait-point::before,
button.portrait-point::before {
  content: "";
  position: absolute;
  inset: calc(min(var(--disque-point), var(--hauteur-lien)) / 2 - var(--hauteur-lien) / 2);
  border-radius: 50%;
}

/* Le focus et le survol se disent par la FORME : le point grandit dans son halo, et ce qui était
   le blanc du halo prend la couleur principale (17,03:1, sur toute photo). Le survol n'existe
   qu'à la souris (PIEGES.md E72) ; le focus, lui, reste dehors, avec son anneau. */
.portrait-point:focus-visible::after {
  scale: var(--survol-point);
}

@media (hover: hover) {
  a.portrait-point:hover::after,
  button.portrait-point:hover::after {
    scale: var(--survol-point);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .portrait-point::after {
    transition: scale var(--duree-courte) var(--courbe);
  }
}

/* Les boîtes qui portent le point : elles en sont le repère. Une ligne de liste (`.carte`) le
   pose dans la case du portrait, où la pastille est centrée en hauteur. */
.carte:has(> .portrait-point),
.fiche-portrait,
.orbite-carte-portrait {
  position: relative;
}

/* ⚠️ `1 / 1 / 2 / 2`, LA CASE DU PORTRAIT ET ELLE SEULE (relecture du run B1) : pour un enfant en
   position absolue, une ligne de fin `auto` est le BORD de la grille (CSS Grid, § 9.1). Écrite
   `1 / 1`, la zone courait jusqu'au bas de la carte, réserve comprise, et le point tombait de 16
   à 34 px sous celui du logo, selon la hauteur de la carte. */
.carte > .portrait-point {
  --haut-pastille: calc(50% - var(--taille-pastille) / 2);
  grid-area: 1 / 1 / 2 / 2;
}

/* Le lecteur d'une vidéo de certification (feature 31, run B1) : dans la fenêtre de la fiche, sur
   `/certification` et dans la carte d'une demande. Ses coins suivent ceux des cartes ; il ne
   dépasse jamais l'écran. */
.lecteur-video {
  display: block;
  width: 100%;
  max-height: var(--hauteur-lecteur-video);
  border-radius: var(--rayon-carte);
}

/* Les questions de la vidéo, sur `/admin/reglages` : une ligne par question, son champ et ses
   trois commandes, sans puce (le rang se dit dans les noms des commandes). */
.questions-video {
  display: grid;
  gap: var(--espace-l);
  margin: 0;
  padding: 0;
  list-style: none;
}

.question-video {
  display: grid;
  gap: var(--espace-s);
}

/* Trois lignes visibles : une question de 300 caractères y tient, et dix questions ne font pas
   une page de zones de texte vides. */
.question-video .champ-zone {
  min-height: var(--hauteur-zone-question);
}

/* Les questions de la vidéo, numérotées, dans la voix des faits secondaires. */
.liste-questions {
  display: grid;
  gap: var(--espace-xs);
  margin: 0;
  padding-left: var(--espace-l);
  font-size: var(--taille-s);
}

/* L'image de partage de la fiche, sous le portrait de `/expert` (feature 25, DESIGN.md
   §6), dans son dépliant (`.depliant`, fermé par défaut depuis le 01/11/2026) : sa légende
   dans la voix des faits secondaires (`.fiche-meta`). Un cadre à contour noir, au rayon des
   cartes : c'est une carte d'aperçu, comme une conversation la montrera. */
.image-partage {
  display: grid;
  gap: var(--espace-s);
  max-width: var(--largeur-image-partage);
  margin: 0;
}

.image-partage img {
  border-radius: var(--rayon-carte);
  border: var(--epaisseur-contour) solid var(--couleur-encre);
}

/* ============================================================
   ÉTATS D'ÉCRAN (feature 7) : chargement, erreur réseau, liste vide
   Deux composants communs, posés ici pour que les features suivantes n'inventent
   pas chacune leur façon d'attendre, d'échouer et de n'avoir rien à montrer.
   ============================================================ */

/* ---------- Le squelette de chargement ----------
   Une forme par ligne du contenu qu'il remplace, dans le même ordre : titre,
   lignes de texte, libellé, champ, bouton. Chaque page pose autant de formes que
   son écran a de lignes, faute de quoi le squelette annonce une hauteur qu'il n'a
   pas et l'arrivée des données fait sauter l'écran, ce qu'il est précisément censé
   empêcher (mesures dans FEATURES.md § Feature 7).

   La géométrie tient à trois nombres : une ligne de texte fait
   `--hauteur-squelette-ligne` et la gouttière `--espace-m`, soit 28 px par ligne ; un
   libellé suivi de son champ fait 12 + 16 + 44 px, soit 72 px. AUCUN padding : le
   squelette commence là où commencera la première ligne, sinon tout l'écran se
   décale à la bascule.

   Sans gris, une forme pleine serait noire ou invisible : ce sont des formes CREUSES à
   contour pointillé noir (DESIGN.md §4), aux dimensions exactes de ce qu'elles
   remplacent, le contour étant compté dans la boîte.

   ⚠️ AUCUNE ANIMATION, ET C'EST VOULU : la liste de motion de DESIGN.md §8 est
   exhaustive, le miroitement des squelettes n'y figure pas, et une nouvelle
   animation se propose avant de s'écrire (ia_slop.md §3). */
.squelette {
  display: grid;
  /* Une colonne pleine largeur, déclarée : une colonne `auto` se dimensionnerait
     sur le contenu des formes, qui est vide, et elles disparaîtraient. */
  grid-template-columns: 100%;
  justify-items: start;
  gap: var(--espace-m);
}

.squelette-forme {
  background: transparent;
  border: var(--epaisseur-contour) dashed var(--couleur-encre);
  border-radius: var(--rayon-pilule);
}

.squelette-pastille {
  width: var(--taille-pastille);
  height: var(--taille-pastille);
  border-radius: 50%;
}

.squelette-titre {
  width: 100%;
  height: var(--hauteur-squelette-titre);
  border-radius: var(--rayon-carte);
}

.squelette-ligne {
  width: 100%;
  height: var(--hauteur-squelette-ligne);
}

/* Le libellé d'un champ, la fin d'un paragraphe : une ligne qui ne va pas au bout. */
.squelette-courte {
  width: 40%;
}

.squelette-champ {
  width: 100%;
  height: var(--hauteur-bouton);
}

/* La zone de texte d'une biographie : même boîte que `.champ-zone`, faute de quoi
   le squelette annoncerait la hauteur d'un champ d'une ligne. */
.squelette-zone {
  width: 100%;
  height: var(--hauteur-zone-texte);
  border-radius: var(--rayon-carte);
}

.squelette-bouton {
  width: var(--largeur-squelette-bouton);
  height: var(--hauteur-bouton);
}

/* Le prix d'entrée d'une ligne d'annuaire : la boîte du montant, à sa hauteur. */
.squelette-prix {
  width: var(--largeur-squelette-prix);
  height: var(--taille-l);
}

/* ---------- L'état d'écran : erreur réseau, liste vide, statut nommé ----------
   Le même bloc dans tous les cas, et TOUJOURS une action : un écran qui dit
   seulement « rien ici » est une impasse. Aligné à gauche de sa colonne, comme tout le
   reste des espaces connectés (DESIGN.md §6), jamais centré. */
.etat {
  display: grid;
  grid-template-columns: 100%;
  justify-items: start;
  gap: var(--espace-m);
  padding-block: var(--espace-xl);
}

/* Le glyphe du logo, en CSS (DESIGN.md §7, composant 1) : un anneau dans le trait de
   contexte, et le point bleu posé sur son bord haut droit, cerclé d'un halo de la
   couleur du fond. L'anneau est une bordure, le point un pseudo-élément : aucun dégradé
   ne dessine une forme dans cette feuille. Ni icône empruntée, ni emoji. */
.etat-anneau {
  position: relative;
  width: var(--taille-anneau-etat);
  height: var(--taille-anneau-etat);
  border: var(--epaisseur-logo) solid var(--couleur-anneau-portrait);
  border-radius: 50%;
}

.etat-anneau::after {
  content: "";
  position: absolute;
  right: var(--debord-point-etat);
  top: var(--debord-point-etat);
  width: var(--taille-point-etat);
  height: var(--taille-point-etat);
  border-radius: 50%;
  background: var(--couleur-ornement);
  box-shadow: 0 0 0 var(--epaisseur-logo) var(--couleur-fond);
}

/* Le titre prend l'ÉCHELLE ENTIÈRE des h2 de DESIGN.md §3 quel que soit le niveau
   de titre que son contexte impose : h1 sur l'écran hors ligne de la connexion, qui
   n'affiche que lui, h2 partout où l'état s'insère sous le titre d'une page, h3 dans le
   panneau de l'accueil. La taille ne suffit pas à la reprendre : l'interlettrage et
   l'interligne se règlent par niveau, et le même bloc n'aurait pas le même dessin d'une
   page à l'autre. Les trois valeurs du h2 sont donc reprises ici. */
.etat .etat-titre {
  margin: 0;
  font-size: var(--taille-xl);
  letter-spacing: var(--interlettrage-titre-h2);
  line-height: var(--interligne-titre);
}

/* ⚠️ ET IL NE PORTE PAS L'ANNEAU DE FOCUS, alors qu'il REÇOIT le focus.
   L'anneau appartient à ce qui se COMMANDE (DESIGN.md §7) ; un titre ne se commande
   pas, et sur une page qui est déjà un écran d'erreur, un rectangle noir autour du
   titre se lit comme le cadre d'un champ en faute. Ce n'est pas un cas réservé au
   clavier : sans interaction préalable, un `.focus()` programmatique fait matcher
   `:focus-visible`, donc TOUT le monde le voit au premier chargement manqué. On garde
   le focus, qui est ce qui fait annoncer l'état par un lecteur d'écran quand il
   remplace le squelette, et on retire l'anneau. Écrite sur la classe, la règle vaut
   d'avance pour tout état qui prendra le focus. */
.etat-titre:focus-visible,
.avis-titre:focus-visible,
.avis:focus-visible,
.reglage h2:focus-visible,
.examen-etat .chapeau:focus-visible,
.carte-zone:focus-visible,
.carte-commandes .message:focus-visible,
main h1:focus-visible {
  outline: none;
}

/* Le texte d'un état EST un chapeau : même rôle, même voix, on ne recrée pas la
   règle. Seule sa marge basse ferait double emploi avec la gouttière de la grille. */
.etat .chapeau {
  margin-bottom: 0;
}

/* ============================================================
   PROFIL ET TARIFS DE L'EXPERT (feature 8)
   Trois composants de cette section ne lui appartiennent pas en propre et sont
   écrits pour être repris tels quels : la pilule à cocher `.choix` (jours et créneaux
   de la réservation, filtres de l'annuaire), le prix `.prix` (annuaire, fiche publique,
   accueil), et le point d'état, avec ses quatre dessins.
   ============================================================ */

/* Un `<fieldset>` porte une bordure, un padding et une marge du navigateur : sans
   cette remise à zéro, chaque groupe de pilules serait encadré d'un filet que
   personne n'a demandé. Le `<legend>` reprend exactement la place d'un
   `.champ-libelle`, pour que les groupes s'alignent sur les champs ordinaires. */
fieldset.champ-groupe {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

fieldset.champ-groupe > legend {
  padding: 0;
}

/* ⚠️ DANS UN FORMULAIRE À GRANDE GOUTTIÈRE, LES MARGES PROPRES S'EFFACENT, sinon elles
   s'AJOUTENT à la gouttière. `.message` et `.actions` portent les marges d'un formulaire
   à gouttière ordinaire ; avec celle de `.formulaire-fiche`, il restait 136 px de vide
   entre la dernière pilule de durée et le bouton, assez pour qu'on croie la page finie
   avant de l'avoir vu. La gouttière suffit à les séparer. */
.formulaire-fiche .message,
.formulaire-fiche .actions,
.motif .message,
.motif .actions,
.carte-commandes .message,
.carte-zone .actions {
  margin-top: 0;
}

/* ---------- La pilule à cocher ----------
   Une case, son libellé, un contour noir. Choisie, elle s'inverse : c'est le marqueur
   « vous êtes ici » de toute l'application (DESIGN.md §4), écrit une fois plus haut. La
   case reste VISIBLE : la cacher pour faire plus net coûterait l'anneau de focus du
   clavier, réservé précisément à ce qui se commande. La case elle-même (`.choix-case`)
   est celle de `.case input`, réglée avec les champs de formulaire. */
.choix-liste {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-s);
}

.choix {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-s);
  min-height: var(--hauteur-lien);
  padding: 0 var(--espace-m);
  border: 0;
  border-radius: var(--rayon-pilule);
  box-shadow: var(--trait-capsule);
  font-size: var(--taille-s);
  font-weight: var(--graisse-moyenne);
  background: var(--couleur-fond);
  color: var(--couleur-encre);
  cursor: pointer;
}

/* LA MÊME PILULE, EN BOUTON : les jours et les créneaux de la réservation
   (feature 14). Les domaines de l'expert sont des cases, les filtres de l'annuaire
   des liens (`.filtre`), et ceux-ci des commandes, parce que choisir un jour ou
   retenir un créneau FAIT quelque chose et n'a pas d'adresse propre. Un bouton
   apporte sa police ; on la remet à celle de la pilule, et rien d'autre ne change.
   `flex: none` pour qu'elle garde sa largeur, qu'elle passe à la ligne ou qu'elle
   sorte d'un cadre défilant, comme `.filtre`. */
button.choix {
  flex: none;
  font-family: inherit;
}

/* ⚠️ LES TROIS DURÉES DE `/expert` S'EMPILENT, À TOUTES LES LARGEURS (décision de
   direction artistique du 29/09/2026, FEATURES.md § Feature 9, run 91). Chaque pilule
   porte son prix, montant ET durée (« 112,50 € · 45 min », composant signature 4) : les
   trois demandent plus que la colonne, et la troisième passait SEULE à la ligne, pilule
   orpheline sous deux autres. Une colonne, donc, à la largeur de la plus longue pour
   que les trois se lisent comme une liste et non comme trois boutons de tailles
   différentes. `fit-content(100%)` et non `max-content` : la colonne ne déborde jamais
   du formulaire, même si un montant s'allongeait. Sans prix (tarif pas encore
   enregistré), les trois tiendraient en ligne : empilées quand même, la liste ne
   change pas de forme au moment où les prix arrivent. */
.choix-empiles {
  display: grid;
  grid-template-columns: fit-content(100%);
}

/* ---------- La recherche des langues de `/expert` (js/choix-langues.js) ----------
   Les langues choisies sont des pilules-boutons qui se retirent d'un clic (leur croix est
   dessinée, deux traits tournés), puis le champ de recherche, et sous lui ses suggestions
   dans un cadre à contour et coins doux. La suggestion active s'inverse : c'est le
   marqueur « vous êtes ici » de toute l'application. */
.choix-liste:empty {
  display: none;
}

.langue-retirer {
  position: relative;
  width: var(--taille-croix);
  height: var(--taille-croix);
}

.langue-retirer::before,
.langue-retirer::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto;
  height: var(--epaisseur-contour);
  background: currentColor;
  transform: rotate(45deg);
}

.langue-retirer::after {
  transform: rotate(-45deg);
}

.langues-recherche {
  position: relative;
  max-width: var(--largeur-recherche-langue);
  margin-top: var(--espace-s);
}

/* LA LISTE DE SUGGESTIONS, sous son champ (js/suggestions.js) : les langues de `/expert`, la
   recherche du header et celle de l'annuaire. Les deux dernières naissent dans le formulaire
   de leur champ, qui devient alors le repère où elles se posent. */
:is(.nav-recherche, .recherche):has(> .suggestions) {
  position: relative;
}

.suggestions {
  position: absolute;
  inset-inline: 0;
  top: calc(100% + var(--espace-xs));
  z-index: 2;
  max-height: var(--hauteur-suggestions);
  margin: 0;
  padding: var(--espace-xs);
  overflow-y: auto;
  list-style: none;
  background: var(--couleur-fond);
  border: var(--epaisseur-contour) solid var(--couleur-encre);
  border-radius: var(--rayon-carte);
}

.suggestion {
  padding: var(--espace-s) var(--espace-m);
  border-radius: var(--rayon-pilule);
  cursor: pointer;
}

/* Le survol souligne, l'active s'inverse : deux suggestions ne paraissent jamais
   choisies ensemble. */
@media (hover: hover) {
  .suggestion:hover {
    text-decoration: underline;
  }
}

.suggestion[aria-selected="true"] {
  background: var(--couleur-encre);
  color: var(--couleur-fond);
}

/* Le délai de réservation et sa lecture en clair, sur une ligne : « 30 h, soit 1 j et
   6 h avant la date de rdv ». Sur un téléphone, la phrase passe sous le nombre. */
.champ-unite {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-s) var(--espace-m);
}

.champ-unite-texte {
  font-weight: var(--graisse-moyenne);
}

/* Le secteur libre de « Autres secteurs », sous les pilules des domaines. */
.champ-autre-secteur {
  margin-top: var(--espace-m);
}

/* Le plafond de trois domaines est atteint : les cases restantes ne se cochent
   plus. Empêcher plutôt que refuser après coup (js/expert.js). Désactivé se dit en
   pointillés et en 400, jamais par une opacité. */
.choix:has(:disabled) {
  box-shadow: none;
  outline: var(--epaisseur-contour) dashed var(--couleur-encre);
  outline-offset: calc(var(--epaisseur-contour) * -1);
  font-weight: var(--graisse-normale);
  cursor: not-allowed;
}

/* ---------- Le prix (DESIGN.md §7, composant 4) ----------
   « 97,50 € · 45 min » : le MONTANT D'ABORD, en 600 à `--taille-l` avec ses chiffres
   tabulaires, puis la durée en 400 à `--taille-s` à côté. C'est la forme exacte du
   composant signature, et elle ne change pas avec le contexte : un composant qui part
   en deux variantes finit par en avoir quatre.

   Le point médian appartient au composant, pas au contenu : porté par le montant,
   il disparaît avec lui quand le serveur n'a pas encore de prix à donner, et la
   pilule se lit alors « 30 min », sans séparateur orphelin. */
.prix {
  display: inline-flex;
  align-items: baseline;
  gap: var(--espace-xs);
  font-weight: var(--graisse-titre);
  font-variant-numeric: tabular-nums;
  font-size: var(--taille-l);
  line-height: 1;
  /* Aucun de ses morceaux ne se coupe : « 90 € » ne passe pas sur deux lignes. */
  white-space: nowrap;
}

.prix-montant::after {
  content: "·";
  margin-left: var(--espace-xs);
  font-weight: var(--graisse-normale);
}

/* ⚠️ ET IL DISPARAÎT AUSSI QUAND RIEN NE SUIT LE MONTANT. Le récapitulatif de la
   réservation (feature 14) écrit la durée sur sa propre ligne, et le montant y reste
   seul. Sans cette règle, le composant finissait par un point médian suspendu,
   « 97,50 € · », qui se lit comme une phrase coupée. Le séparateur SÉPARE : il n'existe
   que lorsqu'il y a deux choses. */
.prix-montant:last-child::after {
  content: none;
}

/* Ce qui accompagne le montant, avant ou après, est du texte courant : la durée
   qu'il achète, et, sur une carte d'annuaire, le « À partir de » qui dit que c'est
   un prix d'entrée (EX-CAT-004). Une seule règle pour les deux, sans quoi deux
   morceaux de la même ligne finiraient par ne plus avoir la même voix. */
.prix-duree,
.prix-avant {
  font-size: var(--taille-s);
  font-weight: var(--graisse-normale);
}

/* ---------- La mise en service (EX-EXP-013) ---------- */
.mise-en-service {
  margin-bottom: var(--espace-xl);
  padding-bottom: var(--espace-l);
  border-bottom: var(--epaisseur-filet) solid var(--couleur-encre);
}

.mise-en-service h2 {
  margin-bottom: var(--espace-s);
}

/* ---------- Les états d'exemple de « Mes rendez-vous » et « Mes paiements » (27/10/2026) ----------
   À part des vraies cartes, sous un filet : ce qui est fictif ne se range jamais avec le
   réel. Chaque carte porte en plus son étiquette « Exemple fictif ». */
.exemples-etats {
  display: grid;
  gap: var(--espace-s);
  margin-top: var(--espace-xl);
  padding-top: var(--espace-l);
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

.exemples-etats-titre,
.exemples-etats .fiche-meta {
  margin: 0;
}

.exemples-etats-titre {
  font-size: var(--taille-l);
  font-weight: var(--graisse-titre);
}

/* ---------- L'aperçu des emails, `/admin/emails` (27/10/2026) ----------
   Une colonne d'emails, chacun sous son nom et son objet, dans un cadre à filet noir et coins
   doux. Le cadre a la largeur d'une carte d'email (520 px et ses marges) quand la page en a. */
.apercu-emails {
  display: grid;
  gap: var(--espace-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}

.apercu-email {
  display: grid;
  gap: var(--espace-s);
}

.apercu-email-nom,
.apercu-email-objet {
  margin: 0;
}

.apercu-email-nom {
  font-size: var(--taille-l);
  font-weight: var(--graisse-titre);
}

.apercu-email-cadre {
  width: 100%;
  max-width: var(--largeur-apercu-email);
  height: var(--hauteur-apercu-email);
  border: var(--epaisseur-filet) solid var(--couleur-encre);
  border-radius: var(--rayon-carte);
  background: var(--couleur-fond);
}

/* ---------- L'avis mis en avant, choisi par l'expert (appel d'Abel du 25/10/2026) ----------
   Sous le formulaire de la fiche, séparé par un filet comme la mise en service au-dessus. Chaque
   avis porte son bouton radio dans la colonne de son auteur ; « Aucun » vient en tête. */
.avis-choix {
  display: grid;
  gap: var(--espace-m);
  margin-top: var(--espace-xl);
  padding-top: var(--espace-l);
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

.avis-choix h2,
.avis-choix .chapeau {
  margin: 0;
}

.avis-choix-option {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-s);
  padding-block: var(--espace-xs);
  font-weight: var(--graisse-titre);
  cursor: pointer;
}

.avis-choix-option input {
  width: var(--taille-case);
  height: var(--taille-case);
  margin: 0;
  accent-color: var(--couleur-accent);
}

/* Une liste de lignes de texte, sans puce : les conditions de la mise en service, et les
   reversements et virements de « Mes revenus » (feature 22). */
.conditions,
.liste-revenus {
  display: grid;
  gap: var(--espace-s);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* LA MÊME LIGNE « POINT PUIS TEXTE » : une condition de mise en service, l'état d'une
   pièce de la certification sous le nom d'un fichier (sa taille, son point, son état),
   l'état d'un champ décidé par l'administrateur, celui d'un rendez-vous. */
.condition,
.fichier-details,
.piece-etat {
  display: flex;
  align-items: baseline;
  gap: var(--espace-s);
}

/* ---------- Le point d'état, quatre dessins (DESIGN.md §4, composant 5 du §7) ----------
   Un état se dit par un MOT, toujours, et par une FORME, jamais par une teinte de plus :
   « Fait », « À faire », « Confirmé », « Annulé » sont écrits en toutes lettres à côté
   du point. Le même disque de 12 px sert aux conditions, au badge et aux états d'une
   pièce, d'une demande, d'un rendez-vous ou d'un paiement.
   Le dessin de départ est le NEUTRE : un anneau creux, pour ce qui n'attend plus rien
   (déposée, terminé, remboursé depuis). Son trait est celui du contexte. */
.condition-point,
.badge-point,
.piece-point,
.notation-point {
  flex: none;
  align-self: center;
  width: var(--taille-point);
  height: var(--taille-point);
  border: var(--epaisseur-contour) solid var(--couleur-anneau-portrait);
  border-radius: 50%;
  background: transparent;
}

/* En attente de quelqu'un : un disque noir plein. Une condition « À faire », un compte
   de reversement que l'expert ou Stripe doit encore compléter (`data-attente` sur le
   badge), une demande à examiner, des pièces à supprimer, un remboursement en cours,
   un reversement à venir (registres de l'administration, run 231). */
.condition-point,
.badge[data-attente] .badge-point,
[data-etat="envoyee"] .piece-point,
[data-etat="en_cours"] .piece-point,
[data-etat="a_purger"] .piece-point,
[data-etat="remboursement_en_cours"] .piece-point,
[data-etat="reversement_en_attente"] .piece-point {
  border-color: var(--couleur-anneau-portrait);
  background: var(--couleur-anneau-portrait);
}

/* Fait, positif : un disque bleu plein. Une condition faite, le badge « Expert
   certifié » et un compte actif, une pièce acceptée, une demande certifiée, un
   rendez-vous confirmé, un paiement reçu, un remboursement parti, et dans les registres
   de l'administration (run 231) une fiche publiée et une part reversée ; un avis publié (feature 29).
   ⚠️ CE GROUPE RESTE APRÈS LE PRÉCÉDENT : `.badge-point` y est à la spécificité de la
   règle de départ, et c'est l'ordre qui lui donne son bleu ; le badge qui attend, lui,
   gagne par sa spécificité. */
.condition[data-fait] .condition-point,
.badge-point,
[data-etat="acceptee"] .piece-point,
[data-etat="validee"] .piece-point,
[data-etat="certifiee"] .piece-point,
[data-etat="confirmee"] .piece-point,
[data-etat="paye"] .piece-point,
[data-etat="remboursement_reussi"] .piece-point,
[data-etat="publiee"] .piece-point,
[data-etat="reversee"] .piece-point,
[data-etat="reverse"] .piece-point,
[data-etat="avis_publie"] .piece-point {
  border-color: var(--couleur-accent);
  background: var(--couleur-accent);
}

/* En échec, refusé, annulé : la cible. Un contour noir, un anneau de la couleur du
   fond, un cœur noir. Les registres de l'administration (run 231) y rangent une fiche
   retirée de l'annuaire, un compte suspendu et un reversement en échec ; un avis retiré
   (feature 29). */
[data-etat="refusee"] .piece-point,
[data-etat="retiree"] .piece-point,
[data-etat="annulee"] .piece-point,
[data-etat="remboursement_echoue"] .piece-point,
[data-etat="depubliee"] .piece-point,
[data-etat="suspendu"] .piece-point,
[data-etat="reversement_echoue"] .piece-point,
[data-etat="avis_retire"] .piece-point {
  border-width: var(--epaisseur-point-cible);
  background: var(--couleur-anneau-portrait);
  box-shadow: inset 0 0 0 var(--epaisseur-point-cible) var(--couleur-fond);
}

/* ⚠️ ET LE MOT NE SE COUPE PAS : « À faire » se cassait en « À » puis « faire » sur
   deux lignes sur petit écran, sur toutes les conditions à la fois. C'est le seul
   endroit de l'écran qui dit à l'expert ce qui lui manque pour être visible, et c'est
   ce qu'il lit en premier en arrivant. */
.condition-etat {
  margin-left: auto;
  padding-left: var(--espace-m);
  font-size: var(--taille-xs);
  white-space: nowrap;
}

/* ============================================================
   DEVENIR EXPERT ET BADGE DE CERTIFICATION (feature 9)
   Le badge ne vit pas ici en propre : la carte de l'annuaire, la fiche publique, la
   réservation et le compte de reversement le reprennent tel quel.
   ============================================================ */

/* ---------- Le badge « Expert vérifié » ----------
   ⚠️ CONTOUR, POINT, TEXTE NOIR : jamais la pastille « fond pâle + texte de la même
   teinte », qui est le réflexe d'IA, et que trois couleurs interdisent de toute façon.
   Le point ne porte jamais l'information seul, « Expert vérifié » est écrit en toutes
   lettres. Son dessin est avec les points d'état, plus haut.

   Il n'a AUCUNE marge, et c'est ce qui le rend reposable ailleurs : tous ses
   emplacements sont des conteneurs à gouttière, où une marge propre s'ajouterait.

   Il est plus bas qu'un bouton, volontairement : à 2,75rem il se lirait comme un
   bouton désactivé, juste à côté du vrai bouton de la ligne du portrait. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-s);
  padding: var(--espace-s) var(--espace-m);
  border-radius: var(--rayon-pilule);
  box-shadow: var(--trait-capsule);
  font-size: var(--taille-s);
  font-weight: var(--graisse-moyenne);
  line-height: 1;
  color: inherit;
}

/* ---------- Les étapes, en liste numérotée ----------
   DESIGN.md §6 : jamais des cartes. Des cartes côte à côte donneraient des offres à
   comparer, alors que chaque étape vient APRÈS la précédente. Le numéro est un disque :
   de l'encre, et de la couleur principale pour le dernier. Les quatre étapes de
   l'accueil et les cinq du guide « Devenir expert » sont la même liste ; le filet qui
   relie les disques et le corps d'une étape sont avec « Comment ça marche », plus bas. */
.etapes {
  display: grid;
  gap: var(--espace-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}

.etape {
  display: grid;
  grid-template-columns: var(--taille-numero-etape) 1fr;
  gap: var(--espace-m);
  align-items: start;
}

.etape-numero {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--taille-numero-etape);
  height: var(--taille-numero-etape);
  border-radius: 50%;
  background: var(--couleur-encre);
  color: var(--couleur-fond);
  font-size: var(--taille-numero);
  font-weight: var(--graisse-titre);
  line-height: 1;
}

.etape:last-child .etape-numero {
  background: var(--couleur-accent);
}

/* `justify-items: start` pour que le badge garde sa largeur de pilule : dans une
   grille, un enfant s'étire par défaut, `inline-flex` compris. Même geste que
   `.etat` et `.squelette`. La certification du guide « Devenir expert » est ce bloc ;
   l'état d'une demande de certification (feature 9) aussi, en tête de `/certification`
   (le badge, puis sa phrase) comme dans la zone du badge de `/expert` (la phrase, puis
   son lien). */
.niveau-texte {
  display: grid;
  justify-items: start;
  gap: var(--espace-m);
}

/* La gouttière de la grille suffit à séparer les blocs : les marges propres d'un
   titre et d'un paragraphe s'y ajouteraient et casseraient le rythme. */
.niveau-texte h2,
.niveau-texte p,
.carte-zone p {
  margin: 0;
}

/* ============================================================
   DISPONIBILITÉS DE L'EXPERT (feature 13)
   DESIGN.md §6, espaces connectés : « colonne de contenu centrée, h1 à gauche de la
   colonne, listes en lignes à filet ». La semaine type EST une liste en lignes : sept
   jours séparés par un filet noir, le nom à gauche, les plages à droite. Aucun aplat,
   aucune carte, aucune grille de sept cases identiques.
   ⚠️ Ce que cette section ne pose PAS : la case à cocher, la pilule, le badge, le prix,
   le squelette et l'état d'écran, qui existent depuis les features 7 à 9 et servent ici
   tels quels.
   ============================================================ */

/* Un cran plus large que les écrans de formulaire (`--largeur-page`) : une ligne de jour
   porte un nom, deux heures et une commande, et dans une page de formulaire la ligne se
   replie dès le grand écran, ce qui ferait lire la semaine en escalier. La largeur de
   LECTURE suffit, la colonne ne contenant pas de liste à cinq colonnes comme l'annuaire.
   L'écran de la certification (feature 9) a la même raison : une ligne de fichier porte
   un nom, sa taille, son état et « Retirer ». Et « Mes rendez-vous » (feature 16) : une
   ligne y porte un portrait, quatre lignes de texte et un état, pas les cinq colonnes
   d'une ligne d'annuaire. « Mes paiements » (feature 19) est la même liste. */
.page-disponibilites,
.page-certification,
.page-rendez-vous,
.page-paiements,
.page-revenus,
.page-legale {
  max-width: var(--largeur-page-liste);
}

/* Un bloc de réglage : son titre, sa phrase d'aide, ses commandes. `justify-items:
   start` pour qu'un bouton ou une pilule garde sa largeur, comme `.niveau-texte` et
   `.etat` (dans une grille, un enfant s'étire par défaut). */
.reglage {
  display: grid;
  justify-items: start;
  gap: var(--espace-m);
  width: 100%;
}

/* La gouttière de la grille suffit : les marges propres du titre et du paragraphe s'y
   ajouteraient et casseraient le rythme de l'écran. */
.reglage h2,
.reglage p {
  margin: 0;
}

/* ⚠️ DEUX RÉGLAGES D'UN MÊME FORMULAIRE, ET NON DEUX SECTIONS DE PAGE : `--espace-l`
   en plus de la gouttière de `.formulaire-fiche`, à toutes les largeurs (décision 5 de
   direction artistique, 19/09/2026, FEATURES.md § Notes de cadrage, reprise par
   DESIGN.md §6). La semaine type et les exceptions portent chacune un h2, mais elles
   appartiennent à un seul formulaire, qui s'enregistre d'un coup : l'espacement de
   section les détacherait au point de les faire lire comme deux écrans. Avec la seule
   gouttière, en revanche, les deux se lisaient comme une seule liste qui continue. */
.reglage + .reglage {
  margin-top: var(--espace-l);
}

.jours {
  width: 100%;
}

/* ⚠️ LE REPLI VIENT DES LARGEURS DE LA LIGNE, PAS D'UN POINT DE RUPTURE, exactement
   comme la fiche publique (feature 11) : dès que le nom du jour et le bloc de ses plages
   ne tiennent plus côte à côte, les plages passent dessous d'elles-mêmes. Un `@media`
   aurait figé ce pli à une largeur d'écran devinée, qui deviendrait fausse le jour où le
   champ d'heure change de taille.
   Le filet SÉPARE deux jours, il ne les encadre pas : `+` le pose entre eux et nulle
   part ailleurs, donc ni au-dessus de lundi ni sous dimanche, où il ferait une boîte. */
.jour {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-s) var(--espace-m);
  padding-block: var(--espace-m);
}

.jour + .jour {
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

/* Le nom du jour est le libellé de ses champs, et il en porte donc la voix : la classe
   `.champ-libelle` est posée avec celle-ci dans le HTML, et rien n'est recopié ici. La
   largeur fixe est ce qui aligne les sept noms en colonne ; le décalage vertical rattrape
   la hauteur d'un champ, sans quoi le nom flotterait au milieu de la première plage. */
.jour-nom {
  flex: 0 0 var(--largeur-jour);
  padding-top: var(--espace-s);
}

/* Les plages s'empilent, et « Fermé » partage sa ligne avec la commande qui ouvre le
   jour : sur une semaine neuve, où les sept jours sont fermés, deux lignes par jour
   donnaient quatorze rangs pour dire sept fois la même chose. Une ligne par jour, c'est
   ce que « listes en lignes » veut dire (DESIGN.md §6).

   ⚠️ L'INTERLIGNE DE CE BLOC EST PLUS GRAND QUE CELUI DE `.intervalle`, ET C'EST LUI QUI
   GROUPE UNE PLAGE AVEC SON « RETIRER ». Sur petit écran, une plage se replie en deux
   rangs (les deux heures, puis sa commande) : avec le même `--espace-s` dedans et
   dehors, « Retirer » se trouvait à égale distance des champs qu'il détruit et de ceux
   de la plage suivante, et « Ajouter une plage » collé au dernier « Retirer ». Rien ne
   rattachait alors une commande destructrice à son objet. L'écart DEHORS vaut donc le
   double de l'écart DEDANS, et c'est la proximité qui dit l'appartenance. Invisible sur
   grand écran, où une plage tient sur un rang et n'use jamais son interligne. */
.jour-plages {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-m);
  flex: 1 1 var(--largeur-plages);
}

/* Une plage prend toute la largeur du bloc : deux plages ne se mettent jamais côte à
   côte, elles se lisent l'une sous l'autre comme les heures d'une journée. */
.jour-plages .intervalle {
  flex-basis: 100%;
}

/* UNE LIGNE QUI PORTE DEUX BORNES ET LA COMMANDE QUI VA AVEC : une plage horaire, et la
   ligne d'ajout d'une exception. Les deux sont le même objet, et deux règles jumelles
   auraient divergé au premier réglage (même geste que `.case input, .choix-case`). */
.intervalle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-s) var(--espace-m);
}

/* Le mot qui nomme une borne (« De », « à », « Du », « au »), collé à son champ : c'est
   un `<label>` qui ENVELOPPE le champ, donc il le nomme sans identifiant à fabriquer. */
.borne {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-s);
  font-size: var(--taille-s);
}

.champ-heure {
  width: var(--largeur-champ-heure);
}

.champ-date {
  width: var(--largeur-champ-date);
}

/* ⚠️ CES DEUX CHAMPS ONT LA RÉSERVE D'UNE PILULE, PAS CELLE D'UN CHAMP DE TEXTE. Leur
   largeur est comptée au plus juste, pour que deux bornes tiennent sur un rang dans la
   colonne la plus étroite : avec les 22 px de `.champ` de chaque côté, il ne restait que
   73 px au sélecteur d'heure de Chrome, qui en demande 77 (« 09:00 » et son icône). */
.champ-heure,
.champ-date {
  padding-inline: var(--espace-m);
}

/* LA LIGNE QUI DIT QU'IL N'Y A RIEN : « Fermé » pour un jour sans plage, « Aucune
   exception » pour la liste vide. Deux phrases, un seul dessin, et surtout pas le bloc
   `.etat` des features 7 et 10, qui répond quand c'est tout un ÉCRAN qui n'a rien à
   montrer (DESIGN.md §6) : ici il n'y a qu'une ligne de formulaire à renseigner. */
.rien {
  margin: 0;
  font-size: var(--taille-s);
}

/* LA LISTE EN LIGNES À FILET, LA COMMANDE À DROITE : les exceptions de
   `/disponibilites` et les fichiers déposés de `/certification` (feature 9) sont le même
   objet, une ligne de texte et le « Retirer » qui la supprime. Mêmes règles, mêmes
   mesures : la phrase cède sa place, jamais la commande. */
.liste-exceptions,
.liste-fichiers {
  display: grid;
  gap: var(--espace-s);
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* La période à gauche, la commande qui la retire à droite, et le filet entre deux
   exceptions comme entre deux jours. */
.exception,
.fichier {
  display: flex;
  align-items: center;
  gap: var(--espace-m);
  padding-block: var(--espace-s);
}

/* ⚠️ C'EST LA PÉRIODE QUI POUSSE LE BOUTON À DROITE, ET SURTOUT PAS
   `justify-content: space-between`, QUI LE DÉPLAÇAIT D'UN RANG À L'AUTRE. Sur deux
   exceptions voisines d'un petit écran, « Du 24 décembre 2026 au 26 décembre 2026 »
   remplissait sa ligne, son « Retirer » passait au rang suivant et `space-between`,
   seul sur ce rang, le calait à GAUCHE ; « Le 1er février 2027 » gardait le sien à
   DROITE. Deux emplacements pour la même commande dans la même liste : l'œil doit
   retrouver « Retirer » au même endroit d'un rang au suivant, sinon il le cherche à
   chaque ligne. La période prend donc la place libre et cède la sienne (`1 1 auto`) :
   c'est SA phrase qui passe à deux lignes, et le bouton ne bouge plus. Le rang ne peut
   alors plus se replier, et c'est pourquoi `flex-wrap` et l'interligne du `gap` partent
   avec `space-between`. */
.exception-periode,
.fichier-texte {
  flex: 1 1 auto;
}

/* ⚠️ ET LA COMMANDE NE CÈDE RIEN, ce qui ne va pas de soi : `.bouton-discret` porte
   `min-width: 0` (c'est un mot souligné, pas une capsule), si bien qu'en flex il se
   laissait comprimer avec la période, « Retirer » rogné par son propre cadre. C'est la
   période qui rend sa place, jamais le bouton. */
.exception > .bouton,
.fichier > .bouton {
  flex-shrink: 0;
}

.exception + .exception,
.fichier + .fichier {
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

/* ============================================================
   ANNUAIRE PUBLIC DES EXPERTS (feature 10)
   DESIGN.md §6 : barre de recherche en capsule fermée par un bouton rond bleu ; dix
   filtres en pilules à contour, le courant inversé en noir, qui passent à la ligne
   au-dessus de 48rem et défilent en dessous ; les experts en lignes séparées d'un filet
   noir (portrait cerclé de noir, nom en 600, domaines, badge, prix à droite), pas une
   grille de cartes. Sur mobile la ligne se replie en deux rangs.
   ============================================================ */

/* La seule colonne large de l'application, et ce n'est pas un caprice : une ligne
   d'annuaire porte un portrait, un nom, ses domaines, un badge et un prix, c'est-à-
   dire cinq choses sur une rangée. Dans la colonne de LECTURE, tout se replie et la
   liste redevient une pile de blocs. La largeur est celle du header et du footer, si
   bien que la page s'aligne sur son propre shell. Les paragraphes, eux, restent bornés
   à `--largeur-texte` par la règle générale de `p`. */
.colonne-annuaire {
  max-width: var(--largeur-max);
}

/* ---------- La barre de recherche ----------
   Le champ en capsule et le bouton rond qui la ferme : un seul objet visuel, le
   bouton d'action principal de cet écran, donc sa seule capsule bleue.
   Bornée à la largeur de lecture, comme le chapeau juste au-dessus : étirée sur toute
   la colonne, elle promet une phrase là où on tape deux mots, et elle ne s'aligne plus
   sur rien.
   La marge basse est `--espace-l` et non `--espace-m` : la barre de recherche et la
   ligne de filtres sont deux blocs qui ne se touchent pas, et DESIGN.md §6 leur
   interdit moins de 2rem. Le `padding-block` de `.filtres` juste dessous n'est pas
   de l'espacement, c'est la réserve de l'anneau de focus. */
.recherche {
  display: flex;
  gap: var(--espace-s);
  max-width: var(--largeur-texte);
  margin-bottom: var(--espace-l);
}

/* Le champ est déjà une capsule (`.champ`). Dans cette rangée il cède sa place plutôt que
   de pousser le bouton rond hors de la colonne : un champ en flex ne descend pas, sans
   cette ligne, sous la largeur que le navigateur lui prête. */
.recherche-champ {
  flex: 1 1 auto;
  min-width: 0;
}

/* ---------- Les filtres par domaine ----------
   DIX PILULES QUI PASSENT À LA LIGNE, la ligne défilante n'étant plus qu'un motif de
   petit écran (décision 4 de direction artistique du 18/09/2026, reprise par DESIGN.md
   §6). ⚠️ CE QUI A TRANCHÉ EST UNE MESURE : sur grand écran les dix filtres demandent
   plus que la colonne, donc plusieurs d'entre eux restaient HORS CADRE, et le marqueur
   « vous êtes ici » avec eux quand le filtre courant en faisait partie. Une ligne qui
   défile à la souris n'a aucune affordance sans flèches, qu'on n'invente pas pour dix
   liens. Repliées, elles tiennent sur deux rangs.
   C'est la même ligne de pilules que `.choix-liste` (feature 8) ; ce qui lui
   appartient en propre est la réserve de l'anneau de focus et le défilement mobile.
   ⚠️ LE PADDING VERTICAL N'EST PAS DE L'AIR, c'est ce qui sauve l'anneau de focus :
   l'`overflow-x: auto` du petit écran (plus bas) rogne ce qui dépasse en HAUT et en
   BAS aussi, et l'anneau est posé à 3 px de la pilule. Sans lui, le repère de qui
   navigue au clavier serait coupé en deux. La réserve LATÉRALE, elle, est écrite dans
   le bloc média : elle n'a de sens que là où le cadre défile. */
/* ⚠️ LA BANDE DES JOURS DE `/reserver` EST LE MÊME OBJET (feature 14), et c'est
   pourquoi elle partage cette règle et celle du bloc média plus bas : une ligne de
   pilules qui passe à la ligne sur grand écran et défile sur petit, avec la réserve
   d'anneau de focus sur les deux axes. Deux copies auraient divergé au premier
   réglage, et c'est justement la réserve de focus qui a coûté trois tours de review
   sur cet écran-ci. Seules leurs marges leur appartiennent en propre. */
.filtres,
.bande-jours {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-s);
  padding-block: var(--espace-s);
}

.filtres {
  margin-bottom: var(--espace-l);
}

/* La pilule à cocher de la feature 8, en lien : même boîte, même contour, même
   inversion quand elle est choisie, même survol (écrit avec la pilule). Un lien apporte
   ce qu'un bouton ne donne pas ici, une adresse qui se partage et un retour arrière qui
   fonctionne. `flex: none` : une pilule garde sa largeur, qu'elle passe à la ligne sur
   grand écran ou qu'elle sorte du cadre défilant sur petit écran, où c'est exactement
   ce qu'on attend d'elle. */
.filtre {
  flex: none;
  text-decoration: none;
}

/* ---------- La liste et ses lignes ---------- */
.liste-experts {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Trois colonnes : le portrait, l'identité, le prix. Le filet SÉPARE deux lignes,
   il ne les encadre pas : `+` le pose entre elles et nulle part ailleurs, donc ni
   au-dessus de la première ni sous la dernière, où il ferait une boîte. */
.carte {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--espace-m) var(--espace-l);
  padding-block: var(--espace-l);
}

.carte + .carte {
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

/* `justify-items: start` pour que le badge garde sa largeur de pilule : dans une
   grille, un enfant s'étire par défaut, `inline-flex` compris.
   Le bloc d'identité de la fiche publique (feature 11) est le MÊME objet, à une
   autre échelle : le nom, les domaines, le badge, empilés et alignés à gauche. Une
   seule règle pour les deux ; ce que la fiche y ajoute en propre, la largeur sous
   laquelle elle passe sous le portrait, est dans sa section. */
.carte-identite,
.fiche-identite {
  display: grid;
  justify-items: start;
  gap: var(--espace-s);
}

/* Le nom est un `h2` parce que la page est une liste de gens sous un seul titre, et
   qu'on doit pouvoir la parcourir de nom en nom au lecteur d'écran. Il prend
   l'échelle des h3 de DESIGN.md §3, qui est celle d'un titre DANS un bloc : même
   geste que `.etat-titre`, le niveau de titre que le document impose n'est pas toujours
   la taille que la composition demande. La graisse est écrite aussi : sur `/reserver`
   le nom est un paragraphe, et il doit garder le 600 d'un nom d'expert.
   Le titre de la carte de réservation (feature 11) est le même cas, et celui de chaque
   pièce de `/certification` (feature 9) : huit blocs d'un formulaire, qu'un h2 de
   section ferait lire comme huit sections de page. */
.carte-nom,
.reservation h2,
.fiche-bio-titre,
.apercu h2,
.piece h2,
.avis-zone-titre {
  margin: 0;
  font-size: var(--taille-l);
  font-weight: var(--graisse-titre);
  letter-spacing: var(--interlettrage-titre-h3);
  line-height: var(--interligne-titre-h3);
}

/* Le nom est le lien vers la fiche publique (feature 11). Il garde EXACTEMENT le
   dessin du titre, couleur comprise : ce qui dit qu'il se clique est le survol, qui
   passe au bleu (DESIGN.md §8), et l'anneau de focus au clavier. Un titre souligné
   ferait de chaque ligne de l'annuaire un lien de page d'aide.

   ⚠️ SA CIBLE FAIT 44 PX SANS QUE RIEN NE BOUGE (run 27). Un nom mesurait 26 px de haut,
   19 px dans le journal : sous le doigt, c'est la seule porte d'une ligne d'annuaire. La
   réserve l'agrandit de tous les côtés, la marge négative la reprend là où elle
   déplacerait un voisin, et l'anneau de focus est ramené d'autant : il se dessine où il
   se dessinait, à `--decalage-focus` du texte. La réserve est un nombre ENTIER de
   pixels : à 14,5 px, le texte d'une ligne sur trois se décalait d'un pixel (captures
   comparées). Elle dépasse le manque parce que le bas de la zone est repris par la
   ligne de texte qui suit le nom : c'est le haut qui fait le compte, mesuré au pointage.
   */
.carte-lien {
  margin: calc(-1 * var(--espace-m));
  padding: var(--espace-m);
  outline-offset: calc(var(--decalage-focus) - var(--espace-m));
  color: inherit;
  text-decoration: none;
}

/* La ligne de fait secondaire posée sous un nom : les domaines d'une ligne
   d'annuaire, et sur la fiche publique la phrase du badge comme les langues parlées.
   Même rôle, même voix, une seule règle : noir, plus petit, en 400. */
.carte-domaines,
.fiche-meta {
  margin: 0;
  font-size: var(--taille-s);
}

/* Le prix d'entrée, calé à droite de la ligne et sur sa ligne de base. Dans la file des
   certifications (run 92), l'état de la demande prend exactement cette place. */
.carte-prix,
.carte-etat {
  margin: 0;
  justify-self: end;
}

/* SOUS LA CARTE, ET ALIGNÉES SUR SON TEXTE (feature 17) : les commandes d'un rendez-vous
   et la zone d'annulation qu'elles déplient prennent chacune un rang entier de la grille,
   de la colonne de l'identité au bord droit. Leur boîte est réglée avec celles qu'elles
   reprennent (`.piece-commandes`, `.motif`, section des certifications).
   ⚠️ CETTE RÈGLE RESTE AVANT LE REPLI MOBILE CI-DESSOUS, qui les fait passer sous le
   portrait avec l'état : à spécificité égale, c'est l'ordre qui tranche. */
.carte-commandes,
.carte-zone {
  grid-column: 2 / -1;
}

/* ---------- La pagination ----------
   Centrée, et non étalée aux deux bords : en page 1 le bouton « Précédent »
   disparaît (il n'y a rien avant, et un bouton mort se clique quand même), et un
   `space-between` laisserait alors « Suivant » seul à droite d'un grand vide. */
.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--espace-l);
  margin-top: var(--espace-xl);
}

.pagination-position {
  margin: 0;
  font-size: var(--taille-s);
}

/* ---------- Mobile : la ligne se replie en deux rangs (DESIGN.md §6) ----------
   Le portrait et l'identité tiennent le premier rang, le prix passe dessous sur
   toute la largeur. Le garder dans une troisième colonne sur petit écran écraserait le
   nom sur trois lignes pour lui laisser sa place. */
@media (max-width: 48rem) {
  /* Et c'est ICI, et nulle part ailleurs, que les filtres redeviennent une seule
     ligne défilante (DESIGN.md §6) : dix pilules repliées dans un écran de 375 px
     prendraient quatre rangs et repousseraient le premier expert sous la ligne de
     flottaison.
     L'affordance de suite est la pilule que le bord droit COUPE, la plus simple qui
     existe : on voit qu'il y a autre chose derrière, sans flèche à inventer et sans
     fondu de bord, qui éteindrait la dernière pilule et son anneau de focus une fois
     la ligne défilée jusqu'au bout. Le filtre courant, lui, est ramené dans le cadre
     par js/experts.js, sans quoi son marqueur serait posé hors de l'écran.
     ⚠️ ET LE CADRE A LA MÊME RÉSERVE À GAUCHE ET À DROITE QU'EN HAUT ET EN BAS :
     `overflow-x: auto` rogne sur LES DEUX AXES, si bien que l'anneau de la PREMIÈRE
     pilule était coupé à plat à scrollLeft 0 et celui de la DERNIÈRE au défilement
     maximal, faute du moindre dégagement latéral pour les 5 px que l'anneau porte
     (2 px de trait à 3 px de décalage). Le `padding-inline` donne le dégagement,
     le `margin-inline` négatif le reprend sur la colonne : les pilules restent
     alignées sur le champ de recherche et sur le h1, et la pilule coupée par le bord
     droit reste coupée, donc l'affordance de suite tient.
     ⚠️ ET LE `scroll-padding-inline` FERME LE MÊME DÉFAUT À UN TROISIÈME ENDROIT, celui
     où js/cadre.js dépose le filtre courant (il lit cette réserve dans le style
     calculé) : « au plus près » colle la pilule contre le bord du cadre, si bien qu'un
     `Tab` jusqu'à elle rognait son anneau alors que Chrome ne redéfilait pas, la
     trouvant déjà visible. Le `scroll-padding-inline` fait atterrir le filtre 8 px à
     l'intérieur. Même réserve, même jeton, trois positions.
     ⚠️ ET UNE QUATRIÈME POSITION, QUE LA RÉSERVE NE POUVAIT PAS FERMER (nettoyage du
     07/10/2026, PIEGES.md E50) : la pilule que le bord COUPE et qui reçoit le focus au
     clavier. Chrome n'amène dans le cadre qu'une pilule cachée ou presque ; dès qu'une
     bonne part en est visible, il lui donne le focus SANS défiler, et son anneau reste
     rogné avec elle. Un `scroll-margin` sur la pilule n'y change RIEN : il déplace
     l'endroit où un défilement s'arrête, il n'en déclenche aucun. Ce qui en déclenche
     un, c'est l'accroche : le cadre s'accroche obligatoirement, et la SEULE cible est
     la pilule qui porte le focus clavier, que le navigateur ramène donc au centre dès
     qu'elle le reçoit (aux deux bouts, contre la réserve). Sans focus clavier il n'y a
     aucune cible, donc aucune accroche : le défilement au doigt et l'arrivée
     du filtre courant ne changent pas d'un pixel. Aucune taille n'entre ici. */
  .filtres,
  .bande-jours {
    flex-wrap: nowrap;
    overflow-x: auto;
    padding-inline: var(--espace-s);
    margin-inline: calc(var(--espace-s) * -1);
    scroll-padding-inline: var(--espace-s);
    scroll-snap-type: inline mandatory;
  }

  .filtres > :focus-visible,
  .bande-jours > :focus-visible {
    scroll-snap-align: center;
  }

  .carte {
    grid-template-columns: auto 1fr;
  }

  .carte-prix,
  .carte-etat,
  .carte-commandes,
  .carte-zone {
    grid-column: 1 / -1;
    justify-self: start;
  }
}

/* ============================================================
   FICHE EXPERT PUBLIQUE (feature 11)
   DESIGN.md §6 : deux colonnes sur grand écran, le portrait de 9rem cerclé de noir, le
   nom en h1, les domaines en pilules-liens et la biographie à gauche ; à droite, collée
   au défilement, la carte de réservation. Sur petit écran la carte passe sous la
   biographie.
   ⚠️ TOUT CE QUI S'Y VOIT EXISTE DÉJÀ AILLEURS : la pastille de portrait et son anneau
   (feature 6), la pilule `.choix` en lien (features 8 et 10), le badge (9), le prix (8),
   l'état d'écran (7). Cette section ne pose que la composition de la page et la carte.
   ============================================================ */

/* ⚠️ AUCUN POINT DE RUPTURE DE PLUS, ET CE N'EST PAS UNE ÉCONOMIE : la fiche se
   replie sur SES PROPRES LARGEURS. La colonne de gauche ne descend jamais sous la
   largeur de lecture (`--largeur-texte`) ; dès que cette largeur, la carte et leur
   gouttière ne tiennent plus côte à côte, la carte passe dessous d'elle-même. Un
   `@media` aurait figé ce pli à une taille d'écran devinée, qui deviendrait fausse le
   jour où la carte ou la colonne changent de largeur.
   `align-items: flex-start` est indispensable au `position: sticky` de la carte :
   étirée sur toute la hauteur de la ligne, elle n'aurait plus rien à parcourir et ne
   collerait jamais. */
.examen {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--espace-xl);
}

/* LA FICHE (Matthias, 29/10/2026, puis 30/10/2026) : à gauche l'en-tête, la biographie et les
   avis, à droite la carte de réservation dès le haut. Sur téléphone, une colonne. */
.fiche {
  max-width: var(--largeur-fiche);
  margin-inline: auto;
}

/* Le bandeau de la démonstration, au-dessus d'elle et sur son bord gauche : une ligne de texte
   adoucie, sans la capsule des messages d'attention (Matthias, 30/10/2026 : un cadre de plus).
   Deux classes, pour égaler `.message[data-nature="attention"]`, que l'ordre départage. */
.message.fiche-bandeau {
  display: block;
  max-width: var(--largeur-fiche);
  margin: 0 auto var(--espace-m);
  padding: 0;
  box-shadow: none;
  color: var(--couleur-texte-doux);
}

.fiche-principal {
  display: grid;
  gap: var(--espace-l);
}

/* La carte occupe la colonne de droite sur toute la hauteur de la fiche (rangées 1 à 3 :
   l'en-tête, la biographie, les avis), collée au défilement pendant leur lecture.
   `align-self: start` est indispensable au collage : étirée sur ses deux rangées, elle n'aurait
   plus rien à parcourir.
   ⚠️ PLUS HAUTE QUE LA FENÊTRE (l'avis mis en avant la fait passer 1 000 px), COLLÉE PAR LE
   HAUT, SA FIN NE SE MONTRAIT JAMAIS (Matthias, 29/10/2026 : « l'avis ne descend pas »). Son
   `top` devient alors négatif : elle défile avec la page jusqu'à montrer son bas, puis colle
   par lui. Plus courte, elle colle sous l'en-tête comme avant. Sa hauteur
   (`--hauteur-carte-reservation`) est tenue par js/fiche-expert.js. */
@media (min-width: 48.0625rem) {
  .fiche-principal {
    grid-template-columns: minmax(0, 1fr) var(--largeur-reservation);
    column-gap: var(--espace-xl);
  }

  .fiche-tete,
  .fiche-bio,
  .fiche .avis-bloc {
    grid-column: 1;
  }

  .fiche .reservation {
    grid-column: 2;
    grid-row: 1 / span 3;
    align-self: start;
    position: sticky;
    top: min(
      calc(var(--hauteur-entete) + var(--espace-l)),
      calc(100dvh - var(--hauteur-carte-reservation, 0px) - var(--espace-l))
    );
  }
}

/* Le portrait et l'identité sur une rangée, qui se replie quand le nom n'a plus la place de
   tenir à côté de la pastille. Alignée à gauche sur grand écran, centrée sur téléphone. */
.fiche-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-l);
}

/* Rien n'est redéfini du portrait : seul son jeton de taille change, et
   `.photo-pastille` suit, anneau compris. */
.fiche-portrait {
  --taille-pastille: var(--taille-pastille-fiche);
}

/* L'identité prend la place qui reste à côté du portrait, et ne passe dessous que sous sa
   largeur de base : sa ligne de faits se replie à côté de lui plutôt que de la pousser. */
.fiche-identite {
  flex: 1 1 var(--largeur-identite-fiche);
}

/* Le nom EST le titre de la page, un cran sous le h1 des pages (`.colonne h1`), et la
   marque « certifié » sur sa ligne. Il perd la marge basse de ce titre-là, que la gouttière
   de la pile remplace : les deux s'ajouteraient. */
.fiche-nom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-s) var(--espace-m);
}

.fiche-identite h1 {
  margin-bottom: 0;
  font-size: var(--taille-nom-fiche);
}

/* Le badge de la feature 9 sans sa capsule : sa pastille et ses mots, à côté du nom. */
.fiche-nom .badge {
  padding: 0;
  box-shadow: none;
}

/* LES DOMAINES EN ÉTIQUETTES (Malt) : la pilule des filtres, pleine et claire, sans contour et
   plus petite. Son survol reste celui des filtres, le contour de la couleur principale. */
.fiche-identite .choix {
  min-height: 0;
  padding: var(--espace-xs) var(--espace-s);
  background: var(--couleur-clair);
  box-shadow: none;
  font-size: var(--taille-xs);
}

/* LES FAITS EN UNE LIGNE (Malt, Intro) : petits, séparés par un point médian, sans filets ni
   grands chiffres. La note y garde le composant moyenne des avis. */
/* Le point médian est posé dans l'écart, à gauche de son fait : celui d'un fait qui ouvre une
   ligne tombe hors de la liste, et `overflow: clip` l'efface (sans en faire une zone qui défile). */
.fiche-faits {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-xs) var(--espace-m);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--taille-s);
  overflow: clip;
}

.fiche-faits li {
  position: relative;
}

.fiche-faits li + li::before {
  content: "·";
  position: absolute;
  left: calc(var(--espace-m) / -2);
  transform: translateX(-50%);
}

/* Sur grand écran, l'en-tête s'aligne à gauche de sa colonne. Sur
   téléphone l'identité passe sous le portrait centré et se centre avec lui ; les faits s'y
   empilent, un par ligne, sans point médian qui ouvrirait une ligne. */
@media (min-width: 48.0625rem) {
  .fiche-tete {
    justify-content: flex-start;
  }
}

@media (max-width: 48rem) {
  .message.fiche-bandeau,
  .fiche-identite {
    text-align: center;
  }

  .fiche-tete {
    justify-content: center;
  }

  .fiche-identite {
    justify-items: center;
  }

  .fiche-nom,
  .fiche-identite .choix-liste {
    justify-content: center;
  }

  .fiche-faits {
    flex-direction: column;
  }

  .fiche-faits li + li::before {
    content: none;
  }
}

/* LA BIOGRAPHIE, SOUS « À PROPOS » (Matthias, 30/10/2026 : elle pesait trop) : ses paragraphes,
   coupés aux lignes vides par js/fiche-expert.js, dans une colonne plus étroite. Le premier
   est une accroche en grand, les suivants passent dans l'encre adoucie, un cran plus petits.
   Une biographie d'un seul paragraphe reste à la taille du texte : tout en accroche, elle
   serait un pavé de plus. `pre-line` garde les sauts de ligne simples qu'un expert a écrits
   (`texteLong`, functions/_lib/profil.ts). */
.fiche-bio {
  display: grid;
  align-content: start;
  gap: var(--espace-m);
  max-width: var(--largeur-biographie);
}

.fiche-biographie {
  display: grid;
  gap: var(--espace-m);
}

/* L'accroche que l'expert a écrite (01/11/2026), au dessin de celle qu'on tire d'une
   biographie de plusieurs paragraphes, et jamais coupée : 140 caractères au plus. */
.fiche-accroche,
.fiche-biographie p:first-child:not(:only-child) {
  font-size: var(--taille-m);
  line-height: var(--interligne-accroche);
}

.fiche-biographie p + p {
  color: var(--couleur-texte-doux);
  font-size: var(--taille-s);
  line-height: var(--interligne-accroche);
}

/* Sous une accroche écrite, toute la biographie est la suite : dans l'encre adoucie, et, repliée,
   derrière « Voir plus ». Écrit après la règle du premier paragraphe, qu'il défait. */
.fiche-accroche:not([hidden]) + .fiche-biographie p {
  color: var(--couleur-texte-doux);
  font-size: var(--taille-s);
}

.fiche-accroche:not([hidden]) + .fiche-biographie-repliee {
  display: none;
}

/* REPLIÉE (Matthias, 30/10/2026) : l'accroche seule, sur deux lignes au plus, « Voir plus »
   dessous ; une biographie d'un seul paragraphe, sur trois. */
.fiche-biographie-repliee p + p {
  display: none;
}

.fiche-biographie-repliee p {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--lignes-accroche);
  line-clamp: var(--lignes-accroche);
  overflow: hidden;
}

.fiche-biographie-repliee p:only-child {
  -webkit-line-clamp: var(--lignes-biographie);
  line-clamp: var(--lignes-biographie);
}

.fiche-bio .bouton-discret {
  justify-self: start;
}

/* ---------- La carte de réservation ----------
   Un panneau blanc à contour noir et coins doux (`--rayon-carte-grande`, en squircle là
   où le navigateur le sait). Le panneau d'aperçu de la carte d'une certification
   (run 92) est le même objet, collé au défilement à côté de ce qu'on lit. Seules leur
   largeur et leur place diffèrent. */
.reservation,
.apercu {
  display: grid;
  gap: var(--espace-m);
  padding: var(--espace-l);
  background: var(--couleur-fond);
  border: var(--epaisseur-contour) solid var(--couleur-encre);
  border-radius: var(--rayon-carte-grande);
  corner-shape: squircle;
}

/* La carte de réservation, à droite de l'en-tête et de la biographie sur grand écran (sa
   place et son collage sont avec la composition de la fiche), centrée avant elle sur
   téléphone. L'avis mis en avant s'empile sous les prix. */
.reservation {
  justify-self: center;
  width: min(100%, var(--largeur-reservation));
}

/* L'aperçu suit la lecture de la certification. Sur une seule colonne il est le dernier
   bloc : il ne reste rien à parcourir, et le collage n'a alors aucun effet. Il ne grandit
   pas quand la place abonde, mais se resserre quand elle manque. */
.apercu {
  position: sticky;
  top: calc(var(--hauteur-entete) + var(--espace-l));
  flex: 0 1 var(--largeur-reservation);
}

/* LE PRIX D'APPEL ET LES DURÉES EN PASTILLES (Matthias, 30/10/2026 : la carte pesait trop).
   Le plus petit prix en grand, « À partir de » devant quand il y a plusieurs durées, puis
   les durées proposées en pastilles, sans boîte autour. Une pastille choisie montre le prix de
   sa durée et passe au marqueur « vous êtes ici » des segments (js/fiche-expert.js). */
.reservation-prix {
  margin: 0;
  font-size: var(--taille-xl);
}

/* Les pastilles se partagent la largeur de la carte en trois parts, une par durée du
   référentiel (`DUREES`, functions/_lib/expert.ts), le texte au centre : trois durées tiennent
   sur une ligne sans se serrer, et une seule garde la largeur d'une pastille. */
.durees {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--espace-s);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Le segment de `/reserver`, détaché de sa capsule : chacun porte son contour, qu'il perd
   une fois choisi pour le fond du marqueur. */
.durees .segment {
  width: 100%;
  min-height: 0;
  padding: var(--espace-s) 0;
  box-shadow: var(--trait-capsule);
  font-size: var(--taille-s);
}

/* Sur téléphone, la carte prend la largeur de la colonne (elle commençait 8 px après le reste)
   et les pastilles la hauteur d'un doigt (31 px au-dessus). */
@media (max-width: 48rem) {
  .reservation {
    width: 100%;
  }

  .durees .segment {
    min-height: var(--hauteur-lien);
  }
}

/* « Réserver » désactivé de la fiche de démonstration : plein et clair, sans le pointillé
   général des boutons désactivés, qui faisait un cadre de plus dans la carte. Le curseur
   et l'absence d'adresse disent toujours qu'il ne mène nulle part. */
.reservation .bouton[aria-disabled="true"] {
  background: var(--couleur-clair);
  outline: none;
}

/* LE BOUTON « RÉSERVER » (feature 14). Il prend toute la largeur de la carte : c'est
   l'action principale de la page, sa seule capsule bleue, et un bouton étroit flottant
   dans la carte se lirait comme une option parmi d'autres. */
.reservation-action {
  display: grid;
}

.reservation-action .bouton {
  width: 100%;
}

/* ============================================================
   RÉSERVATION D'UN CRÉNEAU (feature 14)
   DESIGN.md §6 : la ligne de l'expert, puis trois sections de page (durée, créneau,
   récapitulatif). La durée en capsule segmentée, le prix dessous ; la bande
   des jours et les créneaux en pilules ; le récapitulatif en lignes à filet.
   ⚠️ Ce que cette section ne pose PAS : la ligne d'expert, la pastille de portrait, le
   badge, la pilule, le prix, le squelette et l'état d'écran, qui existent depuis les
   features 6 à 11 et servent ici tels quels. La bande des jours partage la mécanique
   des filtres de l'annuaire, écrite là-bas.
   ============================================================ */

/* Un cran plus large que les écrans de formulaire, comme les disponibilités : la bande
   des jours porte quatorze pastilles et la liste des créneaux jusqu'à une vingtaine, et
   dans une page de formulaire les deux se lisent en escalier. La largeur de LECTURE
   suffit, la page ne contenant aucune liste à cinq colonnes comme l'annuaire. */
.page-reserver {
  max-width: var(--largeur-page-liste);
}

/* AVEC QUI : la ligne de l'annuaire telle quelle (`.carte`), sans sa troisième
   colonne, celle du prix. Le filet la sépare de la suite au lieu de séparer deux
   lignes, et le haut du padding part, le h1 étant juste au-dessus avec sa marge. */
.reserver-expert,
.examen-expert {
  padding-top: 0;
  margin-bottom: var(--espace-xl);
  border-bottom: var(--epaisseur-filet) solid var(--couleur-encre);
}

/* ⚠️ L'ESPACEMENT DE SECTION DE DESIGN.md §6, AUX DEUX VALEURS QU'IL DONNE : sept
   rems au-dessus de 48rem, quatre en dessous (décision 5 de direction artistique,
   19/09/2026, FEATURES.md § Notes de cadrage). Les trois blocs de cet écran sont des
   SECTIONS de page, chacune sous son h2 (« Durée de la session », « Créneau »,
   « Récapitulatif »), et non deux groupes d'un même formulaire comme sur
   `/disponibilites`, dont la règle voisine reste à `--espace-l`. Ici les sections sont
   des enfants directs d'un bloc, sans gouttière à compléter : la marge porte donc
   l'espacement en entier. L'historique de la carte d'une certification (run 92) est une
   section de page de même sorte, sous les deux colonnes, et les questions de la vidéo de
   `/admin/reglages` (feature 31, run B1), un second formulaire sous celui des réglages. */
.page-reserver .reglage + .reglage,
.examen + .historique,
.formulaire-fiche + .formulaire-fiche {
  margin-top: var(--espace-xxl);
}

/* ---------- La capsule segmentée des durées (DESIGN.md §6) ----------
   COUCHÉE, contrairement au bloc des prix de la fiche publique : un segment ne porte
   qu'une durée et tient donc sur une ligne. C'est le sélecteur de l'accueil, le même
   composant : une capsule blanche, des segments transparents qui sont chacun une capsule, et
   le segment choisi inversé en noir (le marqueur « vous êtes ici », écrit plus haut).
   Plus aucun filet entre deux segments.

   ⚠️ AUCUN `overflow: hidden` SUR LA CAPSULE, alors que c'est le réflexe pour en
   arrondir les extrémités : il rognerait l'anneau de focus des segments, réservé
   précisément à ce qui se commande. Chaque segment porte son propre rayon.
   Et rien n'est figé en `flex` : le segment garde le `0 1 auto` par défaut, donc il
   cède plutôt que de pousser la capsule hors de la colonne si un libellé s'allongeait. */
.segments {
  display: inline-flex;
  gap: var(--espace-xs);
  max-width: 100%;
  padding: var(--espace-reserve-segments);
  border-radius: var(--rayon-pilule);
  background: var(--couleur-fond);
  box-shadow: var(--trait-capsule);
}

.segment {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: var(--hauteur-lien);
  padding: 0 var(--padding-segment);
  border: 0;
  border-radius: var(--rayon-pilule);
  background: transparent;
  font: inherit;
  font-size: var(--taille-base);
  font-weight: var(--graisse-moyenne);
  line-height: 1;
  color: inherit;
  white-space: nowrap;
  cursor: pointer;
}

.segment[aria-pressed="true"] {
  font-weight: var(--graisse-titre);
}

/* ---------- La bande des jours et les créneaux ---------- */

/* Sa mécanique (repli sur grand écran, défilement et réserve d'anneau de focus sur
   petit) est celle des filtres de l'annuaire, écrite avec eux. Ne lui appartient en
   propre que sa largeur : dans la grille d'un `.reglage`, qui aligne ses enfants au
   début, un cadre défilant doit occuper toute la colonne pour avoir de quoi défiler. */
.bande-jours {
  width: 100%;
}

/* ---------- Le récapitulatif ---------- */

/* Une liste en lignes à filet (DESIGN.md §6), et non une carte : l'écran n'a pas
   besoin d'un panneau sous les deux listes de pilules qui le précèdent. */
.recap {
  display: grid;
  width: 100%;
  margin: 0;
}

/* ⚠️ UNE GRILLE À DEUX COLONNES, ET NON UN FLEX QUI SE REPLIE. La valeur doit
   s'enrouler DANS sa colonne. En `flex-wrap: wrap`, une valeur dont la largeur
   `max-content` dépasse la place restante ne rétrécit pas, elle passe à la ligne du
   dessous et se pose à l'abscisse de son propre intitulé : la date tombait donc sous
   « Date et heure » et les quatre valeurs se lisaient en escalier, sur grand écran
   comme sur petit. Le repli n'était pas un repli de petit écran, c'était la mesure
   `max-content` d'une phrase.
   La seconde piste est `minmax(0, 1fr)` et non `1fr` : le `1fr` nu vaut
   `minmax(auto, 1fr)`, donc la piste garde la largeur minimale de son contenu et une
   valeur sans espace déborderait au lieu de s'enrouler. */
.recap-ligne {
  display: grid;
  grid-template-columns: var(--largeur-recap-libelle) minmax(0, 1fr);
  align-items: baseline;
  gap: var(--espace-m);
  padding-block: var(--espace-s);
}

.recap-ligne + .recap-ligne {
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

/* L'intitulé occupe la première colonne, dont la largeur est la même pour toutes les
   lignes : c'est elle qui aligne les valeurs. Il a la voix d'un texte secondaire, noir,
   plus petit, en 400 ; la valeur, elle, est en 500 : sans gris, c'est la graisse et la
   taille qui les distinguent (DESIGN.md §3). */
.recap dt {
  font-size: var(--taille-s);
}

/* Les huit compteurs du hub SEULEMENT : le journal et les fiches de l'administration
   gardent la largeur d'intitulé commune, sinon leurs valeurs se resserrent à 375 px. Le
   nombre ne se coupe pas (« 144 · 8 760 € » ne renvoie jamais le « € » à la ligne). */
.recap-compteurs {
  --largeur-recap-libelle: var(--largeur-recap-admin);
}

.recap-compteurs dd {
  white-space: nowrap;
}

/* La valeur occupe la seconde colonne et s'enroule dedans : c'est la date, longue, qui
   passe à deux lignes DANS sa colonne, jamais sous son intitulé. */
.recap dd {
  margin: 0;
  font-weight: var(--graisse-moyenne);
}

/* ---------- Mobile ---------- */
@media (max-width: 48rem) {
  /* La valeur mobile de l'espacement de section (DESIGN.md §6, décision 5 de direction
     artistique) : quatre rems, sur le point de rupture de toute la feuille. */
  .page-reserver .reglage + .reglage,
  .examen + .historique,
  .formulaire-fiche + .formulaire-fiche {
    margin-top: var(--espace-xl);
  }

  /* LA BARRE FIXÉE EN BAS D'ÉCRAN de DESIGN.md §6 : c'est le MÊME bouton que celui de
     la carte de réservation, déplacé par le CSS, et surtout jamais un second bouton
     recopié. La fiche est longue (portrait, domaines, badge, biographie, langues, prix)
     et la carte est son dernier bloc : sans cette barre, l'action principale de la page
     n'est visible qu'après l'avoir lue en entier. Fond blanc, filet noir au-dessus.
     Le pied de page reçoit la hauteur correspondante en bas de la page, faute de quoi
     la barre lui passerait dessus. */
  .reservation-action {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: 1;
    padding: var(--espace-s) var(--gouttiere-page);
    background: var(--couleur-fond);
    border-top: var(--epaisseur-filet) solid var(--couleur-encre);
  }

  /* ⚠️ LA RÉSERVE NE VAUT QUE LÀ OÙ LA BARRE SE PEINT, et le même gabarit sert aux
     deux états de `/experts/<id>`. Posée sur `.page-fiche` seule, elle restait sur
     « Expert non disponible », où `#fiche` garde son `hidden` et où la barre n'existe
     donc pas : une bande vide sous le pied de page. La condition lit l'attribut que la
     Function pose ou retire (`functions/experts/[id].ts`), donc la réserve suit la
     barre sans une ligne de JavaScript, et sans clignotement : c'est le serveur qui a
     déjà tranché avant le premier rendu. */
  .page-fiche:has(.fiche:not([hidden])) {
    padding-bottom: var(--hauteur-barre-reservation);
  }
}

/* ============================================================
   CERTIFICATION DE L'EXPERT (feature 9, second segment)
   Une liste en lignes à filet, un bloc par type de pièce, jamais une grille de cartes.
   ⚠️ Ce que cette section ne pose PAS : le bloc de réglage, la ligne de fichier et sa
   commande, la pilule à cocher, le badge, le point d'état et ses quatre dessins, le
   titre de bloc, la zone de message, la jauge, le champ en faute, le squelette et l'état
   d'écran, qui existent ailleurs dans la feuille et servent ici tels quels.
   ============================================================ */

/* ⚠️ DEUX PIÈCES SONT DEUX RÉGLAGES D'UN MÊME FORMULAIRE, qui part d'un seul bouton :
   `--espace-l` en plus de la gouttière (décision 5b de direction artistique), et le
   filet de la « liste en lignes » posé AU MILIEU de cet écart. Le `margin-top` de
   `.reglage + .reglage` le mettait tout entier au-dessus du filet, qui aurait alors
   touché le titre suivant : il devient ici un `padding` sous le filet. `+` ne pose le
   filet qu'entre deux pièces, jamais au-dessus de la première. */
.piece + .piece {
  margin-top: 0;
  padding-top: var(--espace-l);
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

/* Dans la grille d'un `.reglage`, qui aligne ses enfants au début, un groupe de champs
   se réduirait à la largeur de son contenu : les deux références prennent la colonne. */
.piece > .champ-groupe {
  width: 100%;
}

/* ⚠️ ET LA SECONDE RÉFÉRENCE S'ÉCARTE DE LA PREMIÈRE PLUS QUE SES CHAMPS NE S'ÉCARTENT
   ENTRE EUX : avec la seule gouttière du bloc, « Seconde référence » tombait à la même
   distance de l'email qui la précède que de son propre nom, et rien ne disait où finit
   une référence. `--espace-l` au total entre les deux, `--espace-m` entre deux champs. */
.piece > .champ-groupe + .champ-groupe {
  margin-top: var(--espace-m);
}

/* Le nom d'un fichier vient de l'expert, et il peut être long et sans espace : il
   s'enroule dans sa colonne plutôt que de pousser « Retirer » hors de la ligne.
   `min-width: 0` parce qu'un élément flex ne descend pas sous sa largeur de contenu. */
.fichier-texte {
  display: grid;
  gap: var(--espace-xs);
  min-width: 0;
}

.fichier-nom {
  overflow-wrap: anywhere;
}

/* ============================================================
   LA FILE ET LA CARTE D'UNE CERTIFICATION, ÉCRANS DE L'ADMINISTRATEUR (feature 9, run 92)
   La file est la liste de l'annuaire (`.carte`), l'état à la place du prix ; la carte a
   deux colonnes qui se replient par leurs propres largeurs, comme la fiche publique, les
   pièces en lignes à filet à gauche, le panneau d'aperçu collé au défilement à droite.
   Jamais une modale.
   ⚠️ Ce que cette section ne pose PAS : la ligne d'expert, la pastille, le badge, la
   ligne de fichier et son point d'état, les conditions, le récapitulatif en lignes
   (l'historique), la surface collée (celle de la carte de réservation), les états
   d'écran et le squelette.
   ============================================================ */

/* La colonne large de l'annuaire, pour les deux écrans : la file porte les mêmes lignes
   (un portrait, un nom, ses domaines, une ligne de dates et l'état à la place du prix),
   qu'une colonne de lecture repliait en pile ; la carte porte une liste de pièces et un
   panneau où lire un PDF. Les paragraphes restent à la largeur de lecture par la règle
   générale de `p`. Les écrans de l'administration (feature 23 : le tableau, les
   réglages, le journal, les registres) la prennent aussi : ils portent la même
   navigation que la file, qui ne doit pas changer de largeur d'un écran à l'autre. */
.page-file,
.page-examen,
.page-admin {
  max-width: var(--largeur-max);
}

/* La colonne des pièces ne descend pas sous sa base, et cède sa place au panneau quand
   les deux ne tiennent plus côte à côte : c'est alors lui qui passe dessous. */
.examen-principal {
  flex: 1 1 var(--largeur-examen);
  min-width: 0;
}

/* L'état de la demande, entre la ligne de l'expert et les pièces : le même écart que
   celui qui sépare la ligne de l'expert de la suite. */
.examen-etat {
  margin-bottom: var(--espace-xl);
}

/* Le panneau d'aperçu : la surface de la carte de réservation, à sa propre largeur. Ses
   enfants gardent leur largeur (le bouton « Télécharger » n'est pas l'action de l'écran). */
.apercu {
  flex: 1 1 var(--largeur-apercu);
  justify-items: start;
  /* Passé sous la liste, le panneau est ramené à l'écran par « Voir » : il s'y pose à la
     même distance du bord que lorsqu'il colle au défilement. */
  scroll-margin-top: var(--espace-l);
}

/* Une image entière dans le cadre de la fenêtre, jamais rognée ni étirée. */
.apercu-image {
  display: block;
  max-height: var(--hauteur-apercu);
  object-fit: contain;
}

/* Le PDF, lu par le lecteur du navigateur, dans un cadre de même origine (kit §7). */
.apercu-cadre {
  width: 100%;
  height: var(--hauteur-apercu);
  border: var(--epaisseur-contour) solid var(--couleur-encre);
  border-radius: var(--rayon-carte);
  background: var(--couleur-fond);
}

/* L'historique, sous les deux colonnes : à la largeur de lecture, comme tout texte. */
.historique,
.avis-zone {
  max-width: var(--largeur-texte);
}

/* La valeur d'un champ (le lien LinkedIn, le numéro ORIAS, les références) prend la
   largeur du panneau : un récapitulatif en lignes ne se réduit pas à son contenu. */
.apercu-valeur {
  width: 100%;
}

/* ⚠️ UNE LIGNE DE PIÈCE SE REPLIE, À LA DIFFÉRENCE D'UNE LIGNE DE FICHIER DE L'EXPERT :
   elle porte trois commandes au lieu d'une. Quand le texte et les commandes ne tiennent
   plus côte à côte, les commandes passent dessous, alignées à gauche ; et le motif d'un
   refus se déplie SOUS la ligne, sur toute sa largeur (décision 28). Le repli vient de
   leurs largeurs, jamais d'un point de rupture. */
.piece-examen {
  flex-wrap: wrap;
}

.piece-examen .fichier-texte {
  flex-basis: var(--largeur-identite);
}

/* Ce qui résume une pièce (un nom de fichier, un lien LinkedIn) vient de l'expert, et
   peut être long et sans espace : il s'enroule sur sa propre ligne plutôt que de pousser
   la ligne sur les commandes. La valeur d'une ligne de récapitulatif fait de même : la
   fiche d'une réservation (run 231) y écrit des identifiants Stripe et des adresses,
   plus longs que sa colonne sur petit écran, qui élargissaient la page. Et l'identité
   d'une ligne de registre : un compte sans nom s'y nomme par son adresse, un reversement
   par son transfert (`tr_…`), sans une espace où couper. */
.piece-resume,
.recap dd,
.carte-identite {
  overflow-wrap: anywhere;
}

/* Les commandes d'une carte de « Mes rendez-vous » (feature 17) sont la même rangée :
   un bouton, et la zone de message à sa suite, qui ne prend de place que lorsqu'elle
   parle. */
.piece-commandes,
.carte-commandes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-m);
}

/* ⚠️ VIDE, LA ZONE DE MESSAGE D'UNE CARTE NE PREND AUCUNE PLACE, GOUTTIÈRE COMPRISE
   (PIEGES.md E49). Elle reste dans la page (une région vivante ne s'annonce que si elle
   y était avant de parler), mais sa gouttière suffisait à la faire passer seule à la
   ligne dès que deux commandes remplissent le rang, « Reporter » et « Annuler le
   rendez-vous » sur petit écran : 40 px de vide sous chaque carte. Sa marge rend donc
   la gouttière ; dès qu'elle parle, elle la reprend et passe à la ligne comme avant. */
.carte-commandes .message:empty {
  margin-inline-start: calc(var(--espace-m) * -1);
}

/* La zone de motif, dépliée en ligne sous ce qu'elle décide : son libellé, son champ, la
   raison d'un refus dans la zone même, et ses deux commandes. L'avertissement d'une
   annulation (feature 17, décision 16) est la même zone, dépliée sous une carte de « Mes
   rendez-vous » : son titre, sa phrase, sa case quand rien n'est remboursé, ses deux
   commandes. Jamais une fenêtre. */
.motif,
.carte-zone {
  display: grid;
  gap: var(--espace-m);
  flex-basis: 100%;
  width: 100%;
}

/* La règle et les trois verbes, sous la liste des pièces : un bloc qui prend la colonne,
   pour que « Fait » et « À faire » s'alignent au bord droit. Sa marge complète la
   gouttière du bloc des pièces jusqu'à `--espace-l` : la liste et la règle sont deux
   blocs qui ne se touchent pas (DESIGN.md §6), la règle ne se lit pas comme une pièce de
   plus. */
.decisions {
  display: grid;
  gap: var(--espace-m);
  width: 100%;
  margin-top: var(--espace-m);
}

/* ============================================================
   ACCUEIL (refonte du 09/10/2026, DESIGN.md §6)
   Sous le hero et ses orbites, sur blanc (retours d'Abel du 18/10/2026) : « Ils
   décrochent », « Combien de temps ? », « Comment ça marche » en quatre temps, la FAQ, la
   carte bleue « Rejoignez le cercle ».
   C'est la vitrine : le seul aplat bleu de l'application, que DESIGN.md §9 interdit sur un
   écran de travail.
   ⚠️ Ce que cette section ne pose PAS : le hero, les orbites du hero, les boutons (les
   ronds sont avec les boutons), la capsule segmentée, le disque
   d'un numéro et sa grille, le résumé cliquable, le portrait, le prix, le squelette et
   l'état d'écran. Elle ne fait que les poser dans leur contexte.
   ============================================================ */

.accueil {
  max-width: var(--largeur-max);
  margin-inline: auto;
  padding: 0 var(--gouttiere-accueil);
}

.accueil-section {
  padding-block: var(--espace-section-accueil);
}

/* Deux sections qui se suivent ne cumulent pas leurs réserves : l'écart entre elles reste
   celui de toutes les sections de l'accueil. */
.accueil-section + .accueil-section {
  padding-top: 0;
}

/* Les titres de section de l'accueil ont l'échelle d'un h1 de page (DESIGN.md §3). */
.accueil-section h2,
.accueil-section-titre,
.panneau-bleu h2 {
  margin: 0;
  font-size: var(--taille-xxl);
  line-height: var(--interligne-titre-h1);
  letter-spacing: var(--interlettrage-serre);
}

/* ---------- « Ils décrochent » ----------
   Une section sur blanc comme les autres (retours d'Abel du 18/10/2026 : plus de cadre, plus
   de décor derrière) : la tête, puis la grille des six portraits ou l'un des trois états. */
#experts {
  display: flex;
  flex-direction: column;
  gap: var(--espace-xl);
}

.panneau-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--espace-m);
}

/* L'étiquette d'un exemple, en mode test : sur un expert d'exemple du cadre, sur un avis
   d'exemple. C'est le message « attention » en capsule, sans les marges qu'il prend
   au-dessus d'un sommaire (d'où le sélecteur à deux classes, qui gagne sur lui). */
.message.etiquette-exemple {
  justify-self: start;
  margin: 0;
  font-weight: var(--graisse-titre);
}

.grille-experts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--largeur-portrait-min), 1fr));
  gap: var(--espace-xl) var(--espace-l);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ⚠️ ÉCRIT APRÈS LA GRILLE, ET NON AVEC LES AUTRES RÈGLES DU PETIT ÉCRAN : à spécificité égale,
   la règle de base, plus bas, l'emportait. */
@media (max-width: 48rem) {
  /* LES PORTRAITS DE « ILS DÉCROCHENT » DÉFILENT À L'HORIZONTALE (demande de Matthias du
     14/10/2026) : six portraits sur deux colonnes faisaient trois rangs, plus d'un écran de
     haut. Une ligne, que le doigt fait défiler ; le portrait que le bord coupe dit qu'il y
     en a d'autres, comme la pilule coupée des filtres. Même réserve et même reprise que
     les filtres de l'annuaire, en hauteur aussi : le bouton rond déborde du portrait et porte
     une ombre. Chaque portrait est une cible d'accroche, au bord gauche.
     La bande va d'un bord de l'écran à l'autre, et l'écart entre deux portraits est serré :
     le troisième se montre franchement au bord droit (on n'en voyait qu'1 px, 01/11/2026). */
  .grille-experts {
    display: flex;
    overflow-x: auto;
    gap: var(--espace-m);
    padding: var(--espace-s) var(--gouttiere-accueil);
    margin: calc(var(--espace-s) * -1) calc(var(--gouttiere-accueil) * -1);
    scroll-padding-inline: var(--gouttiere-accueil);
    scroll-snap-type: inline mandatory;
  }

  .grille-experts > li {
    flex: none;
    width: var(--taille-portrait-accueil);
    scroll-snap-align: start;
  }
}

.expert-accueil {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-xs);
  text-align: center;
}

/* Le portrait de 148 px, et la boîte où le bouton rond au combiné vient déborder en bas
   à droite. Le disque en pointillés du squelette porte la même classe et prend la même
   taille. */
.expert-accueil .portrait {
  position: relative;
  --taille-pastille: var(--taille-portrait-accueil);
  margin-bottom: var(--espace-m);
}

/* ⚠️ LA PHOTO GARDE SA LARGEUR. La règle générale des images la ramenait à la largeur de
   sa colonne de grille, plus étroite que le portrait sous 395 px : la photo devenait un
   ovale (139 x 148 px à 375 px) à côté de disques d'initiales bien ronds. */
.expert-accueil .photo-profil {
  max-width: none;
}

.expert-accueil h3,
.expert-accueil p {
  margin: 0;
}

.expert-accueil p,
.expert-accueil .prix {
  font-size: var(--taille-s);
}

/* Sous un portrait de 148 px, « À partir de 90 € · 30 min » ne tient pas sur une ligne :
   « À partir de » prend la sienne, le montant et sa durée restent ensemble dessous. Sans
   cette base, c'est la durée qui passait seule à la ligne, derrière un point médian
   suspendu. */
.expert-accueil .prix {
  flex-wrap: wrap;
  justify-content: center;
}

.expert-accueil .prix-avant {
  flex-basis: 100%;
}

.bouton-decrocher {
  position: absolute;
  right: var(--debord-decrocher);
  bottom: var(--debord-decrocher);
}

/* Les pictogrammes des deux boutons ronds de l'accueil : des traits, dans la couleur du
   bouton. Leurs attributs de forme sont dans le HTML, leur dessin ici (un SVG en ligne
   ne porte aucun attribut `style`, CSP). */
.bouton-decrocher svg,
.prochain-bouton svg {
  width: var(--taille-m);
  height: var(--taille-m);
  fill: none;
  stroke: currentColor;
  stroke-width: var(--epaisseur-trait-icone);
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* L'état vide et l'état d'erreur de l'annuaire, sous la tête de la section : le même bloc
   `.etat`, centré, sans son padding (la section a le sien). */
#experts .etat {
  justify-items: center;
  text-align: center;
  padding-block: 0;
}

/* ---------- « Combien de temps ? » ---------- */
.durees-accueil {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-l);
  text-align: center;
}

.durees-accueil p {
  margin: 0;
  font-size: var(--taille-m);
}

/* Les trois besoins occupent LA MÊME CASE : la section garde la hauteur du plus long, et
   rien ne bouge sous elle quand on change de durée.
   ⚠️ UN BESOIN CACHÉ RESTE DANS LA GRILLE, INVISIBLE. C'est la seule règle de la feuille
   qui rend une boîte à un élément `hidden` (PIEGES.md E1), et c'est voulu : en
   `display: none` il ne compterait plus dans la hauteur. `visibility: hidden` le retire
   de l'écran comme des lecteurs d'écran. */
.besoins {
  display: grid;
  justify-items: center;
}

.besoin {
  grid-area: 1 / 1;
  display: grid;
  justify-items: center;
  align-content: start;
  gap: var(--espace-m);
}

.besoin[hidden] {
  display: grid;
  visibility: hidden;
}

/* Le besoin, en grand : il a pris la place du prix géant de la maquette. Écrit sous
   `.durees-accueil` pour gagner sur la règle du paragraphe juste au-dessus : c'est un
   paragraphe lui aussi, et il en quitte la largeur de lecture. */
.durees-accueil .besoin-titre {
  max-width: none;
  font-size: var(--taille-besoin);
  font-weight: var(--graisse-titre);
  line-height: 1;
  letter-spacing: var(--interlettrage-serre);
}

/* ---------- Une section en deux colonnes : « Comment ça marche », la FAQ ----------
   Le titre à gauche, qui reste en vue pendant qu'on lit la colonne de droite ; sous 64rem
   il passe au-dessus.
   ⚠️ LA RÉSERVE EST ÉCRITE ICI, APRÈS `.accueil-section` que ces sections portent aussi :
   aucune en haut (la section qui précède a déjà la sienne en bas, et les deux
   s'ajouteraient), une en bas, et le retrait latéral que la maquette donnait aux étapes,
   pour que le texte ne colle pas au bord d'un petit écran. La section des avis
   (js/avis-site.js) prend la même. */
.section-duo,
.accueil-avis {
  padding: 0 var(--retrait-etapes) var(--espace-section-accueil);
}

.section-duo {
  display: grid;
  gap: var(--espace-xl);
}

.section-duo-tete {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--espace-l);
}

.section-duo-tete .chapeau {
  margin: 0;
}

@media (min-width: 64rem) {
  .section-duo {
    grid-template-columns: minmax(0, var(--largeur-duo-tete)) minmax(0, var(--largeur-duo-contenu));
    align-items: start;
  }

  .section-duo-tete {
    position: sticky;
    top: calc(var(--hauteur-entete) + var(--espace-l));
  }
}

/* ---------- Les étapes de « Comment ça marche » et du guide « Devenir expert » ----------
   Des numéros ronds (leur disque et leur grille sont plus haut, avec la liste numérotée),
   reliés par un filet qui descend d'un disque au suivant ; à côté, un titre, une phrase et
   deux précisions. Sans carte. Le titre est un h3 sur l'accueil, un h2 sur le guide, où il
   grandit (`--taille-titre-guide`, « de gros textes ») ; sa taille est une variable de
   l'étape, que lit aussi le calage de sa première ligne sur le disque. */
.etape {
  --taille-titre-etape: var(--taille-xl);
  position: relative;
}

.guide .etape {
  --taille-titre-etape: var(--taille-titre-guide);
}

/* Le filet part du bas du disque et rejoint le disque suivant, à travers l'écart de la
   liste. La dernière étape n'en a pas : rien ne la suit. */
.etape:not(:last-child)::before {
  content: "";
  position: absolute;
  top: var(--taille-numero-etape);
  bottom: calc(var(--espace-xl) * -1);
  left: calc(var(--taille-numero-etape) / 2);
  border-left: var(--epaisseur-contour) solid var(--couleur-encre);
}

/* La première ligne du titre se centre sur le disque : la moitié de ce que le disque a de
   plus haut qu'elle. */
.etape-corps {
  display: flex;
  flex-direction: column;
  gap: var(--espace-s);
  padding-top: calc((var(--taille-numero-etape) - var(--taille-titre-etape) * var(--interligne-titre-h3)) / 2);
}

/* L'interligne est celui du h3, que le calage ci-dessus suppose : un h2 de l'étape le prend
   aussi, sinon sa première ligne ne serait plus centrée sur le disque. */
.etape h2,
.etape h3 {
  margin: 0;
  font-size: var(--taille-titre-etape);
  line-height: var(--interligne-titre-h3);
  letter-spacing: var(--interlettrage-titre-h2);
}

/* Le temps d'une étape du guide, sous son titre. */
.etape-duree {
  font-size: var(--taille-s);
  font-weight: var(--graisse-moyenne);
}

.etape p {
  margin: 0;
}

.etape-points {
  display: grid;
  gap: var(--espace-xs);
  margin: var(--espace-s) 0 0;
  padding-left: var(--espace-m);
  font-size: var(--taille-s);
}

/* ---------- Le guide « Devenir expert » (26/10/2026) ----------
   La section en deux colonnes et les étapes de l'accueil, dans la colonne large de
   l'annuaire. Sous les étapes, hors du chemin, la certification (le bloc `.niveau-texte`)
   puis la ligne des règles ; chacune à l'écart de deux blocs qui ne se touchent pas. */
/* ⚠️ AUCUNE RÉSERVE PROPRE À LA SECTION, ET C'EST UNE MESURE : celle de l'accueil (130 px en
   bas, un retrait sur les côtés) s'ajoutait à la gouttière de `.colonne`, et il restait
   194 px entre la dernière ligne et le pied de page, contre 64 sur /experts ; le titre,
   lui, rentrait de 29 px par rapport à celui de l'annuaire. */
.guide .section-duo {
  padding: 0;
}

/* Dans la tête, la précision suit SON bouton de près : la gouttière de la section (32 px)
   l'en détachait. Le bloc d'actions garde sa marge haute, qui l'écarte du chapeau. */
.guide .section-duo-tete {
  gap: var(--espace-m);
}

.guide-certification {
  margin-top: var(--espace-xl);
}

.guide-regles {
  margin-top: var(--espace-l);
}

/* ---------- La FAQ ----------
   Des `<details>` séparés par un filet : la question, et à droite un signe rond, anneau
   creux au repos, disque noir une fois ouverte (l'inversion, DESIGN.md §4), dont le
   « plus » devient un « moins ». Le résumé cliquable est avec le dépliant de la connexion. */
/* Le titre d'un groupe de questions : sa ligne du bas est le filet du haut de la
   première. */
.questions-titre {
  margin: 0;
  padding-bottom: var(--espace-m);
  border-bottom: var(--epaisseur-filet) solid var(--couleur-encre);
  font-size: var(--taille-s);
  font-weight: var(--graisse-titre);
}

.question + .questions-titre {
  margin-top: var(--espace-xl);
}

.question {
  border-bottom: var(--epaisseur-filet) solid var(--couleur-encre);
}

.question summary {
  justify-content: space-between;
  gap: var(--espace-m);
  padding-block: var(--espace-m);
  font-size: var(--taille-l);
  font-weight: var(--graisse-titre);
  letter-spacing: var(--interlettrage-titre-h3);
  line-height: var(--interligne-titre-h3);
}

/* L'anneau de focus rentre dans le résumé : dehors, il longeait les deux filets de la
   question et se lisait comme un cadre à double trait. */
.question summary:focus-visible {
  outline-offset: calc((var(--decalage-focus) + var(--epaisseur-focus)) * -1);
}

.question p {
  margin: 0;
  padding-bottom: var(--espace-l);
}

.question-signe {
  position: relative;
  flex: none;
  width: var(--taille-signe-question);
  height: var(--taille-signe-question);
  border: var(--epaisseur-contour) solid var(--couleur-encre);
  border-radius: 50%;
}

.question-signe::before,
.question-signe::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--taille-point);
  border-top: var(--epaisseur-marqueur) solid currentColor;
  transform: translate(-50%, -50%);
}

.question-signe::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.question[open] .question-signe {
  background: var(--couleur-encre);
  color: var(--couleur-fond);
}

.question[open] .question-signe::after {
  transform: translate(-50%, -50%);
}

/* ---------- La carte bleue ----------
   Le seul grand aplat bleu de l'application, sans décor depuis les retours d'Abel du
   18/10/2026 : la même réserve en haut et en bas. */
.panneau-bleu {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-l);
  max-width: var(--largeur-carte-bleue);
  margin: 0 auto var(--espace-xl);
  padding: var(--carte-bleue-padding-haut) var(--espace-l);
  border-radius: var(--rayon-panneau);
  corner-shape: squircle;
  background: var(--panneau-fond);
  color: var(--panneau-texte);
  text-align: center;
}

.panneau-bleu h2 {
  max-width: var(--largeur-titre-carte-bleue);
}

.panneau-bleu p {
  margin: 0;
  max-width: var(--largeur-accroche);
  font-size: var(--taille-m);
}

/* ---------- La capsule « prochain rendez-vous » ----------
   Une capsule blanche posée sous les deux boutons du hero, pour le membre
   connecté qui a un rendez-vous à venir ; pour tout autre visiteur elle n'existe pas
   (`hidden`), et sa place n'est pas réservée. */
.prochain {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-m);
  margin-top: var(--hero-ecart-prochain);
  padding: var(--espace-s) var(--espace-s) var(--espace-s) var(--espace-m);
  border-radius: var(--rayon-pilule);
  background: var(--couleur-fond);
  box-shadow: var(--trait-capsule);
  text-align: left;
}

.prochain .portrait {
  --taille-pastille: var(--taille-portrait-prochain);
}

.prochain-texte {
  display: grid;
  gap: 0;
  padding-right: var(--espace-m);
}

.prochain-titre {
  font-weight: var(--graisse-titre);
}

.prochain-sous {
  font-size: var(--taille-s);
}

/* ---------- Mobile ---------- */
@media (max-width: 48rem) {
  #experts {
    gap: var(--espace-l);
  }
}

/* ============================================================
   LES AVIS (feature 29, DESIGN.md §7, composants 7 et 8)
   Deux composants et deux seulement : la notation et la ligne d'avis, plus la moyenne qui
   les résume. Aucune couleur de plus, aucune étoile, aucune opacité : une note est une
   MESURE, ni un état ni une action, donc de l'encre.
   ⚠️ Ce que cette section ne pose PAS : le choix de la note (la capsule segmentée), la
   zone dépliée du formulaire (`.carte-zone`), ses champs, ses messages, ses boutons, la
   pagination et l'état vide, qui existent et servent tels quels. Le point creux d'une
   notation, le titre du formulaire, sa largeur, la pile `.avis-bloc` et le titre qui
   prend le focus sont des sélecteurs AJOUTÉS à des règles existantes, plus haut.
   ============================================================ */

/* La notation : cinq points, pleins jusqu'à la note, et la note écrite. En BLEU, pleins
   comme creux, depuis le 10/10/2026 (demande de Matthias ; avant, de l'encre) : c'est le
   seul dessin bleu qui ne soit ni une action ni un état, et la note reste dite en toutes
   lettres à côté. `.notation-point` s'AJOUTE au groupe de base `.condition-point,
   .badge-point, .piece-point` (l'anneau creux), dont il ne change que la couleur. */
.notation {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-s);
  margin: 0;
  font-size: var(--taille-s);
}

.notation-points {
  display: inline-flex;
  gap: var(--espace-xs);
}

.notation-point {
  border-color: var(--couleur-accent);
}

.notation[data-note="1"] .notation-point:nth-child(-n + 1),
.notation[data-note="2"] .notation-point:nth-child(-n + 2),
.notation[data-note="3"] .notation-point:nth-child(-n + 3),
.notation[data-note="4"] .notation-point:nth-child(-n + 4),
.notation[data-note="5"] .notation-point {
  background: var(--couleur-accent);
}

.notation-valeur {
  font-weight: var(--graisse-titre);
  font-variant-numeric: tabular-nums;
}

/* La moyenne : cinq points bleus remplis jusqu'à elle, arrondie au demi-point, puis le
   chiffre précis, en grand, et sa légende (demande de Matthias du 11/10/2026 : une moyenne
   qui se voit). Les points sont ceux de la notation, en plus grand. */
.moyenne {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-s) var(--espace-m);
  margin: 0;
  font-size: var(--taille-s);
}

.moyenne-points {
  display: inline-flex;
  gap: var(--espace-s);
}

.moyenne-points .notation-point {
  width: var(--taille-point-moyenne);
  height: var(--taille-point-moyenne);
}

.moyenne .notation-point[data-rempli="plein"] {
  background: var(--couleur-accent);
}

/* Le demi-point : la moitié gauche du disque, sans dégradé (DESIGN.md §4) ; le disque rogne
   ce qui dépasse de son cercle. */
.moyenne .notation-point[data-rempli="moitie"] {
  position: relative;
  overflow: hidden;
}

.moyenne .notation-point[data-rempli="moitie"]::after {
  content: "";
  position: absolute;
  inset: 0 50% 0 0;
  background: var(--couleur-accent);
}

.moyenne-valeur {
  font-size: var(--taille-xl);
  font-weight: var(--graisse-titre);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* La même moyenne dans une carte de l'annuaire, à la taille d'une ligne de la carte. */
.moyenne-carte {
  --taille-point-moyenne: var(--taille-point-moyenne-carte);
  gap: var(--espace-xs) var(--espace-s);
}

.moyenne-carte .moyenne-points {
  gap: var(--espace-xs);
}

.moyenne-carte .moyenne-valeur {
  font-size: var(--taille-base);
}

/* La ligne d'avis : la grammaire des listes de l'application (lignes à filet), pas une grille
   de cartes. À gauche qui et quand, à droite ce qui est dit. */
.avis-liste {
  margin: 0;
  padding: 0;
  list-style: none;
}

.avis {
  display: grid;
  grid-template-columns: var(--largeur-avis-tete) minmax(0, 1fr);
  gap: var(--espace-m) var(--espace-l);
  padding-block: var(--espace-l);
}

.avis + .avis {
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

/* Qui : le portrait (la photo de profil, les initiales à défaut), puis le nom, la note et
   les dates. */
.avis-tete {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--espace-m);
}

.avis-portrait {
  --taille-pastille: var(--taille-portrait-avis);
}

.avis-portrait .photo-pastille {
  font-size: var(--taille-base);
}

.avis-qui {
  display: grid;
  align-content: start;
  justify-items: start;
  gap: var(--espace-xs);
}

.avis-qui .fiche-meta {
  margin: 0;
}

.avis-auteur {
  margin: 0;
  font-weight: var(--graisse-titre);
}

/* UN TEXTE ÉCRIT PAR QUELQU'UN : un avis, la biographie et l'accroche d'une fiche. Ses sauts de
   ligne simples comptent (`pre-line`), et un mot sans espace ou une adresse collée passe à la
   ligne au lieu d'élargir la page (140 « x » d'accroche élargissaient la fiche à 1 458 px sur
   un écran de 344, 01/11/2026). */
.avis-texte,
.fiche-biographie p,
.fiche-accroche {
  margin: 0;
  max-width: var(--largeur-texte);
  white-space: pre-line;
  overflow-wrap: anywhere;
}

/* L'AVIS MIS EN AVANT, sous la carte de réservation (appel d'Abel du 25/10/2026) : la carte
   est étroite, l'avis s'y empile (qui, puis ce qui est dit) au lieu de ses deux colonnes. Un
   filet le sépare de ce qui précède, comme deux lignes d'avis. */
.avis-en-avant {
  display: grid;
  justify-items: start;
  gap: var(--espace-s);
  padding-top: var(--espace-m);
  border-top: var(--epaisseur-filet) solid var(--couleur-encre);
}

.avis-en-avant-titre {
  margin: 0;
  font-size: var(--taille-base);
  font-weight: var(--graisse-titre);
}

/* Même empilement dans le choix de l'expert (`/expert`), dont la colonne est celle d'un
   formulaire. */
.avis-en-avant .avis,
.avis-choix .avis {
  grid-template-columns: minmax(0, 1fr);
}

.avis-en-avant .avis {
  padding-block: var(--espace-s) 0;
}

/* Replié sur ses `--lignes-avis-en-avant` premières lignes, « Voir plus » dessous
   (29/10/2026) : la carte tient dans l'écran tant qu'on ne le déplie pas. */
.avis-en-avant-replie .avis-texte {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--lignes-avis-en-avant);
  line-clamp: var(--lignes-avis-en-avant);
  overflow: hidden;
}

/* Sur l'accueil, la section prend la réserve des sections en deux colonnes (`.section-duo,
   .accueil-avis`, avec l'accueil). */
.accueil-avis .avis-texte {
  font-size: var(--taille-m);
  line-height: var(--interligne-accroche);
}

@media (max-width: 48rem) {
  .avis {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---------- Les avis de l'accueil en bulles (demande d'Abel du 16/10/2026) ----------
   À gauche le cercle des auteurs, à droite la carte de l'avis choisi ; sur un écran étroit,
   le cercle puis la carte. Les bulles sont posées par js/avis-bulles.js, en pourcentages
   du cercle : elles grandissent et rétrécissent avec lui. */
.avis-scene {
  display: grid;
  grid-template-columns: minmax(0, var(--largeur-bulles-avis)) minmax(0, 1fr);
  align-items: center;
  gap: var(--espace-xl);
  margin-block: var(--espace-l);
}

.avis-bulles {
  position: relative;
  aspect-ratio: 1;
  border-radius: 50%;
}

.avis-bulle {
  position: absolute;
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  container-type: inline-size;
}

/* Le portrait cloné dans la bulle en prend toute la largeur : sa pastille mesure 100 % de
   lui, et lui 100 % de la bulle. */
.avis-bulle .avis-portrait {
  --taille-pastille: 100%;
  width: 100%;
  height: 100%;
}

/* ⚠️ UNE GOUTTE EN APESANTEUR, PAS UN CERCLE (demande d'Abel du 16/10/2026) : pas de contour
   noir, et un bord irrégulier, que le bloc de motion fait onduler. Sans mouvement, la goutte
   garde sa forme irrégulière. */
.avis-bulle .photo-pastille {
  font-size: 30cqi;
  border-radius: var(--goutte-a);
  box-shadow: none;
}

.avis-bulle:nth-child(3n + 2) .photo-pastille {
  border-radius: var(--goutte-b);
}

.avis-bulle:nth-child(3n) .photo-pastille {
  border-radius: var(--goutte-c);
}

/* La bulle choisie : un anneau bleu épais qui suit la goutte, et elle grossit un peu. Une
   forme, pas seulement une couleur. */
.avis-bulle[aria-pressed="true"] .photo-pastille {
  box-shadow: 0 0 0 var(--epaisseur-champ-faute) var(--couleur-accent);
}

/* Plus d'agrandissement : la bulle choisie dériverait hors de son cercle. */
.avis-bulle[aria-pressed="true"] {
  z-index: 1;
}

/* La carte : la ligne de l'avis choisi, seule visible, en grand. */
/* Sa bordure est bleue et deux fois plus épaisse que le contour des cartes (demande d'Abel
   du 16/10/2026). */
.avis-scene .avis {
  grid-template-columns: minmax(0, 1fr);
  padding: var(--espace-xl);
  border: calc(var(--epaisseur-contour) * 2) solid var(--couleur-accent);
  border-radius: var(--rayon-carte-grande);
  background: var(--couleur-fond);
}

.avis-scene .avis + .avis {
  border-top: calc(var(--epaisseur-contour) * 2) solid var(--couleur-accent);
}

.avis-scene .avis-liste .avis-portrait {
  --taille-pastille: var(--taille-portrait-carte-avis);
}

/* Le cercle puis la carte jusqu'à 64rem, et non 48 : sur une tablette, la carte à côté du cercle
   ne gardait que 82 px de texte (mesuré à 820 px, l'avis débordait de l'écran de 8 px). */
@media (max-width: 64rem) {
  .avis-scene {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
  }

  /* Le filet du cercle déborde des bulles d'un cran : la largeur le lui laisse. */
  .avis-bulles {
    width: min(calc(100% - var(--espace-m) * 2), var(--largeur-bulles-avis));
    margin-block: var(--espace-m);
  }

  .avis-scene .avis-liste {
    width: 100%;
  }

  .avis-scene .avis {
    padding: var(--espace-l);
  }
}

/* ============================================================
   LES ORBITES : la mécanique commune au voile de l'accueil « Le cercle » et aux orbites du
   hero de l'accueil. Une ronde, un disque sans trait posé sur une orbite, tourne et
   emporte ses portraits ; chaque portrait s'y pose par son angle (`cos`, `sin` du rayon) et
   tourne en sens inverse sur lui-même, à la même vitesse : son visage reste droit. L'orbite
   donne ses réglages : `--rayon-orbite`, `--taille-pastille`, `--angle-depart`,
   `--pas-orbite`, `--duree-orbite` et, pour tourner à l'envers, `--sens-orbite: reverse` et
   `--sens-portrait: normal`.
   ============================================================ */
.orbite-ronde {
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

.orbite-portrait,
.orbite-astre {
  --angle: var(--angle-depart);
  position: absolute;
  top: 50%;
  left: 50%;
  margin: calc(var(--taille-pastille) / -2);
  translate: calc(cos(var(--angle)) * var(--rayon-orbite)) calc(sin(var(--angle)) * var(--rayon-orbite));
}

.orbite-portrait:nth-child(2) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite));
}

.orbite-portrait:nth-child(3) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 2);
}

.orbite-portrait:nth-child(4) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 3);
}

.orbite-portrait:nth-child(5) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 4);
}

.orbite-portrait:nth-child(6) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 5);
}

.orbite-portrait:nth-child(7) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 6);
}

.orbite-portrait:nth-child(8) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 7);
}

.orbite-portrait:nth-child(9) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 8);
}

.orbite-portrait:nth-child(10) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 9);
}

.orbite-portrait:nth-child(11) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 10);
}

.orbite-portrait:nth-child(12) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 11);
}

@media (prefers-reduced-motion: no-preference) {
  .orbite-ronde {
    animation: tourne var(--duree-orbite) linear infinite var(--sens-orbite, normal);
  }

  .orbite-portrait,
  .orbite-astre {
    animation: tourne var(--duree-orbite) linear infinite var(--sens-portrait, reverse);
  }

  @keyframes tourne {
    to { rotate: 1turn; }
  }
}

/* ============================================================
   ORBITE, LA DIRECTION ARTISTIQUE (retenue le 25/10/2026, décision de Matthias)
   Le cercle qu'on rejoint, sur blanc : les experts gravitent autour du titre. Une seule
   couleur en plus de l'encre, la COULEUR PRINCIPALE (`--couleur-accent`, le bleu du pied de
   page, choisi par Abel le 01/11/2026) : elle colore les orbites, le point du logo et du
   titre, l'anneau des portraits, les boutons principaux, les liens et le pied de page.
   Bricolage Grotesque.
   Le `<html>` de chaque page porte `data-da="orbite"` en dur : les règles qui en dépendent
   restent préfixées par lui.
   ============================================================ */

/* Les pages d'état : un grand anneau de la couleur principale doublé d'un pointillé, immobile,
   décentré en bas à droite, et son point. */
:root[data-da="orbite"] .hero-etat::before {
  content: "";
  position: absolute;
  z-index: -1;
  right: var(--decor-etat-debord);
  bottom: var(--decor-etat-debord);
  width: var(--decor-etat);
  aspect-ratio: 1;
  border-radius: 50%;
  border: var(--epaisseur-glyphe) solid var(--couleur-ornement);
  outline: var(--pointille-etat) dotted var(--couleur-ornement);
  outline-offset: var(--espace-m);
}

:root[data-da="orbite"] .hero-etat::after {
  content: "";
  position: absolute;
  z-index: -1;
  right: calc(var(--decor-etat-debord) + var(--decor-etat) * 0.82);
  bottom: calc(var(--decor-etat-debord) + var(--decor-etat) * 0.82);
  width: var(--taille-anneau-etat);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--couleur-ornement);
  box-shadow: 0 0 0 var(--lisere-etat) var(--couleur-fond);
}

/* Les jetons d'Orbite, qui complètent le `:root` du haut (couleurs, police, boutons). */
:root {
  /* Un noir neutre, et non plus le noir teinté de vert d'Orbite (#0d1f1c) : il va avec
     n'importe quelle couleur principale (Matthias, 26/10/2026). */
  --couleur-encre: #111111;
  --couleur-clair: #f4f4f2;
  /* LA COULEUR DU SITE, CHOISIE PAR ABEL LE 01/11/2026 (« le même bleu pour le site, le bleu
     du footer ») : la valeur exacte que le pied de page affichait, mesurée dans le navigateur
     (`color(srgb 0.0467 0.102 0.2431)`). Le pied de page prend la couleur elle-même, comme le
     logo, les icônes, la carte de marque et les emails. */
  --couleur-accent: #0c1a3e;
  --couleur-ornement: var(--couleur-accent);
  --couleur-anneau-portrait: var(--couleur-accent);
  --police: "Bricolage Grotesque", system-ui, -apple-system, "Segoe UI", sans-serif;
  --graisse-hero: 600;
  --interlettrage-serre: -0.015em;
  --entete-trait: var(--epaisseur-filet);
  --bouton-principal-fond: var(--couleur-accent);
  --bouton-principal-texte: var(--couleur-fond);
  /* Le survol ÉCLAIRCIT : ce bleu-là est presque aussi sombre que l'encre, l'y mêler ne se
     voyait plus (#0d1835 contre #0c1a3e). Texte blanc à 9,1:1. */
  --bouton-principal-survol: color-mix(in srgb, var(--couleur-accent) 80%, var(--couleur-fond));
  --bouton-secondaire-trait: var(--trait-capsule);
  --panneau-fond: var(--couleur-clair);
  --panneau-texte: var(--couleur-encre);
}

/* Le header d'Orbite n'a pas de filet (Matthias, 25/10/2026 : pas de barre noire fine) : c'est
   une bande de verre blanc (translucide), et les orbites du hero passent dessous, floutées. Le fond est un
   pseudo-élément, pour que le volet du burger garde son propre flou. */
:root[data-da="orbite"] .site-header {
  --entete-trait: 0px;
  background: none;
}

:root[data-da="orbite"] .site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--verre-entete);
  backdrop-filter: var(--flou-entete);
}

/* LE HEADER DE L'ACCUEIL S'EFFACE DEVANT LA GALAXIE (appel d'Abel du 25/10/2026 : « il faut
   choisir sur quoi tu veux mettre l'attention » ; Matthias, 26/10/2026 : « il doit apparaître
   quand on passe ici », à « Ils décrochent »). Pour un visiteur, tant que le hero est à l'écran,
   seul le logo reste, plus petit et au bord gauche ; une fois le hero passé sous le header,
   la recherche, le burger et la bande translucide apparaissent et le logo reprend sa place et sa taille ; ils repartent quand
   on remonte dans le hero. Connecté, le header est toujours là (Abel, 25/10/2026 : « tu ne
   peux pas attendre qu'il scrolle »). js/entete-accueil.js pose `data-entete="ouvert"` ;
   l'indice d'un compte connu (js/amorce-compte.js) l'ouvre dès le premier rendu. Effacés par un
   découpage (`clip-path`),
   qui se replie vers le haut, et non par `visibility` : la recherche et le burger restent
   atteignables au clavier, et le focus qui y entre ouvre le header. Ouverts, ils gardent un
   découpage large, qui laisse passer l'anneau de focus : une transition demande deux valeurs
   de même nature. */
[data-page="accueil"] .site-header :is(.nav-recherche, .nav-toggle),
[data-page="accueil"] .site-header::before {
  clip-path: inset(var(--debord-decoupe-entete));
}

/* Ouverte, la recherche ne coupe rien sous elle : sa liste de suggestions (js/suggestions.js)
   y descend. */
[data-page="accueil"] .site-header .nav-recherche {
  clip-path: inset(var(--debord-decoupe-entete) var(--debord-decoupe-entete) var(--debord-suggestions) var(--debord-decoupe-entete));
}

:root:not([data-entete="ouvert"]):not([data-compte="connu"]) [data-page="accueil"] .site-header :is(.nav-recherche, .nav-toggle) {
  clip-path: inset(var(--debord-decoupe-entete) var(--debord-decoupe-entete) 100% var(--debord-decoupe-entete));
  translate: 0 calc(var(--espace-s) * -1);
  pointer-events: none;
}

:root:not([data-entete="ouvert"]):not([data-compte="connu"]) [data-page="accueil"] .site-header::before {
  clip-path: inset(0 0 100% 0);
}

/* Le logo d'arrivée : plus petit, au bord gauche de la fenêtre (Matthias, 26/10/2026) ; il glisse
   à sa place dans la colonne du header, et à sa taille, quand le header s'ouvre. Sur un écran
   plus étroit que le header, il est déjà au bord : il ne fait que grandir. */
:root:not([data-entete="ouvert"]):not([data-compte="connu"]) [data-page="accueil"] .nav-logo {
  translate: var(--entete-logo-decalage) 0;
  scale: var(--entete-logo-arrivee);
}

[data-page="accueil"] .nav-logo {
  transform-origin: left center;
}

@media (prefers-reduced-motion: no-preference) {
  [data-page="accueil"] .site-header :is(.nav-recherche, .nav-toggle, .nav-logo),
  [data-page="accueil"] .site-header::before {
    transition:
      clip-path var(--duree-entete) var(--courbe-eclosion),
      translate var(--duree-entete) var(--courbe-eclosion),
      scale var(--duree-entete) var(--courbe-eclosion);
  }
}

/* Le glyphe : une orbite d'encre au trait fin, et sa planète de la couleur principale. */
:root[data-da="orbite"] .marque-glyphe {
  border-width: var(--epaisseur-marqueur);
}

/* La carte « Rejoignez le cercle » : un panneau clair, son bouton de la couleur principale.
   Des cercles tracés dans deux coins (dessin de Matthias du 25/10/2026), derrière le texte et
   le bouton, coupés par les bords arrondis : en haut à gauche, un arc du grand cercle centré
   au-delà du coin ; en bas à droite, deux anneaux emboîtés centrés au-delà du coin. Ce sont
   des orbites, la mécanique du hero (`.decor-orbite`, rondes, contre-rotations), rondes et
   non aplaties, où tournent des portraits dessinés : un décor pur, sans bouton. La carte n'en
   montre qu'un morceau (un dixième de l'arc, un sixième des anneaux) : douze, huit et sept
   portraits également espacés, pour qu'il y en ait toujours un dans chaque coin, immobile
   ou non. Le texte et le bouton restent devant (rang -1 dans la carte isolée). */
:root[data-da="orbite"] .panneau-bleu {
  position: relative;
  isolation: isolate;
  overflow: clip;
}

.carte-orbites {
  --orbite-aplati: 1;
  --trait-orbite: var(--trait-carte-cercle);
  --taille-pastille: var(--carte-orbite-portrait);
  position: absolute;
  inset: 0;
  z-index: -1;
  isolation: isolate;
}

.carte-orbite-arc {
  --orbite-largeur: calc(var(--carte-arc-rayon) * 2);
  --orbite-x: var(--carte-arc-centre-x);
  --orbite-y: var(--carte-arc-centre-y);
  --angle-depart: 64deg;
  --pas-orbite: calc(1turn / 12);
  --duree-orbite: var(--duree-carte-arc);
}

.carte-orbite-anneau,
.carte-orbite-anneau-grand {
  --orbite-x: calc(100% + var(--carte-anneau-centre));
  --orbite-y: calc(100% + var(--carte-anneau-centre));
}

.carte-orbite-anneau {
  --orbite-largeur: calc(var(--carte-anneau-rayon) * 2);
  --angle-depart: 225deg;
  --pas-orbite: calc(1turn / 8);
  --duree-orbite: var(--duree-carte-anneau);
}

.carte-orbite-anneau-grand {
  --orbite-largeur: calc((var(--carte-anneau-rayon) + var(--carte-anneau-ecart)) * 2);
  --angle-depart: 205deg;
  --pas-orbite: calc(1turn / 7);
  --duree-orbite: var(--duree-carte-anneau-grand);
  --sens-orbite: reverse;
  --sens-portrait: normal;
}

:root[data-da="orbite"] .panneau-bleu .bouton-principal {
  color: var(--bouton-principal-texte);
  background: var(--bouton-principal-fond);
}

@media (hover: hover) {
  :root[data-da="orbite"] .panneau-bleu .bouton-principal:hover {
    background: var(--bouton-principal-survol);
  }
}

/* Le hero : une scène de nuit pleine largeur, le texte centré, et autour trois orbites au
   trait d'or où tournent des portraits dessinés. */
:root[data-da="orbite"] .hero-accueil {
  --hero-ecart-cta: var(--espace-xl);
}

/* ⚠️ TOUS LES PORTRAITS AU-DESSUS DE TOUS LES TRAITS (25/10/2026) : une orbite centrée par
   `translate` formait son propre contexte d'empilement, et le trait d'une orbite venue plus
   tard dans le HTML barrait les portraits des précédentes (un trait passait sur la photo
   d'Abel). L'orbite est donc centrée par `left` et `top` calculés, sans transformation ; son
   trait est un pseudo-élément au rang 0, ses points au rang 1, ses portraits au rang 2, et
   tous se rangent dans le contexte de `.decor-orbites` (`isolation`), qui reste sous le texte
   du hero. */
.decor-orbites {
  position: absolute;
  inset: 0;
  isolation: isolate;
}

.decor-orbite {
  --rayon-orbite: calc(var(--orbite-largeur) / 2);
  position: absolute;
  left: calc(var(--orbite-x, 50%) - var(--rayon-orbite));
  top: calc(var(--orbite-y, var(--orbites-centre-y)) - var(--orbite-largeur) * var(--orbite-aplati) / 2);
  width: var(--orbite-largeur);
  height: calc(var(--orbite-largeur) * var(--orbite-aplati));
}

.decor-orbite::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border: var(--trait-orbite) solid var(--couleur-ornement);
  border-radius: 50%;
}

.decor-orbite-1 {
  --orbite-largeur: var(--orbite-1-largeur);
  --orbite-aplati: var(--orbite-1-aplati);
  --taille-pastille: var(--orbite-1-portrait);
  --angle-depart: var(--orbite-1-depart);
  --pas-orbite: calc(1turn / 2);
  --duree-orbite: var(--duree-orbite-1);
}

.decor-orbite-2 {
  --orbite-largeur: var(--orbite-2-largeur);
  --orbite-aplati: var(--orbite-2-aplati);
  --taille-pastille: var(--orbite-2-portrait);
  --angle-depart: var(--orbite-2-depart);
  --pas-orbite: calc(1turn / 3);
  --duree-orbite: var(--duree-orbite-2);
  --sens-orbite: reverse;
  --sens-portrait: normal;
}

.decor-orbite-3 {
  --orbite-largeur: var(--orbite-3-largeur);
  --orbite-aplati: var(--orbite-3-aplati);
  --taille-pastille: var(--orbite-3-portrait);
  --angle-depart: var(--orbite-3-depart);
  --pas-orbite: calc(1turn / 3);
  --duree-orbite: var(--duree-orbite-3);
}

.orbite-plan {
  position: absolute;
  z-index: 2;
  left: 0;
  top: 50%;
  width: 100%;
  aspect-ratio: 1;
  translate: 0 -50%;
  scale: 1 var(--orbite-aplati);
}

.decor-orbite :is(.orbite-portrait, .orbite-astre) {
  scale: 1 calc(1 / var(--orbite-aplati));
}

.decor-orbites .photo-pastille {
  box-shadow: 0 0 0 var(--lisere-portrait) var(--couleur-ornement);
}

/* LES POINTS DE COULEUR (25/10/2026) : de petits disques pleins qui tournent avec leur orbite,
   dans un plan à eux, au rang 1, entre les traits et les portraits de toutes les orbites (sa
   ronde a la durée et le sens de celle des portraits, et démarre avec elle). Chacun est dans
   l'intervalle entre deux places de portrait (à une fraction irrégulière de cet
   intervalle, pour ne jamais tomber sur un visage), avec un halo du fond qui les détache du
   trait. Leur taille et leur teinte se lisent dans leurs classes. */
.orbite-plan-astres {
  z-index: 1;
}

.orbite-astre {
  --taille-pastille: var(--taille-astre);
  width: var(--taille-astre);
  height: var(--taille-astre);
  border-radius: 50%;
  background: var(--fond-astre);
  box-shadow: 0 0 0 calc(var(--taille-astre) * 0.3) var(--couleur-fond);
}

.orbite-astre:nth-child(1) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 0.5);
}

.orbite-astre:nth-child(2) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 1.32);
}

.orbite-astre:nth-child(3) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 2.66);
}

.orbite-astre:nth-child(4) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 3.4);
}

.orbite-astre:nth-child(5) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 4.62);
}

.astre-minuscule {
  --taille-astre: var(--astre-minuscule);
}

.astre-petit {
  --taille-astre: var(--astre-petit);
}

.astre-moyen {
  --taille-astre: var(--astre-moyen);
}

.astre-grand {
  --taille-astre: var(--astre-grand);
}

.astre-tres-grand {
  --taille-astre: var(--astre-tres-grand);
}

.astre-accent {
  --fond-astre: var(--couleur-accent);
}

.astre-claire {
  --fond-astre: var(--teinte-astre-claire);
}

.astre-tres-claire {
  --fond-astre: var(--teinte-astre-tres-claire);
}

.astre-foncee {
  --fond-astre: var(--teinte-astre-foncee);
}

.astre-encre {
  --fond-astre: var(--couleur-encre);
}

/* LES ORBITES DE LA FICHE PUBLIQUE (Matthias, 30/10/2026, puis le long du header le 01/11/2026 :
   dans la marge gauche, elles attiraient l'œil à côté de la lecture). Deux orbites concentriques
   et leurs points, plus larges que la fenêtre, aplaties, centrées au-dessus de la page : on n'en
   voit que le bas, qui entre par le coin haut gauche, passe sous la bande du header et descend
   un peu sous lui au milieu (`--fiche-orbite-bas`), puis ressort par le coin haut droit. Le
   cadre les coupe à sa hauteur (`overflow: clip`, sans défilement) ; il est sous le header
   (rang 3) et ne touche jamais la fiche. */
.fiche-orbites {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: calc(var(--fiche-orbite-bas) + var(--astre-tres-grand));
  overflow: clip;
  pointer-events: none;
  isolation: isolate;
}

/* La fiche commence assez bas pour que l'orbite passe entre le header et elle. */
.page-fiche .colonne {
  padding-top: var(--fiche-haut);
}

.fiche-orbite {
  --trait-orbite: var(--trait-fiche-orbite);
  --orbite-aplati: var(--fiche-orbite-aplati);
  --orbite-largeur: var(--fiche-orbite-largeur);
  --orbite-y: calc(var(--fiche-orbite-bas) - var(--fiche-orbite-largeur) * var(--fiche-orbite-aplati) / 2);
  --angle-depart: 70deg;
  --pas-orbite: calc(1turn / 12);
  --duree-orbite: var(--duree-fiche-orbite);
}

/* Douze points par orbite (Matthias, 01/11/2026 : « mets plus de boules ») : les cinq premiers
   gardent les places de l'accueil, les sept suivants poursuivent le tour, toujours à une
   fraction irrégulière de l'intervalle, pour que le rythme ne se lise pas. */
.fiche-orbite .orbite-astre:nth-child(6) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 5.25);
}

.fiche-orbite .orbite-astre:nth-child(7) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 6.4);
}

.fiche-orbite .orbite-astre:nth-child(8) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 7.1);
}

.fiche-orbite .orbite-astre:nth-child(9) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 7.85);
}

.fiche-orbite .orbite-astre:nth-child(10) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 9.3);
}

.fiche-orbite .orbite-astre:nth-child(11) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 10.05);
}

.fiche-orbite .orbite-astre:nth-child(12) {
  --angle: calc(var(--angle-depart) + var(--pas-orbite) * 11.5);
}

.fiche-orbite-interieure {
  --orbite-largeur: calc(var(--fiche-orbite-largeur) - var(--fiche-orbite-ecart) * 2);
  --angle-depart: 15deg;
  --duree-orbite: var(--duree-fiche-orbite-interieure);
  --sens-orbite: reverse;
  --sens-portrait: normal;
}

/* LES PORTRAITS SONT DES EXPERTS (25/10/2026, js/orbite-experts.js) : chacun est un bouton qui
   ouvre sa carte condensée. Les dessins du HTML attendent la réponse de l'annuaire pour se
   montrer (ou rester un décor si elle ne vient pas) : un visage n'en remplace pas un autre
   sous les yeux. Un expert réel prend le portrait des plus grands. Sa cible déborde le disque
   d'un quart d'espace. Son orbite ralentit jusqu'à l'arrêt au focus et tant que sa carte est
   ouverte (au survol, js/orbite-experts.js fait varier la vitesse de ses animations). */
.decor-orbites:not(.orbites-pretes) .orbite-portrait {
  visibility: hidden;
}

.orbite-expert {
  width: var(--taille-pastille);
  height: var(--taille-pastille);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  font: inherit;
  cursor: pointer;
  pointer-events: auto;
}

.orbite-expert::after {
  content: "";
  position: absolute;
  inset: calc(var(--espace-xs) * -1);
  border-radius: 50%;
}

.orbite-expert-reel {
  --taille-pastille: var(--orbite-vedette);
}

/* LA CARTE CONDENSÉE : un panneau blanc au trait d'encre, comme le volet du burger, posé près
   du portrait (`--carte-x`, `--carte-y`, écrits par le script) ; sur téléphone, fixé en bas
   de l'écran, dans la gouttière. */
/* L'INVITATION À CRÉER SON COMPTE (js/invitation-compte.js) : un panneau du fond au trait de
   l'encre, au centre, sur un voile clair qui laisse voir la page derrière. */
.invitation {
  width: min(100% - var(--gouttiere-shell) * 2, var(--largeur-invitation));
  padding: var(--espace-l);
  border: 0;
  border-radius: var(--rayon-carte);
  color: var(--couleur-texte);
  background: var(--couleur-fond);
  box-shadow: var(--trait-capsule);
}

.invitation::backdrop {
  background: var(--verre-voile);
}

.invitation-titre {
  margin: 0 0 var(--espace-s);
  font-size: var(--taille-l);
}

.invitation-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-m);
  margin-top: var(--espace-l);
}

/* LES FENÊTRES (`.fenetre`) : celle de l'invitation, plus large, haute au plus de la fenêtre du
   navigateur et défilante. Deux s'en servent : « Devenir expert » (js/fenetre-expert.js), qui porte
   le guide de `/devenir-expert` sur une seule colonne, et la vidéo d'un expert sur sa fiche
   (feature 31, run B1). Le bouton « Fermer » colle en haut à droite pendant le défilement. */
.fenetre {
  width: min(100% - var(--gouttiere-shell) * 2, var(--largeur-fenetre));
  max-height: calc(100dvh - var(--espace-xl) * 2);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Elle porte aussi `.guide`, pour les étapes et la section du guide ; sur une colonne, et
   sans la tête collée sous le header, qui n'existe pas dans une fenêtre. */
.fenetre-expert .section-duo {
  grid-template-columns: minmax(0, 1fr);
  gap: var(--espace-l);
}

.fenetre-expert .section-duo-tete {
  position: static;
}

/* Dans la largeur d'une fenêtre, les titres d'étape reprennent la taille de ceux de l'accueil :
   ceux du guide en page (« de gros textes ») dépassaient son titre. */
.fenetre-expert .etape {
  --taille-titre-etape: var(--taille-xl);
}

@media (max-width: 48rem) {
  .fenetre {
    padding: var(--espace-m);
  }
}

/* La fenêtre de la vidéo d'un expert, sur sa fiche (feature 31, run B1) : une pile, le bouton
   « Fermer » en tête à droite. `display` sur l'état ouvert seulement (PIEGES.md E23). */
.fenetre-video[open] {
  display: grid;
  gap: var(--espace-m);
}

.fenetre-video .fenetre-fermer {
  justify-self: end;
}

.fenetre-fermer {
  position: sticky;
  top: 0;
  z-index: 1;
  float: right;
  background: var(--couleur-fond);
}

.orbite-carte {
  position: absolute;
  left: var(--carte-x, 0);
  top: var(--carte-y, 0);
  z-index: 3;
  display: grid;
  gap: var(--espace-s);
  width: var(--largeur-orbite-carte);
  padding: var(--espace-m);
  border-radius: var(--rayon-carte);
  color: var(--couleur-texte);
  background: var(--couleur-fond);
  box-shadow: var(--trait-capsule);
  scroll-margin: var(--marge-orbite-carte);
  text-align: start;
}

.orbite-carte:focus-visible {
  outline-offset: var(--espace-xs);
}

.orbite-carte-fermer {
  position: absolute;
  top: var(--espace-s);
  right: var(--espace-s);
  display: inline-grid;
  place-items: center;
  width: var(--hauteur-lien-compte);
  height: var(--hauteur-lien-compte);
  padding: 0;
  border: 0;
  border-radius: 50%;
  color: var(--couleur-encre);
  background: none;
  cursor: pointer;
}

.orbite-carte-tete {
  display: flex;
  align-items: center;
  gap: var(--espace-m);
  padding-inline-end: var(--hauteur-lien-compte);
}

.orbite-carte-portrait {
  --taille-pastille: var(--taille-portrait-orbite-carte);
  flex: none;
}

.orbite-carte-portrait .photo-pastille {
  font-size: var(--taille-s);
}

.orbite-carte .etiquette-exemple {
  margin-bottom: var(--espace-xs);
  padding-block: var(--espace-xs);
  font-size: var(--taille-xs);
}

.orbite-carte-nom {
  margin: 0;
  font-size: var(--taille-base);
  font-weight: var(--graisse-titre);
}

.orbite-carte-domaines,
.orbite-carte-langues {
  margin: 0;
  font-size: var(--taille-xs);
}

.orbite-carte-prix {
  margin: var(--espace-xs) 0 0;
  font-size: var(--taille-base);
}

.orbite-carte .moyenne {
  margin: 0;
}

.orbite-carte-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-s);
  margin-top: var(--espace-xs);
}

.orbite-carte-actions .bouton {
  flex: 1;
  min-height: var(--hauteur-lien);
  padding-inline: var(--espace-m);
  font-size: var(--taille-s);
  white-space: nowrap;
}

@media (max-width: 48rem) {
  .orbite-carte {
    position: fixed;
    inset: auto var(--gouttiere-shell) var(--gouttiere-shell);
    width: auto;
  }
}

/* Entre 48 et 80rem, les orbites suivent la largeur de la fenêtre, moins aplaties, toujours
   emboîtées : la plus petite entoure le titre, l'accroche et les boutons.
   ⚠️ `48.0625rem` ET NON `48rem` : à 768 px pile (iPad mini en portrait), le hero est encore
   celui du téléphone (`max-width: 48rem`), et ces orbites-ci, faites pour le hero de la
   tablette, y passaient sur le titre et sur « Ils décrochent » (01/11/2026). */
@media (min-width: 48.0625rem) and (max-width: 80rem) {
  :root {
    --orbite-1-largeur: 120vw;
    --orbite-1-aplati: 0.45;
    --orbite-2-largeur: 150vw;
    --orbite-2-aplati: 0.45;
    --orbite-3-largeur: 180vw;
    --orbite-3-aplati: 0.45;
    /* La carte « Rejoignez le cercle » y est plus basse : ses anneaux, plus petits, ne
       touchent pas l'accroche. */
    --carte-anneau-rayon: 6.5rem;
    --carte-anneau-ecart: 4rem;
  }
}

/* Une tablette en portrait (jusqu'à 60rem, 820 et 884 px mesurés) : le titre, l'accroche et les
   boutons y sont hauts pour la largeur, et la plus petite orbite à 0,45 coupait « Comment ça
   marche ». Elles s'arrondissent, toujours ensemble. */
@media (min-width: 48.0625rem) and (max-width: 60rem) {
  :root {
    --orbite-1-aplati: 0.52;
    --orbite-2-aplati: 0.52;
    --orbite-3-aplati: 0.52;
  }
}

/* Le portrait : un anneau de la couleur principale (l'ornement), détaché de la photo par un
   liseré blanc. */
:root[data-da="orbite"] .photo-pastille {
  box-shadow:
    0 0 0 var(--lisere-portrait) var(--couleur-fond),
    0 0 0 calc(var(--lisere-portrait) + var(--anneau-portrait)) var(--couleur-ornement);
}

/* ============================================================
   LE VOILE DE L'ACCUEIL (« Le cercle », validé par Abel à l'appel du 01/11/2026 ; né des pages
   d'arrivée à l'essai du 22/10/2026, redessinées le 25/10/2026)
   Une fenêtre posée sur l'accueil, sur blanc, une fois par session : js/amorce-arrivee.js dit qui
   la voit et l'estampe avant le premier rendu ; js/arrivee.js tient la scène et la sortie. Tant
   que `data-arrivee` est sur `<html>`, tout le reste de la page est masqué (`visibility` et non
   `display`, pour que sa mise en page ne bouge pas) et ne défile pas ; masqué, il sort aussi du
   parcours au clavier : le lien « Entrer » est le premier Tab, et Échap fait comme le clic. Tout
   ce qui est coloré prend la couleur principale (`--couleur-accent`).
   ============================================================ */
html[data-arrivee] {
  overflow: hidden;
}

html[data-arrivee] body > :not(.arrivee) {
  visibility: hidden;
}

/* La fenêtre entière, au-dessus de la page. `overflow: clip` : le point qui grandit dépasse de
   loin la fenêtre, et ne doit faire apparaître aucune barre de défilement le temps de
   l'animation. */
.arrivee {
  position: fixed;
  inset: 0;
  isolation: isolate;
  overflow: clip;
  padding: var(--arrivee-ecart) var(--gouttiere-arrivee);
  text-align: center;
  background: var(--couleur-fond);
}

.arrivee p {
  margin: 0;
}

/* LE SYSTÈME SOLAIRE VU DE BIAIS (appel d'Abel du 25/10/2026 : « une cohérence à retrouver » ;
   Matthias, 26/10/2026 : « un aperçu du système solaire, les orbites plus proches passent
   devant »). L'anneau est le soleil, au centre ; trois orbites emboîtées, du même aplatissement
   et de la même inclinaison, ne se croisent jamais. Chacune existe en deux exemplaires, coupés à
   mi-hauteur de l'orbite (dans son plan, donc le long de son grand axe) : la moitié éloignée
   (`.arrivee-plan`, avant l'anneau dans le HTML) passe derrière le soleil, la moitié proche
   (`.arrivee-plan-avant`, copie posée après l'anneau par js/arrivee.js et calée sur le même
   instant) passe devant. Un portrait qui franchit la coupe est dessiné moitié par l'un, moitié
   par l'autre : il reste entier. La découpe déborde d'un portrait sur les bords extérieurs. Les
   plus proches tournent plus vite. Chacune trace son trait (`::before`) sous ses points et ses
   portraits ; un visage reste droit par la rotation inverse de l'inclinaison, appliquée en
   premier (`transform`). */
.arrivee-plan {
  clip-path: inset(calc(var(--arrivee-portrait) * -1) calc(var(--arrivee-portrait) * -1) 50%);
  --orbite-x: 50%;
  --orbite-y: 50%;
  --orbite-largeur: calc(var(--arrivee-scene) * var(--arrivee-plan-largeur));
  --orbite-aplati: var(--arrivee-plan-aplati);
  --taille-pastille: var(--arrivee-portrait);
  rotate: calc(var(--arrivee-inclinaison) * -1);
}

.arrivee-plan-avant {
  clip-path: inset(50% calc(var(--arrivee-portrait) * -1) calc(var(--arrivee-portrait) * -1));
}

.arrivee-plan .orbite-portrait {
  transform: rotate(var(--arrivee-inclinaison));
}

/* Le visage d'un expert vérifié dont la fiche montre une vidéo (feature 31, run B1) : son image et
   le point de Cercles, en décor, dans une boîte à la taille de la pastille (js/arrivee.js). */
.arrivee-visage {
  width: var(--taille-pastille);
  height: var(--taille-pastille);
}

.arrivee-plan-1 {
  --arrivee-plan-largeur: var(--arrivee-largeur-plan-1);
  --angle-depart: 35deg;
  --pas-orbite: calc(1turn / 3);
  --duree-orbite: var(--duree-arrivee-plan-1);
}

.arrivee-plan-2 {
  --arrivee-plan-largeur: var(--arrivee-largeur-plan-2);
  --angle-depart: 190deg;
  --pas-orbite: calc(1turn / 4);
  --duree-orbite: var(--duree-arrivee-plan-2);
  --sens-orbite: reverse;
  --sens-portrait: normal;
}

.arrivee-plan-3 {
  --arrivee-plan-largeur: var(--arrivee-largeur-plan-3);
  --angle-depart: 80deg;
  --pas-orbite: calc(1turn / 5);
  --duree-orbite: var(--duree-arrivee-plan-3);
}

/* Sur téléphone, la scène est bornée par la largeur et la hauteur ne manque pas : tout le plan
   tient dans l'écran (Matthias, 01/11/2026 : les portraits coupés sur les bords). La plus
   grande orbite, inclinée et avec ses portraits, ne déborde que dans la gouttière ; le plan se
   redresse (0,75) pour occuper la hauteur entre le titre et la phrase. L'anneau et les portraits
   rapetissent un peu pour garder un portrait d'écart entre deux orbites voisines. */
@media (max-width: 48rem) {
  :root {
    --arrivee-part-cercle: 0.38;
    --arrivee-portrait: calc(var(--arrivee-scene) * 0.08);
    --arrivee-largeur-plan-1: 0.6;
    --arrivee-largeur-plan-2: 0.76;
    --arrivee-largeur-plan-3: 0.92;
    --arrivee-plan-aplati: 0.75;
  }
}

/* Un téléphone en paysage (568 × 320) manque de hauteur : la colonne du voile mesure 338 px
   sans ses marges, et le titre et la phrase y étaient rognés de 9 px. Même colonne, même
   composition, un rythme resserré : les marges et les écarts passent de 2rem à 1rem, le titre
   peut descendre à 1,5rem et la scène à 8rem ; la formule de `--arrivee-scene` rend à la scène
   ce qui reste de hauteur. Au-delà de 26,25rem, rien ne change. */
@media (max-height: 26.25rem) {
  :root {
    --arrivee-titre-min: 1.5rem;
    --arrivee-ecart: var(--espace-m);
    --arrivee-scene-min: 8rem;
  }
}

/* Le titre, la porte, la phrase : une colonne centrée dans la fenêtre. */
.arrivee-une {
  display: grid;
  align-content: center;
  justify-items: center;
  row-gap: var(--arrivee-ecart);
  padding-bottom: var(--arrivee-bas);
}

.arrivee-titre {
  margin: 0;
  font-size: var(--arrivee-titre);
  font-weight: var(--graisse-hero);
  letter-spacing: var(--interlettrage-serre);
  line-height: var(--interligne-hero);
}

/* Une ligne par moitié de la phrase, quelle que soit la largeur. */
.arrivee-ligne {
  display: block;
}

/* Le lien est un disque : son anneau de focus fait le tour de la scène. La scène et le mot
   « Entrer » partagent la même case, le mot au centre de l'anneau. */
.arrivee-cercle {
  display: grid;
  place-items: center;
  padding: var(--espace-s);
  border-radius: 50%;
  color: inherit;
  text-decoration: none;
}

.arrivee-cercle > *,
.arrivee-scene > * {
  grid-area: 1 / 1;
}

.arrivee-scene {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--arrivee-scene);
  height: var(--arrivee-scene);
}

/* L'anneau est un contour rentré, pas une bordure : le point se place par rapport au bord
   extérieur de l'anneau, comme dans le logo. Venu après les orbites, il passe devant elles,
   et son point couvre tout quand il grandit. */
.arrivee-anneau {
  position: relative;
  width: var(--arrivee-cercle);
  height: var(--arrivee-cercle);
  border-radius: 50%;
  box-shadow: inset 0 0 0 var(--arrivee-trait) var(--couleur-encre);
}

/* La planète du logo, de la couleur principale, son halo blanc ouvre l'anneau. */
.arrivee-point {
  position: absolute;
  top: calc(var(--arrivee-point-place) - var(--arrivee-point) / 2);
  right: calc(var(--arrivee-point-place) - var(--arrivee-point) / 2);
  width: var(--arrivee-point);
  height: var(--arrivee-point);
  border-radius: 50%;
  background: var(--couleur-accent);
  box-shadow: 0 0 0 var(--arrivee-halo) var(--couleur-fond);
}

/* « Entrer » au centre de l'anneau, de la couleur principale : c'est l'action de la page. */
.arrivee-entrer {
  position: relative;
  font-size: var(--arrivee-taille-entrer);
  font-weight: var(--graisse-titre);
  color: var(--couleur-accent);
}

.arrivee-phrase {
  font-size: var(--taille-m);
  line-height: var(--interligne-accroche);
}

/* Le survol et le focus se disent par la FORME : l'anneau grossit, et son trait d'encre gagne
   les pixels du bord (PIEGES.md E71). Le survol n'existe qu'à la souris (E72) ; le focus, lui,
   reste dehors. */
.arrivee-cercle:focus-visible .arrivee-anneau {
  scale: var(--arrivee-survol-cercle);
}

@media (hover: hover) {
  .arrivee-cercle:hover .arrivee-anneau {
    scale: var(--arrivee-survol-cercle);
  }
}

.arrivee-cercle.ouvre .arrivee-point {
  scale: var(--arrivee-ouverture-point);
}

/* On entre : l'anneau passe au-dessus des moitiés proches des orbites, posées après lui dans
   le HTML, pour que son point qui grandit les couvre aussi. */
.arrivee-cercle.ouvre .arrivee-anneau {
  z-index: 1;
}

/* ---------- La sortie : ce qui disparaît quand on entre ----------
   Sans opacité : le titre, la phrase et le mot « Entrer » disparaissent d'un coup, au clic ; le
   point couvre le reste, puis le voile se lève (js/arrivee.js). */
.arrivee-sortie > .arrivee-titre,
.arrivee-sortie .arrivee-phrase,
.ouvre .arrivee-entrer {
  visibility: hidden;
}

@media (prefers-reduced-motion: no-preference) {
  .arrivee-anneau {
    transition: scale var(--duree-courte) var(--courbe);
  }

  .arrivee-point {
    transition: scale var(--duree-arrivee) var(--courbe-arrivee);
  }

  /* L'entrée en scène : les deux lignes du titre montent en se découvrant, puis l'anneau,
     les trois orbites éclosent du centre, de la plus proche à la plus large, puis « Entrer » et la phrase.
     Chaque entrée ne remplit que son attente (`backwards`). */
  .arrivee-ligne,
  .arrivee-entrer,
  .arrivee-phrase {
    animation: arrivee-revele var(--duree-eclosion) var(--courbe-eclosion) backwards;
  }

  .arrivee-ligne + .arrivee-ligne {
    animation-delay: var(--arrivee-cadence);
  }

  .arrivee-entrer,
  .arrivee-phrase {
    animation-delay: calc(var(--arrivee-cadence) * 6);
  }

  /* Ce qui tourne : l'anneau et son point ; les rondes des trois orbites. js/arrivee.js
     reconnaît ces rotations à leur nom (`tourne`). */
  .arrivee-anneau {
    animation:
      arrivee-eclot var(--duree-eclosion) var(--courbe-eclosion) calc(var(--arrivee-cadence) * 2) backwards,
      tourne var(--duree-tour-anneau) linear infinite;
  }

  .arrivee-plan-1 {
    animation: arrivee-eclot var(--duree-eclosion) var(--courbe-eclosion) calc(var(--arrivee-cadence) * 3) backwards;
  }

  .arrivee-plan-2 {
    animation: arrivee-eclot var(--duree-eclosion) var(--courbe-eclosion) calc(var(--arrivee-cadence) * 4) backwards;
  }

  .arrivee-plan-3 {
    animation: arrivee-eclot var(--duree-eclosion) var(--courbe-eclosion) calc(var(--arrivee-cadence) * 5) backwards;
  }

  /* On entre : l'anneau s'arrête, le point grandit de là où il est. */
  .ouvre .arrivee-anneau {
    animation-play-state: paused;
  }

  @keyframes arrivee-revele {
    from {
      clip-path: inset(100% calc(var(--arrivee-debord-decoupe) * -1) calc(var(--arrivee-debord-decoupe) * -1));
      translate: 0 var(--arrivee-montee);
    }
    to {
      clip-path: inset(calc(var(--arrivee-debord-decoupe) * -1));
      translate: 0 0;
    }
  }

  @keyframes arrivee-eclot {
    from { scale: 0; }
  }
}

/* ============================================================
   LE MARQUEUR « VOUS ÊTES ICI » : L'INVERSION (DESIGN.md §4)
   Un seul pour toute l'application : entrée de navigation courante, onglet actif,
   filtre courant, durée choisie, jour, créneau, case cochée. Sur blanc, l'élément
   choisi passe en noir plein à texte blanc. Jamais de filet à gauche, jamais de
   contour ajouté : rien ne décale un voisin.

   ⚠️ CETTE SECTION RESTE LA DERNIÈRE DE LA FEUILLE (PIEGES.md E27). Le marqueur doit
   avoir le dernier mot sur le fond et la couleur de ce qu'il marque, et il a la
   spécificité d'une classe : écrit en tête avec les composants communs, il était battu
   par la règle de base de chaque composant venu après lui (`.nav-lien`, `.choix`), et
   l'entrée courante du header sortait en texte noir sur fond noir. Une seule exception,
   voulue et tenue par la spécificité : le bouton « Se connecter » du header, sur
   `/connexion`, reste la capsule noire qu'il est déjà.
   ⚠️ ET IL NE SE DÉFAIT PAS AU SURVOL : chaque survol de composant qui peut croiser un
   élément choisi (`.nav-lien`, `.filtre`, `button.choix`, `.segment`, `.bouton-danger`)
   l'exclut par un `:not()`, sans quoi son bleu donnerait un texte bleu sur fond noir.
   ============================================================ */
[aria-current="page"],
[aria-current="true"],
.choix:has(:checked),
.segment[aria-pressed="true"] {
  background: var(--marqueur-fond);
  color: var(--couleur-fond);
  box-shadow: none;
}
