/* ════════════════════════════════════════════════════════════
   CONTINUUM — one continuous field instead of a stack of boxes
   Pairs with js/continuum.js (which injects the two fixed layers).

   WHY THIS FILE EXISTS
   The page reads as ~20 separate boxes for two reasons:
     1. every section paints its own opaque panel, and
     2. those panels meet at a hard clip-path SLANT — a razor edge
        that the eye reads as "new box starts here".
   This file keeps every panel and every pixel of layout geometry
   exactly as style.css defines it, and only changes HOW the panel
   edge is drawn: `clip-path` (a hard cut) becomes `mask-image`
   (a soft ramp). Behind them all sits one fixed field so the
   sections float over a single continuous backdrop.

   WHY OVERRIDE INSTEAD OF EDIT
   The slants use negative margins (`margin-top: -slant`) that the
   following section's padding compensates for. Touching either side
   opens a gap. clip-path and mask-image are BOTH paint-only — they
   have zero effect on layout — so swapping one for the other cannot
   move anything. That is the whole trick.

   REVERT = remove the <link> to this file and the <script> for
   js/continuum.js. Nothing else on the site knows they exist.
   ════════════════════════════════════════════════════════════ */

:root {
  /* ── The field. Deliberately narrow tonal range. ──────────────
     Every tone here already ships on this site: --cont-top is a
     hair above --bone (#F5F1EA) and --cont-deep IS --warm-mid
     (#EDE8DF), the darkest light surface the design already uses.
     Because the field never goes below a tone the page already
     puts body copy on, no text/background pair can get worse than
     it is today. That is the contrast guarantee, by construction. */
  --cont-top:  #F7F4EE;
  --cont-mid:  #F3EEE6;
  --cont-deep: #EDE8DF;

  /* Length of every soft edge. Kept strictly SHORTER than the
     smallest section padding at each breakpoint, so a fade never
     reaches text:
       >=1467px  pad 188  fade 168
       1440px    pad 188  fade 130
       769px     pad 120  fade  69
     (mobile values are set in the media query below). */
  --cont-fade: clamp(64px, 9vw, 168px);

  /* Reusable edge ramps. Multi-stop, roughly smoothstep, because a
     2-stop linear ramp shows Mach banding on flat colour fields. */
  --cont-in: rgba(0,0,0,0) 0,
             rgba(0,0,0,.04) calc(var(--cont-fade) * .16),
             rgba(0,0,0,.20) calc(var(--cont-fade) * .36),
             rgba(0,0,0,.52) calc(var(--cont-fade) * .56),
             rgba(0,0,0,.84) calc(var(--cont-fade) * .79),
             rgba(0,0,0,1)   var(--cont-fade);
  --cont-out: rgba(0,0,0,1)   calc(100% - var(--cont-fade)),
              rgba(0,0,0,.84) calc(100% - var(--cont-fade) * .79),
              rgba(0,0,0,.52) calc(100% - var(--cont-fade) * .56),
              rgba(0,0,0,.20) calc(100% - var(--cont-fade) * .36),
              rgba(0,0,0,.04) calc(100% - var(--cont-fade) * .16),
              rgba(0,0,0,0)   100%;
}

@media (max-width: 768px) {
  /* --section-pad drops to 84px here and 64px at <=390px, so the
     fade has to shrink with it or it would wash over copy. 44px
     leaves 20px of clearance in the tightest case (.slant-bone at
     390px: 64px of bottom padding). */
  :root { --cont-fade: 44px; }
}

/* ────────────────────────────────────────────────────────────
   1 · THE FIELD (injected by continuum.js as body > .cont-field)
   ──────────────────────────────────────────────────────────── */

/* Two gradients in one element, on purpose: the vignette is baked
   into the field rather than floated over the page. On a LIGHT page
   a vignette laid on top of content is a contrast hazard — it would
   darken body copy every time that copy passed the top or bottom of
   the viewport. Baked in, it only ever tints the field itself, so it
   can never sit between a reader and a word. */
.cont-field {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(125% 105% at 50% 45%,
      rgba(0,0,0,0) 58%,
      rgba(96, 82, 58, .05) 100%),
    radial-gradient(120% 90% at 50% 0%,
      var(--cont-top) 0%,
      var(--cont-mid) 46%,
      var(--cont-deep) 100%);
  /* Promote to its own compositor layer. The field is fixed, so it
     must not be re-rastered on every scroll frame — and on iOS
     Safari an un-promoted fixed layer is the classic jank/repaint
     trap when the URL bar collapses. One static layer, no blending,
     costs essentially nothing. (This is NOT background-attachment:
     fixed, which is the thing iOS actually cannot do cheaply.) */
  transform: translateZ(0);
  backface-visibility: hidden;
}

/* ────────────────────────────────────────────────────────────
   2 · THE GRAIN (injected as body > .cont-grain)
   z-index 45: above every content stage (the corridor tops out at
   25, the wall-of-work at 3, scenes at 2) and far below the nav
   (990) and the custom cursor (9999), so chrome stays crisp.
   ──────────────────────────────────────────────────────────── */
.cont-grain {
  position: fixed;
  inset: 0;
  z-index: 45;
  pointer-events: none;
  opacity: .045;
  mix-blend-mode: overlay;
  background-size: 160px 160px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* The grain is static, but it is still a full-screen blended layer:
   `mix-blend-mode` forces the whole page underneath it to be
   composited through a blend on every frame. That is the single
   most expensive thing in this file on a phone GPU, and it buys
   almost nothing at phone pixel density — so it is removed, not
   merely faded. continuum.js also refuses to create the element at
   all on coarse pointers; this rule is the belt to that braces. */
@media (max-width: 900px), (pointer: coarse) {
  .cont-grain { display: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .cont-grain { display: none; }
}

/* ────────────────────────────────────────────────────────────
   SLANT SOFTENING REMOVED.
   Sections 3 and 4 of this file replaced the slant clip-paths with
   gradient masks. The soft boundary was rejected: the angular edge is
   wanted. The hard clip-path in style.css is authoritative again, and
   each panel now folds itself in — see js/origami.js.
   The field, vignette and grain above are kept: they were never the
   thing being objected to.
   ──────────────────────────────────────────────────────────── */

/* ────────────────────────────────────────────────────────────
   5 · SAFETY
   ──────────────────────────────────────────────────────────── */

/* The hero and the corridor paint their own full-bleed art and must
   stay opaque; nothing above should assume the field shows through. */
.hero { position: relative; z-index: 0; }

/* Belt-and-braces: neither injected layer may ever take a hit. The
   site puts `cursor: none` on everything for its custom cursor, so a
   stray click-blocker would be invisible to debug. */
.cont-field,
.cont-grain { pointer-events: none !important; }

/* ── The field must not paint over the page's own furniture ───
   .cont-field is fixed at z-index 0. Anything that has to appear above it
   needs its own stacking context; the sections all got one from the motion
   layers, but the footer never did — so the field covered it and the page
   ended in a blank bone band with the footer invisible underneath.
   ──────────────────────────────────────────────────────────── */
.footer,
.sticky-call,
.site-header,
.nav { position: relative; z-index: 1; }
.sticky-call { z-index: 900; }
