/* ==========================================================================
  /platform — the PULSAR Platform overview page.  Namespace: .iap-*
  ==========================================================================
  Every rule this page needs that is not already in main.css, blocks-native.css,
  hero-page.css or the shared orient.css lives here. The page carries no inline
  <style>: this file was extracted from the approved draft so that the stamping
  script can hash it and browsers stop holding a stale copy of the page's look
  inside a cached HTML document.

  TOKENS are main.css's own — --teal --teal-mid --teal-ink --orange --mono
  --font --line-strong --radius --text --muted --dim --border.
  design-tokens.css is NOT linked by any page, so --color-* / --font-mono /
  --radius-card do not exist and are never used below.

  COLOUR ON DARK. main.css sets `h3 { color: var(--text) }`, which is
  near-black. The only <h3>s here are the chapter questions (.iap-cha__q),
  which set their own colour, and every dark-ground text colour below is set
  explicitly.

  The .orient-* breadcrumb block that used to sit at the foot of this file in
  the draft is gone: css/orient.css is the shared, extracted copy and the page
  links it. Do not reintroduce a local copy.
  ========================================================================== */

:root { --iap-paper: #f4f5f7; --iap-card: rgba(255,255,255,.045); }

.iap-shell { max-width: min(100%, 1180px); margin: 0 auto; padding: 0 clamp(16px, 4vw, 40px); }
.iap-shell--wide { max-width: min(100%, 1320px); }
.iap-band { padding-block: clamp(44px, 6.6vh, 88px); }
.iap-eyebrow { font-family: var(--mono); font-size: .72rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--teal-ink); margin: 0 0 14px; }
.iap-eyebrow--dark { color: var(--teal); }
.iap-h2 { margin: 0 0 16px; font-size: clamp(25px, 3vw, 40px); font-weight: 700;
  letter-spacing: -.035em; line-height: 1.12; max-width: 24ch; text-wrap: balance;
  color: var(--text); }
.iap-h2--dark { color: var(--iap-paper); max-width: 26ch; }
.iap-lede { margin: 0; font-size: clamp(15px, 1.05vw, 17px); line-height: 1.62;
  color: var(--muted); max-width: 58ch; }
.iap-lede--dark { color: rgba(244,245,247,.76); }
.iap-synth { font-family: var(--mono); font-size: .62rem; letter-spacing: .1em;
  text-transform: uppercase; color: #6c7a8d; margin: 0; }
.iap-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* the site pill is translucent; headings read through it on this page */
.site-header__inner { background: #0e1726 !important; backdrop-filter: none !important; }
.site-header { background: transparent; }

/* ══ 1 · HERO ═══════════════════════════════════════════════════════════
   THE VISUAL IS A PRODUCT SCREEN, NOT A DIAGRAM.
   Founder: "I do not recognize it as our PULSAR platform — as part of it
   and screenshot-alike." So it is given the furniture that makes a screen a
   screen: a window frame, a module rail, a breadcrumb, a toolbar with a
   version selector, an ask row, a status bar. The old behaviour chart on
   the right half is DELETED; the system model now fills the frame.

   THE MODEL ECHOES THE HOMEPAGE. The homepage hero is a regular hex lattice
   of hollow rings with packets running interior routes (js/blocks/
   home-hero-field.js). The same two devices are used here — the lattice as
   a <pattern> ground, signals running the edges — but laid over a STRUCTURED
   architecture: four labelled domain groups, a labelled backbone, 28 named
   units. Organic register, architecture-diagram legibility.
   ═══════════════════════════════════════════════════════════════════════ */
.iap-hero { position: relative; overflow: hidden;
  background:
    radial-gradient(1100px 620px at 72% 34%, rgba(48,116,142,.22), transparent 62%),
    radial-gradient(820px 540px at 14% 92%, rgba(72,84,152,.15), transparent 66%),
    linear-gradient(168deg, #0b1420 0%, #0a121c 52%, #080f18 100%); }
.iap-hero__grid { display: grid; grid-template-columns: minmax(0, .58fr) minmax(0, 1.42fr);
  gap: clamp(26px, 3.4vw, 48px); align-items: center; padding-block: clamp(40px, 6vh, 80px); }
.iap-hero h1 { margin: 0 0 18px; color: var(--iap-paper);
  font-size: clamp(1.85rem, 3.4vw, 2.9rem); font-weight: 700; line-height: 1.07;
  letter-spacing: -.038em; max-width: 15ch; text-wrap: balance; }
.iap-hero h1 em { font-style: normal; color: var(--teal); }
.iap-hero__lede { color: rgba(232,233,237,.82); font-size: clamp(14.5px, 1.05vw, 16.5px);
  line-height: 1.6; max-width: 42ch; margin: 0 0 24px; }
.iap-hero__lede b { color: var(--iap-paper); font-weight: 600; }
.iap-hero__actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

/* ── the application frame ───────────────────────────────────────────── */
.iap-app { margin: 0; border: 1px solid rgba(141,153,174,.3); border-radius: 13px;
  background: linear-gradient(180deg, rgba(20,33,54,.97), rgba(11,21,37,.97));
  box-shadow: 0 30px 76px rgba(0,0,0,.5); overflow: hidden; }
.iap-app__win { display: flex; align-items: center; gap: 11px;
  padding: 9px 14px; border-bottom: 1px solid rgba(141,153,174,.18);
  background: rgba(7,13,24,.94); font-family: var(--mono); font-size: .6rem;
  letter-spacing: .1em; text-transform: uppercase; color: #7d8a9b; }
.iap-app__dots { display: flex; gap: 5px; flex: none; }
/* the frame must recede: the model is the subject, not the chrome */
.iap-app__dots i { width: 7px; height: 7px; border-radius: 50%;
  background: rgba(141,153,174,.14); }
.iap-app__name { color: #b8c4d4; letter-spacing: .13em; }
.iap-app__name b { color: var(--teal); font-weight: 600; }
.iap-app__badge { margin-left: auto; font-size: .56rem; letter-spacing: .1em;
  color: #6c7a8d; border: 1px solid rgba(141,153,174,.26); border-radius: 999px;
  padding: 3px 9px; white-space: nowrap; }

/* THE RAIL IS THE PLATFORM'S ARCHITECTURE, not a list of features.
   Two levels — the engine and its two models, then the three modules —
   and the SAME order and naming the scroll story in §3 walks through, so
   hero and story cannot drift apart. */
.iap-app__body { display: grid; grid-template-columns: 172px minmax(0, 1fr); }
.iap-rail { border-right: 1px solid rgba(141,153,174,.16); padding: 12px 10px;
  background: rgba(7,13,24,.5); display: flex; flex-direction: column; gap: 3px; }
.iap-rail__k { margin: 9px 0 4px 4px; font-family: var(--mono); font-size: .53rem;
  letter-spacing: .16em; text-transform: uppercase; color: #5d6a7c; }
.iap-rail__k:first-child { margin-top: 2px; }
.iap-rail__i--sub { margin-left: 9px; font-size: .71rem; }
.iap-rail__i { display: flex; align-items: center; gap: 7px; border-radius: 7px;
  border: 1px solid transparent; padding: 6px 8px; font-size: .74rem; line-height: 1.25;
  color: #9dabbd; transition: color .4s ease, background .4s ease, border-color .4s ease; }
.iap-rail__i i { width: 5px; height: 5px; border-radius: 50%; flex: none;
  background: currentColor; opacity: .75; }
.iap-rail__i.is-on { color: var(--teal); border-color: rgba(78,205,196,.55);
  background: rgba(78,205,196,.12); }

.iap-app__main { min-width: 0; display: flex; flex-direction: column; }
.iap-tool { display: flex; align-items: center; flex-wrap: wrap; gap: 7px;
  padding: 9px 13px; border-bottom: 1px solid rgba(141,153,174,.14); }
.iap-tool__crumb { font-family: var(--mono); font-size: .58rem; letter-spacing: .12em;
  text-transform: uppercase; color: #6c7a8d; margin: 0 6px 0 0; }
.iap-tool__crumb b { color: #cbd5e1; font-weight: 600; }
.iap-chip { font-family: var(--mono); font-size: .59rem; letter-spacing: .05em;
  color: #b4c0d0; border: 1px solid rgba(141,153,174,.3); border-radius: 6px;
  padding: 4px 8px; background: rgba(255,255,255,.04); white-space: nowrap; }
.iap-chip b { color: var(--teal); font-weight: 600; }
.iap-chip--go { margin-left: auto; color: #0b1420; background: var(--teal);
  border-color: var(--teal); font-weight: 600; }
/* the story's frame swaps its primary button for the chapter it is in:
   at the upload step it says "Upload runs", everywhere else "Ask PULSAR" */
.iap-chip--upl { display: none; }
.iap-stage[data-step="0"] .iap-chip--ask { display: none; }
.iap-stage[data-step="0"] .iap-chip--upl { display: inline-block; }

/* ── the scale strip: how big the model actually is ──────────────────────
   Sits between the toolbar and the canvas, because it is a property of the
   thing on the canvas and has to be read before it. The numerals carry the
   weight and the labels sit under them small: the point lands as three big
   figures whether or not anybody reads the words. */
.iap-scale { display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 6px clamp(18px, 3vw, 40px); padding: 11px 13px 12px;
  border-bottom: 1px solid rgba(141,153,174,.14); }
.iap-scale__i { display: flex; flex-direction: column; gap: 1px; }
.iap-scale__i b { font-family: var(--mono); font-size: clamp(17px, 1.7vw, 25px);
  font-weight: 700; line-height: 1; letter-spacing: -.02em; color: var(--teal); }
.iap-scale__i span { font-family: var(--mono); font-size: .55rem; letter-spacing: .13em;
  text-transform: uppercase; color: #6c7a8d; white-space: nowrap; }
.iap-scale__n { margin: 0 0 0 auto; align-self: flex-end; font-family: var(--mono);
  font-size: .55rem; letter-spacing: .06em; color: #566374; }
@media (max-width: 620px) {
  .iap-scale { gap: 6px 16px; }
  .iap-scale__n { display: none; }
}

/* ── the canvas: the architecture, filling the frame ─────────────────── */
.iap-canvas { position: relative; padding: clamp(8px, 1.2vw, 14px); }
.iap-canvas svg { display: block; width: 100%; height: auto; }
.iap-canvas svg.iap-arch--sm { display: none; }
@media (max-width: 720px) {
  .iap-canvas svg.iap-arch--lg { display: none; }
  .iap-canvas svg.iap-arch--sm { display: block; }
}

/* architecture primitives — one type system, used by the hero AND by the
   assembled figure in §4, because they are the same drawing */
.iap-grp { fill: rgba(255,255,255,.018); stroke: rgba(141,153,174,.26);
  stroke-width: 1; stroke-dasharray: 4 4; }
.iap-grpt { font-family: var(--mono); font-size: 8.6px; letter-spacing: .17em;
  fill: #6b7a90; }
.iap-grpt--bus { fill: #6b7a90; }
/* THE BACKBONE READS LIKE EVERY OTHER GROUP. It used to be drawn in teal,
   which the page never explained — founder: "why is one section marked
   teal? looks strange." Colour on this drawing now means exactly one
   thing: a module has something to say about that node (orange = out of
   normal, teal = changed, red = the root-cause path). Structure is
   structure, and all of it is the same grey. */
.iap-bus { fill: rgba(255,255,255,.018); stroke: rgba(141,153,174,.26);
  stroke-width: 1; stroke-dasharray: 4 4; }
.iap-n { fill: rgba(255,255,255,.055); stroke: rgba(141,153,174,.42); stroke-width: 1; }
.iap-n--spine { fill: rgba(255,255,255,.055); stroke: rgba(141,153,174,.42); }
.iap-nd { fill: var(--teal); opacity: .8; }
.iap-nt { font-family: var(--mono); font-size: 11px; fill: #c6d2e2; letter-spacing: .01em; }
.iap-e { fill: none; stroke: rgba(141,153,174,.32); stroke-width: 1; }
.iap-et { font-family: var(--mono); font-size: 7.6px; letter-spacing: .12em; fill: #5f6d81; }
.iap-sg { fill: none; stroke: #d9f2ff; stroke-width: 1.5; stroke-linecap: round;
  stroke-dasharray: 12 118; animation: iap-run 4.2s linear infinite; opacity: .85; }
.iap-sg--bus { stroke: var(--teal); stroke-width: 1.8; }
@keyframes iap-run { from { stroke-dashoffset: 130; } to { stroke-dashoffset: 0; } }

/* ── the ask row: what makes "AI-native" self-evident ────────────────── */
.iap-ask { border-top: 1px solid rgba(141,153,174,.16); padding: 11px 13px 12px;
  background: rgba(7,13,24,.55); }
.iap-ask__in { display: flex; align-items: center; gap: 9px;
  border: 1px solid rgba(78,205,196,.4); border-radius: 9px; padding: 8px 11px;
  background: rgba(78,205,196,.06); font-size: .82rem; color: #8d99ae; }
.iap-ask__in svg { flex: none; width: 13px; height: 12px; fill: var(--teal); }
.iap-ask__in em { font-style: normal; margin-left: auto; font-family: var(--mono);
  font-size: .56rem; letter-spacing: .12em; text-transform: uppercase; color: var(--teal); }
.iap-qs { list-style: none; margin: 8px 0 0; padding: 0; display: flex;
  flex-wrap: wrap; gap: 6px; }
.iap-qs li { border: 1px solid rgba(141,153,174,.3); border-radius: 999px;
  padding: 5px 11px; background: rgba(255,255,255,.04); font-size: .76rem;
  color: #cbd5e1; line-height: 1.2;
  animation: iap-sel 10.5s ease-in-out infinite; }
.iap-qs li:nth-child(2) { animation-delay: 3.5s; }
.iap-qs li:nth-child(3) { animation-delay: 7s; }
@keyframes iap-sel {
  0%, 22% { border-color: var(--teal); background: rgba(78,205,196,.14); color: var(--iap-paper); }
  31%, 100% { border-color: rgba(141,153,174,.3); background: rgba(255,255,255,.04); color: #cbd5e1; }
}
/* The "Current run …" status bar is DELETED. It carried no information a
   reader could act on. The `Illustrative · synthetic data` declaration —
   which every product screen on this site must carry — lives in the window
   chrome (.iap-app__badge), where it is honest and out of the way. */

/* ══ 2 · AUTOMOTIVE ═════════════════════════════════════════════════════
   CUT TO HALF A SCREEN. Founder: "a section that is larger than one screen!
   Too much unstructured info, I only want maximal half a page — with the
   most important message and that's all."
   ONE message (the black box), ONE image (the car), ONE number, ONE forward
   line. Deleted: three of the four sourced statistics and all their citation
   furniture, the 20,000-suppliers paragraph, the two-door what-you-are-given
   figure, the second black-box paragraph and its two-source citation, and
   the founder row (it is the homepage's claim, not this section's message).
   ═══════════════════════════════════════════════════════════════════════ */
.iap-auto { background: #fbfcfd; }
.iap-auto.iap-band { padding-block: clamp(28px, 3.8vh, 46px); }
.iap-auto__grid { display: grid; grid-template-columns: minmax(0, .88fr) minmax(0, 1.12fr);
  gap: clamp(24px, 3.4vw, 48px); align-items: center; }
.iap-auto__h { margin: 0 0 12px; font-size: clamp(22px, 2.4vw, 31px); font-weight: 700;
  letter-spacing: -.035em; line-height: 1.13; max-width: 22ch; text-wrap: balance;
  color: var(--text); }
.iap-auto__p { margin: 0; font-size: clamp(14.5px, 1.05vw, 16.5px); line-height: 1.58;
  color: var(--muted); max-width: 54ch; }
.iap-auto__p b { color: var(--text); font-weight: 600; }
/* THE SECOND PARAGRAPH IS THE SAME PARAGRAPH. It used to be set smaller
   and tighter than the one above it, so the section read as a lede plus a
   footnote. Both are now the one body treatment; only the emphasis inside
   them is allowed to differ. */
.iap-fwd { margin: clamp(12px, 1.6vh, 18px) 0 0;
  font-size: clamp(14.5px, 1.05vw, 16.5px); line-height: 1.58;
  color: var(--muted); max-width: 54ch; }
.iap-fwd b { color: var(--teal-ink); font-weight: 600; }

/* ══ THE FOUR SUBJECTS, AS A 2x2 MATRIX ═══════════════════════════════
   Was four <details> toggles. Founder: "should be self-explaining, so no +
   needed" and "formulate the texts shorter — not more needed, just
   formulate clean." So there is nothing to open: all four are simply on
   screen, figure first and one short line under it. The citation lines
   are gone -- founder: "I do not need sources, just state as-is" -- and
   no figure was invented to fill the gap they left.
   Deliberately still absent, because a previous pass established they
   cannot be sourced: the BMW 10^32 variant claim, CAN signal/DBC counts,
   per-programme Tier-1 counts, and "~30,000 parts per car".
   At 400px the 2x2 becomes 1x4 and the car card leads it. */
.iap-mx__k { margin: 0 0 10px; font-family: var(--mono); font-size: .62rem;
  font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--teal-ink); }
.iap-mx__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px; }
.iap-mx__c { border: 1px solid var(--border); border-radius: 12px; background: #fff;
  box-shadow: 0 1px 2px rgba(43,45,66,.05); padding: 14px 15px 12px;
  display: flex; flex-direction: column; }
/* ONE FIGURE SLOT FOR ALL FOUR CARDS. A number, a car and a box are three
   different kinds of object; they only scan as one set if they occupy a box
   of the same height and sit on the same line. So the slot is declared once
   and every card's mark — numeral or drawing — is bottom-aligned inside it,
   and every supporting line starts at the same y. Founder: "align the texts
   and symbols on the right - it looks strange." */
.iap-mx__grid { --mx-slot: clamp(30px, 3.4vw, 42px); }
.iap-mx__n,
.iap-mx__fig { display: flex; align-items: flex-end; margin: 0;
  height: var(--mx-slot); }
.iap-mx__n { font-size: var(--mx-slot); font-weight: 700;
  letter-spacing: -.05em; line-height: .96; color: var(--teal-ink);
  font-variant-numeric: tabular-nums; }
.iap-mx__n small { font-size: .42em; font-weight: 600; letter-spacing: 0;
  margin-left: .25em; }
.iap-mx__t { margin: 11px 0 0; font-size: .9rem; font-weight: 600; line-height: 1.35;
  letter-spacing: -.01em; color: var(--text); }
/* THE CITATION LINES ARE DELETED. Founder: "I do not need sources, just
   state as-is." The figures themselves are unchanged; none were invented
   to fill the space a source line left. */

/* THE CAR CARD IS ONE OF THE FOUR AND MUST SCAN AS ONE OF THE FOUR.
   Its message is no longer sealed binaries -- that moved out to the
   black-box card: it names automotive as our first target complex
   industry, and the place the problem is most painful.
   Founder: "The car under challenge could be simpler and nicer... It should
   fit as a number in the whole layout." So the drawing lost its twenty-two
   units and its legend — it is now a plain outline, a quiet mark above the
   line — and the card leads with a word set in the SAME slot and the same
   type as 150+, 100M and 12.3, so the 2x2 reads as one set.
   The word, not a number, because this is the one point with no defensible
   public figure, and an invented one would be worse than none. */
/* THE CAR AND THE BOX ARE DRAWN IN ONE HAND. They were not: the car was an
   outline and the box a shaded solid, which read as two illustrations from
   two sets rather than two marks in one matrix. Both are now the same
   stroked line at the same weight, sized to the shared slot. */
.iap-mx__car, .iap-mx__box { display: block; width: auto; height: 100%;
  overflow: visible; }
.iap-mx__car path, .iap-mx__car circle,
.iap-mx__box path { fill: none; stroke: var(--line-strong);
  stroke-width: 1.7; stroke-linejoin: round; stroke-linecap: round; }
.iap-mx__car .c-glass, .iap-mx__box .b-seam { stroke-width: 1.3; }
.iap-mx__car .c-road { stroke-width: 1.1; opacity: .5; }
.iap-auto__link { color: var(--teal-ink); text-decoration: none;
  border-bottom: 1px solid currentColor; white-space: nowrap; }
@media (max-width: 900px) { .iap-auto__grid { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 520px) { .iap-mx__grid { grid-template-columns: minmax(0, 1fr); } }

/* ══ 3 · THE PLATFORM, ASSEMBLED AS YOU SCROLL ══════════════════════════
   Founder: "I wanted the platform to evolve by scrolling and adding parts,
   deleting unimportant ones, so at the end we one by one get the explained
   platform page and see the overview."
   So this is no longer five figures. It is ONE figure — the same product
   screen the hero shows — pinned beside the chapters and progressively
   assembled: raw runs, then structure, then behaviour, then one module
   layer per chapter, with the previous chapter's layer receding. The last
   step IS the hero's Overview, and the arrival chapter says so.

   FAIL-SAFE BY DEFAULT, in the same shape as js/blocks/home-thesis.js: the
   pinned layout only exists under .is-pinned, which the driver adds after
   it has actually initialised, and the figure's DEFAULT step variables are
   the ASSEMBLED END STATE. So JS-off, a thrown error, a throttled scroll
   handler and prefers-reduced-motion all land on the same readable page:
   every chapter visible at full contrast, the figure complete.
   ═══════════════════════════════════════════════════════════════════════ */
.iap-story { background:
    radial-gradient(1000px 700px at 82% 6%, rgba(48,116,142,.17), transparent 62%),
    radial-gradient(900px 620px at 4% 78%, rgba(72,84,152,.13), transparent 66%),
    linear-gradient(172deg, #0d1828 0%, #0a121c 56%, #080f18 100%); }
.iap-story__head { max-width: 46ch; margin-bottom: clamp(24px, 3.4vh, 40px); }

.iap-asm { display: grid; grid-template-columns: minmax(0, 1.32fr) minmax(0, .68fr);
  gap: clamp(20px, 3vw, 44px); align-items: start; }
.iap-asm__stage { min-width: 0; }
.is-pinned .iap-asm__stage { position: sticky;
  top: calc(var(--nav-bar-h, 56px) + 2 * var(--nav-shell-pad-y, 12px) + 12px); }

/* the figure's own progress furniture — the reader must always know which
   chapter they are in and what the figure is currently showing */
.iap-now { display: flex; align-items: baseline; gap: 10px; padding: 10px 13px 11px;
  font-size: .85rem; line-height: 1.4; color: rgba(244,245,247,.9);
  background: rgba(7,13,24,.6); }
.iap-now b { flex: none; font-family: var(--mono); font-size: .56rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--teal); }
.iap-prog { height: 2px; background: rgba(141,153,174,.16); }
.iap-prog i { display: block; height: 100%; width: var(--p, 100%); background: var(--teal);
  transition: width .25s linear; }

/* ONE VISUAL PER STEP. Founder: "platform visuals only should be one per
   statement on the right." Every value below is 1 or 0 — there are no
   faded leftovers, because a layer dimmed to 20% is still a second thing
   on screen. The structure stays lit under the module steps because it is
   the ground the marker is drawn ON, not a competing layer: at every step
   exactly one thing is being said.
     0 the upload, and the twin building itself while it loads
     1 the unit outside normal          (Anomaly Detection)
     2 the path back to one origin      (Root-Cause Analysis)
     3 what changed between two builds  (Change Detection)
     4 all of it, which is the Overview
   ONE CHAPTER, ONE STEP. The engine chapter used to own three steps that
   swapped the screen out from under the reader -- runs, then structure,
   then behaviour. Founder, twice: the upload and the system model must be
   on the SAME screen. So it is one step now, and the two things happen
   together inside it (see .iap-load below): the bar fills while the
   components arrive, and at about 5 s the whole thing is running.
   Default values = step 4 = the assembled end state, so JS off, a thrown
   error or reduced motion all land on the finished screen. */
.iap-stage { --o-runs: 0; --o-struct: 1; --o-beh: 1; --o-anom: 0;
  --o-chg: 0; --o-rca: 0; --o-agents: 1; }
.iap-stage[data-step="0"] { --o-runs:1; --o-struct:1; --o-beh:1; --o-anom:0; --o-chg:0; --o-rca:0; --o-agents:0; }
.iap-stage[data-step="1"] { --o-runs:0; --o-struct:1; --o-beh:0; --o-anom:1; --o-chg:0; --o-rca:0; --o-agents:0; }
.iap-stage[data-step="2"] { --o-runs:0; --o-struct:1; --o-beh:0; --o-anom:0; --o-chg:0; --o-rca:1; --o-agents:0; }
.iap-stage[data-step="3"] { --o-runs:0; --o-struct:1; --o-beh:0; --o-anom:0; --o-chg:1; --o-rca:0; --o-agents:0; }
.iap-stage[data-step="4"] { --o-runs:0; --o-struct:1; --o-beh:1; --o-anom:0; --o-chg:0; --o-rca:0; --o-agents:1; }

/* WHERE YOU ARE IN THE PRODUCT. Each step lights exactly one rail item —
   the same seven entries, in the same order, as the hero's rail. This is
   the only "annotation" a step gets; everything else is shown. */
.iap-stage[data-step="0"] .iap-rail__i--up,
.iap-stage[data-step="0"] .iap-rail__i--sys,
.iap-stage[data-step="0"] .iap-rail__i--beh,
.iap-stage[data-step="1"] .iap-rail__i--ano,
.iap-stage[data-step="2"] .iap-rail__i--rca,
.iap-stage[data-step="3"] .iap-rail__i--chg,
.iap-stage[data-step="4"] .iap-rail__i--ovw { color: var(--teal);
  border-color: rgba(78,205,196,.55); background: rgba(78,205,196,.12); }
/* NOTHING IN THE MODEL IS SINGLED OUT BY DEFAULT. The drawing carries no
   colour of its own — not in the hero, not here. Colour arrives only with
   a module layer and leaves with it, so the model itself reads even. */
.iap-lay { transition: opacity .65s ease; }
/* --o-runs now drives the HTML load bar (.iap-load), not an SVG layer */
.iap-lay--struct { opacity: var(--o-struct); }
.iap-lay--beh { opacity: var(--o-beh); }
.iap-lay--anom { opacity: var(--o-anom); }
.iap-lay--chg { opacity: var(--o-chg); }
.iap-lay--rca { opacity: var(--o-rca); }
.iap-stage .iap-ask { opacity: var(--o-agents); transition: opacity .65s ease; }
/* AT THE ARRIVAL the ask row IS the idea, so it is the thing that reads.
   Nothing else changes state: the model stays exactly as it was. */
.iap-stage[data-step="4"] .iap-ask { background: rgba(78,205,196,.09);
  box-shadow: inset 0 1px 0 rgba(78,205,196,.35); }

/* THE INSETS ARE DELETED. They were a second picture laid over the model
   at steps 2, 3 and 4 — model plus panel plus bands at once, which is
   exactly the "several things at the same time" the founder rejected.
   Each of those steps now says its one thing on the model itself.
   The drop-zone layer is deleted for the same reason: step 0 showed a
   drop target AND three streams of recorded runs. It shows the runs.  */

/* ══ STEP 0 · THE UPLOAD AND THE SYSTEM MODEL, ON ONE SCREEN ═════════
   Asked for twice, and built wrong twice as separate states that swapped
   the screen out from under the reader. It is ONE state now, and the two
   things happen AT THE SAME TIME inside it:

     t=0.0s  the toolbar's primary button reads "Upload runs", and a load
             bar under the toolbar starts filling
     t=0.3s  the first block of the model appears on the canvas
     0.3-4.3 the other four blocks arrive, one every 0.8 s, WHILE the bar
             is still filling
     t=5.0s  the bar reaches 100 % and the behaviour comes alive on the
             finished model — everything running

   The bar is HTML, not SVG, so it sits at the top of the screen where a
   real upload reports, above the canvas rather than drawn across the
   model it is building. It keeps its row at every step (opacity, never
   display), so the pinned figure cannot change height mid-scroll. */
.iap-load { display: flex; align-items: center; gap: 9px;
  padding: 7px 13px; border-bottom: 1px solid rgba(141,153,174,.14);
  opacity: var(--o-runs); transition: opacity .45s ease; }
.iap-load__k, .iap-load__n { font-family: var(--mono); font-size: .56rem;
  letter-spacing: .12em; text-transform: uppercase; white-space: nowrap; }
.iap-load__k { color: var(--teal); font-weight: 600; }
.iap-load__n { color: #6c7a8d; }
.iap-load__tr { flex: 1 1 auto; min-width: 40px; height: 4px; border-radius: 2px;
  background: rgba(141,153,174,.25); overflow: hidden; }
.iap-load__f { display: block; height: 100%; width: 100%; border-radius: 2px;
  background: var(--teal); }
/* IT RUNS IN CIRCLES. This used to be a one-shot `forwards`: data-step="0" is
   set the moment the section pins, so the bar finished while the reader was
   still on the chapter's first sentence and they arrived at a full bar and an
   already-built model — having missed the one thing the chapter describes.

   The whole build now cycles on a 7s clock: the bar fills, the five blocks
   land one after another beneath it, the behaviour arrives on top, everything
   holds for a beat, and it starts again.

   The timings are baked into the keyframe percentages rather than set with
   animation-delay. A delayed infinite animation keeps its offset forever, so
   five delayed blocks would drift permanently out of phase with each other
   after the first pass instead of rebuilding together. */
.iap-stage[data-step="0"] .iap-load__f {
  animation: iap-load 7s infinite; }
@keyframes iap-load {
  0%   { width: 3%;   opacity: 1; animation-timing-function: cubic-bezier(.32, .06, .2, 1); }
  62%  { width: 100%; opacity: 1; }
  90%  { width: 100%; opacity: 1; }
  95%  { width: 100%; opacity: 0; }
  96%  { width: 3%;   opacity: 0; }
  100% { width: 3%;   opacity: 1; }
}

/* THE MODEL BUILDS WHILE THE BAR FILLS. The structure is drawn in five
   blocks — four domains and the backbone — and at step 0 each one fades
   in after the one before it, on the same clock as the bar above it. */
.iap-blk { opacity: 1; }
.iap-stage[data-step="0"] .iap-lay--struct .iap-blk {
  animation: iap-blk1 7s ease infinite; }
.iap-stage[data-step="0"] .iap-lay--struct .iap-blk:nth-child(2) { animation-name: iap-blk2; }
.iap-stage[data-step="0"] .iap-lay--struct .iap-blk:nth-child(3) { animation-name: iap-blk3; }
.iap-stage[data-step="0"] .iap-lay--struct .iap-blk:nth-child(4) { animation-name: iap-blk4; }
.iap-stage[data-step="0"] .iap-lay--struct .iap-blk:nth-child(5) { animation-name: iap-blk5; }
@keyframes iap-blk1 { 0%, 2%  { opacity: 0; } 8%,  90% { opacity: 1; } 95%, 100% { opacity: 0; } }
@keyframes iap-blk2 { 0%, 11% { opacity: 0; } 17%, 90% { opacity: 1; } 95%, 100% { opacity: 0; } }
@keyframes iap-blk3 { 0%, 20% { opacity: 0; } 26%, 90% { opacity: 1; } 95%, 100% { opacity: 0; } }
@keyframes iap-blk4 { 0%, 29% { opacity: 0; } 35%, 90% { opacity: 1; } 95%, 100% { opacity: 0; } }
@keyframes iap-blk5 { 0%, 38% { opacity: 0; } 44%, 90% { opacity: 1; } 95%, 100% { opacity: 0; } }
/* and the behaviour lands on it as the bar tops out */
.iap-stage[data-step="0"] .iap-lay--beh { animation: iap-beh 7s ease infinite; }
@keyframes iap-beh  { 0%, 58% { opacity: 0; } 66%, 90% { opacity: 1; } 95%, 100% { opacity: 0; } }
@keyframes iap-appear { from { opacity: 0; } to { opacity: 1; } }

/* ── the shared annotation type for steps 2, 3 and 4 ─────────────────
   One vocabulary: an arrow marks a propagation path, a tag names what is
   wrong with it. Anomaly Detection and Root-Cause Analysis use the SAME
   arrows deliberately — one traces forward, one traces back. */
.iap-arw { fill: none; stroke: var(--orange); stroke-width: 2.2; stroke-linecap: round; }
.iap-arwh { fill: var(--orange); }
.iap-tag { fill: #0b1420; stroke: var(--orange); stroke-width: 1.2; }
.iap-tagt { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; fill: #ffb08a; }
/* ── CHANGE DETECTION · TWO BASELINES, HELD AGAINST EACH OTHER ──────────
   WHAT THIS REPLACED, so nobody restores it: three delta chips floating
   over the blurred twin. Founder: "the deltas look strange and overlapped
   … the idea here is that we compare two baselines". They were placed by
   eye against the nodes they pointed at, so they collided with each other
   and with the labels underneath, and worse, three chips on a system
   drawing say "three things are wrong here" — which is Anomaly Detection's
   sentence, not this one.

   This step's sentence is A COMPARISON. So the figure is a comparison: one
   panel, two columns, a rule down the middle, and a row per difference —
   where it happened, what kind it is, and the value on each side. A cold
   reader sees two things being held against each other before they read a
   word. Nothing is positioned by eye and nothing can overlap: every row is
   on a fixed grid inside the panel, at both canvas sizes.

   The panel is opaque, so it is also what stops the blurred twin showing
   through the numbers. The three components it names are the three the
   .iap-foc group redraws sharp on the left, which is how the step still
   says WHERE in the system, without a single connector line.

   VOCABULARY: "software state", here and in the twin-per-software-state
   section at the foot of the page. Not version, not build. The version
   NUMBERS (7.3, 7.4) name the states; the word for the thing is state.
   ────────────────────────────────────────────────────────────────────── */
.iap-cmp { fill: rgba(9, 16, 27, .975); stroke: rgba(78, 205, 196, .34);
  stroke-width: 1.2; }
.iap-cmp__k { font-family: var(--mono); font-size: 10.5px; letter-spacing: .15em;
  fill: #7d8a9b; }
.iap-cmp__div { stroke: rgba(141, 153, 174, .32); stroke-width: 1; }
.iap-cmp__rule { stroke: rgba(141, 153, 174, .15); stroke-width: 1; }
.iap-cmp__hA { font-family: var(--mono); font-size: 11px; letter-spacing: .14em;
  fill: #8d99ae; }
.iap-cmp__hB { font-family: var(--mono); font-size: 11px; letter-spacing: .14em;
  fill: var(--teal); font-weight: 600; }
.iap-cmp__n { font-family: var(--font); font-size: 13px; font-weight: 600;
  letter-spacing: -.01em; fill: #e8e9ed; }
.iap-cmp__a { font-family: var(--mono); font-size: 9.2px; letter-spacing: .16em;
  fill: #8d99ae; }
.iap-cmp__vA { font-family: var(--mono); font-size: 15px; fill: rgba(198, 210, 226, .5); }
.iap-cmp__vB { font-family: var(--mono); font-size: 15px; font-weight: 600; fill: var(--teal); }
/* the narrow canvas is 380 units wide against 780, so its type is set down
   rather than scaled up by the viewBox */
.iap-arch--sm .iap-cmp__n { font-size: 11.5px; }
.iap-arch--sm .iap-cmp__a { font-size: 8px; letter-spacing: .12em; }
.iap-arch--sm .iap-cmp__vA, .iap-arch--sm .iap-cmp__vB { font-size: 12.5px; }
.iap-arch--sm .iap-cmp__k { font-size: 8.6px; letter-spacing: .12em; }
.iap-arch--sm .iap-cmp__hA, .iap-arch--sm .iap-cmp__hB { font-size: 10px; }
.iap-tag--sym { stroke: rgba(141,153,174,.6); }
.iap-tagt--sym { fill: #b8c4d4; font-size: 10px; }
.iap-tag--ev { stroke: rgba(255,157,122,.7); }
.iap-tagt--ev { fill: #ff9d7a; font-size: 11px; }
.iap-tag--root { stroke: #ff6b5b; stroke-width: 1.8; fill: #1a0f10; }
.iap-tagt--root { fill: #ff8f7d; font-size: 13px; letter-spacing: .1em; }
.iap-rcah { fill: #ff9d7a; }

/* ══ BLUR FOR FOCUS, ON ALL THREE MODULE STEPS ══════════════════
   The founder approved this on Change Detection and asked for it on the
   other two — with one refinement that applies back to Change Detection
   as well: BLUR ONLY WHAT THE FINDING DOES NOT INVOLVE.

   How it is scoped, without giving a single node a per-step class:
     · the twin (.iap-lay--struct, and .iap-lay--beh with it) is blurred
       WHOLE at steps 1, 2 and 3;
     · the module layers are never blurred, and each one opens with a
       .iap-foc group that REDRAWS exactly the nodes that finding runs
       through, in place, at the same coordinates.
   So the involved nodes, the paths between them and their labels sit
   sharp on top of their own blurred copies, and everything the module
   has nothing to say about recedes. One rule, three steps, and no step
   can blur something it is pointing at. */
.iap-stage[data-step="1"] .iap-lay--struct,
.iap-stage[data-step="1"] .iap-lay--beh,
.iap-stage[data-step="2"] .iap-lay--struct,
.iap-stage[data-step="2"] .iap-lay--beh,
.iap-stage[data-step="3"] .iap-lay--struct,
.iap-stage[data-step="3"] .iap-lay--beh { filter: blur(2.6px); }
.iap-lay--struct, .iap-lay--beh { transition: opacity .65s ease, filter .45s ease; }
/* the redrawn, in-focus node: opaque enough to mask the soft copy under
   it, same geometry and the same label type as everywhere else */
.iap-n--foc { fill: #101b2b; stroke: rgba(141,153,174,.72); stroke-width: 1.1; }

.iap-rca { fill: none; stroke: rgba(214,73,73,.55); stroke-width: 2.2;
  stroke-linecap: round; }
.iap-rca--run { stroke: #ff9d7a; stroke-width: 2.4; stroke-dasharray: 16 130;
  animation: iap-run3 3.2s linear infinite; }
@keyframes iap-run3 { from { stroke-dashoffset: 146; } to { stroke-dashoffset: 0; } }
.iap-rca-sym { fill: none; stroke: #ff9d7a; stroke-width: 1.6; }
.iap-rca-org { fill: rgba(214,73,73,.3); stroke: #ff6b5b; stroke-width: 1.8; }
.iap-rca-org--2 { fill: none; opacity: .45; }

/* THE THREE HTML CALLOUTS ARE DELETED. Founder: "too many overlay details
   trying to say nothing … the reader can only catch ONE thing at one demo
   step." Every step now shows its one idea and names its place in the
   product through the rail and the breadcrumb. Nothing is labelled twice. */

/* the chapters. Fully visible by default; only the driver dims them. */
.iap-chs { display: grid; gap: clamp(18px, 3vh, 30px); }
.is-pinned .iap-chs { gap: 0; }
.iap-cha { min-width: 0; transition: opacity .45s ease; }
/* THE FIRST CHAPTER IS ONE BEAT NOW, but it is a beat you have to WATCH:
   the bar fills and the model builds over about five seconds. So it still
   gets more room than an even share — 80vh rather than 40 — or the reader
   scrolls past the build before it has finished.
   THE LAST CHAPTER IS THE OTHER SPECIAL CASE. At one even share it went
   live and the pin released almost in the same breath, which is why the
   end of the story felt abrupt and the next band arrived too soon. It now
   holds 67vh: it lights up roughly 55vh before the figure unpins, so it
   can actually be read, and the section lets go on a settled beat.
   80 + 3 x 40 + 67 = 267vh, against 277vh before this pass and the 280vh
   the even split took — so the story is no taller than it was. */
.is-pinned .iap-cha { min-height: 40vh; display: flex; flex-direction: column;
  justify-content: center; opacity: .34; }
.is-pinned .iap-cha:first-child { min-height: 80vh; }
.is-pinned .iap-cha:last-child { min-height: 67vh; }
.is-pinned .iap-cha[data-state="on"] { opacity: 1; }
/* A CHAPTER IS THREE THINGS AND AT MOST ONE LINK. The "Chapter 0N ·"
   kickers and the tag pills are deleted; the role line and the question
   survive because that framing is the point of the section. The link is a
   plain underlined line, not a badge. */
/* THE ROLE LINE IS THE CHAPTER'S ONLY ORIENTATION — it names the module and
   the person asking — so it was the wrong thing to set at 10px in dim grey.
   Larger, lighter, and less tracked: a label still, but a legible one. */
.iap-cha__role { margin: 0 0 10px; font-family: var(--mono);
  font-size: clamp(12px, 1vw, 13.5px); letter-spacing: .05em;
  line-height: 1.45; color: #aeb9c9; }
.iap-cha__q { margin: 0 0 12px; font-size: clamp(20px, 2.2vw, 29px); font-weight: 700;
  letter-spacing: -.035em; line-height: 1.15; color: var(--iap-paper); max-width: 16ch; }
.iap-cha__p { margin: 0; font-size: clamp(14px, 1.05vw, 16px); line-height: 1.55;
  color: rgba(244,245,247,.74); max-width: 38ch; }
.iap-cha__p b { color: var(--iap-paper); font-weight: 600; }
.iap-cha__go { display: inline-block; margin-top: 16px; font-size: .88rem;
  color: var(--teal); text-decoration: none;
  border-bottom: 1px solid rgba(78,205,196,.35); }
.iap-cha__go:hover { border-bottom-color: currentColor; }

@media (max-width: 900px) {
  .iap-asm { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .is-pinned .iap-asm__stage { z-index: 3; padding-bottom: 10px;
    background: linear-gradient(180deg, #0c1626 86%, rgba(12,22,38,0)); }
  /* the figure is pinned at the top of the phone, so the chapter's words sit
     in the space BELOW it rather than centred behind it */
  .is-pinned .iap-cha { min-height: 42vh; justify-content: flex-end;
    padding-bottom: 4vh; }
  .is-pinned .iap-cha:first-child { min-height: 84vh; }
  .is-pinned .iap-cha:last-child { min-height: 66vh; }

  /* THE PINNED FIGURE MUST NOT RESIZE WHILE IT IS PINNED. The captions are
     not the same length — "two software states held side by side, and what
     differs between them" runs to three lines where "the same paths, traced
     back to the root" runs to two — so the stage grew and shrank by one line
     on every step change, and a figure pinned to the top of the screen that
     changes height is read as a stutter, not as a transition. The caption
     reserves its tallest state instead. */
  .is-pinned .iap-now { min-height: calc(3 * 1.4 * 0.85rem + 21px); align-items: flex-start; }
}
@media (max-width: 720px) {
  /* the pinned figure must not eat the phone: the rail, the ask row and the
     window chrome go, the compact model stays, and the caption still says
     which chapter is on screen. */
  .iap-asm__stage .iap-app__win,
  .iap-asm__stage .iap-ask { display: none; }
  /* The rail is gone at this width (see above), so the per-step "you are
     here" entry goes with it. The caption under the figure already names the
     chapter, which is the same information in the place the reader is looking. */
  .iap-asm__stage .iap-tool { padding: 7px 11px; }
  .iap-asm__stage .iap-tool .iap-chip { display: none; }
  .iap-asm__stage .iap-app__body { grid-template-columns: minmax(0, 1fr); }
  /* Cap the pinned figure. 38vh on the SVG puts the whole stage — rail,
     toolbar and caption included — at about 61% of the phone, not the half
     this once claimed. It stays at 38vh anyway: the two ways of buying that
     11% back are both worse than spending it. Capping the stage clips the
     app's last 17px, and taking it off the SVG shrinks the model's own
     labels to 7.7px, which is the figure no longer being readable — the
     thing the cap exists to protect. What actually made this section feel
     broken was the stage changing height under the reader, and that is
     fixed where it was caused, on the caption. */
  .iap-asm__stage .iap-canvas svg { max-height: 38vh; }
}

/* ══ 4 · WHAT WE ARE BUILDING NEXT ══════════════════════════════════════
   Same visual language as the three chapters above — deliberately, so the
   reader reads these as the roadmap of the same system — but dashed and
   unfilled, so nobody mistakes them for something they can buy today.
   ═══════════════════════════════════════════════════════════════════════ */
.iap-nextband { border-top: 1px solid rgba(141,153,174,.18); }
.iap-nexts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(14px, 2vw, 22px); margin-top: clamp(22px, 3vh, 30px); }
.iap-nx { display: flex; flex-direction: column; gap: 10px; text-decoration: none;
  border: 1.5px dashed rgba(141,153,174,.4); border-radius: 16px;
  padding: clamp(20px, 2.6vw, 30px); background: transparent;
  transition: border-color .25s ease, background .25s ease; }
.iap-nx--invite { border-color: rgba(78,205,196,.55); }
.iap-nx:hover { border-color: var(--teal); background: rgba(78,205,196,.06); }
.iap-nx__k { margin: 0; font-family: var(--mono); font-size: .62rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: #8d99ae; }
.iap-nx--invite .iap-nx__k { color: var(--teal); }
.iap-nx__t { margin: 0; font-size: clamp(18px, 1.8vw, 24px); font-weight: 700;
  letter-spacing: -.03em; line-height: 1.2; color: var(--iap-paper); }
.iap-nx__p { margin: 0; font-size: .89rem; line-height: 1.58; color: rgba(244,245,247,.72);
  max-width: 42ch; }
.iap-nx__go { margin-top: auto; padding-top: 6px; font-family: var(--mono); font-size: .64rem;
  font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--teal); }
@media (max-width: 720px) { .iap-nexts { grid-template-columns: minmax(0, 1fr); } }

/* ══ 5 · GET STARTED ════════════════════════════════════════════════════
   Was two paragraphs, a three-stage pipe, a terms line and a roadmap box,
   with "4-6 weeks" printed twice inside one screen. Now: one promise, the
   pipe, and the week count exactly once — on the middle stage, which is
   the only stage it describes.
   ═══════════════════════════════════════════════════════════════════════ */
/* THE THREE-BOX PIPELINE IS BACK. A previous pass replaced it with two
   cards; the founder: "the structure was OK, I just wanted you to highlight
   important stuff bigger and more." So the yours -> ours -> then shape
   returns. THE THIRD STAGE IS NOT A HIGHLIGHTED BOX. Founder: it should
   be a simple box like a normal pipeline stage, with only the words
   "on-prem" picked out inside its text. So display size is now used
   exactly once on this band -- 4-6 WEEKS / ANY FORMAT on the middle
   stage -- and the deployment answer is carried by one emphasised phrase
   in a normal paragraph. Every fact still appears exactly once. */
/* Two stages, not three: the on-prem card came out, and repeat(3) left the
   pair stretched across a row built for one more. auto-fit keeps them
   honest if a stage is ever added back. */
.iap-pipe { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(12px, 1.8vw, 20px); align-items: stretch; }
.iap-st { position: relative; border: 1px solid var(--border); border-radius: 16px;
  background: #fff; box-shadow: 0 1px 2px rgba(43,45,66,.05);
  padding: clamp(18px, 2.2vw, 26px); display: flex; flex-direction: column; }
/* the chevron that makes three boxes a pipeline rather than three cards */
.iap-st + .iap-st::before { content: ""; position: absolute; left: 0; top: 50%;
  width: 11px; height: 11px; border-top: 2px solid var(--teal-mid);
  border-right: 2px solid var(--teal-mid);
  transform: translate(calc(-50% - clamp(6px, .9vw, 10px)), -50%) rotate(45deg); }
.iap-st--focus { border: 1.5px solid var(--teal-mid);
  background: radial-gradient(130% 150% at 50% 0%, rgba(78,205,196,.13), transparent 70%), #fff;
  box-shadow: 0 14px 36px rgba(43,45,66,.09); }
.iap-st__k { margin: 0 0 12px; font-family: var(--mono); font-size: .6rem;
  font-weight: 600; letter-spacing: .15em; text-transform: uppercase; color: var(--dim); }
.iap-st--focus .iap-st__k { color: var(--teal-ink); }
/* THE TWO FACTS A SKIMMER MUST CATCH, and nothing else on this band is
   anywhere near this size. */
.iap-st__big { margin: 0; font-size: clamp(30px, 4.4vw, 52px); font-weight: 700;
  letter-spacing: -.045em; line-height: .98; color: var(--teal-ink);
  text-wrap: balance; }
.iap-st__t { margin: 10px 0 0; font-size: clamp(14.5px, 1.15vw, 17px); font-weight: 600;
  letter-spacing: -.02em; line-height: 1.35; color: var(--text); max-width: 26ch; }
.iap-st__p { margin: 10px 0 0; font-size: .87rem; line-height: 1.58; color: var(--muted);
  max-width: 38ch; }
.iap-st__p b { color: var(--text); font-weight: 600; }
/* the one phrase picked out inside a normal stage's paragraph */
.iap-st__p .iap-hl { font-style: normal; font-weight: 700; color: var(--teal-ink);
  letter-spacing: -.01em; }
.iap-fmt { list-style: none; margin: 14px 0 0; padding: 0; display: flex;
  flex-wrap: wrap; gap: 5px; }
.iap-fmt li { font-family: var(--mono); font-size: .62rem; letter-spacing: .04em;
  color: var(--muted); border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 3px 8px; }
@media (max-width: 860px) {
  /* STACKED, THE CHEVRON HAD NOWHERE TO SIT. Rotated 45 degrees an 11px
     square is 15.6px across, and the row gap here was 12px — so wherever it
     was placed it landed on one of the two card borders, and it was lifted
     only 6px, which put it squarely on the lower card's edge. The gap opens
     to 30px and the chevron sits at its exact midpoint, clear of both. */
  .iap-pipe { grid-template-columns: minmax(0, 1fr); gap: 30px; }
  .iap-st + .iap-st::before { left: 50%; top: 0;
    transform: translate(-50%, calc(-50% - 15px)) rotate(135deg); }
}

/* A NEW SECTION HAS TO LOOK LIKE ONE. This sat at #fbfcfd directly under the
   software-states band at #fff — two whites a screen apart, which is no
   boundary at all, and the reader scrolled from one section into the next
   without anything telling them. It gets its own ground and a hairline. */
.iap-gs { background: #eef1f6; border-top: 1px solid rgba(43, 45, 66, .1);
  padding-block-start: clamp(56px, 8vh, 104px); }
.iap-gs__promise { margin: 0 0 clamp(28px, 4vh, 44px); font-size: clamp(19px, 2vw, 27px);
  font-weight: 600; letter-spacing: -.028em; line-height: 1.32; color: var(--text);
  max-width: 26ch; }
.iap-gs__promise b { color: var(--teal-ink); }
.iap-gs__actions { margin-top: clamp(26px, 4vh, 40px); display: flex; flex-wrap: wrap;
  gap: 12px; align-items: center; }

/* ══ shared responsive collapse ═════════════════════════════════════════ */
@media (max-width: 1040px) {
  .iap-hero__grid { grid-template-columns: minmax(0, 1fr); align-items: start; }
}
@media (max-width: 760px) {
  .iap-app__body { grid-template-columns: minmax(0, 1fr); }
  .iap-rail { flex-direction: row; flex-wrap: wrap; border-right: 0;
    border-bottom: 1px solid rgba(141,153,174,.16); }
  .iap-rail__k { width: 100%; margin: 0 0 2px 2px; font-size: .68rem; }
  .iap-app__badge { margin-left: 0; }

  /* ── THE DEMO HAS TO FIT A SCREEN ──────────────────────────────────────
     At 390px the hero ran 1437px against an 844px viewport, and the app
     alone was 1005 of it — you could not see the thing you were being shown.
     Every block stays; each one is shortened.

     The rail: two items to a row instead of one. The group labels are the
     architecture and they stay; it is the stacking that was costing 90px. */
  /* THE APP MENU GOES. On a phone the rail is not navigation the reader can
     use — nothing in these panels is clickable — and stacked above the content
     it becomes a list of words between the reader and the thing being shown.
     The tab's own content says which view this is. */
  .iap-rail { display: none; }

  /* The model, cropped by the frame at an exact viewBox row so no group is
     shown half-drawn. Four of the five domains fit now that the rail is gone;
     the cut lands at y=362 of 466, between Body & Comfort and Powertrain.
     Stated as a ratio rather than a height so it holds at any width. The
     <title> still describes the whole system. */
  .iap-hero .iap-canvas { aspect-ratio: 380 / 362; overflow: hidden; padding-bottom: 0; }
  .iap-hero .iap-canvas svg.iap-arch--sm { height: auto; }

  /* Three suggested questions is a list; two is an example, which is all this
     strip was ever doing. */
  .iap-hero .iap-qs li:nth-child(3) { display: none; }
}

/* motion is decoration here; the page says the same thing without it */
@media (prefers-reduced-motion: reduce) {
  .iap-sg, .iap-qs li, .iap-load__f,
  .iap-lay--beh, .iap-blk, .iap-rca--run { animation: none; }
  .iap-sg, .iap-rca--run { stroke-dasharray: none; opacity: .5; }
  .iap-qs li:first-child { border-color: var(--teal); background: rgba(78,205,196,.14); }
  /* the assembled end state, with every chapter at full contrast */
  .is-pinned .iap-asm__stage { position: static; }
  .is-pinned .iap-cha { min-height: 0; opacity: 1; }
  .is-pinned .iap-chs { gap: clamp(18px, 3vh, 30px); }
  .iap-lay, .iap-cha { transition: none; }
}


/* ==========================================================================
   § 3 ON A PHONE — THE STORY IS A SWIPE DECK
   ==========================================================================
   The pinned layout puts one figure at the top of the screen and runs five
   chapters of text underneath it, swapping the figure as each chapter passes
   a reading line. On a desktop that reads as one thing being built. On a
   phone it reads as the page stuttering: the figure is already taking half
   the screen, so the text it belongs to is a sliver at the bottom, and the
   thing that changes is behind the thing you are reading.

   Here the same five beats are five cards you swipe. The figure stays at the
   top and changes WITH the card rather than under it, and every chapter gets
   a full screen width instead of a sliver. The driver in
   js/blocks/ia-platform-story.js sets .is-swipe and reads the active card off
   the deck's own scroll position; if that file never runs, .is-swipe is never
   added and the chapters remain a plain readable stack.
   ========================================================================== */

@media (max-width: 900px) {
  .is-swipe .iap-asm {
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
  }

  /* The shared figure steps aside: every card carries its own.
     .is-swipe is set on [data-asm-root], which IS .iap-asm — so this is a
     child combinator off .is-swipe itself, not a descendant of it. Written
     the other way it matched nothing and the page showed the pinned figure
     stacked on top of the deck. */
  .is-swipe > .iap-asm__stage {
    display: none;
  }

  .is-swipe .iap-asm__stage--card {
    display: block;
    position: static;
    padding-bottom: 0;
    margin-bottom: 14px;
    background: none;
  }

  /* a card is the beat: the view and the words for it, moving as one */
  .is-swipe .iap-cha {
    display: flex;
    flex-direction: column;
  }

  /* full-bleed: the cards run edge to edge so a part-swiped neighbour is
     visibly a neighbour, not a broken margin */
  .is-swipe .iap-chs {
    display: flex;
    flex-wrap: nowrap;
    gap: 0;
    margin-inline: calc(var(--page-gutter, 20px) * -1);
    padding: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  .is-swipe .iap-chs::-webkit-scrollbar {
    display: none;
  }

  .is-swipe .iap-cha {
    flex: 0 0 100%;
    width: 100%;
    min-width: 0;
    min-height: 0;
    scroll-snap-align: center;
    scroll-snap-stop: always;
    padding: 2px var(--page-gutter, 20px) 4px;
    justify-content: flex-start;
    /* every card is its own screen, so none of them is "the inactive one" —
       the dimming that tells the pinned layout apart from itself would just
       be a card the reader is looking at, greyed */
    opacity: 1;
  }

  .is-swipe .iap-cha::before,
  .is-swipe .iap-cha::after {
    content: none;
  }

  /* the counter and bar under the figure are the deck's position indicator —
     they already say 03 / 05 and fill to match, driven by the same apply() */
  .is-swipe .iap-now {
    min-height: calc(3 * 1.4 * 0.85rem + 21px);
    align-items: flex-start;
  }

  .is-swipe .iap-swipe-hint {
    display: block;
  }
}

/* One hint, under the deck, saying what to do with it. Authored here rather
   than in the markup so a browser that never reaches the swipe layout never
   shows an instruction for an interaction it does not have. */
.iap-swipe-hint {
  display: none;
  margin: 10px 0 0;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(157, 171, 189, .72);
  text-align: center;
}

/* Cloned per swipe card by js/blocks/ia-platform-story.js. Hidden everywhere
   else so the pinned desktop layout never shows five extra figures — the
   clones are left in the DOM across a resize rather than rebuilt each time. */
.iap-asm__stage--card {
  display: none;
}
