/* Immersify – Effects
   The retro-arcade layer: gradient text, neon glow, RGB-split glitch, the
   section divider, the CRT scanlines and the scroll reveal. Everything that
   moves stops under prefers-reduced-motion. */

/* ── Gradient text ───────────────────────────────────────── */
.g-text {
    background:              var(--gradient-neon);
    -webkit-background-clip: text;
    background-clip:         text;
    -webkit-text-fill-color: transparent;
    color:                   var(--color-violet);   /* forced-colours / no clip support */
}

/* ── Neon glow ───────────────────────────────────────────── */
.neon {
    text-shadow: var(--glow-text);
}

/* Gradient-clipped text can't take a text-shadow – glow it with filters */
.g-text.neon {
    text-shadow: none;
    filter:      drop-shadow(0 0 10px rgb(196 94 255 / 55%)) drop-shadow(0 0 26px rgb(255 0 255 / 25%));
}

/* ── RGB-split glitch ────────────────────────────────────── */
/* Needs data-text="<the same text>". Cyan and magenta copies, hidden at
   rest, tear through clipped slices either side of the text every few
   seconds (and fast on hover). */
.glitch {
    position: relative;
    display:  inline-block;

    &::before,
    &::after {
        content:                 attr(data-text);
        position:                absolute;
        inset:                   0;
        pointer-events:          none;
        background:              none;
        -webkit-text-fill-color: currentColor;
        mix-blend-mode:          screen;
        filter:                  none;
    }

    &::before {
        color:     var(--color-cyan);
        transform: translateX(-2px);
        animation: glitch-a 4.2s steps(1) infinite;
    }

    &::after {
        color:     var(--color-magenta);
        transform: translateX(2px);
        animation: glitch-b 4.2s steps(1) infinite 0.15s;
    }

    &:hover::before,
    &:hover::after,
    a:hover > &::before,
    a:hover > &::after {
        animation-duration: 0.6s;
    }
}

@keyframes glitch-a {
    0%, 86%, 100% { clip-path: inset(0 0 0 0);    transform: translate(-2px, 0);   opacity: 0; }
    87%           { clip-path: inset(12% 0 62% 0); transform: translate(-7px, -1px); opacity: 1; }
    89%           { clip-path: inset(58% 0 18% 0); transform: translate(5px, 1px);  opacity: 1; }
    91%           { clip-path: inset(32% 0 44% 0); transform: translate(-4px, 0);   opacity: 1; }
    93%           { clip-path: inset(80% 0 4% 0);  transform: translate(3px, 0);    opacity: 1; }
}

@keyframes glitch-b {
    0%, 86%, 100% { clip-path: inset(0 0 0 0);    transform: translate(2px, 0);    opacity: 0; }
    87%           { clip-path: inset(66% 0 10% 0); transform: translate(6px, 1px);   opacity: 1; }
    89%           { clip-path: inset(8% 0 70% 0);  transform: translate(-5px, -1px); opacity: 1; }
    91%           { clip-path: inset(44% 0 30% 0); transform: translate(4px, 0);    opacity: 1; }
    93%           { clip-path: inset(2% 0 86% 0);  transform: translate(-3px, 0);   opacity: 1; }
}

/* ── Section divider ─────────────────────────────────────── */
.scan-line {
    height:        1px;
    margin-inline: var(--gutter);
    background:    var(--gradient-scan);
    opacity:       .5;
    border:        0;
}

/* ── Blinking cursor ─────────────────────────────────────── */
.blink {
    animation: blink 1.1s steps(1) infinite;
}

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

/* ── CRT ─────────────────────────────────────────────────── */
/* Fine scanlines and a vignette over the whole page. A fixed pseudo-element
   with no pointer events: it costs one composited layer and no layout. */
body::after {
    content:        '';
    position:       fixed;
    inset:          0;
    z-index:        90;
    pointer-events: none;
    background:
        repeating-linear-gradient(0deg, rgb(0 0 0 / 20%) 0 1px, transparent 1px 3px),
        radial-gradient(ellipse at center, transparent 60%, rgb(0 0 0 / 50%) 100%);
}

/* ── Scroll reveal ───────────────────────────────────────── */
/* js/utilities/reveal.js adds .is-visible as each [data-reveal] scrolls in.
   html.js is set inline in <head>, so without JS nothing is ever hidden. */
.js [data-reveal] {
    opacity:    0;
    transform:  translateY(24px);
    transition: opacity var(--transition-slow), transform var(--transition-slow);
    transition-delay: var(--reveal-delay, 0s);

    &.is-visible {
        opacity:   1;
        transform: none;
    }
}

/* ── Reduced motion ──────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
    .glitch::before,
    .glitch::after,
    .blink {
        animation: none;
    }

    .js [data-reveal] {
        opacity:    1;
        transform:  none;
        transition: none;
    }
}
