/* Global shader layer — page treatment. The picture itself is shaded by js/core/shader.js, which
   draws an opaque .shader-canvas over the scene host; this file hides the raw scene beneath it and
   lays a quiet print-shop treatment over the page to match the chosen shader.

   html[data-shader] is set before first paint (index.html) and on every change (app.js).
   Every treatment is a registered number (--sp-*) transitioned over ~400ms and scaled by
   --shader-page-amount (the Design Controller's "page" param, 0..1, default 0.5 = nominal).
   Overlays live at z-index 1: above the scene layer, below .site (z 2), so they never sit on top
   of a glyph — they only nudge the ground behind it, by a few percent at most. */

@property --shader-page { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --sp-cel { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --sp-pop { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --sp-print { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --sp-wash { syntax: '<number>'; inherits: true; initial-value: 0; }

/* Unlayered on purpose: whatever a direction says about its canvas, a shaded host shows only the
   shader canvas. */
.scene-host[data-shaded] .scene-canvas,
.scene-host[data-shaded] .scene-poster { visibility: hidden; }

.shader-canvas {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%;
  pointer-events: none;
  visibility: hidden;
}
.shader-canvas[data-on] { visibility: visible; }

@layer utilities {
  body {
    /* the page treatment's strength: 0.5 is nominal, 1 is twice that */
    --sp-k: calc(var(--shader-page-amount, 0.5) * 2);
    transition: --shader-page calc(400ms * var(--u-motion, 1)) ease,
      --sp-cel calc(400ms * var(--u-motion, 1)) ease, --sp-pop calc(400ms * var(--u-motion, 1)) ease,
      --sp-print calc(400ms * var(--u-motion, 1)) ease, --sp-wash calc(400ms * var(--u-motion, 1)) ease;
  }
  html:not([data-shader='original'])[data-shader] body { --shader-page: 1; }
  html[data-shader='cel'] body { --sp-cel: 1; }
  html[data-shader='pop'] body { --sp-pop: 1; }
  html[data-shader='print'] body { --sp-print: 1; }
  html[data-shader='wash'] body { --sp-wash: 1; }

  /* ── Pattern plate: Ben-Day dots (pop), registration marks (print), vignette (wash) ── */
  body::before {
    content: ''; position: fixed; inset: 0; z-index: 1; pointer-events: none;
    --a-pop: calc(var(--sp-pop) * var(--sp-k));
    --a-print: calc(var(--sp-print) * var(--sp-k));
    --a-wash: calc(var(--sp-wash) * var(--sp-k));
    --dot: 236 30 122;
    --mark: 42 36 32;
    --vig: 92 64 36;
    background:
      /* print: registration targets, centred on the left and right edges */
      radial-gradient(circle at center, transparent 6.5px, rgb(var(--mark) / calc(0.42 * var(--a-print))) 7px 7.8px, transparent 8.3px) left 10px center / 26px 26px no-repeat,
      linear-gradient(rgb(var(--mark) / calc(0.42 * var(--a-print))) 0 0) left 22.5px center / 1px 26px no-repeat,
      linear-gradient(rgb(var(--mark) / calc(0.42 * var(--a-print))) 0 0) left 10px center / 26px 1px no-repeat,
      radial-gradient(circle at center, transparent 6.5px, rgb(var(--mark) / calc(0.42 * var(--a-print))) 7px 7.8px, transparent 8.3px) right 10px center / 26px 26px no-repeat,
      linear-gradient(rgb(var(--mark) / calc(0.42 * var(--a-print))) 0 0) right 22.5px center / 1px 26px no-repeat,
      linear-gradient(rgb(var(--mark) / calc(0.42 * var(--a-print))) 0 0) right 10px center / 26px 1px no-repeat,
      /* wash: the paper darkens a breath toward its edges */
      radial-gradient(ellipse 120% 110% at 50% 45%, transparent 55%, rgb(var(--vig) / calc(0.07 * var(--a-wash))) 100%),
      /* pop: a 45° Ben-Day lattice (two square grids, the second offset by half a cell) */
      radial-gradient(circle at center, rgb(var(--dot) / calc(0.06 * var(--a-pop))) 0 1.15px, transparent 1.75px) 0 0 / 7px 7px,
      radial-gradient(circle at center, rgb(var(--dot) / calc(0.06 * var(--a-pop))) 0 1.15px, transparent 1.75px) 3.5px 3.5px / 7px 7px;
    /* the dots gather toward the top right and leave the name (lower left) clean */
    -webkit-mask-image: linear-gradient(to top right, rgb(0 0 0 / calc(1 - var(--sp-pop))) 30%, #000 75%);
    mask-image: linear-gradient(to top right, rgb(0 0 0 / calc(1 - var(--sp-pop))) 30%, #000 75%);
  }
  html[data-theme='dark'] body::before { --dot: 64 210 255; --mark: 236 230 222; --vig: 0 0 0; }
  html[data-theme='dark'] body::before { --a-wash: calc(var(--sp-wash) * var(--sp-k) * 2.4); }

  /* ── Stock: paper tooth (print) and grain (wash), one noise tile, multiplied in light and
        screened in dark so it reads as fibre rather than dirt ── */
  body::after {
    content: ''; position: fixed; inset: 0; z-index: 1; pointer-events: none;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.35 0 0 0 0 0.3 0 0 0 0 0.24 0 0 0 1.6 -0.55'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E") 0 0 / 220px 220px;
    opacity: calc((var(--sp-print) * 0.32 + var(--sp-wash) * 0.2) * var(--sp-k));
    mix-blend-mode: multiply;
  }
  html[data-theme='dark'] body::after {
    mix-blend-mode: screen;
    filter: invert(1) brightness(0.32);
    opacity: calc((var(--sp-print) * 0.45 + var(--sp-wash) * 0.3) * var(--sp-k));
  }

  /* ── Type ── */
  /* print: the name and headings carry a cyan plate laid one pixel off (red on dark stock). Pop
     gets no misregistration at all: on type it reads as a rendering fault, not a style. */
  .hero-name, .featured-title, .work-section-title, .work-title-main {
    text-shadow: calc(1px * var(--sp-print)) calc(1px * var(--sp-print)) 0 rgb(0 150 215 / calc(0.34 * var(--sp-print) * min(1, var(--sp-k))));
  }
  html[data-theme='dark'] :is(.hero-name, .featured-title, .work-section-title, .work-title-main) {
    text-shadow: calc(1px * var(--sp-print)) calc(1px * var(--sp-print)) 0 rgb(235 60 50 / calc(0.36 * var(--sp-print) * min(1, var(--sp-k))));
  }
  /* cel: one crisp inked stroke under the name, drawn on from the left */
  .hero-name { position: relative; }
  .hero-name::after {
    content: ''; position: absolute; left: 0.04em; bottom: -0.16em;
    width: 56px; height: 2px; border-radius: 1px;
    background: currentColor;
    opacity: calc(0.85 * min(1, var(--sp-k)));
    transform: scaleX(var(--sp-cel)); transform-origin: left center;
    pointer-events: none;
  }

  @media (max-width: 640px) {
    /* no room at the edges for registration marks on a phone */
    body::before { background-size: 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, auto, 7px 7px, 7px 7px; }
  }
}

/* ── 3D | 2D: how the finish is applied (shader panel, js/core/ui.js) ──────────────────────────
   Same anatomy as the model switch: a thumb slides under the chosen half. The note says when a
   look can only take 2D, so 3D never silently looks like 2D. */
@layer engine {
  .shader-mode {
    display: grid; grid-template-columns: auto auto 1fr; align-items: center; gap: 12px;
    margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); font-size: 12px; color: var(--text-2);
  }
  .shader-mode-switch {
    position: relative; display: grid; grid-template-columns: repeat(2, 48px); height: 30px; padding: 2px;
    border-radius: calc(var(--radius-lg) - 6px); background: color-mix(in srgb, var(--surface-2) 70%, transparent);
  }
  .shader-mode-switch button {
    position: relative; z-index: 1; border-radius: calc(var(--radius-lg) - 8px);
    font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.04em; color: var(--text-2);
    transition: color var(--dur-fast) var(--ease-enter);
  }
  .shader-mode-switch button:hover, .shader-mode-switch button[aria-checked='true'] { color: var(--text); }
  .shader-mode-switch button:focus-visible { outline: 2px solid var(--text-2); outline-offset: -2px; }
  .shader-mode-thumb {
    position: absolute; top: 2px; left: 2px; width: 48px; height: 26px; border-radius: calc(var(--radius-lg) - 8px);
    background: var(--chrome-bg); box-shadow: inset 0 0 0 1px var(--line-strong), 0 2px 6px -2px rgb(0 0 0 / 0.25);
    transition: transform calc(420ms * var(--u-motion, 1)) var(--spring);
  }
  .shader-mode-switch[data-mode='2d'] .shader-mode-thumb { transform: translateX(48px); }
  .shader-mode-note { font-size: 11px; line-height: 1.35; color: var(--text-2); transition: color var(--dur-fast); }
  .shader-mode-note[data-fallback] { color: var(--text); }
  .shader-mode-note[data-fallback]::before {
    content: ''; display: inline-block; width: 6px; height: 6px; margin-right: 6px; border-radius: 50%;
    vertical-align: 1px; background: var(--accent);
  }
}
