/* Lagos Life motion: every keyframe the app ships, rebuilt on tokens, with its reduced-motion form.
   Owner: 5b. Spec: site/surfaces-motion.html#productive, #expressive, #loops, #reduced; 05-sections/5b-layout.md section 9.

   Class names match the app (ll-msg, ll-pop, ll-spring, ll-glow, ll-float, ll-shake, ll-flash, ll-goal,
   bubble-pop, pulse-ring, animate-pulse) so the app can adopt this file without renaming.

   Productive (HUD chrome): press 120ms, state 150ms, message 220ms, enter 300ms, sheet 450ms.
   Expressive (rewards): pop 260ms, bubble 350ms, spring 420ms, flash 380ms, rise 700ms, float 2600ms, goal 3200ms;
   loops: glow 1400ms, ring 1600ms, online dot 2000ms.

   Reduced motion: the app's global rule (every animation and transition 0.01ms, one iteration) stays.
   It makes four effects disappear instead of calming them, so they get a calm form below that wins with
   !important at class specificity:
     ll-float, ll-goal   opacity only, no movement, same duration: the "+N" and the goal are still seen
     ll-glow             no pulse; the gold glow stays on, static
     pulse-ring          no pulse; a static 2px gold ring
   Docs specimens may force the reduced form with data-demo-motion="reduced" on any ancestor. */

/* ---------- productive */
.ll-msg { animation: ll-msg-in var(--duration-message) var(--ease-out) both; }
@keyframes ll-msg-in {
  from { opacity: 0; transform: translateY(var(--space-2)); }
  to { opacity: 1; transform: translateY(0); }
}

.ll-enter { animation: ll-enter var(--duration-enter) var(--ease-standard) both; }
@keyframes ll-enter { from { opacity: 0; } to { opacity: 1; } }

.ll-sheet-up { animation: ll-sheet-up var(--duration-sheet) var(--ease-sheet) both; }
@keyframes ll-sheet-up { from { transform: translateY(100%); } to { transform: translateY(0); } }

.ll-shake { animation: ll-shake var(--duration-shake) var(--ease-in-out) 2; }
@keyframes ll-shake {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-3px, 2px); }
  40% { transform: translate(3px, -2px); }
  60% { transform: translate(-2px, -1px); }
  80% { transform: translate(2px, 1px); }
}

/* ---------- expressive */
.ll-pop { animation: ll-pop var(--duration-pop) var(--ease-spring) both; }
@keyframes ll-pop {
  from { opacity: 0; transform: scale(0.85) translateY(var(--space-1-5)); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

.bubble-pop { transform-origin: 0 var(--space-5); animation: ll-bubble var(--duration-bubble) var(--ease-spring); }
@keyframes ll-bubble { from { transform: scale(0); } to { transform: scale(1); } }

.ll-spring { display: inline-block; animation: ll-spring var(--duration-spring) var(--ease-spring); }
@keyframes ll-spring {
  0% { transform: scale(1); }
  35% { transform: scale(1.35) rotate(-8deg); }
  70% { transform: scale(0.92) rotate(3deg); }
  100% { transform: scale(1) rotate(0); }
}

.ll-flash { animation: ll-flash var(--duration-flash) var(--ease-out) forwards; }
@keyframes ll-flash { from { opacity: 0.92; } to { opacity: 0; } }

.ll-rise { animation: ll-rise var(--duration-rise) var(--ease-rise) both; animation-delay: var(--_delay, 0ms); }
@keyframes ll-rise { from { opacity: 0; transform: translateY(var(--space-3)); } to { opacity: 1; transform: none; } }

.ll-float { animation: ll-float var(--duration-float) var(--ease-out) forwards; }
@keyframes ll-float {
  0% { opacity: 0; transform: translateY(0) scale(0.6); }
  12% { opacity: 1; transform: translateY(calc(var(--space-3) * -1)) scale(1.15); }
  100% { opacity: 0; transform: translateY(calc(var(--reward-float-distance) * -1)) scale(1); } /* 150px, the app's ll-float-up */
}

.ll-goal { animation: ll-goal var(--duration-goal) var(--ease-out) forwards; }
@keyframes ll-goal {
  0% { opacity: 0; transform: scale(0.4); }
  20% { opacity: 1; transform: scale(1.12); }
  80% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1); }
}

/* ---------- loops */
.ll-glow { animation: ll-glow var(--duration-glow) var(--ease-in-out) infinite; }
@keyframes ll-glow {
  0%, 100% { transform: scale(1); box-shadow: var(--glow-gold-rest); }
  50% { transform: scale(1.06); box-shadow: var(--glow-gold-peak); }
}

.pulse-ring { animation: ll-pulse-ring var(--duration-ring) var(--ease-out) infinite; }
@keyframes ll-pulse-ring {
  from { box-shadow: var(--pulse-ring-start); }
  to { box-shadow: var(--pulse-ring-end); }
}

/* The online dot (animate-pulse). 5d's live-stats component uses this class. */
.animate-pulse { animation: ll-breathe var(--duration-pulse) var(--ease-pulse) infinite; }
@keyframes ll-breathe { 50% { opacity: 0.5; } }

/* ---------- reduced motion: calm forms */
@keyframes ll-calm-hold {
  0% { opacity: 0; }
  10% { opacity: 1; }
  80% { opacity: 1; }
  100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ll-float, .ll-goal {
    animation-name: ll-calm-hold !important;
    animation-timing-function: linear !important;
    animation-iteration-count: 1 !important;
    animation-fill-mode: forwards !important;
    transform: none !important;
  }
  .ll-float { animation-duration: var(--duration-float) !important; }
  .ll-goal { animation-duration: var(--duration-goal) !important; }
  .ll-glow { animation: none !important; box-shadow: var(--glow-gold); }
  .pulse-ring { animation: none !important; box-shadow: 0 0 0 2px var(--gold); }
  .animate-pulse { animation: none !important; }
}
[data-demo-motion="reduced"] :is(.ll-float, .ll-goal) {
  animation-name: ll-calm-hold !important;
  animation-timing-function: linear !important;
  transform: none !important;
}
[data-demo-motion="reduced"] :is(.ll-msg, .ll-enter, .ll-sheet-up, .ll-shake, .ll-pop, .bubble-pop, .ll-spring, .ll-rise, .ll-flash) { animation: none !important; }
[data-demo-motion="reduced"] .ll-glow { animation: none !important; box-shadow: var(--glow-gold); }
[data-demo-motion="reduced"] .pulse-ring { animation: none !important; box-shadow: 0 0 0 2px var(--gold); }
[data-demo-motion="reduced"] .animate-pulse { animation: none !important; }
