/*
 * SmidseFX: wat het script beweegt, wordt hier zichtbaar.
 *
 * De verdeling is met opzet: het script rekent posities uit en zet variabelen,
 * de CSS beslist hoe dat eruitziet. Zo kan een thema het effect anders laten
 * vallen zonder een regel javascript aan te raken, en dat is precies wat een
 * skateshop en een speelgoedwinkel nodig hebben.
 */

/* ────────────────────────────────────────────────────────── het deeltjesdoek ── */

.fx-doek {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    /* Achter de inhoud maar voor de achtergrond. Een canvas dat boven de tekst
       hangt, vangt kliks af op elk toestel waar pointer-events niet doet wat
       het belooft. */
    mix-blend-mode: var(--fx-menging, normal);
}

/* De inhoud moet boven het doek staan. Zonder dit verdwijnt de halve pagina
   erachter, want een canvas zonder plek in de stapel wint van statische
   elementen.
   ──────────────────────────────────────────────────────────────────────────
   Maar enkel wat zelf geen plek kiest. Deze regel staat buiten elke laag en
   wint daardoor van alles wat in een @layer staat, hoe specifiek dat ook
   geschreven is. Ze heeft zo maandenlang de plakkende kop, de winkelwagenlade
   en de sluier van `position: fixed` naar `position: relative` gezet. Gevolg:
   de kop plakte niet, en de lade schoof niet onder de kop open maar helemaal
   onderaan de bladzijde — zevenduizend pixels voorbij het scherm. Wie op het
   wagentje tikte, zag niets gebeuren, en dat is precies wat er gemeld werd:
   "de winkelwagen is niet aan te klikken", op de telefoon én op de laptop.
   Wat zichzelf vastzet, blijft dus met rust. Een nieuw zwevend element krijgt
   `data-fx-vast` mee en valt er vanzelf buiten. */
.fx-aan body > *:not(.fx-doek):not([data-fx-vast]):not(.rek):not(.sluier):not(.siteKop) {
    position: relative;
    z-index: 1;
}

/* ──────────────────────────────────────────────────── diepte bij het scrollen ── */

/*
 * De achtergrond van een sectie schuift trager dan de sectie zelf. Dat is het
 * goedkoopste diepte-effect dat er is: één achtergrondpositie per frame, geen
 * enkele herschikking van de pagina.
 */

.fx-diep {
    background-position: center calc(var(--fx-diepte, 0px) * -0.25);
    background-attachment: scroll;
}

.fx-diep--sterk {
    background-position: center calc(var(--fx-diepte, 0px) * -0.55);
}

/* ─────────────────────────────────────────────────────── kaarten die kantelen ── */

/*
 * Vijf graden, niet meer. Bij tien wordt het een speeltje en kijkt niemand nog
 * naar het product; bij vijf voelt de kaart aan alsof hij reageert zonder dat
 * iemand kan zeggen waarom.
 */

.fx-aan .kaart,
.fx-aan .tegel,
.fx-aan [data-fx-kantel] {
    transform-style: preserve-3d;
    transition: transform 220ms cubic-bezier(.22, 1, .36, 1);
}

.fx-aan .fx-kantelt {
    transform:
        perspective(900px)
        rotateX(var(--fx-kantel-x, 0deg))
        rotateY(var(--fx-kantel-y, 0deg))
        translateZ(6px);
    transition-duration: 90ms;
}

/* ──────────────────────────────────────────────────────── de kop die opkomt ── */

/*
 * Een titel die woord voor woord binnenkomt. Het effect zit in het verschil in
 * vertraging; het is niet de beweging zelf die opvalt maar het ritme.
 *
 * Het script hoeft hier niets voor te doen: de woorden krijgen hun vertraging
 * uit hun volgorde, met een CSS-teller.
 */

.fx-aan .fx-kop {
    counter-reset: fxwoord;
}

.fx-aan .fx-kop > span {
    display: inline-block;
    counter-increment: fxwoord;
    animation: fx-woord-op 520ms cubic-bezier(.22, 1, .36, 1) backwards;
    animation-delay: calc(counter(fxwoord) * 60ms);
}

@keyframes fx-woord-op {
    from {
        opacity: 0;
        transform: translateY(0.4em) rotate(-1.5deg);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

/* ───────────────────────────────────────────────────────────── de gloedrand ── */

/*
 * Een lichtvlek die de muis volgt over een sectie. Geen script nodig: de
 * positie komt uit twee variabelen die de browser zelf bijhoudt bij :hover,
 * en de vlek is een verloop dat op nul dekking staat tot er iemand overheen
 * gaat.
 */

.fx-aan .fx-gloed {
    position: relative;
    isolation: isolate;
}

.fx-aan .fx-gloed::before {
    content: '';
    position: absolute;
    inset: -1px;
    z-index: -1;
    border-radius: inherit;
    background: radial-gradient(
        22rem circle at var(--fx-muis-x, 50%) var(--fx-muis-y, 50%),
        var(--accent-waas, rgb(219 152 21 / 0.22)),
        transparent 62%
    );
    opacity: 0;
    transition: opacity 260ms ease;
}

.fx-aan .fx-gloed:hover::before {
    opacity: 1;
}

/* ══════════════════════════════════════════════════════════════════════════════
 *
 * Wie minder beweging vraagt, krijgt niets. Niet minder, niets: een effect dat
 * afgezwakt doorloopt is voor wie er last van heeft even vervelend als een dat
 * op volle sterkte draait.
 */

.fx-uit .fx-doek {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .fx-doek {
        display: none;
    }

    .fx-aan .kaart,
    .fx-aan .tegel,
    .fx-aan [data-fx-kantel],
    .fx-aan .fx-kop > span,
    .fx-aan .fx-gloed::before {
        animation: none !important;
        transition: none !important;
        transform: none !important;
    }

    .fx-diep,
    .fx-diep--sterk {
        background-position: center center;
    }
}
