
.c-reflection,
.m-reflection,
.p-reflection {
  background-position: var(--refl-xpos) var(--refl-ypos);
}
/* The paper texture is the mask of .p-reflection. Webflow's own rule for .p-reflection also uses
   var(--paper-texture), but a relative url() inside a CSS variable is resolved against the stylesheet
   that USES the variable — in Webflow's stylesheet that is Webflow's CDN, where the file does not
   exist (403). Declaring the mask here makes it resolve against /CSS/, i.e. to /textures/ on
   whichever Worker serves this file. Webflow's rule keeps all its other properties. */
.p-reflection {
  -webkit-mask-image: var(--paper-texture);
  mask-image: var(--paper-texture);
}
.c-refl-highlight-masked-2,
.c-refl-highlight-masked-4 {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-color: transparent; /* Essential for the multiply math */
  /* Order is important: Gradient on top, Texture on bottom */
  background-image: radial-gradient(circle 30vw at var(--inv-refl-xpos) var(--refl-ypos), white 0%, black 90%), var(--canvas-refl-mask);
  background-repeat: repeat, repeat;
  background-size:
    100% 100%,
    var(--canvas-size);
}
.soft-light-fade {
  background-image: radial-gradient(circle 800px at var(--inv-refl-xpos) var(--refl-ypos), white, black);
}
.new-canvas,
.canvas-border {
  background-size: calc(var(--canvas-size) * 2);
  background-image: var(--canvas-texture);
}

.p-texture {
  background-size: calc(var(--paper-size));
}
.wall-texture {
  background-size: calc(var(--one-inch) + 50px);
  transition: background-size 200ms ease;
}

/* ==========================================================================
   Substrate layer gating — Safari memory
   --------------------------------------------------------------------------
   These overlays are gated only by `opacity: calc(var(--sub-*))` in Webflow.
   An opacity-0 element that also has mix-blend-mode or filter still keeps its
   full compositing backing store in WebKit — and for a blended layer that
   means a rasterized snapshot of everything beneath it too. So with Canvas
   selected the browser was also holding the paper and metal stacks, including
   .p-reflection's blur(60px) + mask-image, the most expensive layer on the
   page. Chrome merges most of these away, which is why it never showed up
   there.

   `display: none` releases the buffers outright. All targets are inset:0
   overlays, so taking them out of flow has no layout effect.

   CSS can't branch on a numeric custom property, so this keys off
   data-substrate on <html>, set in JS/frame-substrate-var-updates.js. The
   [data-substrate] guard means nothing is hidden before that JS runs — same
   rendering as today until it does.

   Keyed by a marker attribute, not a hand-maintained class list — the same
   contract as data-framer-section / data-frame-type elsewhere on this page
   (see "The data-attribute contract" in CLAUDE.md). A first version of this
   rule listed individual class names (.canvas-group, .p-reflection, ...),
   which is how .canvas-border and .paper-reflection went unnoticed for so
   long: nothing marked them as substrate-specific, so there was nothing to
   grep for. data-substrate-layer="canvas|paper|metal" on a preview element
   now makes it this gate's business with no CSS change — same as adding a
   new frame type needs no JS change. Only the element's own closest
   ancestor needs the attribute; a child (.new-canvas inside .canvas-group,
   .p-reflection inside .paper-reflection) inherits the hidden state.

   You cannot select a substrate and hover at the same time, so hiding the
   inactive substrate's own layers this way never fights the --refl-on-off
   hover fade on the active one — hover opacity is untouched; only switching
   substrates is now a hard cut instead of whatever cross-fade Webflow's
   opacity alone produced.

   .inner-shadow-c-wrap carries data-substrate-layer="canvas" too (gallery
   wrap is a canvas-only format) AND keeps its own data-c-wrap condition —
   canvas but NOT gallery-wrap (stretched canvas) still has to hide it, which
   a substrate value alone can't express. The two conditions are OR'd by
   being separate selectors in one rule, same as the others.
   ========================================================================== */

html[data-substrate]:not([data-substrate='canvas']) [data-substrate-layer='canvas'],
html[data-substrate]:not([data-substrate='paper']) [data-substrate-layer='paper'],
html[data-substrate]:not([data-substrate='metal']) [data-substrate-layer='metal'],
html[data-c-wrap]:not([data-c-wrap='1']) .inner-shadow-c-wrap {
  display: none;
}

/* wrapper: blur the final composited pixels */
.refl-blur {
  display: inline-block;
  filter: blur(0px);
  overflow: visible; /* avoid clipping the blur */
  transform: translateZ(0); /* Safari/WebKit stability */
}
