/* motion.css — reusable, GPU-friendly animation utilities.
   Animates ONLY transform + opacity. Durations 150–450ms, gentle easing.
   Pairs with src/core/motion.js (initScrollReveal adds .is-visible).
   Every effect is neutralized under prefers-reduced-motion (see block at end).
   Tokens come from styles/tokens.css. */

/* ─── Shared easing / duration knobs ─────────────────────────── */
:root {
  --motion-ease: cubic-bezier(.2,.6,.3,1);
  --motion-fast: 180ms;
  --motion-mid:  300ms;
  --motion-slow: 450ms;
  /* Per-element scroll-reveal delay hook (overridable inline or via helpers). */
  --reveal-delay: 0ms;
}

/* ─── Scroll-reveal ──────────────────────────────────────────────
   Initial state = hidden (opacity 0 + small transform). JS adds
   .is-visible when the element enters the viewport. No size/display
   changes, so no layout shift (CLS-safe). */
.reveal,
.reveal-up,
.reveal-scale {
  opacity: 0;
  transition:
    opacity var(--motion-slow) var(--motion-ease),
    transform var(--motion-slow) var(--motion-ease);
  transition-delay: var(--reveal-delay);
  will-change: transform, opacity;
}
.reveal-up   { transform: translateY(18px); }
.reveal-scale { transform: scale(.94); }
/* Plain .reveal is a pure fade (no transform). */

.reveal.is-visible,
.reveal-up.is-visible,
.reveal-scale.is-visible {
  opacity: 1;
  transform: none;
}

/* Stagger helpers — add alongside a reveal class. */
.reveal-d1 { --reveal-delay: 80ms; }
.reveal-d2 { --reveal-delay: 160ms; }
.reveal-d3 { --reveal-delay: 240ms; }

/* ─── Keyframe entrance set ───────────────────────────────────────
   Opt-in via class; runs once on mount. */
@keyframes ss-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes ss-fade-in-up {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
@keyframes ss-fade-in-scale {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: none; }
}

.animate-fade-in    { animation: ss-fade-in var(--motion-mid) var(--motion-ease) both; }
.animate-fade-in-up { animation: ss-fade-in-up var(--motion-slow) var(--motion-ease) both; }
.animate-pop        { animation: ss-fade-in-scale var(--motion-mid) var(--motion-ease) both; }

/* ─── Micro-interaction helpers ──────────────────────────────────
   Add to any button/card/tile. Transform + opacity only. */
.press {
  transition: transform var(--motion-fast) var(--motion-ease);
}
.press:active { transform: scale(.96); }

.hover-lift {
  transition: transform var(--motion-fast) var(--motion-ease);
}
.hover-lift:hover { transform: translateY(-2px); }
.hover-lift:active { transform: translateY(0); }

/* ─── Cheap ambient effects (opt-in) ─────────────────────────────
   Gentle, low-frequency loops on transform/opacity only.
   Paused under reduced-motion in the block below. */
@keyframes ss-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}
@keyframes ss-pulse-soft {
  0%, 100% { opacity: 1; }
  50%      { opacity: .72; }
}
.ambient-float { animation: ss-float 4.5s ease-in-out infinite; }
.ambient-pulse { animation: ss-pulse-soft 2.6s ease-in-out infinite; }

/* ─── Reduced-motion: neutralize ALL non-essential motion ───────── */
@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal-up,
  .reveal-scale {
    opacity: 1;
    transform: none;
    transition: none;
    will-change: auto;
  }
  .animate-fade-in,
  .animate-fade-in-up,
  .animate-pop,
  .ambient-float,
  .ambient-pulse {
    animation: none;
  }
  .press,
  .press:active,
  .hover-lift,
  .hover-lift:hover,
  .hover-lift:active {
    transition: none;
    transform: none;
  }
}
