/* ═══════════════════════════════════════════════════════════
   DHARAVERSE MAP MYSTERY — ANIMATIONS
   File: /games/daily-mystery/css/animations.css
   Used by: index.html, result.html
   Applied by: ui.js (adds/removes classes dynamically)
   
   DEPENDS ON: game.css (uses CSS custom properties)
   ═══════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────
   1. FADE IN
   Applied by: ui.js → general entrance animation
   Class: .fade-in
   ─────────────────────────────────────────────────────────── */
.fade-in {
  animation: fadeIn 0.4s ease forwards;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}


/* ───────────────────────────────────────────────────────────
   2. SLIDE UP
   Applied by: ui.js → attempt rows, game-over banner
   Class: .slide-up
   ─────────────────────────────────────────────────────────── */
.slide-up {
  animation: slideUp 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

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


/* ───────────────────────────────────────────────────────────
   3. SLIDE DOWN
   Applied by: ui.js → dropdowns, news banner
   Class: .slide-down
   ─────────────────────────────────────────────────────────── */
.slide-down {
  animation: slideDown 0.35s ease forwards;
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}


/* ───────────────────────────────────────────────────────────
   4. FLIP IN
   Applied by: ui.js → UIController.renderAttemptRow()
   Each .attempt-cell gets .flip-in with staggered delay
   Class: .flip-in
   ─────────────────────────────────────────────────────────── */
.flip-in {
  animation: flipIn 0.5s ease forwards;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

@keyframes flipIn {
  0% {
    opacity: 0;
    transform: rotateX(90deg) scale(0.8);
  }
  60% {
    opacity: 1;
    transform: rotateX(-5deg) scale(1.02);
  }
  80% {
    transform: rotateX(3deg) scale(1);
  }
  100% {
    opacity: 1;
    transform: rotateX(0) scale(1);
  }
}

/* Staggered delay classes for cells in a row */
/* ui.js applies: .flip-delay-0 through .flip-delay-4 */
.flip-delay-0 { animation-delay: 0ms; }
.flip-delay-1 { animation-delay: 100ms; }
.flip-delay-2 { animation-delay: 200ms; }
.flip-delay-3 { animation-delay: 300ms; }
.flip-delay-4 { animation-delay: 400ms; }

/* Cells start invisible until animation runs */
.flip-in.flip-delay-1,
.flip-in.flip-delay-2,
.flip-in.flip-delay-3,
.flip-in.flip-delay-4 {
  opacity: 0;
}


/* ───────────────────────────────────────────────────────────
   5. SHAKE
   Applied by: ui.js → wrong guess / invalid input
   Class: .shake
   ─────────────────────────────────────────────────────────── */
.shake {
  animation: shake 0.5s ease;
}

@keyframes shake {
  0%, 100% {
    transform: translateX(0);
  }
  10%, 50%, 90% {
    transform: translateX(-6px);
  }
  30%, 70% {
    transform: translateX(6px);
  }
}


/* ───────────────────────────────────────────────────────────
   6. PULSE
   Applied by: ui.js → streak badge on increment
   Class: .pulse
   ─────────────────────────────────────────────────────────── */
.pulse {
  animation: pulse 0.6s ease;
}

@keyframes pulse {
  0% {
    transform: scale(1);
  }
  30% {
    transform: scale(1.25);
  }
  60% {
    transform: scale(0.95);
  }
  100% {
    transform: scale(1);
  }
}


/* ───────────────────────────────────────────────────────────
   7. BOUNCE IN
   Applied by: ui.js → game-over emoji, badge reveals
   Class: .bounce-in
   ─────────────────────────────────────────────────────────── */
.bounce-in {
  animation: bounceIn 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes bounceIn {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  50% {
    opacity: 1;
    transform: scale(1.1);
  }
  70% {
    transform: scale(0.9);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}


/* ───────────────────────────────────────────────────────────
   8. POP IN
   Applied by: ui.js → small elements, badges, pills
   Class: .pop-in
   ─────────────────────────────────────────────────────────── */
.pop-in {
  animation: popIn 0.35s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes popIn {
  0% {
    opacity: 0;
    transform: scale(0.5);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}


/* ───────────────────────────────────────────────────────────
   9. MARKER PING
   Applied by: ui.js → UIController.addGuessMarker()
   Leaflet marker gets .map-marker-pulse class
   ─────────────────────────────────────────────────────────── */
@keyframes markerPing {
  0% {
    box-shadow: 0 0 0 0 rgba(233, 69, 96, 0.6);
  }
  70% {
    box-shadow: 0 0 0 16px rgba(233, 69, 96, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(233, 69, 96, 0);
  }
}

/* Red ping for wrong guesses */
.marker-ping-red {
  animation: markerPing 1s ease-out;
}

/* Green ping for correct guess */
@keyframes markerPingGreen {
  0% {
    box-shadow: 0 0 0 0 rgba(0, 200, 150, 0.7);
  }
  50% {
    box-shadow: 0 0 0 20px rgba(0, 200, 150, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(0, 200, 150, 0);
  }
}

.marker-ping-green {
  animation: markerPingGreen 1.2s ease-out;
}


/* ───────────────────────────────────────────────────────────
   10. TOAST SLIDE (used alongside game.css toast styles)
   Applied by: ui.js → UIController.showToast()
   ─────────────────────────────────────────────────────────── */
@keyframes toastSlide {
  0% {
    opacity: 0;
    transform: translateY(-30px) scale(0.85);
  }
  60% {
    transform: translateY(4px) scale(1.02);
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.toast-bounce {
  animation: toastSlide 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}


/* ───────────────────────────────────────────────────────────
   11. STREAK GLOW
   Applied by: streak.js → when milestone reached
   Class: .streak-glow
   ─────────────────────────────────────────────────────────── */
.streak-glow {
  animation: streakGlow 1.5s ease;
}

@keyframes streakGlow {
  0% {
    box-shadow: 0 0 0 0 rgba(245, 166, 35, 0);
  }
  25% {
    box-shadow: 0 0 16px 4px rgba(245, 166, 35, 0.5);
  }
  50% {
    box-shadow: 0 0 24px 8px rgba(245, 166, 35, 0.3);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(245, 166, 35, 0);
  }
}


/* ───────────────────────────────────────────────────────────
   12. COUNT UP (for stat numbers on result page)
   Applied by: ui.js → stat counters
   Class: .count-up
   ─────────────────────────────────────────────────────────── */
.count-up {
  animation: countUp 0.8s ease-out forwards;
}

@keyframes countUp {
  0% {
    opacity: 0;
    transform: translateY(10px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}


/* ───────────────────────────────────────────────────────────
   13. CONFETTI FALL
   Applied by: ui.js → UIController.triggerConfetti()
   Each .confetti-piece gets random delay + position
   ─────────────────────────────────────────────────────────── */
@keyframes confettiFall {
  0% {
    opacity: 1;
    transform: translateY(0) rotate(0deg) scale(1);
  }
  25% {
    opacity: 1;
    transform: translateY(25vh) rotate(180deg) scale(0.9);
  }
  50% {
    opacity: 0.9;
    transform: translateY(50vh) rotate(360deg) scale(0.85);
  }
  75% {
    opacity: 0.6;
    transform: translateY(75vh) rotate(540deg) scale(0.7);
  }
  100% {
    opacity: 0;
    transform: translateY(100vh) rotate(720deg) scale(0.5);
  }
}

.confetti-piece {
  animation: confettiFall var(--confetti-duration, 3s) 
    var(--confetti-delay, 0s) ease-out forwards;
  will-change: transform, opacity;
}

/* Confetti sway left */
@keyframes confettiSwayLeft {
  0% {
    opacity: 1;
    transform: translateY(0) translateX(0) rotate(0deg);
  }
  50% {
    opacity: 0.9;
    transform: translateY(50vh) translateX(-40px) rotate(360deg);
  }
  100% {
    opacity: 0;
    transform: translateY(100vh) translateX(-80px) rotate(720deg);
  }
}

/* Confetti sway right */
@keyframes confettiSwayRight {
  0% {
    opacity: 1;
    transform: translateY(0) translateX(0) rotate(0deg);
  }
  50% {
    opacity: 0.9;
    transform: translateY(50vh) translateX(40px) rotate(-360deg);
  }
  100% {
    opacity: 0;
    transform: translateY(100vh) translateX(80px) rotate(-720deg);
  }
}

.confetti-sway-left {
  animation-name: confettiSwayLeft;
}

.confetti-sway-right {
  animation-name: confettiSwayRight;
}

/* Confetti shapes (set by ui.js via inline styles) */
.confetti-square {
  border-radius: 2px;
}

.confetti-circle {
  border-radius: 50%;
}

.confetti-strip {
  border-radius: 1px;
  width: 4px !important;
  height: 14px !important;
}


/* ───────────────────────────────────────────────────────────
   14. ROW ENTRANCE (staggered for multiple attempt rows)
   Applied by: ui.js → when restoring saved game state
   Class: .row-enter with --row-delay
   ─────────────────────────────────────────────────────────── */
.row-enter {
  opacity: 0;
  animation: rowEnter 0.35s ease forwards;
  animation-delay: var(--row-delay, 0ms);
}

@keyframes rowEnter {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}


/* ───────────────────────────────────────────────────────────
   15. GLOW BORDER (correct guess row)
   Applied by: ui.js → correct attempt row
   Class: .glow-border-green
   ─────────────────────────────────────────────────────────── */
.glow-border-green {
  animation: glowBorderGreen 2s ease infinite;
}

@keyframes glowBorderGreen {
  0%, 100% {
    box-shadow: 0 0 8px rgba(0, 200, 150, 0.3);
    border-color: rgba(0, 200, 150, 0.5);
  }
  50% {
    box-shadow: 0 0 20px rgba(0, 200, 150, 0.5);
    border-color: rgba(0, 200, 150, 0.8);
  }
}

.glow-border-gold {
  animation: glowBorderGold 2s ease infinite;
}

@keyframes glowBorderGold {
  0%, 100% {
    box-shadow: 0 0 8px rgba(245, 166, 35, 0.3);
    border-color: rgba(245, 166, 35, 0.5);
  }
  50% {
    box-shadow: 0 0 20px rgba(245, 166, 35, 0.5);
    border-color: rgba(245, 166, 35, 0.8);
  }
}


/* ───────────────────────────────────────────────────────────
   16. ARROW SPIN (direction arrow after guess)
   Applied by: ui.js → direction cell arrow
   Class: .arrow-spin
   ─────────────────────────────────────────────────────────── */
.arrow-spin {
  animation: arrowSpin 0.6s ease forwards;
}

@keyframes arrowSpin {
  0% {
    transform: rotate(0deg) scale(0.5);
    opacity: 0;
  }
  60% {
    transform: rotate(var(--arrow-rotation, 0deg)) scale(1.2);
    opacity: 1;
  }
  100% {
    transform: rotate(var(--arrow-rotation, 0deg)) scale(1);
    opacity: 1;
  }
}


/* ───────────────────────────────────────────────────────────
   17. DISTANCE BAR FILL (visual distance indicator)
   Applied by: ui.js → distance cell
   Class: .bar-fill-animate
   ─────────────────────────────────────────────────────────── */
.bar-fill-animate {
  animation: barFill 0.8s ease forwards;
  animation-delay: var(--bar-delay, 200ms);
}

@keyframes barFill {
  from {
    width: 0%;
  }
  to {
    width: var(--bar-width, 50%);
  }
}


/* ───────────────────────────────────────────────────────────
   18. TYPING DOTS (loading state for news fact)
   Applied by: ui.js → while fetching daily fact
   Class: .typing-dots
   ─────────────────────────────────────────────────────────── */
.typing-dots {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  padding: 4px 0;
}

.typing-dots span {
  width: 6px;
  height: 6px;
  background: var(--text-muted);
  border-radius: 50%;
  animation: typingBounce 1.4s ease-in-out infinite;
}

.typing-dots span:nth-child(1) { animation-delay: 0ms; }
.typing-dots span:nth-child(2) { animation-delay: 200ms; }
.typing-dots span:nth-child(3) { animation-delay: 400ms; }

@keyframes typingBounce {
  0%, 60%, 100% {
    transform: translateY(0);
    opacity: 0.4;
  }
  30% {
    transform: translateY(-6px);
    opacity: 1;
  }
}


/* ───────────────────────────────────────────────────────────
   19. SCALE IN (generic scale entrance)
   Class: .scale-in
   ─────────────────────────────────────────────────────────── */
.scale-in {
  animation: scaleIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes scaleIn {
  from {
    opacity: 0;
    transform: scale(0.7);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.scale-out {
  animation: scaleOut 0.2s ease forwards;
}

@keyframes scaleOut {
  from {
    opacity: 1;
    transform: scale(1);
  }
  to {
    opacity: 0;
    transform: scale(0.7);
  }
}


/* ───────────────────────────────────────────────────────────
   20. SHIMMER (skeleton loading placeholder)
   Applied by: ui.js → placeholder while data loads
   Class: .shimmer
   ─────────────────────────────────────────────────────────── */
.shimmer {
  background: linear-gradient(
    90deg,
    var(--bg-secondary) 25%,
    rgba(139, 92, 246, 0.08) 50%,
    var(--bg-secondary) 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.5s ease-in-out infinite;
  border-radius: var(--radius-sm);
}

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


/* ───────────────────────────────────────────────────────────
   21. CELEBRATION BURST (on win — behind confetti)
   Applied by: ui.js → UIController.triggerConfetti()
   Class: .celebration-burst
   ─────────────────────────────────────────────────────────── */
.celebration-burst {
  position: fixed;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(0, 200, 150, 0.3) 0%,
    rgba(139, 92, 246, 0.1) 50%,
    transparent 70%
  );
  animation: celebrationBurst 1s ease-out forwards;
  pointer-events: none;
  z-index: 299; /* just below game-over-banner */
}

@keyframes celebrationBurst {
  0% {
    width: 0;
    height: 0;
    opacity: 1;
    transform: translate(-50%, -50%);
  }
  100% {
    width: 150vmax;
    height: 150vmax;
    opacity: 0;
    transform: translate(-50%, -50%);
  }
}


/* ───────────────────────────────────────────────────────────
   22. NUMBER TICK (animated number change)
   Applied by: ui.js → streak count, stat numbers
   Class: .number-tick
   ─────────────────────────────────────────────────────────── */
.number-tick {
  display: inline-block;
  animation: numberTick 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes numberTick {
  0% {
    transform: translateY(-100%) scale(0.5);
    opacity: 0;
  }
  60% {
    transform: translateY(10%) scale(1.1);
    opacity: 1;
  }
  100% {
    transform: translateY(0) scale(1);
    opacity: 1;
  }
}


/* ───────────────────────────────────────────────────────────
   23. BADGE REVEAL (milestone badge unlock)
   Applied by: streak.js / ui.js → badge animation
   Class: .badge-reveal
   ─────────────────────────────────────────────────────────── */
.badge-reveal {
  animation: badgeReveal 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes badgeReveal {
  0% {
    opacity: 0;
    transform: scale(0) rotate(-180deg);
  }
  60% {
    opacity: 1;
    transform: scale(1.2) rotate(10deg);
  }
  80% {
    transform: scale(0.9) rotate(-5deg);
  }
  100% {
    opacity: 1;
    transform: scale(1) rotate(0deg);
  }
}


/* ───────────────────────────────────────────────────────────
   24. DISTRIBUTION BAR GROW (result page stats)
   Applied by: ui.js → guess distribution chart
   Class: .dist-bar-grow
   ─────────────────────────────────────────────────────────── */
.dist-bar-grow {
  animation: distBarGrow 0.6s ease-out forwards;
  animation-delay: var(--dist-delay, 0ms);
  width: 0%;
}

@keyframes distBarGrow {
  from {
    width: 0%;
  }
  to {
    width: var(--dist-width, 0%);
  }
}


/* ───────────────────────────────────────────────────────────
   25. WIGGLE (attention-grabbing for share button)
   Applied by: ui.js → share button after game over
   Class: .wiggle
   ─────────────────────────────────────────────────────────── */
.wiggle {
  animation: wiggle 0.8s ease 2s 2;
}

@keyframes wiggle {
  0%, 100% {
    transform: rotate(0deg);
  }
  15% {
    transform: rotate(-5deg);
  }
  30% {
    transform: rotate(5deg);
  }
  45% {
    transform: rotate(-4deg);
  }
  60% {
    transform: rotate(3deg);
  }
  75% {
    transform: rotate(-2deg);
  }
}


/* ───────────────────────────────────────────────────────────
   26. COUNTDOWN TICK (next game timer)
   Applied by: app.js → timer update
   Class: .tick
   ─────────────────────────────────────────────────────────── */
.tick {
  animation: tick 0.3s ease;
}

@keyframes tick {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.1);
    color: var(--game-gold);
  }
  100% {
    transform: scale(1);
  }
}


/* ───────────────────────────────────────────────────────────
   27. RIPPLE EFFECT (button press feedback)
   Applied by: ui.js → button clicks
   Class: .ripple (container) + .ripple-wave (animated)
   ─────────────────────────────────────────────────────────── */
.ripple {
  position: relative;
  overflow: hidden;
}

.ripple-wave {
  position: absolute;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
  pointer-events: none;
  transform: scale(0);
  animation: rippleWave 0.6s ease-out forwards;
}

@keyframes rippleWave {
  to {
    transform: scale(4);
    opacity: 0;
  }
}


/* ───────────────────────────────────────────────────────────
   28. MAP LINE DRAW (animated line between guess and target)
   Applied by: ui.js → SVG polyline on Leaflet map
   ─────────────────────────────────────────────────────────── */
.map-line-draw {
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: lineDraw 1s ease forwards;
}

@keyframes lineDraw {
  to {
    stroke-dashoffset: 0;
  }
}


/* ───────────────────────────────────────────────────────────
   29. EMOJI RAIN (result page celebration)
   Applied by: result page JS
   Class: .emoji-rain
   ─────────────────────────────────────────────────────────── */
.emoji-rain {
  position: fixed;
  font-size: 28px;
  top: -40px;
  z-index: 298;
  pointer-events: none;
  animation: emojiRain var(--rain-duration, 3s) 
    var(--rain-delay, 0s) linear forwards;
  will-change: transform;
}

@keyframes emojiRain {
  0% {
    opacity: 1;
    transform: translateY(0) rotate(0deg);
  }
  100% {
    opacity: 0;
    transform: translateY(110vh) rotate(360deg);
  }
}


/* ───────────────────────────────────────────────────────────
   30. PERFORMANCE HINTS
   GPU acceleration for animated elements
   ─────────────────────────────────────────────────────────── */
.flip-in,
.slide-up,
.slide-down,
.bounce-in,
.pop-in,
.confetti-piece,
.celebration-burst,
.emoji-rain,
.badge-reveal,
.arrow-spin {
  will-change: transform, opacity;
}

/* Remove will-change after animation completes (JS handles this) */
.animation-done {
  will-change: auto;
}


/* ───────────────────────────────────────────────────────────
   31. REDUCED MOTION OVERRIDE
   Respects user preference — disables ALL animations
   ─────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .fade-in,
  .slide-up,
  .slide-down,
  .flip-in,
  .shake,
  .pulse,
  .bounce-in,
  .pop-in,
  .marker-ping-red,
  .marker-ping-green,
  .toast-bounce,
  .streak-glow,
  .count-up,
  .confetti-piece,
  .confetti-sway-left,
  .confetti-sway-right,
  .row-enter,
  .glow-border-green,
  .glow-border-gold,
  .arrow-spin,
  .bar-fill-animate,
  .scale-in,
  .scale-out,
  .celebration-burst,
  .number-tick,
  .badge-reveal,
  .dist-bar-grow,
  .wiggle,
  .tick,
  .emoji-rain,
  .map-line-draw {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }

  .shimmer {
    animation: none !important;
    background: var(--bg-secondary) !important;
  }

  .typing-dots span {
    animation: none !important;
    opacity: 1 !important;
  }

  .ripple-wave {
    display: none !important;
  }

  /* Confetti should not appear at all */
  .confetti-container,
  .celebration-burst,
  .emoji-rain {
    display: none !important;
  }
}
