/* ==========================================================================
   Scroll Reveal Animation System
   Reusable across all site pages — do not add page-specific styles here.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Base: blur + fade up (descriptions, body text, general content)
   -------------------------------------------------------------------------- */
[data-animate] {
    opacity: 0;
    transform: translateY(24px);
    filter: blur(6px);
    transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    filter 0.7s cubic-bezier(0.16, 1, 0.3, 1);
    will-change: opacity, transform, filter;
}

/* Slide in from left */
[data-animate="slide-left"] {
    opacity: 0;
    transform: translateX(-50px);
    filter: none;
    transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
    will-change: opacity, transform;
}

/* Slide in from right */
[data-animate="slide-right"] {
    opacity: 0;
    transform: translateX(50px);
    filter: none;
    transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
    will-change: opacity, transform;
}

/* Scale reveal — images grow into frame (IO-safe: no clip-path) */
[data-animate="rise-clip"] {
    opacity: 0;
    transform: scale(0.94);
    filter: none;
    transition: opacity 1.2s cubic-bezier(0.16, 1, 0.3, 1),
    transform 1.2s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.3s ease;
    will-change: opacity, transform;
}

[data-animate="rise-clip"].is-visible {
    opacity: 1;
    transform: scale(1);
}

/* Curtain wipe — reveal bottom-to-top */
@keyframes wipe-up {
    from {
        opacity: 1;
        clip-path: inset(100% 0 0 0);
    }
    to {
        opacity: 1;
        clip-path: inset(0 0 0 0);
    }
}

/* Curtain wipe — reveal left-to-right */
@keyframes wipe-left {
    from {
        opacity: 1;
        clip-path: inset(0 100% 0 0);
    }
    to {
        opacity: 1;
        clip-path: inset(0 0 0 0);
    }
}

/* Curtain wipe — reveal right-to-left */
@keyframes wipe-right {
    from {
        opacity: 1;
        clip-path: inset(0 0 0 100%);
    }
    to {
        opacity: 1;
        clip-path: inset(0 0 0 0);
    }
}

/* Initial state: opacity 0 (no clip-path — keeps element visible to IntersectionObserver) */
[data-animate="wipe-left"],
[data-animate="wipe-right"],
[data-animate="wipe-up"] {
    opacity: 0;
    transform: none;
    filter: none;
}

[data-animate="wipe-left"].is-visible {
    animation: wipe-left 1.1s cubic-bezier(0.16, 1, 0.3, 1) both;
}

[data-animate="wipe-right"].is-visible {
    animation: wipe-right 1.1s cubic-bezier(0.16, 1, 0.3, 1) both;
}

[data-animate="wipe-up"].is-visible {
    animation: wipe-up 1.1s cubic-bezier(0.16, 1, 0.3, 1) both;
}

/* Zoom-fade — image materialises from slight scale + blur */
[data-animate="zoom-fade"] {
    opacity: 0;
    transform: scale(1.06);
    filter: blur(6px);
    transition: opacity 1.2s cubic-bezier(0.16, 1, 0.3, 1),
    transform 1.2s cubic-bezier(0.16, 1, 0.3, 1),
    filter 1.2s cubic-bezier(0.16, 1, 0.3, 1);
    will-change: opacity, transform, filter;
}

/* Pop — logos/icons scale up from compressed */
[data-animate="pop"] {
    transform: scale(0.82);
    filter: none;
}

/* Revealed state: base reset (applies to all non-overridden variants) */
[data-animate].is-visible {
    opacity: 1;
    transform: none;
    filter: none;
}

/* --------------------------------------------------------------------------
   Word-by-word reveal
   -------------------------------------------------------------------------- */
.word-wrap {
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
}

.word-inner {
    display: inline-block;
    transform: translateY(110%);
    transition: transform 0.65s cubic-bezier(0.16, 1, 0.3, 1);
}

[data-word-reveal].is-visible .word-inner {
    transform: translateY(0);
}

/* --------------------------------------------------------------------------
   JS utility slides — use CSS `translate` property so they compose with
   `transform` without overriding transform-based positioning
   -------------------------------------------------------------------------- */
.js-slide-from-right {
    opacity: 0;
    translate: 60px 0;
    transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1),
    translate 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

.js-slide-from-right.is-visible {
    opacity: 1;
    translate: 0 0;
}

.js-slide-from-left {
    opacity: 0;
    translate: -60px 0;
    transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1),
    translate 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

.js-slide-from-left.is-visible {
    opacity: 1;
    translate: 0 0;
}

/* --------------------------------------------------------------------------
   Reduced motion — disable all scroll-reveal animations
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    [data-animate] {
        opacity: 1;
        transform: none;
        filter: none;
        transition: none;
    }

    [data-animate="rise-clip"] {
        opacity: 1;
        transform: none;
        transition: none;
    }

    [data-animate="wipe-left"],
    [data-animate="wipe-right"],
    [data-animate="wipe-up"] {
        opacity: 1;
        animation: none;
    }

    .word-inner {
        transform: none;
        transition: none;
    }

    .js-slide-from-right,
    .js-slide-from-left {
        opacity: 1;
        translate: 0 0;
        transition: none;
    }
}

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

.animate-spin {
    animation: spin 0.75s linear infinite;
    transform-origin: center;
}
