/* ==========================================================================
   NITRATE — THE POSTER WALL (mosaic.js).  Backdrop only.

   Owned by the mosaic agent.  Consumes tokens.css, never redefines a token.
   Every selector is prefixed .nmz- so nothing here can collide with home.css,
   landing.css or wall.css.

   The wall is not artwork, it is DEPTH.  Everything below exists to push it
   behind the thing the page is actually about.  The test is simple: if a viewer
   can READ a title on the wall it is too present, and if the cases have stopped
   looking like cases it has gone too far the other way.  16px sits between the
   two — measured on the vault at 9px you could still read the right-hand column,
   and at 20px the grid dissolved into blobs and stopped being HIS shelf.

   WHERE THE TREATMENT IS APPLIED.  The four --nmz- numbers are the control
   panel, but mosaic.js executes them: it bakes blur/saturate/brightness into
   each poster ONCE, offscreen, at load.  A `filter` on the live canvas is
   re-run on every commit and measured at ~100ms a frame here (9 rAF/s against
   60 with no filter), and it did not improve with will-change, contain:paint,
   a smaller box, or a real compositor.  So the animated layer carries opacity
   and nothing else — opacity is free, filters are not.  Change a number here
   and the wall re-bakes itself within a second, a few tiles per frame.
   ========================================================================== */

/* the mount clips the wall — the host owns everything else about it */
.nmz-host { overflow: hidden; }

.nmz-canvas {
  /* THE CONTROL PANEL.  Read by mosaic.js, not by the compositor. */
  --nmz-blur: 16px;
  --nmz-saturate: .28;
  --nmz-brightness: 1.02;
  /* the mortar between the cases, and an empty case waiting for its art */
  --nmz-ground: var(--ground);
  --nmz-cell: var(--panel-2);
  /* this one IS the compositor's */
  --nmz-opacity: .42;

  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  z-index: 0;
  max-width: none;              /* tokens.css caps every canvas at 100% */
  pointer-events: none;
  opacity: calc(var(--nmz-opacity) * var(--nmz-hold, 1));
}

/* --- DARK: "the vault" ----------------------------------------------------
   Poster art is mostly dark and mostly saturated, which is the same direction
   as the vault's own ground — so here the wall has to be pushed DOWN in value
   to sit behind the page instead of glowing through it, and it needs less
   opacity than the light table, not more.  That is the opposite of the instinct
   and it is what the two screenshots said. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .nmz-canvas {
    --nmz-opacity: .38;
    --nmz-saturate: .34;
    --nmz-brightness: .60;
  }
}
:root[data-theme="dark"] .nmz-canvas {
  --nmz-opacity: .38;
  --nmz-saturate: .34;
  --nmz-brightness: .60;
}

/* --- LIGHT: "the light table" --------------------------------------------
   Poster art is dark and saturated; on a paper ground it reads as dirt unless
   it is lifted almost to the ground's own value and drained of colour. */
:root[data-theme="light"] .nmz-canvas {
  --nmz-opacity: .42;
  --nmz-saturate: .28;
  --nmz-brightness: 1.02;
}

/* Reduced motion still gets a wall, just a still one (mosaic.js paints exactly
   one frame).  A static wall reads as MORE present than a drifting one because
   the eye stops tracking it and starts reading it, so hold it back a little.
   A multiplier rather than a value: it must not undo the theme above it. */
@media (prefers-reduced-motion: reduce) {
  .nmz-canvas { --nmz-hold: .78; }
}

/* --- the fallback --------------------------------------------------------
   Safari before 17 has no canvas filter, so there is nothing to bake into and
   mosaic.js hangs this class on instead.  Costly, but the alternative on those
   engines is a wall of sharp posters shouting over the title.

   Sized with width/height and NOT with `inset`, which looks equivalent and is
   not: a canvas is a REPLACED element, so an absolutely positioned one with
   `width: auto` takes its INTRINSIC width (the backing store) and ignores the
   opposing offset.  Under `inset` alone the box locks to canvas.width, mosaic.js
   sets canvas.width from the box, and the two ratchet each other down — measured,
   it settled at 108x54.  The oversize is real though: a CSS blur samples the
   transparent void outside the element, and a canvas sized exactly to its box
   fades out along all four edges, drawing a soft frame around the very thing it
   is meant to disappear behind. */
.nmz-canvas.nmz-soft {
  top:  calc(var(--nmz-blur) * -2.5);
  left: calc(var(--nmz-blur) * -2.5);
  width:  calc(100% + var(--nmz-blur) * 5);
  height: calc(100% + var(--nmz-blur) * 5);
  filter: blur(var(--nmz-blur))
          saturate(var(--nmz-saturate))
          brightness(var(--nmz-brightness));
}
