/* ── /hardware — pinned instrument stage + editorial column ───────────────── */

/* The stage is a fixed, full-viewport canvas sitting *under* the editorial
   column. Two rules follow from that, and both were wrong before:
   1. Anything stacked above the canvas must not blanket it, or a drag never
      reaches it. So .hw is transparent to the pointer and only its text
      blocks opt back in — which leaves the whole right half live for drag.
   2. Anything beside the canvas must stack above it, or the canvas silently
      eats the clicks. The footer is a sibling of <main> at z-index auto, so it
      sat *under* the canvas and its links were unclickable (grab cursor). The
      nav was always fine — site.css already gives it z-index 50. */
.hw { position: relative; z-index: 2; pointer-events: none; }
.hw-panel, .hw-hero > *, .hw-close > * { pointer-events: auto; }
body > .site-footer { position: relative; z-index: 3; }

/* ── the pinned canvas ────────────────────────────────────────────────────── */
.stage-wrap {
  position: fixed; inset: 0; z-index: 1; pointer-events: none;
  opacity: 0; transition: opacity 700ms ease;
}
.stage-ready .stage-wrap { opacity: 1; }
.stage-out .stage-wrap, .stage-out #stage { opacity: 0; pointer-events: none; }
#stage {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: auto; cursor: grab; touch-action: pan-y;
}
#stage.grabbing { cursor: grabbing; }
.callout-layer { position: absolute; inset: 0; pointer-events: none; }
.callout-leaders { position: absolute; inset: 0; overflow: visible; }
.callout-leaders .leader {
  fill: none; stroke: rgba(0,190,90,.55); stroke-width: 1;
  stroke-dasharray: 2 3; opacity: 0; transition: opacity 300ms ease 120ms;
}
.callout-layer.settled .leader { opacity: 1; }
.callout-leaders .leader.hidden { opacity: 0; }

.callout {
  position: absolute; top: 0; left: 0; max-width: 176px;
  padding: 6px 10px; border-radius: 7px;
  background: rgba(7,15,7,.86); border: 1px solid rgba(0,190,90,.24);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  opacity: 0; transition: opacity 300ms ease;
  will-change: transform;
}
.callout-layer.settled .callout { opacity: 1; }
.callout-layer.settled .callout:nth-child(2) { transition-delay: 60ms; }
.callout-layer.settled .callout:nth-child(3) { transition-delay: 120ms; }
.callout-layer.settled .callout:nth-child(4) { transition-delay: 180ms; }
.callout.hidden { opacity: 0 !important; }
.callout b {
  display: block; font-family: var(--font-sans); font-weight: 600;
  font-size: 12px; letter-spacing: -.01em; color: var(--text); line-height: 1.25;
}
.callout em {
  display: block; font-style: normal; font-size: 10.5px; line-height: 1.35;
  color: var(--text-mute); margin-top: 2px;
}

.stage-hint {
  position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
  font-family: var(--font-sans); font-weight: 700; font-size: 9.5px;
  text-transform: uppercase; letter-spacing: .18em; color: var(--text-mute);
  opacity: .65;
}

/* ── the editorial column ─────────────────────────────────────────────────── */
.hw-hero, .hw-unit, .hw-close { position: relative; padding: 0 clamp(24px, 5vw, 56px); }

.hw-hero {
  /* Anchored to the top, not vertically centred. Centring put the headline in
     the middle of the first screen, so the stage on the right began switching
     the moment the page moved at all. Sitting high leaves the three-up hero
     room to hold while the intro is read. */
  min-height: 100svh; display: flex; flex-direction: column; justify-content: flex-start;
  max-width: 760px; padding-top: clamp(104px, 12vh, 146px); padding-bottom: 64px;
}
.hw-hero h1 {
  font-family: var(--font-sans); font-weight: 800;
  font-size: clamp(46px, 8vw, 96px); letter-spacing: -.05em; line-height: .96;
  color: var(--text); margin: 0 0 22px;
}
.hw-hero .lede {
  font-size: clamp(17px, 1.9vw, 21px); line-height: 1.62; color: var(--text-dim);
  letter-spacing: -.012em; max-width: 620px; margin: 0 0 40px;
}
.eyebrow {
  display: inline-flex; align-items: center; gap: 9px; margin: 0 0 20px;
  font-family: var(--font-sans); font-weight: 700; font-size: 10.5px;
  text-transform: uppercase; letter-spacing: .16em; color: var(--accent);
}
.eyebrow .dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 3px rgba(0,190,90,.16); animation: hwPulse 2.6s ease-in-out infinite;
}
@keyframes hwPulse { 0%,100%{box-shadow:0 0 0 3px rgba(0,190,90,.16)} 50%{box-shadow:0 0 0 6px rgba(0,190,90,.04)} }
.scroll-cue {
  display: inline-flex; align-items: center; gap: 8px; margin: 0;
  font-family: var(--font-sans); font-weight: 700; font-size: 10px;
  text-transform: uppercase; letter-spacing: .18em; color: var(--text-mute);
}
.scroll-cue svg { animation: hwCue 2.2s ease-in-out infinite; }
@keyframes hwCue { 0%,100%{transform:translateY(0);opacity:.5} 50%{transform:translateY(4px);opacity:1} }

/* each unit gets room so the stage can settle on it */
.hw-unit { padding-top: 14vh; padding-bottom: 14vh; }
.hw-close { padding-top: 10vh; padding-bottom: 14vh; }

.hw-panel {
  max-width: 560px;
  background: linear-gradient(180deg, rgba(9,18,10,.90) 0%, rgba(7,15,7,.94) 100%);
  border: 1px solid rgba(255,255,255,.07);
  border-radius: 16px;
  padding: clamp(28px, 4vw, 44px);
  backdrop-filter: blur(14px) saturate(1.2); -webkit-backdrop-filter: blur(14px) saturate(1.2);
  box-shadow: 0 30px 80px rgba(0,0,0,.5);
}

.unit-num {
  font-family: var(--font-mono, var(--font-sans)); font-weight: 700; font-size: 11px;
  letter-spacing: .2em; color: var(--text-mute); margin: 0 0 14px;
}
.unit-kicker {
  font-family: var(--font-sans); font-weight: 700; font-size: 10.5px;
  text-transform: uppercase; letter-spacing: .16em; margin: 0 0 10px;
}
.unit-kicker.s-green { color: #00BE5A; }
.unit-kicker.s-gold  { color: #FFC800; }
.unit-kicker.s-cyan  { color: #32C8FF; }
.unit-kicker.s-magenta { color: #E682E6; }   /* Listener — matches its hue in the 3D stage */
.unit-kicker.s-orange  { color: #FF8C42; }   /* Survey Unit */

/* R&D badge. Rides the h2 rather than sitting above it, so the qualifier cannot
   be read separately from the product name — including by anyone skimming.
   Sized off the heading so it stays proportional as the h2 clamps. */
.unit-badge {
  display: inline-block; vertical-align: middle;
  margin-left: .5em; transform: translateY(-.16em);
  padding: .34em .72em; border-radius: 999px; white-space: nowrap;
  font-family: var(--font-sans); font-weight: 700;
  font-size: clamp(10px, 1.05vw, 12px); letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-dim);
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.18);
}

/* the qualifier in full, at the foot of an R&D panel */
.unit-rnd {
  font-size: 12.5px; line-height: 1.6; color: var(--text-mute);
  margin: 18px 0 0; padding-top: 16px; border-top: 1px solid var(--line-soft);
}

.hw-panel h2 {
  font-family: var(--font-sans); font-weight: 800;
  font-size: clamp(30px, 4.2vw, 46px); letter-spacing: -.042em; line-height: 1.04;
  color: var(--text); margin: 0 0 18px;
}
.unit-line {
  font-size: clamp(16px, 1.7vw, 19px); line-height: 1.58; letter-spacing: -.012em;
  color: var(--text); margin: 0 0 22px;
}
.unit-body {
  font-size: 15.5px; line-height: 1.72; color: var(--text-dim);
  letter-spacing: -.006em; margin: 0 0 16px;
}
.unit-body a { color: var(--accent); }

.hw-cta { display: flex; flex-wrap: wrap; gap: 12px; margin: 26px 0 22px; }
.hw-note {
  font-size: 12.5px; line-height: 1.6; color: var(--text-mute);
  padding-top: 18px; border-top: 1px solid var(--line-soft); margin: 0;
}

/* ── responsive ───────────────────────────────────────────────────────────── */
@media (min-width: 1100px) {
  /* text sits left, the instrument owns the right half of the viewport */
  .hw-hero, .hw-unit, .hw-close { padding-left: clamp(40px, 7vw, 96px); }
  .hw-hero { max-width: 620px; }        /* keep the headline clear of the stage */
  .stage-wrap { left: 42%; }
}
/* ── mobile: a scroll-through deck, not a pinned stage ──────────────────────
   The pinned canvas is a desktop idea — it assumes a column of text beside a
   column of space. A phone has one column, so below 1100px each instrument gets
   its own screen: a full-bleed render band at the top, its copy beneath, and
   the next unit a swipe away.

   The stage stays a single FIXED canvas rather than one per card. Every card is
   the same height and snaps to the same place, so the render band is always at
   the same point in the viewport — which means one canvas can serve all five
   without moving any DOM. Five WebGL contexts on a phone would be five too many.

   Pattern follows hardware-catalogue's mc- block: full-bleed viz, a fade that
   dissolves the render into the copy so there is no seam, and a reveal that is
   PERMANENT once triggered, so text never fades back out while it is being read.
   ────────────────────────────────────────────────────────────────────────── */
@media (max-width: 1099px) {
  .hw { scroll-snap-type: y proximity; }

  .hw-unit {
    min-height: 100svh;
    scroll-snap-align: start; scroll-snap-stop: normal;
    display: flex; flex-direction: column; justify-content: flex-start;
    padding-top: 52svh;          /* clears the render band */
    padding-bottom: 6vh;
  }
  /* The hero sits high on a phone. The desktop top padding is sized to clear a
     stage that is not there at this width, and it pushed the headline into the
     middle of the screen with a third of the viewport empty above it. */
  .hw-hero {
    min-height: auto; scroll-snap-align: start;
    padding-top: 44px; padding-bottom: 12vh;
  }
  .hw-hero h1 { font-size: clamp(42px, 12vw, 62px); margin-bottom: 18px; }
  .hw-hero .lede { font-size: clamp(16px, 4.4vw, 18px); margin-bottom: 30px; }
  .hw-close { scroll-snap-align: start; padding-top: 8vh; }

  /* The render band. Its background is OPAQUE, not transparent, and that is
     load-bearing: cards are taller than one screen, so the copy of the card you
     are leaving scrolls up behind the band. Without a mask it appeared above the
     next instrument as a stray half-line. Solid to 74%, then dissolving into the
     copy below so the render has no hard edge. */
  .stage-wrap {
    top: 0; bottom: auto; height: 56svh;
    background: linear-gradient(180deg,
      var(--bg, #070F07) 0%, var(--bg, #070F07) 74%, rgba(7,15,7,0) 100%);
  }
  #stage { position: absolute; top: 12svh; left: 0; right: 0; height: 40svh; }
  /* the hero has no room for a stage beside it on a phone — it would sit on top
     of the headline, which is exactly what it was doing */
  .hw-hero-active .stage-wrap { opacity: 0; }
  /* the render must never swallow a swipe — the page has to keep scrolling
     with a finger anywhere on it */
  #stage { pointer-events: none !important; touch-action: auto; cursor: default; }
  .stage-hint { display: none; }
  .callout, .callout-leaders { display: none; }

  .hw-panel {
    max-width: none; margin: 0;
    background: none; border: none; box-shadow: none;
    backdrop-filter: none; -webkit-backdrop-filter: none;
    padding: 0 4px;
  }
  /* The reveal, scoped to .hw-unit ONLY. .hw-close carries a .hw-panel too, and
     an unscoped rule hid it at opacity 0 forever — nothing ever adds .shown to
     it, because the observer watches [data-instrument] sections. The whole
     closing section, CTA included, was invisible on every phone. */
  .hw-unit .hw-panel > * { opacity: 0; transform: translateY(18px);
    transition: opacity .55s ease, transform .6s cubic-bezier(.2,.75,.25,1); }
  .hw-unit.shown .hw-panel > * { opacity: 1; transform: none; }
  .hw-unit.shown .hw-panel > :nth-child(1) { transition-delay: .04s }
  .hw-unit.shown .hw-panel > :nth-child(2) { transition-delay: .09s }
  .hw-unit.shown .hw-panel > :nth-child(3) { transition-delay: .14s }
  .hw-unit.shown .hw-panel > :nth-child(4) { transition-delay: .19s }
  .hw-unit.shown .hw-panel > :nth-child(5) { transition-delay: .24s }
  .hw-unit.shown .hw-panel > :nth-child(6) { transition-delay: .29s }
  .hw-unit.shown .hw-panel > :nth-child(7) { transition-delay: .34s }

  .unit-num { margin-bottom: 8px; }
  .hw-panel h2 { font-size: clamp(30px, 8.6vw, 42px); margin-bottom: 14px; }
  .unit-line { font-size: clamp(16px, 4.4vw, 18px); margin-bottom: 16px; }
  .unit-body { font-size: 15px; margin-bottom: 13px; }
}

@media (prefers-reduced-motion: reduce) {
  .hw-unit .hw-panel > * { opacity: 1 !important; transform: none !important; transition: none !important; }
}

@media (max-width: 640px) {
  .hw-panel { padding: 24px 20px; border-radius: 13px; }
}
@media (prefers-reduced-motion: reduce) {
  .eyebrow .dot, .scroll-cue svg { animation: none; }
  .stage-wrap { transition: none; }
}

/* at-a-glance facts strip (replaces the old spec tables) */
.unit-facts {
  list-style: none; margin: 26px 0 0; padding: 20px 0 0;
  border-top: 1px solid var(--line-soft);
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
}
.unit-facts li { display: flex; flex-direction: column; gap: 3px; }
.unit-facts b {
  font-family: var(--font-sans); font-weight: 700;
  font-size: clamp(17px, 2vw, 21px); letter-spacing: -.03em; color: var(--text);
  line-height: 1.1;
}
.unit-facts span {
  font-family: var(--font-sans); font-weight: 600; font-size: 10px;
  text-transform: uppercase; letter-spacing: .12em; color: var(--text-mute);
}
@media (max-width: 640px) { .unit-facts { grid-template-columns: 1fr 1fr; gap: 14px; } }
