@keyframes twinkle { 0%, 100% { opacity: .2; transform: scale(.7); } 50% { opacity: 1; transform: scale(1.15); } }
@keyframes spark-spin { from { transform: rotate(0) scale(1); } 50% { transform: rotate(180deg) scale(1.15); } to { transform: rotate(360deg) scale(1); } }
@keyframes spin-slow { to { transform: rotate(360deg); } }
@keyframes float-soft { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
@keyframes gem-hop { 0%, 100% { transform: translateY(0) scale(1); } 40% { transform: translateY(-12px) scale(1.12); } }
@keyframes loader-fill { from { transform: scaleX(.02); } to { transform: scaleX(1); } }
@keyframes pulse-opacity { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
@keyframes halo { 0% { opacity: .9; transform: scale(.94); } 100% { opacity: 0; transform: scale(1.14); } }
@keyframes tag-bob { 0%, 100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, -4px); } }
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-6px); }
  50% { transform: translateX(5px); }
  75% { transform: translateX(-3px); }
}
@keyframes toast-in {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(.5); }
  100% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes toast-out {
  0% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -80%) scale(.9); }
}
@keyframes banner-pop { 0% { transform: scale(.85); } 100% { transform: scale(1); } }
@keyframes card-glow { from { opacity: .55; } to { opacity: 1; } }
@keyframes think-dot { 0%, 100% { transform: translateY(0); opacity: .45; } 50% { transform: translateY(-3px); opacity: 1; } }
@keyframes roll-invite { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
@keyframes roll-img-invite { 0%, 100% { transform: translateY(-50%) scale(1); } 50% { transform: translateY(-50%) scale(1.06); } }
@keyframes rotate-phone { 0%, 100% { transform: rotate(0); } 50% { transform: rotate(-90deg); } }

@keyframes hop-a { 0% { transform: translateY(0) scale(1); } 45% { transform: translateY(-26%) scale(1.08, 1.12); } 100% { transform: translateY(0) scale(1); } }
@keyframes hop-b { 0% { transform: translateY(0) scale(1); } 45% { transform: translateY(-26%) scale(1.08, 1.12); } 100% { transform: translateY(0) scale(1); } }
@keyframes ring-pulse { 0%, 100% { opacity: .55; transform: scale(.92); } 50% { opacity: 1; transform: scale(1.14); } }
@keyframes token-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8%); } }
@keyframes token-captured {
  0% { transform: scale(1) rotate(0); opacity: 1; }
  30% { transform: scale(1.4) rotate(40deg); opacity: 1; }
  100% { transform: scale(0) rotate(360deg); opacity: 0; }
}
@keyframes token-respawn { 0% { transform: scale(0); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }

@keyframes dice-tumble {
  0% { transform: rotate(0) scale(1); }
  25% { transform: translateY(-7px) rotate(90deg) scale(.9); }
  50% { transform: rotate(180deg) scale(1.06); }
  75% { transform: translateY(-4px) rotate(270deg) scale(.92); }
  100% { transform: rotate(360deg) scale(1); }
}
@keyframes dice-land { 0% { transform: scale(1.3); } 60% { transform: scale(.92); } 100% { transform: scale(1); } }
@keyframes pips-shuffle {
  0% { transform: rotate(0) scale(1); filter: blur(0); }
  25% { transform: rotate(90deg) scale(.78) translateY(-6%); filter: blur(.6px); }
  50% { transform: rotate(180deg) scale(1.05); filter: blur(0); }
  75% { transform: rotate(270deg) scale(.8) translateY(4%); filter: blur(.6px); }
  100% { transform: rotate(360deg) scale(1); filter: blur(0); }
}
@keyframes pips-tumble {
  0%   { transform: rotateX(0) rotateY(0) rotateZ(0) scale(1); filter: blur(0); }
  25%  { transform: rotateX(100deg) rotateY(20deg) rotateZ(25deg) scale(.78); filter: blur(.7px); }
  50%  { transform: rotateX(180deg) rotateY(-30deg) rotateZ(0) scale(1.06); filter: blur(0); }
  75%  { transform: rotateX(280deg) rotateY(20deg) rotateZ(-25deg) scale(.8); filter: blur(.7px); }
  100% { transform: rotateX(360deg) rotateY(0) rotateZ(0) scale(1); filter: blur(0); }
}
@keyframes slot-flicker { from { opacity: .55; } to { opacity: 1; } }
@keyframes pips-land { 0% { transform: scale(1.6) rotate(-18deg); } 45% { transform: scale(.86) rotate(6deg); } 70% { transform: scale(1.08) rotate(-2deg); } 100% { transform: scale(1) rotate(0); } }
@keyframes pips-breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.08); } }
@keyframes slot-glow { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
@keyframes dice-invite { 0%, 100% { transform: translateY(0) rotate(0); } 50% { transform: translateY(-4px) rotate(-6deg); } }

@keyframes trophy-pop { 0% { transform: scale(.2) rotate(-20deg); opacity: 0; } 100% { transform: scale(1) rotate(0); opacity: 1; } }
@keyframes lock-wiggle { 0%, 100% { transform: rotate(0); } 20% { transform: rotate(-10deg); } 40% { transform: rotate(8deg); } 60% { transform: rotate(0); } }
@keyframes star-pop { 0% { transform: scale(0) rotate(-40deg); opacity: 0; } 100% { transform: scale(1) rotate(0); opacity: 1; } }

.fx-particle {
  position: absolute;
  left: var(--px);
  top: var(--py);
  width: var(--size, 7px);
  height: var(--size, 7px);
  margin: calc(var(--size, 7px) / -2) 0 0 calc(var(--size, 7px) / -2);
  border-radius: 50%;
  background: var(--pc, #fff);
  box-shadow: 0 0 6px var(--pc, #fff);
  animation: particle-burst var(--pd, 700ms) var(--ease-out) forwards;
  pointer-events: none;
}
.fx-particle--star {
  border-radius: 0;
  box-shadow: none;
  clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%);
}
.fx-ring {
  position: absolute;
  left: var(--px);
  top: var(--py);
  width: 16%;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 3px solid var(--pc, #fff);
  box-shadow: 0 0 14px var(--pc, #fff), inset 0 0 10px var(--pc, #fff);
  transform: translate(-50%, -50%) scale(.2);
  animation: ring-burst .6s var(--ease-out) forwards;
  pointer-events: none;
}
@keyframes particle-burst {
  0% { transform: translate(0, 0) scale(1); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(.2); opacity: 0; }
}
@keyframes ring-burst {
  0% { transform: translate(-50%, -50%) scale(.2); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(1.6); opacity: 0; }
}
.confetti {
  position: absolute;
  top: -24px;
  left: var(--cx);
  width: var(--cw, 8px);
  height: var(--ch, 14px);
  border-radius: 2px;
  background: var(--cc);
  animation: confetti-fall var(--cd, 2.6s) cubic-bezier(.25, .4, .6, 1) var(--cdelay, 0s) forwards;
  will-change: transform;
}
.confetti--round { border-radius: 50%; height: var(--cw, 8px); }
@keyframes confetti-fall {
  0% { transform: translate(0, 0) rotate(0); opacity: 1; }
  85% { opacity: 1; }
  100% { transform: translate(var(--cdx), 110vh) rotate(var(--cr)); opacity: .2; }
}

@media (min-width: 600px) {
  :root { --app-max: 440px; }
}
@media (min-width: 900px) and (min-height: 700px) {
  :root { --app-max: 540px; }
}
@media (min-width: 600px) and (min-height: 700px) {
  .app { height: min(100dvh, 960px); overflow: visible; }
}
@media (max-width: 400px) {
  .turn-banner { font-size: .72rem; letter-spacing: .04em; padding: 0 9px; gap: 4px; }
  .seat-row { gap: 4px; }
  .player-card { gap: 4px; padding-right: 6px; }
  .player-card__name { font-size: .76rem; }
  .player-card__pips .pip-dot { width: 5px; height: 5px; }
}
@media (max-width: 350px) {
  .btn--xl { min-height: 66px; font-size: 1.65rem; }
  .player-card__pips { display: none; }
  .menu-tile { font-size: .78rem; min-height: 80px; }
  .turn-banner { font-size: .72rem; padding: 0 9px; }
}
@media (max-height: 680px) {
  .screen--home { gap: 10px; }
  .logo__ludo { font-size: clamp(3.2rem, 17vw, 4.4rem); }
  .btn--xl { min-height: 66px; }
  .menu-tile { min-height: 78px; }
  .screen--game { gap: 4px; }
}
@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  .rotate-hint { display: flex; }
}

.q-low .twinkle { animation: none; }
.q-low .twinkle { opacity: .6; }
.q-low .player-card.is-active::before { animation: none; }
.q-low .result__rays, .q-low .logo__spark { animation: none; }
.q-low .modal { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(28, 12, 80, .62); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  .twinkle, .result__rays { animation: none !important; }
  .token.is-movable .token__ring { opacity: 1; transform: none; }
  .btn-play::after { opacity: .6; }
}
