/* ═══════════════════════════════════════════════════════════════════
   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.
   This USED to be a plain opacity:1 that only app.js could clear, and it did so on
   window.load — which waits for every image on the page. On a 25,000px page carrying
   13MB of imagery that meant an opaque, full-screen, click-blocking sheet over the
   entire site until the last image downloaded. On a phone that was most of a minute,
   and it is what "the mobile site is completely broken" looked like: a blank screen.

   It is an animation now, so the browser fades it out on its own at first paint.
   No JavaScript is involved, nothing waits for images, and the intended effect —
   the page fading up out of its background colour — is unchanged. app.js still
   clears .page-loading, which re-arms the overlay for navigation transitions. */
.page-loading .page-transition-overlay {
  animation: adm-page-reveal var(--duration-slow) var(--ease-out) forwards;
  pointer-events: none;
}

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


/* ══════════════════════════════
   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; } }


/* ══════════════════════════════
   REVEAL GATE
   The hidden state above is conditional on <html class="adm-js">, which the
   inline script in header.php sets and a watchdog removes if the reveal system
   has not started within two seconds.

   This block is the ungated state: no JavaScript, JavaScript still blocked, or
   JavaScript that failed — content is visible, unanimated, immediately. It is
   written as an override rather than by rewriting every rule above so the
   animation definitions stay in one readable place, and so that nothing is
   lost if a new reveal variant is added without remembering this file.
   ══════════════════════════════ */

html:not(.adm-js) .reveal,
html:not(.adm-js) .reveal-stagger > *,
html:not(.adm-js) .adm-rvh,
html:not(.adm-js) .adm-rvs,
html:not(.adm-js) .adm-word,
html:not(.adm-js) .magic-blur-in {
  opacity: 1 !important;
  transform: none !important;
  filter: none !important;
  transition: none !important;
}
