/* ===========================================================================
   xemulator -- landing surface (xemulator.com)
   Composition only. Every token, primitive and component lives in
   design-system.css, which MUST be loaded first. See DESIGN.md.
   =========================================================================== */

/* ---------- page frame ---------- */

.skip-link {
  position: absolute;
  left: var(--s4);
  top: -100px;
  z-index: var(--z-skip);
  background: var(--ink);
  color: var(--paper);
  padding: 10px 16px;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  transition: top var(--dur-2) var(--ease-out);
}
.skip-link:focus { top: var(--s3); }

/* One left edge for the whole page. The masthead, the disclosure bar and the
   footer are full-bleed strips so their rules run to the window, but their
   contents start on the same line as the content column -- otherwise the page
   has three different margins and reads as unconsidered before a word of it
   is read. */
:root {
  --edge: max(var(--gutter), calc((100% - var(--page-max)) / 2 + var(--gutter)));
}

main {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--gutter) var(--s9);
}

/* ---------- protocol bar: the standing simulation disclosure ---------- */

.protocol-bar {
  display: flex;
  align-items: center;
  gap: var(--s4);
  padding: 9px var(--edge);
  border-bottom: 1px solid var(--ink);
  background: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--size-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  flex-wrap: wrap;
  row-gap: var(--s1);
}
.protocol-bar b { color: var(--ink); font-weight: 600; }
.protocol-bar__flag {
  flex: none;
  color: var(--paper);
  background: var(--ink);
  padding: 3px 8px;
  font-weight: 600;
}

/* ---------- masthead ---------- */

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  padding: var(--s4) var(--edge);
  border-bottom: 1px solid var(--line);
}
.masthead__nav { display: flex; align-items: center; gap: var(--s4); }

/* The lockup reads XE: the X mark is the first letter, the E is the second.
   Both are capitals, so the mark is cut to the cap height of the wordmark and
   sits on the same baseline. Tight, not touching.

   Archivo carries a width axis and the identity already spends it -- display
   type is expanded, data type is not -- so the lockup borrows the same axis
   for its own hover: the wordmark widens the way an instrument's needle
   travels, rather than changing colour like a link. It is the one place on the
   page where the variable font is animated, and it moves nothing else: the
   mark is sized in em so it holds still, and the masthead is space-between so
   the nav does not shift. Only the wordmark grows.
   Keep this rare. A page where every label breathes on hover is a page where
   the breathing means nothing. */
.brand {
  display: inline-flex;
  align-items: baseline;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 21px;
  font-stretch: 112%;
  letter-spacing: -0.025em;
  text-decoration: none;
  line-height: 1;
  transition: font-stretch var(--dur-2) var(--ease-out);
}
.brand:hover, .brand:focus-visible { font-stretch: 120%; }
.brand__x {
  /* The mark's strokes are thinner than Archivo at 800, so matching cap height
     geometrically makes it read as a lowercase x. Sized to read as a capital
     beside the E, and dropped onto the same baseline. */
  height: 0.72em;
  width: 0.72em;
  flex: none;
  fill: var(--ink);
  margin-right: 0.02em;
  transform: translateY(0.035em);
  transition: fill var(--dur-1) var(--ease-out);
}
.brand__dot { color: var(--blue); }
.brand:hover .brand__x { fill: var(--blue); }

/* ===========================================================================
   THE MESH LANDING (xemulator.com/)
   ---------------------------------------------------------------------------
   This block, and only this block, departs from the flight-test system in
   design-system.css: it has radii, glass blur, shadows, glow and a dark page
   ground. The reasons and the exact scope are written down in DESIGN.md sec 10
   -- read that before extending any of it onto another surface.

   Everything else on this stylesheet (the panel, the composer, /demo, the
   trust pages) is unchanged and still paper.
   =========================================================================== */

.page--mesh {
  background: #0a0b0e;
  color: #fff;
}
/* The drafting grid is ink on paper. On this ground it is either invisible or
   a smear, so the landing simply does not rule its page. */
.page--mesh::before { display: none; }
/* The hero is the viewport, not a column inside it. */
.page--mesh main { max-width: none; margin: 0; padding: 0; }
.page--mesh ::selection { background: rgba(255, 255, 255, .22); color: #fff; }
/* One ring, re-pointed: the paper ring is a blue halo on a near-black ground
   and reads as a rendering fault rather than as focus. */
.page--mesh :focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #0a0b0e, 0 0 0 4px rgba(255, 255, 255, .85);
}

/* ---------- hero ---------- */

.mhero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  overflow: hidden;
  background: radial-gradient(1000px 640px at 55% 42%, #181b23 0%, #0a0b0e 72%);
}
.mhero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* Horizontal drags pan the mesh; vertical ones belong to the page. A
     full-viewport canvas set to touch-action:none is a scroll trap. */
  touch-action: pan-y;
}

/* The standing simulation disclosure. Legal furniture: it is the only thing
   telling a first-time reader that the faces below are arranged around an
   event that never happened. It does not come off, it does not fade, and it
   is not allowed to sit behind anything. */
.mhero__disclosure {
  position: absolute;
  top: 24px;
  right: 28px;
  z-index: 3;
  margin: 0;
  font: 600 9.5px/1 var(--font-mono);
  letter-spacing: 0.18em;
  color: rgba(255, 255, 255, .45);
  border: 1px solid rgba(255, 255, 255, .22);
  padding: 5px 8px 4px;
  border-radius: 99px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  pointer-events: none;
}

/* The event card, flown to the mesh's world point by mesh.js. Left at 0,0
   until the first frame positions it -- the transform is the whole layout. */
.mhero__event {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
  max-width: 310px;
  background: rgba(16, 19, 26, .62);
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: 16px;
  padding: 14px 18px;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 0 60px rgba(255, 255, 255, .07), inset 0 1px 0 rgba(255, 255, 255, .12);
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%);
}
.mhero__event-label {
  display: block;
  font: 600 9px/1 var(--font-mono);
  letter-spacing: 0.2em;
  color: rgba(255, 255, 255, .45);
  margin-bottom: 6px;
}
.mhero__event-text {
  display: block;
  font-size: 13.5px;
  line-height: 1.4;
  font-weight: 500;
  color: #fff;
}
/* The alert. Heat orange, and the one place on this page it is allowed: an
   event landing, not a brand accent. */
.mhero__alert {
  position: absolute;
  top: -13px;
  right: -13px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--heat);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 800 15px/1 var(--font-display);
  box-shadow: 0 0 24px rgba(232, 69, 28, .8);
  opacity: 0;
  transition: opacity .4s var(--ease-out);
}

/* ---------- the glass CTA ---------- */

.mhero__cta {
  position: absolute;
  left: 56px;
  top: 50%;
  z-index: 3;
  transform: translateY(-50%);
  width: 384px;
  max-width: calc(100% - 40px);
  background: rgba(18, 22, 30, .14);
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 20px;
  padding: 36px 34px;
  backdrop-filter: blur(26px);
  -webkit-backdrop-filter: blur(26px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), 0 30px 80px rgba(0, 0, 0, .5);
}
.mhero__mark {
  font-family: var(--font-display);
  font-weight: 800;
  font-stretch: 116%;
  font-size: 21px;
  letter-spacing: -0.02em;
  line-height: 1;
  color: #fff;
  margin-bottom: 26px;
}
.mhero__mark span { color: rgba(255, 255, 255, .4); }
.mhero__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-stretch: 116%;
  font-size: 36px;
  line-height: 1.04;
  letter-spacing: -0.025em;
  color: #fff;
  text-wrap: balance;
}
.mhero__support {
  margin: 16px 0 0;
  font-size: 14px;
  line-height: 1.55;
  color: rgba(255, 255, 255, .66);
}
.mhero__form {
  display: flex;
  gap: 8px;
  margin-top: 26px;
}
.mhero__form input {
  flex: 1 1 auto;
  min-width: 0;
  background: rgba(255, 255, 255, .08);
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: 11px;
  color: #fff;
  padding: 12px 14px;
  font: 400 14px/1.2 var(--font-body);
}
.mhero__form input::placeholder { color: rgba(255, 255, 255, .4); opacity: 1; }
.mhero__form input:hover { border-color: rgba(255, 255, 255, .34); }
.mhero__submit {
  flex: none;
  background: #fff;
  color: #0a0b0e;
  border: 0;
  border-radius: 11px;
  padding: 12px 18px;
  font: 700 13.5px/1.2 var(--font-body);
  box-shadow: 0 0 24px rgba(255, 255, 255, .25);
  transition: box-shadow var(--dur-2) var(--ease-out);
}
.mhero__submit:hover:not(:disabled) { box-shadow: 0 0 36px rgba(255, 255, 255, .45); }
.mhero__submit:disabled { opacity: .6; cursor: default; }
/* Fine print until the form reports back, then the result, in place. */
.mhero__msg {
  margin: 14px 0 0;
  font: 400 10.5px/1.6 var(--font-mono);
  color: rgba(255, 255, 255, .4);
}
.mhero__msg[data-state="ok"] { color: rgba(255, 255, 255, .8); }
.mhero__msg[data-state="error"] { color: var(--heat-on-panel); }

/* ---------- the way down ---------- */

.mhero__chev {
  position: absolute;
  left: 50%;
  bottom: 20px;
  z-index: 3;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  text-decoration: none;
  padding: 8px 18px;
  border-radius: 99px;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .14);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: background var(--dur-2) var(--ease-out);
}
.mhero__chev:hover { background: rgba(255, 255, 255, .1); }
.mhero__chev span:first-child {
  font: 600 10px/1 var(--font-mono);
  letter-spacing: 0.18em;
  color: rgba(255, 255, 255, .6);
}
.mhero__chev-glyph {
  width: 9px;
  height: 9px;
  border-right: 1.5px solid rgba(255, 255, 255, .65);
  border-bottom: 1.5px solid rgba(255, 255, 255, .65);
  transform: rotate(45deg);
  margin-top: -4px;
}

/* ---------- how it works ---------- */

.how {
  display: flex;
  flex-direction: column;
  gap: 28px;
  padding: 80px 120px 88px;
  background: #0b0c10;
  border-top: 1px solid rgba(255, 255, 255, .07);
  scroll-margin-top: 0;
}
.how__row {
  display: grid;
  grid-template-columns: 340px minmax(0, 1fr);
  gap: 52px;
  align-items: center;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 18px;
  padding: 52px 56px;
}
.how__art {
  height: 160px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.how__kicker {
  font: 600 11px/1 var(--font-mono);
  letter-spacing: 0.2em;
  color: rgba(255, 255, 255, .42);
  margin-bottom: 12px;
}
.how__head {
  font-family: var(--font-display);
  font-weight: 800;
  font-stretch: 112%;
  font-size: 24px;
  line-height: 1.1;
  letter-spacing: -0.015em;
  color: #fff;
  margin-bottom: 10px;
}
.how__body {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
  color: rgba(255, 255, 255, .65);
  max-width: 52ch;
}

/* 01: the field, mid-keystroke. */
.how__input {
  width: 270px;
  max-width: 100%;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 12px;
  padding: 15px 18px;
  display: flex;
  align-items: center;
  gap: 2px;
}
.how__input-text {
  font: 400 13.5px/1 var(--font-mono);
  color: rgba(255, 255, 255, .55);
}
.how__caret {
  width: 2px;
  height: 17px;
  background: #fff;
  box-shadow: 0 0 10px rgba(255, 255, 255, .8);
}

/* 03: ripple to firestorm. Brightest first -- the eye reads left to right and
   the label says which end is which, so the bars do not have to grow. */
.how__art--bars { gap: 8px; }
.how__bar { width: 46px; border-radius: 5px; align-self: flex-end; }
.how__bar--1 { height: 20px; background: rgba(255, 255, 255, .85); box-shadow: 0 0 18px rgba(255, 255, 255, .4); }
.how__bar--2 { height: 44px; background: rgba(255, 255, 255, .5); }
.how__bar--3 { height: 72px; background: rgba(255, 255, 255, .18); border: 1px solid rgba(255, 255, 255, .22); }
.how__bar-label {
  font: 600 11px/1 var(--font-mono);
  letter-spacing: 0.14em;
  color: rgba(255, 255, 255, .5);
  margin-left: 12px;
  align-self: flex-end;
  margin-bottom: 4px;
}

/* ---------- the deck: the live engine, kept ----------
   The composer and the run panel are the flight-test system, unchanged. What
   changes is the ground they stand on: the deck re-points the design system's
   surface tokens dark, so every primitive inside it (wells, fields, buttons,
   rules, messages) follows without a single component being rewritten. The
   panel is already dark and is untouched by any of it.

   The footer takes the same remap. Its legal block is the most important
   paragraph on the page and it is written in --ink-faint, which is a 5:1 grey
   chosen against paper and roughly 3:1 against this ground. */

.deck,
.page--mesh .siteflow {
  /* One step LIGHTER than the how-section above it, on purpose. The panel is
     `--panel` (#0e0f12) and the system's whole point is that the instrument is
     the darker surface: a deck at #0b0c10 puts a lighter panel on a darker
     ground and inverts the relationship the reader is being taught. */
  --paper:        #101218;
  --paper-raised: #161922;
  --paper-sunken: #0d0f14;
  --ink:          #ffffff;
  --ink-muted:    rgba(255, 255, 255, .78);
  --ink-faint:    rgba(255, 255, 255, .56);
  --line:         rgba(255, 255, 255, .13);
  --line-strong:  rgba(255, 255, 255, .22);
  --blue:         #8390ff;
  --blue-wash:    rgba(131, 144, 255, .16);
  --heat-ink:     #ff7047;
  --heat-wash:    rgba(232, 69, 28, .16);
  --ok-wash:      rgba(21, 122, 69, .2);
  --caution-wash: rgba(217, 178, 58, .14);
  --focus-ring:   0 0 0 2px #0b0c10, 0 0 0 4px var(--blue);
  color: #fff;
}
.deck {
  background: var(--paper);
  border-top: 1px solid rgba(255, 255, 255, .07);
}
/* The system's footer rule is a full-strength ink hairline. At this weight on
   this ground it is a white bar across the page. */
.page--mesh .siteflow { border-top-color: rgba(255, 255, 255, .1); }
.deck__inner {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--s7) var(--gutter) var(--s9);
}
.deck .section-head:first-child { margin-top: 0; }
/* Two hardcoded paper values in the system that tokens cannot reach. */
.deck ::placeholder { color: rgba(255, 255, 255, .38); }
.deck .field:hover, .deck select:hover, .deck textarea:hover, .deck input:hover {
  border-color: rgba(255, 255, 255, .32);
}
/* The primary button inverts to white-on-dark from the tokens above; its
   hover fills with signal blue, which needs its own foreground. */
.deck .btn--primary:hover:not(:disabled) { color: #0b0c10; }

/* Standby. The slot is held from the first paint; the value arrives into it. */
.readout__value[data-state="pending"] {
  color: var(--on-panel-faint);
  font-family: var(--font-mono);
  font-size: 12px;
  /* Matches the line box of the value that replaces it, so the swap at the
     end of the run does not resize the strip. */
  line-height: 20px;
  font-weight: 500;
  font-stretch: var(--wdth-normal);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

/* ---------- proofs ---------- */

.proofs { margin-top: var(--s2); }

/* ---------- section heads ---------- */

.section-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s3);
  margin: var(--s9) 0 var(--s5);
}
.section-title {
  font-size: var(--size-h3);
  letter-spacing: var(--track-tight);
  line-height: 1;
}
.section-head__note { flex: none; }
.section-head .rule { position: relative; top: -0.35em; }

/* ---------- composer ---------- */

.composer { padding: var(--s5) var(--s6) var(--s5); }
.composer__row { margin-top: var(--s5); }
.composer__row:first-of-type { margin-top: var(--s5); }
.composer__actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s4);
  margin-top: var(--s4);
  flex-wrap: wrap;
}
.composer__msg { margin-top: var(--s4); }
.composer__honesty { margin-top: var(--s4); max-width: 68ch; }

.examples { display: flex; flex-wrap: wrap; gap: var(--s2); }
.examples .chip { max-width: 100%; }

/* ---------- results ---------- */

.results { margin-top: var(--s6); }

/* The caption rail narrates every beat, and a feed sixteen posts long carries
   it off the TOP of the screen -- so by the beat that most needs narrating
   there is no narration on screen, and the provenance pill has gone with it.
   Head and rail ride with the panel, the same way the foot does, and stop
   when the panel does. The rail's offset is the head's own height, so the two
   stay a single unit and no row is ever visible between them. */
.results .panel__head {
  position: sticky;
  top: 0;
  z-index: var(--z-head);
  background: var(--panel);
}
.results .panel__caption {
  position: sticky;
  /* app.js measures the head, because the status line wraps at narrow widths
     and a fixed offset would let a feed row show through the seam. */
  top: var(--head-h, 43px);
  z-index: var(--z-sticky);
}

/* The run has to be skippable at any point, and a feed sixteen posts long
   carries its own controls off the bottom of the screen. The foot rides with
   the panel instead, and stops when the panel does. */
.results .panel__foot {
  position: sticky;
  bottom: 0;
  padding-top: var(--s3);
  background: var(--panel);
  border-top: 1px solid var(--line-panel);
  z-index: var(--z-sticky);
}
.results .panel__foot:empty { display: none; }

/* The degraded-run notice. Paper, because it is us speaking about the engine,
   and above the panel because it changes how everything inside it should be
   read. Caution, not error: nothing failed. */
.run-notice { margin-bottom: var(--s5); max-width: var(--measure); }

.shared-cta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s4);
  border: 1px solid var(--blue);
  padding: var(--s3) var(--s4);
  margin-bottom: var(--s5);
  font-size: 14.5px;
  flex-wrap: wrap;
}

.verdict {
  border: 1px solid var(--line-strong);
  background: var(--paper-raised);
  margin-top: var(--s5);
  padding: var(--s6);
  opacity: 0;
  transform: scale(0.99);
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
}
.verdict.is-stamped { opacity: 1; transform: none; }
.verdict__label {
  display: flex;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--track-wider);
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-bottom: var(--s3);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s5);
}
.verdict h2 { font-size: var(--size-h2); }
.verdict__heat { display: flex; align-items: center; gap: var(--s3); margin-top: var(--s3); flex-wrap: wrap; }
.verdict__prose { margin-top: var(--s4); font-size: var(--size-lead); max-width: var(--measure); color: var(--ink-muted); }
.verdict__note { margin-top: var(--s3); max-width: var(--measure); }
.verdict__stats {
  margin-top: var(--s5);
  padding-top: var(--s3);
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: var(--lh-relaxed);
  color: var(--ink-faint);
}

/* Standby. The slot is held from the moment the panel arms; the verdict
   arrives into it. Same mono register as the hero readout's pending state, so
   a held slot looks the same wherever it is held. */
.verdict--standby { background: var(--paper); }
.verdict__standby {
  font-family: var(--font-mono);
  font-size: var(--size-small);
  font-weight: 500;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
}
.verdict--standby .verdict__note { margin-top: var(--s2); }

/* The offer attached to a finished run. Paper, because it is us speaking, and
   sunken so it reads as the last row of the sheet rather than a second verdict. */
.run-cta {
  margin-top: var(--s4);
  border: 1px solid var(--line);
  background: var(--paper-sunken);
  padding: var(--s5) var(--s6);
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: var(--s5) var(--s6);
  align-items: center;
}
.run-cta h3 { margin-top: var(--s2); max-width: 22ch; }
.run-cta p {
  margin-top: var(--s3);
  font-size: var(--size-small);
  line-height: var(--lh-body);
  color: var(--ink-muted);
  max-width: 52ch;
}
.run-cta__actions { display: flex; flex-direction: column; gap: var(--s2); }
.run-cta__actions .btn { text-align: center; justify-content: center; }

.results-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s4);
  margin-top: var(--s4);
  flex-wrap: wrap;
}
.results-toolbar__actions { display: flex; gap: var(--s2); flex-wrap: wrap; }

/* ---------- /demo -- the run on a page of its own ----------
   On the landing the run is one section among a hero, a composer and a pricing
   argument, and it competes with all of them. Here it is the page: a briefing
   band, the instrument, and one useful way out. Nothing else is on screen. */

.demo { padding-bottom: var(--s8); }

/* The briefing is a band, not a screen. It sits BEFORE the run in reading
   order -- which is what a pre-flight briefing is -- and stays short enough
   that the instrument head is on the first screen behind it. */
.demo-brief {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  gap: var(--s5) var(--s6);
  align-items: center;
  padding: var(--s6) 0 var(--s5);
}
.demo-brief .eyebrow { margin-bottom: var(--s4); }
.demo-brief h1 { font-size: var(--size-h2); max-width: 13ch; }
.demo-brief .lead { margin-top: var(--s3); max-width: 46ch; }
.demo-brief__fact { margin-top: var(--s4); }
.demo-brief__diagram .pipeline { margin-top: 0; }

/* The page is one run, so its sections sit closer together than the landing's
   -- a 96px gap before the instrument is space the instrument should have. */
.demo .section-head { margin-top: var(--s6); }

/* Same note the briefing modal carries, in the same voice and the same box. */
.onboard__fact,
.demo-brief__fact {
  margin-top: var(--s5);
  border-left: 2px solid var(--blue);
  padding: var(--s1) 0 var(--s1) var(--s4);
  font-size: var(--size-small);
  color: var(--ink-muted);
  max-width: var(--measure-tight);
}
.onboard__fact { margin-top: var(--s6); }

/* The instrument holds its own height and scrolls inside it. On the landing
   the feed grows the document, which is survivable there because the reader
   arrived at it by scrolling. Here the run IS the screen: a frame that grew
   from 200px to 800px would walk the verdict, the foot and the page's ending
   down and away while the run was still playing. app.js reads the computed
   overflow and keeps the newest row visible inside the frame instead of
   moving the window. */
.demo .results .panel__body {
  height: clamp(320px, 58vh, 620px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--line-panel) transparent;
}
/* Nothing sticky: the head, the rail and the foot cannot scroll away from a
   panel that does not scroll with the page. */
.demo .results .panel__head,
.demo .results .panel__caption,
.demo .results .panel__foot { position: static; }

.demo #run-error { margin-top: var(--s4); }
.demo-honesty { margin-top: var(--s4); max-width: 68ch; }
.demo-next__alt { margin-top: var(--s4); }
.demo-next__alt a { color: var(--blue); }

/* ---------- 03: the reaction network ---------- */

.network {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--s7);
  align-items: start;
}
.network h3 { margin-bottom: var(--s4); max-width: 18ch; }
.network .prose + .prose { margin-top: var(--s3); }
.network__caveat { margin-top: var(--s5); max-width: 52ch; }
.network__demo { padding: var(--s5); border: 1px solid var(--panel); }

/* The cascade: the shape a run takes, traced. Structure only -- no figure is
   named, no line is machine-generated, and no magnitude is read out. The rail
   is the same hairline the feed uses for a thread. */
.cascade { margin: 0; }
.cascade__wire { display: flex; align-items: center; gap: var(--s3); margin-bottom: var(--s5); }

.cascade__leaf {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  flex-wrap: wrap;
  padding: var(--s2) var(--s3);
  border-left: 2px solid var(--line-panel);
  background: var(--panel-raised);
}
.cascade__leaf--root { border-left-color: var(--blue-on-panel); }
.cascade__leaf--hot { border-left-color: var(--heat); }
.cascade__leaf--silent { border-left-color: var(--caution); }

.cascade__form {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--blue-on-panel);
}
.cascade__leaf--silent .cascade__form { color: var(--caution); }
.cascade__what { font-size: var(--size-small); color: var(--on-panel-muted); }

/* The trace. A rail drops from the node above; each branch stubs off it. The
   last child masks the rail's tail so the line ends where the branching does. */
.cascade__branch {
  list-style: none;
  position: relative;
  margin: 0;
  padding-left: 28px;
}
.cascade__branch::before {
  content: "";
  position: absolute;
  left: 10px;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line-panel);
}
.cascade__branch > li { position: relative; margin-top: var(--s2); }
.cascade__branch > li::before {
  content: "";
  position: absolute;
  left: -18px;
  top: 15px;
  width: 18px;
  height: 1px;
  background: var(--line-panel);
}
.cascade__branch > li:last-child::after {
  content: "";
  position: absolute;
  left: -18px;
  top: 16px;
  bottom: 0;
  width: 1px;
  background: var(--panel);
}
.cascade__cap { margin-top: var(--s5); }

/* ---------- waitlist ---------- */

.waitlist {
  padding: var(--s6);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--s6) var(--s7);
  align-items: start;
}
.waitlist__action { align-self: center; }
.waitlist h3 { max-width: 20ch; }
.waitlist .lead { margin-top: var(--s3); }
.waitlist__row { display: flex; gap: var(--s2); }
.waitlist__row input { flex: 1 1 auto; min-width: 0; }
.waitlist__row .btn { flex: none; }
.waitlist__msg { margin-top: var(--s3); max-width: 56ch; }
.waitlist__msg[data-state="ok"] { color: var(--ok); }
.waitlist__msg[data-state="error"] { color: var(--heat-ink); }

/* ---------- footer ---------- */

.siteflow {
  border-top: 1px solid var(--ink);
  padding: var(--s6) var(--edge) var(--s7);
}
.siteflow__inner { max-width: calc(var(--page-max) - 2 * var(--gutter)); margin: 0 auto; }
.siteflow__cols { display: flex; justify-content: space-between; gap: var(--s5); flex-wrap: wrap; }
.siteflow__cols a, .siteflow__cols span {
  font-size: var(--size-small);
  color: var(--ink-muted);
  text-decoration: none;
  margin-right: var(--s5);
}
.siteflow__cols a { transition: color var(--dur-1) var(--ease-out); }
.siteflow__cols a:hover { color: var(--blue); text-decoration: underline; }
.siteflow__cols a:last-child { margin-right: 0; }
/* The page you are already on states itself rather than offering itself as a
   destination. A footer that links to the page under it is a dead end wearing
   a link's clothes. */
.siteflow__cols a[aria-current="page"] {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--line);
  cursor: default;
}
.siteflow__legal {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: var(--lh-relaxed);
  color: var(--ink-faint);
  max-width: 84ch;
}

/* ---------- pre-flight briefing (before a run, and from "How it works") ---------- */

.onboard {
  position: fixed;
  inset: 0;
  background: var(--paper);
  z-index: var(--z-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s5);
  overflow: auto;
}
/* The briefing covers the page, so it redraws the drafting grid rather than
   sitting on blank paper. Same pitch as body::before, from the same token --
   two hardcoded 96s drift apart the first time one of them is edited. */
.onboard::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(var(--grid) 1px, transparent 1px) 0 0 / 100% var(--grid-step),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0 / var(--grid-step) 100%;
}
.onboard__card { max-width: 660px; width: 100%; position: relative; }
.onboard__wire { display: flex; align-items: center; gap: var(--s3); margin-bottom: var(--s6); }
.onboard h2 { font-size: var(--size-h2); margin-bottom: var(--s4); }
.onboard p { font-size: var(--size-lead); color: var(--ink-muted); max-width: var(--measure-tight); }
.onboard p + p { margin-top: var(--s3); }
.onboard__actions { display: flex; gap: var(--s3); margin-top: var(--s6); align-items: center; }
.onboard__skip { margin-left: auto; }

/* pipeline diagram: scenario -> panel -> how it could go */
.pipeline { display: flex; align-items: stretch; gap: var(--s2); margin-top: var(--s6); }
.pipeline__stage {
  flex: 1;
  border: 1px solid var(--line);
  background: var(--paper-raised);
  padding: var(--s3) var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  animation: pipeline-scan 6s var(--ease-in-out) infinite;
}
.pipeline__stage:nth-child(3) { animation-delay: 2s; }
.pipeline__stage:nth-child(5) { animation-delay: 4s; }
@keyframes pipeline-scan {
  0%, 30%, 100% { border-color: var(--line); }
  8%, 22% { border-color: var(--blue); box-shadow: inset 0 0 0 1px var(--blue); }
}
/* Two lines of label reserved on every stage, so a heading that wraps in one
   box does not push that box's body out of line with its neighbours. */
.pipeline__stage > .microlabel { min-height: 2.4em; }
.pipeline__body { display: flex; align-items: center; flex: 1; }
.pipeline__quote {
  font-size: var(--size-small);
  font-weight: 500;
  border-left: 2px solid var(--blue);
  padding-left: var(--s3);
  color: var(--ink-muted);
}
.pipeline__verdict {
  font-family: var(--font-display);
  font-weight: 800;
  font-stretch: var(--wdth-display);
  font-size: 16px;
  letter-spacing: var(--track-tight);
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}
.pipeline__arrow {
  align-self: center;
  width: 18px;
  height: 1px;
  background: var(--ink);
  position: relative;
  flex: none;
}
.pipeline__arrow::after {
  content: "";
  position: absolute;
  right: 0; top: -3px;
  border-left: 5px solid var(--ink);
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
}
.pipeline__more { font-family: var(--font-mono); font-size: var(--size-micro); font-weight: 600; color: var(--ink-faint); margin-left: var(--s2); }

/* ---------- static pages (terms, privacy, refunds, pricing, billing) ---------- */

/* One left edge for the whole page, the rule at the top of this file, applied
   here too. Centred in the window, a 760px reading column starts at its own
   margin while the masthead above it and the footer below it start at --edge,
   and a screen with three left edges reads as unconsidered before a word of it
   is read. The column keeps its measure; only where it begins changes. */
.page {
  max-width: 760px;
  margin: 0 var(--gutter) 0 var(--edge);
  padding: var(--s8) 0 var(--s9);
}
.page .pkick { margin-bottom: var(--s3); }
.page h1 { font-size: clamp(2rem, 1.4rem + 2.6vw, 3rem); margin-bottom: var(--s4); }
.page .updated {
  font-family: var(--font-mono);
  font-size: var(--size-small);
  color: var(--ink-faint);
  padding-bottom: var(--s5);
  border-bottom: 1px solid var(--line);
}
.page h2 {
  font-size: var(--size-h4);
  font-family: var(--font-mono);
  font-weight: 600;
  font-stretch: var(--wdth-normal);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: var(--s7) 0 var(--s3);
}
.page p { margin: var(--s3) 0; color: var(--ink-muted); max-width: var(--measure); }
.page p b { color: var(--ink); }
.page ul, .page ol { margin: var(--s3) 0 var(--s3) var(--s5); color: var(--ink-muted); max-width: var(--measure); }
.page li { margin: var(--s1) 0; }
/* A prose link is blue. A button that happens to be an anchor is a button, and
   the prose colour must not reach into it -- .page a would otherwise outrank
   .btn--primary and paint blue type onto a black fill. */
.page a:not(.btn) { color: var(--blue); }

/* ---------- dormant billing pages (pricing, refunds, success, cancel) ----------
   These routes are not linked from the landing during the waitlist phase, but
   they stay reachable. This block keeps their older markup rendering inside the
   system rather than falling back to browser defaults. Delete it once those
   pages are rewritten or retired. */

body > header:not(.masthead) {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  padding: var(--s4) var(--gutter);
  border-bottom: 1px solid var(--line);
}
body > header:not(.masthead) .brand { font-size: 21px; }
body > header:not(.masthead) nav { display: flex; gap: var(--s4); }
body > header:not(.masthead) nav a { font-size: var(--size-small); text-decoration: none; }
body > header:not(.masthead) nav a:hover { color: var(--blue); }

body > footer:not(.siteflow) {
  border-top: 1px solid var(--ink);
  margin-top: var(--s7);
  padding: var(--s6) var(--gutter) var(--s7);
}
body > footer:not(.siteflow) .cols { display: flex; justify-content: space-between; gap: var(--s5); flex-wrap: wrap; }
body > footer:not(.siteflow) a, body > footer:not(.siteflow) span {
  font-size: var(--size-small);
  color: var(--ink-muted);
  text-decoration: none;
  margin-right: var(--s5);
}
body > footer:not(.siteflow) .legal {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-faint);
}

.packs { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); }
.pack { background: var(--paper); padding: var(--s5); display: flex; flex-direction: column; gap: var(--s3); }
.pack.featured { outline: 2px solid var(--blue); outline-offset: -2px; }
.pack .pname {
  font-family: var(--font-mono);
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--track-wider);
  text-transform: uppercase;
  color: var(--ink-faint);
}
.pack .price { font-family: var(--font-display); font-size: 34px; font-weight: 800; font-stretch: var(--wdth-display); letter-spacing: var(--track-display); }
.pack .price small { font-size: 12.5px; font-weight: 500; color: var(--ink-faint); font-stretch: var(--wdth-normal); }
.pack ul { list-style: none; margin: 0; font-size: var(--size-small); color: var(--ink-muted); flex: 1; }
.pack ul li { padding: var(--s1) 0; border-bottom: 1px solid var(--line); }
.pack ul li:last-child { border-bottom: 0; }
.pack .btn { text-align: center; }

/* ---------- responsive ---------- */

/* Desktop composition of a finished run.
   A post body is a 52ch column by system rule, so a full-width panel is a
   column of text inside a frame nearly twice as wide, and the rest of it is
   black nothing. The feed is a column, so it gets a column -- and the space
   beside it carries the verdict, which is the readout this instrument
   produces and has no reason to be anywhere else. Paper beside panel, the way
   the hero is composed; the two surfaces sit next to each other and never
   mix. The offer below is us speaking, so it keeps the full width.
   Under this width the same blocks stack in the same order. */
@media (min-width: 900px) {
  .results {
    display: grid;
    /* The readout column tracks the page rather than sitting at one width:
       the feed must never be squeezed below its own measure to hold it. */
    grid-template-columns: minmax(0, 1fr) clamp(256px, 30%, 336px);
    column-gap: var(--s5);
    align-items: start;
  }
  .results > .panel { grid-column: 1; }
  /* The feed runs far longer than the readout, so the verdict rides with it
     rather than sitting once at the top of an empty column. The slot stretches
     to the feed's height and the card sticks inside it: a sticky grid ITEM is
     not reliably clamped to its own row, and would ride on over the offer
     below. */
  .results > #verdict-box { grid-column: 2; align-self: stretch; }
  .results > #verdict-box > .verdict { position: sticky; top: var(--s4); }
  .results > .shared-cta,
  .results > #run-notice,
  .results > #run-cta-box,
  .results > #run-error,
  .results > .results-toolbar { grid-column: 1 / -1; }
  .results .verdict { margin-top: 0; padding: var(--s5); }
  .results .verdict__prose { font-size: var(--size-body); }
  .results .run-cta { margin-top: var(--s5); }
}

/* ---------- the mesh landing, narrowing ----------
   The mesh is desktop-first. Below 900 the hero re-composes rather than
   scaling: the event moves to the top of the frame, the constellation is
   smaller and closer (mesh.js picks that up at the same breakpoint), and the
   glass card stops floating and takes the foot of the screen. */

@media (max-width: 1240px) {
  .how { padding: 72px 56px 80px; }
  .how__row { grid-template-columns: 300px minmax(0, 1fr); gap: 40px; padding: 44px 44px; }
  .mhero__cta { left: 40px; width: 356px; }
}

@media (max-width: 1000px) {
  .how { padding: 64px 32px 72px; gap: 20px; }
  .how__row { grid-template-columns: 240px minmax(0, 1fr); gap: 32px; padding: 36px 32px; }
  .how__art { height: 128px; }
  .how__art svg { width: 200px; height: 80px; }
  .how__input { width: 100%; padding: 13px 15px; }
  .how__bar { width: 34px; }
  .how__bar-label { margin-left: 8px; }
  .demo-brief { grid-template-columns: 1fr; gap: var(--s5); padding-top: var(--s6); }
  .demo-brief h1 { max-width: 18ch; }
  .network { grid-template-columns: 1fr; gap: var(--s5); }
  .network h3 { max-width: 24ch; }
  .run-cta { grid-template-columns: 1fr; gap: var(--s5); align-items: start; }
  /* Stacks with its siblings, not 240px later. Two columns at tablet width
     leave the field about 140px wide -- narrow enough to clip its own
     placeholder, which is the one control on the page that must look
     obviously fillable. */
  .waitlist { grid-template-columns: 1fr; gap: var(--s5); }
}

/* The stacked hero. Column, canvas behind, card at the foot -- and the hero
   grows past the viewport rather than clipping if the copy or the text size
   needs more room than the screen has. */
@media (max-width: 900px) {
  .mhero {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: 0 16px 28px;
    background: radial-gradient(760px 520px at 50% 26%, #181b23 0%, #0a0b0e 74%);
  }
  .mhero__cta {
    position: static;
    transform: none;
    width: 100%;
    max-width: 460px;
    margin: 0 auto;
    padding: 28px 24px;
    /* Denser glass: at this width the card sits over the constellation rather
       than beside it, and 14% fill is not enough to read 14px type through. */
    background: rgba(11, 13, 18, .62);
    border-color: rgba(255, 255, 255, .14);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
  }
  /* On a phone the mesh is the backdrop, not an instrument: it takes no
     input, so nothing competes with the scroll. */
  .mhero__canvas { pointer-events: none; touch-action: auto; }
  .mhero__mark { margin-bottom: 20px; }
  .mhero__title { font-size: 31px; }
  .mhero__event { max-width: min(310px, calc(100vw - 40px)); }
  /* The card already occupies the foot of the screen, and on a phone the fact
     that a page scrolls needs no announcing. */
  .mhero__chev { display: none; }
  .mhero__disclosure { top: 16px; right: 16px; left: 16px; text-align: center; }
}

@media (max-width: 760px) {
  .card-grid--3, .card-grid--2 { grid-template-columns: 1fr; }
  .how { padding: 48px 18px 56px; gap: 16px; }
  .how__row { grid-template-columns: 1fr; gap: 26px; padding: 30px 24px; }
  .how__art { height: 104px; justify-content: flex-start; }
  .how__art--bars { align-items: flex-end; }
  .deck__inner { padding-top: var(--s6); }
  .protocol-bar__opt { display: none; }
  .protocol-bar { gap: var(--s3); }
  .section-head { margin: var(--s8) 0 var(--s4); }
  .composer { padding: var(--s5) var(--s4); }
  .waitlist, .well { padding: var(--s5) var(--s4); }
  .waitlist { grid-template-columns: 1fr; gap: var(--s5); }
  .waitlist__row { flex-direction: column; }
  .waitlist__row .btn { width: 100%; }
  .panel__head, .panel__caption, .panel__body, .panel__foot, .readout { padding-left: var(--s4); padding-right: var(--s4); }
  /* On a phone the screen is the scarce thing: the rail keeps narrating, the
     head scrolls away with the feed. Provenance is a line up the page, not a
     line removed. */
  .results .panel__head { position: static; }
  .results .panel__caption { top: 0; }
  .post[data-depth="1"] { margin-left: var(--s4); }
  .post[data-depth="2"] { margin-left: var(--s6); }
  .verdict { padding: var(--s5) var(--s4); }
  .run-cta { padding: var(--s5) var(--s4); }
  .network__demo { padding: var(--s4) var(--s3); }
  .cascade__branch { padding-left: 22px; }
  .cascade__branch::before { left: 8px; }
  .cascade__branch > li::before, .cascade__branch > li:last-child::after { left: -14px; }
  .cascade__branch > li::before { width: 14px; }
  .pipeline { flex-direction: column; }
  .pipeline__arrow { transform: rotate(90deg); align-self: flex-start; margin-left: var(--s5); }
  .siteflow__cols { flex-direction: column; gap: var(--s3); }
}

@media (max-width: 560px) {
  .section-head__note { display: none; }
  .protocol-bar { letter-spacing: 0.08em; }
  .protocol-bar .rule { display: none; }
  /* The briefing is the explanation for the run, so it has to be reachable at
     every width. The nav keeps both jobs and tightens instead of dropping one:
     labels never abbreviate, so they must never wrap either. */
  .masthead { gap: var(--s2); }
  .masthead__nav { gap: 6px; }
  .masthead .brand { white-space: nowrap; }
  .masthead__nav .btn { padding-left: 10px; padding-right: 10px; white-space: nowrap; }
  .onboard__esc { display: none; }   /* no Esc key to press */
}

@media (max-width: 420px) {
  .masthead { padding: var(--s3) var(--edge); }
  .brand { font-size: 19px; }
  /* One field, one button, full width -- a 375px row cannot hold both and
     still show the placeholder, which is the one thing that has to be legible. */
  .mhero__form { flex-direction: column; }
  .mhero__submit { width: 100%; }
  /* Every row the card gives back is a row the mesh gets. */
  .mhero__cta { padding: 24px 20px; }
  .mhero__mark { margin-bottom: 16px; font-size: 19px; }
  .mhero__title { font-size: 28px; }
  .mhero__support { margin-top: 13px; }
  .mhero__form { margin-top: 20px; }
  .mhero__disclosure { font-size: 8.5px; letter-spacing: 0.14em; }
  .post { grid-template-columns: 34px minmax(0, 1fr); gap: var(--s2); }
  .divergence__row { grid-template-columns: 1fr; gap: var(--s1); }
}
