/* =====================================================
   HOW WE WORK — Terminal Brutalist
   Ported from temp/claude-design/How We Work - Terminal Brutalist.html
   2026-04-26 — initial port (canonical token mapping pass 1)
   See .inventories/how-we-work.md for animation spec.
   See temp/how-we-work-promotion-candidates.md for component-promotion notes.

   Page-scoped — does NOT share marketing-site/style.css.
   Imports canonical tokens directly so --accent, --font-mono, --status-ok align.

   ⚠️  @import MUST be first declaration per CSS spec.
   ===================================================== */
@import url('./colors-and-type.css');

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

/* =====================================================
   FX-PAGE THEME SYSTEM
   Single page wrapper transitions background/color smoothly.
   ScrollTrigger sets [data-active-theme] as sections cross viewport center.
   ===================================================== */
:root {
  --fx-theme-shift-duration: 700;       /* ms */
  --fx-theme-shift-ease: cubic-bezier(0.65, 0, 0.35, 1);
  --fx-theme-shift-dark-bg:  #0a0a0a;
  --fx-theme-shift-dark-fg:  #e8e8e8;
  --fx-theme-shift-light-bg: #fafafa;
  --fx-theme-shift-light-fg: #1a1a1a;

  --page-bg: var(--fx-theme-shift-dark-bg);
  --page-fg: var(--fx-theme-shift-dark-fg);
  --page-rule: #1e1e1e;
  --page-t2: #808080;
  --page-t3: #444444;

  /* Statusbar swap aliases (statusbar uses these names) */
  --swap-dur: calc(var(--fx-theme-shift-duration) * 1ms);
  --swap-ease: var(--fx-theme-shift-ease);
}

/* Background colour MUST live on <html>, not <body>. Body would paint
   its background ABOVE any z:-1 descendants (because body is a static
   descendant of html that paints in tree order, while .fx-bg z:-1 is
   in the negative-z group). With bg on html only, the .fx-bg canvas
   paints between html bg and body content — visible. */
html {
  background-color: #0a0a0a;
  transition: background-color calc(var(--fx-theme-shift-duration) * 1ms) var(--fx-theme-shift-ease);
  /* Firefox scrollbar. Single track color — `scrollbar-color` does NOT
     animate, so theme-flipping it would snap-flip during a 700ms page
     crossfade and read as a peripheral flicker. Dark track works on
     both themes; the accent thumb is the polish detail. */
  scrollbar-color: var(--accent) #1a1a1a;
  scrollbar-width: thin;
}
/* JS toggles this on <html> in lockstep with the canvas uTheme uniform
   so reduced-motion users (no canvas) still see the theme swap. */
html.fx-light-theme {
  background-color: var(--fx-theme-shift-light-bg);
}

/* WebKit/Blink scrollbar — accent thumb, single dark track on both
   themes (see Firefox note above). Hover deepens to accent-hover. */
html::-webkit-scrollbar { width: 10px; height: 10px; }
html::-webkit-scrollbar-track { background: #1a1a1a; }
html::-webkit-scrollbar-thumb {
  background: var(--accent);
  border: 2px solid #1a1a1a;
  border-radius: 0;
  transition: background-color 200ms cubic-bezier(.16, 1, .3, 1);
}
html::-webkit-scrollbar-thumb:hover { background: var(--accent-hover, #d95443); }
html::-webkit-scrollbar-corner { background: transparent; }
body {
  background: transparent;
  font-family: var(--font-mono);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Global WebGL background — fixed, behind everything in body flow.
   z-index:-1 puts it between html bg and body's static content.
   Canvas paints the active-theme ground colour itself + the dot field. */
.fx-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  /* Match the theme transition exactly — same duration, same ease — so
     fxBg opacity rides in lockstep with the html bg transition. GSAP's
     'power2.inOut' is cubic-bezier(0.42, 0, 0.58, 1), which DESYNCS
     against the theme system's cubic-bezier(0.65, 0, 0.35, 1) — visible
     on scroll-up as the shader fading out faster than the html
     lightens, exposing mid-grey for a frame and reading as a phantom
     "second crossfade." Using the same CSS transition guarantees
     pixel-perfect lockstep. JS toggles opacity via style; CSS does
     the rest. */
  transition: opacity calc(var(--fx-theme-shift-duration) * 1ms) var(--fx-theme-shift-ease);
}
.fx-bg canvas { width: 100%; height: 100%; display: block; }

/* THE page wrapper — transparent now. Only animates color so text
   inverts when [data-active-theme] flips. The actual background
   colour comes from the global canvas (with body bg as fallback). */
.fx-page {
  min-height: 100vh;
  min-height: 100svh;  /* Mobile address-bar safe — no viewport jump on iOS scroll */
  background: transparent;
  color: var(--fx-theme-shift-dark-fg);
  transition: color calc(var(--fx-theme-shift-duration) * 1ms) var(--fx-theme-shift-ease);
}
.fx-page[data-active-theme="light"] {
  color: var(--fx-theme-shift-light-fg);
  --page-bg: var(--fx-theme-shift-light-bg);
  --page-fg: var(--fx-theme-shift-light-fg);
  --page-rule: #e4e0da;
  --page-t2: #555555;
  --page-t3: #999999;
}

/* Section component tokens — read live from the wrapper.
   So when wrapper inverts, panels/rules/labels invert WITH it smoothly. */
.theme-dark, .theme-light {
  --bg: var(--page-bg);
  --s1: #141414;
  --s2: #1e1e1e;
  --s3: #2a2a2a;
  --t1: var(--page-fg);
  --t2: var(--page-t2);
  --t3: var(--page-t3);
  --rule-color: var(--page-rule);
  --rule-strong: #2a2a2a;
}
.fx-page[data-active-theme="light"] .theme-dark,
.fx-page[data-active-theme="light"] .theme-light {
  --s1: #ffffff;
  --s2: #f1eeea;
  --s3: #e6e2dc;
  --rule-strong: #1a1a1a;
}

/* Sections are transparent — they let the wrapper's ground show through. */
.hero, section.theme-dark, .section-wrap, .sep {
  background: transparent;
}

/* Component surfaces transition along with the wrapper.
   ⚠️ Anything that uses var(--t1/t2/t3/rule-color/page-fg/page-bg)
   MUST be in this list, or it'll snap-flip on theme change while
   the rest of the page eases through 700ms. The card-bg, panel
   header addr span, faq wrap border, reports family, and cta sub
   were all missing — added 2026-04-30 after Julius reported a
   visible "inversion" at moneyCut + reports reveal. */
.panel, .panel__header, .panel__header .addr,
.sep .rule, .sep .label, .sep .label .slash,
.about__photo, .about__bio40, .about__nameline, .about__nameline b,
.about__prose p, .step-row, .step-row__n, .step-row__label,
.step-row__desc, .step-row__meta, .step-row__meta .k,
.scope__col h4, .scope__col h4 .slash, .scope__list li,
.scope__list--not li::before,
.scope .panel > .card-bg, .faq__wrap > .card-bg,
.faq__wrap, .faq__item, .faq__item summary, .faq__item .qn, .faq__item .a,
.reports__shell, .reports__ribbon, .reports__lede, .reports__sub,
.reports__row, .reports__row__link, .reports__row__title,
.reports__row__sep, .reports__row__meta, .reports__row__cta,
.reports__preview-trigger,
.pricing__floor, .pricing__close,
.cta__sub, .cta__display, .cta__foot,
.statusbar {
  transition:
    background-color calc(var(--fx-theme-shift-duration) * 1ms) var(--fx-theme-shift-ease),
    color            calc(var(--fx-theme-shift-duration) * 1ms) var(--fx-theme-shift-ease),
    border-color     calc(var(--fx-theme-shift-duration) * 1ms) var(--fx-theme-shift-ease);
}

@media (prefers-reduced-motion: reduce) {
  .fx-page { transition: none; }
}

/* CRT scanlines on dark sections */
.crt::after {
  content:''; position:absolute; inset:0; pointer-events:none; z-index:5;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0 2px,
    rgba(255,255,255,0.018) 2px 3px
  );
  mix-blend-mode: overlay;
}
.crt-grain::before {
  content:''; position:absolute; inset:0; pointer-events:none; z-index:4;
  opacity: 0.06; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

/* =====================================================
   TOP STATUS BAR — "terminal chrome"
   ===================================================== */
.statusbar {
  position: fixed; top:0; left:0; right:0; z-index:50;
  display:grid;
  grid-template-columns: auto auto 1fr auto;
  gap: 24px; align-items: center;
  padding: 10px 20px;
  font-family: var(--font-mono);
  font-size: var(--size-micro); letter-spacing: var(--track-wide);
  text-transform: uppercase;
  background: var(--page-bg);
  border-bottom: 1px solid var(--page-rule);
  color: var(--page-t2);
  font-variant-numeric: tabular-nums;
  transition:
    background var(--swap-dur) var(--swap-ease),
    color var(--swap-dur) var(--swap-ease),
    border-color var(--swap-dur) var(--swap-ease),
    transform 320ms cubic-bezier(.4, 0, .2, 1);
  will-change: transform;
}
/* Inline section nav inside the statusbar — quick-jump anchors. */
.statusbar__nav {
  display: flex;
  gap: 18px;
  justify-content: center;
  align-items: center;
}
.statusbar__nav a {
  cursor: pointer;
  color: var(--page-t2);
  text-decoration: none;
  letter-spacing: var(--track-wide);
  position: relative;
  padding: 2px 0;
  transition: color 220ms ease;
}
.statusbar__nav a::after {
  content: '';
  position: absolute;
  left: 0; right: 100%; bottom: 0;
  height: 1px;
  background: var(--accent);
  transition: right 280ms cubic-bezier(.16,1,.3,1);
}
.statusbar__nav a:hover {
  color: var(--accent);
}
.statusbar__nav a:hover::after {
  right: 0;
}
/* Hide on scroll-down, show on scroll-up (JS toggles the class). */
.statusbar.is-hidden {
  transform: translateY(-100%);
}
.statusbar .pill {
  display:inline-flex; align-items:center; gap:8px;
  padding: 4px 10px;
  border: 1px solid currentColor;
  opacity: 0.85;
}
.statusbar .pill.live::before {
  content:''; width:6px; height:6px; background: var(--status-ok);
  border-radius:50%; box-shadow:0 0 6px var(--status-ok);
  animation: sbpulse 2s infinite;
}
@keyframes sbpulse { 0%,100% { opacity:1 } 50% { opacity:0.3 } }
.statusbar .sid b { color: #1a1a1a; font-weight:500; }
.statusbar.on-dark .sid b { color:#e0e0e0; }
.statusbar .cal {
  color: inherit; text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
}
.statusbar .cal:hover { color: var(--accent); border-bottom-color: var(--accent); }
.statusbar .cal::before { content:'['; margin-right:3px; opacity:0.5 }
.statusbar .cal::after  { content:'] ↗'; margin-left:3px; opacity:0.5 }

/* =====================================================
   HERO — ASCII-matrix on fragment shader + massive type
   ===================================================== */
.hero {
  position:relative;
  min-height: 100vh;
  min-height: 100svh;
  padding: 60px 0 0;
  color: #e8e8e8;
  isolation: isolate;
  background-color: #0a0a0a;
}
/* Hero stays dark regardless of page theme — page initial theme is
   light (so the hero→about transition has no visible crossfade), but
   the hero itself must keep its dark tokens. Same specificity as the
   light-cascade rule on .theme-dark; source order wins. */
.fx-page[data-active-theme="light"] .hero,
.fx-page[data-active-theme="dark"] .hero {
  --bg: #0a0a0a;
  --t1: #fafafa;
  --t2: #999;
  --t3: #666;
  --rule-color: #1f1f1f;
  --rule-strong: #2a2a2a;
  --s1: #141414;
  --s2: #1a1a1a;
  --s3: #2a2a2a;
}
.hero__canvas { position: absolute; inset: 0; z-index: -1; overflow: hidden; }
.hero__canvas canvas { display:block; width:100%; height:100%; }

.hero__frame {
  position:relative; z-index:3;
  padding: 56px 28px 48px;
  max-width: 1600px; margin: 0 auto;
  min-height: calc(100vh - 60px);
  min-height: calc(100svh - 60px);
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  gap: 0;
}

.hero__ribbon {
  display:grid;
  grid-template-columns: auto 1fr auto auto auto;
  gap: 18px; align-items:center;
  padding: 14px 18px;
  background: rgba(10,10,10,0.6);
  backdrop-filter: blur(6px);
  font-size: var(--size-micro); letter-spacing: var(--track-terminal);
  color:#808080; text-transform:uppercase;
  font-variant-numeric: tabular-nums;
  position: relative;
}
.hero__ribbon .slash { color: var(--accent); letter-spacing:0; }
.hero__ribbon .acc { color: var(--accent); }
.hero__ribbon b { color:#e8e8e8; font-weight:500; }
.hero__ribbon .rule { height:1px; background:#1e1e1e; }

.hero__body {
  padding: 64px 24px 24px;
  display:grid;
  grid-template-columns: 1fr;
  gap: 32px;
}

.hero__display {
  font-family: var(--font-mono);
  font-size: clamp(var(--size-2xl), 7.5vw, var(--size-display-xl));
  line-height: 0.96;
  letter-spacing: var(--track-tight);
  font-weight: 700;
  text-transform: uppercase;
  margin:0; color:#e8e8e8;
}
.hero__display .l { display:block; position:relative; }
.hero__display .w { display:inline-block; white-space: nowrap; font-kerning: none; }
.hero__display .c {
  display: inline-block;
  position: relative;
  will-change: opacity;
  --opa: 0;
}
/* Line-glitch-cursor block — solid 1ch × 100% rectangle behind each
   char, opacity driven by --opa. Default invisible; JS flashes it on
   3× per char during the cascade so the chars resolve through a
   moving cursor. (Codrops LineTextHoverAnimations pattern, MIT,
   adapted as a one-shot reveal.) */
.hero__display .c::after {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 1ch; height: 100%;
  background: currentColor;
  opacity: var(--opa);
  pointer-events: none;
}
.hero__display .accent { color: var(--accent); }
.hero__display .arrow {
  color: var(--accent);
  display: inline-block;
  padding-right: 0.05em;
}
@media (prefers-reduced-motion: reduce) {
  .hero__display .c::after { display: none; }
}
/* Ink-stamp treatment: crimson overscore bar.
   Color is locked to the hero's dark fg — the WebGL canvas behind hero
   stays dark even after the page wrapper crossfades to light below, so
   the text must NOT inherit --page-fg or it'd become unreadable. */
.hero__display .ink {
  position: relative;
  display: inline-block;
  color: #e8e8e8;
}
.hero__display .ink::before {
  content: '';
  position: absolute;
  left: -0.04em; right: -0.04em;
  top: -0.08em;
  height: 0.08em;
  background: var(--accent);
  transform-origin: left;
  transform: scaleX(0);
  animation: inkscore 900ms cubic-bezier(.16,1,.3,1) 1.6s forwards;
}
@keyframes inkscore { to { transform: scaleX(1); } }
.hero__display .tag {
  position: relative;
  display: inline-block;
  color: #e8e8e8; /* locked to hero dark fg — see .ink note above */
  padding: 0 0.12em;
}
.hero__display .tag::before,
.hero__display .tag::after {
  content: '';
  position: absolute;
  width: 0.16em; height: 0.16em;
  border: 2px solid var(--accent);
  pointer-events: none;
}
.hero__display .tag::before { top: 0.02em;   left: -0.02em;  border-right:0; border-bottom:0; }
.hero__display .tag::after  { bottom: 0.12em; right: -0.02em; border-left:0;  border-top:0; }

.hero__cmd {
  font-size: var(--size-xs); letter-spacing: var(--track-ui);
  color: #808080;
  display: flex; flex-wrap: wrap; gap: 8px 14px; align-items:center;
}
.hero__cmd .p { color: var(--accent); }
.hero__cmd b { color:#e8e8e8; font-weight:500; }
.hero__cmd .cursor {
  display:inline-block; width:0.55ch; height:1.1em; background: var(--accent);
  vertical-align:-0.15em; margin-left:0.1em;
  animation: blink 1s step-end infinite;
  box-shadow: 0 0 10px rgba(194,60,42,0.5);
}
@keyframes blink { 0%,49% { opacity:1 } 50%,100% { opacity:0 } }

/* Pins the readout + foot to the BOTTOM of the hero's 1fr grid row.
   Without this, when the display headline shrinks (3 lines vs 4) the
   stats drift upward to fill the slack. The user wants stats fixed at
   the same vertical position regardless of headline length. */
.hero__bottom {
  align-self: end;
}
.hero__readout {
  display:grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border: 1px solid #1e1e1e;
  border-bottom: 0;
}
.hero__readout .cell {
  padding: 22px 24px;
  border-right: 1px solid #1e1e1e;
  font-family: var(--font-mono);
  position: relative;
}
.hero__readout .cell:last-child { border-right:0; }
.hero__readout .k {
  font-size: var(--size-micro); letter-spacing: var(--track-terminal); text-transform:uppercase; color:#888;
  margin-bottom:8px;
  text-shadow: 0 0 8px rgba(194, 60, 42, 0.5), 0 0 18px rgba(194, 60, 42, 0.25);
}
.hero__readout .k::before { content:'> '; color: var(--accent); }
.hero__readout .v {
  font-size: clamp(var(--size-lg), 2.6vw, var(--size-xl)); line-height:1;
  color:#e8e8e8; font-weight:700;
  letter-spacing: var(--track-tight);
  font-variant-numeric: tabular-nums;
}
.hero__readout .v .u { color:#555; font-size:0.6em; margin-left:4px; }

.hero__sub {
  font-family: var(--font-mono);
  font-size: clamp(var(--size-sm), 1.4vw, var(--size-md));
  line-height: var(--lead-body);
  color: #a8a8a8;
  letter-spacing: var(--track-body);
  max-width: 64ch;
  margin: 28px 0 0;
}

.hero__foot {
  display:grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 24px; align-items:center;
  padding: 14px 18px;
  border: 1px solid #1e1e1e;
  font-size: var(--size-micro); letter-spacing: var(--track-terminal);
  text-transform:uppercase; color:#555;
  font-variant-numeric: tabular-nums;
}
.hero__foot .rule { height:1px; background:#1e1e1e; }
.hero__foot .right { text-align:right; }

/* =====================================================
   BLOCK CHROME — "boxed" terminal panels
   Borders are drawn as SVG strokes (sketched-on-page draw-in) — see
   .panel__stroke below. CSS border:0 lets the SVG own the visual.
   Backgrounds are transparent so the global #fxBg canvas shows through.
   ===================================================== */
.panel {
  border: 0;
  padding: 32px;
  margin-bottom: 24px;
  background: transparent;
  position: relative;
}

/* Semi-opaque dark surfaces. Two patterns based on whether the card has
   inner staggered reveals.

   PARENT-CLIP (pricing__step, reports__row): no inner staggers — clip the
   whole card so the wipe IS the reveal. Bg sits on the parent.

   CHILD-CLIP (scope .panel, faq__wrap): inner content has its own staggered
   reveals (h4, list items, faq items). Clipping the parent would mask
   those tweens — instead a .card-bg child div is JS-injected and clipped.
   The panel itself stays unclipped so its content animates normally. */
.pricing__step,
.reports__row {
  background: rgba(0, 0, 0, 0.7);
  clip-path: inset(100% 0 0 0);
}
.scope .panel,
.faq__wrap {
  background: transparent;
}
/* Border-reveal idiom: ribbons + faq__wrap get a clip-path-animated
   pseudo border. CSS border on the parent is removed; the pseudo
   sits inset:0 with the border definition + clip-path that JS
   reveals via .is-drawn. Paint-only, no layout cost — safe to use
   on FAQ where parent resizes when items open. */
.hero__ribbon::before,
.cta__ribbon::before,
.faq__wrap::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 1px solid var(--rule-color);
  clip-path: inset(50% 50% 50% 50%);
  transition: clip-path 0.95s cubic-bezier(.16, 1, .3, 1);
  pointer-events: none;
  z-index: 0;
}
/* The hero / cta ribbons used #1e1e1e originally — keep that exact
   tone for parity with the rest of the chrome. */
.hero__ribbon::before,
.cta__ribbon::before {
  border-color: #1e1e1e;
}
.hero__ribbon.is-drawn::before,
.cta__ribbon.is-drawn::before,
.faq__wrap.is-drawn::before {
  clip-path: inset(0 0 0 0);
}
@media (prefers-reduced-motion: reduce) {
  .hero__ribbon::before,
  .cta__ribbon::before,
  .faq__wrap::before {
    clip-path: inset(0 0 0 0);
    transition: none;
  }
}
.faq__wrap > .card-bg {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.7);
  clip-path: inset(100% 0 0 0);
  pointer-events: none;
  z-index: 0;
}
/* Scope is permanently light theme. The slide-up card-bg overlay was a
   dark-theme idiom (dark overlay sliding up over a dark page); on a
   light page it only creates a visual mismatch with the fxBg shader
   (which is hardcoded dark via uTheme=0 always). Hiding it lets scope's
   content stagger in directly on the light page bg — cleaner read,
   eliminates the "second crossfade" Julius observed at moneyCut.
   The card-bg div is still injected by JS; this just removes its paint. */
.scope .panel > .card-bg {
  display: none;
}
@media (prefers-reduced-motion: reduce) {
  .pricing__step,
  .reports__row,
  .scope .panel > .card-bg,
  .faq__wrap > .card-bg {
    clip-path: none;
  }
}
/* Topic glyph — section-marker icon between the section number and the
   title in panel headers and ribbons. Adds a per-section visual cue so
   later text-heavy sections (FAQ, CTA) read as distinct on scroll. */
.topic-glyph {
  color: var(--accent);
  margin: 0 8px 0 4px;
  font-weight: 700;
  display: inline-block;
  font-size: 0.95em;
  vertical-align: baseline;
}

.panel__header {
  display:grid;
  grid-template-columns: auto 1fr auto;
  align-items:center; gap:18px;
  padding: 6px 14px;
  background: transparent;
  border: 0;
  margin: -33px -33px 32px;
  font-family: var(--font-mono);
  font-size: var(--size-micro); letter-spacing: var(--track-terminal);
  text-transform:uppercase; color: var(--t2);
  font-variant-numeric: tabular-nums;
  position: relative;
}
.theme-dark .panel__header { background: transparent; }
.panel__header .dot { width:8px; height:8px; background: var(--accent); }
.panel__header .addr { color: var(--t1); }

/* SVG perimeter stroke — injected by JS into every .panel and into
   .panel__header. pathLength=100 + dashoffset 100→0 draws clockwise
   from top-left in 1.4s, looking like the frame is sketched live. */
.panel__stroke,
.panel__header__stroke {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
  overflow: visible;
}
.panel__stroke rect,
.panel__header__stroke rect {
  fill: none;
  stroke: var(--rule-color);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  /* stroke colour transitions in lockstep with the page crossfade
     duration — without it, var(--rule-color) jumps the moment the
     theme attribute flips and the bg's still mid-fade, producing a
     high-contrast border flash. */
  transition:
    stroke-dashoffset 0.85s cubic-bezier(.16, 1, .3, 1),
    stroke calc(var(--fx-theme-shift-duration) * 1ms) var(--fx-theme-shift-ease);
}
.is-drawn > .panel__stroke rect,
.is-drawn > .panel__header__stroke rect {
  stroke-dashoffset: 0;
}
/* Panel header stroke is shorter — draw faster so it lands first. */
.panel__header__stroke rect {
  transition-duration: 0.55s;
}

/* Reports shell + pricing steps need position:relative so their SVG
   stroke (position:absolute) anchors to them, not to the section. */
.reports__shell,
.pricing__steps { position: relative; }

/* All section content blocks share one global vertical padding token so
   the gap on either side of any sep is symmetric. Two knobs in the
   tweak panel: --gb-section-pad-y (this), and --sep-pad-y (sep
   internal). Total visible gap between adjacent section content =
   2 * --gb-section-pad-y + 2 * --sep-pad-y + sep label height. */
:root {
  --sep-pad-y: 64px;
  --gb-section-pad-y: 96px;
}
.section-wrap {
  max-width: 1360px; margin: 0 auto;
  padding: var(--gb-section-pad-y) 28px;
}

/* Divider between sections (reads as packet separator). Larger label
   typography (--size-lg, ~2x prior --size-micro) so the section markers
   read at glance from any scroll speed. The topic glyph is bumped a
   step further so it dominates the sep's visual weight. */
.sep {
  padding: var(--sep-pad-y) 28px;
  display:grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 18px; align-items:center;
  max-width: 1360px; margin: 0 auto;
  font-family: var(--font-mono);
  font-size: var(--size-lg); letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
.sep .rule {
  height:1px;
  background: var(--rule-color);
  /* Pre-collapsed; JS animates scaleX 0→1 from outer-edge transform-origin
     so each rule grows toward the centre label. */
  transform: scaleX(0);
}
.sep .label {
  color: var(--t2);
  white-space: nowrap;
}
.sep .label .topic-glyph {
  color: var(--accent);
  font-size: 1.4em;
  line-height: 1;
  margin-right: 14px;
  vertical-align: -0.06em;
  font-weight: 700;
  display: inline-block;
}
.sep .label .slash {
  color: var(--t3);
  font-size: 0.85em;
  margin-right: 10px;
  vertical-align: 0.15em;
}
.sep .label .acc {
  color: var(--accent);
  font-size: 0.7em;
  margin-left: 12px;
  vertical-align: 0.15em;
}

/* Character split — used for divider labels and select large headers.
   .word is inline-block + nowrap so words wrap at whitespace boundaries
   (between words), but inline-block chars inside a word stay together —
   prevents mid-word breaks like "AUDIT YOUR S\nITE?" that the
   per-character split caused. */
.word {
  display: inline-block;
  white-space: nowrap;
}
.char {
  display: inline-block;
  will-change: transform, opacity;
}

@media (prefers-reduced-motion: reduce) {
  .sep .rule { transform: none; }
  .word, .char { opacity: 1 !important; transform: none !important; }
}

/* =====================================================
   ABOUT — light panel, photo slot + bio
   ===================================================== */
.about__grid {
  display:grid;
  grid-template-columns: 320px 1fr;
  gap: 56px;
  align-items: start;
}
/* ID-PLATE photo slot: filmstrip-style identification card.
   Solid ink ground, embossed bracket, no ASCII noise. */
.about__photo {
  position: relative;
  aspect-ratio: 4/5;
  background: #1a1a1a;
  color: #fafafa;
  border: 1px solid #1a1a1a;
  overflow: hidden;
}
.about__photo__img {
  /* Fill the entire .about__photo box (the full 4:5 plate, not just
     the inner frame). object-fit: cover scales to fill — no black bars,
     edges crop as needed to respect the plate's aspect ratio. */
  position: absolute;
  inset: 0;
  display: block;
  overflow: hidden;
}
/* Top-and-bottom darken — keeps the face area readable while pushing
   the ID grid (top) and slug (bottom) text into legibility. The
   pseudo paints inside the photo wrapper so it sits ABOVE the photo
   but BELOW the frame/id/slug/scan elements, which are later children
   of .about__photo and paint on top. */
.about__photo__img::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* Strong darken at the very top + bottom (where ID grid + slug sit),
     transparent through the middle 35-65% so the face stays bright.
     Image filter raises brightness slightly so the centre band reads
     bright; the gradient masks back down where text needs contrast. */
  background: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0.82) 0%,
    rgba(0, 0, 0, 0.45) 18%,
    rgba(0, 0, 0, 0.00) 35%,
    rgba(0, 0, 0, 0.00) 65%,
    rgba(0, 0, 0, 0.55) 100%
  );
}
.about__photo__img img {
  width: 100%; height: 100%;
  /* cover: fill the 4:5 frame entirely, cropping edges as needed.
     No black bars. Frame aspect ratio is respected; photo is scaled
     so its smaller dimension matches the frame and overflow is hidden. */
  object-fit: cover;
  object-position: center;
  display: block;
  filter: grayscale(0.18) contrast(1.06) brightness(1.05) saturate(1.1);
}
.about__photo__frame {
  position: absolute; inset: 14px;
  border: 1px solid rgba(250,250,250,0.18);
  pointer-events: none;
}
.about__photo__frame::before,
.about__photo__frame::after,
.about__photo__frame > i:nth-child(1),
.about__photo__frame > i:nth-child(2) {
  content: ''; position: absolute;
  width: 14px; height: 14px;
  border-style: solid; border-color: var(--accent);
}
.about__photo__frame::before { top: -1px; left: -1px; border-width: 1px 0 0 1px; }
.about__photo__frame::after  { top: -1px; right: -1px; border-width: 1px 1px 0 0; }
.about__photo__frame > i:nth-child(1) { bottom: -1px; left: -1px; border-width: 0 0 1px 1px; }
.about__photo__frame > i:nth-child(2) { bottom: -1px; right: -1px; border-width: 0 1px 1px 0; }
.about__photo__id {
  position: absolute; top: 28px; left: 28px; right: 28px;
  display: grid; grid-template-columns: auto 1fr; gap: 8px 14px;
  font-family: var(--font-mono);
  font-size: var(--size-micro); letter-spacing: var(--track-terminal); text-transform: uppercase;
  color: rgba(250,250,250,0.55);
  font-variant-numeric: tabular-nums;
}
.about__photo__id b { color: #fafafa; font-weight: 500; }
.about__photo__id .acc { color: var(--accent); }
.about__photo__slug {
  position: absolute; left: 28px; right: 28px; bottom: 28px;
}
.about__photo__slug .tag {
  font-family: var(--font-mono);
  font-size: var(--size-micro); letter-spacing: var(--track-terminal); text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 14px;
  display: flex; align-items: center; gap: 10px;
}
.about__photo__slug .tag::before { content: ''; width: 8px; height: 8px; background: var(--accent); }
.about__photo__slug .name {
  font-family: var(--font-mono);
  font-size: clamp(var(--size-xl), 2.8vw, var(--size-2xl)); line-height: 1;
  font-weight: 700; letter-spacing: var(--track-tight);
  text-transform: uppercase; color: #fafafa;
  margin: 0;
}
.about__photo__slug .role {
  font-family: var(--font-mono);
  font-size: var(--size-micro); letter-spacing: var(--track-terminal); text-transform: uppercase;
  color: rgba(250,250,250,0.55);
  margin-top: 10px;
}
.about__photo__scan {
  position: absolute; left: 14px; right: 14px; top: 50%;
  height: 1px; background: linear-gradient(90deg, transparent, #c23c2a 40%, #c23c2a 60%, transparent);
  opacity: 0.6; pointer-events: none;
  animation: photoscan 5s linear infinite;
}
@keyframes photoscan {
  0%   { top: 22%; opacity: 0; }
  10%  { opacity: 0.6; }
  90%  { opacity: 0.6; }
  100% { top: 82%; opacity: 0; }
}

.about__bio40 {
  font-size: clamp(var(--size-lg), 2.2vw, var(--size-xl));
  line-height: var(--lead-snug);
  letter-spacing: var(--track-tight);
  color: var(--page-fg);
  font-weight: 400;
  margin: 0 0 40px;
  max-width: 720px;
}
.about__bio40 em,
.about__prose em { font-style:normal; color: var(--accent); }

.about__nameline {
  font-size: var(--size-micro); letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: var(--t2);
  margin-bottom: 40px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--t1);
  display:flex; align-items:center; gap:16px;
}
.about__nameline b { color: var(--t1); font-weight:700; }
.about__nameline .acc { color: var(--accent); }

.about__prose p {
  font-family: var(--font-mono);
  font-size: var(--size-base);
  line-height: var(--lead-loose);
  color: var(--t1);
  margin: 0 0 22px;
  max-width: 640px;
  letter-spacing: var(--track-body);
  text-transform: none;
}
.about__prose p::before {
  content: attr(data-n) '  ';
  color: var(--accent);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Lead-in paragraph above the steps list. */
.steps__lede {
  font-family: var(--font-mono);
  font-size: var(--size-base);
  line-height: var(--lead-loose);
  color: var(--t2);
  max-width: 720px;
  margin: 0 0 48px;
  letter-spacing: var(--track-body);
  text-transform: none;
}

/* =====================================================
   STEPS — vertical "pipeline" with sticky cursor
   The rail is sticky to the viewport — the cursor dot stays at viewport
   center while step rows scroll past it. Active row = whichever is
   closest to viewport center (computed in JS, single ScrollTrigger).
   ===================================================== */
.steps__wrap {
  display:grid;
  grid-template-columns: 32px 1fr;
  gap: 40px;
  position: relative;
}
.steps__rail {
  position: relative;
  width: 32px;
  pointer-events: none;
}
.steps__rail .spine {
  position:absolute; left:50%; top:0; bottom:0; width:1px;
  background: linear-gradient(to bottom,
    transparent 0%, var(--t1) 30%, var(--t1) 70%, transparent 100%);
  transform: translateX(-0.5px);
}
/* Cursor dot — SVG with stroke-dashoffset draw-in.
   JS positions the whole element via `top` (rail-local pixels). Lines
   draw outward from the centre core; core fades in once lines complete.
   Hidden until the steps section enters viewport (.is-drawn flips). */
.steps__rail .cursor-dot {
  position:absolute; left:50%; top:0;
  width: 92px; height: 12px;
  transform: translateX(-50%);
  pointer-events: none;
  overflow: visible;
  will-change: top;
}
.steps__rail .cursor-dot line,
.steps__rail .cursor-dot circle {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset 0.7s cubic-bezier(.16, 1, .3, 1);
}
.steps__rail .cursor-dot circle {
  fill: var(--accent);
  fill-opacity: 0;
  filter: drop-shadow(0 0 6px rgba(194,60,42,0.7));
  transition: stroke-dashoffset 0.7s cubic-bezier(.16, 1, .3, 1),
              fill-opacity 0.35s ease 0.45s;
}
.steps__rail .cursor-dot.is-drawn line,
.steps__rail .cursor-dot.is-drawn circle {
  stroke-dashoffset: 0;
}
.steps__rail .cursor-dot.is-drawn circle {
  fill-opacity: 1;
}

.steps__list { list-style:none; padding:0; margin:0; }
.step-row {
  display:grid;
  grid-template-columns: 80px 180px 1fr 140px;
  gap: 32px;
  align-items: baseline;
  padding: 44px 0;
  border-bottom: 1px solid var(--rule-color);
  position: relative;
}
.step-row:first-child { padding-top: 8px; border-top: 0; }
.step-row.active { background: linear-gradient(90deg, rgba(194,60,42,0.04), transparent 60%); }
.step-row__n {
  font-family: var(--font-mono);
  font-size: var(--size-numeric); line-height: 1;
  font-weight: 700;
  color: var(--t1);
  letter-spacing: var(--track-tight);
  font-variant-numeric: tabular-nums;
}
.step-row.active .step-row__n { color: var(--accent); }
.step-row__label {
  font-family: var(--font-mono);
  font-size: var(--size-lg); line-height: var(--lead-tight);
  font-weight: 700;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  color: var(--t1);
}
.step-row__desc {
  font-family: var(--font-mono);
  font-size: var(--size-base); line-height: var(--lead-body);
  color: var(--t2);
  letter-spacing: var(--track-body);
  text-transform: none;
  max-width: 580px;
}
.step-row__meta {
  font-family: var(--font-mono);
  font-size: var(--size-micro); letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: var(--t3);
  font-variant-numeric: tabular-nums;
  text-align: right;
  line-height: var(--lead-body);
}
.step-row__meta .acc { color: var(--accent); display:block; }
.step-row__meta .k { color: var(--t1); display:block; margin-top:4px; }

/* =====================================================
   SCOPE — diff/log styling
   ===================================================== */
.scope__grid {
  display:grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
}
.scope__col h4 {
  font-family: var(--font-mono);
  font-size: var(--size-sm); letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: var(--t1);
  font-weight: 700;
  margin: 0 0 24px;
  padding-bottom: 14px;
  border-bottom: 2px solid var(--t1);
}
.scope__col h4 .slash { color: var(--t3); }
.scope__list { list-style:none; padding:0; margin:0; font-family: var(--font-mono); }
.scope__list li {
  padding: 20px 0 20px 56px;
  position: relative;
  font-size: var(--size-base); line-height: var(--lead-body);
  color: var(--t1);
  border-top: 1px dashed var(--rule-color);
  letter-spacing: var(--track-body);
  text-transform: none;
}
.scope__list li:first-child { border-top:0; padding-top: 6px; }
.scope__list li::before {
  content: attr(data-marker);
  position: absolute; left: 0; top: 20px;
  font-size: var(--size-lg); font-weight: 700;
  font-family: var(--font-mono);
  color: var(--accent);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.scope__list--not li::before { color: var(--t3); }
.scope__list li:first-child::before { top: 8px; }

/* =====================================================
   PRICING — dark panel with teleprinter feel
   ===================================================== */
.pricing {
  position: relative;
  padding: var(--gb-section-pad-y) 28px;
  isolation: isolate;
  max-width: 1360px;
  margin: 0 auto;
}
.pricing__shell { position:relative; z-index: 1; }

/* (Per-section dot-field canvases were removed — the global #fxBg
   handles all WebGL backdrop now. Scope/pricing/cta no longer host
   their own canvases.) */
.pricing__lede {
  font-family: var(--font-mono);
  font-size: clamp(var(--size-xl), 4.2vw, var(--size-2xl));
  line-height: var(--lead-tight);
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
  color: #e8e8e8;
  font-weight: 700;
  margin: 32px 0 72px;
  max-width: 1000px;
}
.pricing__lede .acc { color: var(--accent); }

.pricing__steps {
  border: 0;
  background: transparent;
  position: relative;
}
.pricing__step {
  display: grid;
  grid-template-columns: 80px 1fr 160px;
  gap: 24px;
  padding: 32px 28px;
  border-bottom: 1px solid #1e1e1e;
  font-family: var(--font-mono);
  align-items: baseline;
  position: relative;
}
.pricing__step:last-child { border-bottom: 0; }
.pricing__step .n {
  font-size: var(--size-xl); font-weight: 700;
  color: #444;
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--track-tight);
}
.pricing__step.done .n { color: var(--accent); }
.pricing__step .title {
  font-size: clamp(var(--size-md), 2.2vw, var(--size-xl));
  line-height: var(--lead-snug);
  color: #e8e8e8;
  letter-spacing: var(--track-body);
  font-weight: 500;
  text-transform: none;
  margin: 0;
}
.pricing__step .title b { color: var(--accent); font-weight: 500; }
.pricing__step .len {
  font-size: var(--size-micro);
  letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: #808080;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Pricing body — soft-floor anchor + quiet ownership close. Replaces
   the prior .pricing__footnote tag-block ribbon (which stood out too
   loud) with two unadorned paragraphs that flow as one block. The
   $1,500 anchor is "starting around" so it directionally signals the
   floor without hard-committing to a public price. The close uses
   short fragments ("No monthly. No platform rent. No expiry.") for
   the same V20 stark-filter rhythm we use elsewhere on the page. */
.pricing__body {
  margin-top: 64px;
  max-width: 720px;
}
.pricing__floor {
  font-family: var(--font-mono);
  font-size: clamp(var(--size-md), 1.6vw, var(--size-lg));
  line-height: var(--lead-body);
  color: var(--t1);
  letter-spacing: var(--track-body);
  margin: 0 0 32px;
  text-transform: none;
}
.pricing__floor .acc { color: var(--accent); font-weight: 700; }
.pricing__close {
  font-family: var(--font-mono);
  font-size: var(--size-sm);
  line-height: var(--lead-body);
  color: var(--t2);
  letter-spacing: var(--track-body);
  margin: 0;
  padding-top: 24px;
  border-top: 1px solid var(--rule-color);
  text-transform: none;
}

/* =====================================================
   REPORTS — terminal-listing rows with centered swipe-up preview
   Header uses pricing-style hero__ribbon (full caps, slash + accent).
   Luisa/Nerdgasm rows are static (hover-only — no link). REQUEST
   AUDIT remains the sole click target.
   ===================================================== */
.reports__shell {
  position: relative;
  z-index: 1;
  max-width: 1360px;
  margin: 0 auto;
}
.reports__ribbon {
  margin-bottom: 56px;
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.pricing__ribbon {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.reports__lede {
  font-family: var(--font-mono);
  font-size: clamp(var(--size-xl), 4.2vw, var(--size-2xl));
  line-height: var(--lead-tight);
  letter-spacing: var(--track-tight);
  color: #e8e8e8;
  font-weight: 700;
  text-transform: uppercase;
  margin: 32px 0 24px;
  max-width: 1000px;
}
.reports__lede .acc { color: var(--accent); }
.reports__sub {
  font-family: var(--font-mono);
  font-size: var(--size-sm);
  line-height: var(--lead-body);
  color: var(--t2);
  letter-spacing: var(--track-body);
  text-transform: none;
  max-width: 640px;
  margin: 0 0 40px;
}

.reports__list { list-style:none; padding:0; margin:0; }
.reports__row {
  border-top: 1px solid var(--rule-color);
  position: relative;
}
.reports__row:last-child {
  border-bottom: 1px solid var(--rule-color);
}
.reports__row__link {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto auto;
  column-gap: 32px;
  row-gap: 4px;
  padding: 28px 8px;
  font-family: var(--font-mono);
  text-decoration: none;
  color: var(--t1);
  transition: background-color 240ms ease, color 240ms ease;
}
.reports__row__link:hover {
  background: linear-gradient(90deg, rgba(194,60,42,0.06), transparent 70%);
}
/* Static rows: no navigation, no row-wide hover trigger.
   The preview pill below is the SOLE hover target. */
.reports__row__link--static {
  cursor: default;
}
.reports__row__link--static:hover {
  background: none;
}

/* Small "HOVER TO PREVIEW" pill — the only thing that triggers the
   preview overlay. Sits in the row's right column, replaces the
   removed VIEW REPORT span. Borders + accent dot invite the hover. */
.reports__preview-trigger {
  font-family: var(--font-mono);
  font-size: var(--size-xs);
  letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: var(--accent);
  background: rgba(194,60,42,0.04);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border: 1px solid var(--accent);
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition:
    color 220ms ease,
    border-color 220ms ease,
    background-color 220ms ease,
    transform 240ms cubic-bezier(.16,1,.3,1);
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  font-weight: 700;
}
.reports__preview-trigger:hover {
  color: var(--accent);
  border-color: var(--accent);
  background-color: rgba(194,60,42,0.14);
  transform: translateX(-2px);
}
.reports__preview-trigger__icon {
  color: var(--accent);
  font-size: 13px;
  line-height: 1;
  display: inline-block;
  transition: transform 320ms cubic-bezier(.16,1,.3,1);
}
.reports__preview-trigger:hover .reports__preview-trigger__icon {
  transform: scale(1.25);
}

/* Attention-pull — persistent idle "breathe" loop while clients have
   not yet hovered or opened a preview. JS adds .is-attention on
   section-enter and removes it on first hover or first preview open
   (or after a max idle window). Loops `breathe` continuously, with a
   stronger initial double-beat from `pulse` so the first impression
   reads as a distinct attention grab. */
@keyframes reports-trigger-pulse {
  0%, 100% {
    transform: translateX(0);
    background-color: rgba(194,60,42,0.04);
  }
  18%, 50% {
    transform: translateX(-5px);
    background-color: rgba(194,60,42,0.22);
    box-shadow: 0 0 0 4px rgba(194,60,42,0.18);
  }
  34%, 68% {
    transform: translateX(0);
    background-color: rgba(194,60,42,0.04);
    box-shadow: 0 0 0 0 rgba(194,60,42,0);
  }
}
@keyframes reports-trigger-icon-pulse {
  0%, 100% { transform: scale(1); }
  18%, 50% { transform: scale(1.55); }
  34%, 68% { transform: scale(1); }
}
@keyframes reports-trigger-breathe {
  0%, 100% {
    background-color: rgba(194,60,42,0.04);
    box-shadow: 0 0 0 0 rgba(194,60,42,0);
    transform: translateX(0);
  }
  50% {
    background-color: rgba(194,60,42,0.18);
    box-shadow: 0 0 0 6px rgba(194,60,42,0.10);
    transform: translateX(-3px);
  }
}
@keyframes reports-trigger-icon-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.35); }
}
.reports__preview-trigger.is-attention {
  animation:
    reports-trigger-pulse 1.6s cubic-bezier(.4, 0, .2, 1) 1,
    reports-trigger-breathe 2.4s cubic-bezier(.4, 0, .2, 1) 1.6s infinite;
}
.reports__preview-trigger.is-attention .reports__preview-trigger__icon {
  animation:
    reports-trigger-icon-pulse 1.6s cubic-bezier(.4, 0, .2, 1) 1,
    reports-trigger-icon-breathe 2.4s cubic-bezier(.4, 0, .2, 1) 1.6s infinite;
}
.reports__preview-trigger:hover,
.reports__preview-trigger:focus-visible {
  animation: none;
}
.reports__preview-trigger:hover .reports__preview-trigger__icon,
.reports__preview-trigger:focus-visible .reports__preview-trigger__icon {
  animation: none;
}
@media (prefers-reduced-motion: reduce) {
  .reports__preview-trigger.is-attention,
  .reports__preview-trigger.is-attention .reports__preview-trigger__icon {
    animation: none;
  }
}
.reports__row__title {
  font-size: clamp(var(--size-md), 1.7vw, var(--size-lg));
  font-weight: 700;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  color: var(--t1);
  grid-column: 1;
  grid-row: 1;
}
.reports__row__title .acc { color: var(--accent); margin-right: 8px; }
.reports__row__sep { color: var(--t3); margin: 0 6px; }
.reports__row__meta {
  font-size: var(--size-micro);
  letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: var(--t3);
  grid-column: 1;
  grid-row: 2;
  font-variant-numeric: tabular-nums;
}
.reports__row__cta {
  font-size: var(--size-xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--t2);
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  transition: color 240ms ease, transform 260ms cubic-bezier(.16,1,.3,1);
}
.reports__row__cta.acc { color: var(--accent); }
.reports__row__link:hover .reports__row__cta {
  color: var(--accent);
  transform: translateX(4px);
}

/* Centered swipe-up preview frame — fixed-positioned at viewport
   centre. Width = min(1200, vw-padding, vh*aspect), so it keeps a 4:5
   portrait ratio while never overflowing the viewport. Hidden state
   sits 64px below centre; shown state lifts to centre with opacity. */
.reports__preview {
  position: fixed;
  left: 50%; top: 50%;
  width: min(820px, calc(100vw - 64px), calc((100vh - 64px) * 4 / 5));
  aspect-ratio: 4 / 5;
  margin: 0;
  pointer-events: none;
  opacity: 0;
  transform: translate3d(-50%, calc(-50% + 64px), 0);
  transition:
    opacity 240ms ease,
    transform 520ms cubic-bezier(.16,1,.3,1);
  z-index: 100;
  background: #1a1a1a;
  border: 1px solid #1a1a1a;
  overflow: hidden;
  will-change: transform, opacity;
  box-shadow: 0 32px 96px rgba(0,0,0,0.45);
}
.reports__preview.is-visible {
  opacity: 1;
  transform: translate3d(-50%, -50%, 0);
}
.reports__preview__img {
  width: 100%; height: 100%; display: block;
  object-fit: cover;
}
/* Subtle scanline overlay on the video — reads as an actual analog
   monitor surface. Same repeating gradient idiom as .crt::after,
   tuned to a low opacity so it's a hint, not noise. Sits above the
   video (z-index:1) but below the bracket frame (z-index:2). */
.reports__preview::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0 2px,
    rgba(255, 255, 255, 0.03) 2px 3px
  );
  mix-blend-mode: screen;
  z-index: 1;
}

/* HUD overlay — REC indicator, channel label, timecode, signal,
   progress bar. Sits above the video + scanlines but below the
   bracket frame. Pure flavor — pointer-events:none so hover-leave
   on the trigger isn't broken. */
.reports__preview__hud {
  position: absolute;
  inset: 14px;
  pointer-events: none;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(245, 245, 245, 0.78);
  text-shadow: 0 0 6px rgba(0, 0, 0, 0.6);
  z-index: 3;
}
.reports__preview__rec {
  position: absolute;
  top: 12px; left: 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--accent);
  font-weight: 700;
}
.reports__preview__rec-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 6px rgba(194, 60, 42, 0.7);
  animation: rec-blink 1.4s ease-in-out infinite;
}
@keyframes rec-blink {
  0%, 65%  { opacity: 1; }
  78%      { opacity: 0.15; }
  100%     { opacity: 1; }
}
.reports__preview__src {
  position: absolute;
  top: 12px; right: 12px;
}
.reports__preview__time {
  position: absolute;
  bottom: 18px; left: 12px;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}
.reports__preview__signal {
  position: absolute;
  bottom: 18px; right: 12px;
}
.reports__preview__signal b {
  color: var(--accent);
  font-weight: 700;
}
.reports__preview__bar {
  position: absolute;
  left: 12px; right: 12px; bottom: 10px;
  height: 1px;
  background: rgba(255, 255, 255, 0.12);
  overflow: hidden;
}
.reports__preview__bar-fill {
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width 100ms linear;
}
@media (prefers-reduced-motion: reduce) {
  .reports__preview__rec-dot { animation: none; }
}
.reports__preview__frame {
  position: absolute; inset: 14px;
  border: 1px solid rgba(250,250,250,0.18);
  pointer-events: none;
  z-index: 2;
}
.reports__preview__frame::before,
.reports__preview__frame::after,
.reports__preview__frame > i:nth-child(1),
.reports__preview__frame > i:nth-child(2) {
  content: ''; position: absolute;
  width: 14px; height: 14px;
  border-style: solid; border-color: var(--accent);
}
.reports__preview__frame::before { top: -1px; left: -1px; border-width: 1px 0 0 1px; }
.reports__preview__frame::after  { top: -1px; right: -1px; border-width: 1px 1px 0 0; }
.reports__preview__frame > i:nth-child(1) { bottom: -1px; left: -1px; border-width: 0 0 1px 1px; }
.reports__preview__frame > i:nth-child(2) { bottom: -1px; right: -1px; border-width: 0 1px 1px 0; }

/* Touch / no-hover devices: keep the preview visible (it's now
   tap-driven) but make it bigger and centred for thumb reach. The
   trigger swap from HOVER → TAP label happens via the .hover-only /
   .tap-only span pair. */
@media (hover: none) {
  .reports__preview {
    width: min(420px, calc(100vw - 24px));
    aspect-ratio: 4 / 5;
  }
}

/* Trigger label — desktop shows HOVER variant, touch shows TAP.
   Keyed to BOTH `(hover: none)` (real touch devices) and the
   width breakpoint so DevTools mobile-emulation views (which keep
   reporting hover: hover from the host's mouse) still see the TAP
   label. Either condition triggers the swap. */
.reports__preview-trigger__label .tap-only { display: none; }
@media (max-width: 840px), (hover: none) {
  .reports__preview-trigger__label .hover-only { display: none; }
  .reports__preview-trigger__label .tap-only { display: inline; }
}

/* Backdrop — only active on touch when the preview is visible. On
   hover-capable devices the backdrop never shows. */
.reports__preview__backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.78);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 99; /* below .reports__preview (z:100) */
  opacity: 0;
  pointer-events: none;
  transition: opacity 240ms ease;
}
.reports__preview__backdrop.is-visible {
  opacity: 1;
  pointer-events: auto;
}

/* Close button — only shown on touch (hover devices use mouse-leave) */
.reports__preview__close {
  position: absolute;
  top: 8px; right: 8px;
  width: 36px; height: 36px;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #e8e8e8;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  z-index: 3; /* above scanline overlay */
  -webkit-tap-highlight-color: transparent;
}
@media (hover: none) {
  .reports__preview__close { display: flex; }
}

/* =====================================================
   FAQ — fake terminal transcript
   ===================================================== */
.faq__list { list-style: none; padding: 0; margin: 0; }
.faq__item {
  border-bottom: 1px solid var(--rule-color);
}
.faq__item:first-child { border-top: 1px solid var(--rule-color); }
.faq__item summary {
  list-style: none;
  cursor: pointer;
  padding: 24px 0;
  display: grid;
  grid-template-columns: 60px 1fr 40px;
  gap: 20px;
  align-items: baseline;
  font-family: var(--font-mono);
  font-size: clamp(var(--size-base), 1.9vw, var(--size-lg));
  line-height: var(--lead-snug);
  color: var(--t1);
  letter-spacing: var(--track-body);
  font-weight: 500;
  text-transform: none;
  transition: color 240ms;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:hover { color: var(--accent); }
.faq__item .qn {
  font-size: var(--size-micro); letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: var(--t3);
  font-variant-numeric: tabular-nums;
  padding-top: 6px;
}
.faq__item .qn::before { content: 'Q'; color: var(--accent); margin-right: 4px; }
.faq__item .plus {
  font-size: var(--size-lg);
  color: var(--accent);
  transition: transform 400ms cubic-bezier(.16,1,.3,1);
  padding-top: 0;
  font-weight: 400;
  line-height: 1;
}
/* .plus rotation driven by GSAP in the click handler so it runs in
   parallel with the height tween (CSS [open] toggles too late on close
   — see how-we-work.js FAQ accordion). */
/* Outer .a is the height-animated box. Zero padding here so it can
   actually collapse to 0 (any padding would otherwise pin its rendered
   height to padding-sum and produce a snap at end-of-close).
   .a__inner carries the visual padding instead. */
.faq__item .a {
  font-family: var(--font-mono);
  font-size: var(--size-sm); line-height: var(--lead-loose);
  color: var(--t2);
  letter-spacing: var(--track-body);
  text-transform: none;
  position: relative;
}
.faq__item .a__inner {
  padding: 0 80px 24px;
  max-width: 760px;
}
.faq__item .a::before {
  content: 'A';
  position: absolute;
  left: 20px;
  top: 2px;
  font-size: var(--size-micro); letter-spacing: var(--track-terminal);
  color: var(--accent);
  font-weight: 700;
}
.faq__item .typed {
  display: inline-block;
}

/* =====================================================
   FOOTER CTA
   ===================================================== */
.cta {
  position: relative;
  padding: var(--gb-section-pad-y) 28px;
  overflow: hidden;
}
.cta__shell {
  position: relative; z-index: 2;
  max-width: 1360px; margin: 0 auto;
}
.cta__ribbon {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 24px; align-items: center;
  padding: 14px 18px;
  background: transparent;
  font-family: var(--font-mono);
  font-size: var(--size-micro); letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: #808080;
  margin-bottom: 56px;
  position: relative;
}
.cta__ribbon .rule { height:1px; background:#1e1e1e; }
.cta__ribbon .slash { color: var(--accent); letter-spacing:0; }
.cta__display {
  font-family: var(--font-mono);
  font-size: clamp(var(--size-2xl), 9vw, var(--size-display-xl));
  line-height: 0.94;
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
  font-weight: 700;
  color: #e8e8e8;
  margin: 0 0 40px;
  text-shadow: 0 0 40px rgba(220,225,240,0.08);
}
.cta__display .acc { color: var(--accent); }
.cta__sub {
  font-family: var(--font-mono);
  font-size: clamp(var(--size-sm), 1.4vw, var(--size-md));
  line-height: var(--lead-body);
  color: #a0a0a0;
  max-width: 640px;
  margin: 0 0 64px;
  letter-spacing: var(--track-body);
  text-transform: none;
}
.cta__sub .acc { color: var(--accent); }
.cta__actions {
  display: flex;
  gap: 40px; flex-wrap: wrap;
  margin-bottom: 100px;
  align-items: flex-start;
}
.cta__primary-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* =====================================================
   DESIGN-SYSTEM BUTTONS
   .btn-bracket : primary.   [ LABEL → ]   brackets tick inward on hover.
   .btn-tick    : secondary. hairline underline with end ticks.
   ===================================================== */
.btn {
  font-family: var(--font-mono);
  font-size: var(--size-xs); letter-spacing: var(--track-wide);
  text-transform: uppercase;
  text-decoration: none;
  display: inline-flex; align-items: baseline; gap: 12px;
  position: relative;
  font-weight: 500;
  cursor: pointer;
  color: var(--t1);
  -webkit-tap-highlight-color: transparent;
}
.btn .arr {
  font-size: var(--size-sm);
  color: var(--accent);
  transition: transform 260ms cubic-bezier(.16,1,.3,1);
  font-feature-settings: "ss01";
}
.btn:hover .arr { transform: translateX(4px); }

/* --------  .btn-bracket  — primary, bracketed frame  -------- */
.btn-bracket {
  padding: 18px 26px;
  gap: 14px;
  border: 1px solid var(--t1);
  position: relative;
  isolation: isolate;
  transition: background-color 260ms ease, color 260ms ease, border-color 260ms ease;
}
/* Hairline ticks at each corner — registration marks.
   Drawn via 4 linear-gradient layers, each a 10px L-shape. */
.btn-bracket::before,
.btn-bracket::after {
  content: '';
  position: absolute;
  inset: -5px;
  pointer-events: none;
  background-image:
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent));
  background-repeat: no-repeat;
  background-size:
    10px 1px, 1px 10px,
    10px 1px, 1px 10px,
    10px 1px, 1px 10px,
    10px 1px, 1px 10px;
  background-position:
    0 0, 0 0,
    100% 0, 100% 0,
    0 100%, 0 100%,
    100% 100%, 100% 100%;
  transition: inset 260ms cubic-bezier(.2,.9,.3,1.2), opacity 260ms;
}
.btn-bracket:hover::before,
.btn-bracket:hover::after { inset: -9px; }
.btn-bracket .prefix {
  font-size: var(--size-micro);
  color: var(--accent);
  letter-spacing: var(--track-terminal);
  opacity: 0;
  margin-right: -8px;
  transition: opacity 220ms ease, margin-right 260ms cubic-bezier(.16,1,.3,1);
}
.btn-bracket:hover .prefix {
  opacity: 1;
  margin-right: 0;
}
.btn-bracket:hover {
  background-color: var(--t1);
  color: var(--bg);
  border-color: var(--t1);
}
.btn-bracket:hover .arr { color: var(--bg); }
.btn-bracket-meta {
  display:block;
  margin-top: 14px;
  font-family: var(--font-mono);
  font-size: var(--size-micro);
  letter-spacing: var(--track-terminal);
  color: var(--t2);
  font-variant-numeric: tabular-nums;
}
.btn-bracket-meta .acc { color: var(--accent); }

/* --------  .btn-tick  — secondary, underline with end ticks  -------- */
.btn-tick {
  padding: 18px 4px;
  gap: 12px;
  color: var(--t1);
  border: 0;
  background: transparent;
  position: relative;
}
.btn-tick::before {
  content:'';
  position:absolute;
  left:0; right:0; bottom: 6px;
  height:1px;
  background: var(--t1);
  transform-origin: left;
  transition: background-color 260ms;
}
.btn-tick::after {
  content:'';
  position:absolute;
  left:0; right:0; bottom: 3px;
  height: 7px;
  pointer-events:none;
  background:
    linear-gradient(var(--t1),var(--t1)) 0 0 / 1px 100% no-repeat,
    linear-gradient(var(--t1),var(--t1)) 100% 0 / 1px 100% no-repeat;
  transition: background-image 260ms;
}
.btn-tick:hover { color: var(--accent); }
.btn-tick:hover::before { background: var(--accent); }
.btn-tick:hover::after {
  background:
    linear-gradient(var(--accent),var(--accent)) 0 0 / 1px 100% no-repeat,
    linear-gradient(var(--accent),var(--accent)) 100% 0 / 1px 100% no-repeat;
}
.btn-tick .arr { color: var(--accent); }
.btn-tick:hover .arr { color: var(--accent); }

.cta__foot {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 20px; align-items: center;
  padding-top: 24px;
  border-top: 1px solid #1e1e1e;
  font-family: var(--font-mono);
  font-size: var(--size-micro); letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: #666;
}
.cta__foot a {
  color: #a0a0a0;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 240ms, border-color 240ms;
}
.cta__foot a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.cta__foot .c { text-align: center; }
.cta__foot .r { text-align: right; }

/* =====================================================
   Preload (blockers for GSAP)
   Hides everything that has a reveal animation so nothing flashes in
   the wrong theme between page-load and the scroll trigger firing.
   ===================================================== */
.preload .hero__display .c { opacity: 0; transform: translateY(110%); }
.preload .hero .hero__ribbon > *,
.preload .hero__cmd,
.preload .hero__sub,
.preload .hero__readout .cell,
.preload .hero__foot > * { opacity: 0; }

/* About */
.preload .about__photo,
.preload .about__bio40,
.preload .about__nameline,
.preload .about__prose p { opacity: 0; }

/* Steps */
.preload .panel__header > *,
.preload .steps__lede,
.preload .step-row { opacity: 0; }

/* Scope */
.preload .scope__col h4,
.preload .scope__list li { opacity: 0; }

/* Pricing */
.preload .pricing__ribbon > *,
.preload .pricing__floor,
.preload .pricing__close,
.preload .pricing__lede { opacity: 0; }

/* Reports */
.preload .reports__ribbon > *,
.preload .reports__lede,
.preload .reports__sub,
.preload .reports__row { opacity: 0; }

/* FAQ */
.preload .faq__item { opacity: 0; }

/* CTA */
.preload .cta__ribbon > *,
.preload .cta__display,
.preload .cta__sub,
.preload .cta__actions,
.preload .cta__foot { opacity: 0; }

/* =====================================================
   Reduced motion
   ===================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .preload .hero__display .c,
  .preload .hero .hero__ribbon > *,
  .preload .hero__cmd,
  .preload .hero__sub,
  .preload .hero__readout .cell,
  .preload .hero__foot > * { opacity:1; transform:none; }
  .hero__canvas, .fx-bg { display:none; }
  .hero, .cta { background:#0a0a0a; }
}

/* =====================================================
   Mobile (≤ 840)
   ===================================================== */
@media (max-width: 840px) {
  /* Tablet / large-phone tier. Halve the vertical breathing room
     between sections — the desktop 96/64 stack adds up to ~250px of
     dead air between adjacent section content on narrow viewports.
     Custom properties cascade through .section-wrap, .pricing, .sep
     so a single override scales all three. */
  :root {
    --gb-section-pad-y: 64px;
    --sep-pad-y: 40px;
  }
  .section-wrap, .pricing { padding-left: 20px; padding-right: 20px; }

  /* Mobile flavor-fluff suppression. The "terminal chrome" the page
     leans on at desktop width (ribbons listing STATE/STACK/UP, fake
     prompt lines, "STARTED 2026 · TORONTO · ONTARIO · CA"
     subtitles, "Hey, I'm Juls." over the bio, the "+ YOUR BUSINESS
     · request audit" row at the foot of the reports list, the
     "Start here · AUDIT REQUEST · RESPONSE: ≤ 3 DAYS" ribbon at
     the top of the CTA, the "06 — QUESTIONS I GET ASKED //
     TRANSCRIPT" panel header that duplicates the QUESTIONS sep
     above it) all compress badly on phones — they eat the room
     the actual headline / body copy needs. Hide them here so
     mobile shows just the load-bearing content. Keeps the desktop
     personality untouched. */
  .hero__ribbon,
  .hero__cmd,
  .hero__foot,
  .about__bio40,
  .about__nameline,
  .reports__row--cta,
  .cta__ribbon,
  .faq__wrap > .panel__header { display: none; }

  /* About prose — paragraph breaks on mobile only. The desktop
     copy is one long <p>; on mobile that reads as a wall. Break
     it via inline <span class="about__prose__break"> placed at
     paragraph boundaries — display:block on the span inserts a
     visible line break inside the same <p>, so JS that animates
     `.about__prose p` as a single element keeps working. */
  .about__prose__break {
    display: block;
    height: 0.9em;
  }

  /* Hero subhead readability. The WebGL ASCII shader behind the
     hero is busy; on phones it overlaps the body copy enough to
     hurt contrast. Layered text-shadow gives the copy a soft
     dark halo + faint accent glow so it lifts off the canvas
     without needing a solid backdrop pill. */
  .hero__sub {
    color: #e0e0e0;
    text-shadow:
      0 0 14px rgba(0, 0, 0, 0.95),
      0 0 28px rgba(0, 0, 0, 0.7),
      0 0 36px rgba(194, 60, 42, 0.45);
  }
  .hero__frame { padding: 48px 16px 20px; }
  .hero__body { padding: 40px 12px 16px; }
  .hero__ribbon { grid-template-columns: 1fr; gap: 10px; }
  .hero__ribbon .rule { display:none; }
  .hero__readout { grid-template-columns: 1fr 1fr; }
  .hero__readout .cell:nth-child(2) { border-right: 0; }
  .hero__readout .cell:nth-child(1),
  .hero__readout .cell:nth-child(2) {
    border-bottom: 1px solid #1e1e1e;
  }
  .hero__foot { grid-template-columns: 1fr; }
  .hero__foot .rule { display: none; }
  .hero__foot .right { text-align: left; }

  .about__grid { grid-template-columns: 1fr; gap: 40px; }
  .about__photo { max-width: 260px; }

  .steps__wrap { grid-template-columns: 1fr; gap: 8px; }
  .steps__rail { display: none; }
  .step-row { grid-template-columns: 64px 1fr; gap: 16px; padding: 28px 0; }
  .step-row__n { font-size: 44px; }
  .step-row__label { grid-column: 2; }
  .step-row__desc { grid-column: 1 / -1; margin-top: 8px; }
  .step-row__meta { grid-column: 1 / -1; text-align: left; margin-top: 6px; }

  .scope__grid { grid-template-columns: 1fr; gap: 40px; }

  .pricing__step { grid-template-columns: 56px 1fr; gap: 12px; }
  .pricing__step .len { grid-column: 1 / -1; text-align: left; padding-top: 8px; }

  .faq__item summary { grid-template-columns: 36px 1fr 28px; gap: 12px; font-size: 16px; }
  .faq__item .a { padding: 0 0 24px 56px; }

  /* CTA — centre everything on mobile. The desktop layout is
     left-aligned with the bracketed primary button on the left
     and the secondary 30-min-call link below it; on phones that
     reads as awkwardly off-axis when the headline is the dominant
     element. Centre the headline, body, both buttons (stacked),
     the FREE/3-business-days sublabel, and the cta__foot row. */
  .cta__display { text-align: center; }
  .cta__sub {
    text-align: center;
    margin-left: auto;
    margin-right: auto;
  }
  .cta__actions {
    flex-direction: column;
    align-items: center;
    gap: 28px;
    margin-bottom: 56px;
  }
  .cta__primary-group { align-items: center; }
  .btn-bracket-meta { text-align: center; }
  .cta__foot {
    grid-template-columns: 1fr;
    text-align: center;
  }
  .cta__foot .c,
  .cta__foot .r { text-align: center; }
  .statusbar { grid-template-columns: auto 1fr auto; font-size: 10px; }
  .statusbar .pill:not(.live) { display: none; }
  .statusbar .sid { display: none; }
  /* Swap the inline desktop section nav for a hamburger menu —
     5 anchors + cal.com link won't fit horizontally below 840px,
     and the menu reads as a deliberate mobile pattern instead of
     a cramped tablet compromise. */
  .statusbar__nav { display: none; }
  .statusbar .cal { display: none; }
  /* Pin the hamburger to the right edge — easier to reach with the
     thumb while holding a phone single-handed. With sid/nav/cal
     all display:none, the hamburger would otherwise flow into the
     1fr track right next to the LIVE pill on the left. */
  .statusbar__hamburger { grid-column: -1; }
  /* .statusbar__hamburger show rule lives further down — see the
     @media block right after the .nav-menu styles. CSS source
     order: hamburger defaults are declared after this 840px block,
     so the show rule has to come even later to win the cascade. */
}

/* =====================================================
   COPYRIGHT — page-foot disclaimer below all content
   ===================================================== */
.copyright {
  padding: 32px 28px 28px;
  border-top: 1px solid var(--rule-color);
  font-family: var(--font-mono);
  font-size: var(--size-micro);
  letter-spacing: var(--track-terminal);
  text-transform: uppercase;
  color: var(--t3);
  text-align: center;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  background: #0a0a0a;
  position: relative;
  z-index: 1;
}
.copyright__sep { color: var(--accent); }

/* =====================================================
   AUDIT REQUEST MODAL — opens from [data-modal-trigger="audit"]
   Backdrop + bracket-chrome dialog matching CTA aesthetic.
   ===================================================== */
.modal {
  position: fixed; inset: 0;
  z-index: 1000;
  display: grid; place-items: center;
  padding: clamp(16px, 4vw, 40px);
  font-family: var(--font-mono);
}
.modal[hidden] { display: none; }
body.modal-open { overflow: hidden; }

.modal__backdrop {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.78);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
  opacity: 0;
  transition: opacity 280ms ease;
}
.modal[aria-hidden="false"] .modal__backdrop { opacity: 1; }

.modal__shell {
  position: relative;
  width: min(560px, 100%);
  max-height: calc(100dvh - 64px);
  overflow: auto;
  background: #0a0a0a;
  border: 1px solid var(--rule-color);
  color: var(--t1);
  padding: 20px clamp(20px, 4vw, 32px) 24px;
  transform: translateY(8px);
  opacity: 0;
  transition: transform 320ms cubic-bezier(.2,.7,.2,1), opacity 320ms ease;
}
.modal[aria-hidden="false"] .modal__shell {
  transform: translateY(0);
  opacity: 1;
}

.modal__ribbon {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--t2);
  border-bottom: 1px solid var(--rule-color);
  padding-bottom: 10px;
  margin-bottom: 18px;
  text-transform: uppercase;
}
.modal__ribbon b { color: var(--t1); font-weight: 700; }
.modal__ribbon .slash { color: var(--accent); }

.modal__close {
  background: transparent; border: 0;
  color: var(--t1);
  font-size: 22px; line-height: 1;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  cursor: pointer;
  transition: color 150ms ease;
}
.modal__close:hover { color: var(--accent); }

.modal__title {
  font-family: var(--font-mono);
  font-size: clamp(28px, 4.4vw, 38px);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.01em;
  margin: 0 0 10px;
  color: var(--t1);
}
.modal__title .acc { color: var(--accent); }

.modal__sub {
  font-size: 13px;
  line-height: 1.55;
  color: var(--t2);
  margin: 0 0 28px;
}
.modal__sub .acc { color: var(--accent); font-weight: 700; }

.modal__form {
  display: flex; flex-direction: column;
  gap: 20px;
}
.modal__honeypot {
  position: absolute !important;
  left: -9999px !important;
  opacity: 0;
  height: 0; width: 0;
  pointer-events: none;
}

.modal__field {
  display: flex; flex-direction: column;
  gap: 9px;
}
.modal__label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--t2);
  text-transform: uppercase;
}
.modal__req { color: var(--accent); margin-left: 2px; }

.modal__field input,
.modal__field textarea {
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--t1);
  background: #060606;
  border: 1px solid var(--rule-color);
  padding: 12px 14px;
  outline: none;
  transition: border-color 150ms ease, background 150ms ease;
  width: 100%;
  resize: vertical;
}
.modal__field input::placeholder,
.modal__field textarea::placeholder {
  color: var(--t3);
}
.modal__field input:focus,
.modal__field textarea:focus {
  border-color: var(--accent);
  background: #050505;
}

.modal__actions {
  display: flex; flex-direction: column;
  gap: 12px;
  margin-top: 14px;
}
.modal__submit {
  align-self: flex-start;
  min-width: 220px;
}
.modal__submit[disabled] {
  opacity: 0.5;
  cursor: wait;
  pointer-events: none;
}

/* gb-btn-rail — borderless CTA from canonical component catalog.
   Source: design/components/buttons/rail/. Ported inline because
   the marketing-site dist is flat and pulls from a single CSS. */
.gb-btn-rail {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 14px 0 18px;
  background: transparent;
  color: var(--text-1, var(--t1));
  border: 0;
  position: relative;
  isolation: isolate;
  transition: color 220ms, transform 120ms;
  user-select: none;
  text-align: left;
}
.gb-btn-rail:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}
.gb-btn-rail:active {
  transform: translateY(1px) scale(0.985);
}
.gb-btn-rail__out {
  position: relative;
  z-index: 2;
  display: inline-block;
}
.gb-btn-rail__arrow {
  display: inline-block;
  margin-left: 10px;
  color: var(--text-1, var(--t1));
  will-change: transform, color;
  transition: transform 380ms cubic-bezier(0.16, 1, 0.3, 1), color 240ms;
}
.gb-btn-rail__track {
  position: absolute;
  left: 0; right: 0;
  bottom: 6px;
  height: 1px;
  background: var(--surface-3, var(--rule-color));
}
.gb-btn-rail__fill {
  position: absolute;
  left: 0;
  bottom: 6px;
  height: 1px;
  background: var(--accent);
  width: 0;
  box-shadow: 0 0 8px rgba(194, 60, 42, 0.6);
  will-change: width;
}
.modal__meta {
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--t3);
  text-transform: uppercase;
}
.modal__meta .acc { color: var(--accent); font-weight: 700; }

.modal__status {
  font-size: 13px;
  padding: 10px 12px;
  border-left: 2px solid var(--accent);
  background: rgba(194, 60, 42, 0.08);
  color: var(--t1);
  margin-top: 4px;
  line-height: 1.5;
}
.modal__status.is-success {
  border-left-color: #2c8e3e;
  background: rgba(44, 142, 62, 0.10);
}
.modal__status.is-error {
  border-left-color: var(--accent);
  background: rgba(194, 60, 42, 0.12);
}

@media (max-width: 560px) {
  /* Phone tier — tighter still than the 840px tablet block above,
     plus targeted layout collapses for elements the tablet break
     left in their desktop form. */
  :root {
    --gb-section-pad-y: 40px;
    --sep-pad-y: 24px;
  }

  /* Section dividers (.sep): allow the label to wrap instead of
     clipping off the right edge ("/// MONEY · PACKET 03 OF 05" was
     overflowing the viewport at iPhone widths). Drop the side rules
     and centre-stack the label + packet number on its own line. */
  .sep {
    padding-left: 20px;
    padding-right: 20px;
    grid-template-columns: 1fr;
    text-align: center;
  }
  .sep .rule { display: none; }
  .sep .label {
    white-space: normal;
    font-size: var(--size-base);
  }
  .sep .label .topic-glyph { font-size: 1.1em; margin-right: 8px; }
  .sep .label .acc {
    display: block;
    font-size: 0.65em;
    margin-left: 0;
    margin-top: 4px;
  }

  /* Reports rows: collapse to a single column so titles get full
     width and stop mid-word hyphenating ("VFX & TECHNICAL- ART
     PORTFOLIO"). The hover-preview button is hidden on touch via
     `@media (hover: none)` further down, so on phone-with-mouse it
     stacks below the title; on phone-touch it's gone entirely. */
  .reports__row__link { grid-template-columns: 1fr; }
  .reports__preview-trigger {
    grid-column: 1;
    grid-row: auto;
    justify-self: start;
    margin-top: 12px;
  }

  /* Sticky top nav: tighten padding/gap. The hamburger swap and
     cal hide already happened at the 840px tier above; here we
     just compress the LIVE pill + hamburger stripe further. */
  .statusbar { padding: 8px 14px; gap: 12px; }

  /* FAQ — the 840px tier left a 56px left indent on .a + the
     untouched 80px x-padding on .a__inner stacked to ~136px of
     left-side padding, squashing the answer text to ~130px wide
     on a 390px phone (≈12 mono chars per line — unreadable).
     Reset both at this tier so the answer fills the row. */
  .faq__item summary {
    grid-template-columns: auto 1fr 24px;
    gap: 10px;
    font-size: 15px;
    padding: 18px 0;
  }
  .faq__item .qn { font-size: 10px; padding-top: 4px; }
  .faq__item .a { padding: 0; }
  .faq__item .a__inner { padding: 4px 0 20px 0; max-width: none; }
  .faq__item .a::before {
    /* Drop the floating "A" marker — at this width it would clip
       into the answer text without the desktop's 80px gutter. */
    display: none;
  }

  /* Modal — preserved from the previous 560px block. */
  .modal__shell {
    padding: 16px 18px 20px;
    max-height: calc(100dvh - 32px);
  }
  .modal__title { font-size: 26px; }
}

/* Mobile / touch: keep the trigger visible (now wired for tap),
   bigger / fuller-width for thumb accessibility, and drop the
   "Hover an entry to preview." sentence fragment from the reports
   lede in favour of the TAP variant on the trigger itself. Width
   OR touch triggers it so DevTools mobile-emulation matches what
   a real phone shows. */
@media (max-width: 840px), (hover: none) {
  .reports__sub .hover-only { display: none; }
  .reports__preview-trigger {
    width: 100%;
    justify-content: center;
    padding: 14px 16px;
    font-size: var(--size-xs);
    margin-top: 14px;
  }
}

/* =====================================================
   MOBILE HAMBURGER + NAV MENU
   Hamburger lives inside .statusbar; menu overlay sits as a
   sibling below, sliding down from under the statusbar when
   toggled. Both are display:none on desktop — the inline
   .statusbar__nav handles desktop section nav.
   ===================================================== */
.statusbar__hamburger {
  display: none;
  background: transparent;
  border: 0;
  padding: 8px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  position: relative;
  width: 40px;
  height: 40px;
  color: inherit;
}
.statusbar__hamburger__bar {
  position: absolute;
  left: 8px;
  right: 8px;
  height: 1.5px;
  background: currentColor;
  transition: transform 240ms cubic-bezier(.16,1,.3,1), opacity 200ms ease;
}
.statusbar__hamburger__bar:nth-child(1) { top: 14px; }
.statusbar__hamburger__bar:nth-child(2) { top: 19px; }
.statusbar__hamburger__bar:nth-child(3) { top: 24px; }
.statusbar__hamburger[aria-expanded="true"] .statusbar__hamburger__bar:nth-child(1) {
  transform: translateY(5px) rotate(45deg);
}
.statusbar__hamburger[aria-expanded="true"] .statusbar__hamburger__bar:nth-child(2) {
  opacity: 0;
}
.statusbar__hamburger[aria-expanded="true"] .statusbar__hamburger__bar:nth-child(3) {
  transform: translateY(-5px) rotate(-45deg);
}

.nav-menu {
  position: fixed;
  inset: 0;
  z-index: 49; /* sits behind the statusbar (z:50) — backdrop covers
                  page content but the hamburger remains clickable. */
  display: none;
  font-family: var(--font-mono);
}
.nav-menu[hidden] { display: none; }
.nav-menu:not([hidden]) { display: block; }
.nav-menu__backdrop {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.78);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
  opacity: 0;
  transition: opacity 280ms ease;
}
.nav-menu[aria-hidden="false"] .nav-menu__backdrop { opacity: 1; }
.nav-menu__shell {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  background: var(--page-bg);
  border-bottom: 1px solid var(--page-rule);
  padding: 60px 20px 24px; /* top padding clears the 49px statusbar */
  transform: translateY(-12px);
  opacity: 0;
  transition: transform 320ms cubic-bezier(.2,.7,.2,1), opacity 280ms ease;
}
.nav-menu[aria-hidden="false"] .nav-menu__shell {
  transform: translateY(0);
  opacity: 1;
}
.nav-menu__list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.nav-menu__list li:not(.nav-menu__sep) {
  border-bottom: 1px solid var(--page-rule);
}
.nav-menu__list li:not(.nav-menu__sep):last-child {
  border-bottom: 0;
}
.nav-menu__sep {
  height: 16px;
}
.nav-menu__list a {
  display: block;
  padding: 18px 8px;
  color: var(--page-t1);
  text-decoration: none;
  font-size: 16px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transition: color 220ms ease, background-color 220ms ease;
  cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.nav-menu__list a:active {
  background: rgba(194, 60, 42, 0.08);
}
.nav-menu__cal {
  color: var(--page-t2) !important;
  text-transform: none !important;
  font-size: 14px !important;
}
body.nav-menu-open { overflow: hidden; }

/* Show the hamburger at mobile widths. Lives after the default
   `.statusbar__hamburger { display: none }` declaration above so
   it wins the source-order cascade. */
@media (max-width: 840px) {
  .statusbar__hamburger { display: block; }
}

