/* ══════════════════════════════════════════════════════════════════
   GROOMLY — animations de defilement
   Portage du systeme framer-motion vu sur la page de reference :

     motion.div whileInView={{opacity:1, y:0}} ... [data-anim]
     viewport={{ once: true, margin: "-100px" }} . IntersectionObserver
     transition={{ delay: i * 0.05 }} ............ --i sur chaque enfant
     whileHover={{ y: -8, boxShadow: ... }} ...... :hover en CSS
     whileHover={{ scale:1.1, rotate:5 }} ........ :hover sur l'icone
     animate={{ x: [0, 4, 0] }} repeat Infinity .. @keyframes animFleche
     useScroll + useSpring -> scaleX ............. .prog, pose en JS
     initial={{scaleY:0}} whileInView scaleY:1 ... .ch-frise::before

   DEUX REGLES QUI COMPTENT

   1. L'etat cache est pose par le JS, pas par le CSS. La classe
      « anim-actif » est ajoutee sur <html> par animations.js. Sans JS,
      sans IntersectionObserver, ou si le script tombe, TOUT le contenu
      reste visible. Une page dont le texte est en opacity:0 par defaut
      et qui attend un script est une page blanche pour Google et pour
      quiconque a un reseau qui coupe.

   2. Seules « opacity » et « transform » sont animees. Ce sont les deux
      proprietes que le navigateur confie au compositeur : pas de
      recalcul de mise en page, pas de repeinture. Animer « height » ou
      « top » sur une dizaine de blocs au defilement fait ramer un
      telephone d'entree de gamme, et c'est la moitie de tes visiteurs.
   ══════════════════════════════════════════════════════════════════ */

:root{
  /* Meme ressort que la barre de navigation : masse 1, raideur 350,
     amortissement 32. Echantillonne, pas approxime. */
  --anim-ressort: linear(0.0000, 0.0104, 0.0380, 0.0785, 0.1282, 0.1839, 0.2432,
                         0.3041, 0.3650, 0.4247, 0.4824, 0.5372, 0.5888, 0.6369,
                         0.6813, 0.7220, 0.7590, 0.7923, 0.8223, 0.8490, 0.8726,
                         0.8934, 0.9117, 0.9275, 0.9412, 0.9529, 0.9630, 0.9715,
                         0.9786, 0.9845, 0.9894, 0.9934, 0.9967, 0.9992);
  --anim-sortie: cubic-bezier(.25,.4,.25,1);   /* ease de la page d'origine */
}

/* ── BARRE DE PROGRESSION DE LECTURE ─────────────────────────────
   « useSpring(scrollYProgress) » : la barre suit le defilement avec un
   temps de retard elastique. On transforme scaleX, jamais width — une
   largeur en pourcentage relance la mise en page a chaque pixel. */
.prog{
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 200;
  background: linear-gradient(90deg, var(--rose, #f43f5e), var(--rose-fonce, #e11d48));
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .12s linear;
  pointer-events: none;
}

/* ── APPARITION AU DEFILEMENT ────────────────────────────────────
   Etat de depart pose uniquement quand le JS a pris la main. */
html.anim-actif [data-anim]{
  opacity: 0;
  transform: translateY(var(--anim-y, 28px)) translateX(var(--anim-x, 0));
  transition: opacity .62s var(--anim-sortie), transform .62s var(--anim-sortie);
  transition-delay: calc(var(--i, 0) * var(--anim-pas, 0ms));
  will-change: opacity, transform;
}
html.anim-actif [data-anim].vu{
  opacity: 1; transform: none; will-change: auto;
}

/* Variantes reprises de la page de reference. */
[data-anim="gauche"]{ --anim-x: -46px; --anim-y: 0px; }   /* x: -50 */
[data-anim="droite"]{ --anim-x:  46px; --anim-y: 0px; }   /* x:  30 */

/* En colonne, PAS de deplacement horizontal. Deux raisons, et la
   premiere est un bug : un element decale de 46 px vers la droite est
   plus large que l'ecran tant qu'il n'est pas apparu, et la page gagne
   une barre de defilement horizontale — 26 px de trop, mesures. La
   seconde : sur un ecran etroit les blocs prennent toute la largeur,
   un glissement lateral n'y raconte plus rien. */
@media (max-width: 899px){
  [data-anim="gauche"], [data-anim="droite"]{ --anim-x: 0px; --anim-y: 26px; }
}
[data-anim="liste"] { --anim-x: -12px; --anim-y: 0px; --anim-pas: 55ms; }
[data-anim="pose"]  { --anim-y: 0px; }
html.anim-actif [data-anim="pose"]{ transform: scale(.94); }
html.anim-actif [data-anim="pose"].vu{ transform: none; }

/* Decalage des enfants d'un groupe : staggerChildren. */
[data-anim-groupe] > *{ --anim-pas: 90ms; }

/* ── LE TRAIT DE LA FRISE QUI SE DESSINE ─────────────────────────
   initial={{ scaleY: 0 }} whileInView={{ scaleY: 1 }}, origine en haut.
   Sur grand ecran la frise est horizontale : c'est scaleX. */
html.anim-actif .ch-frise .ch-pas::before{
  transform: scaleY(0); transform-origin: top center;
  transition: transform 1.1s var(--anim-sortie);
  transition-delay: calc(var(--i, 0) * 90ms);
}
html.anim-actif .ch-frise.vu .ch-pas::before{ transform: scaleY(1); }
@media (min-width: 900px){
  html.anim-actif .ch-frise .ch-pas::before{
    transform: scaleX(0); transform-origin: left center;
  }
  html.anim-actif .ch-frise.vu .ch-pas::before{ transform: scaleX(1); }
}

/* Le point de la frise apparait en ressort, comme le badge numerote. */
html.anim-actif .ch-frise .ch-pas::after{
  transform: scale(0);
  transition: transform .5s var(--anim-ressort);
  transition-delay: calc(var(--i, 0) * 90ms + 220ms);
}
html.anim-actif .ch-frise.vu .ch-pas::after{ transform: scale(1); }

/* ── SURVOLS ─────────────────────────────────────────────────────
   whileHover={{ y: -8, boxShadow }} et scale/rotate sur l'icone. */
.anim-leve{ transition: transform .28s var(--anim-ressort), box-shadow .28s ease, border-color .2s ease; }
.anim-leve:hover{
  transform: translateY(-8px);
  box-shadow: 0 22px 44px -24px rgba(244,63,94,.34);
}
.anim-icone{ transition: transform .32s var(--anim-ressort); }
.anim-leve:hover .anim-icone{ transform: scale(1.1) rotate(5deg); }
.anim-leve:nth-child(even):hover .anim-icone{ transform: scale(1.1) rotate(-5deg); }

/* ── LA FLECHE QUI RESPIRE ───────────────────────────────────────
   animate={{ x: [0, 4, 0] }}, repeat: Infinity, 1.5 s. Reservee aux
   appels a l'action : une fleche qui bouge en permanence dans une liste
   de liens devient du bruit. */
@keyframes animFleche{ 0%,100%{ transform: translateX(0); } 50%{ transform: translateX(4px); } }
.anim-fleche{ animation: animFleche 1.5s ease-in-out infinite; }

/* ── RESPECT DE LA PREFERENCE SYSTEME ────────────────────────────
   « prefers-reduced-motion » n'est pas un detail de confort : pour une
   partie des gens, ces mouvements donnent la nausee. On ne ralentit
   pas, on supprime — et le contenu reste evidemment visible. */
@media (prefers-reduced-motion: reduce){
  html.anim-actif [data-anim],
  html.anim-actif [data-anim].vu{ opacity: 1; transform: none; transition: none; }
  html.anim-actif .ch-frise .ch-pas::before,
  html.anim-actif .ch-frise .ch-pas::after{ transform: none; transition: none; }
  .prog{ transition: none; }
  .anim-leve, .anim-icone{ transition: none; }
  .anim-leve:hover{ transform: none; }
  .anim-fleche{ animation: none; }
}
