/* ==========================================================================
   WeRefund — Mouvement
   --------------------------------------------------------------------------
   Un seul foyer pour tout ce qui bouge. Deux règles gouvernent ce fichier :

   1. LA PAGE SE LIT AU REPOS. Aucune règle ci-dessous ne s'applique tant que
      le script n'a pas posé `js-anim` / `js-reveal` sur <html>. Sans
      JavaScript, sans IntersectionObserver, ou pendant la capture d'une
      vignette : tout est visible, rien n'est masqué en attente d'un signal.

   2. LE MOUVEMENT DIT QUELQUE CHOSE. Ici il ne dit que deux choses — le temps
      qui court (c'est le sujet du produit) et le produit qui fonctionne. Tout
      effet qui ne dit ni l'un ni l'autre n'entre pas.
   ========================================================================== */


/* ==========================================================================
   1. Entrée orchestrée au chargement
   Le hero se compose en ~1,2 s : le propos d'abord, la démonstration ensuite.
   Le délai est porté par `--enter-delay`, posé par le script depuis
   `data-enter-delay` — jamais deviné dans le CSS.
   ========================================================================== */

html.js-anim [data-enter] {
  animation: enter-up .78s var(--ease-out) both;
  animation-delay: var(--enter-delay, 0ms);
}

html.js-anim [data-enter="blur"]  { animation-name: enter-blur; animation-duration: .9s; }
html.js-anim [data-enter="fade"]  { animation-name: enter-fade; }
html.js-anim [data-enter="scale"] { animation-name: enter-scale; }
html.js-anim [data-enter="right"] { animation-name: enter-right; animation-duration: .95s; }

@keyframes enter-up    { from { opacity: 0; transform: translateY(20px); } }
@keyframes enter-fade  { from { opacity: 0; } }
@keyframes enter-blur  { from { opacity: 0; transform: translateY(14px); filter: blur(8px); } }
@keyframes enter-scale { from { opacity: 0; transform: translateY(16px) scale(.972); } }
@keyframes enter-right { from { opacity: 0; transform: translateX(28px) scale(.985); } }


/* ==========================================================================
   2. Révélation au défilement
   État de repos VISIBLE : le décalage n'existe que si le script a confirmé
   qu'un observateur le lèvera.
   ========================================================================== */

html.js-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
html.js-reveal [data-reveal].is-in {
  opacity: 1;
  transform: none;
}


/* ==========================================================================
   3. Le motif du temps qui court
   ========================================================================== */

/* 3.1 — L'anneau de fenêtre de retour balaie son arc à l'entrée en vue.
   Le nombre au centre est décompté par le script en parallèle : l'arc et le
   chiffre disent la même chose au même instant. */
.window-ring .bar { transition: stroke-dashoffset 1.4s var(--ease-out); }

/* 3.2 — Le compte à rebours SLA bat la seconde. Chiffres à chasse fixe :
   sans tabular-nums, la ligne tremble à chaque seconde. */
.ticker {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
}
.ticker--warn { color: var(--warn); }


/* ==========================================================================
   5. Profondeur retenue
   ========================================================================== */

/* 5.2 — Les visuels se soulèvent au survol de leur cellule, pas la cellule
   entière : c'est l'objet qu'on regarde qui répond. */
.bento__art,
.help__card,
.post-lead__thumb,
.post-row__thumb {
  transition: transform .45s var(--ease), box-shadow .45s var(--ease);
}
.bento__cell:hover .bento__art {
  transform: translateY(-4px);
  box-shadow: var(--sh-lg);
}
.help__card:hover { transform: translateY(-3px); }
.post-lead:hover .post-lead__thumb,
.post-row:hover .post-row__thumb { transform: translateY(-4px); }

/* 5.3 — LE RÉSEAU : chaque canal charrie la couleur de l'outil dont il vient,
   et tous vont VERS WeRefund — des PSP vers le bas, des plateformes vers le
   haut. Trois règles de conception, chacune tirée d'un défaut évité :

   · Onze durées TOUTES DIFFÉRENTES (3,8 à 5,8 s). Avec une durée commune, les
     paquets se réalignent à chaque tour et le réseau se met à battre la
     mesure — l'effet devient mécanique en dix secondes.
   · Décalages NÉGATIFS : le réseau est déjà peuplé au premier rendu, il n'y a
     pas de premier tour à vide où rien ne circule.
   · La couleur, la durée et le décalage d'un canal sont posés dans le HTML sur
     le nœud (donc la tuile) et, à l'identique, sur ses deux tracés (scène
     large, scène étroite) — un paquet ne peut pas partir d'une tuile et
     arriver dans une autre couleur. */
html.js-anim .tree__wires .tree__flow path {
  animation: packet var(--t, 4.6s) linear infinite;
  animation-delay: var(--d, 0s);
  /* Le flou est en unités du SVG : la scène étroite, plus réduite, l'élargit. */
  filter: drop-shadow(0 0 var(--glow, 4px) var(--c));
}
@keyframes packet {
  from { stroke-dashoffset: 12; }    /* juste avant l'entrée du canal */
  to   { stroke-dashoffset: -109; }  /* juste après la sortie */
}

/* La tuile s'allume à l'instant précis où son paquet part : la source est
   visible, sinon les couleurs semblent surgir de nulle part. */
html.js-anim .tree__node .app-tile::after {
  animation: tile-emit var(--t, 4.6s) linear infinite;
  animation-delay: var(--d, 0s);
}
@keyframes tile-emit {
  0%           { opacity: .85; transform: scale(1); }
  14%          { opacity: 0;   transform: scale(1.24); }
  14.01%, 100% { opacity: 0;   transform: scale(1); }
}

/* Respiration lente et décalée des tuiles, indépendante du flux. */
html.js-anim .tree__node .app-tile {
  animation: tile-float 5.5s var(--ease) infinite;
  animation-delay: calc(var(--i, 0) * 320ms);
}
@keyframes tile-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}

/* 5.4 — Le concentrateur reçoit des deux côtés : un pouls lent, seul geste
   propre à WeRefund dans le réseau. */
html.js-anim .tree__hub { animation: hub-pulse 2.4s var(--ease) infinite; }
@keyframes hub-pulse {
  0%           { box-shadow: var(--sh-pop), 0 0 0 0 var(--accent-glow); }
  20%          { box-shadow: var(--sh-pop), 0 0 0 15px transparent; }
  20.01%, 100% { box-shadow: var(--sh-pop), 0 0 0 0 transparent; }
}

/* 5.5 — Bandeau « Works with » : UNE ligne, défilement continu de droite à gauche,
   en CSS seul (il ne dépend pas de js-anim). La piste porte la liste et sa copie,
   chacune suivie du même espacement : reculer de 50 % ramène exactement au
   départ, sans saut. Pause au survol et quand le focus est dans le bandeau.
   Rico, 15/09 : toujours en défilement, pour tout le monde — plus de version
   rangée sur deux lignes, même en mouvement réduit.
   La coupure globale de base.css (sur `*` en mouvement réduit : durée .01 ms,
   une seule itération, en !important) figerait la piste. Les deux dernières
   déclarations de `.marquee__track` la contredisent, en !important elles
   aussi : à importance égale, une classe l'emporte sur `*`. Elles ne sont pas
   sous media query, exprès : elles valent quelle que soit la préférence. La
   pause au survol passe par animation-play-state, que la coupure ne touche
   pas. La mise en page (une ligne, copie affichée) est dans sections.css. */
.marquee {
  overflow: hidden;
  padding-left: 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, var(--ink) 9%, var(--ink) 91%, transparent);
  mask-image: linear-gradient(90deg, transparent, var(--ink) 9%, var(--ink) 91%, transparent);
}
.marquee__track {
  width: max-content;
  animation: marquee 46s linear infinite;
  animation-duration: 46s !important;
  animation-iteration-count: infinite !important;
}
.marquee__list {
  flex: none;
  padding-right: var(--mq-gap);
}
.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track { animation-play-state: paused; }
@keyframes marquee {
  to { transform: translate3d(-50%, 0, 0); }
}


/* ==========================================================================
   6. Enrichissement piloté par le défilement
   `animation-timeline` n'existe pas partout : tout ce bloc est un bonus, et
   son absence ne retire rien à la page.
   ========================================================================== */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Dérive lente des visuels d'articles pendant leur traversée de l'écran.
       Elle joue sur `background-position`, jamais sur `transform` : le survol
       de ces mêmes vignettes utilise `transform`, et deux écritures de la même
       propriété se seraient annulées en silence.
       Le fond est volontairement plus grand que sa boîte, sinon il n'y a rien
       à déplacer. */
    .post-lead__thumb,
    .post-row__thumb .face {
      background-size: 100% 132%;
      animation: img-drift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    @keyframes img-drift {
      from { background-position: 50% 8%; }
      to   { background-position: 50% 92%; }
    }
  }
}


/* ==========================================================================
   7. Coupure générale
   Un visiteur qui a demandé moins de mouvement ne reçoit AUCUN des effets
   ci-dessus — y compris ceux qui partent d'un état invisible, qui doivent
   alors se poser immédiatement à leur état final plutôt que disparaître.
   Une seule exception, voulue : le bandeau « Works with » (§ 5.5).
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html.js-anim [data-enter],
  html.js-reveal [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    animation: none !important;
    transition: none !important;
  }
  html.js-anim .tree__hub,
  html.js-anim .tree__node .app-tile {
    animation: none !important;
    opacity: 1;
    transform: none;
  }
  /* Le réseau coloré s'éteint entièrement : les paquets retournent hors des
     canaux et les anneaux d'émission disparaissent. Il ne reste que les rails
     gris, qui sont la structure et non le mouvement. Le bandeau « Works with »
     n'est pas coupé : il défile pour tout le monde, sa piste passe outre la
     coupure globale de base.css (§ 5.5). */
  html.js-anim .tree__wires .tree__flow path {
    animation: none !important;
    stroke-dashoffset: 12;
    filter: none;
  }
  html.js-anim .tree__node .app-tile::after {
    animation: none !important;
    opacity: 0;
  }
  .bento__cell:hover .bento__art,
  .help__card:hover,
  .post-lead:hover .post-lead__thumb,
  .post-row:hover .post-row__thumb { transform: none; }
}
