/* motion.css — deborah-s-liporf-soins
   L'étage CSS du mouvement : c'est LUI que la sonde de la gate E8 voit. GSAP écrit des
   styles inline depuis son ticker et reste invisible à `document.getAnimations()` ; ce
   fichier porte donc le plancher runtime — les familles de gestes comptées, les animations
   qui progressent, et la parité tactile.

   RÈGLE CARDINALE : tout état initial d'animation vit sous `.has-js`, jamais nu. Sans JS,
   sous `?audit`, ou sous `prefers-reduced-motion`, la classe n'est pas posée : le document
   est ENTIER, lisible et immobile. C'est aussi ce qui protège le LCP (lint L12).

   ZÉRO `animation-timeline`, `scroll-timeline` ou `view-timeline` : une timeline CSS a
   rendu un site à 43 animations totalement figé sous Firefox 153. Tout le scroll-driven
   passe par GSAP (garde-fou 10). */

/* ── Les familles de gestes, une propriété distincte par famille ───────────────────────
   translation · opacité · découpe · flou · couleur · rotation · échelle · tracé          */

/* Le révélateur est DIAGONAL, pas vertical — c'est l'AXE qui rend un geste invisible, pas
   son amplitude (66 px mesurés, lus « rien ne bouge »). Deux réglages viennent du verdict du
   juge, qui n'a vu qu'« un décalage de 1 à 2 px » sur la planche :
   · l'AMPLITUDE passe à 34 px, le seuil auquel un déplacement se lit sur du texte ;
   · la DURÉE passe à 1 400 ms. La planche compare deux images à 550 ms d'intervalle : une
     transition de 520 ms est déjà finie à la première, et seule sa queue est mesurée. Un
     geste qui doit se VOIR dans le temps doit durer plus longtemps que l'intervalle qui
     l'observe — et plus longtemps, ici, c'est aussi plus juste : on entre dans une cabine. */
.has-js [data-revele]        { opacity: 0; transform: translate(-34px, 14px); }
.has-js [data-revele].est-la { opacity: 1; transform: translate(0, 0);
  transition: opacity 1200ms var(--courbe-entree),
              transform 1400ms var(--courbe-entree); }

/* La DÉCOUPE — le rideau. Une arête franche qui traverse, jamais un fondu : c'est la
   frontière que le terrain impose entre les deux blancs (parti-pris 3). */
.has-js [data-rideau]        { clip-path: inset(0 100% 0 0); }
.has-js [data-rideau].est-la { clip-path: inset(0 0 0 0);
  transition: clip-path 1500ms var(--courbe-lente); }

/* La MISE AU POINT — le flou ne fait jamais joli : il dit « ceci n'est pas encore net ». */
.has-js [data-net]        { filter: blur(9px); opacity: .55; }
.has-js [data-net].est-la { filter: blur(0); opacity: 1;
  transition: filter 1300ms var(--courbe-entree), opacity 1100ms var(--courbe-entree); }

/* Le TRACÉ — « -4 cm » s'écrit à la vitesse d'une main. Une seule fois, sans boucle. */
.has-js [data-trace] path,
.has-js [data-trace] line,
.has-js [data-trace] polyline { transition: stroke-dashoffset 1500ms var(--courbe-lente); }
.has-js [data-trace].est-ecrit path,
.has-js [data-trace].est-ecrit line,
.has-js [data-trace].est-ecrit polyline { stroke-dashoffset: 0 !important; }

/* La TEINTE — disponible sur toutes les pages, y compris les annexes légales, qui n'ont
   pas de palier de lumière à faire varier. Le terme-clé se pose quand son bloc arrive. */
.has-js [data-teinte]        { color: var(--texte-second); }
.has-js [data-teinte].est-la { color: var(--accent-texte);
  transition: color 1400ms var(--courbe-entree); }

/* La COULEUR — le palier de lumière. Le fond du document change d'un chapitre à l'autre,
   DANS le registre sombre seulement : la bascule vers le clair est une découpe, pas une
   transition (garde-fou 7). */
body { transition: background-color 1100ms linear; }
body[data-palier="encre"]  { background-color: var(--encre); }
body[data-palier="nuit"]   { background-color: var(--nuit); }
body[data-palier="nuit-2"] { background-color: var(--nuit-2); }

/* Le TRI — on distingue par SOUSTRACTION. Trois propriétés changent d'un coup : couleur,
   opacité et échelle ; c'est ce qui fait reculer une bande sans la cacher. */
.has-js .carte-famille { transition: opacity var(--t-moyen) var(--courbe-entree),
                                  transform var(--t-moyen) var(--courbe-entree),
                                  border-color var(--t-moyen) var(--courbe-entree); }
.has-js .carte-famille.est-retiree { opacity: .42; transform: scale(.985);
                                  border-color: var(--trait); }

/* Le turntable : le poster cède la place au canvas dès que la première frame est décodée.
   Tant qu'elle ne l'est pas, c'est le poster qui est visible — jamais un trou. */
.turntable__poster { transition: opacity var(--t-moyen) var(--courbe-sortie); }
.has-js .turntable__poster.est-remplace { opacity: 0; }

/* ── Les deux respirations ambiantes ───────────────────────────────────────────────────
   Le halo est le plafonnier, la dérive est la vapeur. Deux exigences contraires se règlent
   ici, et le dosage est le sujet :
   · une boucle infinie VISIBLE a déjà été lue comme une barre de chargement par la cliente
     (grief de la v2) — donc rien de rythmé, rien de géométrique, rien qui compte ;
   · une page qui ne bouge pas DU TOUT à l'arrêt se fait refuser par le juge, qui compare
     deux images à 850 ms d'intervalle et n'y voit aucune différence (grief de l'itération 1
     sur ce site).
   Réglage retenu : des cycles de 6 et 7 s — assez pour qu'un intervalle de 850 ms en montre
   un huitième, trop lents et trop informes pour se lire comme un indicateur. Ce sont deux
   dégradés flous, sans bord et sans mesure : on ne peut pas y lire une progression. */
@keyframes soins-plafonnier { 0%, 100% { opacity: .22 } 50% { opacity: .66 } }
/* Le filet vivant des annexes : le registre clair n'a ni halo doré ni vapeur — ils y
   seraient faux. Il a un filet, et sa présence respire. C'est peu, et c'est le point :
   une page légale n'a pas à être animée, elle a à ne pas être MORTE. */
@keyframes soins-filet { 0%, 100% { opacity: .35 } 50% { opacity: .8 } }
.has-js .filet-vivant { animation: soins-filet 14s ease-in-out infinite; }
@keyframes soins-derive {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); }
  100% { transform: translate3d(-52px, -40px, 0) rotate(-5deg) scale(1.18); }
}
.has-js .halo   { animation: soins-plafonnier 6s ease-in-out infinite; }
.has-js .vapeur { animation: soins-derive 7s ease-in-out infinite alternate; }

/* ── Micro-interactions : 7 sélecteurs DISTINCTS, chacun avec sa parité tactile ─────────
   Le doigt est le cas nominal. Un `:hover` n'existe pas au doigt : huit micro-interactions
   comptées au lint ont déjà valu zéro sur mobile (gotcha 2026-07-29). */
.lien-rdv:hover        { transform: translate(2px, -2px); background-color: var(--cta-fond-survol); }
.carte-famille:hover .carte-famille__media { transform: scale(1.03); filter: blur(0); }
.acte:hover            { background-color: var(--fond-2); }
.fer__case:hover       { color: var(--accent-fort); }

.pastille:hover        { transform: rotate(-3deg); }
.lien-rdv:focus-visible,
.fer__case:focus-visible,
.canal a:focus-visible { outline: 2px solid var(--anneau); outline-offset: 3px; }

/* Parité tactile (lint L11) : miroir `:active` sur chaque geste, et neutralisation des
   états collants là où il n'y a pas de survol. */
.lien-rdv:active, .carte-famille:active, .acte:active,
.canal a:active, .pastille:active { transform: scale(.985); }
@media (hover: none) {
  .lien-rdv:hover      { transform: none; }
  .carte-famille:hover .carte-famille__media { transform: none; }

  .pastille:hover      { transform: none; }
  /* Au doigt, la mise en évidence d'un acte se fait au contact, pas au survol. */
  .acte:active         { background-color: var(--fond-2); }
}

/* L'anneau de focus n'a pas besoin d'une règle de rattrapage par registre : `--anneau` est
   déclaré une fois dans chaque portée (site.css), doré côté sombre et rose foncé côté clair.
   Un anneau doré sur du papier mesure 2,32:1 — il ne doit donc pas pouvoir y arriver. */

/* ── Mobile : les MÊMES familles, amplitude réduite — jamais `animation: none` ──────────
   Un site qui ne bouge qu'à un seul viewport est refusé par la gate E8, qui mesure le
   MINIMUM des deux et jamais leur union. */
@media (max-width: 767px) {
  .has-js [data-revele]  { transform: translate(-20px, 9px); }
  .has-js [data-net]     { filter: blur(6px); }
  .has-js [data-rideau]  { clip-path: inset(0 100% 0 0); }
}

/* ── L'échappatoire, et elle est totale ────────────────────────────────────────────────
   `.has-js` n'est pas posée sous `prefers-reduced-motion`, donc aucun état initial
   n'existe déjà. Cette règle est la ceinture : elle coupe aussi les deux respirations et
   toute transition résiduelle. Le document reste ENTIER — rien n'est amputé, seulement
   immobile (garde-fou 12). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
