/* All motion (keyframes, transitions). Owned by the Animation agent. Loaded last.
 *
 * Hooks this file relies on (all already set by the app shell, nothing new needed):
 *   .screen / .overlay  + .is-active            screen + overlay enter / leave
 *   .hud__score / .arcade-combo + .is-bump      score bump, combo pop (class is added for ~450 ms)
 *   .life.is-lost, .hud__ping.is-warn/.is-bad   lives shake, ping pulse
 *   .over-arcade__badge.is-show, .toast.is-show new-high-score shimmer, toast in/out
 *   .countdown[data-n]                          countdown ring/flash restarts whenever data-n changes
 *   .overlay--goal.is-active                    goal banner burst (re-starts each time the overlay is re-activated)
 *   [dir=rtl] on <html>                         horizontal slides mirror
 *
 * Split with the JS (ui/dom.js pop()): the JS scales `.countdown` and `.goal__text` with the Web Animations
 * API (transform). This file therefore NEVER animates transform/scale on those two elements; it adds opacity,
 * filter, pseudo-element rings and the sibling `.goal__sub` instead. Nothing has to be removed from the JS.
 * (Score bump and combo pop are class-driven (is-bump) and are owned here.)
 *
 * Only transform / opacity (plus filter / box-shadow on tiny elements) are animated. 120-600 ms.
 */

:root {
  --anim-dir: 1; /* +1 ltr, -1 rtl: multiplies every horizontal offset */
  --ease-pop: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-slam: cubic-bezier(0.2, 1.4, 0.4, 1);
}
:root[dir='rtl'] {
  --anim-dir: -1;
}

/* ═════════ Screens: leave = fade + small slide, enter = panel rise + staggered children ═════════ */
.screen,
.overlay {
  transition:
    opacity var(--dur-med) var(--ease-in-out),
    visibility 0s linear var(--dur-med);
}
.screen.is-active,
.overlay.is-active {
  transition:
    opacity var(--dur-med) var(--ease-out),
    visibility 0s linear 0s;
}

/* the leaving screen drifts out; the game screen must stay put */
.screen:not(.screen--game) {
  transform: translateX(calc(var(--anim-dir) * -1.2rem));
  transition:
    opacity var(--dur-fast) var(--ease-in-out),
    transform var(--dur-fast) var(--ease-in-out),
    visibility 0s linear var(--dur-fast);
}
.screen:not(.screen--game).is-active {
  transform: none;
  transition:
    opacity var(--dur-med) var(--ease-out) 90ms,
    transform var(--dur-slow) var(--ease-out) 90ms,
    visibility 0s linear 0s;
}

@keyframes anim-panel-in {
  from {
    opacity: 0;
    transform: translate3d(calc(var(--anim-dir) * 1.6rem), 0.6rem, 0) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes anim-rise {
  from {
    opacity: 0;
    transform: translate3d(0, 0.9rem, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.screen:not(.screen--game).is-active > .panel {
  animation: anim-panel-in var(--dur-slow) var(--ease-out) backwards;
}
.screen:not(.screen--game).is-active > .panel > * {
  animation: anim-rise var(--dur-slow) var(--ease-out) backwards;
  animation-delay: calc(60ms + var(--i, 0) * 45ms);
}
.panel > :nth-child(1) { --i: 0; }
.panel > :nth-child(2) { --i: 1; }
.panel > :nth-child(3) { --i: 2; }
.panel > :nth-child(4) { --i: 3; }
.panel > :nth-child(5) { --i: 4; }
.panel > :nth-child(6) { --i: 5; }
.panel > :nth-child(7) { --i: 6; }
.panel > :nth-child(n + 8) { --i: 7; }

/* the main menu cards stagger one level deeper */
.screen.is-active .mode-grid > .mode-card {
  animation: anim-rise var(--dur-slow) var(--ease-out) backwards;
  animation-delay: calc(180ms + var(--j, 0) * 60ms);
}
.mode-grid > :nth-child(1) { --j: 0; }
.mode-grid > :nth-child(2) { --j: 1; }
.mode-grid > :nth-child(3) { --j: 2; }
.mode-grid > :nth-child(n + 4) { --j: 3; }

/* ═════════ Title wordmark: slow neon breathing + a rare flicker ═════════ */
@keyframes anim-neon-breathe {
  0%, 100% { filter: brightness(1) saturate(1); }
  50% { filter: brightness(1.18) saturate(1.1); }
}
@keyframes anim-neon-flicker {
  0%, 92%, 100% { opacity: 1; }
  93% { opacity: 0.55; }
  94% { opacity: 1; }
  95.5% { opacity: 0.7; }
  97% { opacity: 1; }
}
.screen.is-active .wordmark__neon {
  animation: anim-neon-breathe 4.8s ease-in-out infinite;
}
.screen.is-active .wordmark__air {
  animation: anim-neon-breathe 5.6s ease-in-out -1.7s infinite;
}
.screen.is-active .wordmark__hockey {
  animation:
    anim-neon-breathe 4.2s ease-in-out -0.8s infinite,
    anim-neon-flicker 13s linear 2s infinite;
}

/* ═════════ Buttons, cards, swatches, toggles, tabs ═════════ */
.btn {
  transition:
    transform var(--dur-fast) var(--ease-out),
    color var(--dur-fast), background-color var(--dur-fast), border-color var(--dur-fast), box-shadow var(--dur-med);
}
.btn:hover:not(:disabled):not(.is-disabled) {
  transform: translateY(-2px);
}
.btn:active:not(:disabled):not(.is-disabled) {
  transform: translateY(1px) scale(0.965);
  transition-duration: 60ms;
}

.icon-btn {
  transition:
    transform var(--dur-fast) var(--ease-out),
    color var(--dur-fast), border-color var(--dur-fast), box-shadow var(--dur-med), background-color var(--dur-fast);
}
.icon-btn:hover {
  transform: translateY(-2px) rotate(calc(var(--anim-dir) * -4deg));
}
.icon-btn:active {
  transform: scale(0.9);
  transition-duration: 60ms;
}

.mode-card {
  transition:
    transform var(--dur-med) var(--ease-out),
    border-color var(--dur-fast), box-shadow var(--dur-med), background-color var(--dur-fast);
}
.mode-card:hover {
  transform: translateY(-4px);
}
.mode-card:active {
  transform: translateY(0) scale(0.97);
  transition-duration: 70ms;
}
.mode-card .icon--card {
  transition: transform var(--dur-med) var(--ease-pop);
}
.mode-card:hover .icon--card {
  transform: scale(1.12);
}

.seg,
.tab,
.chip {
  transition:
    transform var(--dur-fast) var(--ease-out),
    color var(--dur-fast), background-color var(--dur-fast), border-color var(--dur-fast), box-shadow var(--dur-med);
}
.seg:active,
.tab:active,
.chip:active {
  transform: scale(0.95);
  transition-duration: 60ms;
}
@keyframes anim-select-pop {
  0% { transform: scale(0.94); }
  60% { transform: scale(1.05); }
  100% { transform: scale(1); }
}
.seg.is-selected,
.tab.is-selected {
  animation: anim-select-pop var(--dur-med) var(--ease-out);
}

.swatch {
  transition:
    transform var(--dur-med) var(--ease-pop),
    box-shadow var(--dur-med), border-color var(--dur-fast);
}
.swatch:hover {
  transform: scale(1.14);
}
.swatch:active {
  transform: scale(0.92);
  transition-duration: 60ms;
}
.swatch.is-selected {
  transform: scale(1.1);
}

.switch__thumb {
  transition:
    inset-inline-start var(--dur-med) var(--ease-pop),
    background-color var(--dur-fast), box-shadow var(--dur-med);
}

.lang-row {
  transition:
    transform var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast), border-color var(--dur-fast), box-shadow var(--dur-med);
}
.lang-row:hover {
  transform: translateX(calc(var(--anim-dir) * 3px));
}
.lang-row:active {
  transform: scale(0.99);
}

/* focus-visible ring pulse (keeps the base outline, only the glow breathes) */
@keyframes anim-focus-ring {
  0%, 100% { box-shadow: 0 0 0 4px rgba(0, 229, 255, 0.4); }
  50% { box-shadow: 0 0 0 8px rgba(0, 229, 255, 0.12); }
}
:focus-visible {
  animation: anim-focus-ring 1.4s ease-in-out infinite;
}

/* ═════════ Lists: language + leaderboard rows (first ~15) ═════════ */
@keyframes anim-row-in {
  from {
    opacity: 0;
    transform: translate3d(calc(var(--anim-dir) * 0.8rem), 0, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.lang-list > *,
.board-list > * {
  animation: anim-row-in var(--dur-med) var(--ease-out) backwards;
  animation-delay: calc(var(--r, 0) * 22ms);
}
:is(.lang-list, .board-list) > :nth-child(1) { --r: 0; }
:is(.lang-list, .board-list) > :nth-child(2) { --r: 1; }
:is(.lang-list, .board-list) > :nth-child(3) { --r: 2; }
:is(.lang-list, .board-list) > :nth-child(4) { --r: 3; }
:is(.lang-list, .board-list) > :nth-child(5) { --r: 4; }
:is(.lang-list, .board-list) > :nth-child(6) { --r: 5; }
:is(.lang-list, .board-list) > :nth-child(7) { --r: 6; }
:is(.lang-list, .board-list) > :nth-child(8) { --r: 7; }
:is(.lang-list, .board-list) > :nth-child(9) { --r: 8; }
:is(.lang-list, .board-list) > :nth-child(10) { --r: 9; }
:is(.lang-list, .board-list) > :nth-child(11) { --r: 10; }
:is(.lang-list, .board-list) > :nth-child(12) { --r: 11; }
:is(.lang-list, .board-list) > :nth-child(13) { --r: 12; }
:is(.lang-list, .board-list) > :nth-child(14) { --r: 13; }
:is(.lang-list, .board-list) > :nth-child(15) { --r: 14; }
:is(.lang-list, .board-list) > :nth-child(n + 16) { animation: none; }

@keyframes anim-spin {
  to { transform: rotate(360deg); }
}
.spinner {
  animation: anim-spin 0.8s linear infinite;
}

/* ═════════ HUD ═════════ */
@keyframes anim-score-bump {
  0% { transform: scale(1); filter: brightness(1); }
  25% { transform: scale(1.45); filter: brightness(1.7); }
  60% { transform: scale(0.94); filter: brightness(1.15); }
  100% { transform: scale(1); filter: brightness(1); }
}
.hud__score {
  display: inline-block;
}
.hud__score.is-bump {
  animation: anim-score-bump 450ms var(--ease-out);
}

@keyframes anim-combo-pop {
  0% { transform: scale(0.7) rotate(-6deg); opacity: 0.4; }
  35% { transform: scale(1.35) rotate(3deg); opacity: 1; }
  70% { transform: scale(0.97) rotate(-1deg); }
  100% { transform: scale(1) rotate(0); }
}
.arcade-combo {
  display: inline-block;
}
.arcade-combo.is-bump {
  animation: anim-combo-pop 450ms var(--ease-slam);
}

@keyframes anim-life-lost {
  0% { transform: translateX(0) scale(1.35); }
  15% { transform: translateX(-4px) scale(1.2) rotate(-8deg); }
  30% { transform: translateX(4px) scale(1.1) rotate(8deg); }
  45% { transform: translateX(-3px) rotate(-5deg); }
  60% { transform: translateX(3px) rotate(5deg); }
  80% { transform: translateX(-1px); }
  100% { transform: translateX(0) scale(1); }
}
.life.is-lost {
  animation: anim-life-lost 520ms var(--ease-out);
}

@keyframes anim-attention {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}
.hud__ping.is-warn {
  animation: anim-attention 1.6s ease-in-out infinite;
}
.hud__ping.is-bad {
  animation: anim-attention 0.7s ease-in-out infinite;
}

/* ═════════ Game overlays ═════════ */
/* Countdown: flash + ring restart on every data-n change (the animation NAME alternates a/b, so it re-runs even
   though element and class stay). Text scale itself stays with the JS pop(). */
@keyframes anim-count-a {
  0% { opacity: 0.2; filter: brightness(2.2) blur(3px); }
  35% { opacity: 1; filter: brightness(1.5) blur(0); }
  100% { opacity: 1; filter: brightness(1) blur(0); }
}
@keyframes anim-count-b {
  0% { opacity: 0.2; filter: brightness(2.2) blur(3px); }
  35% { opacity: 1; filter: brightness(1.5) blur(0); }
  100% { opacity: 1; filter: brightness(1) blur(0); }
}
@keyframes anim-ring-a {
  0% { transform: translate(-50%, -50%) scale(0.55); opacity: 0.9; }
  100% { transform: translate(-50%, -50%) scale(1.5); opacity: 0; }
}
@keyframes anim-ring-b {
  0% { transform: translate(-50%, -50%) scale(0.55); opacity: 0.9; }
  100% { transform: translate(-50%, -50%) scale(1.5); opacity: 0; }
}
.countdown {
  position: relative;
}
.countdown::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1.05em;
  height: 1.05em;
  border-radius: 50%;
  border: 0.03em solid var(--c-cyan);
  box-shadow: 0 0 0.25em var(--c-cyan), inset 0 0 0.25em var(--c-cyan);
  opacity: 0;
  pointer-events: none;
}
.overlay--countdown.is-active .countdown {
  animation: anim-count-a 480ms var(--ease-out) both;
}
.overlay--countdown.is-active .countdown::after {
  animation: anim-ring-a 600ms var(--ease-out) both;
}
.overlay--countdown.is-active .countdown[data-n='2'],
.overlay--countdown.is-active .countdown[data-n='0'] {
  animation-name: anim-count-b;
}
.overlay--countdown.is-active .countdown[data-n='2']::after,
.overlay--countdown.is-active .countdown[data-n='0']::after {
  animation-name: anim-ring-b;
}
.overlay--countdown.is-active .countdown[data-n='0']::after {
  border-color: var(--c-lime);
  box-shadow: 0 0 0.25em var(--c-lime), inset 0 0 0.25em var(--c-lime);
}

/* GOAL banner: overlay flashes, a burst ring plays behind the JS-scaled text, the sub line slams in after it. */
.overlay--goal .goal {
  position: relative;
}
@keyframes anim-goal-flash {
  0% { opacity: 0; }
  12% { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes anim-goal-text {
  0% { opacity: 0; filter: brightness(3) blur(6px); }
  30% { opacity: 1; filter: brightness(1.9) blur(0); }
  100% { opacity: 1; filter: brightness(1) blur(0); }
}
@keyframes anim-goal-burst {
  0% { transform: translate(-50%, -50%) scale(0.2); opacity: 0.95; }
  100% { transform: translate(-50%, -50%) scale(2.2); opacity: 0; }
}
@keyframes anim-goal-sub {
  0% { opacity: 0; transform: translate3d(0, 1.2rem, 0) scale(0.8); }
  100% { opacity: 1; transform: none; }
}
.overlay--goal::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(70% 60% at 50% 50%, color-mix(in srgb, var(--c-white-hot) 22%, transparent), transparent 75%);
  opacity: 0;
  pointer-events: none;
}
.overlay--goal[data-side='left']::before {
  background: radial-gradient(70% 60% at 50% 50%, color-mix(in srgb, var(--c-cyan) 30%, transparent), transparent 75%);
}
.overlay--goal[data-side='right']::before {
  background: radial-gradient(70% 60% at 50% 50%, color-mix(in srgb, var(--c-magenta) 30%, transparent), transparent 75%);
}
.overlay--goal .goal::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 40%;
  width: min(30rem, 60vmin);
  height: min(30rem, 60vmin);
  border-radius: 50%;
  border: 0.3rem solid var(--side);
  box-shadow: 0 0 2rem var(--side), inset 0 0 2rem var(--side);
  opacity: 0;
  pointer-events: none;
}
.overlay--goal.is-active::before {
  animation: anim-goal-flash 700ms ease-out both;
}
.overlay--goal.is-active .goal::before {
  animation: anim-goal-burst 650ms var(--ease-out) both;
}
.overlay--goal.is-active .goal__text {
  animation: anim-goal-text 520ms var(--ease-out) both;
}
.overlay--goal.is-active .goal__sub {
  animation: anim-goal-sub 420ms var(--ease-slam) 220ms both;
}

/* Pause panel drops in, result panel reveals with staggered rows */
@keyframes anim-drop-in {
  0% { opacity: 0; transform: translate3d(0, -2.2rem, 0) scale(0.96); }
  60% { opacity: 1; transform: translate3d(0, 0.35rem, 0) scale(1.005); }
  100% { opacity: 1; transform: none; }
}
.overlay--pause.is-active .panel {
  animation: anim-drop-in 420ms var(--ease-out) backwards;
}
.overlay--pause.is-active .panel > * {
  animation: anim-rise var(--dur-med) var(--ease-out) backwards;
  animation-delay: calc(120ms + var(--i, 0) * 45ms);
}

@keyframes anim-result-in {
  0% { opacity: 0; transform: translate3d(0, 1.6rem, 0) scale(0.9); }
  100% { opacity: 1; transform: none; }
}
@keyframes anim-title-slam {
  0% { opacity: 0; transform: scale(1.5); filter: blur(4px); }
  60% { opacity: 1; transform: scale(0.97); filter: blur(0); }
  100% { opacity: 1; transform: scale(1); }
}
.overlay--over.is-active .panel {
  animation: anim-result-in 480ms var(--ease-out) backwards;
}
.overlay--over.is-active .panel > * {
  animation: anim-rise var(--dur-slow) var(--ease-out) backwards;
  animation-delay: calc(240ms + var(--i, 0) * 90ms);
}
.overlay--over.is-active .over__title {
  animation: anim-title-slam 560ms var(--ease-slam) 160ms backwards;
}
.overlay--over.is-active .over-arcade > * {
  animation: anim-rise var(--dur-med) var(--ease-out) backwards;
  animation-delay: calc(480ms + var(--k, 0) * 90ms);
}
.over-arcade > :nth-child(1) { --k: 0; }
.over-arcade > :nth-child(2) { --k: 1; }
.over-arcade > :nth-child(3) { --k: 2; }
.over-arcade > :nth-child(n + 4) { --k: 3; }

/* new high score: pop in, then a light shimmer sweep */
@keyframes anim-badge-pop {
  0% { transform: scale(0.4) rotate(-8deg); opacity: 0; }
  60% { transform: scale(1.15) rotate(2deg); opacity: 1; }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}
@keyframes anim-shimmer {
  0%, 55% { background-position: 160% 0; }
  100% { background-position: -60% 0; }
}
.over-arcade__badge.is-show {
  background-color: var(--c-lime);
  background-image: linear-gradient(105deg, transparent 35%, rgba(255, 255, 255, 0.75) 50%, transparent 65%);
  background-size: 60% 100%;
  background-repeat: no-repeat;
  background-position: 160% 0;
  animation:
    anim-badge-pop 520ms var(--ease-pop) 600ms backwards,
    anim-shimmer 2.4s ease-in-out 1.2s infinite;
}

/* Toast: rises in, sinks out (keeps the translateX(-50%) centring from ui.css) */
.toast {
  transform: translate(-50%, 0.8rem);
  transition:
    opacity var(--dur-med) var(--ease-in-out),
    transform var(--dur-med) var(--ease-in-out),
    visibility 0s linear var(--dur-med);
}
.toast.is-show {
  transform: translate(-50%, 0);
  transition:
    opacity var(--dur-med) var(--ease-out),
    transform var(--dur-slow) var(--ease-pop),
    visibility 0s linear 0s;
}

/* ═════════ Reduced motion: fades only, nothing moves ═════════ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
  }
  .screen:not(.screen--game),
  .screen:not(.screen--game).is-active {
    transform: none;
  }
  .btn:hover,
  .btn:active,
  .icon-btn:hover,
  .icon-btn:active,
  .mode-card:hover,
  .mode-card:active,
  .mode-card:hover .icon--card,
  .swatch:hover,
  .swatch:active,
  .swatch.is-selected,
  .seg:active,
  .tab:active,
  .chip:active,
  .lang-row:hover,
  .lang-row:active {
    transform: none;
  }
  .toast,
  .toast.is-show {
    transform: translate(-50%, 0);
  }
  /* simple opacity fades survive for screen / overlay / toast changes */
  .screen,
  .overlay,
  .toast {
    transition: opacity 150ms linear, visibility 0s linear 150ms !important;
  }
  .screen.is-active,
  .overlay.is-active,
  .toast.is-show {
    transition: opacity 150ms linear, visibility 0s linear 0s !important;
  }
  /* a spinner that does not turn would look broken: soft pulse instead */
  .spinner {
    animation: anim-attention 1.6s ease-in-out infinite !important;
  }
}
