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

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

@keyframes card-in {
  from {
    opacity: 0;
    transform: translateY(16px) rotate(-0.6deg) scale(0.985);
  }
  to {
    opacity: 1;
    transform: translateY(0) rotate(0) scale(1);
  }
}

@keyframes card-flip {
  0% {
    opacity: 0;
    transform: perspective(900px) rotateY(-72deg) translateY(10px);
  }
  60% {
    opacity: 1;
    transform: perspective(900px) rotateY(8deg) translateY(0);
  }
  100% {
    opacity: 1;
    transform: perspective(900px) rotateY(0) translateY(0);
  }
}

@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes modal-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

@keyframes shake {
  0%,
  100% {
    transform: translateX(0);
  }
  20% {
    transform: translateX(-6px) rotate(-1deg);
  }
  40% {
    transform: translateX(5px) rotate(1deg);
  }
  60% {
    transform: translateX(-4px);
  }
  80% {
    transform: translateX(3px);
  }
}

@keyframes stamp-pop {
  0% {
    opacity: 0;
    transform: scale(0.55) rotate(-6deg);
  }
  65% {
    opacity: 1;
    transform: scale(1.06) rotate(1.5deg);
  }
  100% {
    opacity: 1;
    transform: scale(1) rotate(0);
  }
}

@keyframes blink {
  0%,
  45% {
    opacity: 1;
  }
  50%,
  95% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@keyframes stroke-in {
  from {
    opacity: 0;
    transform: scale(0.9);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes trace-fade {
  to {
    opacity: 0.18;
  }
}

@keyframes hp-hit {
  0% {
    transform: scaleX(1);
  }
  40% {
    transform: scaleX(0.2);
    background: var(--gold);
  }
  100% {
    transform: scaleX(1);
  }
}

@keyframes boss-hit {
  0%,
  100% {
    transform: translateX(0);
    filter: drop-shadow(0 12px 0 rgba(38, 53, 66, 0.08));
  }
  20% {
    transform: translateX(-8px) rotate(-1deg);
    filter: brightness(1.2) drop-shadow(0 12px 0 rgba(38, 53, 66, 0.08));
  }
  45% {
    transform: translateX(7px) rotate(1deg);
  }
  70% {
    transform: translateX(-3px);
  }
}

@keyframes star-burst {
  0% {
    opacity: 1;
    transform: translate(0, 0) scale(0.4) rotate(0deg);
  }
  70% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(var(--dx), var(--dy)) scale(var(--scale, 1)) rotate(var(--rot, 120deg));
  }
}

@keyframes flash {
  0% {
    opacity: 0.55;
  }
  100% {
    opacity: 0;
  }
}

@keyframes ring-out {
  0% {
    opacity: 0.7;
    transform: translate(-50%, -50%) scale(0.4);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(2.2);
  }
}

@keyframes stamp-fly {
  0% {
    opacity: 1;
    transform: translate(0, 0) scale(1) rotate(0);
  }
  70% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(var(--dx), var(--dy)) scale(0.35) rotate(240deg);
  }
}

@keyframes combo-pop {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.4) rotate(-8deg);
  }
  25% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1.12) rotate(2deg);
  }
  55% {
    transform: translate(-50%, -50%) scale(1) rotate(0);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(1.04) translateY(-26px);
  }
}

@keyframes chest-bounce {
  0%,
  100% {
    transform: translateY(0) rotate(-1deg);
  }
  50% {
    transform: translateY(-7px) rotate(1deg);
  }
}

/* ---------- 粒子 ---------- */
.fx-star {
  position: fixed;
  left: var(--x);
  top: var(--y);
  width: var(--size, 12px);
  height: var(--size, 12px);
  background: var(--color, #eaa93c);
  clip-path: polygon(
    50% 0%,
    61% 35%,
    98% 35%,
    68% 57%,
    79% 91%,
    50% 70%,
    21% 91%,
    32% 57%,
    2% 35%,
    39% 35%
  );
  animation: star-burst var(--dur, 0.85s) cubic-bezier(0.15, 0.7, 0.3, 1) forwards;
  animation-delay: var(--delay, 0s);
  z-index: 90;
  pointer-events: none;
}

.fx-flash {
  position: fixed;
  inset: 0;
  z-index: 85;
  pointer-events: none;
  background: radial-gradient(circle at 50% 55%, rgba(255, 230, 150, 0.85), rgba(255, 230, 150, 0) 62%);
  animation: flash 0.5s ease-out forwards;
}

.fx-ring {
  position: fixed;
  left: var(--x);
  top: var(--y);
  width: 80px;
  height: 80px;
  border: 4px solid var(--gold);
  border-radius: 50%;
  z-index: 88;
  pointer-events: none;
  animation: ring-out 0.8s ease-out forwards;
}

.fx-stamp {
  position: fixed;
  left: var(--x);
  top: var(--y);
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border: 2px solid var(--ink);
  border-radius: 50%;
  background: var(--gold);
  color: #4a330d;
  font-size: 15px;
  font-weight: 900;
  z-index: 95;
  pointer-events: none;
  animation: stamp-fly 0.75s cubic-bezier(0.3, 0.7, 0.4, 1) forwards;
}

.combo-burst {
  position: fixed;
  left: 50%;
  top: 46%;
  z-index: 96;
  pointer-events: none;
  display: grid;
  justify-items: center;
  gap: 2px;
  animation: combo-pop 1.15s ease-out forwards;
}

.combo-burst b {
  font-size: clamp(34px, 7vw, 58px);
  font-weight: 900;
  color: var(--ink);
  letter-spacing: 0.06em;
  text-shadow:
    0 3px 0 #fffdf6,
    0 6px 0 rgba(38, 53, 66, 0.14);
}

.combo-burst small {
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.3em;
  color: #8a5d0c;
  background: var(--gold);
  padding: 3px 10px;
  border-radius: 999px;
  border: 1.5px solid var(--ink);
}

/* ---------- 角色 ---------- */
.mascot {
  overflow: visible;
}

.mascot-body {
  animation: bob 3.2s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}

.mascot--sad .mascot-body {
  animation: none;
  transform: translateY(3px);
}

.mascot--cheer .mascot-body {
  animation: bob 0.9s ease-in-out infinite;
}

.mascot-arm {
  transition: transform 0.3s cubic-bezier(0.2, 1.4, 0.4, 1);
}

.mascot--cheer .mascot-arm--left {
  transform: rotate(118deg);
}

.mascot--cheer .mascot-arm--right {
  transform: rotate(-118deg);
}

.mascot--happy .mascot-arm--left {
  transform: rotate(-14deg);
}

.mascot--happy .mascot-arm--right {
  transform: rotate(14deg);
}

.mascot-think-bubble {
  animation: bob 2.4s ease-in-out infinite;
}

.mascot-sparks {
  animation: fade-in 0.4s ease both;
}

.chest-art {
  animation: chest-bounce 3.4s ease-in-out infinite;
}

.chest-art .chest-glow {
  opacity: 0.75;
}

.chest-art .chest-rays {
  animation: fade-in 0.5s ease both;
}

/* ---------- 减少动态 ---------- */
body.reduce-motion *,
body.reduce-motion *::before,
body.reduce-motion *::after {
  animation-duration: 0.001s !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001s !important;
}

body.reduce-motion .fx-star,
body.reduce-motion .fx-flash,
body.reduce-motion .fx-ring,
body.reduce-motion .fx-stamp,
body.reduce-motion .combo-burst {
  display: none !important;
}

body.reduce-motion .mascot-body,
body.reduce-motion .chest-art,
body.reduce-motion .boss-art-wrap {
  animation: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .fx-star,
  .fx-flash,
  .fx-ring,
  .fx-stamp,
  .combo-burst {
    display: none !important;
  }
  .mascot-body,
  .chest-art,
  .boss-art-wrap,
  .event-icon {
    animation: none !important;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01s !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}
