/* GRAIN — full-viewport tiled noise overlay + cursor trail canvas chrome.
   All rules prefixed with their owning id (#grain / #trail). No bare element selectors. */

#grain {
  position: fixed;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  z-index: 9000;
  pointer-events: none;
  background-image: url('../assets/noise.png?v=2');
  background-repeat: repeat;
  background-size: 256px 256px;
  opacity: calc(0.07 + var(--grain-boost, 0));
  mix-blend-mode: overlay;
  /* steps(1, end): HOLD each offset ~100ms, then HARD-CUT to the next.
     ROOT-CAUSE NOTE (round 7): this was `steps(9)`, which per the CSS Animations
     spec applies PER KEYFRAME SEGMENT — 9 sub-steps along the line between every
     pair of offsets = 90 discrete ~6-16px moves/sec (measured), i.e. the whole
     tiled noise field visibly SLID back and forth over every section ("pulsing
     scanline over everything"). Film-grain jitter needs uncorrelated jump-cuts,
     never interpolated travel: keep steps(1, end). */
  animation: grain-jump 1.2s steps(1, end) infinite;
  will-change: transform;
}

/* 12 hold-frames x 100ms. Consecutive offsets differ by >= 57px so each cut is
   fully decorrelated (no apparent motion); 1.2s loop softens the recurrence
   rhythm vs the old 0.9s cycle. */
@keyframes grain-jump {
  0%      { transform: translate3d(0, 0, 0); }
  8.333%  { transform: translate3d(-32px, -48px, 0); }
  16.667% { transform: translate3d(16px, -96px, 0); }
  25%     { transform: translate3d(-48px, 32px, 0); }
  33.333% { transform: translate3d(64px, -24px, 0); }
  41.667% { transform: translate3d(32px, 64px, 0); }
  50%     { transform: translate3d(-16px, -32px, 0); }
  58.333% { transform: translate3d(-8px, 96px, 0); }
  66.667% { transform: translate3d(48px, 80px, 0); }
  75%     { transform: translate3d(-64px, 16px, 0); }
  83.333% { transform: translate3d(-72px, -72px, 0); }
  91.667% { transform: translate3d(8px, -64px, 0); }
  100%    { transform: translate3d(0, 0, 0); }
}

#trail {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: 9400;
  pointer-events: none;
  mix-blend-mode: screen;
}

@media (prefers-reduced-motion: reduce) {
  #grain {
    animation: none;
    opacity: 0.05;
    transform: none;
  }
}
