/* Veteran Vends — Fill the Machine, VIDEO build (video.html/js)
   Scroll-scrubbed Seedance clip + a persistent physics toy layer.
   Scarlet & Steel: Blackout #0A0908, Gunmetal #2B2723, Brushed Steel #C4B39F,
   Dress Silver #E9E4DC, Payton Tan #BA9971, Scarlet #B31005 */

* { margin: 0; padding: 0; box-sizing: border-box; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

:root {
  --blackout: #0A0908;
  --gunmetal: #2B2723;
  --steel: #C4B39F;
  --silver: #E9E4DC;
  --gold: #BA9971;
  --gold-hover: #CBAE8A;
  --gold-lift: #DAC9B3;
  --scarlet: #B31005;
}

html { background: var(--blackout); }
body {
  background: var(--blackout);
  color: var(--silver);
  font-family: "Inter", system-ui, sans-serif;
  overflow-x: hidden;
}

.hero { position: relative; }

.stage {
  position: relative;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: var(--blackout);
  /* dragging products around shouldn't rubber-band a text selection over the copy */
  user-select: none;
  -webkit-user-select: none;
  /* contains the glass layer's blend + sampling to the stage */
  isolation: isolate;
}

.machine {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  user-select: none;
  pointer-events: none;
  /* video.js writes --machine-x once per layout; the still, the video and the
     glass mark read the same offset, so they cannot drift apart. */
  transform: translateX(var(--machine-x, 0px));
}

/* ---- paint order ----
   Video build. The video is the machine now; the product pile is a toy layer
   that lives in front of it for the whole scroll and never flies anywhere.
     0 poster/fallback still   1 machine-stack (video + seam + darkener)
     2 etched glass mark       6 toy pile          4 mobile scrim
     8 copy                    9 hint
   machine-stack is isolated so the darkener flattens onto the clip; the mark
   then screens over that already-dimmed glass. The mark sits BELOW the pile:
   the products are out in the room in front of the door glass. */
.machine-stack {
  position: absolute;
  inset: 0;
  z-index: 1;
  isolation: isolate;
  pointer-events: none;
}
#machineEmpty  { z-index: 0; }
#heroVideo     { z-index: 1; }
.seam-blend    { z-index: 1; } /* later sibling: paints over the video */
.glass-darkener { z-index: 2; }
.glass-monogram { z-index: 2; }
.layer-fg      { z-index: 30; }

/* the video gets the identical cover-fit + shared offset the stills get */
#heroVideo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  user-select: none;
  pointer-events: none;
  transform: translateX(var(--machine-x, 0px));
}

/* Blackout feather over the clip's left field. The overlay is exactly zero
   wide when the layout has no horizontal offset, which matters on portraits. */
.seam-blend {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: calc(var(--machine-x, 0px) * 2);
  pointer-events: none;
  background: linear-gradient(90deg,
    var(--blackout) 0,
    var(--blackout) 50%,
    transparent 100%);
}

/* ---- product layers ---- */
.layer { position: absolute; inset: 0; }
#layerFg.layer-fg {
  position: fixed;
  inset: 0;
  z-index: 30;
  pointer-events: none;
}
.prod {
  position: absolute;
  left: 0; top: 0;
  visibility: hidden;
  will-change: transform;
  pointer-events: none;
  /* the toy pile is always out in the room, so the cast shadow is constant —
     nothing seats into the cabinet in this build */
  filter: drop-shadow(0 14px 24px rgba(0,0,0,0.55));
}
.prod img {
  display: block;
  width: 100%;
  height: 100%;
  -webkit-user-drag: none;
}

/* ---- finale: etched monogram on the door glass ----
   Two siblings share geometry (video.js layoutFinale). The darkener is a soft
   black pool with no mix-blend-mode; the mark screens over that dimmed glass.
   Pointer input writes the same --reveal-x/--reveal-y onto both. */
.glass-darkener,
.glass-monogram {
  position: absolute;
  left: 0; top: 0;
  width: 0; height: 0;
  display: block;
  visibility: hidden;
  pointer-events: none;
}
.glass-darkener {
  opacity: 0;
  transition: opacity 1s ease;
  will-change: opacity;
  background: radial-gradient(circle 140px at var(--reveal-x, 50%) var(--reveal-y, 50%),
    rgba(0,0,0,0.72) 0%,
    rgba(0,0,0,0.48) 32%,
    rgba(0,0,0,0.18) 68%,
    transparent 100%);
}
.glass-darkener.is-revealed {
  visibility: visible;
  opacity: 1;
  transition: opacity 0.2s ease;
}
.glass-monogram {
  overflow: hidden;
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 1s ease;
  will-change: opacity;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-image: radial-gradient(circle 140px at var(--reveal-x, 50%) var(--reveal-y, 50%),
    rgba(255,255,255,1) 0%, rgba(255,255,255,0.88) 32%,
    rgba(255,255,255,0.42) 68%, transparent 100%);
          mask-image: radial-gradient(circle 140px at var(--reveal-x, 50%) var(--reveal-y, 50%),
    rgba(255,255,255,1) 0%, rgba(255,255,255,0.88) 32%,
    rgba(255,255,255,0.42) 68%, transparent 100%);
}
.glass-monogram.is-revealed {
  visibility: visible;
  opacity: 0.9;
  transition: opacity 0.2s ease;
}
.glass-monogram img {
  display: block;
  width: 100%; height: 100%;
  object-fit: fill;
  pointer-events: none;
  opacity: 1;
  filter: grayscale(1) brightness(2.25) contrast(1.22);
}

/* ---- fixed corner mark ---- */
.corner-mark {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 20;
  width: 140px;
  height: 140px;
  aspect-ratio: 1;
  pointer-events: none;
  perspective: 600px;
  transform: translateZ(0);
  opacity: 1;
  transition: opacity 0.45s ease;
}
.corner-mark__frame {
  position: absolute;
  left: 50%; top: 50%;
  width: 104px;
  /* Payton's machine is portrait where the old double-V was landscape, so the
     frame follows it: 256/321 is the real ratio of mark-cabinet-256.png. Width
     is down from 110 because the taller shape would otherwise reach past the
     140px box the badge sits in. */
  aspect-ratio: 256 / 321;
  transform: translate(-50%, -50%);
  transform-style: preserve-3d;
}
.corner-mark__layer {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%; height: 100%;
  transform: rotateY(0deg);
  transform-origin: 50% 50%;
  backface-visibility: visible;
  will-change: transform;
}

/* ---- copy ---- */
.copy {
  position: absolute;
  left: clamp(24px, 6vw, 110px);
  top: 50%;
  transform: translateY(-54%);
  z-index: 8;
  max-width: 560px;
  pointer-events: none;
}
.copy .cta,
.copy .text-link { pointer-events: auto; }

.eyebrow {
  font-family: "Jost", sans-serif;
  font-weight: 500;
  font-size: clamp(11px, 1.1vw, 14px);
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--steel);
  display: flex;
  align-items: center;
  gap: 14px;
  white-space: nowrap;
}
/* the one scarlet accent in this viewport */
.eyebrow .rule {
  display: inline-block;
  width: 44px;
  height: 1px;
  background: var(--scarlet);
}

/* Black Ops One (Scott, 2026-08-16) — military stencil, HERO H1 ONLY. Single
   weight (400); the eyebrow, the mono subheader, section H2s and the nav all
   keep their own faces. The stencil is already shouty and runs wide, so the
   old 0.1em tracking came right down: at stencil scale the counters do the
   separating and wide tracking just breaks the words apart. Line-height opens
   a little because the caps are tall and the stacked triplet needs the air. */
.copy h1 {
  font-family: "Black Ops One", "Jost", sans-serif;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  /* Measured with the stencil at 0.03em: the longest sentence ("Modern
     convenience.") needs one line per 13.7px of type per 100px of column, so
     the 560px desktop column stays single-line up to ~40px. Capped well under
     that at 34px — three stencil lines at 40px would out-shout the machine. */
  font-size: clamp(26px, 2.5vw, 34px);
  line-height: 1.2;
  color: var(--silver);
  margin: 20px 0 18px;
}
/* Each sentence holds its own line; never break mid-thought. Where a sentence
   is too long for the column, balance splits it evenly instead of leaving an
   orphan ("...BEHIND / IT."). */
.copy h1 > span:not(.visually-hidden) {
  display: block;
  text-wrap: balance;
}

/* ---- hero subheader ----
   Replaced the .sub offer paragraph on 2026-08-16. Mono + wide tracking so it
   reads as a stamped line rather than body copy, and deliberately pitched
   between the eyebrow and the H1: larger and brighter than the eyebrow (which
   is Jost 11-14px steel/gold), smaller than the headline. subhead-scrub.js
   splits it into per-letter spans and flies them in against the hero clip's
   scrub position. */
.hero-subhead {
  font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  font-size: clamp(12px, 1.05vw, 15px);
  line-height: 1.5;
  color: #EFE7DA;
  margin: 18px 0 30px;
}
/* Three stacked lines (Scott 2026-08-18), one claim per line, flying in below
   the headline on desktop once the door has closed. nowrap is a guarantee, not
   an optimisation: a wrapped line would break the stack's rhythm and, on the
   phone layout below, would spill onto the machine. */
.hero-subhead__line {
  display: block;
  white-space: nowrap;
  line-height: 1.95;
}
/* Whole words stay together, so a wrap can never split one mid-letter. */
.hero-subhead__word {
  display: inline-block;
  white-space: nowrap;
}
/* The inter-word space is its own span; `pre` stops it collapsing between two
   inline-blocks. */
.hero-subhead__gap {
  display: inline-block;
  white-space: pre;
}
.hero-subhead__ch {
  display: inline-block;
}
/* Pre-JS and pre-first-frame the letters are invisible; the script paints
   opacity on every one of them from progress 0 onward. .is-static (reduced
   motion) never gets the letter spans at all, so it is unaffected. */
.hero-subhead.is-scrub .hero-subhead__ch {
  opacity: 0;
}

.cta {
  display: inline-block;
  font-family: "Jost", sans-serif;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  font-size: clamp(12px, 1.05vw, 14px);
  color: var(--blackout);
  background: var(--gold);
  padding: 16px 34px;
  text-decoration: none;
  transition: background 0.25s ease, transform 0.25s ease;
}
.cta:hover { background: var(--gold-hover); transform: translateY(-1px); }

/* ---- extras ---- */
.hint {
  position: absolute;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 9;
  font-family: "Jost", sans-serif;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  font-size: 11px;
  color: var(--steel);
  opacity: 0.8;
  animation: hintPulse 2.6s ease-in-out infinite;
}
.hint.is-done {
  animation: none;
  opacity: 0;
  transition: opacity 0.3s;
}
@keyframes hintPulse {
  0%, 100% { opacity: 0.45; transform: translateX(-50%) translateY(0); }
  50%      { opacity: 0.9;  transform: translateX(-50%) translateY(-6px); }
}

/* The .shake button ("Shake the machine") was retired 2026-08-16 — see
   shake-retired.js. Its markup and every rule that positioned it are gone;
   nothing was laid out against it (the call button owns bottom-left, the
   corner mark bottom-right, and the shake button merely sat clear of both). */

.after {
  min-height: 60vh;
  display: grid;
  place-items: center;
  color: var(--gunmetal);
  font-family: "Jost", sans-serif;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  font-size: 12px;
  background: var(--blackout);
}

/* ---- short-and-wide desktop ----
   The machine is parked right of centre, but below ~1080px the copy column and
   the shelf window still collide. The copy gives ground rather than the machine
   moving back, because the shelves are the whole point. Widths are set so the
   copy clears the shelf window's left edge (image fraction 0.405), not the
   cabinet's outer edge — overlapping the dark side panel is fine, it's near
   black. Verified down to 721px. */
@media (min-width: 861px) and (max-width: 1080px) {
  .copy { max-width: 380px; }
  .copy h1 { font-size: clamp(23px, 2.5vw, 27px); }
  .hero-subhead { font-size: 13px; letter-spacing: 0.2em; }
}
@media (min-width: 721px) and (max-width: 860px) {
  .copy { max-width: 330px; }
  .copy h1 { font-size: clamp(20px, 2.7vw, 23px); margin: 16px 0 14px; }
  .hero-subhead { font-size: 12px; letter-spacing: 0.18em; margin: 14px 0 24px; }
  .eyebrow { letter-spacing: 0.24em; }
  .cta { padding: 14px 26px; }
}

/* ---- mobile: copy sits above the pile, scrim keeps it readable ---- */
@media (max-width: 720px) {
  /* Bottom-RIGHT on phones, same corner as desktop. The call button owns
     the bottom-left corner on mobile (site.css). */
  .corner-mark {
    right: 12px;
    left: auto;
    bottom: 12px;
    width: 92px;
    height: 92px;
  }
  .corner-mark.is-faded {
    opacity: 0;
  }
  .corner-mark__frame { width: 68px; } /* height from aspect-ratio, no stretch */
  /* Scott 2026-08-16: the portrait hero encode centre-frames the machine, so a
     bottom-anchored copy block landed straight across the cabinet and the lit
     shelves. Phones now park the copy in the black air ABOVE the machine.
     Measured on the portrait clip at 390x844: the site header ends at y=80 and
     the machine's topmost lit pixel is at y=234, so the block gets the 84-228
     band and the headline is sized to fit it.
     site.css loads AFTER this file and its `@media (max-width: 860px)` rule
     sets `.copy { bottom: 224px }` at equal specificity, so this needs the
     .stage prefix to win — same trick as `.stage .copy .cta` below. */
  .stage .copy {
    left: 24px;
    right: 24px;
    top: calc(env(safe-area-inset-top, 0px) + 84px);
    bottom: auto;
    transform: none;
    max-width: none;
  }
  /* Black Ops One, measured in a 342px column at 0.03em: all three sentences
     hold one line each up to 25px ("Modern convenience." is the first to wrap,
     at 26px). The cap is 22px anyway — not a wrap limit but a VERTICAL one,
     since the block has to land above the cabinet at y=234 with the subheader
     under it. Three lines at 22px/1.16 is ~77px of type. */
  .copy h1 {
    font-size: clamp(18px, 5.6vw, 22px);
    line-height: 1.16;
    margin: 14px 0 0;
  }
  /* Scott 2026-08-18: the subheader is three stacked lines now and it lives in
     the black column to the LEFT of the machine, not in the band above it.
     Measured on the portrait encode by scanning the painted frame for the
     leftmost lit pixel: the cabinet's edge sits at x=142 at every height from
     y=225 down past y=640, so the strip from the 24px page margin to ~134 is
     black the whole way down. The clip is cover-fitted to HEIGHT, so that edge
     only moves right on shorter or wider phones — 375x812 is the tightest case
     and the width below is derived from it (50vw - 72px = 115px at 375, i.e.
     the margin to 6px shy of the cabinet).
     Absolutely positioned INSIDE .copy on purpose: .copy is the element the
     pinned/past-hero states put opacity:0 on, so a child fades with it. Moved
     out to .stage the stack would linger behind the overlay sections.
     top is measured off .copy's own height, so it tracks the headline at any
     type size instead of assuming one. The scrim is not extended down here —
     this strip is pure black and the text-shadow below carries readability. */
  .copy .hero-subhead {
    position: absolute;
    left: 0;
    /* Centred on the MACHINE, not hung off the headline above it (Scott
       2026-08-18 — it was sitting high and reading as an afterthought).
       49vh is measured, and it holds on every phone for free: the clip is
       cover-fitted to HEIGHT, so its full height always maps to the viewport
       height and any feature's vertical position is a fixed fraction of it.
       Scanned the painted frame row by row for the cabinet's lit body — it
       runs y=226 to y=575 at 375x812, so its middle is 400/812 = 49.3%.
       The subtraction cancels .copy's own top offset, which is what `top` is
       measured from here; translateY then centres the block on that line
       rather than starting it there. */
    /* svh, to match .stage's own `height:100svh` above. Mixing the two is a
       real iOS bug, not a nicety: vh is the LARGE viewport (chrome hidden) and
       svh the small one (chrome showing), so with the address bar up 49vh
       lands lower than 49% of the stage and the block drifts toward the
       machine. vh first as the fallback for anything without svh. */
    top: calc(49vh - 84px - env(safe-area-inset-top, 0px));
    top: calc(49svh - 84px - env(safe-area-inset-top, 0px));
    transform: translateY(-50%);
    margin: 0;
    /* 600 is a real cut, not a synthesised one — the weight was added to the
       Google Fonts link for this. Mono faces smear badly when faked. */
    font-weight: 600;
    /* The ceiling is the black strip's width, not taste: "FULLY SERVICED" is
       14 characters and IBM Plex Mono advances 0.6em, so the line measures
       14 x (0.6 + tracking) x size. At 12px/0.08em that is 114px against the
       118px between the page margin and the cabinet edge at 375x812 — the
       tightest phone there is, since the edge only moves right on wider or
       shorter ones. Bigger than this and it touches the machine. */
    font-size: clamp(11.5px, 3.15vw, 13px);
    letter-spacing: 0.08em;
  }
  /* The block is three short lines in a 350px-tall column, so the air between
     them is what fills the space — opening the leading does more here than
     more type size could, and it keeps the stamped-list read. */
  .copy .hero-subhead__line { line-height: 2.9; }
  /* The offer paragraph is the single biggest block of text on the phone hero
     and it sat straight over the lit shelves. It is no longer in the hero at
     all — the H1 is now followed by the scroll-synced subheader — and the same
     sentences live on in .hero-offer-mobile, the first thing read after the
     hero on phones (site.css). */
  /* Scott 2026-08-15: phone hero is eyebrow + H1 only. Button and link cut;
     the offer block + form CTAs below the hero carry the conversion path. */
  .copy .text-link { display: none; }
  /* site.css loads after this file and re-sets display on .copy .cta,
     so the hide needs the extra specificity. */
  .stage .copy .cta { display: none; }

  /* Scrim. A soft blackout pool that lives INSIDE .copy: it feathers out on
     every edge (no card), tracks the copy block at any font size, and inherits
     the opacity:0 the pinned/past-hero states put on .copy, so it can never
     linger behind the overlay sections. z-index:-1 stays inside .copy's own
     stacking context (position:absolute + z-index:8), i.e. above the video and
     below the words.
     Retuned for the top-anchored copy, then again when the subheader joined
     the block (2026-08-16). The copy now ends at y≈219 against a cabinet top
     of 234, so the bottom overhang is down to -6px: any more and the pool
     spills onto the machine. The subheader itself needs no scrim — it sits on
     pure black above the cabinet — so readability there comes from the
     per-letter text-shadow below rather than from widening this. */
  .copy::before {
    content: "";
    position: absolute;
    z-index: -1;
    left: -24px;
    right: -24px;
    top: -46px;
    bottom: -6px;
    pointer-events: none;
    /* Both layers must reach alpha 0 strictly inside the box, or the box edge
       itself shows up as a seam across the machine. */
    background:
      radial-gradient(150% 60% at 40% 58%,
        rgba(6, 5, 5, 0.30) 0%,
        rgba(6, 5, 5, 0.22) 44%,
        rgba(6, 5, 5, 0.08) 66%,
        rgba(6, 5, 5, 0) 82%),
      linear-gradient(180deg,
        rgba(6, 5, 5, 0) 0%,
        rgba(6, 5, 5, 0.34) 10%,
        rgba(6, 5, 5, 0.56) 26%,
        rgba(6, 5, 5, 0.58) 52%,
        rgba(6, 5, 5, 0.54) 76%,
        rgba(6, 5, 5, 0.26) 90%,
        rgba(6, 5, 5, 0) 100%);
  }
  /* Second line of defence for the moments a bright bag scrubs through the
     softest part of the pool. */
  .copy .eyebrow,
  .copy h1,
  .copy .hero-subhead,
  .copy .text-link {
    text-shadow: 0 1px 14px rgba(6, 5, 5, 0.9), 0 0 4px rgba(6, 5, 5, 0.7);
  }
  /* Steel eyebrow vanished into the lit shelves; a lifted accent reads as the
     accent it was meant to be. Token, not a literal, so it follows --gold. */
  .copy .eyebrow {
    color: var(--gold-lift);
    letter-spacing: 0.26em;
  }
  .copy .cta { text-shadow: none; }
  .hint { bottom: 14px; }
  .stage::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 46%;
    z-index: 7;
    pointer-events: none;
    background: linear-gradient(180deg, transparent, rgba(10, 9, 8, 0.78) 62%);
  }
}

/* ---- short phones (SE / 8-class, ~667-740px tall) ----
   The portrait clip is cover-fitted, so the shorter the viewport the LARGER
   and higher the machine sits: its top edge measures y=225 at 375x812 but
   y=185 at 375x667. The four-line headline collided with the second; the
   two-line one clears it with room to spare (measured 74-152 against a machine
   top of 185), so this block no longer shrinks the type or the eyebrow at all
   — it just lifts the block 10px to keep the air under it looking deliberate.
   Width query is repeated because a media query cannot inherit one. */
@media (max-width: 720px) and (max-height: 740px) {
  /* Header ends at y=64 here, and the cabinet starts at 185 — 121px for the
     whole block once the subheader joined it, against ~130px at the tall-phone
     sizes. So this is now a real scale-down, not just a nudge: everything is
     pulled in proportionally so the block lands ~176 and keeps ~9px of black
     under it. Verified at 375x667. */
  .stage .copy { top: calc(env(safe-area-inset-top, 0px) + 70px); }
  .copy .eyebrow {
    font-size: 10px;
    letter-spacing: 0.24em;
  }
  .copy h1 {
    font-size: clamp(13px, 4.3vw, 16px);
    line-height: 1.16;
    margin: 10px 0 0;
  }
  /* The clip is cover-fitted to height, so a shorter viewport pushes the
     cabinet's left edge RIGHT (x=150 at 375x667 vs 142 at 375x812) — the strip
     is wider here, not narrower. Only the offset needs pulling in, to keep the
     stack clear of the machine's top corner on the tighter layout. */
  /* Same 49vh line; only the offset being cancelled changes, because .copy
     is pulled up to 70px on short phones. */
  .copy .hero-subhead {
    top: calc(49vh - 70px - env(safe-area-inset-top, 0px));
    top: calc(49svh - 70px - env(safe-area-inset-top, 0px));
  }
  .copy::before { bottom: -4px; }
}

/* ---- narrow phones (360px Android and down) ----
   The black strip left of the machine is set by the clip's cover-fit, so it
   narrows with the viewport: ~104px at 360 wide, ~98px at 320 (SE 1). Type and
   tracking come down together so "FULLY SERVICED" still holds one line inside
   it — 9px/0.07em measures 86px.
   Breakpoint is 365px, not the 380px the one-line sentence used: 375 is the
   SE 2 / 8 / 13 mini width and it has room for the full 10px setting. */
@media (max-width: 365px) {
  /* Only the tracking gives way here. The base clamp already bottoms out at
     11.5px, and at 0.08em that measures 109px against the 113px this column
     has at 360 wide — too close. 0.06em brings it to 106px and back in line
     with the ~6px clearance every other phone size gets. */
  .copy .hero-subhead { letter-spacing: 0.06em; }
}

/* ---- reduced motion: static full machine ---- */
@media (prefers-reduced-motion: reduce) {
  .hint { display: none !important; }
  /* snacks stay visible; they settle at the bottom edge (video.js) */
  #heroVideo, .glass-monogram, .glass-darkener, .seam-blend { display: none !important; }
  .corner-mark__layer { will-change: auto; }
}

/* ---- sticky CTA (top-right: clears the bottom-right corner mark) ---- */
.sticky-cta {
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 30;
  font-family: "Jost", sans-serif;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  font-size: 11px;
  color: var(--blackout);
  background: #6B4518;
  padding: 10px 16px;
  text-decoration: none;
  opacity: 0.85;
  transition: opacity 0.45s ease, background 0.25s ease;
}
.sticky-cta.is-ready,
.sticky-cta:hover,
.sticky-cta:focus-visible {
  opacity: 1;
  background: var(--gold);
}
.sticky-cta:hover { background: var(--gold-hover); }

/* After the 550% scrub pin releases, keep the stage covering the viewport
   so overlay cards have hero at the edges. Does not change the hero ST. */
.stage.is-page-pinned {
  position: fixed !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100vh !important;
  height: 100svh !important;
  z-index: 1;
  /* GSAP pin leaves translate(0, pinDistance) inline; that would park the
     fixed stage below the viewport (solid black page). Kill it. */
  transform: none !important;
}
/* Hero headline would otherwise peek through the gaps between cards. */
.stage.is-page-pinned .copy,
.stage.is-page-pinned .hint {
  opacity: 0;
  pointer-events: none;
}

/* After #worlds arrives, fade the pinned stage out so it stops painting
   behind every later section. Visibility flips after the fade so the
   layer drops out of compositing. Reverse is clean on scroll-back. */
.stage {
  transition: opacity 0.6s ease, visibility 0s linear 0s;
}
body.past-hero .stage {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.6s ease, visibility 0s linear 0.6s;
}

/* Unused leftover from the absolute overlay stack. Height comes from the
   sections themselves now. */
.site-runway {
  display: none;
}

/* Content wrapper in normal flow, after the hero pin-spacer. Overlap
   retired: sections no longer rise over the machine. Ground is Blackout
   so the stage fade cannot flash white behind #worlds. */
.site-layer {
  position: relative;
  z-index: 12;
  pointer-events: none;
  margin-top: calc(-1 * var(--scrub-overlap, 0px));
  background-color: #0A0908;
}
.site-layer > * { pointer-events: auto; }
.site-layer .section-spacer { pointer-events: none; }

.overlay-card {
  position: relative;
  display: block;
  margin: 7vh 5.5vw 8vh;
  overflow: visible;
  pointer-events: auto;
  scroll-margin-top: 80px;
  background: transparent;
  border: none;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  padding: clamp(28px, 4.2vw, 56px) clamp(22px, 4vw, 52px);
  color: var(--silver);
  transform: none;
  opacity: 1;
}

/* Default is identity so off-screen cards are never parked. .is-in plays
   a one-shot rise; after it ends the computed transform is none again. */
@keyframes overlay-rise {
  from { opacity: 0; transform: translateY(60px); }
  to   { opacity: 1; transform: none; }
}
html.js-overlays .overlay-card.is-in {
  animation: overlay-rise 0.7s ease;
}

/* Black Ops One site-wide on display headings (Scott, 2026-08-18). The hero H1
   set the face; every section headline now matches it on phone and desktop.
   Deliberately NOT applied to body copy, buttons, nav or the small mono h3
   labels — stencil is a short-line face and paragraphs in it stop scanning.
   Sizes come down ~15% from the Jost settings because the stencil reads larger
   at the same px and runs wider, and tracking drops to 0.03em for the same
   reason the hero's did (the counters do the separating at stencil scale). */
.overlay-card h2 {
  font-family: "Black Ops One", "Jost", sans-serif;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: clamp(23px, 2.9vw, 40px);
  line-height: 1.12;
  color: var(--silver);
  max-width: 18ch;
  margin-bottom: 22px;
}

.overlay-prose {
  max-width: 62ch;
}
.overlay-prose--narrow { max-width: 52ch; }
.overlay-prose p,
.who-copy p,
.fit-block p {
  font-size: clamp(15px, 1.25vw, 18px);
  line-height: 1.6;
  color: var(--steel);
  margin-bottom: 14px;
}

/* About (#who): looping sunrise sits behind the existing photo + copy.
   Card chrome (border, padding, glass fill) is unchanged; overflow clips
   the cover-fit clip to the card box. Reduced-motion hides .who-bg so the
   static rgba card look is what remains. */
#who {
  overflow: hidden;
}
.who-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.who-bg video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.who-bg-dim {
  position: absolute;
  inset: 0;
  background: rgba(10, 9, 8, 0.60);
}
#who > h2,
#who > .who-grid {
  position: relative;
  z-index: 1;
}

.who-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(20px, 3vw, 48px);
  align-items: center;
}
.who-photo {
  margin: 0;
  overflow: hidden;
  border: 1px solid rgba(196, 179, 159, 0.22);
  background: var(--gunmetal);
}
.who-photo img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 62vh;
  object-fit: cover;
  object-position: center top;
}
.who-close {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 13px !important;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold) !important;
  margin-top: 8px;
}

/* Spec-sheet steps */
.spec-steps {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px 28px;
  margin: 32px 0 36px;
  padding: 22px 0;
  border-top: 1px solid rgba(196, 179, 159, 0.16);
  border-bottom: 1px solid rgba(196, 179, 159, 0.16);
}
.spec-index {
  display: block;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 8px;
}
.spec-steps h3,
.machine-card h3,
.fit-block h3 {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--silver);
  margin-bottom: 8px;
}
.spec-steps p,
.machine-card p {
  font-size: 14px;
  line-height: 1.55;
  color: var(--steel);
}

.machine-grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}
.machine-card {
  background: rgba(43, 39, 35, 0.55);
  border: 1px solid rgba(196, 179, 159, 0.14);
}
.machine-card img {
  display: block;
  width: 100%;
  height: 140px;
  object-fit: cover;
}
.machine-card h3,
.machine-card p { padding: 0 14px; }
.machine-card h3 { margin-top: 12px; }
.machine-card p { padding-bottom: 16px; }

.area-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(20px, 3vw, 40px);
  align-items: start;
}
.area-map {
  margin: 0;
  border: 1px solid rgba(196, 179, 159, 0.18);
  background: var(--gunmetal);
}
.area-map img {
  display: block;
  width: 100%;
  height: auto;
}
.fit-block {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid rgba(196, 179, 159, 0.16);
}

.review-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin-top: 28px;
}
.review-card {
  background: rgba(43, 39, 35, 0.55);
  border: 1px solid rgba(196, 179, 159, 0.14);
  padding: 18px 16px;
}
.review-card p {
  font-size: 15px;
  line-height: 1.55;
  color: var(--silver);
  margin-bottom: 14px;
}
.review-card cite {
  display: block;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-style: normal;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--steel);
}

.place-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 18px;
  max-width: 640px;
  margin-top: 28px;
}
.place-form label {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--steel);
}
.place-form__wide { grid-column: 1 / -1; }
.place-form input,
.place-form select,
.place-form textarea {
  font-family: "Inter", system-ui, sans-serif;
  font-size: 16px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--silver);
  background: rgba(10, 9, 8, 0.65);
  border: 1px solid rgba(196, 179, 159, 0.28);
  padding: 12px 14px;
  border-radius: 0;
  pointer-events: auto;
}
.place-form textarea {
  min-height: 5.5em;
  resize: vertical;
}
.place-form input:focus,
.place-form select:focus,
.place-form textarea:focus {
  outline: 1px solid var(--gold);
  border-color: var(--gold);
}
.place-form button {
  grid-column: 1 / -1;
  justify-self: start;
  font-family: "Jost", sans-serif;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  font-size: 13px;
  color: var(--blackout);
  background: var(--gold);
  border: 0;
  padding: 16px 34px;
  cursor: pointer;
  margin-top: 6px;
  pointer-events: auto;
}
.place-form button:hover { background: var(--gold-hover); }

.overlay-card--footer {
  position: relative;
  z-index: 12;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 0;
  padding-bottom: 48px;
  pointer-events: auto;
}
.site-layer .overlay-card:last-child {
  margin-bottom: 0;
}
.footer-wordmark {
  font-family: "Jost", sans-serif;
  font-weight: 600;
  font-size: clamp(22px, 3vw, 36px);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--silver);
}
.footer-tag { color: var(--steel); font-size: 15px; }
.overlay-card--footer a {
  color: var(--gold);
  text-decoration: none;
  letter-spacing: 0.04em;
}
.overlay-card--footer a:hover { text-decoration: underline; }
.footer-copy {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--steel);
  margin-top: 12px;
}

@media (max-width: 980px) {
  .who-grid,
  .area-grid,
  .machine-grid,
  .spec-steps,
  .review-grid {
    grid-template-columns: 1fr 1fr;
  }
  .spec-steps { grid-template-columns: 1fr; }
  .machine-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 720px) {
  .sticky-cta {
    top: 12px;
    right: 12px;
    font-size: 10px;
    padding: 9px 12px;
  }
  .overlay-card {
    margin: 56px 12px 28px;
    padding: 22px 18px 28px;
  }
  .who-grid,
  .area-grid,
  .machine-grid,
  .review-grid,
  .place-form {
    grid-template-columns: 1fr;
  }
  .who-photo img { max-height: 42vh; }
  .overlay-card h2 { max-width: none; }
  .machine-card img { height: 160px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  body.past-hero .stage {
    transition: none;
  }
  .sticky-cta { opacity: 1; background: var(--gold); }
  /* Never show the sunrise loop; keep the current static card fill. */
  #who .who-bg { display: none; }
  .stage.is-page-pinned {
    position: relative !important;
    inset: auto !important;
    width: auto !important;
    height: 100vh !important;
    height: 100svh !important;
  }
  html.js-overlays .overlay-card.is-in {
    animation: none;
  }
  .overlay-card,
  html.js-overlays .overlay-card {
    transform: none !important;
    opacity: 1 !important;
  }
}
