/* ============================================
   motion.css — First-draft animation polish
   ============================================
   Design principles (per Diallo):
   - Smooth, subtle, easy. Ease-out, not ease-in.
   - Nothing harsh, nothing abrupt.
   - Patient + intentional + dynamic.

   Implementation philosophy:
   - One signature reveal curve everywhere: cubic-bezier(0.22, 1, 0.36, 1).
     Slow start, fast accelerate, slow finish — the "patient drift in" feel.
   - Hover/state transitions use a faster ease-in-out.
   - All ambient (auto-running) animations respect prefers-reduced-motion.
   - Scroll-triggered reveals fire once via IntersectionObserver+unobserve.
   - Staggered children driven by inline --reveal-delay set by JS.

   Reusable pattern:
   - Any element with [data-reveal] starts hidden (opacity 0, translateY 20px)
     and animates to (opacity 1, translateY 0) when it enters the viewport.
   - Parents with [data-reveal-group] auto-stagger their children.
   - [data-reveal="left|right|fade"] for direction variants.
   ============================================ */

:root {
  --ease-reveal: cubic-bezier(0.22, 1, 0.36, 1);   /* expo-out — primary */
  --ease-state:  cubic-bezier(0.4, 0, 0.2, 1);     /* material-style — hover */
  --ease-cinema: cubic-bezier(0.65, 0, 0.35, 1);   /* slow in/out — for long ambient moves */

  --reveal-distance: 22px;       /* slightly more travel so the ease-out reads clearly */
  --reveal-duration: 1500ms;     /* slower so scroll reveals are visible mid-scroll */
  --reveal-stagger: 200ms;       /* generous stagger — siblings arrive distinctly */
}

/* ===========================================================
   Reveal-on-scroll base pattern
   Uses keyframe animation (rather than transition) for deterministic
   timing — animations are robust against rendering-pipeline pauses
   that can stall transitions.
   =========================================================== */

@keyframes reveal-up {
  from { opacity: 0; transform: translateY(var(--reveal-distance)); }
  to   { opacity: 1; transform: translateY(0);                       }
}

@keyframes reveal-left {
  from { opacity: 0; transform: translateX(calc(var(--reveal-distance) * -1)); }
  to   { opacity: 1; transform: translateX(0);                                  }
}

@keyframes reveal-right {
  from { opacity: 0; transform: translateX(var(--reveal-distance)); }
  to   { opacity: 1; transform: translateX(0);                       }
}

@keyframes reveal-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes reveal-up-large {
  from { opacity: 0; transform: translateY(calc(var(--reveal-distance) * 2)); }
  to   { opacity: 1; transform: translateY(0);                                  }
}

@keyframes reveal-scale {
  from { opacity: 0; transform: translateY(var(--reveal-distance)) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1);                          }
}

@keyframes reveal-scale-down {
  from { opacity: 0; transform: scale(1.15); }
  to   { opacity: 1; transform: scale(1);    }
}

[data-reveal] {
  opacity: 0;
}

[data-reveal].is-revealed {
  animation: reveal-up var(--reveal-duration) var(--ease-reveal) var(--reveal-delay, 0ms) forwards;
}
[data-reveal="left"].is-revealed       { animation-name: reveal-left;       }
[data-reveal="right"].is-revealed      { animation-name: reveal-right;      }
[data-reveal="fade"].is-revealed       { animation-name: reveal-fade;       }
[data-reveal="up-large"].is-revealed   { animation-name: reveal-up-large;   }
[data-reveal="scale"].is-revealed      { animation-name: reveal-scale;      }
[data-reveal="scale-down"].is-revealed { animation-name: reveal-scale-down; }

/* ===========================================================
   Hero — initial entrance on page load
   Pure CSS keyframe animation (no JS dependency). Sequence:
   lockup → title → body → CTAs → slider, each staggered.
   `forwards` keeps the end state after the animation completes.

   v2 (per Diallo): durations doubled, staggers doubled, and the
   hero slider now animates in last as the closing beat of the
   load sequence.
   =========================================================== */

@keyframes hero-rise-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0);    }
}

.home-hero__lockup,
.home-hero__title,
.home-hero__body {
  opacity: 0;
  animation: hero-rise-in 2200ms var(--ease-reveal) forwards;
}

.home-hero__lockup { animation-delay: 200ms;  }
.home-hero__title  { animation-delay: 600ms;  }
.home-hero__body   { animation-delay: 1000ms; }

/* Hero CTAs — buttons enter individually with different directions, staggered.
   Pay Dues rises from below (continues the column's downward rhythm).
   Become a Sponsor slides in from the left, slightly offset in time. */
@keyframes hero-btn-rise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0);    }
}

@keyframes hero-btn-slide-left {
  from { opacity: 0; transform: translateX(-24px); }
  to   { opacity: 1; transform: translateX(0);     }
}

.home-hero__ctas .btn-primary--bold,
.home-hero__ctas .btn-primary--sponsor {
  opacity: 0;
}

.home-hero__ctas .btn-primary--bold {
  animation: hero-btn-rise 2200ms var(--ease-reveal) forwards;
  animation-delay: 1400ms;
}

.home-hero__ctas .btn-primary--sponsor {
  animation: hero-btn-slide-left 2200ms var(--ease-reveal) forwards;
  animation-delay: 1800ms;   /* 400ms after Pay Dues — clear staggered arrival */
}

/* Hero slider — slides up into its floating position last in the sequence.
   Visible on first load (bottom half of viewport on most desktops), so we
   want it as the closing beat after the text column lands. */
@keyframes hero-slider-rise {
  from { opacity: 0; transform: translateY(60px); }
  to   { opacity: 1; transform: translateY(0);    }
}

.hero-slider-wrap {
  opacity: 0;
  animation: hero-slider-rise 2400ms var(--ease-cinema) forwards;
  animation-delay: 2300ms;  /* pulled in 500ms — arrives sooner after CTAs */
}

/* Background image — TWO simultaneous animations:
   1. Quick smooth opacity fade-in (1.2s) — the image arrives immediately
   2. Long cinematic scale-down (16s) — the zoom takes its time settling
   Both held in their end state with `forwards`. */
.home-hero__bg img {
  transform-origin: center center;
  opacity: 0;
  animation:
    hero-bg-fade-in 1200ms var(--ease-reveal) forwards,
    hero-bg-zoom-out 16000ms var(--ease-cinema) forwards;
}

/* Subtle noise texture overlay on the hero — adds tactile, print-quality
   grain over the background image. Inline SVG fractalNoise data URL, so
   no extra HTTP request. Sits above bg but below content via z-index. */
.home-hero__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  opacity: 0.10;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-repeat: repeat;
  background-size: 200px 200px;
}

@keyframes hero-bg-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes hero-bg-zoom-out {
  from { transform: scale(1.22); }
  to   { transform: scale(1.0);  }
}

/* ===========================================================
   Hero slider — ken-burns on active slide image
   Slow scale + slight pan over the slide's full dwell time so each
   slide feels like a moving photograph instead of a static frame.
   Driven by --bar-duration which JS already sets per-slide.
   =========================================================== */

.hero-slide.is-active .hero-slide__media img {
  animation: ken-burns var(--bar-duration, 5000ms) var(--ease-state) forwards;
  transform-origin: center center;
}

@keyframes ken-burns {
  from {
    transform: scale(1.0) translateX(0);
  }
  to {
    transform: scale(1.06) translateX(-1.5%);
  }
}

/* Slide content (eyebrow + title + meta + CTA) eases in from below
   each time a slide becomes active. */
.hero-slide__text,
.hero-slide__cta-col {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 1000ms var(--ease-reveal),
    transform 1000ms var(--ease-reveal);
}

.hero-slide.is-active .hero-slide__text    { opacity: 1; transform: none; transition-delay: 300ms; }
.hero-slide.is-active .hero-slide__cta-col { opacity: 1; transform: none; transition-delay: 550ms; }

/* ===========================================================
   About section — torch icon parallax + body copy reveal
   Parallax is JS-driven (translateY set inline); CSS just provides
   the transition smoothness for any jitter dampening.
   =========================================================== */

.home-about__bg-icon {
  /* No CSS transition — JS sets transform every rAF tick for parallax.
     A transition would fight the per-frame updates and cause lag. */
  transition: none;
  will-change: transform;
}

/* ===========================================================
   News card hover — gentle lift
   =========================================================== */

.news-card {
  transition:
    transform 700ms var(--ease-state),
    box-shadow 700ms var(--ease-state);
}

.news-card:hover {
  transform: translateY(-5px);
}

/* ===========================================================
   At a Glance — stat cells get a subtle scale-on-reveal feel
   =========================================================== */

.stat-cell {
  transition: transform 600ms var(--ease-state);
}

/* ===========================================================
   Mosaic — already has shadow + image scale on hover.
   No additions here.
   =========================================================== */

/* ===========================================================
   Footer — columns handled by the data-reveal pattern.
   Badge uses [data-reveal="scale-down"]; nav + NBA cols use "fade".
   Container .site-footer__inner is the data-reveal-group with stagger.

   v4: badge gets a longer landing (~4s) — the rotating seal is the
   anchor element, so it lands cleanly and slowly. Nav + NBA cols
   are extended too but stay shorter than the badge.
   =========================================================== */

.site-footer__brand.is-revealed {
  /* Override the global reveal duration just for the badge — still smooth
     but ~1s quicker on the initial appearance per Diallo's feedback. */
  animation-duration: 2800ms !important;
  animation-timing-function: var(--ease-cinema) !important;
}

.site-footer__nav-col.is-revealed,
.site-footer__nba.is-revealed {
  /* Slower than the global default — these arrive after the badge has
     mostly landed, fading in over a long, smooth window. */
  animation-duration: 2400ms !important;
}

/* ===========================================================
   Reduced-motion overrides — instant where possible, no auto-running
   ambient motion, no parallax.
   =========================================================== */

@media (prefers-reduced-motion: reduce) {
  [data-reveal],
  .home-hero__lockup,
  .home-hero__title,
  .home-hero__body,
  .home-hero__ctas .btn-primary--bold,
  .home-hero__ctas .btn-primary--sponsor,
  .hero-slider-wrap,
  .hero-slide__text,
  .hero-slide__cta-col,
  .news-card {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }

  .home-hero__bg img,
  .hero-slide.is-active .hero-slide__media img,
  .home-about__bg-icon,
  .home-about__bg-icon path {
    animation: none !important;
    transform: none !important;
  }
  /* Reduced motion: torch fills immediately, no trace */
  .home-about__bg-icon path {
    fill-opacity: 1 !important;
    stroke: none !important;
    stroke-dasharray: none !important;
    stroke-dashoffset: 0 !important;
  }
  /* Infinite spinning ring badges in footer + about pull-quote.
     Without this, the badges keep rotating perpetually even with
     reduce-motion preferred. */
  .site-footer__badge .ring,
  .about-pull-quote__badge .ring,
  .site-footer__badge svg text,
  .about-pull-quote__badge svg text {
    animation: none !important;
  }
}


/* ================================================================
   CROSS-DOCUMENT VIEW TRANSITIONS (Diallo 2026-05-31)
   ================================================================
   Subtle page-to-page transition using the native View Transitions
   API. The browser snapshots the outgoing page, the new page loads
   underneath, then we crossfade between them with a slight vertical
   nudge for a "settling in" feel. GPU-accelerated, no JS required.

   Browser support: Chrome 111+, Edge, Safari 18.2+, Firefox 142+.
   Older browsers ignore the @view-transition rule and navigate
   normally with no animation — graceful fallback, no broken pages.

   For cross-document transitions both the source AND destination
   page need this rule active. Since motion.css loads on every page,
   that's automatic.

   Tuning rationale: 280ms out / 380ms in. The new page leads the
   out — the eye settles on what's arriving slightly faster than
   what's leaving. Translate values are tiny (8px) so the motion
   reads as "polish" rather than "transition." Ease curves match
   the site's broader animation language (expo-out family).
   ================================================================ */

@view-transition {
  navigation: auto;
}

/* Old page (outgoing) — fade out + lift slightly upward */
::view-transition-old(root) {
  animation: page-transition-out 280ms cubic-bezier(0.4, 0, 0.2, 1) both;
}

/* New page (incoming) — fade in from a slight drop */
::view-transition-new(root) {
  animation: page-transition-in 380ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes page-transition-out {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-8px); }
}

@keyframes page-transition-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Respect reduced-motion preference — skip the transition entirely
   for users who've opted out of motion in their OS settings. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none !important;
  }
}
