/* ==========================================================================
   SwimSafe — Shared Motion Layer
   --------------------------------------------------------------------------
   The single production home for reusable motion. Mirrors the design-system
   philosophy (user_config/flori/design-system/css/motion.css) into
   source_code, and generalises the patterns proven on the public landing
   page. Any End-User page reuses these primitives instead of re-deriving
   float/bob/reveal/reduced-motion per surface.

   Rules (see .claude/os/motion.md):
     - Every animation does ONE job: ORIENT, REWARD, or RESPOND.
     - Durations/easings come from tokens only (--dur-*, --ease-*, in
       swoom-theme.css). Never invent ms values or curves here.
     - Scroll reveals are FAIL-OPEN: hidden start-states live only under
       html.ss-js (set by lib/motion.js the moment it runs). Without JS
       everything is fully visible.
     - prefers-reduced-motion collapses everything to instant end-state.
     - Ambient loops are for the mascot / hero only, never dense content.

   Prefix: ss- (SwimSafe), matching the design-system + component-library
   production convention. Page-specific compositions may add their own
   namespace and drive initReveals() with a custom selector.
   ========================================================================== */

/* ============================================================ REVEALS
   Fail-open scroll-in. Values ported from the landing page (framer-motion
   parity): y:18→0 / x:∓40→0 / scale .9→1, easing --ease-out. */
html.ss-js .ss-reveal {
  --reveal-delay: 0ms;
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity var(--dur-enter) var(--ease-out) var(--reveal-delay),
    transform var(--dur-enter) var(--ease-out) var(--reveal-delay);
}
html.ss-js .ss-reveal--left  { transform: translateX(-40px); }
html.ss-js .ss-reveal--right { transform: translateX(40px); }
html.ss-js .ss-reveal--scale { transform: scale(.9); }
html.ss-js .ss-reveal.is-in  { opacity: 1; transform: none; }

/* Stagger group: parent .ss-stagger reveals its children in sequence once it
   enters. Delay steps use the --stagger token. */
html.ss-js .ss-stagger > * {
  --reveal-delay: 0ms;
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity var(--dur-enter) var(--ease-out) var(--reveal-delay),
    transform var(--dur-enter) var(--ease-out) var(--reveal-delay);
}
html.ss-js .ss-stagger.is-in > * { opacity: 1; transform: none; }
.ss-stagger > :nth-child(2) { --reveal-delay: calc(1 * var(--stagger)); }
.ss-stagger > :nth-child(3) { --reveal-delay: calc(2 * var(--stagger)); }
.ss-stagger > :nth-child(4) { --reveal-delay: calc(3 * var(--stagger)); }
.ss-stagger > :nth-child(5) { --reveal-delay: calc(4 * var(--stagger)); }
.ss-stagger > :nth-child(6) { --reveal-delay: calc(5 * var(--stagger)); }
.ss-stagger > :nth-child(7) { --reveal-delay: calc(6 * var(--stagger)); }
.ss-stagger > :nth-child(8) { --reveal-delay: calc(7 * var(--stagger)); }
.ss-stagger > :nth-child(n+9) { --reveal-delay: calc(8 * var(--stagger)); }

/* ============================================================ ONE-SHOTS
   Add (or toggle via JS) to play once; `both` keeps the end state. */
.ss-anim-fade-rise { animation: ss-fade-rise var(--dur-slow) var(--ease-out) both; }
.ss-anim-fade-in   { animation: ss-fade-in var(--dur-base) var(--ease-out) both; }
.ss-anim-scale-in  { animation: ss-scale-in var(--dur-base) var(--ease-out) both; }
.ss-anim-pop       { animation: ss-pop var(--dur-slow) var(--ease-spring) both; }

/* ============================================================ AMBIENT LOOPS
   Mascot / hero only. Never on dense content lists. */
.ss-loop-float { animation: ss-float 6s var(--ease-in-out) infinite; }
.ss-loop-float-sm { animation: ss-float-sm 3s var(--ease-in-out) infinite; }
.ss-loop-bob   { animation: ss-bob 3.4s var(--ease-in-out) infinite; }

/* ============================================================ KEYFRAMES */
/* Orient — entrances */
@keyframes ss-fade-rise  { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes ss-fade-in    { from { opacity: 0; } to { opacity: 1; } }
@keyframes ss-scale-in   { from { opacity: 0; transform: scale(.96); } to { opacity: 1; transform: scale(1); } }
@keyframes ss-rise-in    { from { transform: translateY(18px); } to { transform: none; } }

/* Reward */
@keyframes ss-pop        { 0% { transform: scale(.5); opacity: 0; } 60% { transform: scale(1.12); opacity: 1; } 100% { transform: scale(1); opacity: 1; } }
@keyframes ss-bar-grow   { from { width: 0; } }

/* Journey / progress — line draw + node pulses (path pages, waterlines) */
@keyframes ss-line-draw  { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes ss-dash-draw  { from { stroke-dashoffset: var(--dash-len, 1000); } to { stroke-dashoffset: 0; } }
@keyframes ss-bubble     { 0%, 100% { transform: scale(1); opacity: .3; } 50% { transform: scale(1.5); opacity: .6; } }
@keyframes ss-pulse-ring { 0% { transform: scale(.85); opacity: .9; } 100% { transform: scale(1.35); opacity: 0; } }

/* Respond */
@keyframes ss-ripple     { to { transform: scale(2.6); opacity: 0; } }

/* Ambient loops */
@keyframes ss-float      { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
@keyframes ss-float-sm   { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
@keyframes ss-bob        { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }

/* ============================================================ REDUCED MOTION
   Mandatory. Honour the OS setting: kill animation + transition, keep every
   end-state and all functionality. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  html.ss-js .ss-reveal,
  html.ss-js .ss-stagger > * { opacity: 1 !important; transform: none !important; }
}
