/* ============================================================================
   Platicadero v2 — motion.css : la vie du site.
   Chaque animation a un rôle : hiérarchie (héro), narration (pile d'étapes,
   balayage du manifeste), feedback (hovers, coches) ou continuité (rideaux).
   - États d'entrée masqués UNIQUEMENT sous .js (dégradation gracieuse).
   - Enrichissements scroll-driven (CSS animation-timeline) sous @supports :
     les navigateurs sans support gardent un site complet, simplement plus calme.
   - Tout se neutralise sous prefers-reduced-motion.
   ============================================================================ */

/* -------------------------------------------------- Reveal générique (IntersectionObserver)
   ease-out : une entrée démarre vite et se pose — l'in-out signature reste
   pour les morphs à l'écran, pas pour ce que l'œil attend. */
:where(.js) .reveal {
  opacity: 0; transform: translateY(26px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
  transition-delay: calc(var(--i, 0) * var(--stagger, 80ms));
}
.reveal.is-in { opacity: 1; transform: none; }
/* grilles de 6+ éléments : cascade resserrée, la queue reste sous ~500 ms */
.bento .reveal, .perks .reveal, .privacy__list .reveal { --stagger: 55ms; }

/* -------------------------------------------------- Héro : ouverture orchestrée */
@keyframes rise    { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } }
@keyframes rise-sm { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes seat    { from { opacity: 0; transform: translateY(46px) scale(.92); } to { opacity: 1; transform: none; } }
/* jamais depuis presque-rien : .85 + rebond = espiègle, .4 = cartoon */
@keyframes pop     { from { opacity: 0; transform: scale(.85); } to { opacity: 1; transform: scale(1); } }
@keyframes navdrop { from { opacity: 0; transform: translateY(-18px); } to { opacity: 1; transform: none; } }
@keyframes bob {
  0%, 100% { transform: translateY(0) rotate(var(--rot, 0deg)); }
  50%      { transform: translateY(-9px) rotate(calc(var(--rot, 0deg) + 2deg)); }
}
@keyframes float-loop {
  0%   { transform: translateY(0) rotate(0deg); }
  28%  { transform: translateY(-12px) rotate(-1.2deg); }
  55%  { transform: translateY(-4px) rotate(.6deg); }
  78%  { transform: translateY(-13px) rotate(1.1deg); }
  100% { transform: translateY(0) rotate(0deg); }
}

.nav          { animation: navdrop 640ms var(--ease) both; }
.hero .chip   { animation: rise-sm 560ms var(--ease-out) both; }
.hero__title  { animation: rise 760ms var(--ease-out) 90ms both; }
.hero__sub    { animation: rise 760ms var(--ease-out) 230ms both; }
.hero__cta    { animation: rise 680ms var(--ease-out) 370ms both; }
.hero__scene  { animation: seat 880ms var(--ease-out) 300ms both; }
.hero__art img { animation: float-loop 6s var(--ease-soft) 1.4s infinite; transform-origin: 50% 80%; }
.hero__squiggle { animation: pop 520ms var(--ease-bounce) 900ms both; }
.hero__pill { animation: pop 480ms var(--ease-bounce) both, bob 5.5s var(--ease-soft) 1.6s infinite; }
.hero__pill--1 { animation-delay: 750ms, 1.6s; --rot: -2deg; }
.hero__pill--2 { animation-delay: 900ms, 2.1s; --rot: 1.5deg; }
.hero__pill--3 { animation-delay: 1050ms, 2.6s; --rot: -1deg; }

/* trait ondulé : serpente en continu sous le mot clé — en translateX
   (composité) au lieu de background-position (repaint à chaque frame) */
.u-wave::after { animation: serpent 7s linear infinite; }
@keyframes serpent { to { transform: translateX(calc(-1 * var(--tile))); } }  /* = --tile : boucle sans couture */

/* -------------------------------------------------- Coches qui se tracent (arrivée = confirmation) */
:where(.js) .check svg path { stroke-dasharray: 26; stroke-dashoffset: 26; }
.reveal.is-in .check svg path,
.reveal.is-in ~ * .check svg path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 520ms var(--ease);
  transition-delay: calc(220ms + var(--i, 0) * 70ms);
}

/* -------------------------------------------------- Pile d'étapes : narration au scroll
   position:sticky fait l'empilement partout ; là où les timelines CSS existent,
   la carte N recule doucement quand la carte N+1 entre dans l'écran. */
@supports (animation-timeline: view()) {
  .stack__item:nth-child(1) .step-card,
  .stack__item:nth-child(2) .step-card,
  .stack__item:nth-child(3) .step-card {
    animation: step-recede linear both;
    animation-range: entry 30% entry 100%;
  }
  .stack__item:nth-child(1) .step-card { animation-timeline: --step-2; }
  .stack__item:nth-child(2) .step-card { animation-timeline: --step-3; }
  .stack__item:nth-child(3) .step-card { animation-timeline: --step-4; }
  @keyframes step-recede {
    to { transform: scale(.95) translateY(-8px); filter: brightness(.95); }
  }
}

/* -------------------------------------------------- Manifeste : balayage d'encre au scroll */
@supports (animation-timeline: view()) and (-webkit-background-clip: text) {
  .manifesto h2 {
    /* repli littéral : le texte est transparent, si --ink-16 manque (cache
       tokens.css périmé) le dégradé entier serait invalide → titre invisible */
    background: linear-gradient(105deg, var(--ink, #2C2E2A) 46%, var(--ink-16, rgba(44, 46, 42, .16)) 54%) no-repeat;
    background-size: 240% 100%; background-position-x: 100%;
    -webkit-background-clip: text; background-clip: text;
    color: transparent;
    animation: ink-sweep linear both;
    animation-timeline: view();
    animation-range: entry 60% cover 42%;
  }
  @keyframes ink-sweep { to { background-position-x: 0%; } }
}

/* -------------------------------------------------- Illustrations : flottement continu */
.mm__art img  { animation: float-loop 6.5s var(--ease-soft) infinite; transform-origin: 50% 90%; }
.join__peek   { animation: bob 5s var(--ease-soft) infinite; }

/* -------------------------------------------------- Bande Expedition : la troupe avance au scroll
   Horizontal uniquement : le fond de l'illustration est transparent (le warm-white
   de la page passe au travers, aucune couture) et le rideau charcoal couvre le bas ;
   un mouvement vertical révélerait la coupe. L'image est élargie à 106 % pour que
   ses bords restent hors cadre pendant tout le trajet (.band garde overflow: clip). */
@supports (animation-timeline: view()) {
  .band img {
    width: 106%; max-width: none; margin-inline-start: -6%;
    animation: band-travel linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
  /* 6 % du conteneur = 6/106 de la largeur propre de l'image élargie */
  @keyframes band-travel { to { transform: translateX(5.66%); } }
}

/* -------------------------------------------------- Logos : bandeau défilant (marquee unique du site) */
.logos__track { animation: marquee 36s linear infinite; }
@keyframes marquee { to { transform: translateX(-50%); } }  /* 2 séries identiques → boucle sans couture */
@media (hover:hover) and (pointer:fine) { .logos__row:hover .logos__track { animation-play-state: paused; } }
.logos__row:focus-within .logos__track { animation-play-state: paused; }

/* -------------------------------------------------- Reduced motion : tout posé d'emblée */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; }
  :where(.js) .reveal { transform: none; transition: opacity .2s var(--ease); }
  :where(.js) .check svg path { stroke-dashoffset: 0; }
  .step-card { transform: none; filter: none; }
  .manifesto h2 { background: none; color: var(--ink); }
  .band img { width: 100%; max-width: 100%; margin-inline-start: 0; }
  /* pas de défilement : les logos passent à la ligne, tous visibles */
  .logos__row { overflow: visible; -webkit-mask-image: none; mask-image: none; }
  .logos__track { flex-wrap: wrap; width: auto; transform: none; }
  /* les survols restent des états, plus des mouvements */
  .tile:hover { transform: none; }
  .btn::before, .btn__label, .btn__icon, .chip, .link-arrow svg { transition-duration: .1ms; }
}

/* -------------------------------------------------- Impression / rendus sans frames :
   le contenu ne dépend jamais de l'IntersectionObserver */
@media print {
  :where(.js) .reveal { opacity: 1 !important; transform: none !important; }
}
