/* =============================================================================
   scroll.css — chorégraphie de défilement des maquettes « refonte outils » (22/09/2026)
   -----------------------------------------------------------------------------
   À charger APRÈS base.css et motion.css. Compagnon : scroll.js (defer, après motion.js).
   Documentation : SCROLL.md.

   · Tous les états « avant entrée » sont préfixés par .has-scroll (posée par
     scroll.js) : sans JavaScript, rien n'est masqué.
   · On n'anime que transform et opacity (plus clip-path et stroke-dashoffset pour
     les révélations ponctuelles, jamais pendant le défilement continu).
   · prefers-reduced-motion: reduce = état final immédiat (bloc en fin de fichier).
   · Aucune ombre, aucun dégradé : couleur = var(--accent) de la maquette.
   ========================================================================== */

:root {
  --scroll-ease: cubic-bezier(.2, .7, .1, 1);        /* entrées : départ franc, arrivée douce */
  --scroll-ease-wipe: cubic-bezier(.77, 0, .18, 1);  /* balayages : accélère puis freine */
  --scroll-offset: 24px;                             /* marge haute des ancres */
}

/* Ancres : défilement doux, jamais sous reduced-motion. */
@media (prefers-reduced-motion: no-preference) {
  html.has-scroll { scroll-behavior: smooth; }
}
html.has-scroll { scroll-padding-top: var(--scroll-offset); }

/* Copie lisible par les lecteurs d'écran (le décor animé est aria-hidden). */
.scroll-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}


/* -----------------------------------------------------------------------------
   1. Titres découpés — [data-split="lines|words"]
   -------------------------------------------------------------------------- */
/* Le temps de la découpe (polices chargées), le titre est retenu. Filet de
   sécurité 100 % CSS : s'il n'est jamais découpé, il réapparaît à 1,6 s. */
.has-scroll [data-split]:not(.is-split) {
  opacity: 0;
  animation: scroll-failsafe 1ms 1.6s forwards;
}
@keyframes scroll-failsafe { to { opacity: 1; } }

.split-text { display: inline; }
.split-text__mask {                                   /* mot : masque inline-block */
  display: inline-block;
  vertical-align: top;
  overflow: hidden;
  padding-block: .1em;                           /* jambages (g, p, j) jamais coupés */
  margin-block: -.1em;
}
.split-text__mask > .split-text__item { display: inline-block; }
.split-text__line {                                   /* ligne : masque bloc */
  display: block;
  overflow: hidden;
  padding-block: .1em;
  margin-block: -.1em;
}
.split-text__line > .split-text__item { display: block; }

.has-scroll [data-split] .split-text__item {
  transition: transform .9s var(--scroll-ease);
  transition-delay: calc(var(--split-delay, 0ms) + var(--i, 0) * var(--split-stagger, 55ms));
}
.has-scroll [data-split="lines"] { --split-stagger: 110ms; }
.has-scroll [data-split]:not(.is-in) .split-text__item {
  transform: translate3d(0, 115%, 0);
}


/* -----------------------------------------------------------------------------
   2. Balayage — [data-wipe="up|left|right|circle"]
   -------------------------------------------------------------------------- */
.has-scroll [data-wipe] {
  transition: clip-path 1.1s var(--scroll-ease-wipe) var(--wipe-delay, 0ms);
  clip-path: inset(0 0 0 0);
}
.has-scroll [data-wipe="circle"] { clip-path: circle(75% at 50% 50%); }
.has-scroll [data-wipe="up"]:not(.is-in)     { clip-path: inset(100% 0 0 0); }
.has-scroll [data-wipe="left"]:not(.is-in)   { clip-path: inset(0 0 0 100%); }
.has-scroll [data-wipe="right"]:not(.is-in)  { clip-path: inset(0 100% 0 0); }
.has-scroll [data-wipe="circle"]:not(.is-in) { clip-path: circle(0% at 50% 50%); }

/* Le média à l'intérieur se pose en même temps (léger dézoom). */
.has-scroll [data-wipe] > :is(img, svg, picture, video, .wipe__media) {
  transition: transform 1.4s var(--scroll-ease) var(--wipe-delay, 0ms);
}
.has-scroll [data-wipe]:not(.is-in) > :is(img, svg, picture, video, .wipe__media) {
  transform: scale(1.12);
}


/* -----------------------------------------------------------------------------
   3. Coche qui se dessine — [data-check]
   -------------------------------------------------------------------------- */
.check {
  display: inline-block;
  flex: 0 0 auto;
  width: 1.3em;
  height: 1.3em;
  margin-right: .55em;
  vertical-align: -.3em;
  overflow: visible;
}
.check__ring {
  fill: var(--accent-soft, #F3EEFF);
  transform-box: fill-box;
  transform-origin: center;
}
.check__tick {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
}
.has-scroll [data-check] .check__ring {
  transition: transform .5s var(--scroll-ease) var(--check-delay, 0ms),
              opacity .3s linear var(--check-delay, 0ms);
}
.has-scroll [data-check] .check__tick {
  transition: stroke-dashoffset .55s cubic-bezier(.65, 0, .35, 1) calc(var(--check-delay, 0ms) + 180ms);
}
.has-scroll [data-check]:not(.is-in) .check__ring { transform: scale(.4); opacity: 0; }
.has-scroll [data-check]:not(.is-in) .check__tick { stroke-dashoffset: 1; }


/* -----------------------------------------------------------------------------
   4. Scènes épinglées — .scene[data-scene] > .scene__sticky
   --p (0 → 1), --sp (0 → 1 dans l'étape), --step, data-step, .is-step-N
   -------------------------------------------------------------------------- */
.scene {
  --p: 0;
  --sp: 0;
  --step: 0;
  position: relative;
  height: var(--scene-length, 250vh);
}
.scene__sticky {
  position: sticky;
  top: var(--scene-top, 0px);
  height: 100vh;
  height: 100svh;                                /* iOS : barre d'adresse visible */
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
@media (max-width: 720px) {
  .scene { height: var(--scene-length-m, 180vh); }
}

/* Empilement des étapes dans la même case (grille 1×1). */
.scene__steps { display: grid; }
.scene__steps > * { grid-area: 1 / 1; }

.has-scroll .scene [data-step-show] {
  transition: opacity .45s var(--scroll-ease), transform .6s var(--scroll-ease);
}
.has-scroll .scene [data-step-show]:not(.is-active) {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  pointer-events: none;
}
.has-scroll .scene [data-step-show].is-past { transform: translate3d(0, -24px, 0); }

/* Barre de progression de la scène (facultative). */
.scene__bar {
  height: 2px;
  background: var(--accent);
  transform-origin: 0 50%;
  transform: scaleX(var(--p));
}

/* Scène dépliée (reduced-motion) : flux normal, toutes les étapes visibles. */
.scene.is-static { height: auto; }
.scene.is-static .scene__sticky { position: relative; top: auto; height: auto; overflow: visible; padding-block: var(--section-y, 96px); }
.scene.is-static .scene__steps { gap: var(--space-3, 24px); }
.scene.is-static .scene__steps > * { grid-area: auto; }
.scene.is-static [data-step-show] { opacity: 1 !important; transform: none !important; pointer-events: auto; }


/* -----------------------------------------------------------------------------
   5. Scrub — [data-scrub]
   Chemin natif : animation pilotée par la vue (compositeur). Sinon : scroll.js.
   -------------------------------------------------------------------------- */
@keyframes scroll-scrub {
  from {
    transform: translate3d(var(--scrub-x0, 0px), var(--scrub-y0, 0px), 0)
               scale(var(--scrub-s0, 1)) rotate(var(--scrub-r0, 0deg));
    opacity: var(--scrub-o0, 1);
  }
  to {
    transform: translate3d(var(--scrub-x1, 0px), var(--scrub-y1, 0px), 0)
               scale(var(--scrub-s1, 1)) rotate(var(--scrub-r1, 0deg));
    opacity: var(--scrub-o1, 1);
  }
}
.has-sda [data-scrub].is-scrub {
  animation: scroll-scrub linear both;
  animation-timeline: view();
  animation-range: cover var(--scrub-a, 0%) cover var(--scrub-b, 50%);
}
.has-scroll [data-scrub]:is(.is-scrub, .is-scrub-js) { will-change: transform, opacity; }


/* -----------------------------------------------------------------------------
   6. Barre de progression de lecture — <div class="read-progress"></div>
   -------------------------------------------------------------------------- */
.read-progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 1000;
  height: 2px;
  background: var(--accent);
  transform-origin: 0 50%;
  transform: scaleX(0);
  pointer-events: none;
}
@keyframes scroll-read { to { transform: scaleX(1); } }
.has-sda .read-progress {
  animation: scroll-read linear both;
  animation-timeline: scroll(root block);
}


/* -----------------------------------------------------------------------------
   7. Rouleaux de chiffres — [data-roll]
   -------------------------------------------------------------------------- */
.roll {
  --roll-h: 1.15em;
  display: inline-flex;
  align-items: baseline;
  line-height: var(--roll-h);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.roll__col {
  display: flex;
  flex-direction: column;
  height: var(--roll-h);
  overflow: hidden;
}
.roll__strip {
  display: block;
  transform: translate3d(0, 0, 0);
  transition: transform var(--roll-duration, 1600ms) cubic-bezier(.16, .84, .12, 1)
              calc(var(--c, 0) * 70ms);
}
.roll__cell { display: block; height: var(--roll-h); text-align: center; }
.roll__sep { white-space: pre; }
.is-in > .roll .roll__strip,
.is-in > .roll__strip { transform: translate3d(0, var(--to, 0%), 0); }


/* -----------------------------------------------------------------------------
   8. Parallaxe — [data-depth] (coupée sous 900 px et sous reduced-motion)
   -------------------------------------------------------------------------- */
@media (min-width: 901px) and (prefers-reduced-motion: no-preference) {
  .has-scroll [data-depth] { will-change: transform; }
}


/* -----------------------------------------------------------------------------
   prefers-reduced-motion : état final immédiat, rien d'invisible.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .has-scroll [data-split]:not(.is-split) { opacity: 1; animation: none; }
  .has-scroll [data-split] .split-text__item { transform: none !important; transition: none; }
  .has-scroll [data-wipe],
  .has-scroll [data-wipe]:not(.is-in) { clip-path: none !important; transition: none; }
  .has-scroll [data-wipe] > * { transform: none !important; }
  .has-scroll [data-check] .check__ring { transform: none !important; opacity: 1 !important; }
  .has-scroll [data-check] .check__tick { stroke-dashoffset: 0 !important; }
  .has-scroll .scene [data-step-show] { transition: none; }
  [data-scrub] { animation: none !important; transform: none !important; opacity: 1 !important; }
  [data-depth] { transform: none !important; }
  .roll__strip { transition: none; }
}

/* le média agrandi pendant le balayage ne compte pas dans le débordement de la page */
[data-wipe] { overflow: clip; }
