/* ═══════════════════════════════════════════════════════════════════════════
   Motion system — The Greatest Gameshow
   Shared by the primary, games and admin sites (keep the copies identical).

   Built on two libraries:
     • Animate.css 4.1.1 (MIT)  → css/vendor/animate.min.css   classes: animate__animated animate__<name>
     • Animista (animista.net)  → curated keyframes below          classes: tgg-<name>
   plus the small helpers js/motion.js needs ([data-animate] reveals, stagger, press feedback).

   Timing follows the usual interaction-design guidance:
     • micro-interactions (hover/press/toggle)  120–200 ms
     • element entrances & state changes        250–500 ms, ease-out (decelerate = responsive)
     • celebratory / attention moments          600–1000 ms, used once, never looped
     • only loading / waiting states may loop
   Everything animates transform / opacity / filter only (compositor friendly on phones) and is
   switched off for people who ask for reduced motion.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  --tgg-ease-out: cubic-bezier(0.25, 0.46, 0.45, 0.94);        /* ease-out-quad */
  --tgg-ease-out-strong: cubic-bezier(0.19, 1, 0.22, 1);        /* ease-out-expo */
  --tgg-ease-in: cubic-bezier(0.55, 0.085, 0.68, 0.53);         /* ease-in-quad */
  --tgg-ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);   /* ease-out-back */
  --tgg-dur-fast: 160ms;
  --tgg-dur-base: 280ms;
  --tgg-dur-enter: 480ms;
  --tgg-dur-slow: 700ms;

  /* Animate.css defaults to 1 s, which is too slow for interface motion. */
  --animate-duration: 0.6s;
}

/* ─── Reveal-on-view ─────────────────────────────────────────────────────
 * Elements marked data-animate are hidden only while motion.js is running
 * (html.tgg-motion) and not yet revealed, so content is never lost without JS. */
html.tgg-motion [data-animate]:not(.tgg-in) {
  opacity: 0;
}

/* ─── Press & hover feedback (micro-interactions) ─────────────────────── */
html.tgg-motion button:not(:disabled),
html.tgg-motion [class*="btn"]:not(:disabled):not([aria-disabled="true"]) {
  transition-property: transform, box-shadow, background-color, color, border-color, opacity;
  transition-duration: var(--tgg-dur-fast);
  transition-timing-function: var(--tgg-ease-out);
}

html.tgg-motion button:not(:disabled):active,
html.tgg-motion [class*="btn"]:not(:disabled):not([aria-disabled="true"]):active {
  transform: scale(0.96);
  transition-duration: 80ms;
}

html.tgg-motion .tgg-lift:hover {
  transform: translateY(-3px);
}

/* ─── Live / status indicators (allowed to loop: they describe an ongoing state) ─ */
@keyframes tgg-soft-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.tgg-live-pulse {
  animation: tgg-soft-pulse 1.6s ease-in-out infinite;
}

@keyframes tgg-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}

.tgg-float {
  animation: tgg-float 3.2s ease-in-out infinite;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Animista keyframes (generated at animista.net, free to use)
   Each has a tgg-<name> class with its default duration/easing; motion.js can
   override duration/delay per element via inline animation-duration/-delay.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── Entrances ─── */
@keyframes tgg-fade-in {
  0% { opacity: 0; }
  100% { opacity: 1; }
}
.tgg-fade-in { animation: tgg-fade-in var(--tgg-dur-enter) var(--tgg-ease-out) both; }

@keyframes tgg-fade-in-bottom {
  0% { transform: translateY(40px); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}
.tgg-fade-in-bottom { animation: tgg-fade-in-bottom var(--tgg-dur-enter) var(--tgg-ease-out) both; }

@keyframes tgg-fade-in-top {
  0% { transform: translateY(-40px); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}
.tgg-fade-in-top { animation: tgg-fade-in-top var(--tgg-dur-enter) var(--tgg-ease-out) both; }

@keyframes tgg-fade-in-left {
  0% { transform: translateX(-40px); opacity: 0; }
  100% { transform: translateX(0); opacity: 1; }
}
.tgg-fade-in-left { animation: tgg-fade-in-left var(--tgg-dur-enter) var(--tgg-ease-out) both; }

@keyframes tgg-fade-in-right {
  0% { transform: translateX(40px); opacity: 0; }
  100% { transform: translateX(0); opacity: 1; }
}
.tgg-fade-in-right { animation: tgg-fade-in-right var(--tgg-dur-enter) var(--tgg-ease-out) both; }

@keyframes tgg-fade-in-fwd {
  0% { transform: translateZ(-80px); opacity: 0; }
  100% { transform: translateZ(0); opacity: 1; }
}
.tgg-fade-in-fwd { animation: tgg-fade-in-fwd var(--tgg-dur-enter) var(--tgg-ease-out) both; }

@keyframes tgg-scale-in-center {
  0% { transform: scale(0.6); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}
.tgg-scale-in-center { animation: tgg-scale-in-center var(--tgg-dur-enter) var(--tgg-ease-spring) both; }

@keyframes tgg-scale-in-ver-top {
  0% { transform: scaleY(0.4); transform-origin: 100% 0%; opacity: 0; }
  100% { transform: scaleY(1); transform-origin: 100% 0%; opacity: 1; }
}
.tgg-scale-in-ver-top { animation: tgg-scale-in-ver-top var(--tgg-dur-base) var(--tgg-ease-out) both; }

@keyframes tgg-slide-in-top {
  0% { transform: translateY(-100%); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}
.tgg-slide-in-top { animation: tgg-slide-in-top var(--tgg-dur-enter) var(--tgg-ease-out) both; }

@keyframes tgg-slide-in-bottom {
  0% { transform: translateY(120%); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}
.tgg-slide-in-bottom { animation: tgg-slide-in-bottom var(--tgg-dur-enter) var(--tgg-ease-out) both; }

@keyframes tgg-swing-in-top-fwd {
  0% { transform: rotateX(-100deg); transform-origin: top; opacity: 0; }
  100% { transform: rotateX(0deg); transform-origin: top; opacity: 1; }
}
.tgg-swing-in-top-fwd { animation: tgg-swing-in-top-fwd var(--tgg-dur-enter) var(--tgg-ease-spring) both; }

@keyframes tgg-flip-in-hor-bottom {
  0% { transform: rotateX(80deg); opacity: 0; }
  100% { transform: rotateX(0); opacity: 1; }
}
.tgg-flip-in-hor-bottom { animation: tgg-flip-in-hor-bottom var(--tgg-dur-slow) var(--tgg-ease-out) both; }

@keyframes tgg-puff-in-center {
  0% { transform: scale(1.8); filter: blur(4px); opacity: 0; }
  100% { transform: scale(1); filter: blur(0); opacity: 1; }
}
.tgg-puff-in-center { animation: tgg-puff-in-center var(--tgg-dur-enter) cubic-bezier(0.47, 0, 0.745, 0.715) both; }

@keyframes tgg-bounce-in-top {
  0% { transform: translateY(-300px); animation-timing-function: ease-in; opacity: 0; }
  38% { transform: translateY(0); animation-timing-function: ease-out; opacity: 1; }
  55% { transform: translateY(-50px); animation-timing-function: ease-in; }
  72% { transform: translateY(0); animation-timing-function: ease-out; }
  81% { transform: translateY(-22px); animation-timing-function: ease-in; }
  90% { transform: translateY(0); animation-timing-function: ease-out; }
  95% { transform: translateY(-7px); animation-timing-function: ease-in; }
  100% { transform: translateY(0); animation-timing-function: ease-out; }
}
.tgg-bounce-in-top { animation: tgg-bounce-in-top 1.1s both; }

/* ─── Text ─── */
@keyframes tgg-tracking-in-expand {
  0% { letter-spacing: -0.5em; opacity: 0; }
  40% { opacity: 0.6; }
  100% { opacity: 1; }
}
.tgg-tracking-in-expand { animation: tgg-tracking-in-expand var(--tgg-dur-slow) cubic-bezier(0.215, 0.61, 0.355, 1) both; }

@keyframes tgg-text-focus-in {
  0% { filter: blur(12px); opacity: 0; }
  100% { filter: blur(0); opacity: 1; }
}
.tgg-text-focus-in { animation: tgg-text-focus-in var(--tgg-dur-slow) var(--tgg-ease-in) both; }

/* ─── Attention (feedback) ─── */
@keyframes tgg-shake-horizontal {
  0%, 100% { transform: translateX(0); }
  10%, 30%, 50%, 70% { transform: translateX(-8px); }
  20%, 40%, 60% { transform: translateX(8px); }
  80% { transform: translateX(6px); }
  90% { transform: translateX(-6px); }
}
.tgg-shake-horizontal { animation: tgg-shake-horizontal 0.6s cubic-bezier(0.455, 0.03, 0.515, 0.955) both; }

@keyframes tgg-jello-horizontal {
  0% { transform: scale3d(1, 1, 1); }
  30% { transform: scale3d(1.2, 0.8, 1); }
  40% { transform: scale3d(0.8, 1.2, 1); }
  50% { transform: scale3d(1.12, 0.88, 1); }
  65% { transform: scale3d(0.96, 1.04, 1); }
  75% { transform: scale3d(1.04, 0.96, 1); }
  100% { transform: scale3d(1, 1, 1); }
}
.tgg-jello-horizontal { animation: tgg-jello-horizontal 0.8s both; }

@keyframes tgg-wobble-hor-bottom {
  0%, 100% { transform: translateX(0); transform-origin: 50% 50%; }
  15% { transform: translateX(-24px) rotate(-6deg); }
  30% { transform: translateX(12px) rotate(6deg); }
  45% { transform: translateX(-12px) rotate(-3.6deg); }
  60% { transform: translateX(7px) rotate(2.4deg); }
  75% { transform: translateX(-5px) rotate(-1.2deg); }
}
.tgg-wobble-hor-bottom { animation: tgg-wobble-hor-bottom 0.8s both; }

@keyframes tgg-heartbeat {
  from { transform: scale(1); transform-origin: center center; animation-timing-function: ease-out; }
  10% { transform: scale(0.92); animation-timing-function: ease-in; }
  17% { transform: scale(0.98); animation-timing-function: ease-out; }
  33% { transform: scale(0.9); animation-timing-function: ease-in; }
  45% { transform: scale(1); animation-timing-function: ease-out; }
}
.tgg-heartbeat { animation: tgg-heartbeat 1.5s ease-in-out infinite both; }

@keyframes tgg-pulsate-fwd {
  0% { transform: scale(1); }
  50% { transform: scale(1.06); }
  100% { transform: scale(1); }
}
.tgg-pulsate-fwd { animation: tgg-pulsate-fwd 2s ease-in-out infinite both; }

@keyframes tgg-ping {
  0% { transform: scale(0.4); opacity: 0.8; }
  80% { transform: scale(1.6); opacity: 0; }
  100% { transform: scale(2); opacity: 0; }
}
.tgg-ping { animation: tgg-ping 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; }

/* ─── Exits ─── */
@keyframes tgg-fade-out {
  0% { opacity: 1; }
  100% { opacity: 0; }
}
.tgg-fade-out { animation: tgg-fade-out var(--tgg-dur-base) var(--tgg-ease-in) both; }

@keyframes tgg-scale-out-center {
  0% { transform: scale(1); opacity: 1; }
  100% { transform: scale(0.8); opacity: 0; }
}
.tgg-scale-out-center { animation: tgg-scale-out-center var(--tgg-dur-base) var(--tgg-ease-in) both; }

@keyframes tgg-slide-out-bottom {
  0% { transform: translateY(0); opacity: 1; }
  100% { transform: translateY(120%); opacity: 0; }
}
.tgg-slide-out-bottom { animation: tgg-slide-out-bottom var(--tgg-dur-base) var(--tgg-ease-in) both; }

/* ─── 3D helpers for flip/swing entrances ─── */
.tgg-perspective {
  perspective: 900px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Component motion (shared markup patterns: modals, dropdown, status text)
   ═══════════════════════════════════════════════════════════════════════════ */

/* Modals: backdrop fades, dialog springs in from 60%. Restarts every time it opens. */
html.tgg-motion .modal.active,
html.tgg-motion .modal-overlay.open {
  animation: tgg-fade-in 220ms var(--tgg-ease-out) both;
}

html.tgg-motion .modal.active .modal-content,
html.tgg-motion .modal-overlay.open .modal-box {
  animation: tgg-scale-in-center 340ms var(--tgg-ease-spring) both;
}

/* Nav dropdown: hinges down from the toggle. */
html.tgg-motion .nav-dropdown {
  perspective: 800px;
}

html.tgg-motion .navbar-links .dropdown-menu.open {
  animation: tgg-swing-in-top-fwd 360ms var(--tgg-ease-spring) both;
}

/* Status / error text pops in; errors also shake (see TGGUI.setStatus). */
html.tgg-motion .tgg-status-pop {
  animation: tgg-fade-in-bottom 320ms var(--tgg-ease-out) both;
}

/* ─── Reduced motion ─────────────────────────────────────────────────────
 * Vestibular-safe: every decorative animation collapses to an instant change and
 * content never starts hidden. (Animate.css ships the same rule for its classes.) */
@media (prefers-reduced-motion: reduce) {
  html.tgg-motion [data-animate]:not(.tgg-in) {
    opacity: 1;
  }

  .tgg-fade-in, .tgg-fade-in-bottom, .tgg-fade-in-top, .tgg-fade-in-left, .tgg-fade-in-right,
  .tgg-fade-in-fwd, .tgg-scale-in-center, .tgg-scale-in-ver-top, .tgg-slide-in-top,
  .tgg-slide-in-bottom, .tgg-swing-in-top-fwd, .tgg-flip-in-hor-bottom, .tgg-puff-in-center,
  .tgg-bounce-in-top, .tgg-tracking-in-expand, .tgg-text-focus-in, .tgg-shake-horizontal,
  .tgg-jello-horizontal, .tgg-wobble-hor-bottom, .tgg-ping, .tgg-fade-out,
  .tgg-scale-out-center, .tgg-slide-out-bottom {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
  }

  .tgg-live-pulse,
  .tgg-float,
  .tgg-heartbeat,
  .tgg-pulsate-fwd {
    animation: none !important;
  }

  html.tgg-motion button:not(:disabled):active,
  html.tgg-motion [class*="btn"]:not(:disabled):not([aria-disabled="true"]):active,
  html.tgg-motion .tgg-lift:hover {
    transform: none;
  }
}
