@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@keyframes pulseGlow {
  from {
    text-shadow: 0 0 4px var(--danger);
    transform: scale(1);
  }
  to {
    text-shadow: 0 0 16px var(--danger), 0 0 24px var(--danger);
    transform: scale(1.05);
  }
}

@keyframes floatWobble {
  0% {
    transform: translate(0, 0) rotate(0deg) scale(1);
  }
  25% {
    transform: translate(4px, -8px) rotate(5deg) scale(1.08);
  }
  50% {
    transform: translate(-3px, -14px) rotate(-3deg) scale(1.12);
  }
  75% {
    transform: translate(5px, -6px) rotate(4deg) scale(1.06);
  }
  100% {
    transform: translate(0, 0) rotate(0deg) scale(1);
  }
}

@keyframes shimmer {
  0% {
    background-position: -200% 0;
  }
  100% {
    background-position: 200% 0;
  }
}

@keyframes buttonPulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--life) 50%, transparent); }
  70% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--life) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--life) 0%, transparent); }
}

@keyframes floatSmooth {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-5px); }
}

.dynamic-pulse {
  animation: buttonPulse 2s 3; /* a "ready" glow pulses at most 3 times (style guide §6) */
}

.dynamic-float {
  animation: floatSmooth 3s ease-in-out infinite;
}

@keyframes desertDust {
  from { background-position: 0 0, 0 0, 0 0, 0 0; }
  to { background-position: 200px -200px, 400px -400px, -200px -200px, 200px -200px; }
}

body::before {
  content: "";
  position: fixed;
  inset: -400px;
  background-image: 
    radial-gradient(2px 2px at 20px 30px, color-mix(in srgb, var(--gold) 40%, transparent), transparent),
    radial-gradient(2px 2px at 40px 70px, color-mix(in srgb, var(--gold) 20%, transparent), transparent),
    radial-gradient(2px 2px at 90px 40px, color-mix(in srgb, var(--gold) 30%, transparent), transparent),
    radial-gradient(3px 3px at 160px 120px, color-mix(in srgb, var(--gold) 15%, transparent), transparent);
  background-size: 200px 200px;
  animation: desertDust 50s linear infinite;
  pointer-events: none;
  z-index: 1;
}

/* Reduced motion (R24, style guide §6): the global rule in tokens.css stops every animation and
   transition; these drop what is still drawn without one. */
:root[data-motion="reduced"] body::before { display: none; } /* drifting background dust */
:root[data-motion="reduced"] .monster-arena-box.hit-shake,
:root[data-motion="reduced"] .monolith-orb.pulse,
:root[data-motion="reduced"] .monolith-orb.auto-pulse,
:root[data-motion="reduced"] .monolith-orb:active { transform: none; }
@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) body::before { display: none; }
  :root:not([data-motion="full"]) .monster-arena-box.hit-shake { transform: none; }
}

/* Feedback helper (R41, js/ui/feedback.js): T2 shake of one element (3 px, <= 240 ms, one at a
   time) and hit-stop (freeze an element's animations for 60-120 ms; the sim keeps running).
   Reduced motion: the global rule in tokens.css removes both. */
@keyframes fxShake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-3px); }
  50% { transform: translateX(3px); }
  75% { transform: translateX(-2px); }
}
.fx-shake { animation: fxShake 240ms linear; }
.is-hitstop, .is-hitstop * { animation-play-state: paused !important; }
