/* ═══════════════════════════════════════════════════════════════════
   Page glue — The Verification Tax (IDC White Paper)
   ───────────────────────────────────────────────────────────────────
   The design system now lives in:
     css/tokens.css        — Sage Fusion tokens
     css/forma-webdoc.css  — Forma V5 component layer (molecules, web-doc,
                             infographics, cards, reveals)
     js/forma-webdoc.js    — Forma behaviour (reveals, scroll-spy, glow,
                             progress, declarative calculators)
   This file holds only what is specific to THIS document: the live WebGL
   shader ground, the cover hero glass card, and a few integration tweaks
   so the dark web-doc sits transparently over the shader.
   ═══════════════════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html, body { background: #070807; }
body { font-family: var(--font-ui); -webkit-font-smoothing: antialiased; }

/* ── Live shader ground ──────────────────────────────────────────────
   A fixed full-viewport WebGL canvas. The web-doc sits transparently on
   top of it (see .webdoc override below), so the shader reads as the
   document's glow: a colour pool behind the cover, easing to an
   edge-confined near-black floor on the content sections as you scroll. */
#glowfx {
  position: fixed; inset: 0; width: 100vw; height: 100vh;
  z-index: 0; pointer-events: none; display: block;
}

/* The web-doc grid is the live layer above the shader. In dark mode the
   Forma module paints --pg-bg (#070807) on .webdoc; we clear it so the
   shader shows through, and keep the dark sections transparent. */
.webdoc { position: relative; z-index: 1; background: transparent; }
.webdoc[data-paper="dark"] { background: transparent; }
.no-webgl .webdoc { background: var(--pg-bg); }

/* Rail stays a framed dark column over the shader (its own translucent
   ground + blur are defined in forma-webdoc.css). Keep it above content. */
.doc-rail { z-index: 30; }
.doc-rail__brand img { display: block; height: 22px; width: auto; }

/* Reading-progress bar already fixed by the module; lift above the shader. */
.doc-progress { z-index: 40; }

/* Visually hidden, still announced. Used for live regions and for text
   that gives a screen reader context the visual layout already provides. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* ── Skip link ───────────────────────────────────────────────────── */
.skip-link {
  position: fixed; top: 12px; left: 12px; z-index: 100;
  background: var(--pg-brand, #00D639); color: #04130a;
  font-family: var(--font-ui); font-weight: 600; font-size: 13px;
  padding: 8px 14px; border-radius: 8px; text-decoration: none;
  transform: translateY(-150%); transition: transform .18s var(--ease-out);
}
.skip-link:focus { transform: translateY(0); }
/* .doc-canvas and destination headings take tabindex="-1" so chapter
   navigation can move focus to them. They are never tab stops, so a ring
   on a programmatic focus would be noise — :focus-visible below still
   covers the case where a browser decides the ring is warranted. */
.doc-canvas:focus { outline: none; }

/* ═══════════════════════════════════════════════════════════════════
   FOCUS — one shared indicator for the whole document
   ───────────────────────────────────────────────────────────────────
   Dru's review (2026-09-22): component rules removed outlines while no
   page-level :focus-visible treatment existed, so most controls fell back
   to whatever the browser drew and the range inputs lost their indicator
   entirely.

   Dru's follow-up (2026-09-25): use Sage's standard ring, a black inner
   ring and a yellow outer ring, drawn with box-shadow rather than an
   outline. The black ring separates the yellow from whatever the control
   sits on, so it holds on any background. The rule sequence is Dru's:
   ring on :focus for browsers without :focus-visible, removed again when
   the focus came from a mouse, ring on :focus-visible for keyboard focus.
   ═══════════════════════════════════════════════════════════════════ */
:root {
  --focus-ring: 0 0 0 2px #000, 0 0 0 4px var(--core-focus, #FFB500);
}
a:focus,
button:focus,
input:focus,
select:focus,
textarea:focus,
summary:focus,
[tabindex]:not([tabindex="-1"]):focus {
  outline: none;
  box-shadow: var(--focus-ring);
}
a:focus:not(:focus-visible),
button:focus:not(:focus-visible),
input:focus:not(:focus-visible),
select:focus:not(:focus-visible),
textarea:focus:not(:focus-visible),
summary:focus:not(:focus-visible),
[tabindex]:not([tabindex="-1"]):focus:not(:focus-visible) {
  box-shadow: none;
}
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible {
  box-shadow: var(--focus-ring);
  border-radius: 4px;
}
/* Pill-shaped and card controls keep their own silhouette so the ring
   does not cut a square corner across a rounded edge. */
.navrow:focus-visible,
.doc-rail__select:focus-visible,
.rail-action:focus-visible { border-radius: 999px; }
.doc-slider__dot:focus-visible { border-radius: 50%; }
.rail-action--tertiary:focus-visible { border-radius: 6px; }

/* Forced colours (e.g. Windows High Contrast) throws box-shadow away, so
   the ring above would vanish. Give those users a system-coloured outline. */
@media (forced-colors: active) {
  a:focus-visible, button:focus-visible, input:focus-visible,
  select:focus-visible, textarea:focus-visible, summary:focus-visible,
  [tabindex]:not([tabindex="-1"]):focus-visible,
  .ig-calc__field:has(input:focus-visible) {
    outline: 3px solid Highlight; outline-offset: 3px;
  }
}

/* ═══════════════════════════════════════════════════════════════════
   COVER HERO — frosted-glass title card over the live shader
   The .doc-section.is-hero gives the tall, centred frame; the shader
   pools its colour here (u_centerFill ≈ 1 at the top of the scroll).
   ═══════════════════════════════════════════════════════════════════ */
/* Full-bleed: the cover fills the canvas column edge-to-edge, flush like the
   other pages — no floating card, no rounded corners. */
.cover-hero { padding: 0; }
.cover-hero .doc-well { max-width: none; width: 100%; }

.cover-glass {
  display: flex; flex-direction: column; justify-content: space-between;
  gap: 40px; min-height: 92vh;
  padding: clamp(48px, 8vh, 110px) clamp(28px, 6vw, 96px);
  border-radius: 0; border: 0;
  /* Flat black tint over the blurred shader — darkens the vibrant glow
     enough for legible text while staying frosted. */
  background: rgba(0, 0, 0, 0.30);
  -webkit-backdrop-filter: blur(22px) saturate(135%);
  backdrop-filter: blur(22px) saturate(135%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
.no-webgl .cover-glass {
  background:
    radial-gradient(120% 120% at 12% 0%, rgba(0, 214, 57, 0.20), transparent 55%),
    radial-gradient(120% 120% at 100% 100%, rgba(29, 140, 195, 0.16), transparent 60%),
    rgba(0, 0, 0, 0.55);
}
/* One source of truth for the cover height: the OUTER section owns it
   (.doc-section.is-hero, 92vh desktop / 78vh ≤760px in forma-webdoc.css)
   and the glass fills whatever that is. Dru's review (2026-09-22) found a
   ~90px gap at 761–900px, where the outer hero still held 92vh while the
   glass was cut to 82vh and .doc-section's vertical centring split the
   unused 10vh above and below. Don't reintroduce a second min-height. */
@media (max-width: 900px) {
  .cover-glass { padding: 40px 24px; gap: 30px; border-radius: 0; min-height: 0; }
}
/* .doc-section is a centring flex COLUMN, so `flex` here grows the well and
   the glass along the block axis — making the glass exactly as tall as the
   section at every width, with no second min-height to drift out of step.
   flex-basis must stay 0 (not auto): on `align-items: stretch` the well is
   already full width, and an auto basis would size it to its content's
   max-content width instead — 837px inside a 375px viewport. */
.cover-hero .doc-well { display: flex; flex-direction: column; flex: 1 1 0; min-width: 0; }
.cover-hero .cover-glass { flex: 1 1 0; min-width: 0; }

/* ═══════════════════════════════════════════════════════════════════
   SECTION OPENER — full-bleed split: chapter heading on the dark ground at
   left, lead photo filling the right column floor-to-ceiling. Mirrors the
   cover hero. Collapses to a stacked single column on narrow viewports.
   ═══════════════════════════════════════════════════════════════════ */
.doc-section.has-split { padding: 0; min-height: 0; }
/* The text column starts on the same left edge as the centred 1200px content
   wells (so the indent matches page to page); the photo bleeds to the right
   edge. Padding-left replicates the well's auto-margin: max(sec-pad, gutter). */
.sec-split {
  display: grid; grid-template-columns: 65fr 35fr; gap: clamp(28px, 4vw, 72px);
  min-height: 86vh; width: 100%;
  padding-left: max(var(--sec-pad-x), calc((100% - 1200px) / 2));
}
.sec-split__text {
  display: flex; flex-direction: column; justify-content: center; gap: 22px;
  padding: clamp(44px, 8vh, 96px) 0;
  position: relative; z-index: 1;
}
/* Keep prose at a readable measure even though the column is wide. */
.sec-split__text > :not(.doc-display) { max-width: 58ch; } /* was 68ch; matches the prose measure (Jay: "this column is too wide") */
.sec-split__media { position: relative; overflow: hidden; background: var(--pg-surface); }
/* Floor-to-ceiling image placeholder (swap for an <img> when art is chosen). */
.sec-split__ph {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 24px;
  background:
    radial-gradient(120% 100% at 78% 12%, rgba(var(--glow-1), 0.18), transparent 55%),
    repeating-linear-gradient(45deg, rgba(128,128,128,0.05) 0 11px, rgba(128,128,128,0.09) 11px 22px),
    var(--pg-surface);
}
.sec-split__ph span {
  font-family: 'SF Mono', ui-monospace, Menlo, monospace; font-size: 12px; letter-spacing: 0.03em;
  color: var(--pg-fg-3); text-align: center;
  padding: 7px 12px; border: 1px solid var(--pg-border); border-radius: 8px; background: var(--pg-bg);
}

/* Ring chart: left-align each cell so the first ring and the labels line up
   with the surrounding prose. (The default centers content in each grid
   column, pushing the left column ~40px in from the text edge.) */
.ig-rings .ig-ring { align-items: flex-start; }
.sec-split__media > img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  object-position: center; display: block;
}
@media (max-width: 768px) {
  .sec-split { grid-template-columns: 1fr; min-height: 0; padding-left: 0; gap: 0; }
  .sec-split__text { min-height: 40vh; padding: 40px 24px 30px; }
  .sec-split__media { aspect-ratio: 16 / 11; }
}

/* ═══════════════════════════════════════════════════════════════════
   BODY-COLUMN BALANCE
   The default cols-2 keeps each paragraph whole (break-inside:avoid),
   which leaves big whitespace gaps when paragraphs are unevenly sized.
   Letting prose flow across the column break lets the balancer equalise
   both columns (standard newspaper reading order: down the left, then
   continue at the top of the right).
   ═══════════════════════════════════════════════════════════════════ */
.doc-body.cols-2 p { break-inside: auto; -webkit-column-break-inside: auto; }

/* ═══════════════════════════════════════════════════════════════════
   DATA-LABEL LEGIBILITY
   The descriptive body labels inside the infographic components were small
   and dimmed (12–13px at 55–78% opacity), which made them hard to read.
   Bump them up and use the brightest theme foreground (reads as white on
   the dark cards; still theme-correct if the paper ever flips to light).
   ═══════════════════════════════════════════════════════════════════ */
.ig-fig__l   { font-size: 15px;   line-height: 1.5;  color: var(--pg-fg); }
.ig-bar__lbl { font-size: 14.5px; line-height: 1.35; color: var(--pg-fg); }
.ig-ring__lbl{ font-size: 14px;   line-height: 1.4;  color: var(--pg-fg); }
.ig-stack__p { font-size: 14px;   line-height: 1.45; color: var(--pg-fg); }

/* Compact bar chart — tighter vertical rhythm for in-column placement. */
.ig-bars.is-compact { gap: 9px; }
.ig-bars.is-compact .ig-bar__top { margin-bottom: 3px; }

/* Architecture donut rings use smaller wraps (84–96px) than the default 124px,
   so the 26px numeral is oversized — scale it down to fit. */
.doc-section[data-chapter="architecture"] .ig-ring__num { font-size: 18px; }

/* A lede sized to match column-1 width on desktop, full width on mobile
   (an inline max-width can't be undone by a media query). */
.doc-lede.is-col1 { max-width: calc(50% - 20px); }
@media (max-width: 768px) { .doc-lede.is-col1 { max-width: none; } }

/* Wide data tables: keep a legible minimum width so they scroll horizontally
   inside their overflow-x:auto wrapper on mobile instead of char-wrapping. */
.ig-table.is-scroll { min-width: 720px; }
@media (max-width: 768px) {
  .ig-table.is-scroll th, .ig-table.is-scroll td { overflow-wrap: normal; }
}

/* ═══════════════════════════════════════════════════════════════════
   STAT-FIGURE LAYOUT — five cards as 3 + 2
   When a section has exactly five stat cards, lay them three to a row so
   they read as 3-on-top / 2-on-bottom. The bottom two keep the same width
   as the cards directly above and sit left-aligned (the third slot is left
   empty). Sections with three or four cards keep their default layout.
   ═══════════════════════════════════════════════════════════════════ */
.ig-figs:has(> .ig-fig:nth-child(5):last-child) {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; align-items: stretch;
}
@media (max-width: 760px) {
  .ig-figs:has(> .ig-fig:nth-child(5):last-child) { grid-template-columns: 1fr 1fr; }
}

/* ═══════════════════════════════════════════════════════════════════
   EXEC — "Three things you need to know"
   A plain stacked list: all three points visible at once, no scroll
   interaction. Single column (not .pillargrid) because point 3 runs ~3x
   longer than the others — in three narrow columns the row height is set
   by the longest card and the short ones read as half-empty.
   Uses the shared .card component; the numeral sits inline with the title.
   ═══════════════════════════════════════════════════════════════════ */
.execstack__head { margin-bottom: 8px; text-align: center; }
.execlist { display: flex; flex-direction: column; gap: 16px; margin-top: 40px; }
.execlist__card {
  padding: 32px 36px; gap: 14px; height: auto;
  /* per-card glow — hue and origin vary so the three don't read identical */
  --card-glow: var(--glow-3);
  --glow-pos: 100% 0%;
  --glow-a: 0.05;
  background: radial-gradient(130% 120% at var(--glow-pos), rgba(var(--card-glow), var(--glow-a)), transparent 55%), #0E1210;
  border: 1px solid rgba(var(--card-glow), 0.11);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
.execlist__card:nth-child(2) { --card-glow: var(--glow-1); --glow-pos: 6% 0%;   --glow-a: 0.065; }
.execlist__card:nth-child(3) { --card-glow: var(--glow-2); --glow-pos: 88% 100%; --glow-a: 0.055; }
.execlist__head { display: flex; align-items: center; gap: 30px; }
.execlist__card .card__icon.is-numeral { width: 46px; height: 46px; border-radius: 12px; font-size: 20px; }
.execlist__title { font-size: 22px; line-height: 1.2; }
.execlist__body { font-size: 16px; line-height: 1.6; max-width: 78ch; }
@media (max-width: 900px) {
  .execlist { gap: 14px; margin-top: 28px; }
  .execlist__card { padding: 26px 24px; }
  .execlist__head { gap: 13px; }
  .execlist__title { font-size: 19px; }
  .execlist__body { font-size: 15px; }
}

/* ═══════════════════════════════════════════════════════════════════
   MERGED SECTIONS — a chapter title/beat fused with the page below it.
   These sections hold two stacked .doc-well blocks. Align every well to the
   wide measure so the heading shares the body's left edge, and add breathing
   room between the heading block and the content beneath it.
   ═══════════════════════════════════════════════════════════════════ */
.doc-section:has(> .doc-well + .doc-well) > .doc-well { max-width: 1200px; }
.doc-section > .doc-well + .doc-well { margin-top: clamp(36px, 5vh, 60px); }

/* Standalone chapter dividers: align the heading to the same wide measure as
   the body pages so the left indent matches across the document. */
.doc-section.is-divider > .doc-well { max-width: 1200px; }

.cover-glass__top { display: flex; justify-content: space-between; align-items: center; gap: 24px; }
.cover-glass__top img { display: block; height: 23px; width: auto; }
.cover-glass .m-caption { color: rgba(255, 255, 255, 0.74); }
.cover-glass .m-caption strong { color: #fff; }

.cover-glass__head { display: flex; flex-direction: column; }
.cover-kicker, .cover-title {
  font-size: clamp(38px, 4.4vw, 60px); line-height: 1.06;
  color: #fff; margin: 0; padding: 0; text-wrap: balance;
}
.cover-kicker { font-family: var(--font-ui); font-weight: 400; letter-spacing: 0; }
.cover-title  { font-family: var(--font-headline); font-weight: 900; letter-spacing: 0; margin-top: 10px; }
.cover-title .accent { color: var(--pg-brand); }
.cover-glass__foot .m-rule { background: rgba(255, 255, 255, 0.18); }

/* Cover entrance — glass settles in, then the three blocks rise + fade. */
@keyframes coverGlassIn { from { opacity: 0; transform: scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes coverRise    { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
.cover-glass       { animation: coverGlassIn 0.7s var(--ease-out) 0.05s both; }
.cover-glass__top  { animation: coverRise 0.6s var(--ease-out) 0.20s both; }
.cover-glass__head { animation: coverRise 0.6s var(--ease-out) 0.45s both; }
.cover-glass__foot { animation: coverRise 0.6s var(--ease-out) 0.70s both; }
@media (prefers-reduced-motion: reduce) {
  .cover-glass, .cover-glass__top, .cover-glass__head, .cover-glass__foot { animation: none !important; }
}

/* ── Scatter plot figure (industry section) keeps the type legible ──── */
.fig-scatter svg { width: 100%; height: auto; font-family: var(--font-ui); }

/* ── Analyst portrait ───────────────────────────────────────────────── */
.analyst-portrait {
  width: 120px; height: 120px; border-radius: 50%; object-fit: cover;
  border: 3px solid var(--pg-mint); display: block;
}

/* ── Compact rail: the module collapses the rail to a top bar already; make
   sure the cover card breathes and the shader still fills behind.
   Boundary tracks the rail collapse — raised 900 → 1100px, 2026-09-22. ── */
@media (max-width: 1100px) {
  #glowfx { height: 100dvh; }
}

/* ── Rail action: Download (tertiary). Share button removed 2026-09-16 (Jay).
   Uses the Sage kit pill (border-radius 999px, font-ui). Lives inside
   .doc-rail__list so it sits under "About this research" on desktop and
   inside the chapter dropdown on mobile. Inherits the rail's --pg-* tokens. */
/* Sibling of the chapter list, not an item in it. On desktop it sits under
   the list; in the compact rail it moves beside the "Select a chapter"
   trigger so it is reachable without opening the menu at all. */
.doc-rail__actions { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; width: fit-content; margin: 18px 10px 4px; }
.rail-action__meta { font-family: var(--font-ui); font-size: 12px; color: var(--pg-fg-3); padding-left: 2px; }
.rail-action {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 16px; border-radius: 999px; border: 1px solid transparent; cursor: pointer;
  font-family: var(--font-ui); font-weight: 500; font-size: 13px; letter-spacing: .01em; line-height: 1; text-decoration: none;
  transition: background .14s var(--ease-out), border-color .14s var(--ease-out), color .14s var(--ease-out);
}
.rail-action svg { width: 15px; height: 15px; flex: none; }
/* Download — Sage tertiary: white text link, white underline under icon + label.
   Uses border-bottom (not text-decoration) so the rule also spans the icon. */
/* min-height 24px so the target clears the WCAG 2.2 minimum; the visible
   rule stays tight to the label via the inner span's border. */
.rail-action--tertiary { width: auto; gap: 7px;
  background: transparent; border: 0; border-radius: 0; padding: 7px 2px 5px;
  min-height: 24px;
  color: #fff; font-weight: 500; text-decoration: none;
  border-bottom: 1px solid #fff; }
.rail-action--tertiary:hover { color: #fff; border-bottom-color: rgba(255,255,255,.6); }
/* Compact rail: the action sits on the trigger row, to the right of
   "Select a chapter", so it never hides behind the chapter scroller. */
@media (max-width: 1100px) {
  .doc-rail__actions { flex-direction: row; align-items: center; gap: 10px; margin: 0 0 0 14px; flex: none; }
  .rail-action__meta { display: none; }
}
@media (max-width: 560px) {
  /* No room for both on one line at phone widths — keep the label, drop
     the icon's breathing room rather than wrapping the row. */
  .doc-rail__actions { margin-left: 10px; }
  .rail-action--tertiary { font-size: 12.5px; }
}

/* ═══════════════════════════════════════════════════════════════════
   LEGIBILITY SCALE — 2026-09-16
   Stakeholder feedback: type too small in places, and too much on screen
   at once. Every reading size steps up 2–4px and picks up a touch more
   contrast; the long sections are split into more, shorter pages in
   index.html (see .doc-runhead below for the "continued" running head).
   Loaded after forma-webdoc.css, so same-specificity rules here win.
   ═══════════════════════════════════════════════════════════════════ */
.webdoc[data-paper="dark"] { --pg-fg-2: rgba(255, 255, 255, 0.86); --pg-fg-3: rgba(255, 255, 255, 0.62); }

/* Prose */
.doc-body { font-size: 18px; line-height: 1.65; max-width: 58ch; } /* ~72 chars/line in this face */
.doc-body p { margin-bottom: 18px; }
.doc-body.cols-2 { column-gap: 52px; }
.doc-lede { font-size: 18px; line-height: 1.65; max-width: 58ch; }
.doc-h2 { font-size: clamp(24px, 2.5vw, 32px); line-height: 1.16;
  /* Long headings break into two balanced lines instead of one long line
     (text-wrap: balance is already on .doc-h2; it just needed a measure). */
  max-width: 20em; }
.doc-kicker, .card__eyebrow, .ig-cap, .doc-keyline span { font-size: 15px; }
.m-caption { font-size: 16px; line-height: 1.55; }
.m-bullets { gap: 12px; }
.m-bullets li { font-size: 18px; line-height: 1.65; padding-left: 26px; }
.m-bullets li::before { top: 9px; }

/* Cards and lists */
.card { gap: 14px; padding: 28px; }
.card__title { font-size: 20px; }
.card__body { font-size: 18px; line-height: 1.65; max-width: 48ch; }
.execlist__title { font-size: 24px; }
.execlist { max-width: 964px; margin-inline: auto; }
@media (min-width: 901px) { .execlist__card { padding: 48px; } } /* roomier cards; list widened to match so the text measure is unchanged */ /* cards hug their text and sit centred under the heading — no dead space on the right (Jay 2026-09-21) */
.execlist__body { font-size: 18px; line-height: 1.65; max-width: none; margin-left: 76px; } /* runs the card width, indented past the numeral (46px + 30px gap) so it sits under the title */
.doc-steps li { padding: 28px 0; gap: 10px; }
.doc-steps .s-t { font-size: 20px; margin-bottom: 8px; }
.doc-steps .s-d { font-size: 18px; line-height: 1.65; }

/* Tables */
.ig-table { font-size: 16px; }
.ig-table th, .ig-table td { padding: 14px 16px; }
.ig-table thead th { font-size: 14px; }
.ig-table.is-scroll { min-width: 820px; }

/* Infographic labels (supersede the earlier data-label block above) */
.ig-foot { font-size: 16px; line-height: 1.55; color: var(--pg-fg-2); }
.ig-fig { padding: 28px 28px 30px; }
.ig-fig__n { font-size: 44px; }
.ig-fig__l { font-size: 16px; line-height: 1.5; margin-top: 14px; }
.ig-bar__lbl { font-size: 16px; line-height: 1.4; }
.ig-bar__val { font-size: 22px; }
.ig-bars.is-compact .ig-bar__lbl { font-size: 16px; }
.ig-ring__lbl { font-size: 16px; line-height: 1.45; width: 22ch; }
.ig-ring__num { font-size: 28px; }
.ig-stack__layer { padding: 16px 26px 16px 36px; gap: 4px; }
.ig-stack__n { font-size: 18px; }
.ig-stack__p { font-size: 16px; line-height: 1.5; }

/* Calculator */
.ig-calc__k { font-size: 15px; }
.ig-calc__k b { font-size: 17px; }
.ig-calc__rk { font-size: 16px; }
.ig-calc__rv { font-size: 28px; }
.ig-calc__row--total .ig-calc__rv { font-size: 34px; }

/* Page frame — desktop and laptop. A short page (a heading and two
   paragraphs) was a 62vh band with 8vh padding, which reads as a strip, not a
   page. Fill the viewport and open up the vertical padding so the content sits
   in proper top/bottom space. Hero, dividers and the exec card stack keep
   their own floors (their two-class selectors win on specificity). */
@media (min-width: 1101px) {
  .webdoc { --sec-pad-y: clamp(96px, 12vh, 160px); }
  .doc-section { min-height: 100vh; }
}

/* Rail + small print */
.navrow { font-size: 14px; padding: 9px 10px; }
.doc-rail__eyebrow { font-size: 11px; }
.doc-rail__foot { font-size: 12px; }
.doc-avatar__role { font-size: 15px; }

/* Running head for a page that continues the previous one: optional
   numeral chip + the section title, then a green "continued" tag. */
.doc-runhead { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.doc-runhead .card__icon.is-numeral { width: 34px; height: 34px; border-radius: 9px; font-size: 15px; }
.doc-runhead__t { font-family: var(--font-text); font-weight: 500; font-size: 18px; color: var(--pg-fg); }
.doc-runhead__c { font-family: var(--font-text); font-size: 15px; color: var(--pg-fg); }
.doc-runhead__c::before { content: "·"; margin-right: 12px; color: var(--pg-fg-4); }

@media (max-width: 760px) {
  .doc-body { font-size: 17px; }
  .doc-lede { font-size: 17px; }
  .card__body, .doc-steps .s-d, .m-bullets li, .execlist__body { font-size: 17px; }
  .execlist__body { margin-left: 0; } /* no room to indent on phones */
  .ig-fig__l { font-size: 15px; }
  .ig-table { font-size: 14px; }
  .ig-table th, .ig-table td { padding: 11px 12px; }
  .ig-fig__n { font-size: 38px; }
  .ig-ring__lbl { width: auto; }
}

/* Insight "Core Finding" titles: same measure rule as .doc-h2 so a long
   title breaks into two balanced lines instead of one full-width line. */
.insight-title { font-size: clamp(26px, 3vw, 40px); max-width: 18em; }

/* Essay 2 trust-requirement rings: three across, label beneath each ring,
   inside the single 66ch prose column (replaces a 2-col text split that
   left the intro stranded on the left and the rings on the right). */
.essay-rings { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 48px;
  /* wider than the 58ch prose measure so the three labels sit on two lines */
  width: 78ch; max-width: none; }
.essay-rings .ig-ring { align-items: flex-start; gap: 14px; }
.essay-rings .ig-ring__lbl { width: auto; }
@media (max-width: 720px) { .essay-rings { grid-template-columns: 1fr; width: auto; } }

/* Two-column prose: a paragraph never splits across the column break.
   A sentence continuing at the top of the next column reads as broken
   (Jay, 2026-09-16). Odd paragraph counts leave one column shorter, which
   is the lesser evil. */
.doc-body.cols-2 p { break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; }

/* Card glow + stroke, toned down document-wide (Jay, 2026-09-16: "too
   intense"). Corner glow at half the system alpha; accent cards on a
   quieter tint and a softer brand-coloured hairline. */
.fx-cornerglow::after { background: radial-gradient(circle, hsl(var(--glow-h, 150) 88% 62% / 0.09), transparent 70%); }
.card.is-accent { background: color-mix(in srgb, var(--pg-brand) 4%, transparent);
  border-color: color-mix(in srgb, var(--pg-brand) 18%, transparent); }


/* ═══════════════════════════════════════════════════════════════════
   PROSE + FIGURE PAIR — body copy in the left column at its normal
   measure, the figure beside it instead of full-width underneath.
   Stacks on narrow screens. Runhead above stays full width.
   ═══════════════════════════════════════════════════════════════════ */
.doc-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); /* even split — Jay: uneven looked odd */
  column-gap: clamp(40px, 5vw, 80px);
  align-items: start;
}
.doc-pair > .doc-body { max-width: none; }
.doc-pair > .ig-bars, .doc-pair > .card, .doc-pair__col > .ig-bars { margin-top: 30px; }
.doc-pair__col { min-width: 0; } /* right column holding a figure plus prose beneath it */
.doc-pair > .card { height: auto; } /* .card's height:100% resolves against the grid row (incl. its own margin) and adds a phantom bottom gap */ /* sits level with the first line of prose */
@media (max-width: 1100px) { /* below this each column drops under ~40ch, so stack */
  .doc-pair { grid-template-columns: 1fr; }
  .doc-pair > .doc-body { max-width: 58ch; }
  .doc-pair > .ig-bars, .doc-pair > .card, .doc-pair__col > .ig-bars { margin-top: 32px; }
}

/* Wide-figure variant: text 40 / figure 60, for a chart that needs the room
   (the seven confidence rings). Rings become a two-column list, ring beside
   its label, so there is no orphan slot. */
.doc-pair.is-figwide { grid-template-columns: 1fr 2fr; } /* text a third, figure two thirds */
.doc-pair__text > .doc-body { max-width: none; }
.ig-rings.is-list { display: grid; grid-template-columns: 1fr 1fr; gap: 48px 28px; align-items: start; margin-top: 6px; }
.ig-rings.is-list .ig-ringrow { display: contents; }
.ig-rings.is-list .ig-ring { flex-direction: row; align-items: center; gap: 16px; }
.ig-rings.is-list .ig-ring__wrap { width: 92px; height: 92px; flex: none; }
.ig-rings.is-list .ig-ring__num { font-size: 22px; }
.ig-rings.is-list .ig-ring__lbl { width: auto; font-size: 15px; }
@media (max-width: 1100px) { .doc-pair.is-figwide { grid-template-columns: 1fr; } .ig-rings.is-list { margin-top: 28px; } }
@media (max-width: 560px) { .ig-rings.is-list { grid-template-columns: 1fr; } }

/* Feature stat: one ring, shown large, sentence beneath — for a right column
   built around a single number (architecture pillar 1). */
.doc-pair__col > .ig-rings.is-feature { margin-top: 74px; align-items: flex-start; } /* level with the heading, not the numeral */
.ig-rings.is-feature .ig-ringrow { display: flex; flex-direction: row; align-items: center; gap: 24px; } /* ring beside its sentence (Jay, 2026-09-17) */
.ig-rings.is-feature .ig-ring__wrap { width: 148px; height: 148px; flex: none; }
.ig-rings.is-feature .ig-ring__num { font-size: 34px; }
.ig-rings.is-feature .ig-ring__lbl { width: auto; max-width: 34ch; font-size: 18px; line-height: 1.5; }
@media (max-width: 1100px) { .doc-pair__col > .ig-rings.is-feature { margin-top: 28px; } }

/* Stacked ring list: one ring per row, ring beside its label (pillar 2). */
.ig-rings.is-list.is-stack { grid-template-columns: 1fr; gap: 26px; margin-top: 30px; }
.ig-rings.is-list.is-stack .ig-ring__wrap { width: 84px; height: 84px; }
.ig-rings.is-list.is-stack .ig-ring__lbl { font-size: 16px; }
.doc-pair__col > .doc-keyline, .doc-pair__col > .m-bullets, .doc-pair__col > .doc-body { max-width: none; }

/* Stat-card grid inside a pair column: two across, level with the kicker. */
.doc-pair > .ig-figs, .doc-pair > .ig-figs:has(> .ig-fig:nth-child(5):last-child), .doc-pair__col > .ig-figs:has(> .ig-fig:nth-child(5):last-child) { grid-template-columns: 1fr 1fr; margin-top: 6px; } /* second selector out-ranks the global five-card rule */

/* Dense variant of the wide-figure pair (confidence rings page): text back to
   40%, body at the 16px data-label size, heading one step down, so three
   paragraphs and seven rings share one screen without the text towering. */
.doc-pair.is-figwide.is-dense { grid-template-columns: 9fr 11fr; } /* 45/55 — Jay: "a little wider" than 40 */
.doc-pair.is-dense .doc-h2 { font-size: 28px; }
.doc-pair.is-dense .doc-body { font-size: 16px; line-height: 1.6; }
.doc-pair.is-dense .ig-rings.is-list { gap: 40px 28px; margin-top: 10px; }
.doc-pair.is-dense .ig-rings.is-list .ig-ring__wrap { width: 88px; height: 88px; }

/* Three stat cards stacked in a pair column (Business impact risks page). */
.doc-pair > .ig-figs.is-stack { display: grid; grid-template-columns: 1fr; gap: 14px; margin-top: 30px; } /* .ig-figs is a flex row by default */
.doc-pair > .ig-figs.is-stack .ig-fig { min-height: 0; }

.doc-pair__col > .doc-kicker { margin-top: 10px; } /* level with the chapter title's cap height */
.doc-pair__text > .doc-lede { max-width: none; }

/* Full-width accent card with its copy in two columns (Insight 2 implication). */
.card.is-wide { max-width: none; }
.card.is-wide .card__body { max-width: none; column-count: 2; column-gap: 44px; }
@media (max-width: 760px) { .card.is-wide .card__body { column-count: 1; } }

/* Prose above a full-width two-column card: match the card's left column so
   the paragraph's right edge sits on the column break. (50% minus half the
   card's 44px column gap; the card's 28px padding inset is absorbed.) */
.doc-body.is-halfcol { max-width: calc(50% - 22px); }
@media (max-width: 760px) { .doc-body.is-halfcol { max-width: none; } }

/* Lede in a narrow pair column (market-reality opener): 16px so the third-
   width column reads comfortably. */
.doc-lede.is-sm { font-size: 16px; line-height: 1.6; }

/* Stat-page opener with a longer lede (market reality): text 40% not a third. */
.doc-pair.is-figwide.is-text40 { grid-template-columns: 2fr 3fr; }

/* ═══════════════════════════════════════════════════════════════════
   RESPONSIVE BACKSTOP — must stay last in this file
   ───────────────────────────────────────────────────────────────────
   Dru's review (2026-09-22) found "Emerging market reality" cropped at
   375px: `.is-text40` and `.is-dense` set grid-template-columns AFTER
   the `max-width:1100px` stacking rule higher up, so at equal
   specificity the later rule won and the pair stayed two-column at
   every width — 514px of content inside a 375px section, clipped by
   `overflow: clip`.

   Any NEW .doc-pair modifier that sets grid-template-columns must go
   ABOVE this block, or be added to the selector list here.
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width: 1100px) {
  .doc-pair,
  .doc-pair.is-figwide,
  .doc-pair.is-figwide.is-dense,
  .doc-pair.is-figwide.is-text40 { grid-template-columns: 1fr; }
  /* the dense variant shrank its type to survive a narrow column —
     stacked, it has the full width back, so restore the reading size */
  .doc-pair.is-dense .doc-body { font-size: 18px; line-height: 1.65; }
  .doc-pair.is-dense .doc-h2 { font-size: 32px; }
}


/* ═══════════════════════════════════════════════════════════════════
   SCROLLABLE TABLE — make the overflow discoverable
   ───────────────────────────────────────────────────────────────────
   Dru's review (2026-09-22): the two wide tables sit in plain
   `overflow-x: auto` wrappers with an 820px min-width. At intermediate
   widths the visible columns can end cleanly at the edge, so there was
   no cue that more data existed off screen, and no keyboard affordance.

   web-doc.js adds .is-scrollable only when scrollWidth > clientWidth, and
   makes the wrapper focusable in that case only — a focusable region that
   cannot scroll is just a dead tab stop. .is-atstart / .is-atend track the
   scroll position so a fade appears only on the side with content beyond.
   ═══════════════════════════════════════════════════════════════════ */
/* The outer .tablescroll is a static positioning context for the fades;
   .tablescroll__view is the element that actually scrolls. Fades on the
   outer box therefore stay still while the table moves underneath. */
.tablescroll { position: relative; }
.tablescroll__view { overflow-x: auto; }
.tablescroll__hint { display: none; }
.tablescroll.is-scrollable > .tablescroll__hint {
  /* Sits to the RIGHT (Jay, 2026-09-22): the cue belongs at the edge where
     the content is actually cut off, not at the start of the row. */
  display: flex; align-items: center; justify-content: flex-end; gap: 7px;
  font-family: var(--font-ui); font-size: 13px; color: var(--pg-fg-3);
  margin-bottom: 10px;
}
.tablescroll.is-scrollable > .tablescroll__hint svg { width: 15px; height: 15px; flex: none; }

/* "Scroll" or "Swipe" by input device, not by screen size — a touch laptop
   swipes at 1400px and a mouse user scrolls at 500px, so width is the wrong
   signal. `any-pointer: coarse` is true when ANY available pointer is a
   finger, which is the case where "swipe" is the natural word. */
@media (any-pointer: coarse) {
  /* Swap the whole phrase, not just the verb: collapsing one word with
     font-size:0 leaves its trailing space behind ("Swipe  horizontally"). */
  .tablescroll__verb { font-size: 0; }
  .tablescroll__verb::after { content: "Swipe horizontally to see more"; font-size: 13px; }
}
/* The fade must cover the SCROLLING VIEW only. Anchored to the wrapper's
   full height it also sat over the hint above, clipping "…see more".
   --tsHintH is set by web-doc.js to the hint's height + its margin. */
.tablescroll::before,
.tablescroll::after {
  content: ""; position: absolute; top: var(--tsHintH, 0px); bottom: 0; width: 48px;
  z-index: 2; pointer-events: none; opacity: 0;
  transition: opacity .18s var(--ease-out);
}
.tablescroll::before { left: 0;  background: linear-gradient(90deg,  #070807, transparent); }
.tablescroll::after  { right: 0; background: linear-gradient(270deg, #070807, transparent); }
/* Shown only where content actually continues past that edge. */
.tablescroll.is-scrollable:not(.is-atstart)::before { opacity: 1; }
.tablescroll.is-scrollable:not(.is-atend)::after { opacity: 1; }

.tablescroll__view:focus-visible { border-radius: 6px; }

/* Forced colours strips gradients, so the text hint is the real
   affordance — the fade must never be the only cue. */
@media (forced-colors: active) {
  .tablescroll::before, .tablescroll::after { display: none; }
}

/* Publication reference in the document body (About this research). Set a
   step down from body copy but still at a full reading contrast — it is
   citable metadata, not fine print. */
.doc-docref {
  margin-top: 26px; padding-top: 18px;
  border-top: 1px solid var(--pg-rule);
  font-family: var(--font-ui); font-size: 15px; color: var(--pg-fg-2);
}


/* ── 320px: the narrowest supported width ────────────────────────────
   Two failures showed up only here (Dru's review, 2026-09-22, which asked
   for a 320px test). Both are min-width floors that stop being affordable
   once the viewport drops below ~340px. */
@media (max-width: 360px) {
  /* .ig-fig carries min-width:150px, so two cards plus the 16px gap need
     316px of content box — more than a 320px viewport has after padding.
     One card per row below 360px. */
  .ig-figs { flex-direction: column; }
  .ig-figs .ig-fig { min-width: 0; width: 100%; }
  .doc-pair > .ig-figs,
  .doc-pair__col > .ig-figs,
  .doc-pair > .ig-figs:has(> .ig-fig:nth-child(5):last-child),
  .doc-pair__col > .ig-figs:has(> .ig-fig:nth-child(5):last-child) { grid-template-columns: 1fr; }

  /* The cover's date/sponsor line holds two nowrap spans on one row; at
     320px they cannot both fit, so let the group wrap to the left instead
     of pushing past the edge. */
  .cover-glass__top { flex-wrap: wrap; gap: 14px; }
  .cover-glass__top .m-caption { justify-content: flex-start; }
}


/* ═══════════════════════════════════════════════════════════════════
   Running heads removed (Jay, 2026-09-22, during QA of Dru's review)
   ───────────────────────────────────────────────────────────────────
   The "<Chapter> · continued" labels are gone from every page. Several
   elements that used to sit BELOW one still carry the inline
   `margin-top` that spaced them off it — now the first thing on the
   page, that margin just pushes the content down inside a vertically
   centred section. Zero it for a first child only; the same class
   keeps its margin wherever it follows something.
   ═══════════════════════════════════════════════════════════════════ */
.doc-well > :first-child[style*="margin-top"] { margin-top: 0 !important; }
