/* ============================================================================
   text-type.css — títulos de hero escritos à máquina
   ============================================================================

   Porta a mecânica do TextType do reactbits.dev para o site, que é Blade +
   Livewire e não React. Substitui o antigo split-flap (painel de aeroporto),
   que foi removido — havia um efeito de título, e passou a ser este.

   O QUE MUDA EM RELAÇÃO AO ORIGINAL, E PORQUÊ

   O componente original guarda o texto em estado e vai concatenando caracteres
   («displayedText»), ou seja o <h1> CRESCE letra a letra. Num título de hero de
   80px com 56 a 75 caracteres isso empurra tudo o que vem abaixo — lede, botões,
   a página inteira — durante os dois segundos da animação, e a quebra de linha
   muda a cada palavra que entra.

   Aqui o texto está TODO no sítio desde o primeiro frame; o que muda é a
   `visibility` de cada carácter. A caixa do título é a caixa final logo à
   partida: zero layout shift, e a quebra de linha é a definitiva desde o
   princípio. É também o que mantém o <h1> legível para quem não tem JS — o
   texto verdadeiro é o que o servidor mandou, não algo que o cliente monta.

   ESTRUTURA que o JS monta (ver public/js/text-type.js):

       <h1 data-text-type aria-label="O texto todo" data-tt-done>
         <span class="tt-c is-on">O</span><span class="tt-c is-on">l</span>…
         (os espaços ficam como nós de texto soltos)
         <span class="tt-c">a</span>            ← ainda por escrever
       </h1>

   Ao contrário do split-flap, os caracteres NÃO são inline-block e não há
   envelope por palavra: `visibility` não tira o carácter do fluxo, por isso a
   quebra de linha continua a ser a nativa do browser e não precisa de ajuda.
   ========================================================================= */

/* ---------------------------------------------------------------------------
   O flash que esta regra evita

   O script vive no fim do <body> e sem `defer` — mas em ligações lentas o
   browser chega a pintar antes de ele correr. Sem isto via-se o título INTEIRO
   e só depois ele desaparecia para começar a ser escrito, que é pior do que
   não ter efeito nenhum.

   A marca `data-tt` é posta no <html> por um script inline no <head> (ver
   components/layouts/site.blade.php), portanto antes de qualquer pintura. Sem
   JS a marca nunca é posta e o título é servido normal; se o script do efeito
   não chegar a correr, uma rede de segurança no mesmo bloco levanta a marca.
   --------------------------------------------------------------------------- */
html[data-tt] [data-text-type] {
    visibility: hidden;
}

/* Escrito o título, o <h1> volta ao estado normal. Não é cosmética: as camadas
   do glitch da home são `::before`/`::after` do próprio <h1> com
   `content: attr(data-text)` — o título INTEIRO. Enquanto o <h1> está oculto
   elas ficam ocultas com ele (é o que impede que se leia, em bandas, o texto
   que ainda não foi escrito); no fim têm de voltar. */
html[data-tt] [data-text-type][data-tt-done] {
    visibility: visible;
}

/* Cada carácter governa-se a si próprio. Uma regra directa no filho ganha à
   `visibility` herdada do <h1>, por isso isto funciona quer o pai esteja
   oculto (durante a escrita) quer visível (depois). */
[data-text-type] .tt-c {
    visibility: hidden;
}

[data-text-type] .tt-c.is-on {
    visibility: visible;
}

/* ---------------------------------------------------------------------------
   O cursor

   Desenhado como `::after` do carácter onde a escrita vai — e ABSOLUTO, de
   propósito. Um cursor no fluxo teria largura, e essa largura entraria e sairia
   do meio da frase a cada letra, empurrando o resto do título e podendo mudar a
   quebra de linha a meio da animação. Absoluto não ocupa espaço nenhum.
   --------------------------------------------------------------------------- */
[data-text-type] .tt-c.is-caret {
    position: relative;
}

[data-text-type] .tt-c.is-caret::after {
    content: '|';
    position: absolute;
    top: 0;
    left: 100%;
    margin-left: .08em;
    /* Em em, não em rem: o mesmo efeito serve um <h1> de 80px na home e um de
       36px em mobile, e o cursor tem de acompanhar o corpo de letra. */
    font-weight: 400;
    visibility: visible;
    opacity: .85;
    pointer-events: none;
}

/* Pisca só DEPOIS de o título estar escrito. Durante a escrita o cursor já se
   está a mexer — salta de letra em letra a cada ~30ms — e pô-lo a piscar ao
   mesmo tempo lê-se como ruído. É também o comportamento de um terminal a
   sério: sólido enquanto se escreve, a piscar quando pára. */
[data-text-type][data-tt-done] .tt-c.is-caret::after {
    animation: tt-caret-blink 1.06s ease-in-out infinite;
}

@keyframes tt-caret-blink {
    0%, 100% { opacity: .85; }
    50%      { opacity: 0; }
}

/* Quem pediu menos movimento recebe o título já escrito (o JS verifica a mesma
   media query e não anima nada) e um cursor quieto — um cursor a piscar para
   sempre é exactamente o tipo de movimento repetido que esta preferência pede
   para desligar. */
@media (prefers-reduced-motion: reduce) {
    [data-text-type][data-tt-done] .tt-c.is-caret::after {
        animation: none;
    }
}
