/* ============================================
   EFFECTS.CSS — Grain, Scroll Reveals, Cursor
   Cross-cutting visual layer (Phase 2 foundation).
   ============================================ */

/* ---- Film grain overlay ----
   Inline SVG fractalNoise turbulence as data-URI background.
   Fixed, pointer-events:none, on top of everything but below modal/header.
*/
.grain {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 9999;
    opacity: var(--grain-opacity, 0.06);
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml;utf8,<svg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.9 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
    background-size: 200px 200px;
    animation: grainShift 8s steps(8) infinite;
}

@keyframes grainShift {
    0%   { transform: translate(0,   0); }
    12%  { transform: translate(-5%, -2%); }
    25%  { transform: translate(3%,  -4%); }
    37%  { transform: translate(-3%, 3%); }
    50%  { transform: translate(2%,  -5%); }
    62%  { transform: translate(-4%, 2%); }
    75%  { transform: translate(4%,  4%); }
    87%  { transform: translate(-2%, -3%); }
    100% { transform: translate(0,   0); }
}

@media (prefers-reduced-motion: reduce) {
    .grain { animation: none; }
}

/* ---- Scroll Reveal Utilities ----
   Elements start hidden, get .is-visible via IntersectionObserver in scroll.js.
   Multiple animation styles via class composition.
*/
.reveal-up,
.reveal-clip,
.reveal-scale,
.reveal-left,
.reveal-right {
    opacity: 0;
    will-change: transform, opacity;
    transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1),
                transform 0.9s cubic-bezier(0.22, 1, 0.36, 1),
                clip-path 1.1s cubic-bezier(0.22, 1, 0.36, 1);
}

.reveal-up      { transform: translateY(40px); }
.reveal-left    { transform: translateX(-40px); }
.reveal-right   { transform: translateX(40px); }
.reveal-scale   { transform: scale(0.94); }
.reveal-clip    { clip-path: inset(0 0 100% 0); }

.reveal-up.is-visible,
.reveal-left.is-visible,
.reveal-right.is-visible,
.reveal-scale.is-visible {
    opacity: 1;
    transform: none;
}

.reveal-clip.is-visible {
    opacity: 1;
    clip-path: inset(0 0 0 0);
}

/* Stagger delays — apply alongside reveal class */
.reveal--delay-1 { transition-delay: 0.1s; }
.reveal--delay-2 { transition-delay: 0.2s; }
.reveal--delay-3 { transition-delay: 0.35s; }
.reveal--delay-4 { transition-delay: 0.5s; }

@media (prefers-reduced-motion: reduce) {
    .reveal-up,
    .reveal-left,
    .reveal-right,
    .reveal-scale,
    .reveal-clip {
        opacity: 1;
        transform: none;
        clip-path: none;
        transition: none;
    }
}

/* ---- Display font utility ---- */
.font-display {
    font-family: var(--font-display);
    font-optical-sizing: auto;
}

/* ---- Custom cursor (desktop only, pointer device) ----
   16px white dot, mix-blend-mode difference for inversion over any bg.
   Hidden on touch/mobile devices.
*/
.cursor-dot {
    position: fixed;
    top: 0;
    left: 0;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    pointer-events: none;
    z-index: 10000;
    mix-blend-mode: difference;
    transform: translate(-50%, -50%);
    transition: width 0.25s ease, height 0.25s ease, opacity 0.2s ease;
    opacity: 0;
}

.cursor-dot.is-active {
    opacity: 1;
}

.cursor-dot.is-hover {
    width: 40px;
    height: 40px;
}

@media (hover: none), (pointer: coarse), (max-width: 768px) {
    .cursor-dot { display: none; }
}
