/* Shift the existing texture in small steps, keeping its brightness steady. */
.page-grain{position:fixed;inset:-16px;z-index:4;pointer-events:none;user-select:none;background:url('assets/grain.png') repeat;background-size:256px 256px;opacity:.045}
@media(prefers-reduced-motion:no-preference){
 .page-grain{animation:grain-dance 1.2s steps(1,end) infinite;will-change:transform}
}
html:has(.mobile-notice[open]) .page-grain{animation-play-state:paused}
@keyframes grain-dance{
 0%,100%{transform:translate(0,0)}
 12.5%{transform:translate(-7px,4px)}
 25%{transform:translate(5px,-8px)}
 37.5%{transform:translate(-3px,10px)}
 50%{transform:translate(9px,2px)}
 62.5%{transform:translate(-10px,-5px)}
 75%{transform:translate(4px,7px)}
 87.5%{transform:translate(8px,-9px)}
}
.cursor-trail{position:fixed;inset:0;z-index:100;pointer-events:none;user-select:none;opacity:0;transition:opacity 140ms ease-out}
.cursor-trail.is-visible{opacity:1}
.cursor-trail canvas{position:absolute;inset:0;width:100%;height:100%}
.cursor-dot,.cursor-ring{position:absolute;top:0;left:0;border-radius:50%;will-change:transform;pointer-events:none}
.cursor-dot{width:6px;height:6px;margin:-3px;background:#f05a24}
.cursor-ring{width:30px;height:30px;margin:-15px;border:1px solid #f05a24;opacity:.65}
@media(hover:hover) and (pointer:fine) and (prefers-reduced-motion:no-preference) and (forced-colors:none){
 html.has-custom-cursor,html.has-custom-cursor *{cursor:none!important}
}
@media(prefers-reduced-motion:reduce),(hover:none),(pointer:coarse),(forced-colors:active){.cursor-trail{display:none!important}}
@media(forced-colors:active){.page-grain{display:none}}
