/* ============================================================================
   KRUSH ORGANICS — PLATINUM PDP — MOTION
   ----------------------------------------------------------------------------
   Scroll reveals, micro-interactions, sticky support, image shimmer, platinum
   shimmer effect. Import order: tokens → typography → components → THIS FILE.

   PHILOSOPHY:
   - Motion is a quality cue, not decoration. Used sparingly.
   - Reveals trigger ONCE per element (no perpetual loops on viewport entry).
   - All animation honors prefers-reduced-motion (handled here AND in tokens.css).
   - Build phase: pair these classes with an IntersectionObserver helper that
     toggles `.is-in-view` when each `[data-reveal]` element crosses the
     trigger line. Snippet at the bottom of this file.
   ============================================================================ */


/* ============================================================================
   1. SCROLL REVEAL — base
   ----------------------------------------------------------------------------
   Default state = hidden + offset. `.is-in-view` triggers the reveal.
   Combine with stagger via inline `--delay` or `.r-stagger-N` helpers.
   ============================================================================ */

[data-reveal] {
  opacity: 0;
  transition:
    opacity var(--duration-glide) var(--ease-glide),
    transform var(--duration-glide) var(--ease-glide);
  transition-delay: var(--delay, 0ms);
  will-change: opacity, transform;
}

/* Default reveal = fade-up (most common). 24px is the sweet spot — visible
   movement without feeling sluggish. */
[data-reveal="fade-up"]      { transform: translate3d(0, 24px, 0); }
[data-reveal="fade-down"]    { transform: translate3d(0, -24px, 0); }
[data-reveal="fade-in"]      { transform: none; }
[data-reveal="fade-left"]    { transform: translate3d(-32px, 0, 0); }
[data-reveal="fade-right"]   { transform: translate3d(32px, 0, 0); }
[data-reveal="scale-in"]     { transform: scale(0.94); }
[data-reveal="reveal-mask"]  {
  /* clip-path reveal — best for headlines, hero text */
  clip-path: inset(0 100% 0 0);
  opacity: 1;
  transition: clip-path var(--duration-glide) var(--ease-glide);
}

[data-reveal].is-in-view {
  opacity: 1;
  transform: none;
}
[data-reveal="reveal-mask"].is-in-view {
  clip-path: inset(0 0 0 0);
}

/* ---------- Stagger helpers ----------
   Apply to a container; children inherit the delay step.
   Or use inline style="--delay: 120ms;" per element. */

.r-stagger > [data-reveal]:nth-child(1)  { --delay:  0ms; }
.r-stagger > [data-reveal]:nth-child(2)  { --delay:  80ms; }
.r-stagger > [data-reveal]:nth-child(3)  { --delay: 160ms; }
.r-stagger > [data-reveal]:nth-child(4)  { --delay: 240ms; }
.r-stagger > [data-reveal]:nth-child(5)  { --delay: 320ms; }
.r-stagger > [data-reveal]:nth-child(6)  { --delay: 400ms; }
.r-stagger > [data-reveal]:nth-child(7)  { --delay: 480ms; }
.r-stagger > [data-reveal]:nth-child(8)  { --delay: 560ms; }

/* Slower stagger for hero — gives the page entrance gravitas */
.r-stagger--slow > [data-reveal]:nth-child(1)  { --delay:  0ms; }
.r-stagger--slow > [data-reveal]:nth-child(2)  { --delay: 160ms; }
.r-stagger--slow > [data-reveal]:nth-child(3)  { --delay: 320ms; }
.r-stagger--slow > [data-reveal]:nth-child(4)  { --delay: 480ms; }
.r-stagger--slow > [data-reveal]:nth-child(5)  { --delay: 640ms; }


/* ============================================================================
   2. HOVER MICRO-INTERACTIONS
   ----------------------------------------------------------------------------
   Reusable hover behaviors that can be attached to any element.
   ============================================================================ */

.r-lift {
  transition: transform var(--duration-base) var(--ease-glide),
              box-shadow var(--duration-base) var(--ease-default);
}
.r-lift:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
}

.r-press {
  transition: transform var(--duration-fast) var(--ease-spring);
}
.r-press:active {
  transform: scale(0.97);
}

/* Image hover zoom — for product tiles, UGC */
.r-zoom { overflow: hidden; }
.r-zoom > img,
.r-zoom > picture {
  transition: transform var(--duration-glide) var(--ease-glide);
  will-change: transform;
}
.r-zoom:hover > img,
.r-zoom:hover > picture {
  transform: scale(1.06);
}

/* Underline-reveal — for inline text links */
.r-underline {
  position: relative;
  display: inline-block;
}
.r-underline::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 1px;
  background: currentColor;
  transform-origin: right center;
  transform: scaleX(0);
  transition: transform var(--duration-base) var(--ease-out);
}
.r-underline:hover::after {
  transform-origin: left center;
  transform: scaleX(1);
}


/* ============================================================================
   3. STICKY GALLERY SUPPORT
   ----------------------------------------------------------------------------
   For hero §2 — gallery on left, buy box on right that "sticks" past
   gallery scroll. Build with .r-sticky on the buy-box column.
   ============================================================================ */

.r-sticky {
  position: sticky;
  top: var(--sticky-top, 96px);     /* below promo bar + header */
  align-self: start;
}
@media (max-width: 1024px) {
  .r-sticky { position: static; }    /* no sticky on tablet/mobile */
}


/* ============================================================================
   4. IMAGE LOADING SHIMMER
   ----------------------------------------------------------------------------
   Apply to image wrappers OR <img>. Disappears once .is-loaded is added.
   ============================================================================ */

.r-img-skeleton {
  position: relative;
  overflow: hidden;
  background: var(--color-neutral-100);
}
.r-img-skeleton::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    transparent 0%,
    transparent 40%,
    rgba(255, 255, 255, 0.55) 50%,
    transparent 60%,
    transparent 100%
  );
  background-size: 250% 100%;
  background-position: 100% 0;
  animation: r-shimmer 1.6s linear infinite;
  pointer-events: none;
  z-index: 1;
}
.r-img-skeleton.is-loaded::before {
  animation: none;
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease-default);
}
.r-img-skeleton > img {
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease-default);
}
.r-img-skeleton.is-loaded > img { opacity: 1; }

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


/* ============================================================================
   5. PLATINUM SHIMMER
   ----------------------------------------------------------------------------
   THE premium-tier accent effect. Use SPARINGLY:
   - Once on hero (tier-3 card initial reveal)
   - On guarantee medallion (every ~8s)
   - On hover for platinum CTA (one-shot)

   Implementation: an overlaid pseudo-element sweeps a diagonal light band
   across the parent. The parent needs position: relative + overflow: hidden.
   ============================================================================ */

.r-platinum-shimmer {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.r-platinum-shimmer::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--gradient-platinum-shimmer);
  background-size: 220% 100%;
  background-position: 200% 0;
  pointer-events: none;
  z-index: 1;
  mix-blend-mode: overlay;
  opacity: 0.8;
}
/* Triggered on viewport entry once */
.r-platinum-shimmer.is-in-view::after {
  animation: r-platinum-pass var(--duration-shimmer) var(--ease-glide) 1;
}
/* Loop variant — for guarantee medallion */
.r-platinum-shimmer--loop::after {
  animation: r-platinum-pass var(--duration-shimmer) var(--ease-glide) infinite;
  animation-delay: 1.6s;
}
/* Hover one-shot */
.r-platinum-shimmer--hover:hover::after {
  animation: r-platinum-pass 1.2s var(--ease-glide) 1;
}

@keyframes r-platinum-pass {
  0%   { background-position: 200% 0; }
  100% { background-position: -100% 0; }
}


/* ============================================================================
   6. NUMERIC COUNT-UP (helper for stats — JS sets the value, this animates
   the resting state when revealed). For instant fall-back, the static number
   reads correctly without JS.
   ============================================================================ */

.r-countup {
  display: inline-block;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--duration-slow) var(--ease-glide),
              transform var(--duration-slow) var(--ease-glide);
}
.r-countup.is-in-view {
  opacity: 1;
  transform: none;
}


/* ============================================================================
   7. STICKY ADD-TO-CART SLIDE-IN — animation handled by toggling .is-visible
   on .c-sticky-cart (defined in components.css). No additional CSS needed.
   ============================================================================ */


/* ============================================================================
   8. PARALLAX HINT (subtle, performance-friendly)
   ----------------------------------------------------------------------------
   Pure-CSS parallax with translate3d on scroll-bound transforms is fragile
   without JS. Recommend wiring this via a small IntersectionObserver /
   `requestAnimationFrame` hook in the build phase. Helper class below holds
   the parallax-able element steady; JS adds inline transform.
   ============================================================================ */

.r-parallax {
  transition: transform 80ms linear;
  will-change: transform;
}


/* ============================================================================
   9. PAGE-LOAD HERO REVEAL
   ----------------------------------------------------------------------------
   Special-case the hero: reveal without waiting for an IntersectionObserver
   (it's above the fold). Just add .r-hero-reveal to the hero container; on
   DOM-ready the build script flips .is-loaded which triggers the chain.
   ============================================================================ */

.r-hero-reveal [data-reveal] {
  opacity: 0;
}
.r-hero-reveal.is-loaded [data-reveal] {
  opacity: 1;
  transform: none;
}
.r-hero-reveal.is-loaded [data-reveal="fade-up"]    { transition: opacity var(--duration-glide) var(--ease-glide), transform var(--duration-glide) var(--ease-glide); }


/* ============================================================================
   10. REDUCED MOTION SAFETY
   ----------------------------------------------------------------------------
   tokens.css already neutralizes durations globally. This block ADDS the
   "make it appear in its final state immediately" behavior, so a user with
   reduced-motion still sees a fully-revealed page.
   ============================================================================ */

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .r-img-skeleton::before { display: none; }
  .r-platinum-shimmer::after { display: none; }
  .r-countup { opacity: 1; transform: none; }
}


/* ============================================================================
   11. BUILD-PHASE JS HELPERS (copy into the page <script>)
   ----------------------------------------------------------------------------
   Provided here as a comment block so each build subagent can paste this
   verbatim. ~25 lines. Zero deps. Triggers reveals once at 12% into viewport.

   ----------- SNIPPET START -----------
   const io = new IntersectionObserver((entries) => {
     entries.forEach((e) => {
       if (e.isIntersecting) {
         e.target.classList.add('is-in-view');
         io.unobserve(e.target);
       }
     });
   }, { rootMargin: '0px 0px -12% 0px', threshold: 0.1 });

   document.querySelectorAll('[data-reveal], .r-platinum-shimmer, .r-countup')
     .forEach(el => io.observe(el));

   // Sticky-cart visibility — show once user scrolls past hero buy-box
   const buybox = document.querySelector('[data-buybox]');
   const stickyCart = document.querySelector('.c-sticky-cart');
   if (buybox && stickyCart) {
     new IntersectionObserver((entries) => {
       stickyCart.classList.toggle('is-visible', !entries[0].isIntersecting);
     }, { threshold: 0 }).observe(buybox);
   }

   // Image skeleton — flip .is-loaded on each img
   document.querySelectorAll('.r-img-skeleton > img').forEach(img => {
     if (img.complete) img.parentElement.classList.add('is-loaded');
     else img.addEventListener('load', () => img.parentElement.classList.add('is-loaded'));
   });

   // Hero — trigger once DOM is interactive
   document.querySelectorAll('.r-hero-reveal').forEach(el => {
     requestAnimationFrame(() => el.classList.add('is-loaded'));
   });
   ----------- SNIPPET END -----------
   ============================================================================ */
