/* Additive animation utilities for scroll-triggered reveals */
.reveal {
    opacity: 0;
    transform: translate3d(0, 20px, 0) scale(0.98);
    transition-property: opacity, transform, filter;
    transition-duration: 700ms;
    transition-timing-function: cubic-bezier(0.2, 0.65, 0.2, 1);
    transition-delay: var(--reveal-delay, 0ms);
    will-change: opacity, transform;
}

.reveal.fade-up {
    transform: translate3d(0, 24px, 0);
}

.reveal.fade-in {
    transform: translate3d(0, 0, 0);
}

.reveal.fade-in:not(.in-view) {
    filter: blur(4px);
}

.reveal.zoom-in {
    transform: scale(0.96);
}

.reveal.slide-in-left {
    transform: translate3d(-24px, 0, 0);
}

.reveal.slide-in-right {
    transform: translate3d(24px, 0, 0);
}

.reveal.banner-pop {
    transform: translate3d(0, 12px, 0) scale(0.985);
}

.reveal.banner-pop.in-view {
    animation: bannerElevate 900ms cubic-bezier(0.2, 0.65, 0.2, 1) both;
}

@keyframes bannerElevate {
    0% {
        box-shadow: 0 0 0 rgba(0, 0, 0, 0);
    }

    100% {
        box-shadow: 0 10px 24px rgba(0, 0, 0, 0.12);
    }
}

.reveal.in-view {
    opacity: 1;
    transform: none;
    filter: none;
}

@media (prefers-reduced-motion: reduce) {
    .reveal {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }

    .reveal.fade-in {
        filter: none !important;
    }
}