/* =========================================================================
   Bullfinch. Outside read. (v8)
   Single column, baseline 8px grid, true light / true dark.
   No decorative SVG, no gradients in UI, no nature tint in UI.
   Locked panel heights with CSS Grid. Verdict sized by both vw AND vh.
   ========================================================================= */

/* ---- Reset -------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html,
body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
figure,
blockquote,
dl,
dd {
  margin: 0;
}
html {
  -webkit-text-size-adjust: 100%;
  -moz-text-size-adjust: 100%;
  text-size-adjust: 100%;
  overflow-x: hidden;
}
body {
  min-height: 100vh;
  min-height: 100lvh;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img,
picture,
svg,
canvas,
video {
  display: block;
  max-width: 100%;
}
button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
:focus-visible {
  outline: 1px solid color-mix(in srgb, var(--accent) 60%, transparent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---- Theme tokens ------------------------------------------------------- */
:root,
[data-theme="dark"] {
  --bg: #050505;
  --bg-elev: #0E0E0E;
  --ink: #FAFAFA;
  --ink-soft: #8E8E8E;
  --ink-quiet: #5A5A5A;
  --accent: #FF5560;
  --rule: rgba(250, 250, 250, 0.08);
  --gl-canopy: #6F6F6A;       /* cooler upper cloud field in dark mode */
  --gl-understory: #020202;   /* near-black forest floor */
  --gl-light-shaft: #E6D5B0;
  --gl-mote: #C8C2B5;          /* warm light gray, no longer cream-white */
  --gl-line: rgba(250, 250, 250, 0.55);
  --gl-accent: #FF5560;
  --text-veil-bg-strong: 34%;
  --text-veil-bg-soft: 18%;
  --text-veil-blur: 24px;
  --text-veil-saturate: 0.88;
  --text-veil-opacity: 0.84;
}

/* ---- Theme transitions -------------------------------------------------- */
html,
body {
  background-color: var(--bg);
  color: var(--ink);
  transition:
    background-color 400ms ease,
    color 400ms ease;
}
.panel__verdict,
.panel__eyebrow,
.panel__numeric,
.panel__evidence p,
.lead,
.site-footer__line,
.fullscreen-toggle {
  transition:
    background-color 400ms ease,
    border-color 400ms ease,
    color 400ms ease;
}
@media (prefers-reduced-motion: reduce) {
  html,
  body,
  * {
    transition: none !important;
  }
}

/* ---- Typography --------------------------------------------------------- */
:root {
  --font-display: "Geist", "Inter Display", "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-body: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --fs-body: 17px;
  --measure: 60ch;
  --col-narrow: 880px;
  --pad-x: 64px;
}
@media (max-width: 720px) {
  :root {
    --fs-body: 16px;
    --pad-x: 24px;
  }
}

html {
  font-family: var(--font-body);
  font-size: var(--fs-body);
}
body {
  font-family: var(--font-body);
  font-weight: 400;
  position: relative;
  z-index: 0;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 500;
  text-wrap: balance;
  letter-spacing: -0.025em;
  line-height: 1.04;
}

p {
  text-wrap: pretty;
}

#page {
  position: relative;
  z-index: 2;
}

/* ---- Website nav ------------------------------------------------------- */
.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  padding: 24px var(--pad-x);
  color: var(--ink-quiet);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(-8px);
  pointer-events: none;
  transition:
    color 400ms ease,
    opacity 420ms ease,
    transform 420ms ease;
}
/* Nav stays hidden on the hero until the first scroll, then fades in. */
body.has-entered.has-scrolled .site-nav {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.site-nav__brand,
.site-nav__links {
  display: inline-flex;
  align-items: center;
}
.site-nav__brand {
  gap: 12px;
}
.site-nav__mark {
  width: 26px;
  height: auto;
  flex: 0 0 auto;
  opacity: 0.72;
}
.site-nav__hover-label {
  position: absolute;
  top: 26px;
  left: 50%;
  color: var(--ink-quiet);
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, -2px);
  transition:
    color 200ms ease,
    opacity 200ms ease,
    transform 200ms ease;
  white-space: nowrap;
}
.site-nav__hover-label.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}
.site-nav__links {
  gap: 24px;
}
.site-nav a {
  color: var(--ink-quiet);
  transition: color 200ms ease, opacity 200ms ease;
}
/* Real-hover devices only, so a tap on touch doesn't leave the number stuck
   lit (sticky :hover). The lit state on touch comes from .is-current below. */
@media (hover: hover) {
  .site-nav a:hover {
    color: var(--ink);
  }
}
/* Scroll-spy: the link for the section currently in view stays lit. */
.site-nav a.is-current {
  color: var(--ink);
}
/* ---- Splash ------------------------------------------------------------ */
.splash {
  position: fixed;
  inset: 0;
  /* Center against the VISIBLE (dynamic) viewport, not the layout viewport.
     Without this the logo centers behind the mobile address bar and sits too
     low until fullscreen hides the bar. dvh tracks the visible area in both
     states; falls back to inset:0 where dvh is unsupported. */
  height: 100dvh;
  z-index: 100;
  display: grid;
  place-items: center;
  cursor: pointer; /* whole splash advances on click */
  background: #FFFFFF;
  transition:
    background-color 960ms cubic-bezier(0.2, 0.7, 0.18, 1),
    opacity 180ms ease,
    visibility 180ms ease;
}
.splash::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(
      ellipse 70% 55% at 50% 46%,
      rgba(216, 201, 168, 0.22),
      transparent 72%
    );
  opacity: 1;
  transition: opacity 760ms ease;
}
.splash.is-sequence-done {
  background: rgba(255, 255, 255, 0);
  pointer-events: none;
}
.splash.is-sequence-done::before {
  opacity: 0;
}
.splash.is-leaving {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.splash__button {
  position: relative;
  z-index: 1;
  width: clamp(104px, 12vw, 180px);
  /* Square: the logo sequence canvas is 360x360. A 10/7 box squished the
     square mark, distorting it and pushing it off visual centre. */
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  color: var(--ink);
  transition:
    transform 820ms cubic-bezier(0.18, 0.72, 0.16, 1),
    opacity 220ms ease 600ms;
}
.splash__button:hover {
  transform: scale(1.035);
}
.splash.is-sequence-done .splash__button {
  opacity: 0;
  transform: translateX(58vw);
}
.splash__button:active {
  transform: scale(0.99);
}
.splash__sequence {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  opacity: 1;
  pointer-events: none;
}

/* ---- Canopy canvas (fixed, behind every section) ------------------------ */
.canopy-canvas {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  /* lvh, matching .panel (2026-08-12). Was 100dvh, which tracks the URL bar
     live — and scene-claude-teaser.js re-runs setSize + camera.aspect on every
     one of those resizes, so the whole tree field rescaled each time the bar
     slid. ignoreMobileResize does not touch that listener. lvh is static and
     always covers the visible area in both bar states. The renderer buffer is
     now sized off THIS box (canvas.clientHeight), not window.innerHeight, or
     the buffer would be stretched into it. */
  height: 100lvh;
  z-index: 0;
  pointer-events: none;
  transition: none;
}
.text-veil {
  position: fixed;
  inset: 0;
  height: 100lvh; /* matches .canopy-canvas — see the note there */
  z-index: 1;
  pointer-events: none;
  opacity: var(--text-veil-opacity, 0.84);
  background: color-mix(in srgb, var(--bg) var(--text-veil-bg-strong), transparent);
  -webkit-backdrop-filter: blur(var(--text-veil-blur)) saturate(var(--text-veil-saturate));
  backdrop-filter: blur(var(--text-veil-blur)) saturate(var(--text-veil-saturate));
  transform: translate3d(0, 0, 0);
  transition: opacity 320ms ease;
  will-change: opacity, transform;
}

/* Canvas hidden on mobile or reduced-motion. UI shows solid --bg. */
body.is-fallback .canopy-canvas {
  display: none;
}

body.is-mote-hovering {
  cursor: pointer;
}

/* ---- Hero --------------------------------------------------------------- */
.hero {
  min-height: 100vh;
  /* lvh, same basis as .panel. NOT optional: body.swot-pinned #problem is
     pulled up by calc(-100lvh - 8lvh) from the hero's bottom edge, so if the
     hero measured in svh and the pull measured in lvh the whole pinned stack
     would sit ~90px off where it does today. One basis keeps the existing
     geometry proportionally identical. */
  min-height: 100lvh;
  position: relative;
  display: grid;
  place-items: center;
  padding: 96px var(--pad-x);
  isolation: isolate;
}

.hero__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--col-narrow);
  text-align: left;
}

/* Hero logo sits ABOVE the eyebrow but does NOT push layout. It anchors
   to the top-left of the hero column with a small offset, leaving the
   headline pinned in screen center as before. */
/* hero__logo absolute-positioned top-left of hero has been REPLACED with
   an inline mark inside the eyebrow line. See .hero__eyebrow-mark below. */

.hero__eyebrow {
  font-family: var(--font-mono);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 20px 0;
  font-variant-numeric: tabular-nums;
  will-change: transform, opacity;
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.hero__eyebrow-mark {
  height: 22px;          /* roughly cap-height of the eyebrow text */
  width: auto;
  display: inline-block;
  vertical-align: middle;
}
.bullfinch-mark__dark {
  fill: #0A0A0A;
}
.bullfinch-mark__red {
  fill: #D21A10;
}
[data-theme="dark"] .bullfinch-mark__dark {
  fill: #FAFAFA;
}

/* Hero headline: authored as a block child. text-wrap MUST stay off so the
   browser does not re-break the headline. */
.hero__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(44px, 6.4vw, 104px);
  line-height: 1.06;
  letter-spacing: -0.025em;
  text-wrap: normal;       /* explicitly NOT balance */
  color: var(--ink);
  font-feature-settings: "ss01", "ss02";
  margin: 0;
}

.hero__line {
  display: block;
  will-change: transform, opacity;
}
.hero__subtitle {
  font-family: var(--font-display);
  font-size: clamp(20px, 2vw, 34px);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0;
  color: var(--ink-soft);
  margin: 18px 0 0;
}
.site-footer__top {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  color: var(--ink-soft);
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition:
    background-color 260ms ease,
    border-color 260ms ease,
    color 260ms ease,
    opacity 420ms ease,
    transform 260ms ease;
}
.site-footer__top:hover {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 42%, var(--rule));
  transform: translateY(-2px);
}
.site-footer__top:active {
  transform: translateY(0);
}
.hero__scroll-cue {
  /* Fixed to the viewport, not the hero, so it stays pinned to the bottom of
     the screen through the hero AND into section 01 — retiring only once the
     first panel settles (body.has-reached-01). */
  position: fixed;
  left: 50%;
  bottom: max(28px, env(safe-area-inset-bottom));
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  color: var(--ink-soft);
  opacity: 0;
  transform: translate(-50%, 8px);
  pointer-events: none;
  transition:
    color 260ms ease,
    opacity 420ms ease,
    transform 260ms ease;
}
.hero__scroll-cue-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
body.has-entered .hero__scroll-cue {
  /* Lands with the hero, not a beat after it. The 980ms hold this used to carry
     read as "nothing to do here" on 00 -- people did not know to scroll. */
  opacity: 0.72;
  transform: translate(-50%, 0);
  transition-delay: 120ms;
}
body.has-reached-01 .hero__scroll-cue {
  opacity: 0;
  transform: translate(-50%, 8px);
  transition-delay: 0ms;
}
.hero__scroll-cue svg {
  animation: scrollCueFloat 2.2s ease-in-out infinite;
}

@keyframes scrollCueFloat {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(4px); }
}

@media (max-width: 720px) {
  .hero {
    padding: 48px var(--pad-x);
  }
  .hero__eyebrow {
    font-size: 11px;
    margin-bottom: 48px;
  }
}

/* ---- SWOT panels -------------------------------------------------------- */
.swot {
  position: relative;
  z-index: 1;
}

/* Panel is EXACTLY one viewport. overflow:hidden as a safety net so a
   verdict that grew one line too many cannot push the next panel down. */
.panel {
  height: 100vh;
  /* ONE VIEWPORT BASIS: lvh (2026-08-12, Piet: "THINGS SHIFTING AROUND when
     they shouldn't be"). svh is the viewport with the mobile URL bar SHOWING,
     so the moment the bar hides the screen grows ~90px and the panel does not
     — a band of page ground at the bottom of every section. lvh is the
     bar-hidden viewport: it can only ever CROP behind the bar, and a crop is
     invisible in a design that bleeds. Both units are STATIC per device, so
     nothing here re-measures when the bar slides. The swot-pinned margins in
     teaser-dev.html MUST use the same unit or the sections stop stacking. */
  height: 100lvh;
  padding: 32px var(--pad-x);
  /* Bar inset, tablets included. Resolves to exactly 32px anywhere without a
     dynamic toolbar, so desktop is untouched. See the phone rule for why. */
  padding-bottom: calc(32px + (100lvh - 100svh));
  position: relative;
  overflow: hidden;
  display: grid;
  place-items: center;
  isolation: isolate;
}
.panel--media {
  grid-template-columns: minmax(240px, min(38vw, 520px)) minmax(0, var(--col-narrow));
  gap: clamp(48px, 7vw, 112px);
  place-items: center;
}
#problem.panel--media {
  grid-template-columns: auto minmax(0, var(--col-narrow));
  gap: clamp(18px, 2.2vw, 44px);
}

/* ===== Section 01 stat: 1% dot-field + seven-segment readout ===== */
.panel__stat { position: relative; z-index: 2; width: auto;
  display: flex; align-items: center; gap: clamp(20px, 2.6vw, 44px); flex-wrap: wrap; }
.stat-grid { display: grid; gap: 4px; --dot: clamp(11px, 1.15vw, 15px); flex: none;
  grid-template-columns: repeat(10, var(--dot)); }
.stat-dot { width: var(--dot); height: var(--dot); border-radius: 50%;
  background: color-mix(in srgb, var(--ink-soft) 16%, transparent);
  transform: scale(.5); opacity: .42; will-change: transform, opacity, background; }
.stat-dot.is-on { background: var(--ink); transform: scale(1); opacity: 1; }
.stat-dot.is-one { background: var(--accent); transform: scale(1); opacity: 1;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); }
.stat-read { min-width: 180px; }
.stat-label { position: relative; font-size: clamp(18px, 1.9vw, 26px); height: 1.3em; }
.stat-line { position: absolute; top: 0; left: 0; margin: 0; font-family: var(--font-display);
  font-weight: 600; font-size: 1em; letter-spacing: 0.02em; text-transform: uppercase;
  color: var(--accent); line-height: 1.2; will-change: transform, opacity, filter; }
.stat-num { margin: 10px 0 0 0; display: flex; align-items: flex-end; gap: 10px; }
.stat-readout { display: inline-flex; gap: 9px; }
.stat-digit { font-family: var(--font-display); font-weight: 600;
  font-size: clamp(40px, 4.8vw, 66px); line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--ink); display: block; }
.stat-seg { fill: color-mix(in srgb, var(--ink-soft) 13%, transparent); transition: fill 110ms linear; }
.stat-seg.on { fill: var(--ink); }
.stat-unit { font-family: var(--font-mono); font-weight: 500; line-height: 1;
  font-size: clamp(18px, 2vw, 30px); color: var(--ink-soft); margin-bottom: 0.1em; }
.stat-rest { font-family: var(--font-display); font-weight: 500; font-size: clamp(14px, 1.5vw, 19px);
  line-height: 1.25; color: var(--ink); margin: 10px 0 0 0; max-width: 22ch; }

/* inline headline count-up ($39M) — fixed-width tabular digits so the headline
   never reflows (and the $ / M stay put) as the number counts. */
.count-up { display: inline-block; min-width: 2ch; text-align: right;
  font-variant-numeric: tabular-nums; }
#product.panel--media {
  grid-template-columns: minmax(280px, min(40vw, 560px)) minmax(0, var(--col-narrow));
  gap: clamp(18px, 3vw, 48px);
}
#opportunity.panel--media {
  grid-template-columns: minmax(280px, min(40vw, 560px)) minmax(0, var(--col-narrow));
  gap: clamp(18px, 3vw, 48px);
}
#proof.panel--media {
  grid-template-columns: minmax(300px, min(42vw, 560px)) minmax(0, var(--col-narrow));
  gap: clamp(32px, 5vw, 88px);
}
.case-fixed-layer {
  position: fixed;
  left: var(--pad-x);
  top: 0;
  width: min(40vw, 560px);
  max-width: calc(50vw - var(--pad-x) - 32px);
  transform: translate3d(0, 0, 0);
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  will-change: opacity;
}
#product .panel__inner {
  grid-column: 2;
}
.panel__video {
  position: relative;
  z-index: 2;
  width: 100%;
  aspect-ratio: 1.2 / 1;
  justify-self: end;
  border: 1px solid var(--rule);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  -webkit-backdrop-filter: blur(8px) saturate(0.94);
  backdrop-filter: blur(8px) saturate(0.94);
  overflow: hidden;
  opacity: 0;
  transform: translateX(-72px);
  will-change: opacity, transform;
}
.panel__video::before,
.panel__video::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 0;
  opacity: 1;
  pointer-events: none;
}
.panel__video::before {
  background:
    linear-gradient(var(--rule) 1px, transparent 1px),
    linear-gradient(90deg, var(--rule) 1px, transparent 1px);
  background-size: 25% 25%;
  opacity: 0.42;
}
.panel__video::after {
  inset: 50% auto auto 50%;
  width: 48px;
  height: 48px;
  border-left: 1px solid var(--ink-soft);
  border-top: 1px solid var(--ink-soft);
  opacity: 0.45;
  transform: translate(-50%, -50%) rotate(135deg);
}
.panel__video-inner {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 18px;
}
.panel__video-mark {
  width: clamp(64px, 8vw, 116px);
  height: auto;
  opacity: 0.72;
}
.panel__video p {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
}
.panel__video-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.62;
  z-index: 2;
}
.panel__video-gradient {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(circle at 18% 48%, rgba(230, 57, 70, 0.58), transparent 28%),
    radial-gradient(circle at 78% 54%, rgba(216, 201, 168, 0.22), transparent 32%),
    linear-gradient(135deg, #1d1d1a 0%, #14120f 48%, #050505 100%);
  animation: videoGradientDrift 8s ease-in-out infinite alternate;
}
@keyframes videoGradientDrift {
  0% {
    transform: scale(1.08) translate3d(-4%, -2%, 0);
    filter: saturate(0.88) brightness(0.84);
  }
  100% {
    transform: scale(1.16) translate3d(4%, 3%, 0);
    filter: saturate(1.08) brightness(0.98);
  }
}
.panel__video-fallback {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: none;
  color: #FFFFFF;
  text-decoration: none;
}
.panel__video-fallback img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(0.25) contrast(1.05) brightness(0.74);
}
.panel__video-fallback span {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
}
body.is-file-protocol .panel__video-media {
  display: none;
}
body.is-file-protocol .panel__video-fallback {
  display: block;
}
.panel__video--film::before {
  opacity: 0.16;
  z-index: 2;
}
.panel__video--film {
  max-width: 300px;
  opacity: 0;
}
.panel__video--film::after {
  display: none;
}
.panel__video--film .panel__video-inner {
  pointer-events: none;
  z-index: 3;
}
.panel__video--film .panel__video-mark {
  width: clamp(38px, 5vw, 62px);
  opacity: 0.14;
}
.panel__video--film p {
  font-size: 10px;
  color: #FFFFFF;
  opacity: 0.56;
  line-height: 1.5;
  text-transform: none;
}
/* The film is now a procedural canvas (no video), so show it at full opacity
   over the brand gradient — its shafts/motes are already subtle. */
.panel__video--film .panel__video-media {
  opacity: 1;
}
.panel__model {
  width: min(42vw, 560px);
  aspect-ratio: 0.9 / 1;
  align-self: center;
  transform: translate(-72px, -5vh);
  background: transparent;
  border-color: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  overflow: visible;
}
.panel__model::before,
.panel__model::after {
  display: none;
}
.panel__model-canvas {
  width: 100%;
  height: 100%;
}
.case-fixed-layer.panel__model {
  position: fixed;
  left: var(--pad-x);
  top: 0;
  width: min(40vw, 560px);
  max-width: calc(50vw - var(--pad-x) - 32px);
  transform: translate3d(0, 0, 0);
  opacity: 0;
  z-index: 3;
}
.ui-preview-slot {
  display: block;
}
#product .panel__inner {
  padding-top: clamp(28px, 6vh, 76px);
}
.panel__people {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--rule);
}
.panel__people::before,
.panel__people::after {
  display: none;
}
.person {
  position: relative;
  min-width: 0;
  height: 100%;
  overflow: hidden;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  cursor: pointer;
  border-radius: 0;
}
.person img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  filter: grayscale(1) contrast(1.05);
  opacity: 0.82;
  border-radius: 0;
}
.panel__people,
.panel__people *,
.person,
.person img,
.person picture {
  border-radius: 0 !important;
  clip-path: none !important;
}
.person::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 52%, color-mix(in srgb, var(--bg) 82%, transparent));
  pointer-events: none;
}
.person figcaption {
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 14px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.12em;
  line-height: 1.35;
  text-transform: uppercase;
  color: var(--ink);
}
.person:hover img,
.person:focus-visible img {
  filter: grayscale(0.7) contrast(1.08);
  opacity: 1;
}
.person:hover figcaption,
.person:focus-visible figcaption {
  color: var(--accent);
}
.team-bio-link {
  display: inline;
  font: inherit;
  text-align: left;
  text-decoration: none;
  vertical-align: baseline;
}
.team-bio-link:hover,
.team-bio-link:focus-visible {
  color: var(--accent);
}
.panel--media .panel__inner {
  justify-self: start;
  max-width: min(44vw, var(--col-narrow));
}

/* Inner is a FLEX COLUMN. Children stack with NO slack rows between them.
   The block centers vertically as a whole. Bullets sit tight under verdict. */
.panel__inner {
  width: 100%;
  max-width: var(--col-narrow);
  height: 100%;
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
}

.panel__eyebrow {
  font-family: var(--font-mono);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 32px 0;
  font-variant-numeric: tabular-nums;
  /* grid-only align-self removed */
}

/* Flush-left, ragged-right block. SAME 880px column as everything else.
   Sized by BOTH viewport width AND viewport height. text-wrap: balance
   lets the engine even out the ragged lines. NO justify, NO hyphens —
   justified blocks produce river gaps and broken auto-hyphenation. */
.panel__verdict {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: min(5.4vw, 5.0vh, 56px);
  line-height: 1.08;
  letter-spacing: -0.018em;
  color: var(--ink);
  text-align: left;
  -webkit-hyphens: none;
  hyphens: none;
  /* text-wrap: balance evens out line lengths and prevents the awful
     "twelve letters / two letters" orphan-style break. */
  text-wrap: balance;
  word-spacing: normal;
  white-space: normal;
  word-break: keep-all;          /* never break inside a word */
  overflow-wrap: normal;
  margin: 0;
  width: 100%;
  max-width: var(--col-narrow);
  /* grid-only align-self removed */
}

.panel__evidence {
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: 56ch;
  margin: 20px 0 0 0;     /* was 48px — bullets sit tight under verdict */
  align-self: start;
}
.panel__evidence p {
  font-family: var(--font-body);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.55;
  color: var(--ink);          /* full ink: true black light / true white dark */
  text-wrap: pretty;
  margin: 0;
}
.panel__evidence .lead {
  font-family: var(--font-body);
  font-weight: 600;
  color: var(--accent);       /* Bullfinch red on the leads */
  margin-right: 1px;
  letter-spacing: -0.01em;
}

.panel__numeric {
  font-family: var(--font-mono);
  font-size: 14.5px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  font-variant-numeric: tabular-nums;
  margin: 64px 0 0 0;
  max-width: var(--col-narrow);
  align-self: start;
}

.panel__quote {
  font-family: var(--font-display);
  font-size: min(2.6vw, 2.6vh, 22px);
  font-weight: 500;
  line-height: 1.28;
  letter-spacing: -0.012em;
  color: var(--ink);
  text-wrap: balance;
  margin-top: 6px;
  padding-left: 16px;
  border-left: 2px solid var(--accent);
}
.panel__quote cite {
  display: block;
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 13.5px;
  font-weight: 500;
  font-style: normal;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-quiet);
}

/* ---- Market bullseye (section 05) --------------------------------------
   Nested TAM / SAM / SOM / Beachhead rings drawn from the deck's market chart.
   Radii scale with market value, so the $188M beachhead is a small focused
   centre inside the $6B opportunity. The chart is FULLY SCROLL-DRIVEN: a
   growing circular clip reveals the rings outward as the panel is scrolled (and
   retracts on the way out), a red band fills whichever region is being drawn,
   and one label + one leader name that region. No-JS / reduced-motion shows it
   static and complete, red on the TAM. */
.panel__chart {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.bullseye-fig {
  margin: 0;
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}
.bullseye {
  width: 100%;
  height: auto;
  max-height: 72vh;
  overflow: visible;
  display: block;
}
/* Faint neutral scaffold: the four nested market tiers. The growing clip
   (#be-reveal) reveals them outward as the panel scrolls. */
.be-ring {
  fill: color-mix(in srgb, var(--ink) 6%, transparent);
  stroke: color-mix(in srgb, var(--ink) 24%, transparent);
  stroke-width: 1;
}
.be-tam { fill: color-mix(in srgb, var(--ink) 4%, transparent); }
.be-sam { fill: color-mix(in srgb, var(--ink) 6%, transparent); }
.be-som { fill: color-mix(in srgb, var(--ink) 9%, transparent); }
.be-beach { fill: color-mix(in srgb, var(--ink) 12%, transparent); }

/* Red band. fill:none + a thick stroke at a region's mid-radius fills that
   whole annular region red; JS sets r + stroke-width per region (clipped by the
   reveal so it grows with scroll). Default = TAM band for the no-JS fallback. */
.be-sweep {
  fill: none;
  stroke: var(--accent);
  stroke-width: 50;
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--accent) 45%, transparent));
}

/* One leader line; JS points its outer end at the current frontier. */
.be-leader {
  stroke: var(--accent);
  stroke-width: 1.5;
}

/* One label, swapped per region. Dark halo (paint-order) keeps it legible over
   either the dark scaffold or the red band; it "comes up" on each region change
   in step with the section copy. */
.be-cap {
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0.08em;
  paint-order: stroke;
  stroke: color-mix(in srgb, var(--bg) 76%, transparent);
  stroke-width: 3px;
  stroke-linejoin: round;
  transform-box: fill-box;
}
.be-cap-name { fill: var(--accent); font-size: 13px; font-weight: 600; letter-spacing: 0.12em; }
.be-cap-val { fill: var(--ink); font-size: 13.5px; }
.be-cap.is-step { animation: beCapIn 0.34s ease-out; }
@keyframes beCapIn {
  0%   { opacity: 0; transform: translateY(6px); }
  100% { opacity: 1; transform: translateY(0); }
}

.bullseye-cap {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  text-align: center;
}

.panel__eyebrow,
.panel__verdict,
.panel__evidence p,
.panel__numeric {
  will-change: transform, opacity;
}

/* Short viewport: tighten evidence type and the bottom band. */
@media (max-height: 800px) {
  .panel__evidence p {
    font-size: 17px;
    line-height: 1.5;
  }
  .panel__evidence {
    gap: 18px;
    margin-top: 36px;
  }
  .panel__numeric {
    margin-top: 36px;
  }
  .panel__eyebrow {
    margin-bottom: 24px;
  }
  .bullseye {
    max-height: 62vh;
  }
  .bullseye-fig {
    gap: 12px;
  }
}

@media (max-width: 1024px) {
  .panel__evidence p {
    font-size: 17px;
  }
}

@media (max-width: 720px) {
  .site-nav {
    padding: calc(20px + env(safe-area-inset-top)) var(--pad-x) 18px;
    gap: 16px;
  }
  .site-nav__links {
    display: inline-flex;
    gap: clamp(10px, 3vw, 16px);
    font-size: 11.5px;
    letter-spacing: 0.14em;
    margin-left: auto;
  }
  .site-nav__mark {
    width: 22px;
  }
  .site-nav__hover-label {
    display: none;
  }
  .panel {
    padding: 24px var(--pad-x);
    /* THE BAR INSET (2026-08-12). The BOX is 100lvh so no gap can ever open at
       the bottom, but the bottom (100lvh - 100svh) of it is behind the URL bar
       whenever the bar is showing — and 01's note, 02's copy and 03's band are
       all bottom-anchored. Inset the CONTENT by exactly the bar's height and
       the usable area is 100svh again: every panel's inner layout is back on
       the numbers it has today, while the background still bleeds under the
       bar. Both terms are STATIC per device, so this never moves when the bar
       slides. Second declaration only, so a browser without lvh/svh keeps 24px
       — same fallback idiom as .panel's height. */
    padding-bottom: calc(24px + (100lvh - 100svh));
  }
  .panel--media {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    gap: 24px;
    place-items: center;
  }
  #problem.panel--media,
  #product.panel--media,
  #opportunity.panel--media,
  #team.panel--media {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    align-content: center;
  }
  .panel__video {
    grid-column: 1;
    grid-row: 1;
    width: min(42vh, 100%);
    max-width: 320px;
    justify-self: center;
  }
  /* Section 01 stat: stack + center the whole composition on mobile. */
  .panel__stat {
    grid-column: 1;
    grid-row: 1;
    justify-self: center;
    justify-content: center;
    gap: clamp(16px, 5vw, 32px);
  }
  .stat-read { text-align: center; min-width: 0; }
  .stat-label { width: 100%; }
  .stat-line { left: 0; right: 0; text-align: center; }
  .stat-num { justify-content: center; }
  .stat-rest { margin: 10px auto 0; }
  .panel__video--film {
    /* Full-bleed to the screen edges, keep the current height. */
    width: 100vw;
    max-width: none;
    height: min(23vh, 200px);
    aspect-ratio: auto;
    margin-left: calc(50% - 50vw);
    border-left: none;
    border-right: none;
  }
  .panel__people {
    width: min(48vh, 100%);
    max-width: 360px;
  }
  .panel--media .panel__inner {
    grid-column: 1;
    grid-row: 2;
    justify-self: center;
    max-width: none;
    height: auto;
  }
  /* Product panel: the TEXT is bottom-anchored so it is ALWAYS fully on screen
     (never cut off). The model fills the space ABOVE the text and is sized by
     JS (layoutProductCase in swot.js) to be as large as possible without
     pushing the text off-screen — it adapts to the text, not the reverse. */
  #product.panel--media {
    align-content: end;
  }
  #product .panel__inner {
    grid-column: 1;
    grid-row: 2;
    max-width: min(86vw, 420px);
    padding-top: 0;
    padding-bottom: 4vh;
  }
  .case-fixed-layer.panel__model {
    /* Box scales with the available space: 94vw wide (kept < viewport so this
       fixed element can't create horizontal overflow), height = the region
       above the text (set by JS). The canvas resolution tracks this box and the
       art is drawn CONTAIN, so it always stays full-aspect (no crop/stretch). */
    left: 50%;
    top: 0;
    width: 94vw;
    height: 42vh;         /* fallback until JS measures the region */
    max-width: none;
    transform: translate3d(-50%, 0, 0);
  }
  .panel__eyebrow {
    font-size: 11px;
    margin-bottom: 10px;
  }
  .panel__verdict {
    font-size: min(8.2vw, 4.4vh, 33px);
    line-height: 1.04;
    letter-spacing: -0.012em;
  }
  .panel__evidence {
    gap: 8px;
    margin-top: 14px;
    max-width: none;
  }
  .panel__evidence p {
    font-size: 13.4px;
    line-height: 1.34;
  }
  .panel__numeric {
    margin-top: 12px;
    font-size: 10.5px;
    line-height: 1.25;
  }
  #proof.panel--media {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    align-content: center;
    /* Keep the whole block clear of the fixed nav up top and give the long copy
       room below, so nothing is cut off. */
    padding-top: calc(60px + env(safe-area-inset-top));
    row-gap: 12px;
  }
  .panel__chart {
    grid-column: 1;
    grid-row: 1;
    /* Scale the bullseye DOWN to fit the available space on small screens. */
    width: min(30vh, 62vw);
    max-width: 230px;
    justify-self: center;
  }
  .bullseye {
    width: 100%;
    height: auto;
    max-height: 28vh;
  }
  .bullseye-fig {
    gap: 8px;
  }
  .bullseye-cap {
    font-size: 9px;
    letter-spacing: 0.02em;
  }
}

/* ---- Closing section ---------------------------------------------------- */
.closing {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  min-height: 100lvh; /* one basis with .panel — see the note there */
  /* Content sits in the upper portion; the footer is pushed to the bottom
     (margin-top: auto). The open space between them is the lower-centre zone
     the network converges into — see updateFinalRedAnchor in scene.js. */
  padding: clamp(72px, 15vh, 150px) var(--pad-x) 0;
  /* Bar inset — the footer is pushed to the bottom with margin-top:auto, so
     without this it lands under the URL bar. See the note on .panel. */
  padding-bottom: calc(100lvh - 100svh);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  isolation: isolate;
}
.closing__inner {
  position: relative;
  width: 100%;
  max-width: var(--col-narrow);
  text-align: center;
  z-index: 2;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: clamp(28px, 5vh, 56px);
}
/* Subtle radial scrim so the headline reads cleanly over the live network. */
.closing__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: min(7.2vw, 7.0vh, 96px);
  line-height: 1.06;
  letter-spacing: -0.022em;
  color: var(--ink);
  text-wrap: normal;
  text-align: center;
  margin: 0 auto;
  max-width: 18ch;
  position: relative;
  z-index: 2;
}
.closing__logo {
  position: relative;
  height: 80px;
  width: auto;
  margin: 0;
  z-index: 2;
  flex: 0 0 auto;
}
.closing__line {
  display: block;
  will-change: transform, opacity;
}
.contact-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 12px;
  margin-top: 40px;
}
.contact-actions a {
  min-height: 42px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 16px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  color: var(--ink-soft);
  font-size: 14px;
  transition:
    border-color 220ms ease,
    color 220ms ease,
  transform 220ms ease;
}
.contact-actions a:hover {
  border-color: color-mix(in srgb, var(--accent) 38%, var(--rule));
  color: var(--ink);
  transform: translateY(-1px);
}
.closing__actions {
  position: relative;
  justify-content: center;
  gap: clamp(32px, 7vw, 96px);
  margin-top: 0;
}
.closing__actions a {
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: #FFFFFF;
  text-decoration: none;
}
.closing__actions a:hover {
  border-color: transparent;
  color: #FFFFFF;
  transform: none;
}
/* ---- Footer (lives INSIDE .closing — last band of the final viewport) --- */
.site-footer {
  position: relative;
  z-index: 2;
  flex: 0 0 auto;
  margin-top: auto;
  width: 100%;
  padding: 24px var(--pad-x) max(104px, calc(env(safe-area-inset-bottom) + 104px));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 18px;
}
.site-footer__wordmark {
  width: min(44vw, 440px);
  height: auto;
  pointer-events: none;
}
.site-footer__line {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  margin: 0;
  font-variant-numeric: tabular-nums;
  text-align: center;
  opacity: 0;
  transform: translateY(12px);
  will-change: opacity, transform;
}
.site-footer__top {
  position: absolute;
  left: 50%;
  bottom: calc(max(10px, env(safe-area-inset-bottom)) + 26px);
  transform: translateX(-50%);
}
.site-footer__top:hover {
  transform: translate(-50%, -2px);
}
.site-footer__top:active {
  transform: translate(-50%, 0);
}

/* ---- Team bio modal ---------------------------------------------------- */
.bio-modal[hidden] {
  display: none;
}
.bio-modal {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  place-items: center;
  padding: 24px;
}
.bio-modal__backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(0.86);
  backdrop-filter: blur(16px) saturate(0.86);
}
.bio-modal__panel {
  position: relative;
  z-index: 1;
  width: min(860px, calc(100vw - 48px));
  padding: clamp(24px, 4vw, 44px);
  border: 1px solid var(--rule);
  border-radius: 0;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  color: var(--ink);
  display: grid;
  grid-template-columns: minmax(180px, 0.78fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 44px);
  align-items: center;
}
.bio-modal__close {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  color: var(--ink-soft);
}
.bio-modal__close:hover {
  color: var(--accent);
}
.bio-modal__eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  line-height: 1.3;
  text-transform: uppercase;
  color: var(--ink-quiet);
  margin-bottom: 22px;
}
.bio-modal__photo {
  width: 100%;
  aspect-ratio: 0.82 / 1;
  object-fit: cover;
  object-position: center top;
  filter: none;
  margin: 0;
  border-radius: 0;
  clip-path: none;
}
.bio-modal__panel,
.bio-modal__photo,
.bio-modal__panel img {
  border-radius: 0 !important;
  clip-path: none !important;
  overflow: visible;
}
.bio-modal__content {
  min-width: 0;
}
.bio-modal__title {
  max-width: 24ch;
  font-size: clamp(17px, 1.45vw, 22px);
  line-height: 1.18;
  letter-spacing: 0;
  color: var(--ink);
}
.bio-modal__body {
  max-width: 62ch;
  margin-top: 18px;
  color: var(--ink-soft);
  font-size: 14px;
  line-height: 1.55;
  text-align: justify;
  text-align-last: left;
}

@media (max-width: 720px) {
  .bio-modal__panel {
    grid-template-columns: 1fr;
  }
  .bio-modal__photo {
    width: min(54vw, 220px);
  }
  .site-footer {
    padding: 20px var(--pad-x) max(92px, calc(env(safe-area-inset-bottom) + 92px));
  }
  .site-footer__top {
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + 18px);
  }
  .corner-wordmark {
    display: none;
  }
}

/* ---- Fullscreen toggle -------------------------------------------------- */
.fullscreen-toggle {
  width: 16px;
  height: 16px;
  display: inline-grid;
  place-items: center;
  color: var(--ink-quiet);
  transition:
    color 200ms ease,
    opacity 200ms ease;
}
.fullscreen-toggle:hover,
.fullscreen-toggle:focus-visible {
  color: var(--ink);
}
.fullscreen-toggle svg {
  display: block;
}

.corner-wordmark {
  position: fixed;
  right: var(--pad-x);
  bottom: max(58px, calc(env(safe-area-inset-bottom) + 58px));
  z-index: 45;
  color: var(--ink-quiet);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  line-height: 1;
  pointer-events: none;
  text-transform: uppercase;
}
