/* ═══════════════════════════════════════════════════════════════════
   ADM DEVELOPER — SCROLL ANIMATIONS & PAGE TRANSITIONS
   Scroll-reveal classes triggered by IntersectionObserver in JS.
   ═══════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════
   SCROLL REVEAL BASE
   Elements start hidden, become visible when scrolled into view.
   JS adds .is-visible class.
   ══════════════════════════════ */

.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity var(--duration-slower) var(--ease-out),
    transform var(--duration-slower) var(--ease-out);
}

.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* ── Direction variants ── */
.reveal--left {
  transform: translateX(-32px);
}

.reveal--left.is-visible {
  transform: translateX(0);
}

.reveal--right {
  transform: translateX(32px);
}

.reveal--right.is-visible {
  transform: translateX(0);
}

/* ── Scale variant ── */
.reveal--scale {
  transform: scale(0.95);
}

.reveal--scale.is-visible {
  transform: scale(1);
}

/* ── Zoom in from smaller ── */
.reveal--zoom {
  transform: scale(0.85);
  filter: blur(4px);
}

.reveal--zoom.is-visible {
  transform: scale(1);
  filter: blur(0);
}

/* ── Fade only (no movement) ── */
.reveal--fade {
  transform: none;
}

/* ── Stagger children ──
   Each child delays based on its --i index.
   JS sets --i on each child, or use CSS nth-child.
*/
.reveal-stagger > * {
  opacity: 0;
  transform: translateY(20px);
  transition:
    opacity var(--duration-slower) var(--ease-out),
    transform var(--duration-slower) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 80ms);
}

.reveal-stagger.is-visible > * {
  opacity: 1;
  transform: translateY(0);
}

/* Stagger from left */
.reveal-stagger--left > * {
  transform: translateX(-20px);
}

.reveal-stagger--left.is-visible > * {
  transform: translateX(0);
}

/* ── Faster reveal ── */
.reveal--fast {
  transition-duration: var(--duration-slow);
}

/* ── Slower reveal ── */
.reveal--slow {
  transition-duration: 800ms;
}


/* ══════════════════════════════
   PAGE TRANSITION OVERLAY
   Full-screen overlay that fades out on page load
   and fades in on navigation.
   ══════════════════════════════ */

.page-transition-overlay {
  position: fixed;
  inset: 0;
  background: var(--color-bg);
  z-index: 9999;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--duration-slow) var(--ease-out);
}

.page-transition-overlay.is-active {
  opacity: 1;
  pointer-events: all;
}

/* Initial load: overlay visible, then fades out */
.page-loading .page-transition-overlay {
  opacity: 1;
}


/* ══════════════════════════════
   UTILITY KEYFRAMES
   Reusable animations for components.
   ══════════════════════════════ */

/* Fade in + up */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Fade in + down */
@keyframes fadeInDown {
  from {
    opacity: 0;
    transform: translateY(-16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Fade in + left */
@keyframes fadeInLeft {
  from {
    opacity: 0;
    transform: translateX(-24px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* Fade in + right */
@keyframes fadeInRight {
  from {
    opacity: 0;
    transform: translateX(24px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* Scale in */
@keyframes scaleIn {
  from {
    opacity: 0;
    transform: scale(0.9);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* Float (gentle up/down) */
@keyframes float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}

/* Spin */
@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Ping (scale + fade out) */
@keyframes ping {
  75%, 100% {
    transform: scale(2);
    opacity: 0;
  }
}

/* Bounce */
@keyframes bounce {
  0%, 100% {
    transform: translateY(0);
    animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
  }
  50% {
    transform: translateY(-25%);
    animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
  }
}

/* Slide in from bottom (for modals/dropdowns) */
@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}


/* ══════════════════════════════
   ANIMATION UTILITY CLASSES
   ══════════════════════════════ */

.animate-float { animation: float 3s ease-in-out infinite; }
.animate-spin { animation: spin 1s linear infinite; }
.animate-ping { animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; }
.animate-bounce { animation: bounce 1s infinite; }

.animate-fade-in-up { animation: fadeInUp 0.5s var(--ease-out) forwards; }
.animate-fade-in-down { animation: fadeInDown 0.5s var(--ease-out) forwards; }
.animate-fade-in-left { animation: fadeInLeft 0.5s var(--ease-out) forwards; }
.animate-fade-in-right { animation: fadeInRight 0.5s var(--ease-out) forwards; }
.animate-scale-in { animation: scaleIn 0.4s var(--ease-out) forwards; }

/* Stagger delay utilities */
.delay-1 { animation-delay: 100ms; }
.delay-2 { animation-delay: 200ms; }
.delay-3 { animation-delay: 300ms; }
.delay-4 { animation-delay: 400ms; }
.delay-5 { animation-delay: 500ms; }
.delay-6 { animation-delay: 600ms; }

/* ── Heading / subheading fade-up reveal (subheadings delayed) ──
   JS (scroll-animations.js) tags headings with .adm-rvh and subheadings with .adm-rvs. */
.adm-rvh, .adm-rvs { opacity: 0; transform: translateY(12px); }
.adm-rvh { transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out); }
.adm-rvs { transition: opacity 0.6s var(--ease-out) 0.2s, transform 0.6s var(--ease-out) 0.2s; }
.adm-rvh.is-visible, .adm-rvs.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .adm-rvh, .adm-rvs { opacity: 1 !important; transform: none !important; transition: none !important; } }

/* Word-by-word heading stagger (JS splits titles into .adm-word spans with --wi index). */
.adm-rvh--split { opacity: 1 !important; transform: none !important; }
/* padding-bottom + equal negative margin gives each inline-block word room for descenders (the "g"
   in "regulated") that the tight line-height + composited (will-change) box would otherwise clip;
   the negative margin keeps line spacing unchanged. */
.adm-word { display: inline-block; padding-bottom: 0.18em; margin-bottom: -0.18em; opacity: 0; transform: translateY(0.5em); transition: opacity 0.55s var(--ease-out), transform 0.55s var(--ease-out); transition-delay: calc(0.18s + var(--wi, 0) * 0.06s); will-change: opacity, transform; }
.adm-rvh--split.is-visible .adm-word { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .adm-word { opacity: 1 !important; transform: none !important; transition: none !important; } }
