/* ── Scroll-triggered component animations ───────────────────────────────────
   Elements receive [data-anim] from animations.js once the observer is ready.
   .cs-in-view is added by the IntersectionObserver when the element enters
   the viewport. Using data attributes keeps the initial hidden state out of
   CSS until JS confirms it is running, so content is never invisible without JS.
   ─────────────────────────────────────────────────────────────────────────── */

[data-anim] {
    opacity: 0;
    transition:
        opacity   0.7s cubic-bezier(0.22, 1, 0.36, 1),
        transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
    transition-delay: var(--anim-delay, 0ms);
    will-change: opacity, transform;
}

[data-anim="up"]    { transform: translateY(20px); }
[data-anim="scale"] { transform: scale(0.93); }

[data-anim].cs-in-view {
    opacity: 1;
    transform: none;
}

/* ── Component-specific overrides ────────────────────────────────────────── */

/* Hero: longer, more dramatic reveal befitting the top-of-page position */
.page-hero-content [data-anim] {
    transition-duration: 0.9s;
}

/* Page intro: heading gets a slightly longer, more dramatic reveal */
.component-page-intro [data-anim] {
    transition-duration: 0.85s;
}

/* Gallery items: snappy scale-in with stagger */
.gallery-item[data-anim] {
    transition-duration: 0.5s;
}

/* Quote: staggered children fade up */
.quote [data-anim] {
    transition-duration: 0.65s;
}

/* Alert: standard speed */
.cs-alert[data-anim] {
    transition-duration: 0.6s;
}

/* Respect the user's OS-level motion preference */
@media (prefers-reduced-motion: reduce) {
    [data-anim] {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }
}
