/* Pro Surface Supply USA: the 3D stage and the glass layer, shared by every
   public page (with assets/site.css). The scene is a stage, not the content:
   copy, prices and buttons stay HTML on top of it.

   .stage-shell        the region the canvas is pinned inside (hero, then the dive)
     .stage            the backdrop: poster, then the live canvas over it
     .stage-dive       the empty band where the camera dives into the floor
   .after-stage        the slate reading surface; the dive dissolves into exactly
                       --slate, so the seam disappears
   .glass              a translucent panel over the stage (blur, lit edge, sheen)
   [data-tilt]         leans toward a fine pointer (assets/stage/boot.js)
   [data-rise]         rises in as it enters (boot.js arms it)
   .px-in, .is-entering  the pixel-grid dissolve for content that swaps

   Every line of text on the bare stage is measured at 4.5:1 or better
   (tools/verify-stage.mjs); text on .glass sits on at least 78% ink. */

:root {
  --slate: #0b0f14;
  --glass: rgba(9, 12, 16, 0.8);
  --glass-strong: rgba(9, 12, 16, 0.86);
  --glass-edge: linear-gradient(160deg, rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0.05) 38%, rgba(140, 196, 255, 0.16));
  --glass-edge-hot: linear-gradient(160deg, rgba(88, 166, 255, 0.95), rgba(30, 111, 232, 0.25) 45%, rgba(255, 255, 255, 0.12));
  --dive: 52vh;
  --spring: cubic-bezier(0.34, 1.36, 0.42, 1);
}

/* The region --------------------------------------------------------------- */
.stage-shell { position: relative; isolation: isolate; display: flex; flex-direction: column; min-height: calc(100svh + var(--dive) - 110px); }
.stage { position: absolute; inset: 0; z-index: -1; background: var(--ink); }
/* The largest viewport height never changes when a phone's address bar
   slides, so the canvas does not resize (and rebuild) while scrolling. */
.stage-pin { position: sticky; top: 0; height: 100vh; height: 100lvh; overflow: hidden; }
.stage-poster, .stage-poster img, .stage-canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.stage-poster img { object-fit: cover; transition: opacity 600ms var(--ease); }
.stage-poster.is-coming img { opacity: 0; }
.stage-canvas { display: block; opacity: 0; transition: opacity 900ms var(--ease); }
.stage.is-live .stage-canvas { opacity: 1; }
/* The fog band at the top of the scene meets the header in ink. */
.stage-pin::after { content: ""; position: absolute; inset: 0 0 auto; height: 120px; background: linear-gradient(var(--ink), rgba(6, 8, 9, 0)); pointer-events: none; }

.stage-hero { position: relative; padding-top: clamp(20px, 4vh, 48px); }
.stage-dive { flex: 1 0 var(--dive); display: grid; align-content: start; justify-items: center; padding: clamp(36px, 7vh, 72px) var(--gutter) 0; }
.stage-promise {
  margin: 0; max-width: 100%; padding: 12px 22px; border-radius: 999px; text-align: center;
  font-family: var(--font-label); font-weight: 600; font-size: 1.02rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text); background: var(--glass-strong); border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 18px 50px -20px rgba(0, 0, 0, 0.8);
}
@supports (backdrop-filter: blur(8px)) { .stage-promise { backdrop-filter: blur(14px) saturate(140%); } }
.stage-promise a { color: inherit; text-decoration: none; }
.stage-promise a:hover { color: #fff; text-decoration: underline; }

.stage-pause {
  position: absolute; z-index: 3; top: 14px; right: var(--gutter); min-height: 36px; padding: 0 14px; border-radius: 999px;
  border: 1px solid var(--line-control); background: rgba(6, 8, 9, 0.66); color: var(--silver);
  font: 600 0.82rem/1 var(--font-label); letter-spacing: 0.1em; text-transform: uppercase; cursor: pointer;
}
.stage-pause:hover { color: #fff; border-color: var(--blue-glow); }

/* The reading surface below the stage. */
.after-stage { position: relative; background: var(--slate); padding-bottom: 8px; }
.after-stage > :first-child { margin-top: 0; }

/* Glass ----------------------------------------------------------------------- */
.glass { position: relative; isolation: isolate; border-color: transparent; background: var(--glass); border-radius: var(--radius); box-shadow: 0 30px 80px -40px rgba(0, 0, 0, 0.9); }
@supports (backdrop-filter: blur(8px)) { .glass { backdrop-filter: blur(16px) saturate(140%); } }
/* A 1px lit edge, drawn as a masked ring so it never tints the panel. */
.glass::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none;
  background: var(--glass-edge);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.glass.is-hot::after { background: var(--glass-edge-hot); }
.glass.is-hot { box-shadow: 0 30px 90px -40px rgba(30, 111, 232, 0.55), 0 30px 80px -40px rgba(0, 0, 0, 0.9); }
/* The sheen follows the pointer across the glass, under the content. */
.glass::before {
  content: ""; position: absolute; z-index: -1; inset: 0; border-radius: inherit; pointer-events: none;
  background: radial-gradient(520px circle at var(--mx, 50%) var(--my, 0%), rgba(255, 255, 255, 0.07), transparent 45%);
}

/* Tilt: a few degrees toward the pointer, eased back on leave. */
[data-tilt] {
  --rx: 0deg; --ry: 0deg;
  transform: perspective(1100px) rotateX(var(--rx)) rotateY(var(--ry));
  transition: transform 520ms var(--ease), box-shadow 520ms var(--ease), border-color 0.2s var(--ease);
  will-change: transform;
}
[data-tilt].is-tilting { transition: transform 90ms linear, box-shadow 520ms var(--ease), border-color 0.2s var(--ease); }

/* Rise-ins: nothing is hidden until boot.js arms them, and an observer that
   never reports (rise-off) or a printout shows everything. */
[data-rise] { transition: opacity 700ms var(--ease), transform 900ms var(--ease); }
.rise-armed:not(.rise-off) [data-rise]:not(.is-in) { opacity: 0; transform: perspective(900px) translateY(26px) rotateX(7deg); }
@media print { [data-rise] { opacity: 1 !important; transform: none !important; transition: none !important; } }

/* Flake-filled type: blue over a chip mosaic, drifting slowly. Its darkest
   pixel (rgb 119, 167, 217) holds 4.5:1 on the calm stage. */
.flake-fill {
  color: var(--blue-text);
  background: linear-gradient(rgba(140, 196, 255, 0.86), rgba(140, 196, 255, 0.86)), url(/assets/blends/checkmate-card-400.webp) 0 0 / 300px auto;
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
}
/* It drifts only while the stage is live, where the pause control is too
   (WCAG 2.2.2). */
.stage-live .flake-fill { animation: flake-drift 40s linear infinite; }
@keyframes flake-drift { to { background-position: 0 0, 300px 0; } }
[data-motion-paused] .flake-fill { animation-play-state: paused; }

/* The pixel-grid dissolve: two crossed bands per 14px tile make a square
   whose side is --px of the tile. Browsers without @property simply fade. */
@property --px { syntax: "<number>"; inherits: true; initial-value: 1; }
.is-leaving, .is-entering {
  -webkit-mask-image:
    linear-gradient(90deg, transparent calc(50% - var(--px) * 50% - 0.5px), #000 0 calc(50% + var(--px) * 50% + 0.5px), transparent 0),
    linear-gradient(0deg, transparent calc(50% - var(--px) * 50% - 0.5px), #000 0 calc(50% + var(--px) * 50% + 0.5px), transparent 0);
  mask-image:
    linear-gradient(90deg, transparent calc(50% - var(--px) * 50% - 0.5px), #000 0 calc(50% + var(--px) * 50% + 0.5px), transparent 0),
    linear-gradient(0deg, transparent calc(50% - var(--px) * 50% - 0.5px), #000 0 calc(50% + var(--px) * 50% + 0.5px), transparent 0);
  -webkit-mask-size: 14px 14px; mask-size: 14px 14px;
  -webkit-mask-composite: source-in; mask-composite: intersect;
}
.is-leaving { animation: px-out 300ms cubic-bezier(0.55, 0, 0.75, 0.2) both; }
.is-entering { animation: px-in 560ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
@keyframes px-out { from { --px: 1; opacity: 1; } to { --px: 0; opacity: 0.4; } }
@keyframes px-in { from { --px: 0; opacity: 0.5; } to { --px: 1; opacity: 1; } }

/* The header holds still while pages crossfade into each other. */
@view-transition { navigation: auto; }
.site-head { view-transition-name: site-head; }
.announce { view-transition-name: announce; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 420ms; animation-timing-function: var(--ease); }

/* Motion off ------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  [data-tilt] { transform: none !important; transition: none; }
  [data-rise] { transition: none; }
  .rise-armed [data-rise]:not(.is-in) { opacity: 1; transform: none; }
  .flake-fill { animation: none; }
  .is-leaving, .is-entering { animation: none; -webkit-mask-image: none; mask-image: none; }
  .stage-poster img { transition: none; }
}
@media (forced-colors: active) {
  /* System colours over a picture cannot be guaranteed legible: no stage. */
  .stage-pin { display: none; }
  .glass { border: 1px solid CanvasText; }
  .flake-fill { -webkit-text-fill-color: CanvasText; background: none; }
  .stage-pause { border: 1px solid ButtonText; }
}
@media print {
  .stage, .stage-pause, .stage-dive { display: none; }
  .stage-shell { min-height: 0; }
}

/* The poster capture (?stage-still=1): only the stage, the copy hidden but
   laid out so the calm field matches the live first frame. */
html.stage-still body > :not(main), html.stage-still main > :not(.stage-shell),
html.stage-still .stage-shell > :not(.stage), html.stage-still .stage-shell > :not(.stage) * { visibility: hidden !important; }
html.stage-still .stage-poster { visibility: hidden; }
html.stage-still .stage-canvas { opacity: 1; transition: none; }
html.stage-still .stage-pin::after { display: none; }
