/* =============================================================================
   Camada glitch — fundo, sobreposição CRT e primitivas de texto corrompido

   Carregada em todas as páginas, depois de components.css. Tudo aqui é
   decoração: nada nesta folha participa de layout, e remover o <link> devolve
   o site ao visual sóbrio sem quebrar nenhuma tela.

   Duas camadas fixas envolvem a página:

     .fx        z-index 0    atrás do conteúdo — grid, brilho, chuva, raios
     .fx-over   z-index 200  na frente de tudo — scanline, grão, vinheta, flash

   Ambas são pointer-events:none. O conteúdo (main, footer) sobe para z-index 1
   e o header continua no 100, entre as duas.
   ========================================================================== */

/* =============================================================================
   1. Camada de trás
   ========================================================================== */

.fx,
.fx-over {
    position: fixed;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
    /* Camada decorativa: não há nada aqui para selecionar ou copiar. */
    user-select: none;
}

.fx {
    z-index: 0;
}

.fx-over {
    z-index: 200;
}

/* ---- Grid de circuito --------------------------------------------------- */

.fx__grid {
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(var(--grid-line) 1px, transparent 1px),
        linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
    background-size: var(--grid-size) var(--grid-size);
}

/* ---- Brilho de marca --------------------------------------------------- */

.fx__glow {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(circle at 50% 0%, rgba(255, 59, 157, .12), transparent 42%),
        radial-gradient(circle at 12% 82%, rgba(0, 255, 156, .07), transparent 38%);
}

/* ---- Chuva de código --------------------------------------------------- */

/*
   O canvas é desenhado por js/glitch.js. A opacidade fica aqui, no CSS, para
   que o token --rain-opacity possa recuar no mobile sem o JS saber disso.
*/
.fx__rain {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: var(--rain-opacity);
}

/* ---- Raios -------------------------------------------------------------- */

/*
   Três descargas com períodos que não fecham juntos (13s, 19s, 29s). Não é
   aleatório de verdade, mas como os ciclos não coincidem, a repetição não
   aparece — e sai de graça, sem timer em JavaScript.
*/
.fx__bolts {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.fx__bolt {
    fill: none;
    stroke-width: 1.4;
    stroke-linecap: round;
    stroke-linejoin: round;
    opacity: 0;
}

.fx__bolt--1 {
    stroke: var(--color-cyan);
    filter: drop-shadow(0 0 6px var(--color-cyan));
    animation: bolt-strike 13s steps(1, end) infinite;
}

.fx__bolt--2 {
    stroke: var(--color-pink);
    filter: drop-shadow(0 0 6px var(--color-pink));
    animation: bolt-strike 19s steps(1, end) 4s infinite;
}

.fx__bolt--3 {
    stroke: var(--color-matrix);
    filter: drop-shadow(0 0 5px var(--color-matrix));
    animation: bolt-strike 29s steps(1, end) 11s infinite;
}

/*
   O último keyframe é opacity 0 de propósito: com prefers-reduced-motion o
   reset zera a duração e a animação para no fim — ou seja, apagada.
*/
@keyframes bolt-strike {

    0%,
    90% {
        opacity: 0;
    }

    90.4% {
        opacity: 1;
    }

    91% {
        opacity: .12;
    }

    91.6% {
        opacity: .85;
    }

    92.4% {
        opacity: 0;
    }

    93.6% {
        opacity: .45;
    }

    94.2%,
    100% {
        opacity: 0;
    }
}

/* =============================================================================
   2. Camada da frente — CRT
   ========================================================================== */

/* ---- Scanline ----------------------------------------------------------- */

.fx-over__scan {
    position: absolute;
    inset: 0;
    background: repeating-linear-gradient(180deg,
            var(--scanline-color) 0,
            var(--scanline-color) 1px,
            transparent 1px,
            transparent var(--scanline-size));
}

/* Faixa de varredura descendo devagar — o refresh do monitor. */
.fx-over__sweep {
    position: absolute;
    left: 0;
    right: 0;
    height: 45vh;
    background: linear-gradient(180deg,
            transparent,
            rgba(0, 255, 156, .022) 45%,
            rgba(36, 225, 255, .035) 50%,
            transparent);
    animation: sweep 9s linear infinite;
}

@keyframes sweep {
    0% {
        transform: translateY(-50vh);
    }

    100% {
        transform: translateY(100vh);
    }
}

/* ---- Grão --------------------------------------------------------------- */

/*
   Ruído em SVG inline, via data URI — nada de arquivo externo, nada de CDN.
   O http://www.w3.org/2000/svg no xmlns é identificador de namespace XML, não
   endereço: o navegador nunca busca nada ali, e o site continua funcionando
   sem rede. Estático de propósito: grão animado repinta a tela inteira a cada
   frame e o ganho visual não paga a conta numa máquina do laboratório.
*/
.fx-over__grain {
    position: absolute;
    inset: 0;
    opacity: .05;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---- Vinheta ------------------------------------------------------------ */

.fx-over__vignette {
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse at 50% 50%,
            transparent 55%,
            rgba(0, 0, 0, .35) 100%);
}

/* ---- Flash do raio ------------------------------------------------------ */

/* Mesmo ritmo do primeiro raio: a tela pisca junto com a descarga. */
.fx-over__flash {
    position: absolute;
    inset: 0;
    background: rgba(36, 225, 255, .06);
    opacity: 0;
    animation: bolt-strike 13s steps(1, end) infinite;
}

/* =============================================================================
   3. Texto corrompido
   ========================================================================== */

/*
   .glitch exige data-text com o mesmo conteúdo do elemento: as duas cópias
   coloridas saem de attr(). Use só em texto de display curto — o efeito recorta
   fatias horizontais, e em parágrafo isso viraria ruído ilegível.
*/
.glitch {
    position: relative;
    display: inline-block;
}

/*
   inline-block é o padrão porque em <span> a caixa precisa abraçar o texto para
   o inset:0 das cópias cair no lugar. Em título, que é block, esse display
   tiraria o elemento do fluxo próprio e o jogaria na mesma linha do irmão
   anterior — use este modificador lá.
*/
.glitch--block {
    display: block;
}

.glitch::before,
.glitch::after {
    content: attr(data-text);
    position: absolute;
    inset: 0;
    pointer-events: none;
    /* Nas cópias a cor é chapada: é o deslocamento que precisa aparecer. */
    -webkit-text-fill-color: currentColor;
}

.glitch::before {
    color: var(--color-cyan);
    transform: translateX(-3px);
    clip-path: inset(100% 0 0 0);
    animation: glitch-slice-a var(--glitch-step) steps(1, end) infinite;
}

.glitch::after {
    color: var(--color-pink-neon);
    transform: translateX(3px);
    clip-path: inset(100% 0 0 0);
    animation: glitch-slice-b var(--glitch-step) steps(1, end) infinite;
}

/*
   As fatias aparecem em pouquíssimos frames do ciclo: o título fica limpo a
   maior parte do tempo e rasga de repente. Falha se lê como instante, não como
   animação contínua. O keyframe final esconde as cópias, para o modo de
   movimento reduzido parar no estado limpo.
*/
@keyframes glitch-slice-a {

    0%,
    82% {
        clip-path: inset(100% 0 0 0);
    }

    83% {
        clip-path: inset(14% 0 68% 0);
    }

    85% {
        clip-path: inset(62% 0 22% 0);
    }

    86% {
        clip-path: inset(38% 0 47% 0);
    }

    88%,
    100% {
        clip-path: inset(100% 0 0 0);
    }
}

@keyframes glitch-slice-b {

    0%,
    83% {
        clip-path: inset(100% 0 0 0);
    }

    84% {
        clip-path: inset(72% 0 12% 0);
    }

    86% {
        clip-path: inset(26% 0 58% 0);
    }

    87% {
        clip-path: inset(48% 0 38% 0);
    }

    89%,
    100% {
        clip-path: inset(100% 0 0 0);
    }
}

/* ---- Tremor cromático leve --------------------------------------------- */

/*
   Alternativa ao .glitch para onde attr(data-text) não serve: elemento com
   filhos coloridos, valor gerado por JS, texto que quebra em várias linhas.
   Mexe só em text-shadow e transform.
*/
.jitter {
    animation: jitter var(--glitch-step) steps(1, end) infinite;
}

@keyframes jitter {

    0%,
    88% {
        text-shadow: none;
        transform: none;
    }

    89% {
        text-shadow: var(--shadow-split);
        transform: translateX(1px);
    }

    90.5% {
        text-shadow: 2px 0 var(--color-cyan), -2px 0 var(--color-pink);
        transform: translateX(-1px);
    }

    92%,
    100% {
        text-shadow: none;
        transform: none;
    }
}

/* Mesmo tremor, sob controle do ponteiro. */
.jitter-hover:hover {
    animation: jitter-once 320ms steps(1, end) 1;
}

@keyframes jitter-once {
    0% {
        text-shadow: var(--shadow-split);
        transform: translateX(-1px);
    }

    45% {
        text-shadow: 2px 0 var(--color-cyan), -2px 0 var(--color-pink);
        transform: translateX(1px);
    }

    100% {
        text-shadow: none;
        transform: none;
    }
}

/* =============================================================================
   4. Etiquetas monoespaçadas
   ========================================================================== */

/*
   Contorno fino, mono, caixa alta, um papel de cor por variante. Usada na faixa
   de dados do hero; as demais peças que precisam desse tratamento (case tomado,
   composição completa, badge do admin) já o têm embutido no próprio componente.
*/
.tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 9px;
    font-family: var(--font-mono);
    font-size: 11px;
    line-height: 16px;
    letter-spacing: var(--tracking-mono);
    text-transform: uppercase;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--color-gray);
    white-space: nowrap;
}

.tag--pink {
    border-color: var(--border-pink-faint);
    background: var(--tint-pink);
    color: var(--color-pink);
}

.tag--matrix {
    border-color: var(--border-matrix-faint);
    background: var(--tint-matrix);
    color: var(--color-matrix);
}

/*
   Piscada de falha. Usada por quem representa erro: o case tomado por outra
   equipe, o cadeado do briefing bloqueado e a etiqueta ERR dos alertas.
*/
@keyframes bug-flicker {

    0%,
    70% {
        opacity: 1;
    }

    71% {
        opacity: .25;
    }

    72% {
        opacity: 1;
    }

    76% {
        opacity: .4;
    }

    77%,
    100% {
        opacity: 1;
    }
}

/* =============================================================================
   5. Cursor
   ========================================================================== */

/*
   Bloco piscando no fim de uma linha de prompt: a linha de boot do hero e a
   etiqueta de seção. O keyframe final deixa aceso — apagado pareceria defeito.
*/
.cursor {
    display: inline-block;
    width: .55em;
    height: 1.05em;
    margin-left: 2px;
    background: var(--color-matrix);
    vertical-align: -.16em;
    animation: cursor-blink 1.05s steps(1, end) infinite;
}

@keyframes cursor-blink {

    0%,
    49% {
        opacity: 0;
    }

    50%,
    100% {
        opacity: 1;
    }
}

/* =============================================================================
   6. Movimento reduzido
   ========================================================================== */

/*
   O reset já zera a duração de toda animação. O que sobra é o que não é
   animação: a varredura e o flash ficariam parados na tela. A chuva é
   desligada no JS, pelo mesmo media query.
*/
@media (prefers-reduced-motion: reduce) {

    .fx-over__sweep,
    .fx-over__flash,
    .fx__bolts {
        display: none;
    }

    .fx__rain {
        opacity: .06;
    }
}
