.noise-bg {
    --noise-opacity: 0.15;

    background-image:
        repeating-radial-gradient(circle at 1px 1px,
        rgba(255, 255, 255, var(--noise-opacity, 0.03)) 0,
        rgba(0, 0, 0, var(--noise-opacity, 0.03)) 1px,
        transparent 2px
        );
    background-size: 3px 3px;
}

.grain {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 9999;

    background-color: #000;
    mix-blend-mode: overlay;
    opacity: 0.5;

    animation: noise 1s steps(10) infinite;
}

@keyframes noise {
    0%  { filter: hue-rotate(0deg); }
    100% { filter: hue-rotate(360deg); }
}

.noise-overlay {
    --noise-intensity: 0.03;

    view-transition-name: noise;


    position: fixed;
    inset: 0;
    z-index: 9999;
    pointer-events: none;

    mix-blend-mode: overlay;

    background-size: cover;
    background: url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='100%'>\
<filter id='noiseFilter'>\
<feTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/>\
</filter>\
<rect width='100%' height='100%' filter='url(%23noiseFilter)'/>\
</svg>") repeat, rgba(0, 0, 0, var(--noise-intensity, 0.03));
}

.noise-overlay {
    opacity: var(--noise-opacity, 0.05);
    transition: opacity 0.3s ease;
    pointer-events: none;
}

.noise-overlay.hidden {
    opacity: 0;
}
