/**
 * NovaFolio — Scroll Enhancements
 *
 * 0. Lenis smooth-scroll companion rules
 * 1. Clip-path reveal animations
 * 2. Orchestrated container stagger (via --nvf-i custom property)
 * 3. CSS scroll-driven parallax (progressive enhancement)
 *
 * @since 1.8.0
 */

/* ═══════ 0. Lenis companion rules ═══════════════════════════════ */
/* Prevent browser native scroll-behavior from conflicting with Lenis */
html.lenis,
html.lenis body {
  height: auto;
}
.lenis.lenis-smooth {
  scroll-behavior: auto;
}
.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}
.lenis.lenis-stopped {
  overflow: hidden;
}

/*
 * Kill native rubber-band / overscroll bounce at document edges.
 * Without this the OS (especially macOS Safari + trackpad inertia) keeps
 * pumping scroll deltas past the limit, which Lenis interprets as new
 * targets and produces visible rebounds when the footer comes into view.
 */
html,
body {
  overscroll-behavior-y: none;
  overscroll-behavior-x: none;
}

/*
 * CRITICAL (masonry archive): disable browser CSS scroll-anchoring on the
 * pinterest/masonry grid and its items.
 *
 * When the page uses native scroll (Lenis is disabled on the masonry archive),
 * the IntersectionObserver in nvf-scroll-enhancements.js fires
 * `animationPlayState = "running"` on each .nvf-portfolio-card as it enters
 * the viewport.  The browser's scroll-anchor mechanism detects that visual
 * change and compensates by jumping scrollY back — producing a violent rebound
 * (scrollY oscillates between e.g. 1547 and 1695 and never reaches max 1802).
 *
 * Setting `overflow-anchor: none` on those elements opts them out of the
 * anchor-candidate set so the browser no longer adjusts scroll position when
 * card animations start.
 *
 * @since 1.8.1
 */
.nvf-portfolio-grid--pinterest,
.nvf-portfolio-layout--pinterest .nvf-portfolio-item,
.nvf-portfolio-layout--pinterest .nvf-portfolio-card {
  overflow-anchor: none;
}

/*
 * CRITICAL: contain margin-collapse from page wrappers.
 *
 * On certain templates (notably the portfolio archive `/work/`), the inner
 * content has descendants whose vertical margins collapse THROUGH the
 * `#nova-page` wrapper into the body. The collapsed margin reduces the
 * effective body height that the browser uses for `documentElement.scrollTop`
 * clamping — even though `documentElement.scrollHeight` still reports the
 * un-collapsed value (~403px taller than reality on /work/). Lenis aims at
 * that "phantom" max, the browser refuses, the native scroll event makes
 * Lenis re-read the clamped value, and the user sees a violent rebound when
 * the footer comes into view.
 *
 * Forcing the page wrapper to a Block Formatting Context with
 * `display: flow-root` stops the cross-wrapper margin collapse, aligning
 * `scrollHeight` with the real scrollable max and eliminating the rebound
 * on /, /work/, /portfolio/<slug>/ and any other template with vertical
 * margins on top-level content.
 *
 * @since 1.7.5
 */
#nova-page,
#nova-outer-wrap,
#nova-wrap {
  display: flow-root;
}

/* ═══════ 1. Clip-path reveals ═══════════════════════════════════ */

[data-nvf-anim="clip-reveal"] {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

[data-nvf-anim="clip-reveal-left"] {
  clip-path: inset(0 0 0 100%);
  transition: clip-path 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

[data-nvf-anim="clip-reveal-up"] {
  clip-path: inset(100% 0 0 0);
  transition: clip-path 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

[data-nvf-anim="clip-reveal-down"] {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

[data-nvf-anim="clip-reveal-zoom"] {
  clip-path: inset(8% 8% 8% 8%);
  transition: clip-path 1s cubic-bezier(0.16, 1, 0.3, 1),
    transform 1.2s cubic-bezier(0.16, 1, 0.3, 1);
  transform: scale(1.05);
}

[data-nvf-anim="clip-reveal"].nvf-anim-visible,
[data-nvf-anim="clip-reveal-left"].nvf-anim-visible,
[data-nvf-anim="clip-reveal-up"].nvf-anim-visible,
[data-nvf-anim="clip-reveal-down"].nvf-anim-visible {
  clip-path: inset(0 0 0 0);
}

[data-nvf-anim="clip-reveal-zoom"].nvf-anim-visible {
  clip-path: inset(0 0 0 0);
  transform: scale(1);
}

/* ═══════ 2. Container stagger system ════════════════════════════ */

/*
 * Usage: add data-nvf-stagger on a container element.
 * JS sets --nvf-i on each child. CSS computes the delay.
 *
 * Also auto-applied to common grid containers via JS.
 */

[data-nvf-stagger] > [data-nvf-anim],
.nvf-stagger-group > [data-nvf-anim] {
  transition-delay: calc(var(--nvf-i, 0) * 80ms) !important;
}

[data-nvf-stagger] > [data-nvf-anim].nvf-anim-visible,
.nvf-stagger-group > [data-nvf-anim].nvf-anim-visible {
  /* Keep the delay during the entrance, clear after animation */
  transition-delay: calc(var(--nvf-i, 0) * 80ms) !important;
}

/* Slower stagger for hero-level content */
[data-nvf-stagger="slow"] > [data-nvf-anim],
.nvf-stagger-slow > [data-nvf-anim] {
  transition-delay: calc(var(--nvf-i, 0) * 120ms) !important;
}

/* Faster stagger for dense grids */
[data-nvf-stagger="fast"] > [data-nvf-anim],
.nvf-stagger-fast > [data-nvf-anim] {
  transition-delay: calc(var(--nvf-i, 0) * 50ms) !important;
}

/* ═══════ 3. Scroll-driven parallax (progressive) ═══════════════ */

@supports (animation-timeline: scroll()) {
  @keyframes nvf-parallax-up {
    from {
      transform: translateY(40px);
    }
    to {
      transform: translateY(-40px);
    }
  }

  @keyframes nvf-parallax-scale {
    from {
      transform: scale(1.08);
    }
    to {
      transform: scale(1);
    }
  }

  @keyframes nvf-parallax-fade {
    0% {
      opacity: 0.3;
    }
    30% {
      opacity: 1;
    }
    80% {
      opacity: 1;
    }
    100% {
      opacity: 0.3;
    }
  }

  .nvf-scroll-parallax {
    animation: nvf-parallax-up linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }

  .nvf-scroll-scale {
    animation: nvf-parallax-scale linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 60%;
  }

  .nvf-scroll-fade {
    animation: nvf-parallax-fade linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }

  /* Auto-apply subtle parallax to portfolio card images */
  .nvf-core-card--portfolio .nvf-core-card__media img {
    animation: nvf-parallax-scale linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 70%;
  }

  /* Hero images get full parallax */
  .nvf-hero__bg img,
  .nvf-hero__media img {
    animation: nvf-parallax-up linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }
}

/* ═══════ 4. Scroll-linked clip-path reveals ═════════════════════ */
/* Driven proportionally by scroll position via nvf-clip-scroll.js */

[data-nvf-anim="clip-scroll"] {
  clip-path: inset(0 100% 0 0);
  will-change: clip-path;
}

[data-nvf-anim="clip-scroll-left"] {
  clip-path: inset(0 0 0 100%);
  will-change: clip-path;
}

[data-nvf-anim="clip-scroll-up"] {
  clip-path: inset(100% 0 0 0);
  will-change: clip-path;
}

[data-nvf-anim="clip-scroll-down"] {
  clip-path: inset(0 0 100% 0);
  will-change: clip-path;
}

[data-nvf-anim="clip-scroll-circle"] {
  clip-path: circle(0% at 50% 50%);
  will-change: clip-path;
}

/* ═══════ 5. Horizontal scroll on vertical scroll ════════════════ */
/* Section pinned while inner track scrolls horizontally.
   JS sets wrapper height and animates track translateX.            */

.nvf-hscroll-section {
  position: relative;
  overflow: hidden;
}

.nvf-hscroll-section__sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  align-items: center;
}

.nvf-hscroll-section__track {
  display: flex;
  gap: clamp(16px, 3vw, 48px);
  will-change: transform;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.nvf-hscroll-section__panel {
  flex: 0 0 auto;
  width: 80vw;
  max-width: 900px;
}

.nvf-hscroll-section__panel img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: var(--nvf-radius-m, 8px);
}

/* Mobile: disable horizontal scroll trick, become normal scroll */
@media (max-width: 768px) {
  .nvf-hscroll-section {
    height: auto !important;
  }
  .nvf-hscroll-section__sticky {
    position: static;
    height: auto;
  }
  .nvf-hscroll-section__track {
    flex-direction: column;
    transform: none !important;
  }
  .nvf-hscroll-section__panel {
    width: 100%;
    max-width: none;
  }
}

/* ═══════ 6. WebGL distort container ═════════════════════════════ */

.nvf-webgl-distort {
  position: relative;
  overflow: hidden;
}

.nvf-webgl-distort canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

/* ═══════ 7. Reduced motion ══════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  [data-nvf-anim="clip-reveal"],
  [data-nvf-anim="clip-reveal-left"],
  [data-nvf-anim="clip-reveal-up"],
  [data-nvf-anim="clip-reveal-down"],
  [data-nvf-anim="clip-reveal-zoom"] {
    clip-path: none !important;
    transform: none !important;
    transition: none !important;
  }

  [data-nvf-anim="clip-scroll"],
  [data-nvf-anim="clip-scroll-left"],
  [data-nvf-anim="clip-scroll-up"],
  [data-nvf-anim="clip-scroll-down"],
  [data-nvf-anim="clip-scroll-circle"] {
    clip-path: none !important;
    will-change: auto;
  }

  .nvf-hscroll-section__track {
    transform: none !important;
  }

  .nvf-scroll-parallax,
  .nvf-scroll-scale,
  .nvf-scroll-fade,
  .nvf-core-card--portfolio .nvf-core-card__media img,
  .nvf-hero__bg img,
  .nvf-hero__media img {
    animation: none !important;
  }
}
