/* ============================================================
   CREANA CLEANING — MOUVEMENT

   Deux gestes, jamais trois :
     · le masque qui balaie   (clip-path / scaleX)
     · la ligne qui monte     (translateY sous overflow)

   Tout le reste est une progression continue pilotée par --p,
   publiée par motion-core.js. Le CSS seul décide de l'effet.

   Aucune règle de ce fichier n'est nécessaire à la lecture :
   sans JavaScript, la page reste dans son état final.
   ============================================================ */

/* ─────────────────────────────────────────────
   ÉTAT INITIAL — uniquement si le JS répond
   ───────────────────────────────────────────── */

.cc-js [data-in] { --in: 0; }

/* ─────────────────────────────────────────────
   TRANSITION DE PAGE
   Le même voile que le Clean Reveal, à l'échelle
   du document. Il balaie, il ne clignote pas.
   ───────────────────────────────────────────── */

/* L'entrée est une animation, jamais un état : si le JS ne démarre
   pas, la page reste visible. Seule la sortie est pilotée. */
.cc-js body {
  animation: cc-page-in var(--cc-dur-page) var(--cc-ease-clean) both;
  transition: opacity 260ms var(--cc-ease-clean);
}

@keyframes cc-page-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.cc-js body.cc-page-out {
  animation: none;
  opacity: 0;
}

/* ─────────────────────────────────────────────
   HERO — continuité vers la scène suivante
   Le hero ne disparaît pas : il se retire.
   ───────────────────────────────────────────── */

.cc-js .cc-hero[data-scroll] {
  --p: 0;
}

.cc-js .cc-hero[data-scroll] .cc-hero__media .cc-media img {
  transform: scale(calc(1 + var(--p) * 0.06));
  transform-origin: center 40%;
  will-change: transform;
}

/* Clean Reveal : le voile se retire par le bas et découvre la photo.
   C'est le geste fondateur du site — il n'apparaît qu'ici et à la clôture.

   Le hero est toujours en haut de page : il n'a rien à observer.
   Tout y est donc joué en animation pure, avec `both` — si le JS
   s'arrête net après avoir posé .cc-js, l'état final est garanti. */
.cc-js .cc-hero__media {
  animation: cc-veil-lift var(--cc-dur-mask) var(--cc-ease-mask) 120ms both;
}

@keyframes cc-veil-lift {
  from { clip-path: inset(0 0 100% 0); }
  to { clip-path: inset(0 0 0 0); }
}

.cc-js .cc-hero__title .cc-line-inner {
  animation: cc-line-up var(--cc-dur-reveal) var(--cc-ease-clean) both;
}

.cc-js .cc-hero__title .cc-line-mask:nth-child(2) .cc-line-inner {
  animation-delay: var(--cc-stagger);
}

@keyframes cc-line-up {
  from { transform: translateY(105%); }
  to { transform: translateY(0); }
}

.cc-js .cc-hero__eyebrow,
.cc-js .cc-hero__lead,
.cc-js .cc-hero__actions,
.cc-js .cc-hero__proof {
  animation: cc-rise var(--cc-dur-reveal) var(--cc-ease-clean) both;
}

.cc-js .cc-hero__eyebrow { animation-delay: 90ms; }
.cc-js .cc-hero__lead { animation-delay: 240ms; }
.cc-js .cc-hero__actions { animation-delay: 330ms; }
.cc-js .cc-hero__proof { animation-delay: 420ms; }

@keyframes cc-rise {
  from { opacity: 0; transform: translateY(var(--cc-shift)); }
  to { opacity: 1; transform: none; }
}

.cc-js .cc-hero[data-scroll] .cc-hero__copy {
  transform: translateY(calc(var(--p) * -28px));
  opacity: calc(1 - var(--p) * 0.55);
}

.cc-js .cc-hero[data-scroll] .cc-hero__thread {
  transform: scaleX(calc(0.25 + var(--p) * 0.75));
  transform-origin: left center;
}

/* ─────────────────────────────────────────────
   TITRES — la ligne monte sous son masque
   Réservé aux display. Jamais sur du corps de texte.
   ───────────────────────────────────────────── */

.cc-js .cc-lines { display: block; }

.cc-js .cc-lines > .cc-line-mask > .cc-line-inner {
  transform: translateY(105%);
}

.cc-js .cc-lines.is-in > .cc-line-mask > .cc-line-inner {
  transform: translateY(0);
}

/* Le masque coupe au ras : le serif a des jambages descendants. */
.cc-line-mask { padding-bottom: 0.06em; margin-bottom: -0.06em; }

/* ─────────────────────────────────────────────
   SANS CREANA / AVEC CREANA
   Désordre → clarté, sans jamais gêner la lecture.
   À --p = 0 tout est déjà lisible : le mouvement
   ne fait que resserrer ce qui était dispersé.
   ───────────────────────────────────────────── */

.cc-js .cc-compare[data-scroll] { --p: 0; }

.cc-js .cc-compare[data-scroll] .cc-compare__divider {
  transform: scaleY(clamp(0, calc(var(--p) * 2.2 - 0.3), 1));
  transform-origin: top center;
}

/* Colonne « sans » : les lignes se désalignent à mesure qu'on descend.
   Le texte ne perd jamais son contraste — c'est la tenue qui se défait,
   pas la lisibilité. */
.cc-js .cc-compare[data-scroll] .cc-compare__side--before .cc-compare__item {
  transform: translateX(calc(var(--p) * var(--cc-drift, 0px)));
}

.cc-compare__side--before .cc-compare__item:nth-child(1) { --cc-drift: 10px; }
.cc-compare__side--before .cc-compare__item:nth-child(2) { --cc-drift: -6px; }
.cc-compare__side--before .cc-compare__item:nth-child(3) { --cc-drift: 14px; }
.cc-compare__side--before .cc-compare__item:nth-child(4) { --cc-drift: -9px; }
.cc-compare__side--before .cc-compare__item:nth-child(5) { --cc-drift: 7px; }
.cc-compare__side--before .cc-compare__item:nth-child(6) { --cc-drift: -12px; }
.cc-compare__side--before .cc-compare__item:nth-child(7) { --cc-drift: 5px; }

/* Colonne « avec » : les lignes arrivent alignées, une à une, et
   sont toutes lisibles bien avant que la scène soit au centre. */
.cc-js .cc-compare[data-scroll] .cc-compare__side--after .cc-compare__item {
  --step: calc(var(--p) * 12);
  opacity: clamp(0, calc(var(--step) - var(--i) + 0.4), 1);
  transform: translateY(calc(clamp(0, calc(var(--i) + 0.4 - var(--step)), 1) * 10px));
}

.cc-compare__side--after .cc-compare__item:nth-child(1) { --i: 0; }
.cc-compare__side--after .cc-compare__item:nth-child(2) { --i: 1; }
.cc-compare__side--after .cc-compare__item:nth-child(3) { --i: 2; }
.cc-compare__side--after .cc-compare__item:nth-child(4) { --i: 3; }

/* ─────────────────────────────────────────────
   SERVICES — l'image suit la lecture
   Un seul cadre visible, les autres attendent.
   ───────────────────────────────────────────── */

.cc-frames {
  position: relative;
  display: grid;
}

.cc-frames > .cc-frame { grid-area: 1 / 1; }

/* Sans JS, le premier cadre tient la place ; avec JS, la lecture décide. */
.cc-frames > .cc-frame { opacity: 0; }
.cc-frames > .cc-frame:first-child { opacity: 1; }

/* Le changement d'image est un balayage, pas un fondu :
   le nouveau cadre découvre par la gauche celui qui l'attendait. */
.cc-js .cc-frames > .cc-frame {
  opacity: 1;
  clip-path: inset(0 0 0 100%);
  z-index: 0;
}

.cc-js .cc-frames.is-ready > .cc-frame.is-active {
  transition: clip-path var(--cc-dur-mask) var(--cc-ease-mask);
}

/* Le cadre sortant reste entièrement visible, en dessous : le masque
   balaie toujours par-dessus une image, jamais par-dessus le vide.
   Les cadres plus anciens se replient instantanément, hors de vue. */
.cc-js .cc-frames > .cc-frame.is-prev {
  clip-path: inset(0);
  z-index: 0;
}

.cc-js .cc-frames > .cc-frame.is-active {
  clip-path: inset(0);
  z-index: 1;
}

.cc-js .cc-frames > .cc-frame img {
  transform: scale(1.04);
  transition: transform var(--cc-dur-mask) var(--cc-ease-clean);
}

.cc-js .cc-frames > .cc-frame.is-active img { transform: scale(1); }

/* Le bloc lu se détache : le filet s'épaissit, rien ne saute. */
.cc-js .cc-service {
  transition: opacity var(--cc-dur-base) var(--cc-ease-clean);
}

@media (min-width: 901px) {
  .cc-js [data-service-sync] .cc-service { opacity: 0.45; }
  .cc-js [data-service-sync] .cc-service.is-active,
  .cc-js [data-service-sync] .cc-service:hover,
  .cc-js [data-service-sync] .cc-service:focus-visible { opacity: 1; }
}

/* ─────────────────────────────────────────────
   TIMELINE — la progression descend le filet
   Une seule barre traverse les cinq étapes :
   --p est réparti entre elles, le filet ne s'arrête jamais.
   ───────────────────────────────────────────── */

.cc-js .cc-steps[data-scroll] { --p: 0; --n: 5; }

.cc-js .cc-step__rail { position: relative; }

/* Sans pilotage de scroll (pages internes) : l'étape atteinte remplit son filet. */
.cc-js .cc-step__rail::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  background: var(--cc-ink);
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform var(--cc-dur-mask) var(--cc-ease-clean);
}

.cc-js .cc-step.is-reached .cc-step__rail::after { transform: scaleY(1); }

/* Avec pilotage (homepage) : une seule barre traverse les cinq étapes.
   --p est réparti entre elles, le filet ne s'arrête jamais. */
.cc-js .cc-steps[data-scroll] .cc-step__rail::after,
.cc-js .cc-steps[data-scroll] .cc-step.is-reached .cc-step__rail::after {
  transform: scaleY(clamp(0, calc(var(--p) * var(--n) - var(--i, 0)), 1));
  transition: none;
}

.cc-steps[data-scroll] .cc-step:nth-child(1) { --i: 0; }
.cc-steps[data-scroll] .cc-step:nth-child(2) { --i: 1; }
.cc-steps[data-scroll] .cc-step:nth-child(3) { --i: 2; }
.cc-steps[data-scroll] .cc-step:nth-child(4) { --i: 3; }
.cc-steps[data-scroll] .cc-step:nth-child(5) { --i: 4; }

.cc-js .cc-step__numeral {
  color: var(--cc-ink-soft);
  transition: color var(--cc-dur-reveal) var(--cc-ease-clean);
}

.cc-js .cc-step.is-reached .cc-step__numeral { color: var(--cc-ink); }

.cc-js .cc-step__body,
.cc-js .cc-step__label {
  opacity: 0;
  transform: translateY(var(--cc-shift));
  transition: opacity var(--cc-dur-reveal) var(--cc-ease-clean),
              transform var(--cc-dur-reveal) var(--cc-ease-clean);
}

.cc-js .cc-step.is-reached .cc-step__label { opacity: 1; transform: none; }

.cc-js .cc-step.is-reached .cc-step__body {
  opacity: 1;
  transform: none;
  transition-delay: var(--cc-stagger);
}

/* ─────────────────────────────────────────────
   CLÔTURE — le papier se retire, l'encre reste
   Même geste que le hero, joué à l'envers :
   un voile clair se rétracte vers le bas et découvre
   la dernière scène pendant que le scroll descend.
   ───────────────────────────────────────────── */

.cc-js .cc-close[data-scroll] { --p: 0; }

.cc-js .cc-close[data-veil] {
  position: relative;
  isolation: isolate;
}

.cc-js .cc-close[data-veil]::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--cc-paper);
  pointer-events: none;
  clip-path: inset(calc(var(--p) * 100%) 0 0 0);
}

.cc-js .cc-close[data-veil] > * { position: relative; z-index: 0; }

.cc-js .cc-close[data-scroll] .cc-close__title {
  transform: translateY(calc((1 - var(--p)) * 24px));
}

/* ─────────────────────────────────────────────
   FORMULAIRE
   ───────────────────────────────────────────── */

.cc-js .cc-form [data-submit-btn][disabled] { opacity: 0.55; }

.cc-success {
  transition: opacity var(--cc-dur-reveal) var(--cc-ease-clean),
              transform var(--cc-dur-reveal) var(--cc-ease-clean);
}

/* display:none coupe la transition : on anime à la frame suivante,
   une fois le panneau entré dans le flux. */
.cc-js [data-form-scope].cc-form-done .cc-success {
  opacity: 0;
  transform: translateY(var(--cc-shift));
  animation: cc-success-in var(--cc-dur-reveal) var(--cc-ease-clean) 60ms forwards;
}

@keyframes cc-success-in {
  to { opacity: 1; transform: none; }
}

/* ─────────────────────────────────────────────
   MOUVEMENT RÉDUIT
   Rien ne bouge, rien ne manque.
   ───────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .cc-js body,
  .cc-js body.cc-page-out {
    animation: none !important;
    opacity: 1 !important;
    transition: none !important;
  }

  .cc-js .cc-hero[data-scroll] .cc-hero__media .cc-media img,
  .cc-js .cc-hero[data-scroll] .cc-hero__copy,
  .cc-js .cc-hero[data-scroll] .cc-hero__thread,
  .cc-js .cc-close[data-scroll] .cc-close__title,
  .cc-js .cc-compare[data-scroll] .cc-compare__item,
  .cc-js .cc-compare[data-scroll] .cc-compare__divider {
    transform: none !important;
    opacity: 1 !important;
  }

  .cc-js .cc-hero__media,
  .cc-js .cc-hero__title .cc-line-inner,
  .cc-js .cc-hero__eyebrow,
  .cc-js .cc-hero__lead,
  .cc-js .cc-hero__actions,
  .cc-js .cc-hero__proof {
    animation: none !important;
    clip-path: none !important;
    opacity: 1 !important;
    transform: none !important;
  }

  .cc-js .cc-step__body,
  .cc-js .cc-step__label {
    opacity: 1 !important;
    transform: none !important;
  }

  .cc-js .cc-lines > .cc-line-mask > .cc-line-inner { transform: none !important; }
  .cc-js .cc-step__rail::after { transform: scaleY(1) !important; }
  .cc-js [data-service-sync] .cc-service { opacity: 1 !important; }
  .cc-js .cc-frames > .cc-frame img { transform: none !important; }

  /* Sans masque, un seul cadre doit rester visible : sans quoi les
     quatre se superposent dans la même cellule de grille. */
  .cc-js .cc-frames > .cc-frame {
    clip-path: none !important;
    opacity: 0 !important;
  }

  .cc-js .cc-frames > .cc-frame.is-active { opacity: 1 !important; }

  .cc-js .cc-close[data-veil]::before { display: none !important; }
}

/* ─────────────────────────────────────────────
   MOBILE — le geste reste, l'amplitude baisse.
   Une colonne unique ne supporte pas la dérive latérale.
   ───────────────────────────────────────────── */

@media (max-width: 720px) and (prefers-reduced-motion: no-preference) {
  .cc-js .cc-compare[data-scroll] .cc-compare__side--before .cc-compare__item {
    --cc-drift: 0px;
  }

  .cc-js .cc-hero[data-scroll] .cc-hero__media .cc-media img {
    transform: scale(calc(1 + var(--p) * 0.03));
  }

  /* Le hero mobile est déjà court : le voile de clôture couvrirait
     l'écran entier trop longtemps. On garde l'encre franche. */
  .cc-js .cc-close[data-veil]::before { display: none; }
}
