/* docs/UPDATE_CELEBRATION.md : styles du moteur partage de celebrations
   (public/js/app/Celebrations.js), utilise a la fois par le vrai plateau
   (jeu.css/#emplacements) et les apercus de la boutique (boutique.css).
   Reprend fidelement le langage visuel de la maquette
   maquette/celebration_pions_rentres/celebrations.css, adapte aux vrais
   pions (jamais leur transform de positionnement, voir docs/BOUTIQUE.md §11
   pour le meme invariant applique a la devoration) et a un point d'origine
   dynamique (au lieu de coordonnees figees). Aucune image d'effet : tout est
   genere en HTML/CSS, seule la couronne utilise Font Awesome Free local. */

/* ---- Calque d'effet partage (positionne par Celebrations.js via left/top
   inline sur le vrai plateau ; centre par defaut à 50%/50% dans une mini-scene
   de boutique) ---- */
.celebration-layer {
	position: absolute;
	left: 50%;
	top: 50%;
	width: 0;
	height: 0;
	pointer-events: none;
	z-index: 60;
}
/* --celebration-echelle : posee par Celebrations.js#joueSurPlateau sur
   #emplacements (largeur reelle / 520px, la taille de plateau de la maquette
   pour laquelle tous les px ci-dessous ont ete regles). Chaque taille, distance
   et ombre en px de ce fichier est multipliee par elle pour rester
   proportionnelle au plateau, quel que soit l'ecran. Absente dans les
   mini-scenes de la boutique : repli a 1, rendu inchange. */

/* ---- Confettis de la base ---- */
.confetti-piece {
	--x: 0px; --y: 0px; --r: 0deg; --delay: 0s; --duration: 1.8s;
	position: absolute;
	left: 0; top: 0;
	width: calc(6px * var(--celebration-echelle, 1)); height: calc(14px * var(--celebration-echelle, 1));
	border-radius: calc(2px * var(--celebration-echelle, 1));
	background: var(--color);
	opacity: 0;
	transform: translate(-50%, -50%);
}
.celebration-effect-confetti.is-playing .confetti-piece {
	animation: celebration-confetti-flight var(--duration) cubic-bezier(.18, .7, .35, 1) var(--delay) both;
}
@keyframes celebration-confetti-flight {
	0% { opacity: 0; transform: translate(-50%, -50%) rotate(0) scale(.4); }
	9% { opacity: 1; }
	65% { opacity: 1; }
	100% { opacity: 0; transform: translate(calc(-50% + calc(var(--x) * var(--celebration-echelle, 1))), calc(-50% + calc(var(--y) * var(--celebration-echelle, 1)))) rotate(var(--r)) scale(.92); }
}

/* ---- Bouquet final (feux d'artifice) ---- */
.firework { position: absolute; left: 0; top: 0; width: 1px; height: 1px; }
.firework i {
	--angle: 0deg;
	position: absolute; left: 0; top: 0;
	width: calc(3px * var(--celebration-echelle, 1)); height: calc(22px * var(--celebration-echelle, 1));
	border-radius: 99px;
	background: linear-gradient(to top, transparent, var(--spark, #ffd700));
	opacity: 0;
	transform-origin: 50% 100%;
	transform: rotate(var(--angle)) translateY(0) scaleY(.1);
}
/* --spark : toujours pose en inline par Celebrations.js#construitFeuxArtifice
   (teinte du pion du joueur) - le repli ci-dessus ne sert qu'en dernier
   recours si le JS n'a pas tourne. */
.firework.fw-1 { transform: translate(calc(-16px * var(--celebration-echelle, 1)), calc(-14px * var(--celebration-echelle, 1))); --fire-delay: .12s; }
.firework.fw-2 { transform: translate(calc(14px * var(--celebration-echelle, 1)), calc(-20px * var(--celebration-echelle, 1))); --fire-delay: .52s; }
.firework.fw-3 { transform: translate(0, calc(-38px * var(--celebration-echelle, 1))); --fire-delay: .92s; }
.celebration-effect-fireworks.is-playing .firework i {
	animation: celebration-firework-spark 1.05s ease-out calc(var(--fire-delay) + var(--spark-delay, 0s)) both;
}
@keyframes celebration-firework-spark {
	0% { opacity: 0; transform: rotate(var(--angle)) translateY(0) scaleY(.1); }
	12% { opacity: 1; }
	70% { opacity: 1; }
	100% { opacity: 0; transform: rotate(var(--angle)) translateY(calc(-42px * var(--celebration-echelle, 1))) scaleY(1); }
}

/* ---- Quatre lumières (calque partagé - liaisons + halo commun) ---- */
.energy-line {
	position: absolute; left: 0;
	width: calc(4px * var(--celebration-echelle, 1)); height: calc(32px * var(--celebration-echelle, 1));
	transform: translate(-50%, -50%);
	border-radius: 99px;
	background: linear-gradient(to bottom, rgba(255, 255, 255, 0), #fff7b0, rgba(255, 255, 255, 0));
	opacity: 0;
	filter: drop-shadow(0 0 calc(5px * var(--celebration-echelle, 1)) #fff2a0);
}
.energy-line-1 { top: calc(-26px * var(--celebration-echelle, 1)); }
.energy-line-2 { top: 0; }
.energy-line-3 { top: calc(26px * var(--celebration-echelle, 1)); }
.glow-orbit {
	position: absolute; left: 0; top: 0;
	width: calc(64px * var(--celebration-echelle, 1)); height: calc(64px * var(--celebration-echelle, 1));
	border: calc(3px * var(--celebration-echelle, 1)) solid rgba(255, 246, 159, .9);
	border-radius: 50%;
	opacity: 0;
	transform: translate(-50%, -50%) scale(.2);
	box-shadow: 0 0 calc(20px * var(--celebration-echelle, 1)) rgba(255, 240, 128, .9), inset 0 0 calc(18px * var(--celebration-echelle, 1)) rgba(255, 240, 128, .5);
}
.celebration-effect-glow.is-playing .energy-line { animation: celebration-energy-link .5s ease-out .3s both; }
.celebration-effect-glow.is-playing .glow-orbit { animation: celebration-glow-orbit 1.35s ease-out .6s both; }
@keyframes celebration-energy-link {
	0% { opacity: 0; transform: translate(-50%, -50%) scaleY(.1); }
	45% { opacity: 1; }
	100% { opacity: 0; transform: translate(-50%, -50%) scaleY(1.3); }
}
@keyframes celebration-glow-orbit {
	0% { opacity: 0; transform: translate(-50%, -50%) scale(.2); }
	32% { opacity: 1; }
	100% { opacity: 0; transform: translate(-50%, -50%) scale(1.6); }
}
/* Habillage des VRAIS pions (public/js/app/Pion.js#animeCapture applique le
   meme invariant a la devoration) : jamais le `transform` racine du pion
   (deja pilote par _deplaceToEmplacement), uniquement `filter` sur le pion et
   un pseudo-element decoratif dont le `transform` est independant de celui du
   parent - le pion ne perd donc jamais sa position/son deplacement en cours. */
.pion.celebration-pion-lumiere {
	animation: celebration-pawn-glow 2.2s ease-in-out;
	animation-delay: var(--celebration-delai-pion, 0s);
}
.pion.celebration-pion-lumiere::after {
	content: "";
	position: absolute; left: 50%; top: 50%;
	width: 170%; height: 170%;
	border-radius: 50%;
	background: radial-gradient(circle, rgba(255, 240, 160, .9), transparent 70%);
	opacity: 0;
	pointer-events: none;
	animation: celebration-pawn-halo 2.2s ease-in-out;
	animation-delay: var(--celebration-delai-pion, 0s);
}
@keyframes celebration-pawn-glow {
	0%, 100% { filter: drop-shadow(0 0 0 transparent); }
	35%, 62% { filter: drop-shadow(0 0 calc(4px * var(--celebration-echelle, 1)) #fff) drop-shadow(0 0 calc(10px * var(--celebration-echelle, 1)) #fff09b); }
}
@keyframes celebration-pawn-halo {
	0%, 100% { opacity: 0; transform: translate(-50%, -50%) scale(.4); }
	40%, 62% { opacity: .85; transform: translate(-50%, -50%) scale(1.15); }
}

/* ---- Couronnement (calque partagé - ondes + couronne + rayons) ---- */
.victory-wave {
	position: absolute; left: 0; top: 0;
	width: calc(56px * var(--celebration-echelle, 1)); height: calc(56px * var(--celebration-echelle, 1));
	border: calc(3px * var(--celebration-echelle, 1)) solid #ffd95a;
	border-radius: 50%;
	opacity: 0;
	transform: translate(-50%, -50%) scale(.25);
	box-shadow: 0 0 calc(12px * var(--celebration-echelle, 1)) #fff3a2;
}
.wave-2 { animation-delay: .28s !important; }
.wave-3 { animation-delay: .56s !important; }
.crown {
	position: absolute; left: 0; top: 0;
	color: #ffdb55;
	font-style: normal;
	font-size: calc(34px * var(--celebration-echelle, 1));
	line-height: 1;
	opacity: 0;
	filter: drop-shadow(0 calc(3px * var(--celebration-echelle, 1)) calc(1px * var(--celebration-echelle, 1)) #8d5b16) drop-shadow(0 0 calc(7px * var(--celebration-echelle, 1)) #fff1a1);
	transform: translate(-50%, -70%) scale(.2) rotate(-12deg);
}
.ray {
	position: absolute; left: 0; top: 0;
	width: calc(2px * var(--celebration-echelle, 1)); height: calc(34px * var(--celebration-echelle, 1));
	opacity: 0;
	background: linear-gradient(to top, rgba(255, 218, 82, .85), transparent);
	transform-origin: 50% 0%;
}
.ray-1 { transform: translateX(-50%) rotate(0deg); }
.ray-2 { transform: translateX(-50%) rotate(60deg); }
.ray-3 { transform: translateX(-50%) rotate(120deg); }
.ray-4 { transform: translateX(-50%) rotate(180deg); }
.ray-5 { transform: translateX(-50%) rotate(240deg); }
.ray-6 { transform: translateX(-50%) rotate(300deg); }
.celebration-effect-wave.is-playing .victory-wave { animation: celebration-wave-expand 1.4s ease-out both; }
.celebration-effect-wave.is-playing .crown { animation: celebration-crown-rise 2.15s cubic-bezier(.16, .8, .28, 1) .32s both; }
.celebration-effect-wave.is-playing .ray { animation: celebration-ray-shine 1.35s ease-out .25s both; }
@keyframes celebration-wave-expand {
	0% { opacity: .9; transform: translate(-50%, -50%) scale(.25); }
	100% { opacity: 0; transform: translate(-50%, -50%) scale(3); }
}
@keyframes celebration-crown-rise {
	0% { opacity: 0; transform: translate(-50%, 10%) scale(.2) rotate(-12deg); }
	22%, 72% { opacity: 1; transform: translate(-50%, -70%) scale(1) rotate(0); }
	100% { opacity: 0; transform: translate(-50%, -95%) scale(.9); }
}
@keyframes celebration-ray-shine {
	0%, 100% { opacity: 0; }
	35% { opacity: .8; }
}
/* Habillage des VRAIS pions - meme invariant que quatre_lumieres ci-dessus,
   uniquement `filter`, jamais `transform`. */
.pion.celebration-pion-couronnement {
	animation: celebration-pawn-glow-or 1.8s ease-in-out;
	animation-delay: var(--celebration-delai-pion, 0s);
}
@keyframes celebration-pawn-glow-or {
	0%, 100% { filter: drop-shadow(0 0 0 transparent); }
	40%, 70% { filter: drop-shadow(0 0 calc(3px * var(--celebration-echelle, 1)) #fff) drop-shadow(0 0 calc(9px * var(--celebration-echelle, 1)) #ffdb55); }
}

/* ---- Vague de couleur (calque partagé - anneaux + traînées radiales,
   teintés à la couleur réelle du joueur via --rgb posé en JS,
   Celebrations.js#construitVagueCouleur) ---- */
.color-wave-wash {
	--rgb: 224, 6, 5;
	position: absolute; left: 0; top: 0;
	width: calc(34px * var(--celebration-echelle, 1)); height: calc(34px * var(--celebration-echelle, 1));
	border: calc(3px * var(--celebration-echelle, 1)) solid rgba(var(--rgb), .85);
	border-radius: 50%;
	background: radial-gradient(circle, rgba(255, 255, 255, .4), rgba(var(--rgb), .32) 30%, rgba(var(--rgb), 0) 68%);
	box-shadow: 0 0 calc(16px * var(--celebration-echelle, 1)) rgba(var(--rgb), .6);
	opacity: 0;
	transform: translate(-50%, -50%) scale(.2);
}
.color-wave-streak {
	--rgb: 224, 6, 5;
	position: absolute; left: 0; top: 0;
	width: calc(3px * var(--celebration-echelle, 1)); height: calc(34px * var(--celebration-echelle, 1));
	border-radius: 99px;
	background: linear-gradient(to top, rgba(var(--rgb), 0), rgba(255, 255, 255, .9));
	opacity: 0;
}
.celebration-effect-vague-couleur.is-playing .color-wave-wash {
	animation: celebration-color-wave-expand 1.5s cubic-bezier(.18, .65, .24, 1) var(--delay, 0s) both;
}
.celebration-effect-vague-couleur.is-playing .color-wave-streak {
	animation: celebration-color-wave-streak 1s ease-out var(--delay, 0s) both;
}
@keyframes celebration-color-wave-expand {
	0% { opacity: 0; transform: translate(-50%, -50%) scale(.2); }
	16% { opacity: .9; }
	100% { opacity: 0; transform: translate(-50%, -50%) scale(5.5); }
}
@keyframes celebration-color-wave-streak {
	0% { opacity: 0; transform: translateX(-50%) rotate(var(--angle)) translateY(0) scaleY(.15); }
	22% { opacity: .9; }
	100% { opacity: 0; transform: translateX(-50%) rotate(var(--angle)) translateY(calc(64px * var(--celebration-echelle, 1))) scaleY(1.25); }
}
/* Habillage des VRAIS pions - meme invariant que quatre_lumieres/couronnement,
   uniquement `filter`, jamais `transform`. --celebration-rgb : posee par
   Celebrations.js#appliqueClassePions (couleur reelle du pion celebre). */
.pion.celebration-pion-vague-couleur {
	animation: celebration-pawn-vague 1.3s ease-out;
	animation-delay: var(--celebration-delai-pion, 0s);
}
@keyframes celebration-pawn-vague {
	0%, 100% { filter: drop-shadow(0 0 0 transparent); }
	32% { filter: drop-shadow(0 0 calc(4px * var(--celebration-echelle, 1)) #fff) drop-shadow(0 0 calc(10px * var(--celebration-echelle, 1)) rgba(var(--celebration-rgb, 224, 6, 5), .95)); }
}

/* ---- La ola (calque partagé - anneau du salut collectif final,
   Celebrations.js#construitOlaDesPions ; le bond de chaque pion, lui, est
   porté par .pion.celebration-pion-ola ci-dessous, jamais par ce calque -
   voir le commentaire du constructeur JS) ---- */
.ola-salut-collectif {
	--rgb: 224, 6, 5;
	position: absolute; left: 0; top: 0;
	width: calc(40px * var(--celebration-echelle, 1)); height: calc(40px * var(--celebration-echelle, 1));
	border: calc(3px * var(--celebration-echelle, 1)) solid rgba(var(--rgb), .85);
	border-radius: 50%;
	opacity: 0;
	transform: translate(-50%, -50%) scale(.25);
	box-shadow: 0 0 calc(14px * var(--celebration-echelle, 1)) rgba(var(--rgb), .7);
}
.celebration-effect-ola.is-playing .ola-salut-collectif {
	/* Apres le bond sequentiel des 4 pions (4 * 0.18s de delai + marge). */
	animation: celebration-ola-salut 1.1s ease-out .87s both;
}
@keyframes celebration-ola-salut {
	0% { opacity: .85; transform: translate(-50%, -50%) scale(.25); }
	100% { opacity: 0; transform: translate(-50%, -50%) scale(2.6); }
}
/* Bond individuel des VRAIS pions, en sequence (--celebration-delai-pion) -
   uniquement `filter`/pseudo-element, jamais `transform` sur le pion racine :
   le "bond" est mime par un flash d'energie + un anneau qui se detend depuis
   le pion, jamais un deplacement reel (qui entrerait en conflit avec
   _deplaceToEmplacement). */
.pion.celebration-pion-ola {
	animation: celebration-pawn-ola-flash .78s cubic-bezier(.2, .78, .35, 1);
	animation-delay: var(--celebration-delai-pion, 0s);
}
.pion.celebration-pion-ola::after {
	content: "";
	position: absolute; left: 50%; top: 50%;
	width: 190%; height: 190%;
	border-radius: 50%;
	border: calc(2px * var(--celebration-echelle, 1)) solid rgba(var(--celebration-rgb, 224, 6, 5), .8);
	opacity: 0;
	pointer-events: none;
	animation: celebration-pawn-ola-ripple .72s ease-out;
	animation-delay: var(--celebration-delai-pion, 0s);
}
@keyframes celebration-pawn-ola-flash {
	0%, 100% { filter: drop-shadow(0 0 0 transparent); }
	42% { filter: drop-shadow(0 0 calc(5px * var(--celebration-echelle, 1)) #fff) drop-shadow(0 0 calc(11px * var(--celebration-echelle, 1)) rgba(var(--celebration-rgb, 224, 6, 5), .95)); }
}
@keyframes celebration-pawn-ola-ripple {
	0% { opacity: .8; transform: translate(-50%, -50%) scale(.35); }
	100% { opacity: 0; transform: translate(-50%, -50%) scale(1.5); }
}

/* ---- TOC ! (calque partagé - impact, mot et éclats de bois,
   Celebrations.js#construitTocExplosion). Le mot ne tourne jamais avec le
   plateau : seul son point d'ancrage (le calque, positionné via left/top
   inline sur `origine`) suit le joueur célébré. ---- */
.toc-impact-ring {
	position: absolute; left: 0; top: 0;
	width: calc(44px * var(--celebration-echelle, 1)); height: calc(44px * var(--celebration-echelle, 1));
	border: calc(5px * var(--celebration-echelle, 1)) solid rgba(255, 246, 205, .9);
	border-radius: 50%;
	opacity: 0;
	transform: translate(-50%, -50%) scale(.15);
	box-shadow: 0 0 calc(26px * var(--celebration-echelle, 1)) rgba(255, 245, 196, .85);
}
.celebration-effect-toc.is-playing .toc-impact-ring { animation: celebration-toc-ring 1s ease-out .1s both; }
@keyframes celebration-toc-ring {
	0% { opacity: .95; transform: translate(-50%, -50%) scale(.15); }
	100% { opacity: 0; transform: translate(-50%, -50%) scale(3.4); }
}
.toc-mot {
	--rgb: 224, 6, 5;
	position: absolute; left: 0; top: 0;
	color: #fff8d9;
	font: 700 calc(2.6rem * var(--celebration-echelle, 1))/.85 "Amaranth", sans-serif;
	text-shadow: 0 calc(3px * var(--celebration-echelle, 1)) 0 rgba(var(--rgb), .95), 0 calc(6px * var(--celebration-echelle, 1)) calc(12px * var(--celebration-echelle, 1)) rgba(42, 22, 5, .55);
	opacity: 0;
	white-space: nowrap;
	transform: translate(-50%, -110%) rotate(-7deg) scale(.15);
}
.celebration-effect-toc.is-playing .toc-mot { animation: celebration-toc-mot 1.6s cubic-bezier(.16, .82, .24, 1) .12s both; }
@keyframes celebration-toc-mot {
	0% { opacity: 0; transform: translate(-50%, -70%) rotate(-12deg) scale(.15); }
	18%, 70% { opacity: 1; transform: translate(-50%, -110%) rotate(-4deg) scale(1); }
	100% { opacity: 0; transform: translate(-50%, -130%) rotate(0) scale(.92); }
}
.toc-chip {
	position: absolute; left: 0; top: 0;
	width: calc(var(--size) * var(--celebration-echelle, 1)); height: calc(var(--size) * .34 * var(--celebration-echelle, 1));
	border-radius: 99px;
	background: #f4d395;
	box-shadow: 0 0 calc(5px * var(--celebration-echelle, 1)) rgba(255, 239, 190, .75);
	opacity: 0;
}
.celebration-effect-toc.is-playing .toc-chip { animation: celebration-toc-chip 1.05s ease-out var(--delay, 0s) both; }
@keyframes celebration-toc-chip {
	0% { opacity: 0; transform: translate(-50%, -50%) rotate(var(--angle)) translateY(0) scale(.4); }
	18% { opacity: 1; }
	100% { opacity: 0; transform: translate(-50%, -50%) rotate(var(--angle)) translateY(calc(var(--distance) * var(--celebration-echelle, 1))) rotate(180deg); }
}
/* Flash synchronisé (pas de séquence : un impact frappe les 4 pions à la
   fois), uniquement `filter`. */
.pion.celebration-pion-toc {
	animation: celebration-pawn-toc-flash .6s ease-out .08s;
}
@keyframes celebration-pawn-toc-flash {
	0%, 100% { filter: drop-shadow(0 0 0 transparent); }
	38% { filter: drop-shadow(0 0 calc(4px * var(--celebration-echelle, 1)) #fff8d9) drop-shadow(0 0 calc(9px * var(--celebration-echelle, 1)) rgba(var(--celebration-rgb, 224, 6, 5), .85)); }
}

/* ---- Photo de famille (calque partagé - cadre, flash et étoiles,
   Celebrations.js#construitPhotoDeFamille). Les étoiles sont décalées en px
   FIXES autour du cadre (jamais des points cardinaux du plateau) : elles
   restent groupées autour de lui quel que soit l'endroit où `origine` tombe
   à l'écran. --cadre-largeur/--cadre-hauteur : posées en JS (retour de
   Corentin, 2026-09-27 - assez grandes pour contenir les 4 VRAIS pions
   rentrés). Le calque entier est tourné selon la direction réelle de l'allée,
   afin que le bord `4 / 4`, le flash et les étoiles restent solidaires ; les
   valeurs par défaut ci-dessous servent à la mini-scène boutique. ---- */
.photo-cadre {
	--rgb: 224, 6, 5;
	--cadre-largeur: 40px;
	--cadre-hauteur: 86px;
	position: absolute; left: 0; top: 0;
	width: var(--cadre-largeur);
	height: var(--cadre-hauteur);
	margin: calc(var(--cadre-hauteur) / -2) 0 0 calc(var(--cadre-largeur) / -2);
	border: var(--cadre-bordure, 5px) solid #fffdf5;
	border-bottom-width: var(--cadre-bordure-bas, 15px);
	background: rgba(255, 255, 255, .04);
	box-shadow: 0 calc(5px * var(--celebration-echelle, 1)) calc(15px * var(--celebration-echelle, 1)) rgba(43, 25, 8, .4), 0 0 0 calc(2px * var(--celebration-echelle, 1)) rgba(var(--rgb), .5);
	opacity: 0;
	transform: rotate(-3deg) scale(.45);
}
.photo-cadre::after {
	content: "4 / 4";
	position: absolute;
	left: 50%; bottom: calc(var(--cadre-bordure-bas, 15px) * -0.86);
	color: #405047;
	font: 700 var(--cadre-libelle, .5rem)/1 "Comfortaa", sans-serif;
	transform: translateX(-50%);
}
.celebration-effect-photo.is-playing .photo-cadre { animation: celebration-photo-cadre 2.35s cubic-bezier(.18, .78, .28, 1) .12s both; }
@keyframes celebration-photo-cadre {
	0% { opacity: 0; transform: rotate(-8deg) scale(.45); }
	18%, 80% { opacity: 1; transform: rotate(-3deg) scale(1); }
	100% { opacity: 0; transform: rotate(0) scale(.96) translateY(calc(-4px * var(--celebration-echelle, 1))); }
}
.photo-flash {
	--photo-flash-size: 240px;
	position: absolute; left: 0; top: 0;
	width: var(--photo-flash-size); height: var(--photo-flash-size);
	margin: calc(var(--photo-flash-size) / -2) 0 0 calc(var(--photo-flash-size) / -2);
	border-radius: 50%;
	background: radial-gradient(circle, rgba(255, 255, 255, .9), rgba(255, 255, 255, 0) 62%);
	opacity: 0;
}
.celebration-effect-photo.is-playing .photo-flash { animation: celebration-photo-flash 1.1s ease .8s both; }
@keyframes celebration-photo-flash { 0%, 62%, 100% { opacity: 0; } 68% { opacity: .85; } 75% { opacity: 0; } }
.photo-etoile {
	position: absolute; left: 0; top: 0;
	color: #fff8c7;
	font-size: calc(10px * var(--celebration-echelle, 1));
	opacity: 0;
	filter: drop-shadow(0 0 calc(4px * var(--celebration-echelle, 1)) rgba(var(--rgb, 224, 6, 5), .85));
	transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) scale(.2) rotate(0);
}
.celebration-effect-photo.is-playing .photo-etoile { animation: celebration-photo-etoile 1s ease-out var(--delay, 0s) both; }
@keyframes celebration-photo-etoile {
	0%, 25% { opacity: 0; transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) scale(.2) rotate(0); }
	45% { opacity: 1; transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) scale(1.1) rotate(35deg); }
	100% { opacity: 0; transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) scale(.7) rotate(90deg); }
}
/* Pose des VRAIS pions (retour de Corentin, 2026-09-27 : reproduit
   fidèlement la maquette - chaque pion se décale légèrement d'un côté puis
   de l'autre, comme pour montrer sa tête sur la photo). Le VRAI pion porte
   lui-même son image (background-image sur .pion_joueur_N, contrairement à
   la maquette qui anime un enfant .pawn-visual dédié) : impossible d'animer
   un enfant sans bouger le sprite. Les propriétés CSS individuelles
   La propriété `translate` se compose avec le transform inline posé par
   _deplaceToEmplacement sans jamais le lire ni l'écraser.
   --celebration-peek-x/-y (Celebrations.js#appliquePosePhoto) :
   décalage en % de la boîte du pion (donc proportionnel à sa taille réelle,
   quel que soit l'écran) sur l'axe PERPENDICULAIRE à l'allée d'arrivée
   réelle du joueur (translateX si l'allée est une colonne verticale,
   translateY si c'est une rangée horizontale - voir estAllureHorizontale) :
   un seul des deux vaut ±22%, l'autre reste à 0%. */
.pion.celebration-pion-photo {
	animation: celebration-pawn-photo-pose 2s ease-in-out var(--celebration-delai-pion, 0s);
}
@keyframes celebration-pawn-photo-pose {
	0%, 100% { translate: 0 0; }
	20%, 78% {
		translate: var(--celebration-peek-x, 0%) var(--celebration-peek-y, 0%);
		filter: drop-shadow(0 0 calc(6px * var(--celebration-echelle, 1)) rgba(255, 255, 255, .75));
	}
}

/* ---- Mode "Réduire les animations"/prefers-reduced-motion : flash bref des
   quatre pions + petit bandeau, jamais de particules ni de mouvement
   prolongé (docs/UPDATE_CELEBRATION.md). ---- */
.celebration-flash-reduit {
	animation: celebration-flash-reduit .9s ease-out;
}
@keyframes celebration-flash-reduit {
	0%, 100% { filter: drop-shadow(0 0 0 transparent); }
	30% { filter: drop-shadow(0 0 calc(3px * var(--celebration-echelle, 1)) #fff) drop-shadow(0 0 calc(9px * var(--celebration-echelle, 1)) #ffe27a) brightness(1.35); }
}
.celebration-bandeau-reduit {
	position: absolute;
	z-index: 61;
	left: 50%; top: 6%;
	transform: translateX(-50%);
	display: flex; align-items: center; gap: 8px;
	padding: 7px 14px 7px 8px;
	border: 1px solid rgba(255, 255, 255, .6);
	border-radius: 999px;
	color: #243329;
	background: rgba(255, 255, 255, .95);
	box-shadow: 0 8px 20px rgba(12, 38, 22, .22);
	font: 700 .74rem/1.1 "Comfortaa", "Amaranth", sans-serif;
	white-space: nowrap;
	pointer-events: none;
	animation: celebration-bandeau-enter 2.6s ease both;
}
.celebration-bandeau-reduit i { color: #457655; }
@keyframes celebration-bandeau-enter {
	0% { opacity: 0; transform: translateX(-50%) translateY(-8px); }
	12%, 82% { opacity: 1; transform: translateX(-50%) translateY(0); }
	100% { opacity: 0; transform: translateX(-50%) translateY(-4px); }
}

/* ---- Mini-scène partagée (Celebrations.js#creeApercu/creeSceneComplete) :
   carte du catalogue et modale d'achat de la boutique (Boutique.js). ---- */
.celebration-scene {
	position: relative;
	width: 100%; height: 100%;
	overflow: hidden;
}
.celebration-scene-grand { height: 190px; }
.celebration-scene-plateau {
	position: relative;
	width: 100%; height: 100%;
	display: flex; align-items: center; justify-content: center;
}
.celebration-scene-pions { position: relative; width: 46px; height: 46px; }
.celebration-scene-grand .celebration-scene-pions { width: 66px; height: 66px; }
.celebration-scene-pion {
	position: absolute; left: 50%;
	width: 22px; height: 22px;
	object-fit: contain;
	filter: drop-shadow(1px 2px 1px rgba(0, 0, 0, .35));
	transform: translateX(-50%);
}
.celebration-scene-grand .celebration-scene-pion { width: 30px; height: 30px; }
.celebration-scene-pion:nth-child(1) { top: 0; }
.celebration-scene-pion:nth-child(2) { top: 12px; }
.celebration-scene-pion:nth-child(3) { top: 24px; }
.celebration-scene-pion:nth-child(4) { top: 36px; }
.celebration-scene-grand .celebration-scene-pion:nth-child(1) { top: 0; }
.celebration-scene-grand .celebration-scene-pion:nth-child(2) { top: 16px; }
.celebration-scene-grand .celebration-scene-pion:nth-child(3) { top: 32px; }
.celebration-scene-grand .celebration-scene-pion:nth-child(4) { top: 48px; }
.celebration-scene .celebration-bandeau-reduit { font-size: .6rem; padding: 5px 10px 5px 6px; }

@media (prefers-reduced-motion: reduce) {
	/* Filet de sécurité si la branche JS (Celebrations.js#reduireAnimations)
	   n'a pas déjà remplacé l'effet par le mode réduit (ex. cache agressif
	   d'un ancien build) - n'affecte que les éléments de ce moteur. */
	.celebration-layer, .celebration-layer *,
	.pion.celebration-pion-lumiere, .pion.celebration-pion-lumiere::after,
	.pion.celebration-pion-couronnement,
	.pion.celebration-pion-vague-couleur,
	.pion.celebration-pion-ola, .pion.celebration-pion-ola::after,
	.pion.celebration-pion-toc,
	.pion.celebration-pion-photo {
		animation-duration: .01ms !important;
		animation-delay: 0ms !important;
	}
}
