/*
 * Film grain behind the page (script: src/scripts/site/grain.js, which adds the frame, paints the
 * noise and keeps every grain animation on one clock). After baseline.agency: a 1024px noise
 * canvas stretched to 112% of the viewport, crisp pixels, jumping between ten offsets.
 *
 * It sits behind the content (z-index -1, above the body's own background), so it shows only on
 * the plain dark page: images, video, cards and other filled surfaces cover it. For that, the
 * sections below, which used to paint the same colour as the page, are transparent instead (they
 * look identical).
 *
 * Where a solid piece must still show the grain, it shows the very same grain, not a copy that
 * looks alike: the site header carries a copy of the page canvas ([data-grain-local]), and the
 * other surfaces (yellow buttons, solid bars, small solid pieces) paint the page's noise image as
 * their background, pinned to the viewport at the same size and position and jumping through the
 * same offsets at the same moments. Across an edge between page and surface the grain is
 * continuous. Cards and panels have no grain.
 */
.grain {
  z-index: -1;
  pointer-events: none;
  position: fixed;
  inset: 0;
  overflow: hidden;
}

/* A touch calmer than baseline.agency's .5s: the same ten jumps over .7s (about 14 a second).
   Offsets only (no mirroring), so the surfaces' background images can follow them exactly. */
.grain__noise {
  width: 112%;
  height: 112%;
  image-rendering: pixelated;
  will-change: transform;
  animation: grain-jump .7s step-end infinite;
  position: absolute;
  top: -6%;
  left: -6%;
}

@keyframes grain-jump {
  0% { transform: translate(0, 0); }
  10% { transform: translate(-5%, 3%); }
  20% { transform: translate(4%, -5%); }
  30% { transform: translate(-4%, -2%); }
  40% { transform: translate(5%, 4%); }
  50% { transform: translate(-3%, 5%); }
  60% { transform: translate(5%, -3%); }
  70% { transform: translate(-5%, -5%); }
  80% { transform: translate(3%, 5%); }
  90% { transform: translate(-2%, -4%); }
}

/*
 * The site header ([data-grain-local]): a copy of the page canvas, placed and sized against the
 * viewport, above the bar's background and below its content (the bar isolates its stacking).
 */
[data-grain-local] {
  isolation: isolate;
}

.grain.is-local {
  position: absolute;
}

.grain.is-local .grain__noise {
  width: 112vw;
  height: 112vh;
  top: -6vh;
  left: -6vw;
}

/* Page-colour blocks let the grain through (they sit on the same colour, so nothing else
   changes). The html .body prefix outranks the blocks' own rules, including page stylesheets that
   load after this one (the hero's). */
html .body :is(
  .page-hero,
  .section,
  .section-video,
  .section-under-video,
  .section-talk-themes,
  .section-sponsors,
  .section-speakers,
  .section-speakers-copy,
  .section-venn,
  .section-logos,
  .section-cta,
  .marquee-css,
  .w-tab-pane,
  .div-block-38,
  .accordion-css__item,
  .progress-nav__inner
) {
  background-color: transparent;
}

/*
 * Solid surfaces showing the page grain: the page's noise image (--grain-image, shared by
 * grain.js) as their background, fixed to the viewport at the page layer's size (112vw × 112vh)
 * and resting position (-6vw, -6vh), and moved by the same ten offsets (1% of the layer = 1.12vw
 * or 1.12vh). A new surface only needs its class here.
 */
html .body :is(
  .site-nav__btn-bg:not(.is-influence),
  .btn-animate-chars.cta.yellow,
  .cta-slider-wrapper,
  .btn-animate-chars__bg.sponsors-contact,
  .progress-nav,
  .tabs-menu,
  .is-txt-schedule-speaker-name,
  .is-txt-schedule-time-dash,
  .is-txt-schedule-time-end,
  .button,
  .btn-animate-chars_footer-email,
  .btn-animate-chars__bg.tickets-page
) {
  background-image: var(--grain-image, none);
  background-size: 112vw 112vh;
  background-repeat: no-repeat;
  background-attachment: fixed;
  background-position: -6vw -6vh;
  image-rendering: pixelated;
  animation: grain-jump-surface .7s step-end infinite;
}

/* Only the grain itself is drawn with hard pixels. */
html .body :is(
  .site-nav__btn-bg:not(.is-influence),
  .btn-animate-chars.cta.yellow,
  .cta-slider-wrapper,
  .btn-animate-chars__bg.sponsors-contact,
  .progress-nav,
  .tabs-menu,
  .button
) * {
  image-rendering: auto;
}

@keyframes grain-jump-surface {
  0% { background-position: -6vw -6vh; }
  10% { background-position: calc(-6vw - 5 * 1.12vw) calc(-6vh + 3 * 1.12vh); }
  20% { background-position: calc(-6vw + 4 * 1.12vw) calc(-6vh - 5 * 1.12vh); }
  30% { background-position: calc(-6vw - 4 * 1.12vw) calc(-6vh - 2 * 1.12vh); }
  40% { background-position: calc(-6vw + 5 * 1.12vw) calc(-6vh + 4 * 1.12vh); }
  50% { background-position: calc(-6vw - 3 * 1.12vw) calc(-6vh + 5 * 1.12vh); }
  60% { background-position: calc(-6vw + 5 * 1.12vw) calc(-6vh - 3 * 1.12vh); }
  70% { background-position: calc(-6vw - 5 * 1.12vw) calc(-6vh - 5 * 1.12vh); }
  80% { background-position: calc(-6vw + 3 * 1.12vw) calc(-6vh + 5 * 1.12vh); }
  90% { background-position: calc(-6vw - 2 * 1.12vw) calc(-6vh - 4 * 1.12vh); }
}

@media (prefers-reduced-motion: reduce) {
  .grain__noise,
  html .body :is(.site-nav__btn-bg, .btn-animate-chars.cta.yellow, .cta-slider-wrapper, .btn-animate-chars__bg.sponsors-contact, .progress-nav, .tabs-menu, .is-txt-schedule-speaker-name, .is-txt-schedule-time-dash, .is-txt-schedule-time-end, .button, .btn-animate-chars_footer-email, .btn-animate-chars__bg.tickets-page) {
    animation: none;
  }
}
