/* Bubble Pop Math — motion.
 *
 * Animation is used where it carries meaning: a bubble bursting, a wrong answer
 * wobbling, a hint pulsing, stars arriving one at a time. Nothing loops
 * forever, nothing moves while a child is reading, and every rule here is
 * switched off by `.reduced-motion` at the bottom of the file.
 *
 * The bubbles themselves are the one thing that does move continuously, and
 * that is why Calm mode exists: `.calm-motion` stops the drift in JavaScript
 * (the field lays out in a static grid instead) and stops the bob here. The
 * game is complete and fully playable with every rule in this file disabled.
 */

@keyframes bpm-pop {
  0% { transform: scale(1); opacity: 1; }
  45% { transform: scale(1.25); opacity: 1; }
  100% { transform: scale(0.2); opacity: 0; }
}

@keyframes bpm-wobble {
  0%, 100% { rotate: 0deg; }
  20% { rotate: -9deg; }
  45% { rotate: 8deg; }
  70% { rotate: -5deg; }
}

@keyframes bpm-bob {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -6px; }
}

@keyframes bpm-glow {
  0%, 100% { box-shadow: 0 4px 14px rgba(11, 79, 108, 0.25); }
  50% { box-shadow: 0 0 0 8px rgba(255, 209, 102, 0.75), 0 4px 14px rgba(11, 79, 108, 0.25); }
}

@keyframes bpm-rise {
  from { opacity: 0; transform: translate(-50%, 12px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

@keyframes bpm-star-in {
  from { opacity: 0; transform: scale(0.4) rotate(-25deg); }
  to { opacity: 1; transform: scale(1) rotate(0deg); }
}

/* The bob is applied to an inner element so it cannot fight the transform the
 * physics loop writes on the button itself. Phase is set per bubble in JS so
 * the field does not pulse in unison. */
.bubble .bubble-value {
  animation: bpm-bob 3.4s ease-in-out infinite;
  animation-delay: var(--phase, 0s);
}

.bubble.popped {
  animation: bpm-pop 340ms ease-out forwards;
  pointer-events: none;
}

/* A wrong tap wobbles and dims. It does not pop, and the question stays. */
.bubble.wrong {
  animation: bpm-wobble 420ms ease-in-out;
  filter: saturate(0.45) brightness(0.9);
}

.bubble.hint-glow { animation: bpm-glow 1.4s ease-in-out 3; }

.overlay { animation: bpm-rise 220ms ease-out; }

.done-stars svg { animation: bpm-star-in 420ms ease-out backwards; }
.done-stars svg:nth-child(2) { animation-delay: 160ms; }
.done-stars svg:nth-child(3) { animation-delay: 320ms; }

.btn, .tier-chip, .icon-btn { transition: transform 120ms ease, box-shadow 120ms ease; }
.btn:active, .tier-chip:active, .icon-btn:active { transform: translateY(2px); }
.tier-chip:hover { border-color: var(--sky); }

/* Calm mode: the bubbles hold still. Not a degraded version of the game — the
 * layout is a proper grid and every question is answered the same way. */
body.calm-motion .bubble .bubble-value { animation: none; }

/* Honour the OS setting and the in-game override. Nothing above survives this:
 * transitions collapse to instant rather than being merely shortened, so a
 * child who needs stillness gets stillness. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

.reduced-motion *,
.reduced-motion *::before,
.reduced-motion *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}
