/* ==========================================================================
   RETROVAULT — motion.css · C3 « Système de motion unifié »
   Réf : docs/CHANTIERS-UX.md §C3 · docs/UX-AUDIT-2026.md §3 (R1→R8) + P18
         docs/DA-V4-G.md · docs/DA-SPEC.md §12 · docs/MOTION.md

   UNE seule source de mouvement. Les VALEURS sont dans css/tokens.css
   (--dur-*, --ease-*, --pas-cascade) ; ce fichier n'en contient AUCUNE en dur.

   Chargé en DERNIER sur toutes les pages : il harmonise ce que forgeos.css,
   pages.css, compte.css et admin.css avaient chacun posé de leur côté.

   Sommaire
     1. Cascade d'apparition (.reveal)
     2. Rebond des boutons et des blocs (hover / press)
     3. Modales natives (<dialog>) — scale .96 → 1 + fondu
     4. Toasts — slide-up
     5. Formes de fond — flottement 6-9 s
     6. Scroll-driven (@supports) — apparition des sections
     7. prefers-reduced-motion
   ========================================================================== */

/* ==========================================================================
   1. CASCADE D'APPARITION
   --------------------------------------------------------------------------
   `--rv-i` = INDEX (0, 1, 2…), pas une durée : c'est --pas-cascade qui porte
   le temps. js/forgeos.js le pose à l'entrée dans la fenêtre ; le HTML et les
   gabarits JS le posent pour les blocs au-dessus de la ligne de flottaison.
   Plafond à 6 : au-delà, le 13ᵉ bloc d'une grille attendrait une demi-seconde.
   ========================================================================== */
/* La liste `.reveal.bento`, `.reveal.card`… n'est pas décorative : un bloc qui
   apparaît est presque toujours AUSSI un bento ou une carte, et la règle de
   survol du §2 (même spécificité, écrite plus bas) lui volerait sa transition
   d'opacité. On monte donc la spécificité à 0,2,0 pour ces combinaisons. */
.reveal,
.reveal.bento, .reveal.card, .reveal.win, .reveal.rv-carte {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity   var(--dur-base) var(--ease-enter) calc(var(--rv-i, 0) * var(--pas-cascade)),
    transform var(--dur-base) var(--ease-enter) calc(var(--rv-i, 0) * var(--pas-cascade));
}
.reveal.is-in,
.reveal.is-in.bento, .reveal.is-in.card,
.reveal.is-in.win, .reveal.is-in.rv-carte { opacity: 1; transform: none; }

/* Repli sans JS : les six premiers enfants d'une grille cascadent quand même.
   (Écrasé dès que forgeos.js pose son propre --rv-i, qui est plus précis.) */
.bento-grid > .reveal:nth-child(1),
.grid > .reveal:nth-child(1),
.grid-2 > .reveal:nth-child(1), .grid-3 > .reveal:nth-child(1),
.grid-4 > .reveal:nth-child(1), .grid-auto > .reveal:nth-child(1) { --rv-i: 0; }
.bento-grid > .reveal:nth-child(2),
.grid > .reveal:nth-child(2),
.grid-2 > .reveal:nth-child(2), .grid-3 > .reveal:nth-child(2),
.grid-4 > .reveal:nth-child(2), .grid-auto > .reveal:nth-child(2) { --rv-i: 1; }
.bento-grid > .reveal:nth-child(3),
.grid > .reveal:nth-child(3),
.grid-2 > .reveal:nth-child(3), .grid-3 > .reveal:nth-child(3),
.grid-4 > .reveal:nth-child(3), .grid-auto > .reveal:nth-child(3) { --rv-i: 2; }
.bento-grid > .reveal:nth-child(4),
.grid > .reveal:nth-child(4),
.grid-2 > .reveal:nth-child(4), .grid-3 > .reveal:nth-child(4),
.grid-4 > .reveal:nth-child(4), .grid-auto > .reveal:nth-child(4) { --rv-i: 3; }
.bento-grid > .reveal:nth-child(5),
.grid > .reveal:nth-child(5),
.grid-2 > .reveal:nth-child(5), .grid-3 > .reveal:nth-child(5),
.grid-4 > .reveal:nth-child(5), .grid-auto > .reveal:nth-child(5) { --rv-i: 4; }
.bento-grid > .reveal:nth-child(n + 6),
.grid > .reveal:nth-child(n + 6),
.grid-2 > .reveal:nth-child(n + 6), .grid-3 > .reveal:nth-child(n + 6),
.grid-4 > .reveal:nth-child(n + 6), .grid-auto > .reveal:nth-child(n + 6) { --rv-i: 5; }

/* ==========================================================================
   2. REBOND DES BOUTONS ET DES BLOCS
   --------------------------------------------------------------------------
   Rebond LÉGER (C3) : hover 1.02, press .97. L'appui est deux fois plus
   court que l'entrée, pour qu'il se sente instantané sous le doigt.
   R2 : aucun overshoot — l'échelle ne dépasse jamais sa valeur d'arrivée,
   et rien de tout cela ne touche un prix ni un état de stock.
   ========================================================================== */
.pill, .btn, .key, .fo-vault, .adl-g, .adl-apple {
  transition:
    transform  var(--dur-fast) var(--ease-standard),
    background var(--dur-fast) var(--ease-standard),
    color      var(--dur-fast) var(--ease-standard),
    border-color var(--dur-fast) var(--ease-standard),
    box-shadow var(--dur-fast) var(--ease-standard);
}
.pill:hover, .btn:hover, .key:hover,
.fo-vault:hover, .adl-g:hover {
  transform: translateY(-2px) scale(1.02);
}
.pill:active, .btn:active, .key:active,
.fo-vault:active, .adl-g:active {
  transform: translateY(0) scale(.97);
  transition-duration: var(--dur-press);
}
/* Un bouton désactivé ou purement textuel ne rebondit pas. */
.pill[disabled], .btn[disabled], .key[disabled],
.pill[disabled]:hover, .btn[disabled]:hover, .key[disabled]:hover,
.pill[disabled]:active, .btn[disabled]:active, .key[disabled]:active,
.btn-lien:hover, .btn-lien:active,
.adl-apple:hover, .adl-apple:active { transform: none; }

/* Blocs bento et cartes : le soulèvement de 6 px de la DA v4, sur la courbe
   commune. Pas d'échelle ici — un bloc qui grandit déplace ses voisins à
   l'œil et fait vibrer la grille. */
.bento, .card, .win, .rv-carte {
  transition:
    transform  var(--dur-base) var(--ease-standard),
    box-shadow var(--dur-base) var(--ease-standard);
}
.bento:active, a.win:active, .card:active { transition-duration: var(--dur-press); }
.bento.plat:hover, .bento.plat:active { transform: none; }

/* ==========================================================================
   3. MODALES NATIVES — <dialog> · scale .96 → 1 + fondu
   --------------------------------------------------------------------------
   `@starting-style` (état d'ENTRÉE) + `transition-behavior: allow-discrete`
   (sans lui, la SORTIE est instantanée : piège nº 1 de ce motif, R6).
   Entrée sur --ease-enter, sortie plus courte sur --ease-exit.
   ========================================================================== */
.fo-dialog {
  opacity: 0;
  transform: scale(.96);
  transition:
    opacity   var(--dur-fast) var(--ease-exit),
    transform var(--dur-fast) var(--ease-exit),
    overlay   var(--dur-fast) var(--ease-exit) allow-discrete,
    display   var(--dur-fast) var(--ease-exit) allow-discrete;
}
.fo-dialog::backdrop {
  opacity: 0;
  transition:
    opacity var(--dur-fast) var(--ease-exit),
    overlay var(--dur-fast) var(--ease-exit) allow-discrete,
    display var(--dur-fast) var(--ease-exit) allow-discrete;
}
.fo-dialog[open] {
  opacity: 1;
  transform: scale(1);
  transition:
    opacity   var(--dur-base) var(--ease-enter),
    transform var(--dur-base) var(--ease-enter),
    overlay   var(--dur-base) var(--ease-enter) allow-discrete,
    display   var(--dur-base) var(--ease-enter) allow-discrete;
}
.fo-dialog[open]::backdrop {
  opacity: 1;
  transition:
    opacity var(--dur-base) var(--ease-enter),
    overlay var(--dur-base) var(--ease-enter) allow-discrete,
    display var(--dur-base) var(--ease-enter) allow-discrete;
}
@starting-style {
  .fo-dialog[open] { opacity: 0; transform: scale(.96); }
  .fo-dialog[open]::backdrop { opacity: 0; }
}

/* ==========================================================================
   4. TOASTS — slide-up
   --------------------------------------------------------------------------
   Le toast reste piloté par `hidden` côté JS (c'est ce que lit le lecteur
   d'écran via role="status"). `display` étant discret, on le transitionne en
   `allow-discrete` : sans cela, l'apparition serait un claquement.
   ========================================================================== */
.fo-toast {
  opacity: 0;
  transform: translateX(-50%) translateY(12px);
  transition:
    opacity   var(--dur-fast) var(--ease-exit),
    transform var(--dur-fast) var(--ease-exit),
    display   var(--dur-fast) var(--ease-exit) allow-discrete;
}
.fo-toast:not([hidden]) {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  transition:
    opacity   var(--dur-base) var(--ease-enter),
    transform var(--dur-base) var(--ease-enter),
    display   var(--dur-base) var(--ease-enter) allow-discrete;
}
@starting-style {
  .fo-toast:not([hidden]) { opacity: 0; transform: translateX(-50%) translateY(12px); }
}

/* ==========================================================================
   5. FORMES DE FOND — flottement 6-9 s
   --------------------------------------------------------------------------
   Purement décoratif, `aria-hidden`, jamais sous un texte de lecture.
   WCAG 2.2.2 : mouvement automatique de plus de 5 s → coupé en §7.
   ========================================================================== */
.fo-formes .flot {
  animation: fo-flot var(--dur-flot) var(--ease-standard) infinite alternate;
  transform-origin: center;
}
.fo-formes .flot:nth-child(2n) {
  animation-duration: var(--dur-flot-2);
  animation-delay: calc(var(--dur-flot) / -5);
}
.fo-formes .flot:nth-child(3n) {
  animation-duration: var(--dur-flot-3);
  animation-delay: calc(var(--dur-flot) / -2.5);
}
.fo-formes .tourne {
  animation: fo-tourne var(--dur-tourne) linear infinite;
  transform-origin: center;
  transform-box: fill-box;
}

/* ==========================================================================
   6. SCROLL-DRIVEN — apparition des sections (amélioration progressive)
   --------------------------------------------------------------------------
   R7 : uniquement décoratif, toujours sous @supports, aucun polyfill JS.
   Firefox reste derrière un flag en 2026 : il garde la cascade JS, qui est
   déjà le comportement par défaut. Jamais sur un prix, un état de stock ni
   un total — d'où l'exclusion explicite des porteurs de chiffres.
   ========================================================================== */
@supports (animation-timeline: view()) {
  .reveal:not(.is-in) {
    animation: rv-entree linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 22%;
  }
  /* Une section entière (titre + grille) monte doucement à l'approche. */
  .sect-motion {
    animation: rv-entree linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 30%;
  }
}
@keyframes rv-entree {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

/* ==========================================================================
   7. prefers-reduced-motion — réduire, pas supprimer
   --------------------------------------------------------------------------
   On garde les fondus d'opacité (ils n'induisent pas de vection) et on retire
   TOUT déplacement, échelle et rotation. Durées ramenées à 1 ms, aucune
   itération, défilement instantané, transitions de vue coupées.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
  html { scroll-behavior: auto !important; }

  /* Aucune translation, aucune échelle, aucune rotation.
     La liste répète les combinaisons du §1 : sans elle, un `.bento.reveal`
     (0,2,0) resterait invisible tant que le JS n'a pas posé `.is-in`. */
  .reveal, .reveal.is-in,
  .reveal.bento, .reveal.card, .reveal.win, .reveal.rv-carte,
  .reveal.is-in.bento, .reveal.is-in.card,
  .reveal.is-in.win, .reveal.is-in.rv-carte { opacity: 1; transform: none; }
  .pill:hover, .btn:hover, .key:hover, .fo-vault:hover, .adl-g:hover,
  .pill:active, .btn:active, .key:active, .fo-vault:active, .adl-g:active,
  .bento:hover, .card:hover, a.win:hover, .win.is-clic:hover,
  .fo-canal:hover { transform: none; }
  .fo-dialog, .fo-dialog[open] { transform: none; }
  .fo-toast, .fo-toast:not([hidden]) { transform: translateX(-50%); }

  /* Formes figées (WCAG 2.2.2) et scroll-driven désarmé : une durée de 1 ms
     ne suffit pas à arrêter une animation pilotée par une timeline. */
  .fo-formes .flot, .fo-formes .tourne { animation: none !important; }
  .reveal:not(.is-in), .sect-motion {
    animation: none !important;
    animation-timeline: auto !important;
  }

  @view-transition { navigation: none; }
}
