/* ══ SECTION BACKGROUND SYSTEM ═══════════════════════════════════════════
 *
 * Six treatments. Every section on the site picks exactly one via a data
 * attribute; no section invents its own look. Variety comes from rotating
 * through the set, not from designing a new background each time — which is
 * what keeps a long multi-page site coherent instead of noisy.
 *
 *   <section data-bg="photo-duotone"
 *            style="--bg-photo:url(media/gallery/project/yles/03.webp)">
 *
 * The rule that makes it work: never run the same treatment twice in a row,
 * and never more than two photographic treatments in a row — photography is
 * the loudest thing here and it stops registering if it never lets up.
 *
 * Every section gets `position: relative` and its own stacking context; the
 * background lives in ::before at z-index 0 and content sits above it.
 * ═══════════════════════════════════════════════════════════════════════ */

[data-bg] { position: relative; isolation: isolate; }
[data-bg] > * { position: relative; z-index: 1; }
[data-bg]::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
}

/* ── 1 · flat ────────────────────────────────────────────────────────────
   The page canvas, nothing else. The rest depends on this one existing —
   without quiet sections the loud ones have nothing to be loud against. */
[data-bg="flat"]::before { background: var(--ink); }
[data-bg="flat-raised"]::before { background: var(--surface); }


/* ── 2 · hairline grid ───────────────────────────────────────────────────
   Structure without imagery. Good under dense content — rosters, glossaries,
   anything that is already visually busy and needs a background that holds
   still. The mask fades the grid out at the edges so it never boxes in. */
[data-bg="grid"]::before {
  background:
    linear-gradient(var(--hairline) 1px, transparent 1px) 0 0 / 100% 96px,
    linear-gradient(90deg, var(--hairline) 1px, transparent 1px) 0 0 / 96px 100%,
    var(--ink);
  -webkit-mask-image: radial-gradient(120% 90% at 50% 40%, #000 35%, transparent 100%);
          mask-image: radial-gradient(120% 90% at 50% 40%, #000 35%, transparent 100%);
}


/* ── 3 · gradient mesh ───────────────────────────────────────────────────
   Three offset radial pools that drift on a long cycle. This is the only
   purely generated treatment in the set and it earns its place by being
   slow and almost subliminal — it is atmosphere, not an effect. */
[data-bg="mesh"]::before {
  background:
    radial-gradient(60% 55% at 18% 22%, color-mix(in oklab, var(--crimson) 55%, transparent), transparent 70%),
    radial-gradient(55% 60% at 82% 38%, color-mix(in oklab, var(--oxblood) 85%, transparent), transparent 72%),
    radial-gradient(70% 65% at 48% 92%, color-mix(in oklab, var(--crimson-live) 28%, transparent), transparent 70%),
    var(--ink);
  filter: blur(0.5px);
  animation: bg-mesh 48s ease-in-out infinite alternate;
}
@keyframes bg-mesh {
  from { transform: scale(1.04) translate3d(-1.5%, -1%, 0); }
  to   { transform: scale(1.14) translate3d(1.5%, 2%, 0); }
}


/* ── 4 · crimson texture plate ───────────────────────────────────────────
   The two supplied crimson textures, blurred hard and drifting. Use where a
   section needs warmth but no subject matter. Set --bg-tex to either plate;
   the -rot variants are there so vertical sections do not reuse the same
   composition as horizontal ones. */
[data-bg="texture"]::before {
  background-image: var(--bg-tex, url(media/texture/crimson-a.webp));
  background-size: cover; background-position: center;
  opacity: .42; filter: blur(38px) saturate(1.25);
  animation: bg-mesh 52s ease-in-out infinite alternate;
}
[data-bg="texture"]::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(180deg, var(--ink), transparent 22%, transparent 78%, var(--ink));
}


/* ── 5 · photo duotone ───────────────────────────────────────────────────
   A photograph pushed into the palette and dropped behind a scrim. This is
   the workhorse — it is how the site uses its own archive as wallpaper
   without the photo fighting the type. The scrim is non-negotiable: ivory
   text on an ungraded photo fails contrast somewhere on every image. */
[data-bg="photo-duotone"]::before {
  background-image: var(--bg-photo);
  background-size: cover; background-position: var(--bg-pos, center);
  filter: grayscale(1) contrast(1.15) brightness(.42) sepia(.55) hue-rotate(-18deg) saturate(2.6);
}
[data-bg="photo-duotone"]::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    linear-gradient(180deg, var(--ink) 0%, transparent 28%, transparent 72%, var(--ink) 100%),
    linear-gradient(90deg, rgba(11,9,10,.82) 0%, rgba(11,9,10,.35) 55%, rgba(11,9,10,.6) 100%);
}

/* A full-bleed band: the photo is the point, so the scrim only protects the
   edges where the section meets its neighbours. Use sparingly — once a page. */
[data-bg="photo-band"]::before {
  background-image: var(--bg-photo);
  background-size: cover; background-position: var(--bg-pos, center);
  filter: grayscale(.3) contrast(1.06);
}
[data-bg="photo-band"]::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(180deg, var(--ink), transparent 18%, transparent 82%, var(--ink));
}


/* ── 6 · parallax plate ──────────────────────────────────────────────────
   The photograph plus its depth map, displaced in WebGL. Reserved for the
   two or three moments per page that carry the most weight — it is the most
   expensive treatment and it stops feeling special if it is everywhere.
   Markup: <div class="px" data-src data-depth data-amount data-grade>. */
.px { position: absolute; inset: 0; z-index: 0; overflow: hidden; background: var(--ink); }
.px canvas { width: 100%; height: 100%; display: block; opacity: 0; transition: opacity 1.1s var(--ease, ease); }
.px.is-ready canvas { opacity: 1; }
.px.is-fallback { filter: grayscale(.4) brightness(.5) contrast(1.1); }
[data-bg="parallax"]::before { background: var(--ink); }
[data-bg="parallax"]::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(180deg, var(--ink), transparent 26%, transparent 74%, var(--ink));
}


/* ── grain, over everything ──────────────────────────────────────────────
   One layer, applied once at the body level, not per section. On large flat
   dark fields banding is the thing that makes a site look cheap. */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 900; pointer-events: none;
  opacity: .04; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='150' height='150' filter='url(%23n)'/%3E%3C/svg%3E");
}


/* ── the Resources palette ───────────────────────────────────────────────
   Resources runs on the blue palette. Same six treatments, different tokens —
   scope them by putting data-theme="indigo" on the section or the body. */
[data-theme="indigo"] {
  --ink: #0B0E1E; --surface: #10152D;
  --crimson: #425B6F; --crimson-live: #6E8CA8; --oxblood: #1B2B4B;
  --hairline: rgba(226,217,203,.12);
}
[data-theme="indigo"][data-bg="photo-duotone"]::before {
  filter: grayscale(1) contrast(1.12) brightness(.45) sepia(.5) hue-rotate(165deg) saturate(2.2);
}


@media (prefers-reduced-motion: reduce) {
  [data-bg="mesh"]::before, [data-bg="texture"]::before { animation: none; }
}
