/* ============================================================
   SuiteScore — Civic Editorial Design System
   Motion · keyframes + animation utilities
   Extracted 2026-05-13 from docs/mockups/blocks-civic-editorial-desktop.html

   Vocabulary (forbidden list deliberately exhaustive in README):
   ▸ page-load fade           (body opacity 0 → 1, 200ms)
   ▸ reveal-up on scroll      (IntersectionObserver opacity + 4px translate)
   ▸ tier-switch crossfade    (opacity 1 → 0.4 → 1 over 360ms)
   ▸ slider live recalc       (no animation, instant DOM update)
   ▸ hover lift on CTA        (background tint, no transform)
   FORBIDDEN: stamp lands, digit-rolls, scan-lines, sonar pings,
   parallax, scroll-jacking, auto-carousels, spring physics.
   ============================================================ */

/* ===== REVEAL UP — small translate + fade, used by IntersectionObserver ===== */
@keyframes revealUp {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ===== FADE IN — simple opacity ramp ===== */
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ============================================================
   ANIMATION UTILITY CLASSES
   ============================================================
   Pattern: pages declare elements `.reveal`; an IntersectionObserver
   adds `.in` when 6% visible (rootMargin: 0px 0px -60px 0px).
   Until then, the element is held at opacity 0 + 4px down.
   This keeps animations off-axis until users actually scroll there. */

.reveal {
  opacity: 0;
  transform: translateY(4px);
  transition:
    opacity   var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out);
}
.reveal.in {
  opacity: 1;
  transform: none;
}

/* Page-load body fade is wired in grid.css via body.ready — kept there
   because the body bg is a layout concern, not motion. */

/* ============================================================
   PRINT — reveals must never reach paper half-faded or hidden
   ============================================================ */
@media print {
  .reveal { opacity: 1 !important; transform: none !important; }
}

/* ============================================================
   REDUCED MOTION — accessibility kill-switch (global)
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
}
