/* motion.css — Scroll-reveal helpers and shared keyframes. Every page, after page styles. */

/* ---------- Shared keyframes ---------- */
@keyframes ping {
    0% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.5); }
    80%, 100% { box-shadow: 0 0 0 9px rgba(34, 197, 94, 0); }
}

@keyframes blink {
    50% { opacity: 0; }
}

/* ---------- Reveal & animation helpers ---------- */
.js .reveal,
.js [data-stagger] > * {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
    transition-delay: var(--d, 0ms);
}

.js .reveal.is-visible,
.js [data-stagger].is-visible > * {
    opacity: 1;
    transform: none;
}

.js .hero-text > * {
    animation: rise 0.8s var(--ease) both;
}

.js .hero-text > *:nth-child(1) { animation-delay: 0.05s; }
.js .hero-text > *:nth-child(2) { animation-delay: 0.15s; }
.js .hero-text > *:nth-child(3) { animation-delay: 0.25s; }
.js .hero-text > *:nth-child(4) { animation-delay: 0.35s; }
.js .hero-text > *:nth-child(5) { animation-delay: 0.45s; }
.js .hero-text > *:nth-child(6) { animation-delay: 0.55s; }

.js .hero-code {
    animation: rise 1s var(--ease) 0.3s both;
}

@keyframes rise {
    from { opacity: 0; transform: translateY(22px); }
    to { opacity: 1; transform: none; }
}

/* assets/js/main.js strips the reveal hooks once the entrance finishes,
   so card hover transitions fall back to their own rules */
