/* ============================================================
   DRIP CLIENT — Animation System (Premium Motion Layer)
   ------------------------------------------------------------
   Purely additive on top of style.css — nothing here overrides
   existing colors/layout, only motion. Loaded AFTER style.css so
   these rules win on equal specificity where they intentionally
   extend an existing selector (e.g. .modal.closing).

   What already existed in style.css before this file (kept as-is,
   not duplicated here): entrance keyframes for modals/drawers/toast
   (fadeIn, modalPop, drawerSlideIn, toastSlideIn/Out), product-card
   hover, button hover/active states, hero ambient motion, skeleton
   shimmer keyframe. This file fills the remaining gaps:

     1) Exit/close animations for modals & drawers (previously
        instant `display:none`, now fade+scale / slide out).
     2) A generic IntersectionObserver-driven scroll-reveal system
        (.reveal / .reveal.in-view), wired up by assets/js/motion.js.
     3) A cart-badge "bump" pulse on count change.
     4) A single, comprehensive prefers-reduced-motion override —
        the old codebase only had one scoped instance of this query.
   ============================================================ */

/* ── 1. Exit animations (paired with assets/js/motion.js's
   window.animatedHide helper, and used by closeModal/toggleMobileDrawer/
   toggleNotifPanel) ─────────────────────────────────────────── */
@keyframes modalFadeOut{from{opacity:1}to{opacity:0}}
@keyframes modalPopOut{from{opacity:1;transform:scale(1) translateY(0);}to{opacity:0;transform:scale(.94) translateY(8px);}}
@keyframes drawerSlideOut{from{transform:translateY(0);opacity:1;}to{transform:translateY(-14px);opacity:0;}}

.modal.closing{animation:modalFadeOut var(--dur-fast) ease forwards;}
.modal.closing .modal-card{animation:modalPopOut var(--dur-fast) var(--ease-spring) forwards;}
.mobile-drawer.closing{animation:drawerSlideOut var(--dur-fast) var(--ease-spring) forwards;}
.drawer-overlay.closing{animation:modalFadeOut var(--dur-fast) ease forwards;}
.notif-panel.closing{animation:drawerSlideOut var(--dur-fast) var(--ease-spring) forwards;}
#notifOverlay.closing{animation:modalFadeOut var(--dur-fast) ease forwards;}

/* ── 2. Scroll reveal ─────────────────────────────────────────
   Applied by assets/js/motion.js via a single shared
   IntersectionObserver. Elements start subtly faded+offset and
   settle into place once ~15% visible; the class is added once
   and never removed, so re-scrolling past a section never
   re-triggers it (avoids "excessive"/repeated animation). Only
   transform + opacity are animated — no layout properties. */
.reveal{opacity:0;transform:translateY(20px);transition:opacity var(--dur-slow) var(--ease-spring),transform var(--dur-slow) var(--ease-spring);will-change:opacity,transform;}
.reveal.in-view{opacity:1;transform:translateY(0);}
/* Staggered children within a revealed grid/list — capped delay so a
   long list never makes the tail wait too long to appear. */
.reveal[data-stagger="1"]{transition-delay:60ms;}
.reveal[data-stagger="2"]{transition-delay:120ms;}
.reveal[data-stagger="3"]{transition-delay:180ms;}
.reveal[data-stagger="4"]{transition-delay:240ms;}
.reveal[data-stagger="5"]{transition-delay:300ms;}
.reveal[data-stagger="6"]{transition-delay:360ms;}

/* ── 3. Cart badge bump ───────────────────────────────────────
   Triggered by app.js's updateCartBadgeUI() adding/removing this
   class when the count increases. GPU-cheap (transform only). */
@keyframes cartBadgeBump{0%{transform:scale(1);}35%{transform:scale(1.35);}100%{transform:scale(1);}}
.cart-badge.bump{animation:cartBadgeBump 360ms var(--ease-spring);}

/* ── 4. Generic press feedback fallback ───────────────────────
   Low-specificity safety net for any interactive element that
   doesn't already define its own :active transform in style.css
   (existing more-specific rules — .hero-cta-primary:active etc. —
   continue to win the cascade, this only fills gaps). */
button:not(.no-tap):active,
.btn-sm:not(.no-tap):active,
a.notif-btn:not(.no-tap):active{transform:scale(.96);}

/* ── 6. Keyboard focus visibility ─────────────────────────────
   Buttons and links had no visible focus indicator anywhere on the
   site — fine for mouse/touch use, but a real gap for keyboard-only
   navigation (nothing showed which control was focused while
   tabbing). Uses :focus-visible specifically (not :focus) so this
   only appears for keyboard/assistive-tech navigation, never on a
   mouse/touch click — no visual change for the vast majority of
   users, purely additive for accessibility. Inputs already have
   their own :focus-within treatment above and are unaffected. */
button:focus-visible,
a:focus-visible,
.btn-sm:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible{
  outline:2px solid #ff2da8;
  outline-offset:2px;
  border-radius:4px;
}

/* ── 5. Ambient background system ─────────────────────────────
   Fixed, full-viewport decorative layer sitting behind #app content
   (see .ambient-bg placement in includes/header.php, right before
   <main>). Layers: slow-drifting blurred purple/pink glow "orbs", a
   glowing upper-right moon, and falling cherry-blossom petals
   (generated by assets/js/ambient-bg.js — see that file for the
   randomization/count logic). Everything here only animates
   transform + opacity (GPU-cheap) and the whole wrapper is
   `pointer-events:none` so it can never intercept taps/clicks/scroll
   on real content. */
/* z-index:-1 (not 0) is deliberate: .main-wrap and most page content
   are non-positioned static blocks, which paint ABOVE a positioned
   z-index:0 sibling regardless of DOM order per the CSS stacking
   spec. A negative z-index guarantees this layer stays behind every
   normal-flow element on the page, not just ones with their own
   z-index. */
.ambient-bg{position:fixed;inset:0;z-index:-1;overflow:hidden;pointer-events:none;}
.ambient-bg .ambient-orb{position:absolute;border-radius:50%;filter:blur(60px);opacity:.4;will-change:transform;}
.ambient-bg .ambient-orb.purple{width:520px;height:520px;left:-140px;top:-80px;background:radial-gradient(circle,rgba(157,61,240,.55),transparent 70%);animation:ambientDriftA 22s ease-in-out infinite;}
.ambient-bg .ambient-orb.pink{width:460px;height:460px;right:-160px;top:35%;background:radial-gradient(circle,rgba(255,45,168,.45),transparent 70%);animation:ambientDriftB 26s ease-in-out infinite;}
.ambient-bg .ambient-orb.pink-2{width:380px;height:380px;left:8%;bottom:-140px;background:radial-gradient(circle,rgba(255,45,168,.3),transparent 70%);animation:ambientDriftA 30s ease-in-out infinite reverse;}
@keyframes ambientDriftA{0%,100%{transform:translate3d(0,0,0);}50%{transform:translate3d(40px,30px,0);}}
@keyframes ambientDriftB{0%,100%{transform:translate3d(0,0,0);}50%{transform:translate3d(-35px,-25px,0);}}

/* Premium moon — upper-right, responsive size (75–110px mobile,
   110–150px desktop via clamp), soft white/lavender disc with a
   layered atmospheric halo (box-shadow, not just blur) so it reads
   as a glowing sphere rather than a flat circle or a blurry blob.
   Positioned with %-based right/top so it never drifts off-screen
   or over the header on any viewport.
   The halo (box-shadow blur+spread) is intentionally kept tight —
   an earlier version spread up to ~220px past the disc's edge, which
   was barely noticeable on content-dense pages (product grid) but
   washed out a large part of the screen on sparse pages like
   login.php/register.php, reading as the site being "covered".
   Keeping the total halo under ~60px avoids that on any page. */
.ambient-bg .ambient-orb.moon{
  width:clamp(75px,20vw,150px);height:clamp(75px,20vw,150px);
  right:6%;top:4%;
  border-radius:50%;
  background:radial-gradient(circle at 34% 30%,#fff,rgba(232,228,255,.92) 30%,rgba(200,182,255,.55) 58%,rgba(180,150,255,.15) 78%,transparent 88%);
  box-shadow:0 0 22px 4px rgba(232,228,255,.28),0 0 46px 14px rgba(157,61,240,.12);
  filter:none;opacity:.85;
  animation:ambientMoonPulse 9s ease-in-out infinite;
}
@keyframes ambientMoonPulse{0%,100%{transform:scale(1);opacity:.8;}50%{transform:scale(1.03);opacity:.9;}}

/* Falling cherry-blossom petals — generated dynamically by
   assets/js/ambient-bg.js (count, position, size, timing, drift and
   opacity all randomized per petal, per pageload; 20–30 on desktop,
   10–18 on mobile, none if the OS asks for reduced motion). CSS only
   defines the *shape variants* and the shared fall animation; JS
   supplies everything else through inline custom properties
   (--size/--drift/--op/--dur/--delay/--left set on each element) so
   no two petals move identically. Movement uses translate3d + rotate
   + opacity only (GPU-cheap, no layout thrashing). */
.ambient-particles{position:absolute;inset:0;}
.ambient-particles .particle{
  position:absolute;top:-8%;left:var(--left,0%);
  width:var(--size,10px);height:calc(var(--size,10px) * 1.3);
  opacity:0;will-change:transform,opacity;
  animation-name:petalFall;animation-timing-function:ease-in-out;animation-iteration-count:infinite;
  animation-duration:var(--dur,16s);animation-delay:var(--delay,0s);
}
/* Four subtly different petal "species" — two pink tones, one
   white-pink, one soft translucent blur — so the flurry doesn't read
   as one shape copy-pasted across the screen. */
.ambient-particles .particle.petal-a{background:linear-gradient(150deg,#ffc2e6,#ff8fc9);border-radius:50% 50% 50% 4%;box-shadow:0 0 5px rgba(255,150,210,.5);}
.ambient-particles .particle.petal-b{background:linear-gradient(150deg,#ffd9ee,#ffb3dd);border-radius:4% 50% 50% 50%;box-shadow:0 0 5px rgba(255,180,225,.45);}
.ambient-particles .particle.petal-c{background:linear-gradient(150deg,#fff,#ffe3f2);border-radius:50%;box-shadow:0 0 6px rgba(255,255,255,.6);}
.ambient-particles .particle.petal-d{background:linear-gradient(150deg,#f5c8ff,#e79bef);border-radius:50% 4% 50% 50%;box-shadow:0 0 5px rgba(230,160,240,.4);}
/* Gentle S-curve wind drift (left→right→left) instead of a single
   straight diagonal fall, plus continuous rotation for a natural,
   tumbling look. --drift is a signed px value supplied per petal. */
@keyframes petalFall{
  0%{opacity:0;transform:translate3d(0,-4vh,0) rotate(0deg);}
  10%{opacity:var(--op,.7);}
  25%{transform:translate3d(calc(var(--drift,40px) * .6),20vh,0) rotate(70deg);}
  50%{transform:translate3d(calc(var(--drift,40px) * -.5),48vh,0) rotate(150deg);}
  75%{transform:translate3d(calc(var(--drift,40px) * .55),76vh,0) rotate(230deg);}
  90%{opacity:var(--op,.7);}
  100%{opacity:0;transform:translate3d(0,112vh,0) rotate(320deg);}
}
/* Reduced motion: freeze the drifting/pulsing orbs; the moon stays
   visible but static. Petals are removed by assets/js/ambient-bg.js
   (it checks the same media query before generating any), and this
   rule is a CSS-only backstop in case JS hasn't run yet. */
@media (prefers-reduced-motion: reduce){
  .ambient-bg .ambient-orb{animation:none !important;}
  .ambient-particles{display:none;}
}

/* Light theme: existing dark-purple ambient system is tuned for the
   dark background; on the (rare) light theme it's dimmed so it never
   competes with text/card readability rather than being redesigned. */
body.theme-light .ambient-bg{opacity:.35;}

/* ── 7. Reduced motion — comprehensive, site-wide ─────────────
   The pre-existing codebase only silenced one specific marquee
   (.bs-track). This is the full standard override: every
   animation and transition anywhere on the site (including all
   the ones already defined in style.css) collapses to effectively
   instant, and smooth-scroll is disabled, for anyone whose OS/
   browser requests reduced motion. Core functionality is
   completely unaffected — only the motion itself is removed. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  .reveal{opacity:1 !important;transform:none !important;}
}
