/* ============================================================================
   BOUGE — mouvement.css
   Le mouvement répond à une action. Rien ne bouge au chargement, rien ne
   boucle, rien ne clignote. Seuls `transform`, `opacity` et
   `stroke-dashoffset` sont animés — ce sont les trois propriétés que le
   téléphone d'entrée de gamme compose sans repeindre.
   ============================================================================ */

/* ---------- 1. Pression ---------- */

.bouton,
.bouton-rond,
.carte-coach,
.nav__item {
  transition:
    transform var(--duree-1) var(--courbe-sortie),
    background-color var(--duree-2) var(--courbe-sortie),
    border-color var(--duree-2) var(--courbe-sortie),
    color var(--duree-2) var(--courbe-sortie);
}

.bouton:active,
.bouton-rond:active,
.carte-coach:active {
  transform: scale(0.97);
}

/* ---------- 2. Bouton GO ---------- */
/* Le GO se pose avec un ressort court (12,6 % de dépassement, posé à 88 %) :
   c'est la seule respiration de l'app, et elle n'a lieu qu'à l'ouverture de
   l'accueil et au relâchement du doigt. */

.bouton-go {
  transition:
    transform var(--duree-6) var(--ressort-go),
    box-shadow var(--duree-2) var(--courbe-sortie);
}

.bouton-go:active {
  transform: scale(0.96) translateY(2px);
  transition-duration: var(--duree-1);
  transition-timing-function: var(--courbe-sortie);
}

.bouton-go--arrive {
  animation: go-arrive var(--duree-6) var(--ressort-go) both;
}

@keyframes go-arrive {
  from {
    transform: scale(0.9);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

/* ---------- 3. Cartes et portraits ---------- */

.carte--arrive,
.carte-coach--arrive {
  animation: carte-arrive var(--duree-5) var(--ressort-doux) both;
}

@keyframes carte-arrive {
  from {
    transform: translateY(10px);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

/* ---------- 4. Chronomètre ---------- */
/* L'arc avance d'une seconde par seconde, en linéaire : une courbe
   d'assouplissement ferait mentir le temps affiché. */

.chrono__arc {
  transition: stroke-dashoffset var(--duree-anneau) var(--courbe-lineaire);
}

/* Les trois dernières secondes : l'arc et le chiffre passent en accent,
   sans clignotement. Un changement d'état, pas une alarme. */
.chrono--fin .chrono__valeur {
  color: var(--accent);
  transition: color var(--duree-2) var(--courbe-sortie);
}

/* ---------- 5. Barre de progression ---------- */

.barre__remplissage {
  transition: width var(--duree-4) var(--courbe-sortie);
}

/* ---------- 6. Compte à rebours 3-2-1 ---------- */

.compte__chiffre--anime {
  animation: compte-pose var(--duree-6) var(--ressort-go) both;
}

@keyframes compte-pose {
  from {
    transform: scale(1.35);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

/* ---------- 7. Bascules et pastilles ---------- */

.bascule::before,
.bascule::after {
  transition:
    background-color var(--duree-2) var(--courbe-sortie),
    border-color var(--duree-2) var(--courbe-sortie),
    left var(--duree-2) var(--ressort-doux),
    right var(--duree-2) var(--ressort-doux);
}

.pastille__disque {
  transition:
    background-color var(--duree-2) var(--courbe-sortie),
    color var(--duree-2) var(--courbe-sortie);
}

/* ---------- 7 bis. Carte des muscles ---------- */
/* Appuyer sur un nom isole son muscle : les autres s'effacent au lieu de
   disparaître d'un coup. Seules `fill` et `opacity` changent — la silhouette
   ne bouge pas, rien ne clignote. */

.muscles__corps .muscle {
  transition:
    fill var(--duree-2) var(--courbe-sortie),
    opacity var(--duree-2) var(--courbe-sortie);
}

/* ---------- 8. Voile et feuille ---------- */

.voile--arrive {
  animation: voile-arrive var(--duree-3) var(--courbe-sortie) both;
}

@keyframes voile-arrive {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.feuille--arrive {
  animation: feuille-arrive var(--duree-5) var(--ressort-doux) both;
}

@keyframes feuille-arrive {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}

/* ---------- 9. Changement d'écran (View Transitions) ---------- */

::view-transition-old(root) {
  animation: var(--duree-3) var(--courbe-entree) both ecran-sort;
}

::view-transition-new(root) {
  animation: var(--duree-4) var(--courbe-sortie) both ecran-entre;
}

/* ⚠️ Ne JAMAIS écrire `animation: none` sur un `::view-transition-old/new`.
   Un élément nommé présent dans l'ancien écran et absent du nouveau produit
   un `old` sans `new` : sans animation, ce pseudo-élément ne se retire
   jamais, la couche de transition reste au-dessus de la page et avale tous
   les taps. L'app s'affiche normalement et ne répond plus à rien.
   C'est pour la même raison que la barre de navigation et le bouton GO n'ont
   pas de `view-transition-name` : ils font partie du fondu de la racine.
   Le test qui attrape cette panne : après une navigation,
   `document.elementFromPoint(innerWidth/2, innerHeight/2)` ne doit être ni
   la surcouche ni un de ses descendants, ET un vrai clic sur un bouton doit
   produire son effet. */

@keyframes ecran-sort {
  to {
    opacity: 0;
  }
}

@keyframes ecran-entre {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ---------- 10. Mouvement réduit ---------- */
/* Règle : une animation devient un changement instantané. Jamais un
   scintillement, jamais une durée nulle qui ferait sauter l'événement
   `transitionend` — 1 ms, l'état final s'applique tout de suite et les
   écouteurs se déclenchent quand même.
   Aucune exception : l'arc du chronomètre et la barre de progression passent
   eux aussi à 1 ms. Ils avancent alors d'un cran par seconde au lieu de
   glisser — c'est exactement le comportement attendu, la valeur affichée
   reste juste à chaque instant. Mesuré : 0,52 s / 0,32 s / 1 s en mouvement
   normal, 0,001 s partout en mouvement réduit. */

@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;
  }

  .bouton:active,
  .bouton-rond:active,
  .carte-coach:active,
  .bouton-go:active,
  .bouton-go--arrive,
  .carte--arrive,
  .carte-coach--arrive,
  .compte__chiffre--anime,
  .voile--arrive,
  .feuille--arrive {
    animation: none !important;
    transform: none !important;
    opacity: 1 !important;
  }

  ::view-transition-old(root),
  ::view-transition-new(root) {
    /* Fondu ramené à 1 ms : la transition se termine et la couche se retire.
       `animation: none` la laisserait au-dessus de la page pour toujours. */
    animation-duration: 1ms;
  }
}

/* Même effet quand le réglage vient de l'app plutôt que du système. */
html[data-mouvement="reduit"] *,
html[data-mouvement="reduit"] *::before,
html[data-mouvement="reduit"] *::after {
  animation-duration: 1ms !important;
  animation-delay: 0ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 1ms !important;
  transition-delay: 0ms !important;
}

/* Cette liste doit rester le MIROIR de celle du bloc `prefers-reduced-motion`
   ci-dessus : une classe d'entrée ajoutée d'un seul côté serait coupée par le
   réglage du système et pas par celui de l'app, ou l'inverse. */
html[data-mouvement="reduit"] .bouton-go--arrive,
html[data-mouvement="reduit"] .carte--arrive,
html[data-mouvement="reduit"] .carte-coach--arrive,
html[data-mouvement="reduit"] .compte__chiffre--anime,
html[data-mouvement="reduit"] .voile--arrive,
html[data-mouvement="reduit"] .feuille--arrive {
  animation: none !important;
  transform: none !important;
  opacity: 1 !important;
}
