/* ==========================================================================
   Suite Home Renovations — animations.css
   Scroll-animation from-states, will-change hints, CSS keyframes, and a
   global prefers-reduced-motion override.

   How the system works (see js/animations.js):
   • An inline <head> script adds `.js-anim` to <html> before first paint
     (only when motion is allowed). The from-states below are scoped to
     `.js-anim`, so users without JS — and search-engine crawlers — always
     see fully visible content.
   • GSAP animates each [data-anim] element to its natural state and LEAVES
     the end styles inline (opacity:1; transform:none), which override these
     from-states. JS only clears `will-change` afterward.
   • A failsafe in the head script removes `.js-anim` if GSAP never loads
     (CDN failure) — revealing everything.
   ========================================================================== */

/* --------------------------------------------------------------------------
   FROM-STATES (only while motion is allowed and JS is present)
   -------------------------------------------------------------------------- */
.js-anim [data-anim="reveal"],
.js-anim [data-anim="heading"] {
  opacity: 0;
  transform: translateY(24px);
  will-change: transform, opacity;
}

.js-anim [data-anim="fade"] {
  opacity: 0;
  will-change: opacity;
}

.js-anim [data-anim="zoom"] {
  opacity: 0;
  transform: scale(1.04);
  will-change: transform, opacity;
}

/* Staggered groups: children start hidden, parent stays in flow (no CLS) */
.js-anim [data-anim="stagger"] > * {
  opacity: 0;
  transform: translateY(28px);
  will-change: transform, opacity;
}

/* Parallax layers translate during scroll — never affect layout */
.js-anim [data-parallax] { will-change: transform; }

/* Hero entrance group */
.js-anim [data-anim="hero"] > * {
  opacity: 0;
  transform: translateY(26px);
  will-change: transform, opacity;
}

/* --------------------------------------------------------------------------
   CSS KEYFRAME ANIMATIONS (independent of GSAP)
   -------------------------------------------------------------------------- */
@keyframes shr-bob {
  0%, 100% { transform: translateY(0); opacity: .9; }
  50%      { transform: translateY(6px); opacity: .4; }
}
.hero__scroll-cue .dot { animation: shr-bob 2.4s var(--ease-in-out) infinite; }

@keyframes shr-shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

/* Skeleton shimmer for any lazy media still loading (optional usage) */
.is-loading {
  background: linear-gradient(100deg, rgba(255,255,255,.04) 30%, rgba(255,255,255,.09) 50%, rgba(255,255,255,.04) 70%);
  background-size: 200% 100%;
  animation: shr-shimmer 1.4s linear infinite;
}

/* --------------------------------------------------------------------------
   REDUCED MOTION — neutralise everything
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  /* Ensure any from-state is fully visible and untransformed */
  .js-anim [data-anim],
  .js-anim [data-anim="stagger"] > *,
  .js-anim [data-anim="hero"] > * {
    opacity: 1 !important;
    transform: none !important;
    will-change: auto !important;
  }
  .hero__scroll-cue,
  .scroll-hero__cue { display: none; }
  /* scroll-hero: no scrubbing under reduced motion — js paints the final
     "after" frame once; reveal it instantly (transition already neutralised). */
  .scroll-hero[data-shf-ready="true"] .scroll-hero__canvas { opacity: 1 !important; }
}
