/* =========================================================================
   site.css - Home « Jardin intérieur » · Aurélie Rey
   À charger APRÈS tokens.css + base.css. Tout est scopé .psy-.
   Réutilise intégralement les tokens (aucun hex/valeur en dur hors nuances
   déjà actées dans le proto).

   Plus aucune fleur illustrée sur le site (décision Thomas, 2026-09-03) :
   le lotus (retiré le 2026-09-01), puis le tournesol du hero et la pivoine
   de la section « avancer » qui l'avaient brièvement remplacé, ont tous été
   retirés. Le hero repose désormais sur la typo + un reveal générique
   (cf. §3 et site.js §5).

   La section « avancer » elle-même (pré-CTA sombre « Grandir, se
   construire ») a été retirée le 2026-09-13 à la demande d'Aurélie. Avec
   elle disparaissent le SEUL fond sombre de la page entre le hero et le
   footer, et donc la variante sombre du champ de pollen (.psy-pollen
   .is-dark) et l'IntersectionObserver qui la pilotait.

   PROTOTYPE D'ARCHITECTURE (DESIGNER, validé par Thomas le 2026-09-27) :
   ses 17 recompositions sont FONDUES dans les sections ci-dessous (pas de
   feuille additionnelle), repérées dans les commentaires par « prototype
   d'architecture #n ». Grilles asymétriques, numéros et chiffres tirés du
   texte, exergues des mots d'Aurélie, alternance, éléments collants.

   SOMMAIRE
     0. Reveals au scroll (mécanique commune) + finition prose (justify/hyphens)
     1. Header / nav (sticky + hamburger + LOGO image)
     2. Boutons (psy-btn)
     3. HERO (typo + reveal, sans fleur)
        3b. Champ de pollen global sticky (.psy-pollen, position: fixed,
            visible hero → footer, réactif à la vélocité de scroll)
        3c. Filigranes de section (.psy-filigrane) : l'overline repris en très
            grand + flouté, À CHEVAL sur la couture entre 2 sections, bord à
            bord du viewport en ALTERNANT gauche / droite, et MODULÉ AU SCROLL
            (view-timeline native, avec repli statique)
     4. « Qui suis-je » (À propos) : portrait collant + chiffre clé,
        chapeau, et le composant EXERGUE (.psy-exergue, partagé avec le §5)
     5. « Comment je vous accompagne » (Approche : titre et texte en regard
        dès 1024 px ; 2 piliers en bandes alternées crème/ivoire, en
        DIPTYQUE dès 1024 px). Numéro de section conservé, mais dans la
        PAGE elle vient désormais après les quatre sections du §7
        (déplacement du 2026-09-26).
     6. Nuage de mots-clés « Ce qui vous amène ici » (.psy-motscles).
        N'est plus une section depuis le 2026-09-26 : le nuage vit DANS
        « Pour qui » (§7), après le sommaire des portes (en deux colonnes
        dès 1024 px). Les pastilles
        sont des BULLES : matière translucide + TROIS couches de mouvement
        (flottement, parallaxe au scroll du nuage entier, survol
        grossissant/poussant, déclenché par un vrai mouvement de souris).
        Reflet mobile retiré le 2026-09-27 (passe perf). Lire impérativement le pavé « ARCHITECTURE
        DES COUCHES DE TRANSFORMATION » en tête de §6 avant d'y toucher.
        Partie JS de la poussée : site.js §2ter.
     7. « Pour qui » : chapeau + le SOMMAIRE (quatre portes numérotées,
        en grille dès 768 px) + nuage (§6, APRÈS les portes) + les QUATRE SECTIONS
        D'ACCOMPAGNEMENT qu'il dessert (.psy-public : Adultes, Enfants &
        Adolescents, Consultation Familiale, Approche groupale). Remplace
        l'accordéon 5 panneaux <details>/<summary> démonté le 2026-09-15.
     8. Diplômes & formations (liste chronologique, en-tête collant)
     9. Contact & infos pratiques (colonne « venir au cabinet » collante)
    10. Footer (dont lien de la page en cours, aria-current)
        10b. Pages légales (.psy-legal : mentions-legales.html,
             politique-de-confidentialite.html) : colonne de lecture,
             tableaux empilés sur mobile, emplacements à compléter
    11. prefers-reduced-motion  ← TOUJOURS EN DERNIER
   ========================================================================= */

/* =========================================================================
   0. REVEALS AU SCROLL - état initial, révélé via .is-in (ajouté par JS).
   Soft-skill : fade + translateY + BLUR léger qui se résout.
   UN SEUL MOTEUR depuis le 2026-09-26 (audit DESIGNER #2) : CETTE
   transition. site.js §5 ne fait que poser .is-in (IntersectionObserver) et,
   pour la cascade, --reveal-delay. GSAP, qui réécrivait les mêmes propriétés
   en inline à chaque image et relançait donc cette transition en boucle
   (apparition mesurée à ~2,3 s au lieu de 1,1 s), a été retiré.
   Durée --dur-reveal (1100ms) + easing --ease-eclosion. En reduced-motion ou
   sans JS : contenu visible, sans blur (cf. §11 et fallback no-js).
   ========================================================================= */
.psy [data-reveal] {
  opacity: 0;
  /* 22px -> 28px (2026-09-04) : dans la fourchette documentée par le design
     system (§4, "translateY 24-32px"), l'ancienne valeur était en dessous.
     Rend la montée plus perceptible sans devenir un mouvement large. */
  transform: translateY(28px);
  /* 6px -> 8px : le flou de départ se voit un peu mieux à la résolution,
     toujours "léger" (cf. retour Thomas : reveal existant jugé trop discret). */
  filter: blur(8px);
  transition: opacity var(--dur-reveal) var(--ease-eclosion),
              transform var(--dur-reveal) var(--ease-eclosion),
              filter var(--dur-reveal) var(--ease-eclosion);
  transition-delay: var(--reveal-delay, 0ms);
  /* Pas de will-change ici : posé en permanence sur les 46 blocs, il
     promouvait ~59 calques dès le chargement. site.js §5 le pose juste avant
     l'apparition et le retire à la fin de la transition. */
}
.psy [data-reveal].is-in {
  opacity: 1;
  transform: none;
  filter: none;
}

/* Texte réservé aux lecteurs d'écran (motif standard « visually hidden »).
   Premier usage : le « n sur 4 » des surtitres des publics (§7b, #12). */
.psy-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Ancres : les cibles s'arrêtent SOUS le header sticky, pas derrière lui.
   (Lenis compense déjà en JS ; ceci couvre le scroll natif, :target,
   reduced-motion et le cas libs absentes.) */
#hero-contenu,
#a-propos,
#approche,
#pour-qui,
#adultes,
#enfants-adolescents,
#consultation-familiale,
#approche-groupale,
#contact {
  scroll-margin-top: calc(var(--header-h) + var(--space-sm));
}

/* Finition prose (retour Aurélie 2026-09-04) : paragraphes de contenu NON
   centrés justifiés des deux côtés ("ça fait net"), avec césure pour éviter
   les rivières de blancs sur une colonne de mesure modeste. `hyphens: auto`
   s'appuie sur `lang="fr"` (posé sur <html>, cf. index.html). Les blocs déjà
   centrés (.psy-pourqui__motscles, .psy-section-head,
   têtes de section, etc.) ne sont volontairement PAS concernés : lignes
   centrées + justifiées ensemble ne veut rien dire. `text-wrap: pretty`
   évite en plus les lignes veuves (les .t-lead en sont déjà couverts
   globalement dans base.css). Uniquement des paragraphes de prose : jamais
   sur les listes (mots-clés, diplômes, contact), libellés de bouton ou
   overlines, qui restent courts par nature. */
.psy-hero__accroche,
.psy-apropos__text p,
.psy-approche__lead,
.psy-pilier__chapeau,
.psy-pilier__point-texte p,
.psy-public__accroche,
.psy-public__volet > p,
.psy-public__texte > p,
.psy-public__sous > p,
.psy-contact__note,
.psy-contact__secret,
.psy-contact__urgence {
  text-align: justify;
  -webkit-hyphens: auto;
  hyphens: auto;
  text-wrap: pretty;
}

/* SOUS 768 PX : PLUS DE JUSTIFICATION (audit DESIGNER #8, 2026-09-26,
   validé par Thomas pour essai). À 390 px la colonne fait ~342 px, soit
   ~41 signes par ligne, sous le minimum de 45 : le justifié y creusait des
   rivières de blancs malgré la césure (« Votre      consultation
   individuelle »). Fer à gauche, et césure MANUELLE (plus de coupure
   automatique « d'éla-boration ») : sur une ligne en drapeau la césure
   n'apporte plus rien, elle ne ferait que hacher les mots.
   Au-dessus de 768 px RIEN NE CHANGE : le justifié demandé par Aurélie
   (« ça fait net ») reste, là où la mesure le supporte. Même liste de
   sélecteurs que la règle ci-dessus : les deux blocs vont ensemble. */
@media (max-width: 767px) {
  .psy-hero__accroche,
  .psy-apropos__text p,
  .psy-approche__lead,
  .psy-pilier__chapeau,
  .psy-pilier__point-texte p,
  .psy-public__accroche,
  .psy-public__volet > p,
  .psy-public__texte > p,
  .psy-public__sous > p,
  .psy-contact__note,
  .psy-contact__secret,
  .psy-contact__urgence {
    text-align: start;
    -webkit-hyphens: manual;
    hyphens: manual;
  }
}

/* =========================================================================
   1. HEADER / NAV
   ========================================================================= */
/* ATTENTION (piège corrigé le 2026-07-19) : `backdrop-filter` sur .psy-header
   faisait du header un BLOC CONTENEUR pour ses descendants `position: fixed`.
   Le tiroir mobile (.psy-nav__list) se retrouvait donc dimensionné sur la
   hauteur du header (~80px) au lieu du viewport → il fallait scroller dans un
   ruban de 80px pour voir les 5 entrées. Le filtre est donc déporté sur un
   pseudo-élément : le rendu visuel est identique, mais le header ne crée plus
   de bloc conteneur et `position: fixed` retrouve le viewport comme référence.
   Ne jamais remettre backdrop-filter / filter / transform sur .psy-header. */
.psy-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-base) var(--ease-doux),
              box-shadow var(--dur-base) var(--ease-doux);
}
/* FOND DU HEADER : deux états, et PLUS AUCUN backdrop-filter (audit
   DESIGNER #7, 2026-09-26).
   - EN HAUT DE PAGE : transparent. Le hero glisse sous le header (cf. §3,
     margin-top négatif) et son dégradé monte jusqu'au bord de l'écran : le
     premier écran est d'un seul tenant, sans la bande crème qui le coupait
     net à --header-h ni le halo de pollen tranché par le bord du header.
   - UNE FOIS DÉFILÉ (.is-scrolled, posé par site.js §2 au-delà de 8 px) :
     aplat crème PLEIN. L'ancien voile à 82 % + blur(10px) obligeait le
     navigateur à re-flouter la page sous le header à CHAQUE image de scroll
     (coût connu sur iPhone). Le rapport proposait un aplat à 94 % ; au rendu
     on lisait encore en fantôme les paragraphes qui passaient sous la nav,
     à 94 % comme à 97 % (constaté sur capture, passe 2) : c'est le flou qui
     les effaçait jusque-là. Sans flou, seul l'opaque les efface. On ne perd
     rien de visible : la teinte des sections qui défilaient dessous ne se
     devinait déjà plus à 82 %.
   Le fond reste porté par ::before, jamais par .psy-header lui-même (cf.
   le piège du 2026-07-19 juste au-dessus) : on garde la même architecture,
   seul le contenu du pseudo change. */
.psy-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1; /* sous le contenu du header, au-dessus de la page qui défile */
  background: rgb(var(--creme-rgb) / 0);
  transition: background var(--dur-base) var(--ease-doux);
}
/* État « décollé » (ajouté par JS quand on a scrollé) */
.psy-header.is-scrolled {
  border-bottom-color: var(--vert-tendre);
  box-shadow: var(--shadow-sm);
}
.psy-header.is-scrolled::before { background: rgb(var(--creme-rgb) / 1); }
/* Sans JS, .is-scrolled n'est jamais posé : on garde alors l'aplat en
   permanence, sinon le header resterait transparent au-dessus du texte. */
.psy.no-js .psy-header::before { background: rgb(var(--creme-rgb) / 1); }

.psy-header__inner {
  max-width: var(--maxw);
  margin-inline: auto;
  /* Padding vertical --space-2xs depuis le détourage du logo (2026-09-26,
     audit DESIGNER #13) : le PNG n'a plus de marge transparente native, le
     dégagement vient donc de nouveau du header. Cf. --logo-h et --header-h
     dans tokens.css : les deux valeurs se calibrent ENSEMBLE. (Avant :
     --space-3xs, quand ~27 % de vide autour du lockup faisait ce travail.) */
  padding: var(--space-2xs) var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-base);
}

/* --- Logo (image) dans le header ---------------------------------------
   img/logo-header.png (720x720) = LOCKUP COMPLET d'Aurélie (monogramme AR +
   baseline « PSYCHOLOGUE CLINICIENNE »), simple downscale du canevas carré
   intact src/img/Logo/LOGO VF-04.png. Recadré une première fois au monogramme
   seul le 2026-09-04 (baseline jugée illisible à 44-58px), puis remis intact
   le jour même sur retour explicite d'Aurélie : elle veut son logo affiché tel
   qu'elle l'a livré, jamais recoupé.

   PNG À FOND TRANSPARENT (encre verte monochrome #75856B) depuis le
   2026-09-04. Avant : le JPEG issu de la variante VF-01 avait un fond OPAQUE
   #EFE7DB, qu'on masquait par une PASTILLE (fond --creme + radius + ring
   ::after + mix-blend-mode multiply). Deux blancs voisins mais différents
   (#EFE7DB du fichier vs #F7F6F2 du header) faisaient malgré tout ressortir un
   liseré autour du logo. Tout cet échafaudage est SUPPRIMÉ : le logo se pose
   nu sur le header, donc zéro démarcation, aussi bien en haut de page que sur
   le header sticky translucide (rgb(creme / 0.82)).
   NE PAS réintroduire background / border-radius / ring ::after /
   mix-blend-mode ici : ils n'ont de sens que sur un fichier à fond opaque.

   DÉTOURÉ LE 2026-09-26 (audit DESIGNER #13, partie logo seulement, essai
   local validé par Thomas ; À MONTRER À AURÉLIE avant toute mise en ligne).
   Seul le VIDE TRANSPARENT du canevas carré a été retiré : le fichier passe
   de 720x720 à 330x305 (bounding box alpha), somme des alphas identique au
   pixel près, monogramme ET baseline « PSYCHOLOGUE CLINICIENNE » entiers.
   Même opération que celle déjà acceptée pour img/logo-hero.png, rien à
   voir avec le recadrage au monogramme refusé le 2026-09-04 (qui coupait
   la baseline). Ancien fichier conservé : img/logo-header-carre-720.png.
   Conséquences : --logo-h mesure désormais le lockup lui-même (cf.
   tokens.css) et l'ancienne compensation optique (margin-inline-start
   négative de 27,2 % de --logo-h, qui rattrapait le vide à gauche du
   canevas) disparaît : l'encre commence maintenant au bord de la boîte, le
   logo cale au pixel sur le gutter comme le CTA à l'opposé. */
.psy-logo {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  line-height: 0;
}
.psy-logo__img {
  height: var(--logo-h);
  /* Ratio du fichier détouré (330x305) : largeur calculée par le navigateur
     à partir des attributs width/height, donc zéro recalcul de layout. */
  width: auto;
  aspect-ratio: 330 / 305;
}

/* Repli texte : utilisé si l'image est retirée (et dans le footer, où l'encre
   vert sauge du lockup manque de contraste). Serif de signature. */
.psy-wordmark {
  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature);
  font-weight: var(--fw-medium);
  font-size: clamp(1.3125rem, 1.15rem + 0.65vw, 1.625rem);
  letter-spacing: 0;
  color: var(--vert-foret);
  text-decoration: none;
  line-height: 1;
}
.psy-wordmark:hover { color: var(--vert-foret); }

.psy-nav { display: flex; align-items: center; }

.psy-nav__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.psy-nav__link {
  font-family: var(--font-corps);
  font-size: var(--fs-small);
  font-weight: var(--fw-semi);
  color: var(--encre);
  text-decoration: none;
  padding-block: var(--space-2xs);
  position: relative;
}
.psy-nav__link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1.5px;
  background: var(--dore-tournesol);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-base) var(--ease-doux);
}
.psy-nav__link:hover { color: var(--vert-foret); }
.psy-nav__link:hover::after { transform: scaleX(1); }

/* Hamburger - masqué ≥ 1024px. Il reste AU-DESSUS du tiroir ouvert (le
   panneau couvre toute la hauteur du viewport, croix comprise). */
.psy-nav__toggle {
  display: none;
  position: relative;
  z-index: var(--z-drawer-toggle);
  width: 44px;
  height: 44px;
  border: none;
  background: transparent;
  cursor: pointer;
  padding: 0;
  align-items: center;
  justify-content: center;
}
.psy-nav__burger,
.psy-nav__burger::before,
.psy-nav__burger::after {
  content: "";
  display: block;
  width: 24px;
  height: 2px;
  background: var(--vert-foret);
  border-radius: var(--radius-pill);
  transition: transform var(--dur-base) var(--ease-doux),
              opacity var(--dur-base) var(--ease-doux);
}
.psy-nav__burger { position: relative; }
.psy-nav__burger::before { position: absolute; top: -7px; }
.psy-nav__burger::after  { position: absolute; top:  7px; }
/* état ouvert → croix */
.psy-nav__toggle[aria-expanded="true"] .psy-nav__burger { background: transparent; }
.psy-nav__toggle[aria-expanded="true"] .psy-nav__burger::before { transform: translateY(7px) rotate(45deg); }
.psy-nav__toggle[aria-expanded="true"] .psy-nav__burger::after  { transform: translateY(-7px) rotate(-45deg); }

/* Voile derrière le tiroir : ferme au clic « à côté » et absorbe les gestes
   tactiles (touch-action: none) → le fond ne défile plus sous le menu ouvert,
   sans avoir à mettre le body en position: fixed (ce qui casserait le header
   sticky ET les mesures de ScrollTrigger). Masqué en desktop. */
.psy-nav__scrim {
  display: none;
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer-scrim);
  background: var(--scrim);
  opacity: 0;
  visibility: hidden;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
  transition: opacity var(--dur-base) var(--ease-doux),
              visibility 0s linear var(--dur-base);
}
.psy-nav__scrim.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-base) var(--ease-doux), visibility 0s;
}

/* --- Bouton « Rendez-vous » compact, à côté du burger (audit DESIGNER #14,
   2026-09-26) ------------------------------------------------------------
   Mesuré à 390 px : 14 700 px (17 écrans) sans aucun appel à l'action
   visible entre le hero et Contact, parce que le CTA du header est rangé
   dans le tiroir. Ce bouton le ressort, sous 1024 px uniquement (au-dessus,
   le CTA de la nav est déjà visible en permanence).
   QUAND IL EST VISIBLE : dès que le header passe en .is-scrolled (en haut
   de page le hero porte déjà son propre « Prendre rendez-vous », deux
   boutons identiques dans le même écran feraient doublon) ET tant que la
   section Contact n'est pas à l'écran (.is-contact-visible, posé par
   site.js §2 : là, les vrais boutons de contact sont sous les yeux).
   MASQUÉ = opacity 0 + visibility hidden : hors de l'ordre de tabulation et
   des lecteurs d'écran, pas seulement transparent. La visibilité bascule
   APRÈS le fondu en sortie, AVANT en entrée (même technique que le tiroir).
   Pourquoi pas une barre collante en bas d'écran : pour un public en
   détresse elle pèse plus, et elle masquerait du contenu et le focus
   clavier (WCAG 2.4.11). Ici rien n'est masqué.
   Cible tactile : min-height 44 px (WCAG 2.5.5 / Apple HIG). */
.psy-header__inner > .psy-header__rdv { display: none; } /* spécificité > .psy-btn (§2, déclaré après) */

@media (max-width: 1023px) {
  .psy-header__inner { gap: var(--space-xs); }
  .psy-header__inner > .psy-header__rdv {
    display: inline-flex;
    margin-inline-start: auto; /* se cale contre le burger, à droite */
    min-height: 44px;
    padding-block: 0;
    padding-inline: var(--space-sm);
    font-size: var(--fs-small);
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease-doux),
                visibility 0s linear var(--dur-base),
                transform var(--dur-base) var(--ease-doux),
                box-shadow var(--dur-base) var(--ease-doux);
  }
  .psy-header.is-scrolled:not(.is-contact-visible) .psy-header__inner > .psy-header__rdv,
  .psy.no-js .psy-header__inner > .psy-header__rdv {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity var(--dur-base) var(--ease-doux),
                visibility 0s,
                transform var(--dur-base) var(--ease-doux),
                box-shadow var(--dur-base) var(--ease-doux);
  }
}

@media (max-width: 1023px) {
  .psy-nav__toggle { display: inline-flex; }
  .psy-nav__scrim { display: block; }

  .psy-nav__list {
    position: fixed;
    top: 0;
    right: 0;
    left: auto;
    bottom: auto;
    z-index: var(--z-drawer-panel);
    width: min(82vw, 340px);
    /* Hauteur : dvh suit la barre d'URL mobile qui se rétracte, svh sert de
       repli pour les navigateurs sans unités dynamiques. Jamais 100vh pur. */
    height: 100svh;
    height: 100dvh;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: var(--space-sm);
    /* Dégagement en haut = hauteur réelle du header, pour que la croix du
       hamburger reste lisible par-dessus le panneau. */
    padding: calc(var(--header-h) + var(--space-sm)) var(--space-lg) var(--space-lg);
    background: var(--creme);
    box-shadow: var(--shadow-lg);
    transform: translateX(100%);
    /* Fermé : sorti du flux de tabulation (sinon on tabule dans un menu
       invisible). La visibilité bascule après la glissade en fermeture. */
    visibility: hidden;
    transition: transform var(--dur-base) var(--ease-doux),
                visibility 0s linear var(--dur-base);
    /* Si le contenu dépasse (paysage), il défile DANS le panneau et le geste
       ne se propage pas à la page. */
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
  .psy-nav__list.is-open {
    transform: translateX(0);
    visibility: visible;
    transition: transform var(--dur-base) var(--ease-doux), visibility 0s;
  }

  .psy-nav__link {
    font-size: var(--fs-lead);
    display: block;
    padding-block: var(--space-xs);
    border-bottom: 1px solid var(--vert-tendre);
  }
  .psy-nav__link::after { display: none; }
  .psy-nav__cta-item { margin-top: var(--space-sm); }
  .psy-nav__cta-item .psy-btn { width: 100%; }
}

/* Téléphone en PAYSAGE (~390px de haut) : on compacte pour faire tenir les
   5 entrées sans scroll interne. Au-delà, le panneau reste défilable. */
@media (max-width: 1023px) and (max-height: 520px) {
  .psy-nav__list {
    gap: var(--space-3xs);
    padding-top: calc(var(--header-h) + var(--space-3xs));
    padding-bottom: var(--space-sm);
  }
  .psy-nav__link {
    font-size: var(--fs-small);
    padding-block: var(--space-2xs);
  }
  .psy-nav__cta-item { margin-top: var(--space-2xs); }
}

/* Blocage du défilement de la page quand le tiroir est ouvert.
   `overflow: hidden` est posé sur <html> et NON sur un ancêtre du header :
   position: sticky et ScrollTrigger restent intacts, et la position de scroll
   est conservée (pas de saut). --psy-sbw compense la barre de défilement qui
   disparaît sur les fenêtres étroites en desktop. */
html.psy-menu-open { overflow: hidden; }
html.psy-menu-open body { padding-right: var(--psy-sbw, 0px); }

/* =========================================================================
   2. BOUTONS - psy-btn (repris des states validés du proto)
   ========================================================================= */
.psy-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-corps);
  font-size: var(--fs-body);
  font-weight: var(--fw-semi);
  line-height: 1;
  padding: var(--space-sm) var(--space-lg);
  border-radius: var(--radius-pill);
  text-decoration: none;
  cursor: pointer;
  border: none;
  transition: transform var(--dur-base) var(--ease-doux),
              box-shadow var(--dur-base) var(--ease-doux),
              background var(--dur-base) var(--ease-doux),
              color var(--dur-base) var(--ease-doux);
}
.psy-btn--sm { padding: var(--space-2xs) var(--space-base); font-size: var(--fs-small); }

.psy-btn--primary {
  background: var(--vert-foret);
  color: var(--creme);
  box-shadow: var(--shadow-md);
}
.psy-btn--primary:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
  color: var(--creme);
}

.psy-btn--ghost {
  /* Fond crème plein (pas transparent) : contraste net et constant quel que
     soit le fond de section où ce bouton apparaît (hero, contact). Si ce
     bouton finit un jour sur un fond différent, retenir cette règle. */
  background: var(--creme);
  color: var(--vert-foret);
  box-shadow: inset 0 0 0 1px var(--vert-sauge); /* ring 1px net (anti-flou subpixel) */
}
.psy-btn--ghost:hover {
  transform: translateY(-2px);
  background: rgb(var(--vert-sauge-rgb) / 0.10);
  color: var(--vert-foret);
}

/* Accent doré. INUTILISÉ depuis le retrait de la section sombre « Grandir,
   se construire » (2026-09-13) : c'était le seul endroit du site où un CTA
   se posait sur du vert forêt. La variante est CONSERVÉE (elle appartient au
   système de boutons, pas à cette section-là) mais plus rien ne l'appelle ;
   à supprimer si aucune section sombre ne revient. */
.psy-btn--accent {
  background: var(--dore-tournesol);
  color: var(--vert-foret);
  box-shadow: var(--shadow-md);
}
.psy-btn--accent:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
  filter: brightness(1.04);
  color: var(--vert-foret);
}

/* Anneau de focus clavier (2026-09-27). Le `:focus-visible` global de
   base.css pose --focus-ring en box-shadow, mais chaque variante ci-dessus
   redéclare box-shadow (ombre portée ou ring inset) à spécificité égale et
   APRÈS base.css : l'anneau était écrasé, les boutons n'avaient aucun focus
   visible au clavier (WCAG 2.4.7). On COMPOSE l'anneau avec l'ombre propre à
   chaque variante. Placé après les :hover (spécificité égale 0,2,0) pour que
   l'anneau reste visible si le bouton est à la fois survolé et focalisé. */
.psy-btn--primary:focus-visible,
.psy-btn--accent:focus-visible { box-shadow: var(--focus-ring), var(--shadow-md); }
.psy-btn--ghost:focus-visible  { box-shadow: var(--focus-ring), inset 0 0 0 1px var(--vert-sauge); }

/* =========================================================================
   3. HERO - logo + accroche + CTA, sans fleur (retirée le 2026-09-03).
   Un seul écran, pas de scroll scrubé ni de sticky : le geste d'ouverture
   vient du logo d'Aurélie (H1, depuis le 2026-09-04) puis du reveal en
   cascade (site.js §5, [data-reveal] sur chaque bloc) porté par le halo du
   dégradé de fond et les spores.
   ========================================================================= */
.psy-hero {
  position: relative;
  overflow: hidden;
  /* PAS de isolation: isolate ici (retiré 2026-09-03) : le champ de pollen
     (§3b) est désormais une couche globale hors de cette section, comparée
     à .psy-hero__content dans la pile de la racine (cf. tokens.css
     --z-pollen/--z-contenu). Isoler la section piégerait son contenu dans
     une pile locale et casserait cette comparaison. */
  /* LE HERO GLISSE SOUS LE HEADER (audit DESIGNER #7, 2026-09-26). Le header
     sticky reste dans le flux (il occupe --header-h en haut de page) ; le
     margin-top négatif remonte le hero dessous, et le padding-top du même
     montant rend au contenu exactement la place qu'il avait. Résultat : le
     dégradé du hero monte jusqu'au bord de l'écran derrière un header
     devenu transparent (§1), sans bande ni couture.
     Hauteur : 100svh AVEC le padding (box-sizing: border-box, base.css),
     donc la zone utile sous le header vaut toujours 100svh - --header-h,
     comme avant (retour Thomas du 2026-09-04, « contenu trop bas ») : le
     centrage vertical du contenu ne bouge pas d'un pixel. Le header
     passant de ~94-105 à ~68-80 px (logo détouré, #13), cette zone utile
     gagne ~26 px ; c'est le seul décalage. Le header (z-index --z-header)
     reste au-dessus du hero et de ses calques (--z-pollen / --z-contenu). */
  margin-top: calc(-1 * var(--header-h));
  padding-top: var(--header-h);
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  align-items: center;
  /* Gouttière nommée : relue par les mots-échos (§3a, --bord-texte) pour
     savoir où s'arrête RÉELLEMENT la colonne de texte. */
  --hero-gouttiere: clamp(var(--space-base), 6vw, var(--space-4xl));
  padding-inline: var(--hero-gouttiere);
  background:
    radial-gradient(120% 80% at 78% 30%, var(--vert-brume) 0%, var(--creme) 55%);
}

/* Asymétrie voulue (anti-slop : hero centré = tell) : la colonne de texte
   occupe ~60% de la largeur, le reste respire dans le halo du dégradé +
   les spores. */
.psy-hero__content {
  position: relative;
  z-index: var(--z-contenu);
  max-width: 38rem;
  width: min(60%, 38rem);
}

/* H1 = le LOGO d'Aurélie (2026-09-04). L'ancienne paire overline typographié
   + wordmark Fraunces a été retirée : le fichier logo porte déjà le nom en
   script ET la baseline « PSYCHOLOGUE CLINICIENNE ». Le <h1> ne fait plus que
   contenir l'image (le style typo n'a plus rien à habiller), d'où le reset :
   sans line-height à 0, la line-box du h1 ajoute quelques pixels fantômes
   sous une image pourtant en display:block, et le rythme vertical décroche.
   ATTENTION : la classe utilitaire .t-overline (partagée par À propos,
   Approche, Pour qui, Contact) n'est PAS concernée, seule la règle
   .psy-hero__overline, propre au hero, a disparu. */
.psy-hero__wordmark {
  margin: 0 0 var(--space-md);
  line-height: 0;
  font-size: 0;
}

/* Taille « imposante mais élégante » (demande Thomas) : le logo occupe TOUTE
   la colonne de contenu, plafonnée à 38rem (608px) par .psy-hero__content.
   Avec le ratio 3.35:1 du wordmark détouré, ça donne ~181px de haut au
   maximum : le logo domine nettement l'ouverture sans écraser l'accroche ni
   les CTA (~390px pour l'ensemble de la colonne, dans un hero d'au moins
   ~700px utiles), et il reste dans la moitié gauche : les mots-échos (§3a)
   le contournent, au-dessus, à droite et en dessous.
   La baseline du logo reste lisible partout : cap-height ~20px à 608px de
   large, encore ~11px à 342px (iPhone), soit l'équivalent optique d'un
   texte de 16px. */
.psy-hero__logo {
  display: block;
  width: 100%;
  max-width: 38rem;
  height: auto;
}

.psy-hero__accroche {
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: var(--encre);
  max-width: 34ch;
  margin-bottom: var(--space-lg);
}

.psy-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

/* -------------------------------------------------------------------------
   3a. Mots-échos flottants - fond décoratif DERRIÈRE .psy-hero__content.
   Écho du thème général du site (ce qu'Aurélie propose et à qui, cf. la
   section "Pour qui" et la meta description), CSS pur (pas de GSAP) : fade
   in/out + flou gaussien en boucle, timing décalé par mot pour éviter tout
   clignotement synchronisé.

   2026-09-13, demande d'Aurélie : la liste passe de 5 à 6 mots et surtout la
   COULEUR DEVIENT UN CODE, pas une décoration (cf. .psy-hero__mot--dore).
   « Parent » est retiré, « Famille » devient « Consultation familiale »,
   « Consultation individuelle » et « Approche groupale » entrent.

   Empilement : réutilise volontairement --z-pollen (même niveau conceptuel
   que le champ de pollen - fond décoratif) plutôt qu'un nouveau jalon de
   z-index. `.psy-hero` ne crée pas de contexte d'empilement propre (position:
   relative + z-index:auto, cf. commentaire §3 juste au-dessus), donc ce
   calque se compare à la racine avec .psy-hero__content (--z-contenu = 2)
   et reste bien SOUS le texte, quelle que soit sa position à l'écran.

   Lisibilité : opacité pic volontairement basse (--o, cf. la table de
   profondeur plus bas) et mots posés HORS de la colonne de texte (les
   proches à droite, deux modalités dorées au-dessus du logo et sous les boutons) -
   la position ET l'opacité travaillent ensemble, aucune des deux ne porte
   seule la sécurité de lecture.

   Départ différé (--delay 0.3s à 1.8s, resserré le 2026-09-04 - c'était
   1.7s à 5.2s, jugé trop tardif par Thomas : "je veux voir les mots assez
   vite avant de scroller") : suit de près le début de la cascade d'entrée du
   hero ([data-reveal], cascade de 120 ms + --dur-reveal 1100ms, cf. site.js
   §5, ~1.3-1.5s au total) sans attendre qu'elle se termine - diversité relative
   entre mots conservée (juste compressée) pour éviter tout clignotement
   synchronisé. ------------------------------------------------------------- */
.psy-hero__mots {
  position: absolute;
  /* Commence SOUS le header, pas au bord du hero : depuis que le hero glisse
     sous le header (#7, cf. §3), sa boîte démarre à y = 0. Sans ce décalage,
     les --y en % se mesureraient sur une boîte plus haute et les mots du
     haut (« Consultation individuelle », --y: 3 %) passeraient derrière la
     nav. Avec lui, la zone des mots commence exactement sous le header. */
  inset: var(--header-h) 0 0 0;
  z-index: var(--z-pollen);
  overflow: hidden;
  pointer-events: none;
  /* TROIS PLANS DE PROFONDEUR (prototype d'architecture DESIGNER #1,
     variante A « constellation en profondeur », validée le 2026-09-27).
     Avant : six mots au même flou (2,5 px), en colonne à droite, bords
     gauches alignés : une liste verticale, sans profondeur. Désormais
     chaque mot appartient à un PLAN qui règle ensemble son flou de repos
     et son opacité (sa taille est dans la table plus bas) :
       proche  = grand, presque net (1,2 px), le plus présent ;
       moyen   = le flou historique --flou-echo (2,5 px) ;
       lointain = petit, flou (3,6 px), plus pâle.
     Les flous restent FIXES (seule l'opacité s'anime, cf. #3 plus bas).
     OPACITÉS : historique des réglages. 0,14 -> 0,22 (2026-09-04, « un peu
     plus foncés ») ; doré à part (audit DESIGNER #9, 2026-09-26) : à
     opacité égale un mot doré ressort à 1,18:1 sur le crème contre 1,35:1
     pour le sauge, alors que la couleur porte un CODE (modalité /
     population, cf. .psy-hero__mot--dore). Le rapport doré ≈ 1,7 x vert
     est conservé à chaque plan, pour que les deux registres pèsent autant.
     Plafond : au-delà de ~0,26 sur crème, le sauge se lit comme du texte
     de contenu. Mesuré sur fond réel : 1,25 à 1,43:1, ce sont des FONDS. */
  --flou-proche: 1.2px;
  --flou-moyen:  var(--flou-echo);
  --flou-loin:   3.6px;
  --o-proche: 0.26;      --o-moyen: 0.21;      --o-loin: 0.17;
  --o-dore-proche: 0.42; --o-dore-moyen: 0.36; --o-dore-loin: 0.3;
  /* Bord droit RÉEL de la colonne de texte (gouttière du hero + largeur de
     .psy-hero__content, cf. §3) + 2rem d'air. Plancher des mots posés à
     droite à mi-hauteur : en tablette la colonne occupe ~66 % de l'écran,
     un pourcentage fixe finirait sur l'accroche. */
  --bord-texte: calc(var(--hero-gouttiere) + min(60vw, 38rem) + 2rem);
}

.psy-hero__mot {
  position: absolute;
  /* Position, taille, rotation et plan : cf. la TABLE plus bas, un mot par
     ligne. Les replis ne servent qu'à ce qu'un mot ajouté sans ligne reste
     visible au lieu de disparaître. */
  left: var(--x, 60%);
  /* Ancrage par la DROITE (2026-09-28) : un mot qui doit finir près du bord
     droit pose --x: auto et --x-droite (distance au bord). Sa largeur varie
     avec la police et la taille : ancré à gauche, on ne peut pas garantir
     qu'il tienne dans le cadre ; ancré à droite, si. */
  right: var(--x-droite, auto);
  top: var(--y, 50%);
  font-family: var(--font-signature);
  font-style: italic;
  font-weight: var(--fw-medium);
  font-size: var(--fs, 2.5rem);
  /* Interligne SERRÉ et explicite (2026-09-13). Par défaut la line-box de
     Fraunces fait ~1,65em : la boîte d'un mot dépassait de 60 % la hauteur de
     son encre, deux mots voisins se chevauchaient en boîte (donc parfois à
     l'œil) et « Adolescent » se faisait rogner par le overflow: hidden du
     conteneur. À 1,15 la boîte colle au dessin, --y veut dire ce qu'il
     semble dire, et la réserve reste suffisante pour les descendantes de
     l'italique (le p et le g de « Approche groupale », seul mot concerné,
     cf. anti-slop : « italique avec descendantes, line-height >= 1,1 »). */
  line-height: 1.15;
  color: var(--vert-sauge);
  white-space: nowrap;
  /* AUCUNE ROTATION (décision Thomas, 2026-09-27). Le prototype inclinait
     chaque mot de -3° à +2,5° pour casser l'alignement : ça se lisait comme
     du « désordre », à l'opposé du registre voulu (rassurer, apaiser). Les
     mots restent droits ; c'est la répartition sur trois plans (taille,
     opacité, flou) qui porte seule la profondeur. Ne pas réintroduire. */
  /* Opacité de pic du mot, FIXE (celle de son plan) : c'est le plafond que
     multiplient les deux calques animés ci-dessous (0 -> 1). Rien n'est
     animé sur l'élément lui-même. */
  opacity: var(--o, 0.21);
}

/* DEUX FLOUS FIXES, UN FONDU ENTRE EUX (audit DESIGNER #3, 2026-09-26,
   validé par Thomas pour essai).
   AVANT : un seul calque dont on animait `filter: blur()` de 16 px à 2,5 px
   en boucle. Un flou qui change à chaque image ne peut pas être confié au
   compositeur (Chrome : `compositeFailed`, « filtre qui déplace des
   pixels ») : le fil principal recalculait le style des six mots à CHAQUE
   image, en permanence, tant que le hero est à l'écran (mesuré : 60
   recalculs par seconde, cf. rapport de passe 2). Sur iPhone, Safari
   refait en plus le flou lui-même à chaque image.
   APRÈS : le mot est dessiné DEUX FOIS, par ses deux pseudo-éléments, à
   partir de data-mot (le texte n'est plus dans le DOM : le conteneur est
   aria-hidden, rien n'est perdu pour les lecteurs d'écran) :
     ::before = LA BRUME, flou fixe --flou-brume (16 px), superposé ;
     ::after  = LE MOT POSÉ, flou fixe de son plan (--flou : 1,2 / 2,5 /
                3,6 px), dans le flux (c'est lui qui donne sa taille à la
                boîte, donc --x / --y gardent exactement leur sens).
   Seule leur OPACITÉ est animée : 100 % compositeur, zéro recalcul de
   style, zéro repeinture, y compris sur iPhone. Chaque calque est
   rastérisé une fois, flou compris.
   LES COURBES NE SONT PAS À L'ŒIL : elles sont CALCULÉES pour coller au
   rendu d'avant. Pour 13 instants de la rampe d'entrée (0 à 12 % du cycle),
   on a rendu l'ancien état (opacité x flou intermédiaire) et cherché par
   moindres carrés le mélange brume + net qui le reproduit au mieux, sur le
   masque réel d'un mot en Fraunces italique. Écart résiduel : nul aux
   extrémités, 21 % au pire à mi-rampe (un flou de ~7 px qu'un fondu entre
   16 et 2,5 px ne peut qu'approcher), pendant ~0,2 s, sous une opacité de
   0,22. La sortie (68 -> 88 %) est le miroir exact de l'entrée, comme
   avant (ease-respire est symétrique). Durées, délais, plateau (12 -> 68 %)
   et palier de repos (88 -> 100 %) : inchangés.
   Les keyframes sont en `linear` ENTRE des points déjà échantillonnés sur
   la courbe ease-respire d'origine : l'accélération douce est portée par
   les valeurs, pas par un easing appliqué une seconde fois. */
.psy-hero__mot::before,
.psy-hero__mot::after {
  content: attr(data-mot);
  opacity: 0;
  animation-duration: var(--dur, 13s);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-delay: var(--delay, 2s);
}
.psy-hero__mot::before {
  position: absolute;
  inset: 0;
  filter: blur(var(--flou-brume));
  animation-name: psy-mot-brume;
}
.psy-hero__mot::after {
  display: block;
  filter: blur(var(--flou, var(--flou-moyen)));
  animation-name: psy-mot-net;
}
/* CODE COULEUR SÉMANTIQUE (2026-09-13, formulé par Aurélie) :
     doré = MODALITÉ de prise en charge (consultation individuelle,
            consultation familiale, approche groupale)
     vert = POPULATION accueillie (enfant, adolescent, adulte)
   La règle anti-slop « doré = accent rare, ≤10 % » est ici VOLONTAIREMENT
   dépassée : on passe de 1 doré sur 5 à 3 sur 6 (50 %). Ce n'est pas un
   relâchement de la charte mais un changement de nature de la couleur, qui
   cesse d'être un rehaut esthétique pour porter une distinction de sens. Un
   lecteur qui repère « doré = ce qu'on fait / vert = pour qui » lit le hero
   plus vite. La garde-fou anti-slop reste pleinement en vigueur PARTOUT
   ailleurs sur la page (CTA, soulignés, jalons) : ici les mots vivent sous
   un voile (opacité 0,3 à 0,42 pour le doré) et un flou, ils ne pèsent pas
   comme 3 aplats dorés.
   Conséquence pratique : ne jamais masquer tout un registre, sinon le code
   perd son sens au lieu de se simplifier. Depuis le 2026-09-28 on ne masque
   plus AUCUN mot sur téléphone (ils passent en fond, cf. le bloc mobile).
   L'opacité propre au doré est portée par la TABLE (--o-dore-*), pas par
   cette classe : elle dépend du plan du mot. */
.psy-hero__mot--dore { color: var(--dore-tournesol); }

/* TABLE DE LA CONSTELLATION (prototype d'architecture #1, variante A).
   Remplace le calibrage 2026-09-13 (--top / --right / min(--fs, --fsv) posés
   inline, mots empilés en colonne dans la marge droite, bords gauches
   alignés par construction). Les mots habitent maintenant TOUTE la surface :
   un mot doré au-dessus du logo, un sous les boutons, les proches à droite.
   Lecture en trois plans, comme une mise au point photographique.
   « ADOLESCENT » RENTRE DANS LE CADRE (2026-09-28, retour d'Aurélie : « sur
   le PC, "adolescent" est coupé »). La variante A le faisait volontairement
   déborder du bord droit, rogné par l'overflow: hidden du conteneur : c'était
   lu comme une erreur, pas comme un effet. Il est désormais ANCRÉ PAR LA
   DROITE (--x-droite: 3 %) : son encre, flou compris, finit à 3 % du bord
   quelle que soit la largeur. Règle générale depuis : AUCUN mot ne touche un
   bord du cadre (mesuré sur l'encre réelle + le flou, pas sur la boîte).
   UNITÉS : --x / --y en % de la boîte des mots (sous le header) ; --fs en
   vw bornée par clamp, pour que l'équilibre tienne de 768 à 2560 sans
   palier. « Consultation familiale », seul mot posé à mi-hauteur à droite,
   ne descend jamais sous --bord-texte (la colonne de texte).
   CONTRÔLES (DESIGNER, puis portage) à 320, 360, 390, 414, 768, 1024, 1280,
   1440, 1920 et 2560 : aucun mot ne touche le logo, l'accroche, les
   boutons ni le header ; aucun mot n'en chevauche un autre ; zéro
   défilement horizontal.
   LES TROIS MODALITÉS DORÉES AU MÊME PLAN (demande d'Aurélie, 2026-09-28 :
   « Consultation individuelle » et « Approche groupale » doivent être aussi
   visibles que « Consultation familiale »). Elles quittent le plan lointain
   pour le plan MOYEN : même opacité (--o-dore-moyen), même flou
   (--flou-moyen). Taille : « Approche groupale » prend exactement celle de
   « Consultation familiale » ; « Consultation individuelle » (25 signes
   contre 22) est un cran en dessous (2,7vw au lieu de 2,9vw) pour une
   PRÉSENCE équivalente, pas une largeur démesurée. Positions desktop
   inchangées : la place suffisait (mesuré, cf. CONTRÔLES ci-dessus).
   PLAFOND À DROITE de « Consultation familiale » (2026-09-28) : poussé par
   --bord-texte, il sortait du cadre en tablette (17 px rognés à 768, 6 px à
   800). Son encre mesure ~10,1 em (Fraunces italique) : calc(100% - 10,5 em)
   le garde entier dans le cadre, flou compris, et ne mord jamais sur la
   colonne de texte (mesuré de 768 à 2560).
   Changer un mot = changer data-mot dans index.html ET son sélecteur ici. */
.psy-hero__mot[data-mot="Consultation individuelle"] { --x: 4%;  --y: 3%;  --fs: clamp(1.4rem, 2.7vw, 3.5rem);   --o: var(--o-dore-moyen);  --flou: var(--flou-moyen); }
.psy-hero__mot[data-mot="Enfant"]                    { --x: 60%; --y: 5%;  --fs: clamp(3rem, 8vw, 10rem);         --o: var(--o-proche);      --flou: var(--flou-proche); }
.psy-hero__mot[data-mot="Consultation familiale"]    { --x: min(max(57%, var(--bord-texte)), calc(100% - 10.5em)); --y: 37%; --fs: clamp(1.5rem, 2.9vw, 3.8rem); --o: var(--o-dore-moyen); --flou: var(--flou-moyen); }
.psy-hero__mot[data-mot="Adulte"]                    { --x: 74%; --y: 51%; --fs: clamp(2.6rem, 6.4vw, 8rem);       --o: var(--o-proche);      --flou: var(--flou-proche); }
.psy-hero__mot[data-mot="Approche groupale"]         { --x: 36%; --y: 88%; --fs: clamp(1.5rem, 2.9vw, 3.8rem);   --o: var(--o-dore-moyen);  --flou: var(--flou-moyen); }
.psy-hero__mot[data-mot="Adolescent"]                { --x: auto; --x-droite: 3%; --y: 76%; --fs: clamp(2rem, 4.6vw, 5.8rem);     --o: var(--o-moyen);       --flou: var(--flou-moyen); }

/* MOBILE (< 768 px) : LES SIX MOTS, EN VRAI FOND (2026-09-28, décision de
   Thomas après le retour d'Aurélie : « sur la version tel on ne voit que
   "Adulte" et "Consultation familiale", il manque les autres »).
   AVANT : les mots devaient loger dans les deux bandes libres, au-dessus du
   logo et sous les boutons. Sur les écrans courts (iPhone SE 375x667, Android
   360x640, 320x568) et étroits, ces bandes ne font que 45 à 115 px : trois
   paliers « deux mots » en retiraient quatre (.psy-hero__mot--hors-mini).
   MAINTENANT : on ACCEPTE que les mots passent DERRIÈRE le logo, l'accroche
   et les boutons. Ils sont déjà sous .psy-hero__content (--z-pollen contre
   --z-contenu, cf. l'en-tête du §3a) ; les boutons, à fond plein (forêt ou
   crème), les masquent là où ils passent. Composition en TROIS RANGS sur
   toute la hauteur, un doré et un vert par rang, en quinconce :
     haut   : « Enfant » (proche, à droite) + « Consultation individuelle » ;
     milieu : « Consultation familiale » + « Adolescent », DERRIÈRE
              l'accroche : c'est le plan de fond ;
     bas    : « Approche groupale » + « Adulte » (proche, à droite), calés
              sur le BAS de la boîte (hauteur de leur ligne + une marge) et
              non en % : les boutons ont un fond plein et, à 85 %, ils
              masquaient entièrement « Approche groupale » sur 320x568.
   Positions en % de la boîte (sous le header) : la composition suit la
   hauteur de l'écran, du 320x568 au 430x932, sans palier.
   LISIBILITÉ, NON NÉGOCIABLE. Opacités de pic abaissées (x ~0,75 par
   rapport au desktop). Les deux mots du milieu sont au plan LOINTAIN, qui
   sur mobile devient le « plan de fond » : flou 2,8 px, opacité propre
   (0,17 vert, 0,30 doré), un peu AU-DESSUS du plan moyen pour rester
   perceptibles entre les lignes de l'accroche (à 0,13 / 0,22, « Consultation
   familiale » disparaissait derrière le texte), mais sous le seuil où la
   forme du mot rivalise avec celle des lettres noires : ils se lisent comme
   une texture, pas comme du texte.
   Contraste de l'accroche (encre #23271F) mesuré sur le fond COMPOSÉ, au
   pic des mots, pixel le plus sombre sous l'accroche : cf. le rapport du
   2026-09-28 (plancher visé : 10:1, AAA = 7:1). Si un réglage remonte une
   opacité, remesurer.
   TAILLES PLAFONNÉES À LEUR VALEUR DE 414 PX (portage 2026-09-27) : en pur
   vw, les mots continueraient de grandir jusqu'à 767 px alors que la
   colonne de texte grandit aussi. */
@media (max-width: 767px) {
  .psy-hero__mots {
    --o-proche: 0.19;      --o-moyen: 0.16;      --o-loin: 0.17;
    --o-dore-proche: 0.32; --o-dore-moyen: 0.28; --o-dore-loin: 0.3;
    --flou-loin: 2.8px;
  }
  .psy-hero__mot[data-mot="Enfant"]                    { --x: auto; --x-droite: 5%; --y: 0.5%; --fs: min(13vw, 3.36rem); }
  /* max() : jamais plus haut que la ligne d'« Enfant » (sa taille x 1,35, flou compris),
     sinon les deux se touchent sur les écrans très courts (320x480). */
  .psy-hero__mot[data-mot="Consultation individuelle"] { --x: 4%;  --y: max(11%, calc(min(13vw, 3.36rem) * 1.35)); --fs: min(5.8vw, 1.5rem);  --o: var(--o-dore-moyen); --flou: var(--flou-moyen); }
  .psy-hero__mot[data-mot="Consultation familiale"]    { --x: 4%;  --y: 41%;  --fs: min(6.4vw, 1.66rem); --o: var(--o-dore-loin);  --flou: var(--flou-loin); }
  .psy-hero__mot[data-mot="Adolescent"]                { --x: auto; --x-droite: 5%; --y: 50%; --fs: min(9vw, 2.33rem); --o: var(--o-loin); --flou: var(--flou-loin); }
  .psy-hero__mot[data-mot="Approche groupale"]         { --x: 4%;  --y: calc(100% - 1.45em); --fs: min(6.4vw, 1.66rem); --o: var(--o-dore-moyen); --flou: var(--flou-moyen); }
  .psy-hero__mot[data-mot="Adulte"]                    { --x: auto; --x-droite: 5%; --y: calc(100% - 1.2em); --fs: min(11.5vw, 2.98rem); }
}

/* TÉLÉPHONES TRÈS COURTS (500 px de haut ou moins : à l'horizontale sous
   768 px, 667x375, 568x320 ; ou 320x480). Le contenu y remplit TOUT le hero,
   qui déborde de l'écran : le rang du bas (calé sur le bas de la boîte)
   finissait entièrement caché derrière le second bouton, à fond plein. Une
   bande de 4 rem sous les boutons lui rend sa place. Aucun effet ailleurs :
   ces écrans font défiler le hero de toute façon. */
@media (max-width: 767px) and (max-height: 500px) {
  .psy-hero { padding-bottom: 4rem; }
}

/* ÉCRANS LARGES ET COURTS (768 px et plus de large, 640 px ou moins de haut :
   fenêtres d'ordinateur basses, 1024x600, et surtout TÉLÉPHONES À L'HORIZONTALE
   comme 844x390 ou 932x430, qui prennent la mise en page desktop). Jusqu'au
   2026-09-28, « Consultation individuelle » et « Approche groupale » y étaient
   RETIRÉS (plus de bande libre au-dessus du logo ni sous les boutons). Même
   logique que sur mobile désormais : on les GARDE, en fond.
   - « Consultation individuelle » passe au plan LOINTAIN (opacité et flou de
     fond) : elle glisse derrière le haut du logo.
   - « Approche groupale » quitte le dessous des boutons (fond plein, ils la
     masquaient) : calée sur le BAS de la boîte (1,4 em : sa ligne + son
     flou), à 50 % de la largeur, donc à droite des boutons et à gauche
     d'« Adolescent ». À 2560x640, à 88 %, elle était en outre rognée de
     9,5 px par le bas du cadre.
   Mesuré de 844x390 à 2560x640 : aucun mot rogné, aucun chevauchement entre
   mots. */
@media (min-width: 768px) and (max-height: 640px) {
  .psy-hero__mot[data-mot="Consultation individuelle"] { --o: var(--o-dore-loin); --flou: var(--flou-loin); }
  .psy-hero__mot[data-mot="Approche groupale"]         { --x: 50%; --y: calc(100% - 1.4em); }
}
}

/* Plateau de visibilité maximale ÉLARGI le 2026-09-04 (retour Thomas : « il
   faudrait que la phase où ils sont le plus visibles dure plus longtemps ») :
   18%->50% (32 % du cycle) devient 12%->68% (56 % du cycle), soit ~1,7x plus
   de temps net à l'écran, et sur des durées de 11 à 16s ça fait 6,5 à 9s de
   lisibilité par mot au lieu de 3,5 à 5s. Les rampes restent longues (entrée
   12 % du cycle ~1,4-1,9s, sortie 20 % ~2,4-3,2s) : l'effet « brume qui se
   condense puis se dissipe » est conservé, ce n'est pas devenu un fondu
   brutal. Le palier à 0 en fin de cycle (88->100 %) garde un temps de
   respiration entre deux apparitions du même mot. */
/* Ancien keyframe, pour mémoire (remplacé le 2026-09-26, cf. #3 plus haut) :
     0 % { opacity: 0; blur 16px }   12 % { opacity: --o; blur 2.5px }
    68 % { opacity: --o; blur 2.5px } 88 % { opacity: 0; blur 16px } -> 100 %
   Les deux keyframes ci-dessous en sont la décomposition en deux calques.
   Les pas de 1,67 % de la sortie = les 12 pas de l'entrée étalés sur 20 %. */
@keyframes psy-mot-brume {
  0%     { opacity: 0; }
  1%     { opacity: 0.02; }
  2%     { opacity: 0.07; }
  3%     { opacity: 0.15; }
  4%     { opacity: 0.25; }
  5%     { opacity: 0.37; }
  6%     { opacity: 0.48; }
  7%     { opacity: 0.56; }
  8%     { opacity: 0.55; }
  9%     { opacity: 0.42; }
  10%    { opacity: 0.22; }
  11%    { opacity: 0.06; }
  12%    { opacity: 0; }
  68%    { opacity: 0; }
  69.67% { opacity: 0.06; }
  71.33% { opacity: 0.22; }
  73%    { opacity: 0.42; }
  74.67% { opacity: 0.55; }
  76.33% { opacity: 0.56; }
  78%    { opacity: 0.48; }
  79.67% { opacity: 0.37; }
  81.33% { opacity: 0.25; }
  83%    { opacity: 0.15; }
  84.67% { opacity: 0.07; }
  86.33% { opacity: 0.02; }
  88%    { opacity: 0; }
  100%   { opacity: 0; }
}
@keyframes psy-mot-net {
  0%     { opacity: 0; }
  4%     { opacity: 0.01; }
  5%     { opacity: 0.03; }
  6%     { opacity: 0.07; }
  7%     { opacity: 0.15; }
  8%     { opacity: 0.29; }
  9%     { opacity: 0.5; }
  10%    { opacity: 0.75; }
  11%    { opacity: 0.93; }
  12%    { opacity: 1; }
  68%    { opacity: 1; }
  69.67% { opacity: 0.93; }
  71.33% { opacity: 0.75; }
  73%    { opacity: 0.5; }
  74.67% { opacity: 0.29; }
  76.33% { opacity: 0.15; }
  78%    { opacity: 0.07; }
  79.67% { opacity: 0.03; }
  81.33% { opacity: 0.01; }
  83%    { opacity: 0; }
  100%   { opacity: 0; }
}
/* Hero hors écran : cycle en pause (site.js §2quater pose .is-endormi, audit
   DESIGNER #1). `paused` fige le mot là où il en est et le fait repartir du
   même point au retour : aucun saut, aucune remise à zéro. Depuis #3 les
   animations vivent sur les deux pseudo-éléments : c'est eux qu'on fige. */
.psy-hero.is-endormi .psy-hero__mot::before,
.psy-hero.is-endormi .psy-hero__mot::after { animation-play-state: paused; }

/* --- Champ de pollen (spores flares), champ UNIQUE plein viewport ---
   Une seule couche `position: fixed`, insérée une fois en tout début de
   <body> (cf. index.html), visible du hero jusqu'au footer plutôt que 3
   instances locales qui disparaissaient hors de leur section (ancienne
   version : `.psy-hero__spores` + 2x `.psy-spores`, retirées le 2026-09-03).

   Empilement (cf. tokens.css --z-pollen/--z-contenu) : la couche vit AU-DESSUS
   des fonds de section (crème/ivoire/brume/vert-forêt, peints "niveau 0" de la
   pile de la racine puisque aucune section n'isole plus son contenu) mais SOUS
   tout `.container` (texte, CTA - cf. règle globale dans base.css). Jamais
   interactive (pointer-events: none), jamais devant un CTA.

   Réactivité à la vitesse de scroll (site.js) : chaque spore est une
   animation CSS pure (rise + drift) pilotée en continu via `playbackRate`
   (Web Animations API sur `element.getAnimations()`), jamais en modifiant
   `animation-duration` (ça ferait sauter la progression en cours). */
.psy-pollen {
  position: fixed;
  inset: 0;
  z-index: var(--z-pollen);
  pointer-events: none;
  overflow: hidden;
}
/* La variante fond SOMBRE (.psy-pollen.is-dark : doré/sauge basculés en
   crème/vert tendre) a été retirée le 2026-09-13 avec la section « Grandir,
   se construire », seul fond vert forêt que le pollen traversait. La page ne
   présente plus que des fonds clairs (crème / ivoire / brume) entre le hero
   et le footer, sur lesquels la palette doré/sauge est justement celle qui
   se lit (cf. lessons.md, "spores sur fond clair"). Si une section sombre
   revient un jour, c'est ce bloc + l'IntersectionObserver de site.js §2ter
   qu'il faut restaurer, pas un réglage d'opacité. */

.psy-spore {
  position: absolute;
  left: var(--x, 75%);
  top: var(--y, 60%);
  width: var(--size, 8px);
  height: var(--size, 8px);
  border-radius: 50%;
  opacity: 0;
  will-change: transform, translate, opacity;
  animation:
    psy-spore-rise var(--d, 14s) var(--ease-respire) infinite,
    psy-spore-drift var(--d, 14s) var(--ease-respire) infinite;
  animation-delay: var(--delay, 0s);
}
.psy-spore--dore {
  background: radial-gradient(circle at 38% 38%,
              rgb(var(--dore-rgb) / 0.85),
              rgb(var(--dore-rgb) / 0.30) 55%,
              rgb(var(--dore-rgb) / 0) 78%);
}
.psy-spore--sauge {
  background: radial-gradient(circle at 38% 38%,
              rgb(var(--vert-sauge-rgb) / 0.80),
              rgb(var(--vert-sauge-rgb) / 0.28) 55%,
              rgb(var(--vert-sauge-rgb) / 0) 78%);
}
.psy-spore--halo { filter: blur(14px); }
.psy-spore--point {
  filter: blur(0.4px);
  box-shadow: 0 0 6px 1px currentColor;
  color: rgb(var(--dore-rgb) / 0.4);
}
.psy-spore--point.psy-spore--sauge { color: rgb(var(--vert-sauge-rgb) / 0.4); }

@keyframes psy-spore-rise {
  0%   { transform: translate(0, 0) scale(0.85);  opacity: 0; }
  14%  { opacity: var(--o, 0.3); }
  82%  { opacity: var(--o, 0.3); }
  100% { transform: translate(var(--tx, -200px), var(--ty, -360px)) scale(1.05); opacity: 0; }
}
/* Le drift latéral utilise la propriété INDIVIDUELLE `translate`, pas `margin-left`
   (qui déclenchait un layout + paint à chaque frame sur 8 à 17 éléments).
   `translate` et `transform` sont deux propriétés distinctes qui se composent
   (translate s'applique avant transform) : les deux animations peuvent donc
   tourner en parallèle sur le même élément, en compositing pur. */
@keyframes psy-spore-drift {
  0%   { translate: 0; }
  25%  { translate: var(--dx, 20px); }
  50%  { translate: 0; }
  75%  { translate: calc(var(--dx, 20px) * -1); }
  100% { translate: 0; }
}

/* Scroll cue retiré (anti-slop : "scroll cues bannis"). Le hero tient dans un
   seul écran, le reveal en cascade suffit à installer le rythme. Réintroduction
   possible via un signe ultra-minimal sans texte, gaté no-preference, si
   Thomas le souhaite. */

/* --- HERO responsive (mobile : la colonne de texte passe pleine largeur) --- */
@media (max-width: 767px) {
  .psy-hero__content { width: 100%; max-width: none; }
  /* Le logo suit la colonne (100% de large) : à 390px de viewport il fait
     ~342px, soit ~102px de haut, une ouverture franche sans repousser les CTA
     sous le fold. On resserre juste l'air sous le logo, l'écran étant plus
     court que le desktop. */
  .psy-hero__wordmark { margin-bottom: var(--space-base); }
  .psy-hero__actions { flex-direction: column; align-items: stretch; }
  .psy-hero__actions .psy-btn { width: 100%; }
}

/* --- Champ de pollen responsive : sur mobile, on ne garde que la moitié
   des spores (encore plus discret, moins de calques compositing sur un
   appareil probablement moins puissant). --- */
@media (max-width: 767px) {
  .psy-pollen .psy-spore:nth-child(n+6) { display: none; }
}

/* =========================================================================
   3c. FILIGRANES DE SECTION (ébauche 2026-09-12, demande Thomas)
   Chaque section reprend son propre overline (« Pour qui », « Contact »…) en
   TRÈS grand, flouté, très peu opaque, posé À CHEVAL SUR LA COUTURE avec la
   section précédente : moitié haute chez la voisine du dessus, moitié basse
   dans la section qu'il titre, centre du mot exactement sur la ligne de
   rupture.

   Vocabulaire visuel : celui des mots-échos du hero (§3a) et pas un second
   langage décoratif - --font-signature (Fraunces) en italique, encre dans les
   verts du système, flou gaussien léger, opacité basse. Différence assumée :
   les mots du hero respirent EN BOUCLE (un temps propre, indépendant du
   lecteur), le filigrane n'a AUCUN temps propre - il ne fait que suivre la
   position de son mot dans l'écran (cf. MODULATION AU SCROLL en fin de
   section). Il n'entre donc pas en concurrence avec le hero ni avec la
   cascade [data-reveal] : il n'y a rien à synchroniser, seulement du scroll.
   Étant animé, il est en revanche traité en §11 reduced-motion.

   Empilement : réutilise --z-pollen (même niveau conceptuel que le champ de
   pollen et que les mots du hero = fond décoratif), donc TOUJOURS sous
   .container / .psy-*__inner qui portent --z-contenu. Il passe en revanche
   AU-DESSUS des FONDS de section, y compris celui de la section précédente
   (peint « niveau 0 » de la pile de la racine) : c'est ce qui rend le
   chevauchement possible.

   DEUX MOITIÉS, PAS UNE : ::before porte la moitié haute, ::after la moitié
   basse, chacune clippée à 50 % de la boîte, c'est-à-dire EXACTEMENT sur la
   couture. Chaque pseudo rend le mot ENTIER puis le floute puis le clippe :
   quand les deux encres sont identiques, les deux moitiés se recollent en un
   flou parfaitement continu (aucune couture visible). Quand elles diffèrent
   (sections qui touchent le vert forêt), on obtient une encre par fond, et la
   coupure franche tombe pile là où le fond change déjà de couleur.

   AXE HORIZONTAL : PAS de centrage, et BORD À BORD DU VIEWPORT (arbitrage
   Thomas, 2026-09-12, 2e passe). Les mots ALTERNENT gauche / droite en
   descendant la page et se calent À FLEUR DE L'ÉCRAN : un filigrane « gauche »
   commence à x = 0, un filigrane « droite » finit sur l'arête droite. Pas de
   gouttière, pas de marge de sécurité.
   Pourquoi pas la gouttière de `.container`, essayée avant : les titres du
   site sont larges (jusqu'à ~1600 px rendus), une fois posés dans la colonne
   de contenu ils la remplissaient d'un bord à l'autre et se relisaient comme
   des mots CENTRÉS - le défaut même que la révision voulait supprimer. Seul
   l'alignement à fleur de bord rend l'asymétrie lisible.
   Sens retenu : GAUCHE d'abord. Séquence au 2026-09-26, après
   l'intégration du nuage de mots-clés dans « Pour qui » (sa section et son
   filigrane ont disparu) et le déplacement de l'Approche après les quatre
   sections d'accompagnement :
     1 Qui suis-je . . . . . . . gauche    6 Approche groupale . . . droite
     2 Pour qui  . . . . . . . . droite    7 Se mettre en mouvement  gauche
     3 Adultes . . . . . . . . . gauche    8 Formation . . . . . . . droite
     4 Enfants & Adolescents . . droite    9 Contact . . . . . . . . gauche
     5 Consultation Familiale  . gauche

   ALTERNANCE STRICTE, AUCUN DOUBLON. Thomas a posé deux repères qui ne
   bougent pas : « Qui suis-je » à gauche (le filigrane d'ouverture, qui
   donne le sens) et « Contact » à gauche (du côté de la colonne d'infos,
   pas du plan d'accès). Une alternance stricte entre deux repères du même
   côté demande un nombre IMPAIR de filigranes : c'est le cas depuis que
   « Ce qui vous amène ici » a disparu (9). Le doublon « Adultes / Enfants
   & Adolescents » du 2026-09-15, qui n'existait que parce qu'on en avait
   10, disparaît du même coup. Corollaire : si un filigrane est ajouté ou
   retiré un jour, la parité rebascule et un doublon redevient
   inévitable ; le placer derrière la section la plus longue (Adultes,
   ~2 écrans), là où les deux mots ne sont jamais visibles ensemble.

   EFFET DE BORD HEUREUX : en passant de la colonne de contenu au viewport, la
   boîte d'ancrage a GAGNÉ les deux gouttières, et plus aucun titre ne sort de
   l'écran. --fg-largeur: 200 cale le mot le plus large à ~92 % du viewport :
   il touche son bord et s'arrête juste avant l'opposé. Mesuré à 320, 360, 375,
   390, 414, 540, 640, 767, 768, 1024, 1280, 1440, 1680, 1920, 2200, 2560 :
   0 px de sortie sur les 6 filigranes, et scrollWidth == innerWidth partout.
   `overflow-x: clip` sur les sections porteuses reste là comme filet, pas
   comme béquille : plus rien ne dépend de lui aujourd'hui.
   Corollaire si un futur titre venait à sortir : ce n'est PAS --fg-cote qu'on
   recentre (ça réintroduit l'effet centré que Thomas a rejeté), c'est
   --fg-largeur qu'on baisse sur cette seule ligne.

   RÉGLAGES : tout est en custom properties, groupées section par section plus
   bas. Deux boutons, un par axe, pour ré-orienter vite sans rien réécrire :
   - --fg-cote (horizontal) : 0 = aligné à gauche, 1 = aligné à droite.
     Basculer une section = changer ce seul chiffre. 0.5 redonne exactement
     l'ancien centrage si on veut revenir en arrière.
   - --fg-y (vertical) : 0 = mot centré sur la couture ; --fg-y: 50% le
     descend entièrement dans sa section, -50% le remonte entièrement dans la
     précédente.
   ========================================================================= */

/* Ancrage. `position: relative` SANS z-index ni isolation : une section qui
   isolerait son contenu piégerait .container dans une pile locale et
   casserait la comparaison globale pollen/contenu (cf. tokens.css --z-pollen
   et le commentaire du §3). `position: relative` seul ne crée pas de contexte
   d'empilement, la comparaison tient.
   `overflow-x: clip` et surtout PAS `overflow: hidden` : il faut clipper le
   débordement horizontal des mots longs (sinon barre de défilement
   horizontale sur mobile) tout en LAISSANT passer le débordement vertical,
   qui est toute la condition du « à cheval ». `overflow-x: hidden` forcerait
   l'axe Y en `auto` et couperait net la moitié haute du filigrane ; `clip` est
   le seul mot-clé qui permet le mélange clip-X / visible-Y. */
.psy-apropos,
.psy-approche,
.psy-pourqui,
.psy-public,
.psy-formations,
.psy-contact {
  position: relative;
  overflow-x: clip;
}

.psy-filigrane {
  position: absolute;
  top: 0;          /* = la couture avec la section précédente */

  /* Boîte d'ancrage = LA SECTION ENTIÈRE, BORD À BORD (cf. entête, AXE
     HORIZONTAL). Volontairement PAS la gouttière de `.container` : calés sur
     la colonne de contenu, les mots larges la remplissaient d'un bord à
     l'autre et se relisaient comme centrés.
     `left/right: 0` et pas `width: 100vw` : la boîte est absolue DANS la
     section, donc 100 % = largeur de la section = viewport SANS la barre de
     défilement, là où `100vw` l'inclut et décalerait les mots de ~15 px sous
     Windows. C'est ce qui protège aussi le bord droit de la dérive Windows.
     Les pourcentages de --fg-cote plus bas se mesurent sur cette boîte. */
  left: 0;
  right: 0;
  height: 0;       /* hauteur nulle : seule la couture (top: 0) fait foi */
  z-index: var(--z-pollen);
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;

  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature);
  font-style: italic;
  font-weight: var(--fw-medium);
  line-height: 1;

  /* Taille pilotée par la LONGUEUR du mot (--fg-chars) : « Contact » (7
     signes) monte jusqu'au plafond --fg-max, « Se mettre en mouvement » (22)
     se calme tout seul pour tenir dans la largeur. Le terme central vaut
     ~--fg-largeur % de viewport de large une fois rendu (l'avance moyenne de
     Fraunces italique tourne autour de 0,46 em par signe) : c'est ce qui
     garantit qu'aucun mot ne déborde franchement, de 320 à 1920 px. */
  --fg-chars: 10;
  --fg-largeur: 200;
  --fg-min: 2rem;
  --fg-max: 13rem;
  font-size: clamp(
    var(--fg-min),
    calc(1vw * var(--fg-largeur) / var(--fg-chars)),
    var(--fg-max)
  );
}

.psy-filigrane::before,
.psy-filigrane::after {
  content: attr(data-filigrane);
  position: absolute;
  top: 0;
  white-space: nowrap;

  /* --fg-cote = LE bouton gauche/droite (cf. entête). 0 : le mot COMMENCE à
     x = 0, soit le bord gauche de l'écran ; 1 : il FINIT sur le bord droit —
     `left: 100%` le pose sur l'arête droite puis `translateX(-100%)`, qui se
     mesure sur la largeur du mot lui-même, le ramène entièrement à gauche de
     cette arête. Une seule valeur à changer pour basculer une section. */
  left: calc(var(--fg-cote, 0) * 100%);
  /* --fg-y = le bouton de ré-orientation (cf. entête). 0 = mot centré sur la
     couture. Valeur vérifiée au rendu réel (capture headless + mesure de la
     boîte d'encre) : avec line-height 1, centrer la BOÎTE DE LIGNE met la
     bande capitale/ligne de base à ± 10 px de la couture sur toute l'échelle
     de tailles. Les mots à jambage (« Qui suis-je », « Pour qui ») lisent un
     peu plus bas : c'est le jambage, pas un défaut d'alignement, et tous les
     filigranes partagent bien la même ligne de base. */
  transform: translate(
    calc(var(--fg-cote, 0) * -100%),
    calc(-50% + var(--fg-y, 0px))
  );
  /* Flou en `em` : il suit automatiquement la taille du mot, donc le même
     rendu « léger » de 320 à 1920 px sans second réglage à maintenir. */
  filter: blur(var(--fg-flou, 0.032em));
  will-change: auto;
}

/* Le 50 % est la seule valeur porteuse (c'est la couture). Les autres côtés
   sont NÉGATIFS pour laisser le halo de flou sortir de la boîte de ligne :
   sans ça, on verrait une coupure franche en haut du mot et sur ses flancs. */
.psy-filigrane::before {
  color: var(--fg-encre-haut, var(--vert-sauge));
  opacity: var(--fg-opacite-haut, 0.13);
  clip-path: inset(-60% -15% 50% -15%);
}
.psy-filigrane::after {
  color: var(--fg-encre-bas, var(--vert-sauge));
  opacity: var(--fg-opacite-bas, 0.13);
  clip-path: inset(50% -15% -60% -15%);
}

/* -------------------------------------------------------------------------
   Réglages par section. Une ligne par filigrane = un seul endroit à toucher.
   --fg-chars compte les signes ESPACES COMPRISES (c'est la largeur rendue
   qui compte, pas le nombre de mots).
   ------------------------------------------------------------------------- */

/* « Qui suis-je » : haut sur le dégradé du hero, bas sur ivoire.
   GAUCHE — c'est le filigrane d'ouverture, celui qui pose le sens de
   l'alternance, et Thomas le veut à gauche. Mot court (11 signes, donc
   plafonné à --fg-max) : il ne traverse pas la page, il tient dans le tiers
   gauche et laisse la carte photo de .psy-apropos respirer. */
.psy-apropos > .psy-filigrane { --fg-chars: 11; --fg-cote: 0; }


/* « Pour qui » : haut sur ivoire (À propos), bas sur crème. Mot court ->
   plafonné. DROITE. Section à head centré : l'alternance est ici le seul
   repère d'asymétrie, elle porte tout le rythme.
   Encres par défaut : ivoire/crème, 10 % d'écart, le cas non compensé
   (cf. RÈGLE D'ENCRE plus bas). Depuis le 2026-09-26 sa voisine du dessus
   n'est plus le brume des mots-clés mais l'ivoire de « Qui suis-je ». */
.psy-pourqui > .psy-filigrane { --fg-chars: 8; --fg-cote: 1; }

/* -------------------------------------------------------------------------
   LES QUATRE SECTIONS D'ACCOMPAGNEMENT (§7, 2026-09-15).

   RÈGLE D'ENCRE appliquée ici, et elle tient en une phrase : on ne compense
   QUE les coutures où le vert brume est en jeu. Le sauge (#6E8B73) rend un
   delta de luminance de 0,695 sur crème, 0,622 sur ivoire, 0,581 sur brume.
   Crème contre ivoire, c'est 10 % d'écart et le filigrane « Contact » vit
   très bien sans compensation depuis le 2026-09-12 : les deux moitiés se
   recollent sans couture perceptible. Crème contre brume, c'est 16 %, et
   ivoire contre brume 7 % (le cas déjà traité pour « Ce qui vous amène
   ici », section disparue le 2026-09-26) : là, la moitié posée sur le
   brume se lit franchement plus faible et il faut lui rendre son poids.
   Valeurs retenues : 0,15 pour une moitié sur brume face à du crème, 0,14
   face à de l'ivoire (desktop) ; 0,13 et 0,12 en mobile. Quatre coutures
   touchent le brume depuis le 2026-09-26 : Familiale (haut crème / bas
   brume), Groupale (haut brume / bas ivoire), Approche (haut ivoire / bas
   brume), Formation (haut brume / bas crème).
   ------------------------------------------------------------------------- */

/* « Adultes » : haut sur crème (Pour qui), bas sur ivoire. Mot très court
   (7 signes) -> plafonné à --fg-max, comme « Contact ». GAUCHE.
   Encres par défaut : crème/ivoire, cf. RÈGLE D'ENCRE ci-dessus. */
.psy-public--adultes > .psy-filigrane { --fg-chars: 7; --fg-cote: 0; }

/* « Enfants & Adolescents » : haut sur ivoire (Adultes), bas sur crème.
   DROITE depuis le 2026-09-26 (l'ancien doublon de côté a disparu, cf.
   entête). 21 signes : la formule le calme d'elle-même, il ne déborde pas.
   Encres par défaut : ivoire/crème, cf. RÈGLE D'ENCRE. */
.psy-public--enfants > .psy-filigrane { --fg-chars: 21; --fg-cote: 1; }

/* « Consultation Familiale » : haut sur crème (Enfants), bas sur BRUME.
   GAUCHE depuis le 2026-09-26. Le mot le plus long du lot avec 22 signes,
   à égalité avec « Se mettre en mouvement » : il commence sur l'arête
   gauche et tient entier.
   ENCRE : la moitié basse tombe sur le brume, soit 16 % de delta de
   luminance en moins que la moitié haute sur crème (cf. RÈGLE D'ENCRE).
   0,13 x 1/0,836 = 0,155 -> 0,15, et les deux moitiés se relisent du même
   poids. C'est la compensation la plus forte de la page, avec son miroir
   « Formation » (brume en haut, crème en bas) : ce sont les deux seules
   coutures crème/brume, ailleurs le brume touche de l'ivoire, qui en est
   beaucoup plus proche. */
.psy-public--familiale > .psy-filigrane {
  --fg-chars: 22;
  --fg-cote: 0;
  --fg-opacite-bas: 0.15;
}

/* « Approche groupale » : haut sur BRUME (Consultation Familiale), bas sur
   ivoire. DROITE depuis le 2026-09-26. 17 signes, mais --fg-largeur abaissé de 200 à 190 : à 200
   le mot rendait 98,6 % de la largeur à 320 px, c'est-à-dire qu'il touchait
   SES DEUX bords, là où l'intention est qu'il touche le sien et s'arrête
   juste avant l'opposé. Fraunces italique a une avance plus large que la
   moyenne sur cette chaîne (beaucoup de rondes : o, p, c, g). C'est
   exactement le levier prévu par l'entête (« si un futur titre venait à
   sortir, ce n'est PAS --fg-cote qu'on recentre, c'est --fg-largeur qu'on
   baisse sur cette seule ligne »). 190 le ramène à 93,5 %, au niveau de ses
   trois voisins.
   ENCRE : miroir exact du cas « Se mettre en mouvement » juste en dessous
   (ivoire contre brume, 7 % d'écart), mais dans l'autre sens — ici c'est
   la moitié HAUTE qui est posée sur le brume et qui a besoin du cran
   supplémentaire. */
.psy-public--groupale > .psy-filigrane {
  --fg-chars: 17;
  --fg-largeur: 190;
  --fg-cote: 1;
  --fg-opacite-haut: 0.14;
}

/* « Se mettre en mouvement » (Approche, déplacée le 2026-09-26 après les
   quatre sections d'accompagnement) : haut sur IVOIRE (Approche groupale),
   bas sur BRUME. GAUCHE (7e rang). Le titre le plus large du lot avec
   « Consultation Familiale » (22 signes, ~1600 px vers 1920) : posé sur
   l'arête gauche il tient entier. Si l'asymétrie se lit mal (un mot presque
   pleine largeur reste un mot presque pleine largeur), baisser
   --fg-largeur ici, surtout pas recentrer.
   ENCRE : ivoire contre brume, la moitié BASSE est sur le brume et prend le
   cran supplémentaire (0,14), cf. RÈGLE D'ENCRE. C'est exactement la
   compensation que portait l'ancien filigrane « Ce qui vous amène ici »
   sur la même paire de fonds. */
.psy-approche > .psy-filigrane {
  --fg-chars: 22;
  --fg-cote: 0;
  --fg-opacite-bas: 0.14;
}

/* « Formation » : haut sur BRUME (fin de l'Approche, depuis le
   2026-09-26), bas sur crème. DROITE (8e rang).
   ENCRE : la moitié HAUTE tombe sur le brume, face à une moitié basse sur
   crème, soit 16 % de delta de luminance en moins en haut : c'est le miroir
   exact de « Consultation Familiale » (crème en haut, brume en bas), même
   compensation, 0,15, posée sur l'autre moitié.
   Historique : ce filigrane a d'abord traversé une couture vert forêt /
   crème (encre claire en haut, retirée avec « Grandir, se construire » le
   2026-09-13), puis un aplat crème/crème (13 au 15/09), puis une couture
   ivoire/crème non compensée (15 au 26/09). */
.psy-formations > .psy-filigrane {
  --fg-chars: 9;
  --fg-cote: 1;
  --fg-opacite-haut: 0.15;
}

/* « Contact » : haut sur crème, bas sur ivoire. Mot le plus court -> plafond.
   GAUCHE (9e et dernier rang de l'alternance, repère fixé par Thomas). .psy-contact est en 2 colonnes infos
   (gauche) / plan d'accès (droite) : le filigrane tombe donc du côté de la
   colonne d'infos. Mot très court et très flou, posé sur la couture bien
   au-dessus du premier bloc d'infos : pas de collision au rendu. */
.psy-contact > .psy-filigrane { --fg-chars: 7; --fg-cote: 0; }

/* -------------------------------------------------------------------------
   Filigranes responsive. Sur mobile la colonne de texte est pleine largeur :
   un filigrane trop présent passerait DERRIÈRE chaque ligne de prose au lieu
   de rester dans la respiration entre deux sections. On abaisse le plafond de
   taille et l'opacité (même logique que la réduction des mots du hero et du
   champ de pollen juste au-dessus). Ils sont conservés (et non masqués) : son
   flou est calculé une fois et mis en cache par le compositeur, et la
   modulation au scroll ne fait varier que l'alpha de ce calque - ce n'est pas
   un coût récurrent comme une boucle animée qui repeindrait à chaque frame.
   Les maxima abaissés ici restent les maxima : la courbe du scrub les
   multiplie, elle ne les remplace pas.
   ------------------------------------------------------------------------- */
@media (max-width: 767px) {
  .psy-filigrane {
    --fg-min: 1.75rem;
    --fg-max: 6rem;
    --fg-opacite-haut: 0.11;
    --fg-opacite-bas: 0.11;
  }
  /* Les lignes ci-dessous re-déclarent leur compensation d'encre : leur
     sélecteur de section (0,2,0) l'emporte sur le `.psy-filigrane` (0,1,0)
     juste au-dessus, donc sans ça la valeur desktop resterait active en
     mobile et ces filigranes-là ne baisseraient pas avec les autres.
     Ratios desktop ramenés sur la base mobile de 0,11 : 0,11 x 1,196 =
     0,131 -> 0,13 (crème/brume) ; 0,11 x 1,066 = 0,117 -> 0,12
     (ivoire/brume). Les cinq autres n'ont aucune compensation et suivent
     la baisse commune tout seuls. */
  .psy-public--familiale > .psy-filigrane { --fg-opacite-bas: 0.13; }
  .psy-formations > .psy-filigrane        { --fg-opacite-haut: 0.13; }
  .psy-approche > .psy-filigrane          { --fg-opacite-bas: 0.12; }
  .psy-public--groupale > .psy-filigrane  { --fg-opacite-haut: 0.12; }
}

/* -------------------------------------------------------------------------
   MODULATION AU SCROLL (2026-09-12, 5e passe, demande Thomas). Le filigrane
   n'est plus posé à son opacité pleine en permanence : son intensité suit la
   POSITION de son mot dans l'écran. Il monte depuis 0 quand le mot entre par
   le bas, tient son maximum le temps que la section entre en lecture, puis
   s'éteint quand le mot remonte vers l'arête haute. Ce n'est PAS un reveal
   one-shot : c'est un scrub réversible, remonter la page rejoue la courbe à
   l'envers.

   TECHNIQUE : animation pilotée par le scroll NATIVE (`animation-timeline:
   view()`), zéro JS. Le choix contre GSAP ScrollTrigger `scrub`, pourtant
   déjà chargé et câblé :
   - 9 filigranes = 9 ScrollTriggers de plus et un calcul par frame sur le
     thread principal, à côté des reveals [data-reveal] et du ticker pollen
     qui y sont déjà. La version native tourne sur le thread COMPOSITEUR :
     elle ne coûte rien au JS et ne peut pas être ralentie par lui.
   - Lenis pilote le scroll NATIF de la racine (aucune option wrapper/content
     en site.js §4, donc `window.scrollTo` sous le capot) : le scroll lissé
     nourrit la view-timeline exactement comme la molette. Rien à câbler,
     et aucune cohabitation à arbitrer avec les ScrollTrigger existants.
   - Contrepartie assumée : support inégal selon les navigateurs. D'où le
     @supports ci-dessous et, hors support, EXACTEMENT le rendu statique
     validé plus haut — la règle d'or étant qu'une absence d'animation ne
     doit jamais rendre le décor invisible.

   OÙ PORTE L'ANIMATION : sur .psy-filigrane (le conteneur), PAS sur ses deux
   pseudos. C'est volontaire, et c'est là que se joue la performance :
   - une seule animation par filigrane (9) au lieu de deux (18) ;
   - les opacités validées (--fg-opacite-haut / --fg-opacite-bas, y compris
     les compensations d'encre par section et les valeurs mobiles) restent
     sur les pseudos et ne bougent pas d'un iota : l'opacité de GROUPE les
     multiplie par un facteur 0 → 1. Aucun maximum n'est modifié, on n'ajoute
     qu'une modulation temporelle par-dessus ;
   - .psy-filigrane crée déjà un contexte d'empilement (position + z-index) :
     l'opacité de groupe n'en change donc ni la pile, ni le chevauchement ;
   - le flou des deux moitiés est rastérisé UNE fois dans le calque du groupe,
     et c'est l'alpha de ce calque qui varie. On n'anime JAMAIS `filter` :
     repeindre un blur de cette taille à chaque frame coûterait cher, là où
     l'alpha d'un calque est gratuit côté compositeur.
   Pas de `will-change` : le navigateur promeut le calque pour la seule durée
   utile de l'animation. En poser 9 en dur laisserait autant de calques
   promus en permanence sur toute la hauteur de la page, pour rien.

   LA COURBE (le vrai sujet). La boîte d'ancrage a une hauteur NULLE et est
   posée sur la couture : la plage `cover` se lit donc très simplement —
   0 % = la couture touche le bas de l'écran, 100 % = elle touche le haut.
   Le calage tient compte de ce que le CONTENU de la section (overline, titre,
   texte) arrive --section-y SOUS la couture : il serait raté que le mot soit
   déjà en train de s'effacer quand on lit ce à quoi il se rapporte.
     0 %           éteint — la moitié haute du mot pointe en bas de l'écran
     0 → 42 %      montée douce pendant que la section remonte
     42 → 68 %     PLEIN. La couture est alors entre 58 % et 32 % de la
                   hauteur d'écran, donc le titre de la section traverse la
                   zone de lecture pendant toute la durée du palier.
     68 → 94 %     extinction, le mot approche de l'arête haute
     94 → 100 %    déjà éteint quand il passe sous le header
   `ease-in-out` et non `linear` : l'accélération douce en entrée et en sortie
   de chaque segment évite la rampe mécanique. Le palier 42 → 68 % portant
   deux fois la même valeur, l'easing n'y produit rien.

   LA GLISSADE (2026-09-12, 6e passe, demande Thomas). Au fondu s'ajoute UN
   SEUL axe de mouvement : le mot arrive en glissant horizontalement, depuis
   le bord OPPOSÉ à celui où il s'ancre. Un filigrane « gauche » part décalé
   vers la droite et glisse vers la gauche ; un « droite » fait l'inverse.
   Le sens se déduit du bouton existant, sans second réglage à tenir :
   `1 - 2 * --fg-cote` vaut +1 à gauche (--fg-cote: 0) et -1 à droite (1).

   OÙ SE COMPOSE LA TRANSLATION : sur .psy-filigrane, le CONTENEUR — alors que
   la translation d'ANCRAGE (`translateX(--fg-cote * -100%)`, celle qui pose
   le bord à bord) vit sur les deux pseudos. Deux éléments, deux `transform`
   distinctes qui se multiplient naturellement dans l'arbre : la glissade
   déplace la boîte entière, l'ancrage garde son calage relatif au mot. Rien
   n'est écrasé, et c'est la raison pour laquelle il ne faut JAMAIS descendre
   cette animation sur les pseudos — elle y remplacerait le `transform`
   d'ancrage et casserait d'un coup le bord à bord ET le calage vertical.
   Même logique que l'opacité de groupe : on module le conteneur, on ne
   retouche aucune des valeurs validées en dessous.

   SYNCHRONISATION : la translation atteint 0 à 42 %, c'est-à-dire à l'instant
   EXACT où le fondu atteint son opacité pleine et où commence le palier. Le
   mot prend donc sa position définitive pile quand il finit d'apparaître,
   puis ne bouge plus du tout — ni pendant le palier, ni pendant l'extinction
   (les keyframes 68 / 94 / 100 % reportent `translateX(0)` explicitement,
   sinon l'interpolation repartirait vers la valeur de la keyframe suivante).
   `ease-in-out` porte les deux propriétés : arrivée freinée, pas d'à-coup.

   AMPLITUDE : --fg-glisse, clamp(1.5rem, 4vw, 4.5rem), soit 24 px à 320 et
   72 px au plafond. Volontairement modeste — un mot qui partirait de bien
   plus loin « fuserait » et contredirait le propos d'un décor qui ne fait que
   suivre le lecteur. Mesuré à 320 → 2560 px, à TOUTES les progressions de la
   course et pas seulement à l'arrivée : scrollWidth == innerWidth partout.
   Ce qui protège n'est d'ailleurs pas la marge de manœuvre mais
   `overflow-x: clip` des sections porteuses, qui, contrairement à `visible`,
   empêche le débordement de remonter dans la zone défilable de la racine.
   Coût : `transform` est composité comme `opacity`, le flou des pseudos reste
   rastérisé une fois et n'est pas repeint — vérifié au traçage (cf. lessons).
   ------------------------------------------------------------------------- */

/* État de repli, et seule vérité hors @supports comme en reduced-motion :
   opacité de groupe pleine, c'est-à-dire le rendu statique validé le
   2026-09-12. Écrit explicitement plutôt que laissé à la valeur initiale,
   parce que c'est CETTE ligne qui garantit que le décor ne disparaît jamais
   quand l'animation n'est pas jouée. */
.psy-filigrane {
  opacity: 1;

  /* Amplitude de la glissade (cf. AMPLITUDE ci-dessus) et son point de
     départ signé. Déclarées ici, hors @supports, pour garder UN seul endroit
     à régler ; sans animation-timeline personne ne les lit, et aucune des
     deux n'applique quoi que ce soit par elle-même — elles ne servent qu'à
     nourrir la keyframe 0 %. Le repli reste donc strictement `opacity: 1` et
     transform vide, c'est-à-dire la position finale. */
  --fg-glisse: clamp(1.5rem, 4vw, 4.5rem);
  --fg-glisse-depart: calc(var(--fg-glisse) * (1 - 2 * var(--fg-cote, 0)));
}

@keyframes psy-filigrane-scrub {
  0%   { opacity: 0; transform: translateX(var(--fg-glisse-depart)); }
  42%  { opacity: 1; transform: translateX(0); }
  /* Les trois dernières reportent translateX(0) : le mot est POSÉ à 42 % et
     ne bouge plus. Les omettre ferait interpoler vers `none` et réintroduirait
     un mouvement pendant le palier puis l'extinction. */
  68%  { opacity: 1; transform: translateX(0); }
  94%  { opacity: 0; transform: translateX(0); }
  100% { opacity: 0; transform: translateX(0); }
}

@supports (animation-timeline: view()) {
  .psy-filigrane {
    animation-name: psy-filigrane-scrub;
    /* `auto` = l'animation dure exactement la plage désignée plus bas. Valeur
       qui n'existe QUE là où les timelines de scroll existent : elle est donc
       à sa place dans ce @supports, et nulle part ailleurs. */
    animation-duration: auto;
    animation-timing-function: ease-in-out;
    /* `both` : hors plage, l'animation tient la keyframe de bord — 0 % avant
       d'entrer par le bas, 100 % après être sorti par le haut, les deux à
       opacité nulle. Dans les deux cas le mot est hors écran, y compris le
       décalage horizontal que porte la keyframe 0 % : invisible, et clippé
       par l'`overflow-x: clip` de sa section. */
    animation-fill-mode: both;
    /* `view()` sans argument : le sujet de la timeline est l'élément lui-même
       (la boîte d'ancrage de hauteur nulle posée sur la couture) et le
       scrollport est la racine. `overflow-x: clip` sur les sections porteuses
       n'interfère pas : `clip` ne crée pas de conteneur de défilement, au
       contraire de `hidden` — une raison de plus de ne pas y toucher. */
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
}

/* =========================================================================
   4. « QUI SUIS-JE » - À propos (fond ivoire). Grille texte + photo.
   ========================================================================= */
.psy-apropos { background: var(--ivoire); }
.psy-apropos__grid {
  display: grid;
  /* Mobile : portrait + « 2014 » PUIS le texte (le portrait passe devant
     depuis son arrivée, 2026-09-27). 64 px suffisent entre les deux : les
     96 px d'avant séparaient le texte d'un placeholder, ils décrochaient
     désormais la photo de son titre. */
  gap: var(--space-xl);
  align-items: center;
}
/* PORTRAIT COLLANT (prototype d'architecture #2, 2026-09-27). Avant : grille
   0,85/1,15 centrée verticalement, le placeholder flottait face à cinq
   paragraphes avec ~400 px de vide au-dessus et en dessous. Désormais grille
   5/7 calée EN HAUT, et en tablette/desktop la colonne portrait colle sous
   le header le temps de la lecture : elle accompagne le texte au lieu de
   flotter au milieu d'un vide. Défilement natif, rien d'animé. */
@media (min-width: 768px) {
  .psy-apropos__grid {
    grid-template-columns: 5fr 7fr;
    gap: var(--space-3xl);
    align-items: start;
  }
  .psy-apropos__media {
    position: sticky;
    top: calc(var(--header-h) + var(--space-lg));
  }
}

/* PORTRAIT (2026-09-27, remplace le placeholder brume + picto ; photo
   remplacée le 2026-09-28). 4:5, comme l'emplacement prévu par DESIGNER.
   Source : 832x1284 (WhatsApp, ~9:14), recadrée en 752x940 : haut intact
   (air au-dessus des cheveux), 40 px retirés de chaque côté, bas coupé sur
   les avant-bras, JUSTE AVANT les mains jointes (un 832x1040 les tranchait
   à mi-doigts). Plus grand export = 752w, pas de 800w : on n'agrandit pas.
   Squircle --radius-lg + --carte-bezel, le même traitement que le plan
   d'accès (§9, système de radius unique) : --radius-blob, qui habillait le
   placeholder, rognait les épaules et une partie du décor du cabinet ;
   sur une vraie photo il faisait gadget. Fond brume = teinte d'attente
   tant que l'image n'est pas décodée (le ratio, lui, est réservé par
   aspect-ratio + width/height : aucun décalage). */
.psy-apropos__photo {
  display: block;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-lg);
  background: var(--vert-brume);
  box-shadow: var(--carte-bezel);
  overflow: hidden;
}
.psy-apropos__photo-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* CHIFFRE CLÉ « 2014 » (#2, confirmé par Aurélie le 2026-09-28) : raccourci d'une phrase EXISTANTE (« j'accompagne
   les familles [...] depuis 2014 »), le point focal de la section. aria-hidden
   dans le HTML, il double le paragraphe.
   Depuis l'arrivée du portrait (2026-09-27) il ne DÉBORDE PLUS sur la photo
   (ancienne marge négative -64 px) : le bas de l'image, sous le chiffre, est
   la veste marine d'Aurélie ; le forêt y tomberait autour de 1,1:1. Il se pose juste sous la carte, sur l'ivoire : 9,9:1 (forêt),
   libellé sauge 5,1:1. Même place sur mobile, sous la photo. */
.psy-apropos__chiffre {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  margin: var(--space-sm) var(--space-sm) 0 0;
  max-width: none;
  text-align: right;
  pointer-events: none;
}
.psy-apropos__chiffre-txt {
  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature-petit);
  font-size: var(--fs-overline);
  font-weight: var(--fw-semi);
  text-transform: uppercase;
  letter-spacing: var(--ls-signature);
  color: var(--vert-sauge);
  text-wrap: balance; /* à 390 px, « DEPUIS » restait seul sur sa ligne */
}
.psy-apropos__chiffre-nb {
  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature);
  font-style: italic;
  font-weight: var(--fw-medium);
  font-size: clamp(4rem, 2.4rem + 5vw, 8rem);
  line-height: 0.9;
  color: var(--vert-foret);
}
.psy-apropos__text > * + * { margin-top: var(--space-base); }
.psy-apropos__text h2 { margin-top: var(--space-sm); }
.psy-apropos__text p { color: var(--encre); max-width: 60ch; }

/* CHAPEAU + EXERGUE (prototype d'architecture #3). Cinq paragraphes de même
   poids faisaient un mur. La première phrase devient le CHAPEAU (corps lead,
   encre forêt, fer à gauche : une phrase courte justifiée s'étirerait), et
   une phrase d'Aurélie est mise en EXERGUE avant le 4e paragraphe pour
   casser le rythme.
   Sélecteurs à deux classes : ils doivent passer devant
   `.psy-apropos__text p` (juste au-dessus, et la justification du §0). */
.psy-apropos__text .psy-apropos__chapeau {
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  font-weight: var(--fw-medium);
  color: var(--vert-foret);
  text-align: start;
}

/* EXERGUE : composant partagé (ici et en tête de l'Approche, §5). Toujours
   une reprise LITTÉRALE des mots d'Aurélie, en aria-hidden (doublon du
   texte), jamais un titre. Fraunces italique sauge (4,8 à 5,1:1 sur fond
   réel), filet doré à gauche. Même double sélecteur que le chapeau. */
.psy-exergue,
.psy-apropos__text .psy-exergue {
  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature);
  font-style: italic;
  font-weight: var(--fw-medium);
  font-size: clamp(1.6rem, 1.1rem + 1.6vw, 2.5rem);
  line-height: 1.2;
  color: var(--vert-sauge);
  text-align: start;
  -webkit-hyphens: manual;
  hyphens: manual;
  text-wrap: balance;
  max-width: 22ch;
  margin-block: var(--space-lg);
  padding-inline-start: var(--space-base);
  border-inline-start: 2px solid var(--dore-tournesol);
}
/* Léger débord dans la gouttière de la grille en desktop. */
@media (min-width: 1024px) {
  .psy-apropos__text .psy-exergue { margin-inline-start: calc(-1 * var(--space-lg)); }
}

/* =========================================================================
   5. « COMMENT JE VOUS ACCOMPAGNE » - Approche (fond vert brume)
   ========================================================================= */
.psy-approche { background: var(--vert-brume); }
.psy-approche__head {
  text-align: center;
  max-width: 52rem;
  margin-inline: auto;
}
.psy-approche__head .t-overline { color: var(--vert-sauge); text-indent: var(--ls-signature); margin-inline: auto; }
.psy-approche__head h2 { margin-top: var(--space-2xs); }
.psy-approche__lead {
  margin-top: var(--space-base);
  margin-inline: auto;
  max-width: 50ch;
  color: var(--encre);
}

/* TITRE ET TEXTE EN REGARD (prototype d'architecture #12, 2026-09-27).
   Avant : un head centré de trois longs paragraphes dans une colonne
   étroite, au milieu d'un grand aplat, soit la structure de « Pour qui ».
   L'expression-clé d'Aurélie, « Une clinique du lien » (reprise de son
   texte, aria-hidden), passe en exergue sous le H2.
   SOUS 1024 PX : composition centrée conservée, exergue centrée, filet doré
   AU-DESSUS (variante --titre de l'exergue du §4).
   À PARTIR DE 1024 PX : grille 5/7, titre + exergue à gauche (collants sous
   le header pendant la lecture), les trois paragraphes à droite, fer à
   gauche de la colonne. */
.psy-exergue--titre {
  border-inline-start: none;
  padding-inline-start: 0;
  margin: var(--space-base) auto 0;
  font-size: clamp(1.9rem, 1.2rem + 2.6vw, 3.4rem);
  text-align: inherit;
}
.psy-exergue--titre::before {
  content: "";
  display: block;
  width: 28px;
  height: 2px;
  margin: 0 auto var(--space-sm);
  background: var(--dore-tournesol);
}
@media (min-width: 1024px) {
  .psy-approche__head {
    max-width: none;
    text-align: start;
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: var(--space-2xl);
    align-items: start;
  }
  .psy-approche__head .t-overline { text-indent: 0; margin-inline: 0; }
  .psy-approche__titre {
    position: sticky;
    top: calc(var(--header-h) + var(--space-lg));
  }
  .psy-exergue--titre { margin: var(--space-lg) 0 0; }
  .psy-exergue--titre::before { margin-inline: 0; }
  .psy-approche__texte .psy-approche__lead { margin-inline: 0; max-width: 60ch; }
  .psy-approche__texte .psy-approche__lead:first-child { margin-top: 0; }
}

/* --- LES DEUX PILIERS ---
   SOUS 1024 PX : 2 bandes pleine largeur alternées crème/ivoire (2026-09-01),
   décrites ci-dessous.
   À PARTIR DE 1024 PX : DIPTYQUE (prototype d'architecture #13,
   2026-09-27), cf. le bloc media en fin de §5.
   Bandes (2026-09-01) : `.psy-approche__piliers` est un enfant DIRECT de <section class="psy-approche">,
   SIBLING du premier `.container` (qui, lui, ne porte que le head) : sans
   padding-inline propre, il hérite de la largeur pleine du <section> (comme
   .psy-hero) pendant que `.container` à l'intérieur de chaque
   bande recentre le contenu. Pas de carte-dans-la-carte : juste un fond plat
   + filets fins entre les sous-points. */
.psy-approche__piliers {
  margin-top: var(--space-2xl);
}
.psy-pilier { padding-block: var(--space-xl); }
.psy-pilier--un  { background: var(--creme); }
.psy-pilier--deux { background: var(--ivoire); }
.psy-pilier__inner { max-width: 54rem; }
.psy-pilier__titre {
  color: var(--vert-foret);
  font-size: clamp(1.5rem, 1.2rem + 1vw, 2.1rem);
}
/* Numéro du pilier (#13) : décoratif (aria-hidden), le H3 porte le sens.
   Vert tendre, même famille que les grands numéros des publics (§7b). */
.psy-pilier__num {
  display: block;
  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature);
  font-style: italic;
  font-weight: var(--fw-medium);
  font-size: clamp(3rem, 2rem + 3vw, 5rem);
  line-height: 0.9;
  color: var(--vert-tendre);
  margin-bottom: var(--space-2xs);
}
.psy-pilier__chapeau {
  margin-top: var(--space-sm);
  color: var(--encre-douce);
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  max-width: 62ch;
}

.psy-pilier__points {
  list-style: none;
  margin: var(--space-lg) 0 0;
  padding: 0;
}
.psy-pilier__point {
  display: flex;
  gap: var(--space-base);
  align-items: flex-start;
  padding-block: var(--space-base);
  border-top: 1px solid var(--vert-tendre);
}
.psy-pilier__point:first-child {
  border-top: none;
  padding-top: 0;
}
.psy-pilier__icone {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 24px;
  margin-top: 0.15em;
  color: var(--vert-sauge);
}
.psy-pilier__icone svg { width: 22px; height: 22px; }
.psy-pilier__label {
  display: block;
  font-weight: var(--fw-semi);
  color: var(--vert-foret);
  margin-bottom: var(--space-3xs);
}
.psy-pilier__point-texte p { color: var(--encre-douce); max-width: 60ch; }

/* DIPTYQUE (prototype d'architecture #13). Deux bandes pleine largeur avec
   une colonne de 54rem au milieu laissaient ~60 % de l'écran vide sur
   1 200 px de haut, alors que le texte dit « deux piliers ». En desktop on
   les pose CÔTE À CÔTE : deux panneaux crème / ivoire sur le brume de la
   section (le seul système de carte du site : --radius-lg + --carte-bezel),
   le second décalé vers le bas pour casser la symétrie. Section ramenée de
   ~2 190 à ~1 900 px à 1440. */
@media (min-width: 1024px) {
  .psy-approche__piliers {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-lg);
    align-items: start;
    max-width: var(--maxw);
    margin-inline: auto;
    padding-inline: var(--gutter);
  }
  .psy-pilier {
    border-radius: var(--radius-lg);
    padding: var(--space-xl) var(--space-lg);
    box-shadow: var(--carte-bezel);
  }
  .psy-pilier .psy-pilier__inner { padding-inline: 0; max-width: none; }
  /* Panneaux de ~420 px utiles : le justifié du §0 y creuse des rivières
     (« Nous    avançons    ensemble »). Fer à gauche, comme sous 768 px. */
  .psy-pilier .psy-pilier__chapeau,
  .psy-pilier .psy-pilier__point-texte p { text-align: start; hyphens: manual; }
  .psy-pilier--deux { margin-top: var(--space-2xl); }
}

/* =========================================================================
   6. NUAGE DE MOTS-CLÉS « CE QUI VOUS AMÈNE ICI » (.psy-motscles)
   Ce n'est plus une section depuis le 2026-09-26 (retour d'Aurélie :
   « mettre les mots “ce qui vous amène ici” dans cette partie ») : le nuage
   vit DANS « Pour qui » (§7). Placé par Aurélie entre le chapeau et le
   sommaire des quatre portes, il vient APRÈS elles depuis le prototype
   d'architecture #5 (visuel seulement, cf. §7a). L'ancienne section autonome des mots-clés (fond brume, filigrane
   « Ce qui vous amène ici » remonté par --fg-y) a disparu avec tout son
   CSS. Le nuage lui-même, ses bulles et ses couches de mouvement
   sont inchangés, à une exception près : la MATIÈRE a été recalibrée pour
   le fond crème de « Pour qui » (cf. .psy-motscles__bulle).
   ========================================================================= */

/* Le bloc : SOUS 1024 PX, colonne centrée de 56rem (un peu plus large que
   le chapeau, pour que les bulles longues tiennent à trois ou quatre par
   rangée). À PARTIR DE 1024 PX, DEUX COLONNES (prototype d'architecture #6,
   cf. le bloc media après .psy-motscles__intro).
   Écarts : --space-2xl au-dessus (le nuage vient APRÈS les portes depuis
   #5, cf. §7a), --space-lg entre l'intro et les bulles. */
.psy-pourqui__motscles {
  max-width: 56rem;
  margin: var(--space-2xl) auto 0;
  text-align: center;
}

/* LE REPÈRE. Pas un titre (cf. index.html) et pas un .t-overline : la
   section en porte déjà un, et l'anti-slop limite l'eyebrow à un toutes les
   trois sections. Il emprunte la voix « signature » du site, celle des
   filigranes et des mots du hero : Fraunces italique, en petit et net. Deux
   filets vert tendre de part et d'autre le posent comme une légende du
   nuage, sans le hisser au rang de titre.
   Encre : vert forêt, pas sauge. Le sauge (#616845) passe l'AA sur crème,
   mais cette ligne est courte et en italique fin : la forêt lui garde un
   poids lisible sans monter en graisse. */
.psy-motscles__repere {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  max-width: none;
  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature-petit);
  font-style: italic;
  font-weight: var(--fw-medium);
  font-size: var(--fs-lead);
  line-height: 1.3;
  color: var(--vert-foret);
}
.psy-motscles__repere::before,
.psy-motscles__repere::after {
  content: "";
  flex: none;
  width: var(--space-lg);
  height: 1px;
  background: var(--vert-tendre);
}
.psy-motscles__intro {
  max-width: 46ch;
  margin: var(--space-sm) auto 0;
  color: var(--encre-douce);
}

/* LE NUAGE EN DEUX COLONNES (prototype d'architecture #6, 2026-09-27).
   Titre, repère, intro, bulles et portes centrés sur le même axe : aucune
   tension, et un nuage de 56rem qui flottait au milieu d'un écran de
   1 440 px. En desktop, le repère et son intro prennent une colonne étroite
   à gauche (4/12), les bulles s'étalent à droite, calées au fer à gauche.
   Un filet vert tendre sépare le bloc des portes (au-dessus depuis #5).
   Le repère perd ses deux filets de légende (::before), qui n'ont de sens
   que centrés ; il garde celui de droite comme amorce vers les bulles.
   Matière, flottement, parallaxe et poussée : inchangés. site.js §2ter
   relit la géométrie au survol, il suit la nouvelle grille tout seul. */
@media (min-width: 1024px) {
  .psy-pourqui__motscles {
    max-width: none;
    margin-top: var(--space-2xl);
    padding-top: var(--space-xl);
    border-top: 1px solid var(--vert-tendre);
    display: grid;
    grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
    grid-template-rows: auto 1fr;
    column-gap: var(--space-2xl);
    align-items: start;
    text-align: start;
  }
  .psy-motscles__repere { justify-content: flex-start; grid-column: 1; }
  .psy-motscles__repere::before { display: none; }
  .psy-motscles__intro { grid-column: 1; margin-inline: 0; }
  .psy-pourqui__motscles .psy-motscles {
    grid-column: 2;
    grid-row: 1 / span 2;
    margin-top: 0;
    justify-content: flex-start;
  }
}

/* Pastilles mots-clés : AUCUNE hiérarchie de taille/couleur entre les termes
   (contrainte clinique autant que graphique : un terme plus gros que les
   autres hiérarchiserait des souffrances). Toutes identiques.

   VARIABLES DE RÉGLAGE, toutes déclarées ICI sur le conteneur pour n'avoir
   qu'un seul endroit à toucher (et un seul à neutraliser en mobile) :
     --amp            amplitude du flottement permanent (cf. .psy-motscles__bulle)
     --par-amp        amplitude de la parallaxe au scroll (cf. ARCHITECTURE)
     --pousse-amp     poussée maximale d'une voisine au survol — LUE PAR LE JS
     --pousse-portee  distance (de BORD à bord) au-delà de laquelle une voisine
                      ne bouge plus — idem
     --pousse-aplatissement  facteur appliqué à la seule composante VERTICALE
                      de la poussée — idem
   Les trois dernières ne sont jamais utilisées par le CSS : elles sont là parce
   que ce sont des réglages de MISE EN SCÈNE, pas de logique, et qu'elles n'ont
   rien à faire dans un fichier .js. site.js §2ter les relit à chaque calcul
   via getComputedStyle : les changer ici suffit, sans toucher au script. */
.psy-motscles {
  list-style: none;
  /* --space-lg (et non plus 2xl) depuis l'intégration dans « Pour qui » :
     l'intro est juste au-dessus et appartient au nuage, 96 px l'en
     détachaient comme d'un autre bloc. */
  margin: var(--space-lg) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-xs);
  --amp: 2.5px;
  --par-amp: 8px;
  --pousse-amp: 10px;
  --pousse-portee: 190px;
  /* 0,5 : le bloc est une grille de rangées, et l'œil y lit d'abord des lignes
     de base alignées. Une voisine poussée de 8 px vers le haut se lit comme une
     rangée cassée, pas comme une bulle qui s'écarte — alors que le même
     déplacement à l'horizontale passe pour de la place qu'on fait. Le détail
     du raisonnement est dans site.js §2ter. */
  --pousse-aplatissement: 0.5;

  /* LES DEUX PILES D'OMBRES DE LA BULLE, au repos et au survol. Déclarées ici
     en custom properties plutôt qu'en dur sur .psy-motscles__bulle pour une
     raison précise : le repli reduced-motion (§11) doit pouvoir RÉTABLIR la
     pile de repos sur une bulle survolée, sans la recopier. Une pile d'ombres
     dupliquée à deux endroits est une divergence garantie à la passe suivante.
     Le détail de chaque couche est commenté sur .psy-motscles__bulle. */
  --bulle-ombre:
    inset 0 1.5px 0.5px -0.5px rgb(var(--blanc-rgb) / 0.95),
    inset 0 -1.5px 1px -0.5px rgb(var(--vert-sauge-rgb) / 0.34),
    inset 0 -10px 11px -9px rgb(var(--blanc-rgb) / 0.82),
    inset 0 0 0 1px rgb(var(--blanc-rgb) / 0.55),
    0 0 0 1px rgb(var(--vert-sauge-rgb) / 0.10),
    0 12px 20px -13px rgb(var(--vert-foret-rgb) / 0.38);
  /* Survol : mêmes couches, toutes d'un cran. L'ombre portée descend et se
     creuse (la bulle s'est décollée du fond), les lumières de paroi montent
     légèrement (elle s'est rapprochée de la source). */
  --bulle-ombre-survol:
    inset 0 1.5px 0.5px -0.5px rgb(var(--blanc-rgb) / 0.98),
    inset 0 -1.5px 1px -0.5px rgb(var(--vert-sauge-rgb) / 0.34),
    inset 0 -10px 11px -9px rgb(var(--blanc-rgb) / 0.88),
    inset 0 0 0 1px rgb(var(--blanc-rgb) / 0.62),
    0 0 0 1px rgb(var(--vert-sauge-rgb) / 0.12),
    0 16px 26px -14px rgb(var(--vert-foret-rgb) / 0.42);
}

/* =========================================================================
   ARCHITECTURE DES COUCHES DE TRANSFORMATION (2026-09-12, 2e passe §6).
   À LIRE AVANT DE TOUCHER À QUOI QUE CE SOIT ICI.

   QUATRE effets veulent déplacer les mêmes 23 éléments, en même temps et sur
   des horloges différentes :
     1. FLOTTEMENT     boucle temporelle infinie, propre à chaque bulle
     2. PARALLAXE      pilotée par la progression du scroll
     3. GROSSISSEMENT  transition, déclenchée par le survol de CETTE bulle
     4. POUSSÉE        transition, déclenchée par le survol d'une AUTRE bulle
   Les empiler sur un seul élément est IMPOSSIBLE, et pas par manque d'astuce :
   CSS n'offre que trois emplacements de transformation indépendants et
   composables (`translate`, `rotate`, `scale`, appliqués dans cet ordre PUIS
   `transform`). Le flottement en consomme déjà deux (`transform` pour l'axe Y,
   `translate` pour l'axe X, cf. plus bas). Il reste `scale` — qui ne sait pas
   translater — donc aucune place pour DEUX translations supplémentaires
   (parallaxe et poussée). Et on ne peut pas les fusionner : deux animations
   sur la même propriété ne se composent pas (la dernière déclarée gagne), et
   une transition ne s'applique jamais à une propriété déjà animée par des
   keyframes (l'animation l'emporte toujours) — la poussée serait donc avalée
   par le flottement.

   D'où DEUX BOÎTES par bulle, avec un partage qui se retient facilement :

     <li>  = LA PLACE de la bulle dans le groupe
             · transform ← POUSSÉE    (transition, --pousse-x / --pousse-y du JS)
             · (translate ← PARALLAXE jusqu'au 2026-09-27 : la parallaxe est
               désormais UNE animation sur le <ul>, cf. « PASSE PERF » plus
               bas ; le `translate` du <li> est libre)
             · position/z-index : la bulle survolée passe au-dessus

     <span class="psy-motscles__bulle"> = LA VIE de la bulle elle-même
             · transform ← FLOTTEMENT axe Y  (animation temporelle)
             · translate ← FLOTTEMENT axe X  (animation temporelle, autre période)
             · scale     ← GROSSISSEMENT     (transition)
             · toute la MATIÈRE (fond, parois, ombre) et les deux éclats

   Trois conséquences à garder en tête :
   - La parallaxe (sur le <ul>) et la poussée (sur le <li>) sont deux
     translations commutatives : elles s'additionnent sans que l'ordre compte.
   - `scale` s'applique AVANT `transform` dans la chaîne : le flottement d'une
     bulle survolée est donc multiplié par 1,065. Soit 2,5 px → 2,66 px.
     Invisible, et personne n'a besoin de le compenser.
   - AUCUNE des quatre couches ne touche au flux : ni marge, ni padding, ni
     largeur, ni position. Le placement validé des 23 termes est rigoureusement
     conservé, et une bulle qui grossit ne peut pas provoquer de retour à la
     ligne. C'est la contrainte n°1 de ce bloc.

   Les --d / --delay posés en inline sur les <li> (index.html) sont hérités par
   le <span> : les valeurs restent sur le <li>, l'animation qui les lit est un
   cran plus bas. Même chose pour --amp, déclaré sur le <ul>.
   ========================================================================= */

/* Le <li> n'a plus aucune apparence : c'est une boîte de placement. Il ne porte
   que les deux déplacements « de groupe ». */
.psy-motscles li {
  position: relative;
  /* z-index explicite (et non `auto`) : sans contexte d'empilement déclaré,
     l'ordre du document ferait passer chaque bulle sous les suivantes, et une
     bulle grossie serait rognée par sa voisine de droite. */
  z-index: 1;
  display: block;
  /* POUSSÉE. Les deux custom properties sont posées par site.js §2ter sur
     CHAQUE voisine à l'entrée du survol, et remises à zéro à la sortie. La
     transition porte sur `transform` et non sur les custom properties
     elles-mêmes : changer --pousse-x recalcule `transform`, ce qui déclenche
     la transition depuis la VALEUR COURANTE. C'est exactement ce qu'il faut
     pour le passage rapide d'une bulle à l'autre : la trajectoire est
     réorientée en cours de route, jamais réinitialisée — aucun saut. */
  transform: translate(var(--pousse-x, 0px), var(--pousse-y, 0px));
  transition: transform 420ms var(--ease-doux);
}

/* MATIÈRE « BULLE DE SAVON » (2026-09-12, RECALIBRÉE SUR CRÈME le
   2026-09-26). L'ancienne pastille était un aplat crème opaque + rien
   d'autre. Ce sont maintenant des bulles.

   RECALIBRAGE CRÈME (le nuage est passé du fond brume de son ancienne
   section au fond crème de « Pour qui »). Sur brume, la bulle se lisait
   comme une lentille PLUS CLAIRE que le fond : cœur crème translucide,
   paroi blanche. Sur crème, ce même cœur disparaît (crème sur crème) et la
   paroi blanche ne gagne que 3 % de luminance : il ne restait qu'une
   pastille blanche et son ombre, plus aucune « bulle ». On inverse donc le
   rapport, comme le fait une vraie bulle devant un fond clair :
   - CŒUR teinté vert brume à 0,72 (au lieu de crème 0,33) : la lentille est
     désormais un soupçon PLUS FROIDE et plus sombre que le fond, et c'est
     contre elle que la paroi blanche se lit à nouveau ;
   - palier 72 % : crème 0,58 -> 0,62, pour garder la rampe vers la paroi ;
   - UN FILET EXTÉRIEUR sauge 1px à 0,10 (0,12 au survol), ajouté aux deux
     piles d'ombres : sur crème, l'anneau blanc intérieur ne dessine plus le
     contour, ce filet le reprend (la tranche du film vue de profil).
   Le reste (reflet, éclats, arêtes, croissant bas, ombre portée) est
   inchangé : ce sont des LUMIÈRES, elles se lisent mieux sur le cœur teinté.
   CONTRASTE DU TEXTE (encre douce #4A5145), sur le fond réel : 6,97:1 sur
   le cœur au repos ; PIRE CAS 6,18:1 quand la spore la plus sombre (point
   sauge, 0,32 d'alpha effectif) passe exactement derrière le libellé, le
   cœur à 0,72 l'écrantant aux trois quarts. Plancher ~5,9:1 tenu (c'était
   5,69:1 avec l'ancien cœur crème 0,33 dans le même pire cas sur crème).

   Les couches, de l'arrière vers l'avant :
   1. REMPLISSAGE (2e radial-gradient) : cœur vert brume 0.72 (crème 0.33
      avant le 2026-09-26), paroi blanche 0.94. C'est ce dégradé, et pas une
      bordure, qui fait lire « paroi » : une bulle est une pellicule qu'on voit
      par la tranche sur les bords et de face au milieu. La rampe a été
      RAIDIE lors de la 2e passe (palier intermédiaire à 72 % au lieu d'une
      montée régulière) : le bord se referme plus franchement, ce qui est la
      différence de lecture entre « verre doux » et « bulle ».
   2. REFLET (1er radial-gradient) : crème quasi opaque en haut-gauche,
      dissous avant le milieu.
   3. ÉPAISSEUR (box-shadow inset) : arête crème 1px + un sauge très dilué en
      bas, soit la paroi opposée vue par transparence. C'est la SEULE nuance
      colorée de la bulle et elle reste dans la palette : surtout pas
      d'irisation arc-en-ciel, qui ferait basculer le registre (savon de fête
      foraine) et sortirait des verts/crème du site.
   4. OMBRE (box-shadow porté, unique) : très diffuse, spread négatif, aucun
      contact net. Une bulle ne pose pas, elle repose.

   Tout ça est STATIQUE. Aucune de ces couches n'entre dans les keyframes :
   ni box-shadow, ni background-position, ni filter, ni backdrop-filter (23
   éléments = 23 repaints par frame, cf. le commentaire perf de
   psy-spore-drift au §3b). Les effets restants n'animent que des propriétés
   compositées. LEÇON du 2026-09-27 : « composé » exige que la valeur animée
   soit portée par une animation ou une transition SUR l'élément lui-même.
   Le reflet mobile, qui déplaçait les éclats par un `translate` calculé
   depuis une custom property animée sur le parent, se lisait comme
   composé mais forçait en réalité un repaint des 23 bulles à chaque image
   (cf. « PASSE PERF » plus bas).

   Pas de backdrop-filter du tout, même statique, et c'est un choix ASSUMÉ
   plutôt qu'une mesure : en Chrome headless (rendu logiciel SwiftShader) son
   coût n'est pas mesurable de façon représentative, on ne peut donc PAS
   prouver ici qu'il passerait sur un vrai téléphone. Or son cas est le pire
   possible : une bulle qui bouge voit le fond changer sous elle à chaque
   frame, donc le flou du backdrop devrait être refait à chaque frame, 23
   fois. Et il n'apporte rien de visible ici, puisque le fond traversé est un
   aplat crème : flouter un aplat ne produit aucune image. Le remplissage
   semi-transparent seul donne toute la translucidité utile. */
.psy-motscles__bulle {
  display: block;
  position: relative;
  color: var(--encre-douce);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-small);
  padding: var(--space-2xs) var(--space-sm);
  border-radius: var(--radius-pill);
  background:
    radial-gradient(70% 150% at 26% -30%,
      rgb(var(--blanc-rgb) / 0.74) 0%,
      rgb(var(--creme-rgb) / 0.55) 34%,
      rgb(var(--creme-rgb) / 0) 70%),
    radial-gradient(125% 190% at 50% 46%,
      rgb(var(--vert-brume-rgb) / 0.72) 34%,
      rgb(var(--creme-rgb) / 0.62) 72%,
      rgb(var(--blanc-rgb) / 0.94) 100%);
  /* Les cinq couches de --bulle-ombre (déclarée sur .psy-motscles), dans
     l'ordre : (1) arête HAUTE allumée — la lumière prend la paroi par le
     dessus, et c'est ce trait, plus qu'aucun autre, qui fait basculer la
     pastille de « plate » à « sphérique » ; (2) arête BASSE ombrée en sauge
     très dilué — l'épaisseur du film vue par en dessous, seule nuance colorée
     de la bulle, et elle reste dans la palette (aucune irisation arc-en-ciel :
     registre savon de fête foraine, hors sujet ici) ; (3) croissant lumineux
     BAS — le second point de lumière, la part qui traverse et ressort à
     l'opposé du reflet ; sans lui la bulle reste une pastille éclairée, avec
     lui elle se referme (densifié à la 2e passe, 0.72 → 0.82 et 8 → 10 px :
     c'est du BLANC, donc il renforce le volume sans coûter un point de
     contraste au texte) ; (4) anneau de paroi continu et faible — il tient le
     pourtour là où ni l'arête haute ni le croissant bas ne passent, c'est-à-dire
     les deux flancs, qui étaient le point faible de la 1re version (0.45 →
     0.55) ; (5) ombre portée unique, très diffuse, spread négatif, aucun
     contact net : une bulle ne pose pas, elle repose. */
  box-shadow: var(--bulle-ombre);
  /* GROSSISSEMENT AU SURVOL : la propriété `scale`, seule, indépendante de
     `transform` (occupé par le flottement) et de `translate` (idem). Valeur
     de repos écrite explicitement pour que la transition ait un point de
     départ dans les deux sens. Même durée et même easing que la poussée du
     <li> : les deux mouvements sont solidaires à l'œil. */
  scale: 1;
  transition: scale 420ms var(--ease-doux);
  /* FLOTTEMENT : deux boucles en parallèle sur DEUX propriétés distinctes qui
     se composent (translate s'applique avant transform, même astuce qu'au §3b
     pour les spores) : ça évite d'écrire un seul jeu de keyframes et ça permet
     surtout des PÉRIODES DIFFÉRENTES sur les deux axes (rapport 1,37, non
     entier). Résultat : la trajectoire de chaque bulle ne se referme jamais
     exactement sur elle-même, donc aucune cadence perceptible, même en
     regardant fixement. */
  animation:
    psy-bulle-flotte var(--d, 9s) var(--ease-respire) infinite,
    psy-bulle-derive calc(var(--d, 9s) * 1.37) var(--ease-respire) infinite;
  /* Délais NÉGATIFS (cf. --delay inline dans index.html) : au chargement les
     23 bulles sont déjà chacune à un endroit différent de leur cycle, aucune
     « vague » de démarrage synchronisée. Le 2e délai est décalé du 1er pour
     désolidariser aussi les deux axes d'une même bulle. */
  animation-delay: var(--delay, 0s), calc(var(--delay, 0s) * 1.6);
  /* Pas de will-change : l'animation de transform promeut déjà l'élément en
     couche composite. L'ajouter forcerait 23 couches permanentes en mémoire,
     y compris quand la section est hors écran, pour zéro gain. */
}

/* LES DEUX ÉCLATS SPÉCULAIRES.
   ::before = l'éclat PRINCIPAL, le petit trait franc que fait la source
   lumineuse sur la paroi, plus net que le reflet diffus du dégradé.
   ::after  = l'éclat SECONDAIRE (ajouté à la 2e passe), plus petit et plus
   discret, à l'autre extrémité. Sur une sphère de savon la lumière ressort
   aussi du côté opposé, en plus faible ; c'est cette seconde ponctuation qui
   fait qu'on lit « bulle » et non « pastille brillante ». Sur les libellés
   longs (jusqu'à ~330 px) les deux éclats ponctuent les deux bouts de la
   capsule, ce qui la referme visuellement.

   Taille FIXE (et non en %) pour les deux : les termes vont de « Deuil » à
   « Difficulté de séparation, d'endormissement », un éclat proportionnel
   serait une flaque sur les longs.

   Dessinés au dégradé, pas au filter: blur() (même rendu, pas de couche de
   flou à rastériser sur 42 pseudos).

   `rotate` et non `transform: rotate()` : `transform` reste disponible.
   Les éclats sont FIXES depuis le 2026-09-27 (le « reflet mobile » qui les
   faisait glisser au scroll a été retiré, cf. « PASSE PERF » plus bas). */
.psy-motscles__bulle::before,
.psy-motscles__bulle::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  rotate: -16deg;
  pointer-events: none;
}
.psy-motscles__bulle::before {
  top: 5px;
  left: 13px;
  width: 17px;
  height: 6px;
  background: radial-gradient(closest-side,
    rgb(var(--blanc-rgb) / 0.95), rgb(var(--blanc-rgb) / 0));
}
.psy-motscles__bulle::after {
  bottom: 6px;
  right: 15px;
  width: 10px;
  height: 4px;
  background: radial-gradient(closest-side,
    rgb(var(--blanc-rgb) / 0.66), rgb(var(--blanc-rgb) / 0));
}

/* Flottement. Amplitude verticale = --amp (2,5 px desktop), horizontale = 55 %
   de --amp. À 9 s de période, la vitesse de pointe est d'environ 1,7 px/s :
   on est sous le seuil où l'œil suit un mouvement. L'effet se lit comme « ça
   respire », jamais comme « ça bouge ». */
@keyframes psy-bulle-flotte {
  0%   { transform: translateY(0); }
  50%  { transform: translateY(calc(var(--amp) * -1)); }
  100% { transform: translateY(0); }
}
@keyframes psy-bulle-derive {
  0%   { translate: 0; }
  25%  { translate: calc(var(--amp) * 0.55); }
  50%  { translate: 0; }
  75%  { translate: calc(var(--amp) * -0.55); }
  100% { translate: 0; }
}
/* Nuage hors écran : flottement en pause (site.js §2quater, audit DESIGNER
   #1). C'était ~85 % du travail de fond de la page, même en haut de page.
   La pause reprend exactement où elle s'était arrêtée. La parallaxe, liée
   au scroll, n'est pas concernée : elle ne coûte rien au repos. */
.psy-motscles.is-endormi .psy-motscles__bulle { animation-play-state: paused; }

/* -------------------------------------------------------------------------
   PARALLAXE « GRAVITÉ » (2026-09-12, 2e passe, demande Thomas ; ALLÉGÉE le
   2026-09-27 après mesure, cf. « PASSE PERF 2026-09-27 » ci-dessous).
   Pilotée par le SCROLL, donc par la même mécanique que les filigranes de
   §3c : `animation-timeline`, zéro JS.

   SENS DU MOUVEMENT. On descend → la page monte → le nuage doit partir vers
   le BAS, en retard sur le reste. La keyframe de départ (nuage en bas de
   l'écran) est donc négative et celle d'arrivée positive : le nuage remonte
   moins vite que la page, ce qui est exactement la sensation de « retenue »
   décrite. Et comme c'est un scrub et non une animation jouée, remonter la
   page rejoue la course à l'envers.

   AMPLITUDE : --par-amp (8 px desktop, 5 px mobile) de part et d'autre du
   repos, étalée sur toute la traversée de l'écran par la liste (environ
   1 200 px de scroll en 1440×900). C'est un frémissement d'ambiance, pas un
   déplacement. `linear` : la parallaxe est une proportion du scroll.

   PASSE PERF 2026-09-27 (retour Thomas : « les bulles font lagger le site »,
   surtout sur ordinateur). Mesures Chrome, défilement réel à travers le
   nuage, chaque couche coupée une à une (compte rendu complet dans le
   rapport de l'agent frontend du 2026-09-27) :
   - LE REFLET MOBILE était la couche chère, de loin. Il passait par une
     custom property héritée (--eclat, @property, animée sur le <ul>) dont
     les deux éclats de chaque bulle déduisaient leur `translate`. Deux
     conséquences, mesurées : (1) à chaque image de défilement, recalcul de
     style de tout le sous-arbre (jusqu'à 99 éléments) ; (2) surtout, un
     `translate` qui dépend d'une variable n'est pas composé : les 23 bulles
     étaient REPEINTES et re-rastérisées à chaque image. En 1440 DPR 2, le
     GPU passait de ~9 à ~96 ms par seconde de défilement à cause de lui
     seul ; en mobile ÷4, 39 images perdues sur 5 s contre 1 sans lui.
     Sa variante « composée » (une animation `translate` par éclat, sur la
     timeline nommée) a été mesurée aussi : plus de repaint, mais 46
     animations et 46 calques de plus, et +40 % de recalcul de style. Le
     reflet ne glissait que de ±3 px sur toute la traversée, imperceptible
     sous le flottement : SUPPRIMÉ. Les éclats restent, FIXES, à leur
     position dessinée (celle qu'ils avaient quand le nuage est centré).
   - LA PARALLAXE PAR BULLE (23 animations, profondeur --par de 0,62 à 1,28
     répartie en 5n) est ramenée à UNE animation sur le <ul>. L'écart de
     profondeur entre deux bulles voisines n'excédait pas ±2,6 px sur toute
     la traversée : invisible, alors que les 23 animations coûtaient ~25 %
     du recalcul de style en défilement. Le nuage garde sa « retenue »,
     d'un seul tenant.
   Conséquence sur l'architecture (cf. pavé en tête de §6) : le `translate`
   du <li> est désormais LIBRE, le <li> ne porte plus que la poussée.
   ------------------------------------------------------------------------- */
@keyframes psy-bulle-parallaxe {
  from { translate: 0 calc(var(--par-amp) * -1); }
  to   { translate: 0 var(--par-amp); }
}

@supports (animation-timeline: view()) {
  /* La timeline est portée par le <ul> lui-même, qui est aussi le sujet
     animé (une timeline nommée est visible de son propre élément) : sa
     traversée de l'écran est exactement la fenêtre pendant laquelle les
     bulles sont regardées. La poser sur la SECTION donnerait une course
     beaucoup plus longue et une parallaxe si lente qu'elle deviendrait
     invisible. Le `translate` animé ne gêne pas le reveal du <ul>, qui
     passe par `transform` (deux propriétés distinctes, qui se composent). */
  .psy-motscles {
    view-timeline-name: --psy-bulles;
    view-timeline-axis: block;
    /* Longhands et pas la forme courte `animation:` : le raccourci remet
       `animation-timeline` à `auto`. Même précaution qu'au §3c. */
    animation-name: psy-bulle-parallaxe;
    animation-duration: auto;
    animation-timing-function: linear;
    /* `both` : hors plage, le nuage tient la keyframe de bord (quelques
       pixels, alors qu'il est hors écran). */
    animation-fill-mode: both;
    animation-timeline: --psy-bulles;
    animation-range: cover 0% cover 100%;
  }
}

/* -------------------------------------------------------------------------
   SURVOL : grossissement + poussée des voisines.

   `@media (hover: hover)` : sur tactile, `:hover` reste collé sur la dernière
   bulle touchée jusqu'au tap suivant. Une bulle restée grossie avec ses
   voisines écartées, sans moyen de revenir à l'état neutre, serait un défaut
   permanent à l'écran. site.js §2ter applique le même garde-fou côté JS,
   et n'attache alors aucun écouteur.

   1,065 et pas davantage : au-delà, une bulle longue (« Difficulté de
   séparation, d'endormissement », ~330 px) gagnerait plus de 20 px de large
   et le mouvement passerait de « elle vient vers moi » à « elle zoome ».
   ------------------------------------------------------------------------- */
/* `.is-survolee` et non `:hover` (2026-09-27, lag desktop) : la classe est
   posée par site.js §2ter sur un VRAI mouvement de souris uniquement, et
   gelée pendant le défilement. Avec `:hover`, chaque bulle qui glissait sous
   un curseur immobile pendant le scroll se mettait à grossir, repeindre son
   ombre et pousser ses voisines. Repli sans JS : `:hover` natif, sous
   `.no-js` (le script, absent, ne peut pas poser la classe). */
@media (hover: hover) {
  .psy-motscles li.is-survolee,
  .psy.no-js .psy-motscles li:hover {
    /* Le passage au-dessus de la pile est instantané, et c'est voulu : une
       bulle qui grossit doit couvrir ses voisines dès le premier pixel de
       croissance, pas à mi-transition. Au retour, les voisines reviennent en
       même temps qu'elle rétrécit, donc rien ne la rogne. */
    z-index: 3;
  }
  .psy-motscles li.is-survolee .psy-motscles__bulle,
  .psy.no-js .psy-motscles li:hover .psy-motscles__bulle {
    scale: 1.065;
    /* La bulle survolée se détache aussi par la lumière (cf.
       --bulle-ombre-survol). Transitionner une box-shadow coûte un repaint —
       mais sur UN SEUL élément à la fois, et seulement pendant les 420 ms du
       survol, pas en régime permanent sur 23 éléments. C'est la seule entorse
       à la règle « que du composité » de ce bloc, et elle est bornée. */
    box-shadow: var(--bulle-ombre-survol);
  }
  .psy-motscles__bulle {
    transition: scale 420ms var(--ease-doux),
                box-shadow 420ms var(--ease-doux);
  }
}

/* Mobile : amplitudes quasi divisées par deux. L'écran est plus petit, les
   bulles plus serrées, et l'appareil probablement moins puissant - même
   logique que la réduction du champ de pollen au §3b. Le NOMBRE de bulles
   animées, lui, n'est pas réduit : elles portent toutes du contenu, en figer
   une partie créerait une hiérarchie entre les termes (cf. le commentaire en
   tête de §6). Les deux réglages de poussée ne sont pas touchés : sous
   768 px on est presque toujours en `hover: none`, donc ils ne servent pas —
   et sur le cas résiduel (petite fenêtre desktop) la poussée reste juste. */
@media (max-width: 767px) {
  .psy-motscles {
    --amp: 1.4px;
    --par-amp: 5px;
  }
}

/* =========================================================================
   7. « POUR QUI » (fond crème) + LES QUATRE SECTIONS D'ACCOMPAGNEMENT

   Réécrit le 2026-09-15. L'accordéon 5 panneaux <details>/<summary> qui
   occupait ce numéro a été démonté : son contenu est devenu quatre sections
   de plein droit (.psy-public), et « Pour qui » n'en garde que le sommaire.
   Tout le CSS .psy-accordeon* est parti avec (plus une seule occurrence dans
   src/, prototypes compris), ainsi que le bloc site.js §2bis qui rejouait sa
   fermeture en douceur.
   ========================================================================= */
.psy-pourqui { background: var(--creme); }
.psy-section-head { text-align: center; max-width: 48rem; margin-inline: auto; }
/* margin-inline: auto sur les overlines des têtes centrées (corrigé le
   2026-09-26) : base.css borne tout <p> à --measure (~594 px). Sans
   centrage de la BOÎTE, le texte était centré dans une boîte calée à
   gauche du head (768 px), soit ~86 px de décalage visible sous le H2. */
.psy-section-head .t-overline { color: var(--vert-sauge); text-indent: var(--ls-signature); margin-inline: auto; }
.psy-section-head h2 { margin-top: var(--space-2xs); }
.psy-section-head .t-lead { margin-top: var(--space-base); margin-inline: auto; max-width: 52ch; }

/* -------------------------------------------------------------------------
   7a. LE SOMMAIRE (.psy-acces) - quatre liens d'ancrage vers les sections.

   POURQUOI UNE LISTE À FILETS ET PAS DES CARTES : les quatre entrées sont
   des PAIRS. Aucune ne prime, il n'y a rien à hiérarchiser, et l'anti-slop
   réserve la carte aux cas où l'élévation porte une hiérarchie réelle ;
   sinon on groupe par l'espace et le filet. Le filet 1px vert tendre est
   d'ailleurs déjà le langage de la page (ancien accordéon, liste des
   diplômes, listes de contact) : la section change de fonction sans changer
   de vocabulaire.

   LA FLÈCHE EST DESCENDANTE, pas un chevron. Un chevron (celui de l'ancien
   accordéon) dit « ça se déplie ici » ; ces liens, eux, EMMÈNENT plus bas
   dans la page. Icône Tabler `arrow-narrow-down` (MIT), inline, comme le
   reste des pictos du site.

   Colonne calée sur 52rem sous 768 px (la largeur de l'ancien accordéon).

   QUATRE PORTES NUMÉROTÉES (prototype d'architecture #4, 2026-09-27). Une
   liste de quatre lignes pleine colonne se lisait comme une table des
   matières, alors que c'est la DÉCISION de la page. Chaque porte porte
   désormais un numéro 01-04 (Fraunces italique, le même que les grands
   numéros des sections, §7b), son titre, un repère de tarif repris des
   fiches (aria-hidden : les noms de lien restent courts) et la flèche.
   Mobile : lignes conservées, numéro à gauche. Tablette : 2 colonnes.
   Desktop : 4 colonnes. Toujours des FILETS, jamais des cartes (cf.
   ci-dessus : les quatre entrées restent des pairs).
   ------------------------------------------------------------------------- */
.psy-acces {
  list-style: none;
  margin: var(--space-2xl) auto 0;
  padding: 0;
  max-width: 52rem;
}
.psy-acces__item { border-top: 1px solid var(--vert-tendre); }
.psy-acces__item:last-child { border-bottom: 1px solid var(--vert-tendre); }

.psy-acces__lien {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;   /* numéro · titre · flèche */
  align-items: center;
  column-gap: var(--space-sm);
  padding-block: var(--space-base);
  color: var(--vert-foret);
  /* Le soulignement par défaut de base.css n'a pas de sens sur une ligne de
     sommaire pleine largeur : c'est la ligne ENTIÈRE qui est la cible, le
     filet du dessus et du dessous la délimite déjà. */
  text-decoration: none;
  transition: color var(--dur-base) var(--ease-doux);
}
/* Les <span> sont des enfants directs d'une grille, donc blockifiés :
   `transform` s'y applique (il serait ignoré sur un inline). */
.psy-acces__titre {
  font-family: var(--font-titre);
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  font-weight: var(--fw-semi);
  letter-spacing: -0.006em;
  transition: transform var(--dur-base) var(--ease-doux);
}
.psy-acces__fleche {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  color: var(--vert-sauge);
  transition: transform var(--dur-base) var(--ease-doux);
}
.psy-acces__fleche svg { width: 20px; height: 20px; }

.psy-acces__num {
  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature);
  font-style: italic;
  font-weight: var(--fw-medium);
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.6rem);
  line-height: 1;
  color: var(--vert-sauge);
  font-variant-numeric: lining-nums tabular-nums;
  min-width: 1.6em;   /* « 01 » et « 04 » n'ont pas la même chasse en italique */
}
/* Repère de tarif, sous le titre (7,6:1 sur crème). Il vit DANS le titre
   pour glisser avec lui au survol. */
.psy-acces__tarif {
  display: block;
  margin-top: var(--space-3xs);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  font-weight: var(--fw-medium);
  letter-spacing: 0;
  color: var(--encre-douce);
}
@media (min-width: 768px) {
  .psy-pourqui .psy-acces {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--space-lg);
    max-width: none;
  }
  /* En grille, chaque porte n'a que son filet du HAUT : un filet bas sur la
     dernière seule la décalerait d'un pixel par rapport à ses voisines. */
  .psy-acces__item:last-child { border-bottom: none; }
  .psy-acces__lien {
    height: 100%;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "num fleche" "titre titre";
    grid-template-rows: auto 1fr;
    row-gap: var(--space-sm);
    align-items: start;
    align-content: start;
    padding-block: var(--space-base) var(--space-lg);
  }
  .psy-acces__num { grid-area: num; }
  .psy-acces__fleche { grid-area: fleche; }
  .psy-acces__titre { grid-area: titre; }
}
@media (min-width: 1024px) {
  .psy-pourqui .psy-acces { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* `@media (hover: hover)` : sur tactile, un :hover se « colle » après le tap
   et la ligne resterait décalée pendant tout le défilement qui suit. */
/* LES QUATRE PORTES AVANT LES BULLES. D'abord sur mobile (audit DESIGNER
   #15, 2026-09-26) : sous 768 px le nuage fait un écran entier (~880 px) et
   le sommaire, la vraie navigation de la section, arrivait ~1,7 écran après
   le titre. Puis À TOUTES LES LARGEURS (prototype d'architecture #5,
   2026-09-27) : en desktop aussi il arrivait après ~700 px de bulles. La
   décision d'abord, l'exploration ensuite.
   ⚠ AURÉLIE AVAIT PLACÉ LE NUAGE AVANT LES PORTES : ce changement d'ordre est
   à lui présenter explicitement. S'il est refusé, remettre ce bloc sous
   `@media (max-width: 767px)` suffit ; #4 et #6 fonctionnent sans lui.
   RÉORDONNÉ EN CSS, PAS DANS LE DOM (ordre du document logique). C'est
   sans risque ici pour deux
   raisons : les bulles ne contiennent AUCUN élément focalisable, donc
   l'ordre de tabulation est identique dans les deux cas (on tombe sur les
   quatre liens juste après le chapeau) ; et un lecteur d'écran lit
   « chapeau, nuage, portes » comme sur desktop, ce qui garde son sens (le
   nuage aide à se reconnaître AVANT de choisir). Seul l'ordre VISUEL mobile
   change.
   `width: 100%` : dans une colonne flex, un enfant en margin-inline: auto
   se rétrécit à son contenu au lieu de s'étirer ; les trois blocs ont un
   max-width, ils restent donc pleine largeur de leur colonne. */
.psy-pourqui > .container {
  display: flex;
  flex-direction: column;
}
.psy-pourqui .psy-section-head,
.psy-pourqui .psy-acces,
.psy-pourqui__motscles { width: 100%; }
.psy-pourqui .psy-section-head { order: 1; }
.psy-pourqui .psy-acces        { order: 2; margin-top: var(--space-xl); }
.psy-pourqui__motscles         { order: 3; }

@media (hover: hover) {
  .psy-acces__lien:hover { color: var(--vert-sauge); }
  .psy-acces__lien:hover .psy-acces__titre { transform: translateX(6px); }
  /* La flèche descend : même geste que ce que le lien va faire à la page. */
  .psy-acces__lien:hover .psy-acces__fleche { transform: translateY(4px); }
}

/* -------------------------------------------------------------------------
   7b. LES QUATRE SECTIONS (.psy-public).

   FONDS : cf. le pavé de index.html au-dessus de la section « Adultes ».
   Chaque couture porte un filigrane, donc aucune voisine ne partage son ton.
   La chaîne complète au 2026-09-26, de « Qui suis-je » à « Contact » :
     À propos ivoire -> Pour qui crème -> Adultes ivoire -> Enfants crème
     -> Familiale brume -> Groupale ivoire -> Approche brume
     -> Formations crème -> Contact ivoire.

   TITRE ALIGNÉ À GAUCHE, volontairement : « Pour qui » juste au-dessus a un
   head CENTRÉ (.psy-section-head), et quatre sections centrées à la suite
   auraient fait cinq blocs identiques d'affilée. La bascule au fer à gauche
   tient la règle de diversité de layout (pas plus de deux schémas
   consécutifs identiques) sans rien coûter en lisibilité, et convient mieux
   à des sections de PROSE longue qu'un titre centré au-dessus d'un pavé.
   ------------------------------------------------------------------------- */
.psy-public--adultes   { background: var(--ivoire); }
.psy-public--enfants   { background: var(--creme); }
.psy-public--familiale { background: var(--vert-brume); }
.psy-public--groupale  { background: var(--ivoire); }

/* Même colonne de 52rem que le sommaire qui y mène : l'œil descend dans un
   couloir de lecture constant du haut de « Pour qui » au bas de « Approche
   groupale ». Les paragraphes gardent en plus leur propre --measure (68ch)
   hérité de base.css, qui s'applique en premier sur les écrans larges. */
.psy-public__corps { max-width: 52rem; margin-inline: auto; }

/* SURTITRE « ACCOMPAGNEMENT · n/4 » (audit DESIGNER #12, 2026-09-26).
   5 des 9 sections suivent le schéma « surtitre + H2 cursive » ; les quatre
   publics n'avaient que le H2, et sur mobile on traversait 9 écrans sans
   savoir où on en était. Le compteur n/4 EST le repère de progression.
   Ce n'est PAS un titre (un <p>, comme tous les .t-overline du site) : le
   plan du document reste H2 > H3 > H4, rien n'est sauté.
   Le « n/4 » visible est aria-hidden, doublé d'un « n sur 4 » réservé aux
   lecteurs d'écran : lu tel quel, « 1/4 » s'annonce « un quart ».
   Même écart surtitre -> H2 que .psy-section-head (--space-2xs). */
.psy-public__surtitre { color: var(--vert-sauge); }
.psy-public__surtitre + .psy-public__titre { margin-top: var(--space-2xs); }

/* GRAND NUMÉRO DE SECTION 01-04 (prototype d'architecture #7, 2026-09-27).
   Le H2 « Adultes » (7 lettres) flottait seul en haut à gauche d'un bloc de
   1 100 px : le numéro donne un point focal et une échelle, et relie les
   sections aux portes numérotées du sommaire (§7a). Décoratif (aria-hidden),
   le surtitre « n/4 » porte déjà l'information : vert tendre (1,8 à 2,1:1),
   volontairement. À passer en sauge (5,4:1) s'il doit un jour être « lu ».
   Au-dessus du surtitre sous 1024 px ; à gauche du surtitre + H2, bas
   alignés, à partir de 1024 px (cf. le bloc media en fin de §7b). */
.psy-public__num {
  display: block;
  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature);
  font-style: italic;
  font-weight: var(--fw-medium);
  font-size: clamp(3.5rem, 2rem + 6vw, 8.5rem);
  line-height: 0.8;
  color: var(--vert-tendre);
  font-variant-numeric: lining-nums;
  margin-bottom: var(--space-sm);
}

/* --space-lg et pas --space-md : le H2 et le H3 qui le suit partagent la
   même famille, la même couleur et un poids voisin (600), la hiérarchie se
   lit surtout à la taille et à l'espace. 32 px les collait ; 48 px pose le
   H2 comme titre de section et non comme surtitre du premier volet. */
/* - var(--encre-bas) : réserve d'encre des H2 cursifs (base.css, h2), le
   texte garde exactement sa position. */
.psy-public__titre { margin-bottom: calc(var(--space-lg) - var(--encre-bas)); }

/* Un volet = une sous-partie de niveau H3 (« Consultation individuelle »,
   « Consultation parentale »), ou, dans les sections qui n'en ont pas
   encore, le corps entier. Le grand écart entre deux volets est ce qui
   remplace la séparation que donnait l'ouverture/fermeture de l'accordéon.
   Depuis le 2026-09-26 (#11) un volet = DEUX blocs : .psy-public__texte (la
   prose) et .psy-public__tarifs (la fiche tarif). Côte à côte en desktop,
   l'un sous l'autre en dessous de 1024 px. */
.psy-public__volet + .psy-public__volet { margin-top: var(--space-2xl); }
.psy-public__texte > h3 { margin-bottom: var(--space-base); }

.psy-public__accroche {
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: var(--encre);
}
.psy-public__texte > p + p,
.psy-public__sous > p + p { margin-top: var(--space-sm); }
.psy-public__texte > p,
.psy-public__sous > p { color: var(--encre-douce); }
/* L'accroche reprend l'encre pleine : c'est elle qui porte l'entrée en
   matière, les paragraphes suivants passent en encre douce. */
.psy-public__texte > p.psy-public__accroche { color: var(--encre); }

/* LE TRIO DES SITUATIONS, Consultation Familiale (prototype d'architecture
   #9, 2026-09-27). Le texte d'Aurélie décrit trois situations parallèles
   (« L'un de vos proches… », « Un évènement bouleversant… », « Votre famille
   traverse… ») : empilées en prose, on ne voyait pas qu'il y en avait
   trois. En trio à filet doré, on s'y reconnaît d'un coup d'œil. Texte
   inchangé, au fer à gauche (hors de la justification du §0 : ces <p> ne
   sont pas enfants directs de .psy-public__texte). Encre pleine, 12,5:1. */
.psy-public__trio {
  display: grid;
  gap: var(--space-base);
  margin-block: var(--space-lg);
}
.psy-public__trio > p {
  max-width: none;
  padding-top: var(--space-sm);
  border-top: 1px solid var(--vert-tendre);
  color: var(--encre);
}
.psy-public__trio > p::before {
  content: "";
  display: block;
  width: 28px;
  height: 2px;
  margin-bottom: var(--space-xs);
  background: var(--dore-tournesol);
}
@media (min-width: 768px) {
  .psy-public__trio { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-lg); }
}

/* -------------------------------------------------------------------------
   Sous-parties de niveau H4. Dans le document d'Aurélie, « Le soutien à la
   parentalité / Guidance parentale », « Le soutien psychologique » et « La
   psychothérapie » sont SOULIGNÉS : ce sont des sous-titres.

   Pas de soulignement ici pour autant : sur une page où le soulignement est
   la marque des LIENS (base.css), souligner trois titres de rang 4 créerait
   trois faux liens. On garde l'intention (marquer le début d'une sous-partie)
   en la traduisant dans le vocabulaire du site : un court trait doré posé
   au-dessus du titre. C'est aussi la seule apparition de l'accent doré dans
   ces quatre sections, donc très en deçà du plafond des 10 %.

   Taille = celle du corps, poids 700 : la hiérarchie se lit au POIDS et non
   à la taille (design-system §3), et un H4 plus gros que le corps sur trois
   sous-parties d'affilée écraserait le H3 qui les chapeaute.
   ------------------------------------------------------------------------- */
.psy-public__sous { margin-top: var(--space-lg); }
/* Le même composant est balisé <h4> dans « Adultes » (sous un H3 de volet)
   et <h3> dans « Enfants & Adolescents » (pas de H3 de volet, hiérarchie
   oblige). Rendu IDENTIQUE exigé : la classe fixe donc explicitement tout ce
   que base.css fait différer entre h3 et h4 — taille, interlignage, graisse
   ET l'approche (h3 : -0,006em, h4 : -0,012em hérité de h1..h4). */
.psy-public__soustitre {
  font-size: var(--fs-body);
  line-height: var(--lh-h3);
  font-weight: var(--fw-bold);
  letter-spacing: -0.012em;
  color: var(--vert-foret);
  margin-bottom: var(--space-2xs);
}
.psy-public__soustitre::before {
  content: "";
  display: block;
  width: 28px;
  height: 2px;
  background: var(--dore-tournesol);
  margin-bottom: var(--space-xs);
}

/* -------------------------------------------------------------------------
   Tarifs. Reprend trait pour trait le bloc de l'ancien accordéon (filet
   pointillé, label en capitales espacées) : les tarifs n'ont pas changé de
   nature en changeant de conteneur, et Thomas les avait validés publics le
   2026-09-01.
   Le groupe .psy-public__tarifs existe pour une raison précise : il sort les
   lignes de tarif de la portée de `.psy-public__texte > p`, qui justifie la
   prose des deux côtés (§0). Une ligne courte et justifiée s'étire en
   rivières de blancs ; les tarifs restent donc au fer à gauche.

   DEVENU UNE FICHE LE 2026-09-26 (audit DESIGNER #11, validé par Thomas
   pour essai). Les quatre publics enchaînaient quatre fois le même schéma
   (H2 + colonne de prose), soit 5 000 px en desktop dans la zone où l'on
   décide. Le bloc tarif devient une fiche :
   - libellé « Tarif », ligne de prix, condition d'annulation à 48 h, et un
     bouton « Prendre rendez-vous » vers #contact ;
   - surface --carte-bezel + --radius-lg, le seul système de carte du site
     (même parti que le plan d'accès de Contact) ;
   - EN DESKTOP (>= 1024 px) : colonne de droite de 20rem, COLLANTE
     (position: sticky) sous le header le temps de lire son volet. Chaque
     volet est sa propre grille, donc dans « Adultes » chacune des deux
     fiches reste collée à SON volet et cède la place à la suivante ;
   - EN DESSOUS : bloc normal dans le flux, à la fin du volet, bouton
     compris, exactement où était le tarif avant.
   TARIFS : textes repris AU CARACTÈRE PRÈS, et chaque tarif n'existe
   qu'UNE fois dans le DOM (la même fiche change de place selon la largeur,
   elle n'est jamais dupliquée).
   « APPROCHE GROUPALE » n'a pas de tarif (« À venir. ») : sa fiche garde le
   libellé et cette mention, SANS condition d'annulation (il n'y en a pas)
   et SANS bouton (proposer de réserver un groupe qui n'existe pas encore
   serait une fausse promesse). Classe --a-venir : ton plus discret.
   Fond de la fiche : crème sur les sections ivoire et brume, ivoire sur la
   seule section crème (Enfants & Adolescents), pour que la carte se
   détache toujours de son fond d'une teinte, jamais du même ton.
   ------------------------------------------------------------------------- */
.psy-public__tarifs {
  margin-top: var(--space-lg);
  padding: var(--space-base);
  border-radius: var(--radius-lg);
  background: var(--creme);
  box-shadow: var(--carte-bezel);
}
.psy-public--enfants .psy-public__tarifs { background: var(--ivoire); }
.psy-public__tarif {
  color: var(--vert-foret);
  font-weight: var(--fw-medium);
}
.psy-public__tarif-cond,
.psy-public__tarif-note { color: var(--encre-douce); }
.psy-public__tarif + .psy-public__tarif-cond { margin-top: var(--space-2xs); }
.psy-public__tarif-label {
  /* Sur sa propre ligne dans la fiche : c'est l'en-tête de la carte. */
  display: block;
  margin-bottom: var(--space-2xs);
  font-size: var(--fs-overline);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: var(--ls-overline);
  color: var(--vert-sauge);
}
.psy-public__fiche-cta {
  width: 100%;
  margin-top: var(--space-base);
  /* Cible tactile >= 44 px (le --sm seul en fait ~36). */
  min-height: 44px;
}
.psy-public__tarifs--a-venir .psy-public__tarif { color: var(--encre-douce); }

/* INFO PRATIQUE DANS LA FICHE, Enfants & Adolescents (prototype
   d'architecture #11, 2026-09-27). « Lors de la première consultation, la
   présence d'au moins un des parents est nécessaire » est une CONDITION, pas
   de la prose : elle rejoint la fiche, là où l'on décide. Phrase inchangée,
   icône Tabler `users` (celle de l'Approche), filet sous l'info. */
.psy-public__fiche-info {
  display: flex;
  gap: var(--space-xs);
  align-items: flex-start;
  margin-bottom: var(--space-base);
  padding-bottom: var(--space-base);
  border-bottom: 1px solid var(--vert-tendre);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  color: var(--encre);
}
.psy-public__fiche-icone { flex: none; color: var(--vert-sauge); margin-top: 0.1em; }
.psy-public__fiche-icone svg { width: 20px; height: 20px; }
/* Le paragraphe retiré laissait « Tout au long… » collé à la sous-partie. */
.psy-public--enfants .psy-public__sous + p { margin-top: var(--space-base); }

/* APPROCHE GROUPALE EN BANDEAU (prototype d'architecture #10, 2026-09-27).
   ~520 px pour une phrase et « Tarif : À venir » : la section la plus vide
   du site. Rythme vertical resserré (--space-xl au lieu de --section-y) et
   fiche discrète en pointillé, sans surface ni ombre : ce n'est pas une
   offre qu'on réserve. En desktop, une seule rangée (cf. le bloc media en
   fin de §7b). Ordre, fond et filigrane inchangés. Dès qu'Aurélie a le
   texte, ce bandeau peut redevenir une section complète. */
.psy-public--groupale { padding-block: var(--space-xl); }
.psy-public--groupale .psy-public__tarifs {
  box-shadow: none;
  background: transparent;
  border: 1px dashed var(--vert-tendre);
}

@media (min-width: 1024px) {
  /* Le couloir de lecture de 52rem s'élargit à tout le conteneur : la
     colonne de prose garde ~42rem (sous sa --measure de 68ch), la fiche
     prend les 20rem de droite.
     Grille à deux colonnes pour le grand numéro (#7) : numéro à gauche du
     surtitre + H2 (bas alignés : sa marge basse = celle du H2), tout le
     reste en pleine largeur. */
  .psy-public__corps {
    max-width: none;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--space-lg);
  }
  .psy-public__corps > * { grid-column: 1 / -1; }
  .psy-public__corps > .psy-public__num {
    grid-column: 1;
    grid-row: 1 / span 2;
    align-self: end;
    margin-bottom: var(--space-lg);
  }
  .psy-public__corps > .psy-public__surtitre { grid-column: 2; grid-row: 1; align-self: end; }
  .psy-public__corps > .psy-public__titre { grid-column: 2; grid-row: 2; }
  .psy-public__volet {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 20rem;
    column-gap: var(--space-2xl);
    /* start : la fiche ne s'étire pas sur toute la hauteur de la prose,
       c'est ce qui lui laisse la place de coller en descendant. */
    align-items: start;
  }
  .psy-public__tarifs {
    margin-top: 0;
    position: sticky;
    top: calc(var(--header-h) + var(--space-lg));
  }

  /* ALTERNANCE EN MIROIR (#8) : quatre fois « prose à gauche, fiche à
     droite », c'est la répétition qui rendait la zone monotone. Enfants &
     Adolescents passe la fiche à GAUCHE : droite, gauche, droite (Familiale,
     #9), puis le bandeau groupal. */
  .psy-public--enfants .psy-public__volet { grid-template-columns: 20rem minmax(0, 1fr); }
  .psy-public--enfants .psy-public__tarifs { grid-column: 1; grid-row: 1; }
  .psy-public--enfants .psy-public__texte  { grid-column: 2; grid-row: 1; }

  /* FAMILIALE (#9) : accroche en première rangée, trio pleine largeur, puis
     la conclusion avec la fiche EN REGARD. On lit les situations, ce que la
     consultation offre, puis le tarif. `display: contents` fait des enfants
     de .psy-public__texte des cellules de la grille du volet. La fiche n'a
     plus de prose à accompagner : elle ne colle pas. */
  .psy-public--familiale .psy-public__texte { display: contents; }
  .psy-public--familiale .psy-public__volet { row-gap: 0; }
  .psy-public--familiale .psy-public__accroche { grid-column: 1; grid-row: 1; }
  .psy-public--familiale .psy-public__trio { grid-column: 1 / -1; grid-row: 2; margin-block: var(--space-xl); }
  .psy-public--familiale .psy-public__texte > p:last-child { grid-column: 1; grid-row: 3; }
  .psy-public--familiale .psy-public__tarifs { grid-column: 2; grid-row: 3; position: static; }

  /* GROUPALE (#10) : une seule rangée, numéro · titre · annonce + fiche.
     128 px de marge verticale : assez pour que les filigranes des deux
     coutures (« Approche groupale » en haut, « Se mettre en mouvement » en
     bas) ne se touchent pas. */
  .psy-public--groupale { padding-block: var(--space-3xl); }
  .psy-public--groupale .psy-public__accroche { text-align: start; hyphens: manual; }
  .psy-public--groupale .psy-public__corps {
    grid-template-columns: auto minmax(0, 22rem) minmax(0, 1fr);
    align-items: center;
  }
  .psy-public--groupale .psy-public__titre { margin-bottom: calc(-1 * var(--encre-bas)); }
  .psy-public--groupale .psy-public__volet {
    grid-column: 3;
    grid-row: 1 / span 2;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
  }
  .psy-public--groupale .psy-public__tarifs { position: static; padding: var(--space-sm) var(--space-base); }
}

/* =========================================================================
   8. DIPLÔMES & FORMATIONS - liste chronologique simple (fond crème).
   Pas de cartes : diversité de layout après les quatre sections de prose
   du §7. Réutilise
   .psy-section-head (défini en §7).

   COUTURE HAUTE : depuis le 2026-09-26, la voisine du dessus est
   l'Approche (brume), déplacée juste avant. La couture brume/crème est
   franche ; le filigrane « Formation » y prend une compensation d'encre
   sur sa moitié haute (cf. §3c). Fond crème CONSERVÉ, et l'alternance tient
   aussi de l'autre côté (crème contre l'ivoire de Contact, inchangé).
   Conséquence à retenir si l'ordre des sections rebouge un jour : c'est
   .psy-approche qui tient le brume au-dessus de cette ligne.
   ========================================================================= */
.psy-formations { background: var(--creme); }
.psy-diplomes {
  list-style: none;
  margin: var(--space-2xl) auto 0;
  padding: 0;
  max-width: 46rem;
}
/* Grid (pas flex) : même technique que .psy-contact__list li. Avec flex-wrap,
   les libellés longs ("Formation APPEA, « Troubles de l'identité sexuée... »")
   font passer TOUT le 2e item à la ligne suivante au lieu de wrapper son texte
   sous l'année - bug constaté à la vérif visuelle 2026-09-01. */
.psy-diplomes li {
  display: grid;
  grid-template-columns: 6rem 1fr;
  gap: var(--space-base);
  align-items: baseline;
  padding-block: var(--space-sm);
  border-top: 1px solid var(--vert-tendre);
  color: var(--encre);
}
.psy-diplomes li:first-child { border-top: none; }
/* Années en Fraunces italique (prototype d'architecture #14) : la voix
   « signature » du site, qui donne un rythme à la colonne des dates. */
.psy-diplome__annee {
  font-family: var(--font-signature);
  font-variation-settings: var(--fvs-signature);
  font-style: italic;
  font-weight: var(--fw-medium);
  font-size: 1.15em;
  color: var(--vert-sauge);
  font-variant-numeric: tabular-nums;
}

/* EN-TÊTE COLLANT, DIPLÔMES DISTINGUÉS (prototype d'architecture #14,
   2026-09-27). Une liste centrée de 46rem sur un écran de 1 440 px, huit
   lignes identiques : le Master 2 et le DIU de Victimologie, qui fondent
   l'exercice, ne se distinguaient pas d'une formation d'une journée. Ils
   passent en encre forêt, graisse 600, avec un filet doré à gauche.
   En desktop : en-tête à gauche (collant), liste à droite. */
.psy-diplomes li.psy-diplome--majeur {
  color: var(--vert-foret);
  font-weight: var(--fw-semi);
  box-shadow: inset 3px 0 0 var(--dore-tournesol);
  padding-inline-start: var(--space-sm);
}
@media (min-width: 1024px) {
  .psy-formations > .container {
    display: grid;
    grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
    column-gap: var(--space-2xl);
    align-items: start;
  }
  .psy-formations .psy-section-head {
    text-align: start;
    margin: 0;
    position: sticky;
    top: calc(var(--header-h) + var(--space-lg));
  }
  .psy-formations .psy-section-head .t-overline { text-indent: 0; margin-inline: 0; }
  .psy-formations .psy-diplomes { margin: 0; max-width: none; }
}

/* =========================================================================
   9. CONTACT & INFOS PRATIQUES (fond ivoire)
   ========================================================================= */
.psy-contact { background: var(--ivoire); }
.psy-contact__grid {
  display: grid;
  gap: var(--space-2xl);
  align-items: start;
}
@media (min-width: 768px) {
  .psy-contact__grid { grid-template-columns: 1.1fr 0.9fr; gap: var(--space-3xl); }
}
/* min-width: 0 : sans lui, un item de grille ne descend pas sous son
   min-content. L'e-mail insécable de la fiche (~188 px) élargissait toute la
   colonne à 316 px à 320 px de viewport : 44 px débordaient, rognés sans
   bruit par l'overflow-x: clip de la section (bouton RDV coupé à droite). */
.psy-contact__grid > * { min-width: 0; }
.psy-contact__infos .t-overline { color: var(--vert-sauge); }
.psy-contact__infos h2 { margin-top: var(--space-2xs); }
.psy-contact__infos .t-lead { margin-top: var(--space-base); }

.psy-contact__list {
  list-style: none;
  margin: var(--space-lg) 0;
  padding: 0;
  display: grid;
  gap: var(--space-sm);
}
.psy-contact__list li {
  display: grid;
  grid-template-columns: 7rem 1fr;
  gap: var(--space-sm);
  /* start (pas baseline) : la ligne Téléphone empile lien + petite note,
     un alignement baseline sur un bloc multi-lignes lit de travers. */
  align-items: start;
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--vert-tendre);
}
.psy-contact__label {
  font-size: var(--fs-overline);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: var(--ls-overline);
  color: var(--vert-sauge);
}
/* Très petits écrans (< 375 px) : 7rem de label + gouttière ne laissent plus
   la place à l'e-mail entier. Le label passe AU-DESSUS de sa valeur plutôt
   que de couper « contact@aurelierey.com » en deux. anywhere = filet ultime. */
.psy-contact__list li > * { min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 374px) {
  .psy-contact__list li { grid-template-columns: 1fr; gap: var(--space-3xs); }
}
/* Valeur multi-lignes (ex. Téléphone : lien + note) : empilée, même colonne. */
.psy-contact__value {
  display: grid;
  gap: var(--space-3xs);
}

/* Duo de CTA : RDV en ligne (primaire) + email (ghost, pas de doublon
   d'intention entre deux boutons primaires - cf. pre-flight anti-slop).
   L'ACTION AVANT LA FICHE (audit DESIGNER #16, 2026-09-26) : les boutons
   (et la mention du secret professionnel, qui les rassure) passent juste
   sous le chapeau, AVANT la liste des coordonnées. Sur mobile ils
   arrivaient ~600 px sous le titre « Prendre rendez-vous » ; le titre tient
   maintenant sa promesse dans le même écran. */
.psy-contact__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}
/* DUO EMPILÉ, MÊME LARGEUR (2026-09-27, bouton renommé « Contacter Aurélie
   Rey ») : la colonne Contact est trop étroite pour les deux boutons côte à
   côte à TOUTES les largeurs (ils s'empilaient déjà par flex-wrap), mais avec
   deux largeurs différentes et un « Prendre rendez-vous en ligne » cassé sur
   deux lignes à 320-360 et vers 768 px (48 px de padding latéral dans une
   colonne de ~330 px). On assume donc la pile : une seule colonne de grille,
   calée sur le bouton le plus large, les deux pilules alignées bord à bord.
   Padding latéral resserré (32 px, 24 px sous 1024, 16 px sous 480) : il ne sert que de marge minimale, le
   texte reste centré. Mobile : pleine largeur, comme les CTA du hero. */
@supports (display: grid) {
  .psy-contact__actions {
    display: grid;
    grid-template-columns: minmax(0, auto);
    justify-content: start;
  }
  .psy-contact__actions .psy-btn { padding-inline: var(--space-md); }
}
@media (max-width: 767px) {
  .psy-contact__actions { justify-content: stretch; }
}
/* 768-1023 : la colonne ne fait que ~300 px ; 24 px de padding suffisent à
   garder « Prendre rendez-vous en ligne » sur une ligne. */
@media (max-width: 1023px) {
  .psy-contact__actions .psy-btn { padding-inline: var(--space-base); }
}
@media (max-width: 479px) {
  .psy-contact__actions .psy-btn { padding-inline: var(--space-sm); }
}

/* Invite douce au-dessus des boutons de RDV */
.psy-contact__note {
  margin-bottom: var(--space-base);
  max-width: 48ch;
}

/* Mention secret professionnel, entre le bouton et l'encart urgence */
.psy-contact__secret {
  margin-top: var(--space-sm);
  color: var(--encre-douce);
}

.psy-contact__urgence {
  margin-top: var(--space-lg);
  padding: var(--space-base);
  border-radius: var(--radius-md);
  background: var(--vert-brume);
  color: var(--encre);
  border-left: 3px solid var(--vert-sauge);
  max-width: none;
}
/* Les numéros d'urgence LISIBLES D'UN COUP D'ŒIL (prototype d'architecture
   #16) : dans quatre lignes en petit corps, 15, 3114 et 119 se perdaient.
   Ce sont les seules informations qu'une personne en détresse doit trouver
   en une seconde : grossis dans le texte, rien d'autre ne change. */
.psy-contact__urgence strong {
  color: var(--vert-foret);
  font-size: 1.4em;
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
}

/* PLAN D'ACCÈS, CHARGEMENT AU CLIC (2026-09-27, remplace le placeholder
   brume + picto + légende). Cf. le commentaire d'index.html et site.js
   §2quinquies. Au chargement : aperçu statique hébergé (tuiles OSM teintées
   dans la palette) + bouton. Au clic : l'iframe Google prend EXACTEMENT la
   place de l'aperçu, dans la même boîte à aspect-ratio fixe : aucun saut.
   - 4:3 sous 1024 px (img/plan-acces.webp, 480x360), carré au-delà
     (img/plan-acces-carre.webp, 560x560, via <picture>) : chaque recadrage
     garde le repère au même endroit, rien n'est rogné par object-fit.
   - Le repère est à ~40 % de la hauteur : le bouton, en bas, ne le couvre
     jamais. */
.psy-contact__plan {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--radius-lg); /* squircle (système de radius unique) */
  background: var(--vert-brume); /* visible le temps que l'iframe charge */
  box-shadow: var(--carte-bezel);
}
.psy-contact__plan picture,
.psy-contact__plan-img,
.psy-contact__plan iframe {
  display: block;
  width: 100%;
  height: 100%;
}
.psy-contact__plan-img { object-fit: cover; }
.psy-contact__plan iframe { border: 0; }

/* Attribution OSM (licence ODbL) : obligatoire, TOUJOURS visible sur
   l'aperçu. Pastille crème opaque : encre-douce sur crème = 7,6:1, quel que
   soit le plan dessous. */
.psy-contact__plan-osm {
  position: absolute;
  top: var(--space-2xs);
  right: var(--space-2xs);
  margin: 0;
  max-width: none;
  padding: 2px var(--space-2xs);
  border-radius: var(--radius-sm);
  background: var(--creme);
  font-size: 0.6875rem; /* 11 px : mention légale, pas du contenu */
  line-height: 1.3;
}
.psy-contact__plan-osm a { color: var(--encre-douce); }

/* Le bouton (ou, sans JS, le lien vers la fiche) posé en bas, centré.
   Centrage par inset + margin auto + width: max-content, PAS par left: 50%
   + translateX(-50%) : avec left: 50%, la largeur « shrink-to-fit » d'un
   élément absolu est bornée à la moitié droite du plan, et le libellé
   passait sur deux lignes à 390 px. Le survol garde ainsi le translateY
   standard de .psy-btn. */
.psy-contact__plan-btn {
  position: absolute;
  inset-inline: 0;
  bottom: var(--space-base);
  margin-inline: auto;
  width: max-content;
  max-width: calc(100% - 2 * var(--space-sm));
  min-height: 44px; /* cible tactile confortable (taille --sm = 34 px) */
  text-align: center;
  line-height: 1.25;
}
/* L'ombre de .psy-btn--primary (même spécificité, déclarée après base.css)
   écraserait l'anneau de focus global : on le repose explicitement. */
.psy-contact__plan-btn:focus-visible { box-shadow: var(--focus-ring); }
.psy-contact__plan-btn[hidden] { display: none; }

.psy-contact__plan-info {
  margin-top: var(--space-xs);
  color: var(--encre-douce);
}
.psy-contact__plan-info[hidden] { display: none; }

/* Itinéraire + fiche : deux liens texte, toujours là, hors de l'iframe. */
.psy-contact__plan-liens {
  list-style: none;
  margin: var(--space-sm) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-base);
  font-size: var(--fs-small);
  font-weight: var(--fw-semi);
}
.psy-contact__plan-liens a { color: var(--vert-foret); }

/* Mention « (nouvel onglet) » : lue par les lecteurs d'écran, invisible. */
.psy-contact__nouvel-onglet {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* COLONNE « VENIR AU CABINET » (prototype d'architecture #15, 2026-09-27).
   Avant : à droite un plan de 320 px de haut puis ~1 000 px de vide, à
   gauche tout le reste. Adresse et Horaires (les mêmes <li>, déplacés)
   rejoignent le plan ; la colonne de gauche garde l'action et le contact
   (boutons, e-mail, téléphone, tarifs, urgence). En desktop le plan passe
   au CARRÉ et la colonne colle sous le header. Section ~1 505 -> ~1 290 px. */
@media (min-width: 1024px) {
  .psy-contact__cabinet {
    position: sticky;
    top: calc(var(--header-h) + var(--space-lg));
  }
  .psy-contact__cabinet .psy-contact__plan { aspect-ratio: 1 / 1; }
}

/* =========================================================================
   10. FOOTER - sobre, fond vert forêt
   ========================================================================= */
.psy-footer { background: var(--vert-foret); color: var(--creme); padding-block: var(--space-2xl) var(--space-lg); }
.psy-footer__grid {
  display: grid;
  gap: var(--space-xl);
}
@media (min-width: 768px) {
  .psy-footer__grid { grid-template-columns: 1.2fr 1fr; align-items: start; }
}
/* LA SIGNATURE EN LOGO (2026-09-27, demande d'Aurélie) : le wordmark texte
   Fraunces du prototype d'architecture #17 (nom passé de ~26 à 58 px pour
   signer le grand aplat forêt) est remplacé par le LOGO, comme dans le hero.
   Variante VF-10, encre crème #EFE7DB (9,4:1 sur --vert-foret) : le sauge de
   logo-hero.png / logo-header.png serait illisible ici. Fichier 720x215
   (2x la largeur max), détouré sur la bounding box alpha.
   Taille : la même présence que le nom en 58 px (le script « Aurélie Rey »
   mesure ~65 px de haut à 360 px de large), sans concurrencer le hero, qui
   monte à 608 px. 240 px sur petit mobile, 360 px au-delà de ~1200 px. */
.psy-footer__wordmark {
  margin: 0;
  line-height: 0;
}
.psy-footer__logo {
  display: block;
  width: clamp(15rem, 11rem + 9vw, 22.5rem);
  max-width: 100%;
  height: auto;
}
/* Ligne de rôle « Psychologue clinicienne & psychothérapeute » RETIRÉE le
   2026-09-27 (décision Thomas) : elle doublait la baseline du logo, juste
   au-dessus. « psychothérapeute » reste porté par l'alt du logo et par le
   texte de « Qui suis-je ». */
.psy-footer__legal { color: var(--vert-tendre); margin-top: var(--space-2xs); }
/* Première ligne après le logo : l'image n'a pas d'interligne, l'écart de
   8 px entre deux lignes de coordonnées collerait l'e-mail au logo. */
.psy-footer__wordmark + .psy-footer__legal { margin-top: var(--space-sm); }
/* Lien email du footer : la couleur de lien globale (vert forêt) serait
   invisible sur le fond forêt. Même traitement que les liens de nav. */
.psy-footer__legal a { color: var(--vert-brume); text-decoration-color: rgb(var(--creme-rgb) / 0.4); }
.psy-footer__legal a:hover { color: var(--creme); text-decoration-color: var(--dore-tournesol); }

.psy-footer__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xl);
}
.psy-footer__nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-xs);
  /* les rangées de la colonne courte (2 liens) ne doivent pas s'étirer sur la
     hauteur de la colonne voisine (4 liens) : on tasse en haut */
  align-content: start;
}
.psy-footer__nav a { color: var(--vert-brume); text-decoration: none; font-size: var(--fs-small); }
.psy-footer__nav a:hover { color: var(--creme); text-decoration: underline; text-decoration-color: var(--dore-tournesol); }
/* Page en cours (pages légales, 2026-09-27) : crème + soulignement doré
   permanent, soit l'état de survol figé. Le signal ne repose pas sur la
   couleur seule (soulignement), et aria-current le porte pour les lecteurs
   d'écran. */
.psy-footer__nav a[aria-current="page"] {
  color: var(--creme);
  text-decoration: underline;
  text-decoration-color: var(--dore-tournesol);
  text-underline-offset: 0.25em;
}

.psy-footer__bottom {
  margin-top: var(--space-xl);
  padding-top: var(--space-base);
  border-top: 1px solid rgb(var(--creme-rgb) / 0.18);
}
.psy-footer__bottom .t-small { color: var(--vert-tendre); }

/* =========================================================================
   10b. PAGES LÉGALES (.psy-legal) - 2026-09-27
   mentions-legales.html + politique-de-confidentialite.html. Pages de
   LECTURE : même header, même footer, mais ni hero, ni mots-échos, ni
   filigrane, ni bulles, ni reveals, ni champ de pollen (du mouvement
   permanent derrière un texte juridique à lire en entier gêne la lecture
   sans rien raconter). Fond crème uni.

   TITRES :
   - <h1> en Hurricane (la cursive des titres de section de l'accueil) :
     c'est le seul moment « signature » de la page, un titre court, en
     grand, au-dessus de la ligne de flottaison (police préchargée).
   - <h2> en Plus Jakarta Sans 700, PAS en Hurricane. Une page juridique se
     PARCOURT : on cherche « Hébergement » ou « Vos droits » d'un coup
     d'œil. Dix titres cursifs de 44 à 62 px, souvent longs (« Transferts
     hors de l'Union européenne »), noieraient la structure et étireraient
     la page. La règle h2 de base.css (cursive) est donc surchargée ici,
     scopée à .psy-legal, sans toucher à l'accueil.
   - <h3> Plus Jakarta Sans 600, plus petit : la hiérarchie se lit au poids
     et à la taille, comme le veut le design system.

   COLONNE : 34em, soit ~68 signes par ligne en médiane dès 768 px (mesuré
   au rendu à 768, 1440 et 2560 ; à 390 px c'est l'écran qui borne, ~40). Texte au fer à gauche, sans justification : le
   justifié de l'accueil creuserait des rivières autour des références
   d'articles et des adresses web.
   ========================================================================= */
.psy-legal {
  padding-block: var(--space-xl) var(--space-2xl);
}
/* Cible du lien d'évitement (tabindex="-1") : pas d'anneau de focus sur un
   conteneur de page entier. */
.psy-legal:focus { outline: none; }
.psy-legal:focus-visible { box-shadow: none; }

/* Ancres : sous le header sticky (Lenis ne gère que les liens internes à
   la page ; ceci couvre l'arrivée depuis une autre page, ex. le lien
   « politique de confidentialité » sous le bouton de la carte). */
.psy-legal,
.psy-legal [id] {
  scroll-margin-top: calc(var(--header-h) + var(--space-sm));
}

.psy-legal__page {
  /* En em (corps fluide 16 -> 18 px) et non en rem : la colonne suit la
     taille du texte, donc le nombre de signes par ligne reste stable
     d'une largeur d'écran à l'autre (~68 signes mesurés). */
  --legal-mesure: 34em;
  max-width: calc(var(--legal-mesure) + 2 * var(--gutter));
  overflow-wrap: break-word;
}
/* base.css borne tout <p> à --measure : la colonne s'en charge déjà.
   text-wrap: pretty : pas de ponctuation haute orpheline en dernière ligne
   (« … en obtenir une copie » puis « ; » seul, constaté à 1440 px), sans
   toucher au texte (les espaces avant « ; » et « : » restent normales). */
.psy-legal p,
.psy-legal li { max-width: none; text-wrap: pretty; }
/* Adresses web longues (policies.google.com/privacy) : coupure permise
   plutôt qu'un débordement horizontal à 320 px. */
.psy-legal a { overflow-wrap: anywhere; }

/* --- En-tête de page ---------------------------------------------------- */
.psy-legal__tete {
  padding-bottom: var(--space-lg);
  margin-bottom: var(--space-lg);
  border-bottom: 1px solid var(--vert-tendre);
}
.psy-legal__titre {
  font-family: var(--font-manuscrite);
  font-size: clamp(3rem, 2.4rem + 2.6vw, 4.5rem); /* 48 -> 72 */
  line-height: var(--lh-h2-manuscrit);
  font-weight: 400;
  font-synthesis: none;
  letter-spacing: normal;
  -webkit-font-smoothing: auto;
  -moz-osx-font-smoothing: auto;
  /* Même réserve d'encre que les H2 cursifs (base.css, h2, 2026-09-28) :
     la boîte englobe les boucles de Hurricane, le texte ne bouge pas. */
  --encre-g: 0.3em;
  --encre-d: 0.4em;
  --encre-bas: 0.06em;
  padding: 0 var(--encre-d) var(--encre-bas) var(--encre-g);
  margin-inline: calc(-1 * var(--encre-g)) calc(-1 * var(--encre-d));
  margin-bottom: calc(var(--space-sm) - var(--encre-bas));
}
.psy-legal__intro {
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: var(--texte-doux);
  text-wrap: pretty;
}

/* --- Rythme vertical ------------------------------------------------------ */
.psy-legal__section + .psy-legal__section { margin-top: var(--space-xl); }
.psy-legal__section > * + * { margin-top: var(--space-sm); }

.psy-legal h2 {
  font-family: var(--font-titre);
  font-size: clamp(1.375rem, 1.2rem + 0.75vw, 1.75rem); /* 22 -> 28 */
  line-height: 1.25;
  font-weight: var(--fw-bold);
  font-synthesis: weight style;
  letter-spacing: -0.012em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Grotesk, pas Hurricane : aucune réserve d'encre (cf. base.css, h2). */
  padding: 0;
  margin-inline: 0;
  margin-bottom: 0;
}
.psy-legal__section > h2 + * { margin-top: var(--space-base); }
.psy-legal h3 {
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.1875rem); /* 17 -> 19 */
  line-height: var(--lh-h3);
  font-weight: var(--fw-semi);
}
.psy-legal__section > h3 { margin-top: var(--space-lg); }
.psy-legal__section > h2 + h3 { margin-top: var(--space-base); }
.psy-legal__section > h3 + * { margin-top: var(--space-2xs); }

.psy-legal ul { padding-left: 1.25em; }
.psy-legal li + li { margin-top: var(--space-2xs); }
.psy-legal li::marker { color: var(--vert-sauge); }
.psy-legal strong { font-weight: var(--fw-semi); color: var(--encre); }

/* Blocs d'adresse (hébergeur, responsable du traitement, CNIL) : filet
   vertical, comme une fiche. */
.psy-legal__bloc {
  border-inline-start: 2px solid var(--vert-tendre);
  padding-inline-start: var(--space-sm);
}

.psy-legal__filet {
  border: 0;
  border-top: 1px solid var(--vert-tendre);
  margin-block: var(--space-xl) var(--space-base);
}
.psy-legal__maj {
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  color: var(--texte-doux);
}

/* --- Tableaux (tarifs, durées de conservation) --------------------------
   Nom accessible : aria-labelledby vers le titre qui précède (pas de
   <caption> qui le répéterait). Rôles ARIA explicites dans le HTML : ils
   gardent la sémantique de tableau quand, sous 40em, les lignes sont
   empilées en fiches (display: block), ce que Safari ne fait pas seul. */
.psy-legal__tableau {
  background: var(--ivoire);
  border-radius: var(--radius-md);
  padding: var(--space-2xs) var(--space-base);
}
.psy-legal table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
.psy-legal th,
.psy-legal td {
  text-align: start;
  vertical-align: top;
  padding: var(--space-xs) var(--space-sm) var(--space-xs) 0;
}
.psy-legal th:last-child,
.psy-legal td:last-child { padding-inline-end: 0; }
.psy-legal thead th {
  font-weight: var(--fw-bold);
  color: var(--vert-foret);
  border-bottom: 2px solid var(--vert-tendre);
}
.psy-legal tbody tr + tr { border-top: 1px solid rgb(var(--vert-tendre-rgb) / 0.6); }
.psy-legal tbody th {
  font-weight: var(--fw-semi);
  color: var(--encre);
}
.psy-legal td[data-label="Tarif"] {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 39.99em) {
  .psy-legal__tableau { padding: var(--space-3xs) var(--space-sm); }
  .psy-legal table,
  .psy-legal tbody,
  .psy-legal tr,
  .psy-legal th,
  .psy-legal td { display: block; }
  /* En-têtes de colonnes : masqués à l'écran, gardés pour les lecteurs
     d'écran (motif « visually hidden », cf. .psy-sr en §0). */
  .psy-legal thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .psy-legal tbody tr { padding-block: var(--space-sm); }
  .psy-legal tbody th,
  .psy-legal td { padding: 0; }
  .psy-legal tbody th { font-size: var(--fs-body); margin-bottom: var(--space-3xs); }
  .psy-legal td + td { margin-top: var(--space-3xs); }
  .psy-legal td[data-label="Tarif"] { white-space: normal; }
  /* Libellé de colonne devant chaque valeur. Deuxième déclaration = texte
     alternatif VIDE (content: ... / "") : le libellé est vu, pas relu par
     les lecteurs d'écran, qui annoncent déjà l'en-tête de colonne. Les
     navigateurs sans cette syntaxe gardent la première déclaration. */
  .psy-legal td[data-label]::before {
    content: attr(data-label) " : ";
    content: attr(data-label) " : " / "";
    font-weight: var(--fw-semi);
    color: var(--texte-doux);
  }
}

/* --- Emplacements à compléter --------------------------------------------
   <mark class="psy-a-completer">[A COMPLETER : …]</mark> : repérables d'un
   coup d'œil sur la préprod. Fond doré léger + liseré doré ; le texte
   reste à l'encre (contraste mesuré sur crème ET sur ivoire, cf. compte
   rendu). inline-block : la mention forme UN bloc, jamais coupée entre
   « [À » et « COMPLÉTER » en fin de ligne ; une mention plus longue que la
   ligne se replie DANS son bloc (max-width 100 %). On garde des espaces
   normales dans le texte : un grep sur le libellé accentué doit tout
   retrouver (ce commentaire l'écrit sans accents, « A COMPLETER », pour
   ne pas sortir dans la recherche). À la mise en ligne, ce grep sur src/
   ne doit plus rien renvoyer. */
.psy-a-completer {
  display: inline-block;
  max-width: 100%;
  vertical-align: baseline;
  background: rgb(var(--dore-rgb) / 0.24);
  color: var(--encre);
  font-weight: var(--fw-medium);
  padding: 0.05em 0.35em;
  border-radius: calc(var(--radius-sm) / 2);
  box-shadow: inset 0 0 0 1px rgb(var(--dore-rgb) / 0.75);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* =========================================================================
   11. prefers-reduced-motion - TOUJOURS EN DERNIER
   Contenu visible (reveals annulés), pas de boucles.
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  .psy [data-reveal] { opacity: 1 !important; transform: none !important; filter: none !important; transition: none !important; will-change: auto !important; }
  .psy-pollen { display: none; }
  /* Mots-échos du hero (§3a) : purement décoratif et animé en boucle -> on
     masque entièrement plutôt que de figer une opacité, même logique que
     .psy-pollen juste au-dessus (aucun des deux calques ne porte de sens). */
  .psy-hero__mots { display: none; }
  /* Filigranes de section (§3c). Depuis le 2026-09-12 ils sont MODULÉS AU
     SCROLL (opacité de groupe + glissade horizontale, toutes deux pilotées
     par la position du mot dans l'écran) : il y a donc désormais quelque
     chose à neutraliser ici. `animation: none` coupe le scrub et rend la main
     au `opacity: 1` déclaré en §3c ET à l'absence de transform sur le
     conteneur, soit exactement le rendu statique validé : mot à sa POSITION
     FINALE, pleinement visible - aucune valeur de fill-mode ne survit, donc
     aucun risque de rester bloqué à 0 ni décalé sur le côté.
     Surtout PAS `display: none` comme pour .psy-pollen et .psy-hero__mots
     juste au-dessus : ces deux calques sont des boucles sans fin et sans
     propos, tandis que le filigrane PORTE le titre de sa section et tient la
     composition. Demander moins de mouvement n'est pas demander la
     disparition du décor. */
  .psy-filigrane { animation: none; }
  /* Bulles mots-clés (§6) : TOUT LE MOUVEMENT D'AMBIANCE disparaît, la
     MATIÈRE reste. Depuis la 2e passe du 2026-09-12 il y a quatre effets à
     traiter, et ils ne se traitent pas de la même façon.

     COUPÉS — les trois qui bougent tout seuls, sans que l'utilisateur ait rien
     demandé : le flottement permanent, la parallaxe au scroll et la glissade
     des deux éclats. `animation: none` suffit et est exact pour les trois : la
     keyframe de repos de chacune est la valeur neutre (translate/transform à
     zéro, éclats à leur position dessinée), il n'y a donc rien à réécrire et
     aucun risque de bulle ou d'éclat figé de travers.

     COUPÉE AUSSI — la poussée des voisines. Elle n'est pas une animation mais
     une transition pilotée par --pousse-x / --pousse-y : `transform: none` la
     neutralise ici, et site.js §2ter n'attache de toute façon aucun
     écouteur en reduced-motion (double verrou, volontaire : le CSS protège si
     le JS venait à changer, le JS évite de faire tourner du calcul pour rien).

     GARDÉ, en plus sobre — le grossissement au survol. Ce n'est pas de
     l'animation d'ambiance : c'est le RETOUR d'une action délibérée de
     l'utilisateur, au même titre qu'un changement de couleur au survol d'un
     lien. Le supprimer retirerait un signal d'interface sans rien apaiser.
     Il est donc conservé, ramené de 1,065 à 1,03 et raccourci à --dur-micro,
     et sa transition d'ombre est retirée (c'était l'effet de décollement,
     lui purement décoratif). Une bascule instantanée aurait été un choix
     défendable mais plus dur à l'œil qu'un fondu de 200 ms.

     Surtout pas `display: none` ni retour à l'aplat opaque, contrairement à
     .psy-pollen / .psy-hero__mots plus haut : ces 23 pastilles PORTENT du
     contenu (les motifs de consultation), leur aspect n'est pas du décor.
     Demander moins de mouvement n'est pas demander un autre design. */
  .psy-motscles,
  .psy-motscles li { animation: none; transform: none; }
  .psy-motscles__bulle,
  .psy-motscles__bulle::before,
  .psy-motscles__bulle::after { animation: none; }
  .psy-motscles__bulle { transition: scale var(--dur-micro) var(--ease-doux); }
  /* En reduced-motion le JS du §2ter ne s'installe pas : le grossissement
     sobre reste sur `:hover` natif (pas de poussée, donc rien de coûteux au
     défilement), avec le passage au-dessus des voisines que portait avant
     la règle `li:hover` du §6, désormais `li.is-survolee`. */
  .psy-motscles li:hover { z-index: 3; }
  .psy-motscles li:hover .psy-motscles__bulle { scale: 1.03; box-shadow: var(--bulle-ombre); }
  /* Tiroir mobile : apparition/disparition franche, sans glissade ni fondu.
     (La bascule de `visibility` reste immédiate, donc pas de piège de focus.) */
  .psy-nav__list,
  .psy-nav__scrim { transition: none; }
  /* Sommaire « Pour qui » (§7a) : le survol ne fait plus glisser le titre ni
     descendre la flèche. Le changement de COULEUR au survol est conservé,
     comme sur les liens du site : c'est un signal d'interface, pas du
     mouvement d'ambiance.
     (Remplace le réglage de l'accordéon <details>/<summary> qui occupait ces
     lignes jusqu'au 2026-09-15 : il n'existe plus.) */
  .psy-acces__titre,
  .psy-acces__fleche { transition: none; transform: none !important; }
}

/* Fallback no-JS : si le JS ne tourne pas, on rend les reveals visibles.
   (.psy.no-js posé par défaut, retiré par site.js - voir §0 du JS.) */
.psy.no-js [data-reveal] { opacity: 1; transform: none; filter: none; will-change: auto; }
