/*
  css/animations.css
  BETA B7 — Animations et micro-interactions transverses. Fichier dedie
  (plutot que disperse dans chaque feuille d'ecran) pour que cette passe de
  "polish" reste facile a auditer, desactiver ou retirer d'un bloc si
  besoin, sans toucher au reste du CSS.

  Regles impératives de ce fichier (voir UI_POLISH.md) :
    - Uniquement transform/opacity dans les animations en boucle ou
      declenchees frequemment (jamais width/height/top/left, qui forcent un
      recalcul de mise en page a chaque frame).
    - Toute duree provient des tokens --duration-* (tokens.css), deja mis a
      0ms a la fois par [data-reduce-motion="true"] (reglage applicatif,
      accessibility.css) et par prefers-reduced-motion (preference systeme,
      meme fichier, regle generique). Aucune duree codee en dur ici : une
      animation qui ignorerait les tokens ignorerait aussi les deux
      mecanismes de reduction, ce qui est exactement ce que ce fichier doit
      eviter.
    - Aucune dependance externe : uniquement des @keyframes CSS.
*/

/* ============================================================================
   1. Transition d'apparition entre ecrans (js/core/router.js)
   ============================================================================ */
/* Chaque ecran est un <section> reconstruit et re-attache a #app-root a
   chaque navigation (voir router.js#render, container.replaceChildren()).
   Une regle CSS ciblant l'element fraichement insere suffit : les
   animations CSS (contrairement aux transitions) se declenchent
   automatiquement a l'insertion dans le DOM, sans code JS supplementaire. */
#app-root > section {
  animation: screen-enter var(--duration-base) var(--easing-standard);
}

@keyframes screen-enter {
  from {
    opacity: 0;
    transform: translateY(var(--space-2));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ============================================================================
   2. Confirmation de copie du lien/code (js/screens/lobby.js)
   ============================================================================ */
.lobby-code-card__copy--confirmed {
  animation: copy-confirm var(--duration-slow) var(--easing-standard);
}

@keyframes copy-confirm {
  0% { transform: scale(1); }
  30% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

/* ============================================================================
   3. Apparition progressive d'un nouvel indice (js/screens/game.js)
   ============================================================================ */
/* Appliquee uniquement au dernier <li> ajoute par renderClueList() (voir
   game.js), pas a la liste entiere a chaque re-rendu : la liste est
   reconstruite en integralite a chaque changement (replaceChildren()), donc
   sans ce ciblage precis, TOUS les indices deja affiches rejoueraient
   l'animation a chaque nouvel indice - highlight incorrect et distrayant. */
.game-clues-list__item--enter {
  animation: clue-enter var(--duration-base) var(--easing-standard);
}

@keyframes clue-enter {
  from {
    opacity: 0;
    transform: translateX(calc(-1 * var(--space-3)));
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* ============================================================================
   4. Mise en evidence du joueur dont c'est le tour (js/screens/game.js)
   ============================================================================ */
/* .game-turn-order__item--current existe deja (mise en evidence statique,
   voir game.css) : impulsion ponctuelle en plus, a chaque fois que ce
   joueur devient celui dont c'est le tour (la classe est reappliquee a
   chaque reconstruction de la liste declenchee par un nouvel indice, donc
   au bon rythme - un rendu = un changement d'etat reel, jamais une boucle). */
.game-turn-order__item--current {
  animation: turn-pulse var(--duration-slow) var(--easing-standard);
}

@keyframes turn-pulse {
  0% { transform: scale(1); }
  40% { transform: scale(1.03); }
  100% { transform: scale(1); }
}

/* ============================================================================
   5. Minuteur visuel qui se vide progressivement (game.js, vote.js, results.js)
   ============================================================================ */
/* Barre generique : la largeur du conteneur reste fixe, seul le fill est
   mis a l'echelle via transform: scaleX(...) depuis la droite ou la gauche
   selon le sens de lecture (aucun recalcul de mise en page par frame,
   contrairement a une approche par width). La valeur de scaleX est ecrite
   en JS a chaque tick existant (onTimerTick, deja cable dans les 3 ecrans -
   aucun nouveau minuteur, seulement un habillage visuel du minuteur textuel
   deja fonctionnel). */
.timer-bar {
  position: relative;
  width: 100%;
  height: 4px;
  border-radius: var(--radius-full);
  background-color: var(--color-border);
  overflow: hidden;
}

.timer-bar__fill {
  position: absolute;
  inset: 0;
  transform-origin: left center;
  background-color: var(--color-primary);
  border-radius: var(--radius-full);
  /* Transition courte entre deux ticks (1s d'ecart) pour un mouvement
     fluide plutot qu'un saut sec, jamais plus longue que l'intervalle du
     minuteur lui-meme. */
  transition: transform var(--duration-base) linear;
}

.timer-bar__fill--urgent {
  background-color: var(--color-danger);
}

/* ============================================================================
   6. Revelation du Cameleon (js/screens/results.js)
   ============================================================================ */
/* Effet marquant mais bref (< 1s, voir duration-slow = 320ms) : ne bloque
   jamais la lecture du texte (l'animation est purement visuelle, le texte
   est present et lisible des le premier frame via opacity qui ne descend
   jamais en dessous de la lisibilite). */
.results-reveal__chameleon {
  animation: reveal-pop var(--duration-slow) var(--easing-standard);
}

@keyframes reveal-pop {
  0% {
    opacity: 0;
    transform: scale(0.92) translateY(calc(-1 * var(--space-1)));
  }
  60% {
    opacity: 1;
    transform: scale(1.02) translateY(0);
  }
  100% {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

/* ============================================================================
   7. Confettis legers pour la victoire finale (js/screens/results.js, ecran
      de fin de partie)
   ============================================================================ */
/* Approche CSS/SVG legere : un petit nombre de rectangles colores (pas
   d'image, pas de canvas, pas de librairie), chacun anime independamment
   en transform (translateY + rotate) et opacity uniquement. Nombre de
   particules volontairement limite (voir game-over-confetti__piece:nth-child
   ci-dessous, 12 elements) pour rester leger sur un mobile d'entree de
   gamme - un vrai systeme de particules canvas serait hors de la contrainte
   "aucune dependance externe, budget de performance strict". */
.game-over-confetti {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.game-over-confetti__piece {
  position: absolute;
  top: -10px;
  width: 8px;
  height: 14px;
  opacity: 0;
  border-radius: var(--radius-sm);
  animation: confetti-fall 2.4s var(--easing-standard) forwards;
  animation-delay: var(--confetti-delay, 0s);
}

@keyframes confetti-fall {
  0% {
    opacity: 1;
    transform: translateY(0) rotate(0deg);
  }
  100% {
    opacity: 0;
    transform: translateY(220px) rotate(280deg);
  }
}

/* ============================================================================
   8. Apparition en cascade des cellules de la grille de 16 mots (js/screens/game.js)
   ============================================================================ */
/* Chaque cellule de la grille recoit un delai calcule en JS via une custom
   property --cell-delay, produisant un effet de cascade leger (de gauche a
   droite, de haut en bas) au moment ou la grille est revelee. Uniquement
   transform/opacity, delai maximal de 16 * 40ms = 640ms pour la derniere
   cellule (acceptable car ponctuel, pas une boucle). */
.game-grid__cell--enter {
  opacity: 0;
  animation: grid-cell-enter var(--duration-base) var(--easing-standard) forwards;
  animation-delay: var(--cell-delay, 0ms);
}

@keyframes grid-cell-enter {
  from {
    opacity: 0;
    transform: scale(0.92);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* ============================================================================
   9. Impulsion de selection lors du vote (js/screens/vote.js)
   ============================================================================ */
/* Quand un joueur est selectionne comme suspect (.vote-player-item--selected
   appliquee via JS), une breve impulsion visuelle confirme l'action.
   Uniquement transform, duree courte pour ne pas distraire. */
.vote-player-item--selected {
  animation: vote-select-pulse var(--duration-slow) var(--easing-standard);
}

@keyframes vote-select-pulse {
  0% { transform: scale(1); }
  35% { transform: scale(1.02); }
  100% { transform: scale(1); }
}

/* ============================================================================
   10. Apparition en cascade du classement final (js/screens/results.js)
   ============================================================================ */
/* Chaque ligne du classement de fin de partie apparait avec un leger decalage
   (--rank-delay calcule en JS), donnant un effet de "revele progressif" du
   podium. Uniquement transform/opacity. */
.results-gameover__item--enter {
  opacity: 0;
  animation: rank-enter var(--duration-base) var(--easing-standard) forwards;
  animation-delay: var(--rank-delay, 0ms);
}

@keyframes rank-enter {
  from {
    opacity: 0;
    transform: translateY(var(--space-2));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ============================================================================
   11. Revelation du badge de resultat (js/screens/results.js)
   ============================================================================ */
/* Le badge de resultat (echappee/nul/capture) apparait avec un effet "pop"
   bref et marquant, coherent avec l'importance de l'information. Uniquement
   transform/opacity, duree courte (< 1s). */
.results-reveal__outcome {
  animation: outcome-pop var(--duration-slow) var(--easing-standard);
}

@keyframes outcome-pop {
  0% {
    opacity: 0;
    transform: scale(0.85);
  }
  60% {
    opacity: 1;
    transform: scale(1.04);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* ============================================================================
   12. Revelation du mot secret dans les resultats (js/screens/results.js)
   ============================================================================ */
/* Le mot secret apparait avec un leger fondu + translation, soulignant son
   importance sans etre trop voyant (le Cameleon vient juste d'etre revele). */
.results-reveal__secret {
  animation: secret-reveal var(--duration-base) var(--easing-standard);
}

@keyframes secret-reveal {
  from {
    opacity: 0;
    transform: translateY(var(--space-1));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ============================================================================
   13. Apparition de la notice Cameleon (js/screens/game.js, phase ROUND_REVEAL)
   ============================================================================ */
/* Le message "Vous etes le Cameleon !" apparait avec un effet legerement
   plus marque que le reste, pour que le joueur le remarque immediatement. */
.game-reveal__chameleon--enter {
  animation: chameleon-notice var(--duration-slow) var(--easing-standard);
}

@keyframes chameleon-notice {
  0% {
    opacity: 0;
    transform: scale(0.95);
  }
  50% {
    opacity: 1;
    transform: scale(1.02);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* ============================================================================
   14. Revelation du nom du theme (js/screens/game.js, phase ROUND_REVEAL)
   ============================================================================ */
/* Le nom du theme apparait avec un fondu discret, coherent avec le reste de
   la phase de revelation. */
.game-reveal__theme-name--enter {
  animation: theme-reveal var(--duration-base) var(--easing-standard);
}

@keyframes theme-reveal {
  from {
    opacity: 0;
    transform: translateY(var(--space-1));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ============================================================================
   15. Entree d'un joueur dans le lobby (js/screens/lobby.js)
   ============================================================================ */
/* Quand un nouveau joueur rejoint le lobby, sa ligne apparait avec un leger
   glissement depuis le bas. La classe --enter est appliquee uniquement aux
   joueurs nouvellement ajoutes (pas a toute la liste a chaque rendu). */
.lobby-player-item--enter {
  animation: player-enter var(--duration-base) var(--easing-standard);
}

@keyframes player-enter {
  from {
    opacity: 0;
    transform: translateY(var(--space-2));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ============================================================================
   16. Pulsation urgente du minuteur (< 25% restant)
   ============================================================================ */
/* Quand le minuteur passe en mode urgent (.timer-bar__fill--urgent), la
   barre pulse doucement en plus de changer de couleur, attirant l'attention
   sans etre anxiogene. Animation en boucle mais uniquement sur opacity,
   tres legere (0.7 -> 1), donc peu couteuse. */
.timer-bar__fill--urgent {
  animation: timer-urgent-pulse 1s var(--easing-standard) infinite;
}

@keyframes timer-urgent-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.7; }
}

/* ============================================================================
   17. Apparition en cascade des lignes de score (js/screens/results.js)
   ============================================================================ */
/* Chaque ligne du tableau de scores apparait avec un leger decalage,
   donnant un effet de remplissage progressif du tableau. */
.results-scores__row--enter {
  opacity: 0;
  animation: score-row-enter var(--duration-base) var(--easing-standard) forwards;
  animation-delay: var(--score-delay, 0ms);
}

@keyframes score-row-enter {
  from {
    opacity: 0;
    transform: translateX(calc(-1 * var(--space-2)));
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* ============================================================================
   18. Apparition en cascade des boutons du menu principal (js/screens/menu.js)
   ============================================================================ */
/* Les boutons d'action du menu principal (Creer, Rejoindre) apparaissent
   avec un leger decalage pour un effet de "mise en scene" a l'arrivee sur
   l'accueil. */
.menu-actions .btn--enter {
  opacity: 0;
  animation: menu-btn-enter var(--duration-base) var(--easing-standard) forwards;
  animation-delay: var(--menu-btn-delay, 0ms);
}

@keyframes menu-btn-enter {
  from {
    opacity: 0;
    transform: translateY(var(--space-2));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ============================================================================
   19. Feedback de pression sur les boutons (tous ecrans)
   ============================================================================ */
/* Un leger retrecissement au toucher/clic donne un feedback tactile
   satisfaisant. Uniquement transform, pas de transition de layout. */
.btn:active:not(:disabled) {
  transform: scale(0.97);
}

/* ============================================================================
   Reduction des animations : cas non couverts par les tokens de duree
   ============================================================================ */
/* Les regles ci-dessus utilisent toutes var(--duration-*), donc deja
   neutralisees a 0ms par [data-reduce-motion="true"] ET par
   prefers-reduced-motion (voir accessibility.css). Les confettis utilisent
   une duree codee en 2.4s car ce sont des particules decoratives isolees,
   pas des transitions d'interface : elles doivent neanmoins disparaitre
   entierement dans les deux cas, couvert explicitement ici (aucun des deux
   mecanismes generiques ne les neutralise, une duree en dur n'etant pas un
   token --duration-*). */
:root[data-reduce-motion="true"] .game-over-confetti__piece {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .game-over-confetti__piece {
    display: none;
  }
}

/* Le minuteur urgent pulse utilise une duree codee en dur (1s) car c'est
   une boucle continue, pas une transition ponctuelle : il doit etre
   neutralise explicitement par les deux mecanismes de reduction. */
:root[data-reduce-motion="true"] .timer-bar__fill--urgent {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  .timer-bar__fill--urgent {
    animation: none;
  }
}
