/* ==========================================================================
   COMMBLUE — story.css
   The narrative layer for the two home pages. Loaded AFTER main.css, which
   stays the shared design system (Education still runs on it alone).

   Rule that governs this whole file: nothing here may hide content.
   Every from-state of every animation is set by GSAP at runtime, never in
   CSS, so a blocked CDN or a thrown script leaves a complete, readable
   document behind. The only things gated on the .anim class are
   LAYOUT affordances the choreography needs (pin heights, sticky rails) —
   absence of the class simply means normal document flow.
   ========================================================================== */

:root {
  /* Grain stays under 4% so it never fights body copy for legibility. */
  --grain-opacity: 0.04;
  /* HARD RULE — anything above 5rem is for NUMBERS and phrases of three words
     or fewer, nothing else. A sentence in display type belongs on
     --fs-sentence; a paragraph belongs on --fs-intro and carries no display
     family at all. The audit that enforces this lives in the QA harness: it
     lists every element computing over 80px and each one has to be a hero H1,
     a counter, a Blue Room line or the footer wordmark. */
  --fs-mega: clamp(4rem, 11vw, 11rem);
  --fs-sentence: clamp(2.5rem, 5.5vw, 5rem);
  --fs-manifesto: clamp(2.75rem, 6vw, 6.5rem);
  --fs-intro: clamp(21px, 2vw, 28px);
}

/* ScrollTrigger and CSS smooth-scroll fight over scroll position. */
html.anim {
  scroll-behavior: auto;
}

/* --------------------------------------------------------------------------
   ACTS — shared shell
   -------------------------------------------------------------------------- */
.act {
  position: relative;
}
.act__pin {
  position: relative;
  padding: var(--section-y-tight) 0;
}
/* Only once the choreography is actually alive — and only where it actually
   runs, which is above 760px — do acts claim a full screen. */
@media (min-width: 761px) {
  .anim .act--pin .act__pin {
    /* 88vh, not 100: the pinned scenes still own the screen, and two of them
       at 12vh less each is another chunk of scroll back. */
    min-height: 88vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: var(--space-9) 0;
  }
}

/* Numbers and three-word phrases only. */
.mega {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-mega);
  letter-spacing: -0.055em;
  line-height: 0.86;
  color: var(--text-hi);
}
/* Anything longer than three words in display type lives here. */
.h-sentence {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-sentence);
  letter-spacing: -0.045em;
  line-height: 1;
  color: var(--text-hi);
}
/* A paragraph that opens a section. Body family, body weight, just larger —
   not display type. This is where prose goes when it wants presence. */
.intro {
  font-size: var(--fs-intro);
  line-height: 1.45;
  color: var(--text-hi);
  max-width: 40ch;
}

/* A breath: the quiet act between two loud ones. */
.act--breath {
  padding: var(--section-y) 0;
}

/* --------------------------------------------------------------------------
   ACT 0 — COLD OPEN
   -------------------------------------------------------------------------- */
.act0 {
  border-bottom: var(--rule);
}
.act0 .container {
  display: grid;
  gap: var(--space-8);
  justify-items: center;
}
.chat--hero {
  width: min(820px, 100%);
}
/* No pin here any more — the cold open plays itself on load and the visitor
   scrolls over it whenever they like. It still owns most of a screen. */
@media (min-width: 761px) {
  .anim .act0 .act__pin {
    /* Enough to read as a cold open, not enough to be a toll gate. */
    min-height: 72vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: var(--space-8) 0;
  }
}
.act0__line {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-serif-lg);
  line-height: 1.2;
  letter-spacing: var(--ls-serif);
  color: var(--text-mid);
  text-align: center;
  max-width: 22ch;
  transform: rotate(-0.6deg);
}
/* The caret that survives the fade-out. */
.act0__caret {
  display: none;
}
.gsap-on .act0__caret {
  display: block;
  width: 0.42em;
  height: 1.1em;
  font-size: clamp(28px, 4vw, 56px);
  background: var(--electric-500);
  animation: cb-blink 1.05s steps(1, end) infinite;
  margin: 0 auto;
}

/* --------------------------------------------------------------------------
   ACT 1 — HERO + BRAND INPUT
   -------------------------------------------------------------------------- */
.hero--story .hero__h1 {
  font-size: clamp(42px, 11vw, 168px);
  max-width: 15ch;
}
.brandform {
  margin-top: var(--space-7);
  max-width: 46ch;
}
/* Dead control without JS — the copy around it carries the point instead. */
html:not(.js) .brandform {
  display: none;
}
.brandform__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: 10px;
  transition: border-color var(--dur-fast) var(--ease-heavy);
}
.brandform__row:focus-within {
  border-bottom-color: var(--electric-500);
}
.brandform__mark {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  color: var(--signal-text);
  flex: 0 0 auto;
}
.brandform input {
  flex: 1;
  min-width: 0;
  appearance: none;
  background: transparent;
  border: 0;
  outline: none;
  color: var(--text-hi);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--ls-mono);
  text-transform: uppercase;
  padding: 6px 0;
  min-height: 32px;
  cursor: crosshair;
}
.brandform input::placeholder {
  color: var(--text-lo);
  text-transform: none;
  letter-spacing: 0.06em;
}
.brandform input:focus-visible {
  box-shadow: none;
}
/* The typed brand, once it takes over the headline. */
.hero__brand {
  color: var(--electric-500);
}
.brandform__note {
  margin-top: var(--space-4);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body);
  color: var(--text-lo);
  max-width: 52ch;
}

/* Ticker pair, opposite directions, slow. */
.tickers {
  border-top: var(--rule);
  border-bottom: var(--rule);
}
.tickers .marquee {
  border-top: 0;
  border-bottom: 0;
}
.tickers .marquee + .marquee {
  border-top: var(--rule);
}

/* --------------------------------------------------------------------------
   ACT 2 — THE DROP (the funeral of the ten links)
   -------------------------------------------------------------------------- */
.serp {
  display: grid;
  gap: 10px;
  max-width: 720px;
}
.serp__row {
  display: grid;
  gap: 7px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border-subtle);
}
.serp__url {
  font-family: var(--font-mono);
  font-size: var(--fs-mono-xs);
  letter-spacing: 0.1em;
  color: var(--text-lo);
}
/* The ten links are a shape, not a claim: hairline bars, no invented prose. */
.serp__bar {
  height: 10px;
  background: var(--depth-2);
  width: var(--w, 70%);
}
.serp__bar--title {
  height: 13px;
  background: #1d2a44;
  width: var(--w, 58%);
}
/* The rest of the page of results: no names, just the shape of a list,
   collapsing away. Purely decorative, so it is aria-hidden in the markup. */
.serp__rest {
  display: grid;
  gap: 6px;
  margin-top: var(--space-4);
}
.serp__rest span {
  height: 8px;
  background: var(--depth-2);
}
.serp__rest span:nth-child(1) { width: 78%; }
.serp__rest span:nth-child(2) { width: 64%; }
.serp__rest span:nth-child(3) { width: 71%; }
.serp__rest span:nth-child(4) { width: 55%; }
.serp__rest span:nth-child(5) { width: 68%; }
.serp__more {
  margin-top: var(--space-3);
}
.serp__answer {
  outline: 1px solid var(--electric-500);
  outline-offset: -1px;
  background: var(--surface-panel);
  padding: clamp(24px, 4vw, 48px);
  max-width: 720px;
  display: grid;
  gap: var(--space-4);
}
.serp__answer p:first-child {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(30px, 5vw, 66px);
  letter-spacing: var(--ls-display-tight);
  line-height: 0.96;
  color: var(--text-hi);
}
.act2__stage {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: var(--space-9);
  align-items: center;
}
/* Evidence: the same four figures. They used to enter one per scroll beat
   inside the pin, which cost about six screens on its own. Now they are a
   static band directly under the scene — same copy, same sources, read at
   a glance instead of unlocked one at a time. */
.evidence {
  display: grid;
  gap: var(--space-8);
}
.evidence--band {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-6);
  border-top: var(--rule);
  padding-top: var(--space-7);
  margin-top: var(--space-9);
}
.evidence--band .evidence__item {
  border-top: 0;
  padding-top: 0;
}
.evidence--band .evidence__n {
  font-size: clamp(38px, 4.6vw, 68px);
}
.evidence--band .evidence__label {
  font-size: var(--fs-body-sm);
  max-width: none;
}
.evidence__item {
  border-top: var(--rule);
  padding-top: var(--space-5);
}
.evidence__n {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(56px, 8vw, 128px);
  letter-spacing: -0.05em;
  line-height: 0.86;
  color: var(--text-hi);
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.evidence__n span {
  font-size: 0.36em;
  color: var(--signal-text);
  letter-spacing: 0;
}
.evidence__label {
  margin-top: var(--space-4);
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body-tight);
  color: var(--text-mid);
  max-width: 34ch;
}
.evidence__src {
  margin-top: var(--space-3);
}

/* --------------------------------------------------------------------------
   ACT 3 — THE SHIFT (the number that hurts)
   -------------------------------------------------------------------------- */
.act3__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: var(--space-9);
  align-items: center;
}
/* The counter IS the number in the sentence — one clause, two scales, so it
   lives inside the h2 rather than repeating above it. */
.bignum {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-mega);
  letter-spacing: -0.06em;
  line-height: 0.86;
  color: var(--text-hi);
  display: flex;
  align-items: baseline;
  font-variant-numeric: tabular-nums;
  margin-bottom: var(--space-3);
}
.bignum span {
  font-size: 0.3em;
  color: var(--signal-text);
  letter-spacing: 0;
}

.srcmap {
  display: grid;
  gap: 0;
}
.srcmap__nodes {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-3);
}
.srcmap__nodes li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono-sm);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-mid);
  border: 1px solid var(--border-subtle);
  padding: 7px 10px;
}
.srcmap__nodes li::before {
  content: "";
  width: 6px;
  height: 6px;
  background: var(--signal-text);
  flex: 0 0 auto;
}
.srcmap__lines {
  display: block;
  width: 100%;
  height: clamp(48px, 7vw, 96px);
}
.srcmap__lines line {
  stroke: var(--border-strong);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.srcmap__answer {
  justify-self: center;
  outline: 1px solid var(--electric-500);
  outline-offset: -1px;
  background: var(--surface-panel);
  padding: var(--space-5) var(--space-7);
  text-align: center;
  display: grid;
  gap: 6px;
}
.srcmap__pct {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(34px, 4.6vw, 60px);
  letter-spacing: -0.05em;
  line-height: 1;
  color: var(--text-hi);
}

.bars {
  display: grid;
  gap: var(--space-5);
  margin-top: var(--space-8);
  max-width: 560px;
}
.bar__head {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: 8px;
}
.bar__val {
  color: var(--text-hi);
  font-variant-numeric: tabular-nums;
}
.bar__track {
  height: 14px;
  background: var(--depth-2);
  outline: 1px solid var(--border-subtle);
  outline-offset: -1px;
}
.bar__fill {
  display: block;
  height: 100%;
  width: var(--v);
  background: var(--electric-500);
  transform-origin: left center;
}
.bar--weak .bar__fill {
  background: var(--hairline-hi);
}

/* --------------------------------------------------------------------------
   ACT 4 — THE METHOD (one artefact, four states)
   -------------------------------------------------------------------------- */
.method {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: var(--space-9);
  align-items: start;
}
.method__rail {
  display: grid;
  gap: var(--space-6);
}
.anim .method__panel {
  position: sticky;
  top: calc(var(--nav-h) + var(--space-6));
}
.phase {
  border-left: 2px solid var(--border-subtle);
  padding-left: var(--space-5);
  transition: border-color var(--dur-base) var(--ease-heavy);
}
.phase.is-on {
  border-left-color: var(--electric-500);
}
.phase__n {
  font-family: var(--font-mono);
  font-size: var(--fs-mono-xs);
  letter-spacing: var(--ls-mono-wide);
  color: var(--signal-text);
  margin-bottom: var(--space-3);
}
.phase h3 {
  font-size: clamp(24px, 3vw, 40px);
  letter-spacing: var(--ls-display-tight);
  line-height: 1.02;
  margin-bottom: var(--space-4);
}
.phase p {
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body);
  color: var(--text-lo);
  max-width: 44ch;
}
.phase__out {
  margin-top: var(--space-4);
}
/* The one artefact the whole act happens to. */
.coverage {
  display: flex;
  gap: 6px;
  margin-top: var(--space-4);
}
.coverage__cell {
  flex: 1;
  height: 8px;
  background: var(--depth-2);
  outline: 1px solid var(--border-subtle);
  outline-offset: -1px;
}
.coverage__cell.is-on {
  background: var(--electric-500);
  outline-color: var(--electric-500);
}
/* Four pre-rendered coverage readings; one shows at a time. With no JS the
   4/4 state is the one marked in the HTML, so the artefact still reads. */
.cov-label {
  display: none;
}
.cov-label.is-on {
  display: inline;
}

/* --------------------------------------------------------------------------
   SERVICES
   -------------------------------------------------------------------------- */
.panel-grid--services {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.cards--compact .card {
  padding: var(--space-6) var(--space-5);
  gap: var(--space-3);
}
.cards--compact .card h3 {
  font-size: var(--fs-subheading);
}

/* --------------------------------------------------------------------------
   ACT 6 — THE BLUE ROOM
   The one inverted moment on the page. Blue stops being the signal and
   becomes the room.
   -------------------------------------------------------------------------- */
.blueroom {
  background: var(--electric-500);
  color: var(--void);
  border-top: 0;
  border-bottom: 0;
  padding: var(--section-y) 0;
  position: relative;
  overflow: hidden;
}
/* Natural height with generous padding, not a full screen. The four lines and
   the colour inversion do the work; the empty space below them did not. */
.blueroom {
  padding: clamp(72px, 9vw, 132px) 0;
}
@media (min-width: 761px) {
  .anim .blueroom {
    min-height: 60vh;
    display: flex;
    align-items: center;
  }
}
.blueroom__lines {
  display: grid;
  gap: clamp(4px, 0.6vw, 12px);
}
.blueroom__lines p {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-manifesto);
  letter-spacing: -0.055em;
  line-height: 0.94;
  color: var(--void);
  max-width: 22ch;
}
.blueroom__lines p:last-child {
  color: #ffffff;
}
/* White, not Void: at 10px the caption needs 4.5:1, and void-on-blue is
   3.65:1 — fine for the display lines, not for a mono provenance row. */
.blueroom .mono {
  color: #ffffff;
  margin-top: var(--space-8);
}
/* The dead pixel inverts here: black square on blue. */
.deadpixel--inverted {
  background: var(--void);
}

/* --------------------------------------------------------------------------
   REDACTION — story pages use it as a real device, three times
   -------------------------------------------------------------------------- */
.redaction--wide {
  white-space: normal;
}

/* --------------------------------------------------------------------------
   RESPONSIVE
   -------------------------------------------------------------------------- */
@media (max-width: 1080px) {
  .act2__stage,
  .act3__grid,
  .method {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-8);
  }
  .anim .method__panel {
    position: static;
  }
  .serp,
  .serp__answer {
    max-width: none;
  }
}

@media (max-width: 760px) {
  /* No Act 0 fade-out down here, so nothing for the caret to survive. */
  .gsap-on .act0__caret {
    display: none;
  }
  .srcmap__nodes {
    justify-content: flex-start;
  }
  .srcmap__lines {
    display: none;
  }
  .srcmap__answer {
    justify-self: start;
    margin-top: var(--space-5);
  }
  .evidence {
    gap: var(--space-7);
  }
}

@media (max-width: 1080px) {
  .evidence--band {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 620px) {
  .evidence--band {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --------------------------------------------------------------------------
   REDUCED MOTION — no pins, no scrub, no decode, no counter, no marquee.
   story.js bails out entirely; these rules undo the layout affordances so
   the page is a plain, complete document in its final state.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .anim .act--pin .act__pin {
    min-height: 0 !important;
    display: block !important;
    padding: var(--section-y-tight) 0;
  }
  .anim .blueroom {
    min-height: 0 !important;
    display: block !important;
  }
  .anim .method__panel {
    position: static;
  }
  .gsap-on .act0__caret {
    display: none;
  }
  .phase {
    border-left-color: var(--electric-500);
  }
}
