/* AfterLife motion library. Mirror of motion.json; keep both in sync.
   Loops: add class m-<name>. One-shots: use play() from motion.js. */

@property --m-delay { syntax: '<time>'; inherits: false; initial-value: 0ms; }

:root {
  --ease-out: cubic-bezier(0.22, 0.8, 0.3, 1);
  --ease-in: cubic-bezier(0.5, 0, 0.75, 0);
  --ease-in-out: cubic-bezier(0.45, 0, 0.55, 1);
  --ease-back: cubic-bezier(0.34, 1.56, 0.64, 1);
  --dur-press: 160ms;
  --dur-fast: 200ms;
  --dur-base: 320ms;
  --dur-slow: 560ms;
}

/* ---------- Loops ---------- */
.m-bob-idle { animation: m-bob-idle 2800ms var(--ease-in-out) var(--m-delay) infinite; }
.m-breathe { animation: m-breathe 3200ms var(--ease-in-out) var(--m-delay) infinite; transform-origin: 50% 100%; }
.m-blink { animation: m-blink 4200ms linear var(--m-delay) infinite; }
.m-flame-flicker { animation: m-flame-flicker 1400ms var(--ease-in-out) var(--m-delay) infinite; transform-origin: 50% 100%; }
.m-glow-pulse { animation: m-glow-pulse 2800ms var(--ease-in-out) var(--m-delay) infinite; }
.m-curtain-sway { animation: m-curtain-sway 4000ms var(--ease-in-out) var(--m-delay) infinite; transform-origin: 50% 0%; }
.m-current-node-pulse { animation: m-current-node-pulse 1800ms var(--ease-in-out) var(--m-delay) infinite; }
.m-head-tilt { animation: m-head-tilt 5200ms var(--ease-in-out) var(--m-delay) infinite; transform-origin: 50% 100%; }
.m-tail-flick { animation: m-tail-flick 3600ms var(--ease-out) var(--m-delay) infinite; }
.m-arm-sway { animation: m-arm-sway 3200ms var(--ease-in-out) var(--m-delay) infinite; }
.m-wing-ruffle { animation: m-wing-ruffle 4800ms var(--ease-out) var(--m-delay) infinite; transform-origin: 50% 0%; }

@keyframes m-bob-idle { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
@keyframes m-breathe { 0%, 100% { transform: scale(1, 1); } 50% { transform: scale(1.015, 1.035); } }
@keyframes m-blink { 0%, 90%, 96%, 100% { transform: scaleY(1); } 93% { transform: scaleY(0.1); } }
@keyframes m-flame-flicker {
  0%, 100% { transform: scale(1, 1) skewX(0deg); }
  25% { transform: scale(0.97, 1.05) skewX(-2deg); }
  50% { transform: scale(1.02, 0.97) skewX(1deg); }
  75% { transform: scale(0.98, 1.03) skewX(2deg); }
}
@keyframes m-glow-pulse { 0%, 100% { opacity: 0.7; transform: scale(1); } 50% { opacity: 1; transform: scale(1.06); } }
@keyframes m-curtain-sway { 0%, 100% { transform: skewX(0deg); } 35% { transform: skewX(2deg); } 70% { transform: skewX(-1.5deg); } }
@keyframes m-current-node-pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.07); opacity: 0.65; } }
@keyframes m-head-tilt { 0%, 40%, 85%, 100% { transform: rotate(0deg); } 50%, 75% { transform: rotate(-10deg); } }
@keyframes m-tail-flick { 0%, 80%, 100% { transform: rotate(0deg); } 86% { transform: rotate(-12deg); } 92% { transform: rotate(4deg); } }
@keyframes m-arm-sway { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(var(--sway, 5deg)); } }
@keyframes m-wing-ruffle { 0%, 85%, 100% { transform: rotate(0deg); } 90% { transform: rotate(-8deg); } 95% { transform: rotate(3deg); } }

.m-ring-shake { animation: m-ring-shake 1800ms linear var(--m-delay) infinite; }
.m-ring-waves { animation: m-ring-waves 1800ms var(--ease-out) var(--m-delay) infinite; }
@keyframes m-ring-shake {
  0%, 36%, 100% { transform: translateY(0) rotate(0deg); }
  4%, 12%, 20%, 28% { transform: translateY(-2px) rotate(-4deg); }
  8%, 16%, 24%, 32% { transform: translateY(-2px) rotate(4deg); }
}
@keyframes m-ring-waves {
  0%, 100% { opacity: 0.35; transform: scale(0.92); }
  6%, 34% { opacity: 1; transform: scale(1); }
  48% { opacity: 0.35; transform: scale(0.92); }
}

.m-pendulum-swing { animation: m-pendulum-swing 2600ms var(--ease-in-out) var(--m-delay) infinite; transform-origin: 50% 0%; }
@keyframes m-pendulum-swing { 0%, 100% { transform: rotate(9deg); } 50% { transform: rotate(-9deg); } }
/* Gameplay timing reads this loop, so reduced motion slows it instead of stopping it. */
:root[data-motion="reduced"] .m-pendulum-swing { animation-duration: 4400ms; }
@media (prefers-reduced-motion: reduce) { :root:not([data-motion="full"]) .m-pendulum-swing { animation-duration: 4400ms; } }

/* ---------- One-shots ---------- */
.m-tap-squash { animation: m-tap-squash 260ms var(--ease-out) var(--m-delay) 1; transform-origin: 50% 100%; }
.m-press { animation: m-press var(--dur-press) var(--ease-out) var(--m-delay) 1; }
.m-wobble-wrong { animation: m-wobble-wrong 420ms var(--ease-out) var(--m-delay) 1; transform-origin: 50% 100%; }
.m-slide-in { animation: m-slide-in var(--dur-base) var(--ease-out) var(--m-delay) 1 backwards; }
.m-fade-in { animation: m-fade-in var(--dur-fast) var(--ease-out) var(--m-delay) 1 backwards; }
.m-fade-out { animation: m-fade-out var(--dur-fast) var(--ease-in) var(--m-delay) 1 forwards; }
.m-sparkle { animation: m-sparkle 640ms var(--ease-out) var(--m-delay) 1 both; }
.m-node-unlock { animation: m-node-unlock var(--dur-slow) var(--ease-back) var(--m-delay) 1; transform-origin: 50% 100%; }
.m-lock-drop { animation: m-lock-drop 420ms var(--ease-in) var(--m-delay) 1 forwards; }
.m-meter-needle-settle { animation: m-meter-needle-settle 640ms var(--ease-out) var(--m-delay) 1; }
.m-gem-tick { animation: m-gem-tick 280ms var(--ease-back) var(--m-delay) 1; }
.m-popup-in { animation: m-popup-in 300ms var(--ease-back) var(--m-delay) 1 backwards; }
.m-popup-out { animation: m-popup-out 180ms var(--ease-in) var(--m-delay) 1 forwards; }
.m-win-burst { animation: m-win-burst 800ms var(--ease-out) var(--m-delay) 1 both; }
.m-fragment-found { animation: m-fragment-found 760ms var(--ease-out) var(--m-delay) 1 backwards; }
.m-hop { animation: m-hop 360ms var(--ease-out) var(--m-delay) 1; transform-origin: 50% 100%; }
.m-fly-to { animation: m-fly-to 620ms var(--ease-in-out) var(--m-delay) 1 forwards; }
.m-page-turn { animation: m-page-turn 360ms var(--ease-out) var(--m-delay) 1 backwards; transform-origin: 0% 50%; }
.m-memory-bloom { animation: m-memory-bloom 1100ms var(--ease-out) var(--m-delay) 1 both; }

@keyframes m-page-turn { from { transform: perspective(1400px) translateX(var(--turn-x, 26px)) rotateY(var(--turn-deg, -7deg)); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes m-memory-bloom { 0% { transform: scale(0.4); opacity: 0; } 45% { transform: scale(1.1); opacity: 1; } 100% { transform: scale(1); opacity: 1; } }

@keyframes m-tap-squash { 0%, 100% { transform: scale(1, 1); } 35% { transform: scale(1.1, 0.88); } 70% { transform: scale(0.97, 1.04); } }
@keyframes m-press { 0%, 100% { transform: scale(1); } 45% { transform: scale(0.92); } }
@keyframes m-wobble-wrong {
  0%, 100% { transform: rotate(0deg); }
  20% { transform: rotate(-7deg); }
  40% { transform: rotate(6deg); }
  60% { transform: rotate(-4deg); }
  80% { transform: rotate(2deg); }
}
@keyframes m-slide-in { from { transform: translate(var(--slide-x, 0px), var(--slide-y, 24px)); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes m-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes m-fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes m-sparkle {
  0% { transform: scale(0) rotate(0deg); opacity: 0; }
  40% { transform: scale(1.1) rotate(30deg); opacity: 1; }
  100% { transform: scale(0.4) rotate(60deg); opacity: 0; }
}
@keyframes m-node-unlock {
  0% { transform: scale(0.7) rotate(-6deg); }
  60% { transform: scale(1.1) rotate(3deg); }
  100% { transform: scale(1) rotate(0deg); }
}
@keyframes m-lock-drop { 0% { transform: translateY(0); opacity: 1; } 30% { transform: translateY(-4px); opacity: 1; } 100% { transform: translateY(18px); opacity: 0; } }
@keyframes m-meter-needle-settle {
  0% { transform: rotate(var(--needle-from, 0deg)); }
  55% { transform: rotate(calc(var(--needle-to, 0deg) + var(--needle-over, 5deg))); }
  80% { transform: rotate(calc(var(--needle-to, 0deg) - var(--needle-over, 5deg) / 3)); }
  100% { transform: rotate(var(--needle-to, 0deg)); }
}
@keyframes m-gem-tick { 0%, 100% { transform: scale(1); } 40% { transform: scale(1.25); } }
@keyframes m-popup-in { from { transform: scale(0.88); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes m-popup-out { from { transform: scale(1); opacity: 1; } to { transform: scale(0.94); opacity: 0; } }
@keyframes m-win-burst {
  0% { transform: scale(0.3) rotate(0deg); opacity: 0; }
  25% { opacity: 1; }
  100% { transform: scale(1.25) rotate(25deg); opacity: 0; }
}
@keyframes m-fragment-found {
  0% { transform: translateY(12px) scale(0.2) rotate(-25deg); opacity: 0; }
  55% { transform: translateY(-4px) scale(1.15) rotate(6deg); opacity: 1; }
  80% { transform: translateY(0) scale(0.97) rotate(-2deg); }
  100% { transform: none; opacity: 1; }
}
@keyframes m-hop {
  0%, 100% { transform: translateY(0) scale(1, 1); }
  40% { transform: translateY(-10px) scale(0.96, 1.05); }
  80% { transform: translateY(0) scale(1.06, 0.94); }
}

@keyframes m-fly-to {
  0% { transform: none; opacity: 1; }
  85% { opacity: 1; }
  100% { transform: translate(var(--fly-x, 0px), var(--fly-y, -60px)) scale(var(--fly-scale, 0.45)); opacity: 0; }
}

/* Needle keeps its angle after the one-shot class is removed. */
.part-needle { transform: rotate(var(--needle-to, 0deg)); }

.pressable { transition: transform 90ms var(--ease-out); cursor: pointer; }
.pressable:active { transform: translateY(1px) scale(0.95); }

/* ---------- Character idles: add class "idle" to the character's root <svg> ---------- */
.idle .part-figure { animation: m-bob-idle 3000ms var(--ease-in-out) infinite; }
.idle .part-glow { animation: m-glow-pulse 3000ms var(--ease-in-out) infinite; }
.idle .part-eyes, .idle .part-eye { animation: m-blink 4200ms linear 600ms infinite; }

.al-gran.idle .part-body { animation: m-breathe 3000ms var(--ease-in-out) infinite; }
.al-gran.idle .part-arm-l { animation: m-arm-sway 3000ms var(--ease-in-out) infinite; --sway: 6deg; }
.al-gran.idle .part-arm-r { animation: m-arm-sway 3000ms var(--ease-in-out) 150ms infinite; --sway: -6deg; }

.al-crow.idle .part-figure { animation: m-breathe 3400ms var(--ease-in-out) infinite; transform-origin: 50% 100%; }
.al-crow.idle .part-head { animation: m-head-tilt 5200ms var(--ease-in-out) infinite; }
.al-crow.idle .part-tail { animation: m-tail-flick 3600ms var(--ease-out) 900ms infinite; }
.al-crow.idle .part-wing-r { animation: m-wing-ruffle 4800ms var(--ease-out) 2000ms infinite; }
.al-crow.idle .part-eye { animation-delay: 1400ms; }

.al-flame.idle .part-outer { animation: m-flame-flicker 1400ms var(--ease-in-out) infinite; }
.al-flame.idle .part-core { animation: m-flame-flicker 1100ms var(--ease-in-out) 300ms infinite; }

/* ---------- Reduced motion: loops stop, one-shots become short fades ---------- */
@keyframes m-still { from { opacity: 1; } to { opacity: 1; } }
@keyframes m-soft-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes m-dim-flash { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }

:root[data-motion="reduced"] :is(.m-bob-idle, .m-breathe, .m-flame-flicker, .m-glow-pulse, .m-curtain-sway,
  .m-current-node-pulse, .m-head-tilt, .m-tail-flick, .m-arm-sway, .m-wing-ruffle, .m-ring-shake, .m-ring-waves) { animation: none; }
/* Idle parts get their own rule: inside the :is() list above, this selector's specificity would also beat the reduced one-shot fallbacks below on looping parts. */
:root[data-motion="reduced"] .idle .part:not(.part-eye, .part-eyes) { animation: none; }
:root[data-motion="reduced"] :is(.m-tap-squash, .m-press, .m-gem-tick, .m-hop, .m-meter-needle-settle) {
  animation: m-still 1ms linear 1;
}
:root[data-motion="reduced"] :is(.m-slide-in, .m-popup-in, .m-node-unlock, .m-fragment-found, .m-page-turn, .m-memory-bloom) {
  animation: m-soft-in var(--dur-fast) linear 1 backwards;
}
:root[data-motion="reduced"] .m-wobble-wrong { animation: m-dim-flash 300ms linear 1; }
:root[data-motion="reduced"] :is(.m-sparkle, .m-win-burst, .m-lock-drop, .m-fly-to) { animation: m-fade-out var(--dur-fast) linear 1 forwards; }
:root[data-motion="reduced"] .pressable:active { transform: none; opacity: 0.8; }

@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) :is(.m-bob-idle, .m-breathe, .m-flame-flicker, .m-glow-pulse, .m-curtain-sway,
    .m-current-node-pulse, .m-head-tilt, .m-tail-flick, .m-arm-sway, .m-wing-ruffle, .m-ring-shake, .m-ring-waves) { animation: none; }
  :root:not([data-motion="full"]) .idle .part:not(.part-eye, .part-eyes) { animation: none; }
  :root:not([data-motion="full"]) :is(.m-tap-squash, .m-press, .m-gem-tick, .m-hop, .m-meter-needle-settle) {
    animation: m-still 1ms linear 1;
  }
  :root:not([data-motion="full"]) :is(.m-slide-in, .m-popup-in, .m-node-unlock, .m-fragment-found, .m-page-turn, .m-memory-bloom) {
    animation: m-soft-in var(--dur-fast) linear 1 backwards;
  }
  :root:not([data-motion="full"]) .m-wobble-wrong { animation: m-dim-flash 300ms linear 1; }
  :root:not([data-motion="full"]) :is(.m-sparkle, .m-win-burst, .m-lock-drop, .m-fly-to) { animation: m-fade-out var(--dur-fast) linear 1 forwards; }
}
