/*
 * ScrollReveal default presentation.
 *
 * index.js marks what moves (data-reveal-item) and what is visible right now
 * (data-reveal-visible); this file turns that into a fade with a short rise.
 * Nothing here matches until the script has marked an element, so content is
 * visible without JavaScript.
 *
 * Tune it with custom properties, globally on :root or per group on
 * [data-reveal="<group name>"]. The defaults below are var() fallbacks, so
 * any value a consumer sets wins without a specificity contest:
 *
 *   --reveal-duration   transition length                  800ms
 *   --reveal-easing     transition timing function         cubic-bezier(0.16, 1, 0.3, 1)
 *   --reveal-distance   how far a hidden item sits out     1rem
 *   --reveal-opacity    opacity of a hidden item           0
 *   --reveal-delay      stagger, set per item by index.js  0ms
 *
 * Scrubbed items (a group with scrub set) follow the scroll instead, tuned by
 * the distance and opacity above plus:
 *
 *   --reveal-scrub-in      scroll range of the fade in    entry 0% entry 100%
 *   --reveal-scrub-out     scroll range of the fade out   exit 0% exit 100%
 *   --reveal-scrub-easing  timing function of each fade   ease-in-out
 */

[data-reveal-item] {
    transition:
        opacity var(--reveal-duration, 800ms) var(--reveal-easing, cubic-bezier(0.16, 1, 0.3, 1)) var(--reveal-delay, 0ms),
        transform var(--reveal-duration, 800ms) var(--reveal-easing, cubic-bezier(0.16, 1, 0.3, 1)) var(--reveal-delay, 0ms);
}

/* Hidden until visible. An item holding keyboard focus always shows, so focus
   never lands on something invisible. A hidden item sits beyond the viewport
   edge it left by (data-reveal-edge): below its place at the bottom edge, so
   it rises into view, and above it at the top edge, so it settles down into
   view. Offsetting towards the edge keeps a hidden item from sliding back
   into view on its own. */
[data-reveal-item]:not([data-reveal-visible], :focus-within) {
    opacity: var(--reveal-opacity, 0);
    transform: translateY(var(--reveal-distance, 1rem));
}

[data-reveal-item][data-reveal-edge="top"]:not([data-reveal-visible], :focus-within) {
    transform: translateY(calc(-1 * var(--reveal-distance, 1rem)));
}

/* Scrubbed items (a group with scrub set) follow the scroll position instead
   of transitioning: they fade and rise in over --reveal-scrub-in and back out
   over --reveal-scrub-out, both ranges of the view timeline of the item's
   first trigger (data-reveal-timeline). By default the fade in plays while
   the trigger crosses the bottom edge and the fade out while it crosses the
   top edge. Tied to the scroll, they never lag behind it. The animations
   outrank the hidden state above, so the attributes still track visibility
   but no longer decide the look. The fade out only fills forwards, so it
   takes over from the fade in once its range begins. Without scroll-driven
   animations, scrubbed items transition like any other. */
@supports (animation-timeline: view()) and (timeline-scope: --reveal-scrub) {
    [data-reveal-item][data-reveal-scrub] {
        timeline-scope: --reveal-scrub;
        transition: none;
        animation: reveal-scrub-in both, reveal-scrub-out forwards;
        animation-timing-function: var(--reveal-scrub-easing, ease-in-out);
        animation-timeline: --reveal-scrub;
        animation-range: var(--reveal-scrub-in, entry 0% entry 100%), var(--reveal-scrub-out, exit 0% exit 100%);
    }

    [data-reveal-item][data-reveal-scrub]:focus-within {
        animation: none;
    }

    [data-reveal-timeline] {
        view-timeline: --reveal-scrub block;
    }
}

@keyframes reveal-scrub-in {
    from {
        opacity: var(--reveal-opacity, 0);
        transform: translateY(var(--reveal-distance, 1rem));
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@keyframes reveal-scrub-out {
    from {
        opacity: 1;
        transform: none;
    }

    to {
        opacity: var(--reveal-opacity, 0);
        transform: translateY(calc(-1 * var(--reveal-distance, 1rem)));
    }
}

@media print, (prefers-reduced-motion: reduce) {
    [data-reveal-item] {
        transition: none;
        animation: none;
    }

    [data-reveal-item]:not([data-reveal-visible], :focus-within),
    [data-reveal-item][data-reveal-edge="top"]:not([data-reveal-visible], :focus-within) {
        opacity: 1;
        transform: none;
    }
}
