/* ============================================================
   ASTRON — ENTRADA DOS TEXTOS

   Nada anima sozinho: tudo espera a classe .is-in, que o mundo 3D
   coloca no bloco quando ele chega na distância de leitura.
   ============================================================ */

/* --- Estado de repouso ---------------------------------------
   Escrito no elemento, não no .is-in, para o texto já nascer
   escondido — sem piscar antes de a animação começar. */
[data-reveal] {
    opacity: 0;
}

[data-reveal="lines"] .wd {
    display: inline-block;
    opacity: 0;
    transform: translateY(0.6em);
    will-change: transform, opacity;
}

/* --- Headline: falha de sinal --------------------------------
   Fatias horizontais deslocadas, com franja em lime e teal, e
   três batidas antes de assentar. O passo é seco de propósito:
   glitch com transição suave vira transição, não falha.        */
@keyframes astron-glitch-in {
    0% {
        opacity: 0;
        clip-path: inset(45% 0 45% 0);
        transform: translate3d(-14px, 0, 0) skewX(6deg);
        filter: blur(9px);
        text-shadow: 10px 0 var(--lime), -10px 0 var(--teal);
    }

    10% {
        opacity: 1;
        clip-path: inset(45% 0 45% 0);
        transform: translate3d(11px, 0, 0) skewX(-4deg);
        filter: blur(7px);
        text-shadow: -9px 0 var(--lime), 9px 0 var(--teal);
    }

    22% {
        clip-path: inset(10% 0 68% 0);
        transform: translate3d(-9px, 0, 0) skewX(3deg);
        filter: blur(5px);
        text-shadow: 8px 0 var(--teal), -8px 0 var(--lime);
    }

    34% {
        clip-path: inset(72% 0 6% 0);
        transform: translate3d(8px, 0, 0);
        filter: blur(4px);
        text-shadow: -6px 0 var(--lime), 6px 0 var(--teal);
    }

    46% {
        clip-path: inset(26% 0 36% 0);
        transform: translate3d(-5px, 0, 0) skewX(-2deg);
        filter: blur(3px);
        text-shadow: 5px 0 var(--lime), -5px 0 var(--teal);
    }

    58% {
        clip-path: inset(0 0 0 0);
        transform: translate3d(4px, 0, 0);
        filter: blur(2px);
        text-shadow: -3px 0 var(--teal), 3px 0 var(--lime);
    }

    72% {
        transform: translate3d(-2px, 0, 0);
        filter: blur(1.2px);
        text-shadow: 2px 0 var(--lime), -2px 0 var(--teal);
    }

    86% {
        transform: translate3d(1px, 0, 0);
        filter: blur(0.5px);
        text-shadow: -1px 0 var(--teal), 1px 0 var(--lime);
    }

    100% {
        opacity: 1;
        clip-path: inset(0 0 0 0);
        transform: translate3d(0, 0, 0);
        filter: blur(0);
        text-shadow: none;
    }
}

@keyframes astron-sobe-in {
    from {
        opacity: 0;
        transform: translateY(0.6em)
    }

    to {
        opacity: 1;
        transform: translateY(0)
    }
}

/* A saída tem keyframes próprios, com nome diferente.
   Reaproveitar o mesmo nome e só inverter a direção não reinicia
   a animação: o navegador entende como mudança de propriedade e
   continua de onde estava. O efeito simplesmente não aparecia. */
@keyframes astron-sobe-out {
    from {
        opacity: 1;
        transform: translateY(0)
    }

    to {
        opacity: 0;
        transform: translateY(0.5em)
    }
}

@keyframes astron-glitch-out {
    0% {
        opacity: 1;
        clip-path: inset(0 0 0 0);
        filter: blur(0);
        transform: translate3d(0, 0, 0);
        text-shadow: none;
    }

    25% {
        clip-path: inset(18% 0 42% 0);
        filter: blur(2px);
        transform: translate3d(6px, 0, 0) skewX(-3deg);
        text-shadow: -5px 0 var(--lime), 5px 0 var(--teal);
    }

    55% {
        clip-path: inset(58% 0 14% 0);
        filter: blur(5px);
        transform: translate3d(-9px, 0, 0) skewX(4deg);
        text-shadow: 8px 0 var(--teal), -8px 0 var(--lime);
    }

    100% {
        opacity: 0;
        clip-path: inset(46% 0 46% 0);
        filter: blur(10px);
        transform: translate3d(13px, 0, 0) skewX(-6deg);
        text-shadow: 11px 0 var(--lime), -11px 0 var(--teal);
    }
}

/* --- Disparo -------------------------------------------------- */
.is-in [data-reveal="glitch"] {
    animation: astron-glitch-in 0.62s steps(1, end) forwards;
}

.is-in [data-reveal="lines"] {
    opacity: 1;
}

.is-in [data-reveal="lines"] .wd {
    animation: astron-sobe-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) forwards;
    /* Uma linha atrás da outra. O índice vem do reveal.js. */
    animation-delay: calc(var(--i, 0) * 110ms + 180ms);
}

/* --- Saída de quadro ------------------------------------------
   A mesma animação, ao contrário. O texto se desfaz em vez de
   apagar de uma vez — e ao voltar no scroll ele se refaz. */
.is-out [data-reveal="glitch"] {
    animation: astron-glitch-out 0.42s steps(1, end) forwards;
}

.is-out [data-reveal="lines"] {
    opacity: 1;
}

.is-out [data-reveal="lines"] .wd {
    animation: astron-sobe-out 0.36s cubic-bezier(0.4, 0, 1, 1) forwards;
    /* Ao sair, a última linha desce primeiro. */
    animation-delay: calc((var(--n, 6) - var(--i, 0)) * 55ms);
}

/* --- Movimento reduzido ---------------------------------------
   Quem pediu menos animação recebe o texto direto, sem entrada. */
@media (prefers-reduced-motion: reduce) {

    [data-reveal],
    [data-reveal="lines"] .wd {
        opacity: 1 !important;
        transform: none !important;
        clip-path: none !important;
        animation: none !important;
    }
}