/* ============================================================
   EchoGlobal — site stylesheet.

   Every page on the shared shell loads this, block-rendered and hand-built
   alike, on top of the design-system bundle. Tokens live in the bundle, so
   a token change reaches the whole site from one place. This file imports
   the shell first, then adds the page-level classes the pages share, so a
   new page stays short and consistent.
   ============================================================ */
@import url("site-shell.css");

* { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: calc(var(--header-h) + 18px); }

body {
  margin: 0;
  font-family: var(--font-sans);
  color: var(--ink);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: var(--ink); text-decoration: none; }
img { max-width: 100%; }

/* ============================================================
   Layout
   ============================================================ */
.wrap { max-width: 1240px; margin: 0 auto; padding: 0 clamp(20px, 3.5vw, 40px); }
.wrap-md { max-width: 1000px; margin: 0 auto; padding: 0 clamp(20px, 3.5vw, 40px); }
/* 720px is the reading measure (plan/21 §3). */
.wrap-sm { max-width: 720px; margin: 0 auto; padding: 0 clamp(20px, 3.5vw, 40px); }

/* The band rhythm, opened up in slice 1 of plan/21 (2026-09-01): .sec was
   56 to 108px and .sec-sm 40 to 72. Every banded block goes through shell(),
   so this one pair of numbers is most of the difference between a page that
   reads as a template and one that gives each idea its own screen. */
.sec { padding: clamp(80px, 10vw, 160px) 0; }
.sec-sm { padding: clamp(56px, 7vw, 108px) 0; }
.sec-xs { padding: clamp(26px, 3.4vw, 46px) 0; }

.bg-white { background: var(--white); }
.bg-mist  { background: var(--mist); }
.bg-ice   { background: var(--grad-ice-fade); }

.grid { display: grid; gap: clamp(16px, 2vw, 26px); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
.split  { display: grid; gap: clamp(40px, 6vw, 96px); grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); align-items: center; }
.stack  { display: flex; flex-direction: column; }
.spacer { flex: 1 1 auto; }

/* ============================================================
   Type
   ============================================================ */
/* Restyled, not removed (plan/21 §3): a plain 15px sentence-case line. The
   11px tracked capitals were the micro-label half of the shape CLAUDE.md bans,
   and sectionHead() put one on nearly every section of every page. The words
   stay exactly as the rows hold them; only the transform is gone. --slate and
   not --steel on purpose: --steel is the 3.24:1 known debt on the ice grounds,
   and a new font size would key a new contrast failure against it. */
.eyebrow {
  font-size: 15px; font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--slate); margin: 0;
}
.eyebrow-brand { color: var(--wordmark-blue); }

/* The scale (plan/21 §3), desktop at 1280 / phone at 390. The weights are
   real: the bundle asks Google Fonts for Inter as a variable range, so 750,
   650 and 300 render as themselves rather than snapping to 800, 700 and 400.
   Display is the wordmark's own 750/300 pairing at headline size. */
.display {
  margin: 0; font-size: clamp(44px, 7.8vw, 100px); line-height: .98;
  letter-spacing: -0.035em; font-weight: 750; text-wrap: balance;
}
.display .light, .display-light { font-weight: 300; }
h1, .h1 {
  margin: 0; font-size: clamp(40px, 5.6vw, 72px); line-height: 1.02;
  letter-spacing: -0.032em; font-weight: 750; text-wrap: balance;
}
h2, .h2 {
  margin: 0; font-size: clamp(30px, 3.9vw, 50px); line-height: 1.08;
  letter-spacing: -0.028em; font-weight: 700; text-wrap: balance;
}
h3, .h3 {
  margin: 0; font-size: clamp(22px, 2.2vw, 28px); line-height: 1.2;
  letter-spacing: -0.02em; font-weight: 650; text-wrap: balance;
}
h4, .h4 { margin: 0; font-size: 19px; font-weight: 750; letter-spacing: -0.015em; line-height: 1.3; }

.lead { margin: 18px 0 0; font-size: clamp(19px, 1.7vw, 22px); line-height: 1.55; color: var(--slate); text-wrap: pretty; }
.body { margin: 14px 0 0; font-size: 18px; line-height: 1.65; color: var(--slate); }
.body-sm { margin: 10px 0 0; font-size: 16px; line-height: 1.6; color: var(--slate); }
/* A card's small print — a caveat under the body, set a step down and in italics. */
.card-note { margin: 10px 0 0; font-size: 14px; line-height: 1.55; font-style: italic; color: var(--slate); }
/* Bold inside running text reads as ink, the way the hand-written pages inline it. */
.body b, .lead b { color: var(--ink); }
.meta { font-size: 13.5px; line-height: 1.6; color: var(--steel); }
.mono { font-family: var(--font-mono); }
.hl { color: var(--wordmark-blue); }
.center { text-align: center; }
.center .lead, .center .body { margin-left: auto; margin-right: auto; }
.limit { max-width: 640px; }
.limit-sm { max-width: 520px; }
.center .limit, .center .limit-sm { margin-left: auto; margin-right: auto; }

ul.ticks { margin: 16px 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 11px; }
ul.ticks li { position: relative; padding-left: 28px; font-size: 15.5px; line-height: 1.6; color: var(--slate); }
ul.ticks li::before {
  content: ""; position: absolute; left: 0; top: 3px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--ice) var(--icon-tick) center/12px no-repeat;
}
ul.plain { margin: 14px 0 0; padding-left: 19px; font-size: 15px; line-height: 1.75; color: var(--slate); }

/* ============================================================
   Surfaces
   ============================================================ */
.card {
  background: var(--white); border-radius: var(--radius-2xl);
  box-shadow: var(--shadow-card); padding: clamp(22px, 2.4vw, 30px);
}
.card-flat { background: var(--white); border: 1px solid var(--cloud); border-radius: var(--radius-2xl); padding: clamp(26px, 3vw, 40px); }
.card-quiet { background: var(--panel); border-radius: var(--radius-xl); padding: clamp(18px, 2vw, 26px); }
.card-featured { box-shadow: var(--shadow-brand); }
.card-link { display: block; transition: transform var(--dur-base) var(--ease-standard), box-shadow var(--dur-base) var(--ease-standard); }
.card-link:hover { transform: translateY(-3px); box-shadow: var(--shadow-float); color: var(--ink); }

.icon-tile {
  flex: 0 0 auto; width: 44px; height: 44px; border-radius: var(--radius-lg);
  background: var(--ice); color: var(--action-ink); display: grid; place-items: center;
}
.icon-tile-sm { width: 34px; height: 34px; border-radius: var(--radius-md); }
.icon-tile-rose { background: var(--blush); color: var(--bad-ink); }

.chip {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700;
  letter-spacing: .02em; color: var(--slate); background: var(--panel);
  border-radius: var(--radius-pill); padding: 5px 11px;
}
.chip-brand { background: var(--ice); color: var(--action-ink); }
.chip-live { background: var(--success-tint); color: var(--good-ink); }
.chip-mono { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .02em; }

.rule { height: 1px; background: var(--cloud); border: 0; margin: 22px 0; }

/* The "to collect" wrapper. It was amber, dashed and labelled in tracked
   capitals: a build-time affordance leaking to readers, wearing the banned
   micro-label. Until slice 2 of plan/21 renders nothing to the public here, it
   is a quiet hairline card with a plain label. See CLAUDE.md: never invent
   proof. */
.slot {
  border: 1px solid var(--cloud); border-radius: var(--radius-xl);
  background: var(--white); padding: clamp(18px, 2vw, 26px); color: var(--slate);
}
.slot-label { font-size: 15px; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--ink); }
.slot p { margin: 10px 0 0; font-size: 15px; line-height: 1.65; }
.slot p + p { margin-top: 8px; }

/* ============================================================
   Footer
   ============================================================ */
.site-footer { background: var(--mist); border-top: 1px solid var(--cloud); padding: clamp(48px, 6vw, 80px) 0 28px; }
.footer-top { display: flex; flex-wrap: wrap; gap: clamp(28px, 3.5vw, 56px); }
.footer-brand { flex: 1 1 280px; min-width: 0; max-width: 360px; }
.footer-cols { flex: 2 1 520px; min-width: 0; display: grid; gap: clamp(20px, 2.5vw, 36px); grid-template-columns: repeat(auto-fit, minmax(min(100%, 140px), 1fr)); }
.footer-cols h5 { margin: 0 0 14px; font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--steel); }
.footer-cols div a, .footer-links a { display: block; font-size: 14.5px; color: var(--slate); padding: 5px 0; }
.footer-cols div a:hover { color: var(--action-ink); }
.footer-bottom {
  margin-top: clamp(30px, 4vw, 48px); padding-top: 20px; border-top: 1px solid var(--cloud);
  display: flex; flex-wrap: wrap; gap: 14px; align-items: center; justify-content: space-between;
  font-size: 13px; color: var(--steel);
}
.footer-bottom a { color: var(--steel); }
.live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--success); animation: echoLiveDot 2.6s ease-in-out infinite; display: inline-block; }
.lang-select {
  margin-top: 18px; max-width: 210px; width: 100%; font: inherit; font-size: 14.5px;
  padding: 11px 13px; border-radius: var(--radius-sm); border: 1px solid var(--cloud);
  background: var(--white); color: var(--ink);
}

/* ============================================================
   Page furniture
   ============================================================ */
/* The page top sits on the page ground since slice 1 of plan/21 (2026-09-01).
   It carried --grad-ice-fade before that, and thirteen pages opened on the
   same pale wash under the same three lines. A header that is simply the page
   with larger type is the first thing that stops every page looking like the
   same page. */
.page-hero { background: var(--white); padding: clamp(48px, 6vw, 96px) 0 clamp(40px, 5vw, 80px); }

/* A header may take a ground of its own, from settings.background on the hero
   row. This is NOT the wash slice 1 removed: that was every page opening on
   --grad-ice-fade, and the complaint was sameness across thirteen headers. One
   page opting in is the opposite move, and /product/graphql is the page that
   asked for it -- its header carries a dark code figure and ran straight into
   a white card grid with nothing between them.

   Needs the doubled class to beat .page-hero's own background above, which is
   a single class and declared later than .bg-ice / .bg-mist. */
.page-hero.bg-ice  { background: var(--grad-ice-fade); }
.page-hero.bg-mist { background: var(--mist); }

/* --steel is the one text colour on the site that does NOT clear AA on this
   gradient, and tools/contrast.mjs cannot catch it: a gradient is not a
   computed background colour, so the harness measures the ground behind it and
   passes. Measured analytically against the 100% stop #D9E8F8, which is the
   darkest ground any text on this band can sit on: --steel #606D85 is 4.19:1
   at 13.5px, under the 4.5 minimum. The bundle's own note says what to use
   instead -- "Use --slate for tertiary text on those" -- and --slate clears it
   at 4.59:1. Everything else in the header already clears: --ink 10.37,
   --action-ink 4.71, --slate 4.59. Dark is comfortable throughout (worst 4.73).
   Re-measure the same way before putting another ground on a header. */
.page-hero.bg-ice .breadcrumbs,
.page-hero.bg-ice .breadcrumbs a { color: var(--slate); }

/* The hero illustration is switched off here, by CSS, rather than in the
   renderer: slice 1 changes no markup and no row, so the renderer still emits
   the figure for settings.art (about, customers, pricing, security) and
   art_behind (the product heroes), and this is what keeps it off the page.
   Slice 2 makes the renderer ignore settings.art and this block goes with it.
   The layout hooks the art needed (a flex-centred minimum height, a copy
   column capped clear of the picture, a band reserved under the copy on a
   phone) are neutralised with it, or the header would keep a picture-shaped
   hole where the picture was. The masks, the object positions and the reason
   the beside treatment was capped near 16:9 are in git history at 4046653. */
.hero-art-shot { display: none; }
.page-hero.has-art { position: relative; min-height: 0; display: block; }
.page-hero.has-art > .wrap, .page-hero.has-art > .wrap-md { position: relative; z-index: 1; width: 100%; }
.page-hero.has-art .hero-copy { max-width: 760px; }
.page-hero.art-behind { position: relative; }
.page-hero.art-behind > .wrap, .page-hero.art-behind > .wrap-md { position: relative; z-index: 1; }
/* /pricing's header row carries `center: true`, which the has-art layout never
   honoured for the copy (the copy is a left-aligned block) but the renderer
   still writes as an inline justify-content:center on the CTA row. Inside a
   560px column that put the button 27px off the margin; inside the 760px
   column above it is 127px, a button visibly off the grid under a left-aligned
   headline. An inline style needs !important to be overruled, and this is the
   one place on the site it is used: the setting is in a row, and this slice
   changes no rows. */
.page-hero.has-art .cta-row { justify-content: flex-start !important; }

/* The header already carries its own air at the bottom; a white band that
   follows it on the same ground does not need the full .sec top padding on
   top of that, or there is a 200px hole between the lead and the first
   heading at 1280. Only white-on-white: a mist band starting under the header
   is a new ground and keeps the rhythm. */
.page-hero + .sec.bg-white { padding-top: clamp(36px, 5vw, 80px); }
/* ...but only while they share one. A header on its own ground is a band in
   its own right, so the white section under it takes the full .sec rhythm
   again rather than the reduced one, or the join reads as a hairline. */
.page-hero.bg-ice + .sec.bg-white,
.page-hero.bg-mist + .sec.bg-white { padding-top: clamp(80px, 10vw, 160px); }
.page-hero + .sec-sm.bg-white { padding-top: clamp(24px, 3.5vw, 56px); }

.breadcrumbs { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 13.5px; color: var(--steel); margin-bottom: 18px; }
.breadcrumbs a { color: var(--steel); }
.breadcrumbs a:hover { color: var(--action-ink); }
.breadcrumbs span { opacity: .5; }

.section-head { max-width: 820px; }
.center .section-head, .section-head.center { margin-left: auto; margin-right: auto; }
.section-head h2 { margin-top: 14px; }

.feature-row { display: grid; gap: clamp(28px, 4vw, 62px); grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr)); align-items: center; padding: clamp(34px, 4.5vw, 60px) 0; }
.feature-row + .feature-row { border-top: 1px solid var(--cloud); }
.feature-row.flip > *:first-child { order: 2; }
@media (max-width: 820px) { .feature-row.flip > *:first-child { order: 0; } }

/* ============================================================
   Product moments (composed UI, never stock photography)
   ============================================================ */
.ui-frame {
  background: var(--white); border-radius: var(--radius-2xl);
  box-shadow: var(--shadow-float); padding: clamp(12px, 1.4vw, 18px);
}
.ui-bar { display: flex; align-items: center; gap: 8px; padding: 4px 6px 12px; border-bottom: 1px solid var(--cloud); margin-bottom: 12px; }
.ui-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--cloud); display: block; }
.ui-bar b { font-size: 12.5px; font-weight: 700; color: var(--steel); letter-spacing: .02em; margin-left: 6px; }

.conv {
  display: flex; gap: 12px; align-items: flex-start; background: var(--white);
  border-radius: 12px; box-shadow: var(--shadow-sm); padding: 12px 14px; border: 1px solid var(--cloud);
}
.conv + .conv { margin-top: 10px; }
.conv-av { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%; background: var(--ice); color: var(--action-ink); display: grid; place-items: center; font-size: 12px; font-weight: 750; }
.conv-main { min-width: 0; flex: 1 1 auto; }
.conv-name { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13.5px; font-weight: 700; }
.conv-tag { font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--slate); background: var(--panel); border-radius: 5px; padding: 2px 6px; }
.conv-text { display: block; margin-top: 4px; font-size: 13px; color: var(--slate); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conv-state { flex: 0 0 auto; font-size: 11.5px; font-weight: 650; white-space: nowrap; margin-top: 2px; }
.conv-state.ok { color: var(--good-ink); }
.conv-state.wait { color: var(--warning-ink); }
.conv-state.live { color: var(--action-ink); }

.bubble { max-width: 82%; padding: 11px 14px; border-radius: 16px; font-size: 14px; line-height: 1.5; }
.bubble-in { background: var(--panel); color: var(--ink); border-bottom-left-radius: 5px; }
.bubble-out { background: var(--grad-action); color: var(--on-action); border-bottom-right-radius: 5px; margin-left: auto; }

/* Live mission-control panel — the light treatment; the dark band was rejected */
.statband { background: var(--white); border: 1px solid var(--cloud); border-radius: var(--radius-2xl); padding: clamp(20px, 2.4vw, 30px); }
/* A plain sentence over the figures, not tracked capitals (plan/21 §3). The
   dot stays: it is the house device for state. */
.statband-head { display: flex; align-items: center; gap: 9px; font-size: 16px; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--slate); }
.stat-grid { display: grid; gap: clamp(14px, 2vw, 26px); grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); margin-top: 22px; }
/* Platform totals: weight 750 with tabular figures (plan/21 §3), in the text
   face rather than mono, so the numbers read as the site's own type. */
.stat-num { font-size: clamp(30px, 3.4vw, 44px); font-weight: 750; letter-spacing: -0.03em; color: var(--ink); font-variant-numeric: tabular-nums; }
.stat-label { margin-top: 6px; font-size: 13.5px; color: var(--slate); }
.stat-spark { margin-top: 10px; display: block; width: 100%; height: 22px; }

/* ============================================================
   Provider marks

   Real trademarks, copied from the platform's own integration assets.
   NEVER recolour, tint or filter one. site.js applies brightness(0) to the
   ministry logo wall to unify it — that treatment is for logos we have
   permission to restyle and must not be reused here.
   ============================================================ */
.provider-wall {
  display: grid; gap: clamp(10px, 1.2vw, 14px); margin-top: clamp(22px, 2.6vw, 32px);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 236px), 1fr));
}
.provider-tile {
  display: flex; gap: 13px; align-items: flex-start; min-width: 0;
  background: var(--white); border: 1px solid var(--cloud);
  border-radius: var(--radius-xl); padding: 15px 16px;
}
.provider-mark { flex: 0 0 auto; width: 34px; height: 34px; display: grid; place-items: center; }
.provider-mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
/* Our own glyph, for the channels that are not somebody's trademark —
   phone, email, web chat. */
.provider-mark.is-glyph, .provider-strip .is-glyph {
  background: var(--ice); color: var(--action-ink); border-radius: var(--radius-md);
  display: grid; place-items: center;
}
/* Neutral lettermark, used only where the official asset is missing. It must
   never be mistaken for the real thing, so it carries no brand colour. */
.provider-mark.is-letter, .provider-strip .is-letter {
  background: var(--panel); color: var(--slate); border-radius: var(--radius-md);
  display: grid; place-items: center; font-weight: 800; letter-spacing: -0.02em;
}
.provider-mark.is-letter { font-size: 14px; }
.provider-body { min-width: 0; }
.provider-name { font-size: 14.5px; font-weight: 700; color: var(--ink); line-height: 1.3; }
.provider-note { margin: 4px 0 0; font-size: 13px; line-height: 1.5; color: var(--slate); }

.provider-strip { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 14px; }
.provider-strip img { width: 24px; height: 24px; object-fit: contain; display: block; }
.provider-strip .is-letter, .provider-strip .is-glyph {
  width: 24px; height: 24px; font-size: 11px; border-radius: var(--radius-sm);
}
.provider-legal { margin-top: clamp(16px, 2vw, 22px); font-size: 12.5px; line-height: 1.65; color: var(--slate); }

/* A conversation avatar that is a channel mark rather than initials. */
.conv-av-logo { background: var(--white); border: 1px solid var(--cloud); padding: 5px; }
.conv-av-logo img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* The reply window, stated as a pill so it reads as a fact and not a claim. */
.window-pill {
  display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-mono);
  font-size: 12px; font-weight: 700; color: var(--action-ink); background: var(--ice);
  border-radius: var(--radius-pill); padding: 4px 10px; white-space: nowrap;
}
.window-pill.is-open { color: var(--good-ink); background: var(--success-tint); }
.window-pill.is-unknown { color: var(--warning-ink); background: var(--warning-tint); }

/* ============================================================
   Screenshot slots

   The reusable "a real platform capture goes here" component. Holds the exact
   aspect ratio the capture will occupy, so dropping the image in later shifts
   nothing. .shot-frame mimics browser chrome, which is what makes a reader
   able to tell a capture from decoration at a glance.
   ============================================================ */
.shot { margin: clamp(18px, 2.2vw, 26px) 0 0; }
.shot-frame {
  border: 1px solid var(--cloud); border-radius: var(--radius-xl); overflow: hidden;
  background: var(--white); box-shadow: var(--shadow-card);
}
.shot-chrome { display: flex; align-items: center; gap: 7px; padding: 10px 13px; background: var(--panel); border-bottom: 1px solid var(--cloud); }
.shot-chrome i { width: 9px; height: 9px; border-radius: 50%; background: var(--cloud); display: block; }
.shot-chrome b { font-size: 12px; font-weight: 650; color: var(--slate); margin-left: 6px; font-family: var(--font-mono); }
.shot-plate {
  aspect-ratio: 16 / 10; display: grid; place-items: center; padding: clamp(18px, 2.4vw, 28px);
  background: repeating-linear-gradient(135deg, var(--mist) 0 10px, var(--white) 10px 20px);
}
.shot-plate img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shot-empty { text-align: center; max-width: 420px; }
.shot-empty .shot-icon { color: var(--steel); }
.shot-empty b { display: block; margin-top: 10px; font-size: 14.5px; font-weight: 700; color: var(--ink); }
.shot-empty p { margin: 6px 0 0; font-size: 13.5px; line-height: 1.6; color: var(--slate); }
.shot-cap { margin: 10px 2px 0; font-size: 13px; line-height: 1.6; color: var(--slate); }

/* ============================================================
   The white paper, which is a Claude Design <doc-page> export

   doc-page renders a fixed letter-size column: 7.5in of content inside an
   840px sheet. That is 450px wider than a 390px phone, and it cannot be
   reflowed — the document is paginated, so every page break, full-bleed
   image and pull-quote is positioned against that width.

   So it is fitted to the viewport with `zoom` rather than reflowed. zoom
   scales layout, not just paint, so the page height stays correct and the
   document does not leave a blank column below it the way transform:scale
   would. Below tablet width the type ends up small and the reader pinches
   in — the same thing everyone already does with a PDF on a phone. A
   properly reflowed mobile reading view is logged as an open item in
   plan/README.md rather than faked here.

   Nothing here touches the exported markup. Wrapping <x-import> in a div
   broke the export's own renderer and silently swallowed the site footer,
   so the whole fix lives page-side and survives a re-export.

   The steps are fixed rather than fluid because `zoom` takes a number or a
   percentage, and CSS cannot divide a length by a length — calc((100vw -
   20px) / 840) evaluates to a length, so the declaration is dropped and the
   document overflows exactly as before. Each step keeps 840px inside the
   viewport with a little air.
   ============================================================ */
doc-page { display: block; }
@media (max-width: 856px) { doc-page { zoom: 0.98 } }
@media (max-width: 800px) { doc-page { zoom: 0.92 } }
@media (max-width: 740px) { doc-page { zoom: 0.85 } }
@media (max-width: 680px) { doc-page { zoom: 0.78 } }
@media (max-width: 620px) { doc-page { zoom: 0.71 } }
@media (max-width: 560px) { doc-page { zoom: 0.64 } }
@media (max-width: 500px) { doc-page { zoom: 0.57 } }
@media (max-width: 440px) { doc-page { zoom: 0.50 } }
@media (max-width: 400px) { doc-page { zoom: 0.45 } }
@media (max-width: 360px) { doc-page { zoom: 0.40 } }

/* ============================================================
   EchoAnalyst figures

   Every figure here is CSS and SVG — no image of a chart, because an image
   of a chart cannot be read by a screen reader, cannot reflow at 390px and
   goes stale the moment the product changes.

   Two rules hold across all of them:
   1. NO NUMBERS. The funnel, the movement scale, the rubric and the tier
      ladder ship with shape only. A plausible-looking number in a diagram is
      an invented statistic even when nobody meant it as one. The two
      exceptions are the published <0.1% and 100% in the review-gap figure.
   2. Body text uses --slate (5.72:1 on white), never --steel (3.26:1, which
      fails WCAG AA and is a pre-existing site-wide problem logged in
      plan/README.md rather than patched per-page).
   ============================================================ */
.fig { margin: clamp(24px, 3vw, 38px) 0 0; }
.fig figcaption {
  margin-top: 14px; font-size: 13.5px; line-height: 1.65; color: var(--slate);
  max-width: 68ch; border-inline-start: 3px solid var(--ice); padding-inline-start: 14px;
}
.fig figcaption b { color: var(--ink); font-weight: 700; }

/* ---- The review gap: <0.1% against 100% -------------------------------- */
.gapbar { display: flex; flex-direction: column; gap: clamp(18px, 2.2vw, 26px); }
.gapbar-row { display: grid; gap: 8px; }
.gapbar-head { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: baseline; justify-content: space-between; }
.gapbar-name { font-size: 15.5px; font-weight: 750; color: var(--ink); }
.gapbar-val { font-family: var(--font-mono); font-size: clamp(22px, 3vw, 32px); font-weight: 700; letter-spacing: -0.02em; color: var(--slate); }
.gapbar-row.is-now .gapbar-val { color: var(--warning-ink); }
.gapbar-row.is-echo .gapbar-val { color: var(--action-ink); }
.gapbar-track { height: 14px; border-radius: var(--radius-pill); background: var(--panel); overflow: hidden; }
/* The filled width is the CSS default so the figure is correct with no
   scripting and under reduced motion; the reveal state animates *from* zero. */
.gapbar-fill { height: 100%; border-radius: var(--radius-pill); width: var(--w, 100%); transition: width .9s var(--ease-standard); }
.has-reveal .reveal:not(.in) .gapbar-fill { width: 0; }
.gapbar-row.is-now .gapbar-fill { background: var(--warning); }
.gapbar-row.is-echo .gapbar-fill { background: var(--grad-action); }
.gapbar-note { margin: 0; font-size: 14px; line-height: 1.6; color: var(--slate); }

/* ---- Does / does not --------------------------------------------------- */
.contrast { display: grid; gap: clamp(14px, 2vw, 22px); grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); }
.contrast-col { border-radius: var(--radius-xl); padding: clamp(18px, 2.2vw, 26px); border: 1px solid var(--cloud); background: var(--white); }
.contrast-col.is-does { background: var(--ice); border-color: transparent; }
.contrast-h { font-size: 11px; font-weight: 800; letter-spacing: .13em; text-transform: uppercase; color: var(--slate); margin: 0 0 14px; }
ul.deny { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 11px; }
ul.deny li { position: relative; padding-inline-start: 28px; font-size: 15px; line-height: 1.6; color: var(--slate); }
ul.deny li::before {
  content: ""; position: absolute; inset-inline-start: 0; top: 3px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--blush) var(--icon-deny) center/11px no-repeat;
}
.commitment {
  margin-top: clamp(20px, 2.4vw, 28px); background: var(--band-deep); color: var(--on-action);
  border-radius: var(--radius-xl); padding: clamp(20px, 2.6vw, 30px);
}
.commitment .contrast-h { color: rgba(255,255,255,.7); }
.commitment p { margin: 0; font-size: clamp(16px, 1.5vw, 19px); line-height: 1.6; font-weight: 650; }

/* ---- Figure 1, the flow ------------------------------------------------ */
.flow { display: grid; gap: clamp(12px, 1.6vw, 18px); grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); align-items: stretch; }
.flow-main { display: grid; gap: 10px; }
.flow-step { background: var(--white); border: 1px solid var(--cloud); border-radius: var(--radius-lg); padding: 14px 16px; position: relative; }
.flow-step + .flow-step { margin-top: 18px; }
/* The connector is drawn on the gap between steps, so it never adds width. */
.flow-step + .flow-step::before {
  content: ""; position: absolute; inset-inline-start: 26px; top: -19px; height: 18px; width: 2px; background: var(--cloud);
}
.flow-num { font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--action-ink); }
.flow-title { margin: 6px 0 0; font-size: 15.5px; font-weight: 750; color: var(--ink); }
.flow-what { margin: 5px 0 0; font-size: 14px; line-height: 1.55; color: var(--slate); }
.flow-branch { background: var(--warning-tint); border: 1px dashed var(--warning); border-radius: var(--radius-lg); padding: 16px 18px; align-self: start; }
.flow-branch .flow-num { color: var(--warning-ink); }
.flow-loop { margin-top: 12px; border: 1px dashed var(--cloud); border-radius: var(--radius-lg); padding: 14px 16px; background: var(--mist); }

/* ---- The rubric -------------------------------------------------------- */
.rubric-grid { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); }
.rubric-cell { background: var(--white); border: 1px solid var(--cloud); border-radius: var(--radius-lg); padding: 14px; }
.rubric-cell.is-situational { background: var(--mist); border-style: dashed; }
.rubric-n { font-family: var(--font-mono); font-size: 11px; font-weight: 700; color: var(--echo-cyan); }
.rubric-name { margin: 5px 0 0; font-size: 14.5px; font-weight: 750; color: var(--ink); }
.rubric-what { margin: 4px 0 0; font-size: 13px; line-height: 1.5; color: var(--slate); }

.anchors { display: grid; gap: 8px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 140px), 1fr)); }
.anchor { border-radius: var(--radius-lg); padding: 13px 14px; border: 1px solid var(--cloud); background: var(--white); }
.anchor-n { font-family: var(--font-mono); font-size: 17px; font-weight: 700; color: var(--ink); }
.anchor-t { margin: 5px 0 0; font-size: 13px; line-height: 1.5; color: var(--slate); }
.anchor.is-harm { background: var(--blush); border-color: transparent; }
.anchor.is-harm .anchor-n { color: var(--bad-ink); }
.anchor.is-baseline { background: var(--ice); border-color: transparent; }
.anchor.is-baseline .anchor-n { color: var(--action-ink); }
.anchor.is-top { background: var(--success-tint); border-color: transparent; }
.anchor.is-top .anchor-n { color: var(--good-ink); }

.walk { display: flex; flex-direction: column; gap: clamp(16px, 2vw, 22px); }
.walk-beat { display: grid; gap: 8px; }
.walk-who { font-size: 10.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--slate); }
.walk-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.walk-tag { font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--action-ink); background: var(--ice); border-radius: var(--radius-pill); padding: 3px 9px; }
.walk-note { margin: 0; font-size: 13.5px; line-height: 1.6; color: var(--slate); }

/* ---- Movement, funnel, postures, barriers, tiers ----------------------- */
/* The spiritual-movement scale — one track, five stops, drawn as the scale it
   actually is. It replaced five tinted boxes running pink to green on
   2026-08-29; the renderer's comment says why. Two things about it are
   deliberate rather than decorative:

   The ramp is NEUTRAL to BRAND, not red to green. Away from God is not an
   error state and should not be painted like one — this is a report a
   ministry reads about its own faithful work. The left end is the page's own
   hairline grey and the colour arrives as the stops move right.

   The stops GROW as well as darken, so the scale still reads in one glance
   for a reader who cannot separate the two hues, and still reads in print. */
.mscale-solo { max-width: 900px; }
.mscale-rail { position: relative; padding-top: 26px; }
/* The track runs between the FIRST and LAST dot, not edge to edge. The stops
   are grid cells and their dots sit at the cell centres, so a full-width rail
   sticks out past both ends and the scale looks like it was cropped. */
.mscale-track {
  position: absolute; left: 10%; right: 10%; top: 9px; height: 6px; border-radius: 999px;
  background: linear-gradient(90deg,
    var(--cloud) 0%, var(--cloud) 18%, var(--ice) 42%,
    color-mix(in srgb, var(--echo-cyan) 55%, var(--ice)) 68%,
    var(--echo-cyan) 88%, var(--action-ink) 100%);
}
.mscale-stops { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; }
.mscale-stop { position: relative; text-align: center; }
/* The dot sits ON the track, so it is pulled up out of its own row by exactly
   the padding above. */
.mscale-dot {
  position: absolute; left: 50%; top: -26px; transform: translateX(-50%);
  display: block; width: 12px; height: 12px; border-radius: 50%;
  background: var(--slate); box-shadow: 0 0 0 4px var(--white);
}
.mscale-stop:nth-child(2) .mscale-dot { width: 13px; height: 13px; background: var(--steel); }
.mscale-stop:nth-child(3) .mscale-dot { width: 15px; height: 15px; top: -27px; background: var(--action-ink); opacity: .55; }
.mscale-stop:nth-child(4) .mscale-dot { width: 17px; height: 17px; top: -28px; background: var(--echo-cyan); }
.mscale-stop:nth-child(5) .mscale-dot {
  width: 21px; height: 21px; top: -30px; background: var(--action-ink);
  box-shadow: 0 0 0 4px var(--white), 0 0 0 9px color-mix(in srgb, var(--echo-cyan) 26%, transparent);
}
.mscale-label { display: block; margin-top: 14px; font-size: 13px; line-height: 1.4; color: var(--slate); }
.mscale-stop:nth-child(5) .mscale-label { color: var(--ink); font-weight: 650; }
.move-axis { display: flex; flex-wrap: wrap; gap: 10px; justify-content: space-between; margin-top: 14px; font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--steel); }
@media (max-width: 640px) {
  /* Five labels across a phone is five stacks of one word each. The scale
     turns on its side and keeps every part it had. */
  .mscale-rail { padding-top: 0; padding-left: 30px; }
  .mscale-track { left: 9px; right: auto; top: 11px; bottom: 11px; width: 6px; height: auto;
    background: linear-gradient(180deg,
      var(--cloud) 0%, var(--cloud) 18%, var(--ice) 42%,
      color-mix(in srgb, var(--echo-cyan) 55%, var(--ice)) 68%,
      var(--echo-cyan) 88%, var(--action-ink) 100%); }
  .mscale-stops { grid-template-columns: 1fr; gap: 14px; }
  .mscale-stop { text-align: left; min-height: 22px; }
  .mscale-dot, .mscale-stop:nth-child(n) .mscale-dot { left: -30px; top: 2px; transform: none; }
  .mscale-label { margin-top: 0; }
  .move-axis { justify-content: flex-start; gap: 8px; padding-left: 30px; }
}

.funnel { display: flex; flex-direction: column; gap: 8px; align-items: center; }
.funnel-band {
  border-radius: var(--radius-lg); padding: 16px 18px; text-align: center; color: var(--on-action);
  display: grid; gap: 4px; width: 100%; max-width: var(--w, 100%);
  transition: max-width .8s var(--ease-standard);
}
.has-reveal .reveal:not(.in) .funnel-band { max-width: 100%; }
.funnel-band b { font-size: 15.5px; font-weight: 750; }
.funnel-band span { font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; opacity: .82; }
.funnel-1 { background: #3E5C86; }
.funnel-2 { background: #2E6E96; }
.funnel-3 { background: var(--band-3); }
.funnel-4 { background: #12233F; }

.ladder { display: grid; gap: 8px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); }
.ladder-step { border-radius: var(--radius-lg); border: 1px solid var(--cloud); background: var(--white); padding: 13px 14px; }
.ladder-step b { display: block; font-size: 14.5px; font-weight: 750; color: var(--ink); }
.ladder-step span { display: block; margin-top: 4px; font-size: 13px; line-height: 1.5; color: var(--slate); }
.ladder-step.is-unclear { background: var(--mist); border-style: dashed; }

.tiers { display: flex; flex-direction: column; gap: 8px; }
.tier { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: baseline; border-radius: var(--radius-lg); padding: 13px 16px; background: var(--white); border: 1px solid var(--cloud); }
.tier b { flex: 0 0 auto; min-width: 108px; font-size: 14.5px; font-weight: 750; color: var(--ink); }
.tier span { flex: 1 1 220px; min-width: 0; font-size: 14px; line-height: 1.55; color: var(--slate); }
.tier.is-critical { background: var(--blush); border-color: transparent; }
.tier.is-critical b { color: var(--bad-ink); }

/* ---- The calibration loop --------------------------------------------- */
.loop { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
.loop-step { background: var(--white); border: 1px solid var(--cloud); border-radius: var(--radius-lg); padding: 16px; }
.loop-n { font-family: var(--font-mono); font-size: 11px; font-weight: 700; color: var(--echo-cyan); }
.loop-step b { display: block; margin-top: 6px; font-size: 15px; font-weight: 750; color: var(--ink); }
.loop-step span { display: block; margin-top: 5px; font-size: 13.5px; line-height: 1.55; color: var(--slate); }

.pullquote {
  margin: clamp(24px, 3vw, 36px) 0 0; padding: clamp(22px, 2.6vw, 32px);
  background: var(--ice); border-radius: var(--radius-xl);
}
.pullquote p { margin: 0; font-size: clamp(18px, 1.9vw, 23px); line-height: 1.5; font-weight: 650; color: var(--ink); letter-spacing: -0.015em; }
.pullquote cite { display: block; margin-top: 12px; font-style: normal; font-size: 13px; color: var(--slate); }

/* The note of humility. 02-DESIGN-BRIEF assigned it the page's single --rose
   moment and it was a blush panel until 2026-08-29; Andre's call was that the
   pink is the wrong colour for this page and too much of it. It carries the
   same weight now with the house device instead: the ordinary card surface,
   and one dot. Colour survives inside 8px. */
.humility {
  margin-top: clamp(24px, 3vw, 38px); border-radius: var(--radius-xl);
  padding: clamp(20px, 2.4vw, 28px);
  background: var(--white); border: 1px solid var(--cloud); box-shadow: var(--shadow-sm);
  max-width: 900px;
}
.humility-h {
  display: flex; align-items: center; gap: 10px; margin: 0 0 10px;
  font-size: 12.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--steel);
}
.humility-h::before { content: ""; flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; background: var(--echo-cyan); }
.humility p { margin: 0; font-size: 15.5px; line-height: 1.65; color: var(--ink); }

/* ============================================================
   The EchoAnalyst report catalogue

   Every card carries the report's real printed title, its real question and
   its real KPI tile labels, copied from the product. .report-shot is where
   the capture goes; it is deliberately neutral rather than amber, because
   thirteen amber boxes reads as an unfinished site rather than as one
   outstanding deliverable. A single .slot covers all thirteen.
   ============================================================ */
.report-grid { display: grid; gap: clamp(14px, 1.8vw, 20px); grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); }
.report-card {
  display: flex; flex-direction: column; min-width: 0; background: var(--white);
  border: 1px solid var(--cloud); border-radius: var(--radius-2xl); overflow: hidden;
}
.report-card[hidden] { display: none; }
.report-shot {
  aspect-ratio: 16 / 9; display: grid; place-items: center; border-bottom: 1px solid var(--cloud);
  background: linear-gradient(150deg, var(--mist) 0%, var(--ice) 100%); color: var(--steel);
}
.report-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.report-shot.is-empty span { font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--slate); }
.report-body { padding: clamp(16px, 1.8vw, 22px); display: flex; flex-direction: column; flex: 1 1 auto; }
.report-kind {
  align-self: flex-start; font-size: 10.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  border-radius: var(--radius-pill); padding: 4px 9px; background: var(--panel); color: var(--slate);
}
.report-kind.is-instant { background: var(--success-tint); color: var(--good-ink); }
.report-kind.is-narrative { background: var(--ice); color: var(--action-ink); }
.report-name { margin: 12px 0 0; font-size: 18px; font-weight: 750; letter-spacing: -0.015em; color: var(--ink); }
.report-q { margin: 8px 0 0; font-size: 14.5px; line-height: 1.6; color: var(--slate); }
.report-kpis { margin: 16px 0 0; padding: 14px 0 0; border-top: 1px solid var(--cloud); list-style: none; display: flex; flex-direction: column; gap: 7px; }
.report-kpis li { font-family: var(--font-mono); font-size: 12px; line-height: 1.5; color: var(--slate); padding-inline-start: 14px; position: relative; }
.report-kpis li::before { content: ""; position: absolute; inset-inline-start: 0; top: 7px; width: 5px; height: 5px; border-radius: 50%; background: var(--echo-cyan); }
/* The label sits inside the list so the markup stays one block per card;
   it is not a KPI, so it takes neither the bullet nor the mono face. */
.report-kpis .report-kpis-label {
  font-family: var(--font-sans); font-size: 10.5px; font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; color: var(--slate); padding-inline-start: 0; margin-bottom: 3px;
}
.report-kpis .report-kpis-label::before { content: none; }

/* ============================================================
   The EchoAnalyst reports sales page (product/echoanalyst-reports.html)

   An immersive one-off: a navy hero, a pitch under every card instead of
   KPI bullets, and a drawn sample report behind every card, opened in a
   native <dialog>. The miniatures and mocks are openly stylized — sample
   numbers only ever appear under a visible "Sample data" badge.
   ============================================================ */
.reports-hero {
  background: linear-gradient(120deg, #16284E 0%, #24467F 100%);
  color: #fff; padding: clamp(64px, 8vw, 128px) 0 clamp(60px, 7.5vw, 116px);
  position: relative; overflow: hidden;
}
.reports-hero::after {
  content: ""; position: absolute; right: -180px; top: -180px; width: 560px; height: 560px;
  border-radius: 50%; background: radial-gradient(closest-side, rgba(61,180,232,.22), transparent 70%);
  pointer-events: none;
}
.reports-hero > .wrap { position: relative; }
.reports-hero .breadcrumbs, .reports-hero .breadcrumbs a { color: #AFC3E2; }
.reports-hero .breadcrumbs a:hover { color: #fff; }
.reports-hero .eyebrow { color: #7FD0F5; }
.reports-hero h1 { color: #fff; }
.reports-hero .lead { color: #C9D6EA; }
.reports-hero .lead b { color: #fff; }
.report-pitch { margin: 14px 0 0; padding: 14px 0 16px; border-top: 1px solid var(--cloud); font-size: 14.5px; line-height: 1.62; color: var(--slate); }
.report-pitch b { color: var(--ink); }
/* The whole card is a click target for its sample report (wired in the page's
   script); the button stays for keyboards and to name the action. It is
   anchored to the card's bottom edge so a row of cards ends level. */
.report-card { transition: transform .18s var(--ease-standard), box-shadow .18s var(--ease-standard); }
.report-card:has(.report-open) { cursor: pointer; }
.report-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-float); }
.report-open {
  margin-top: auto; align-self: flex-start; display: inline-flex; align-items: center; gap: 8px;
  border: 0; cursor: pointer; border-radius: var(--radius-pill); padding: 9px 16px;
  background: var(--ice); color: var(--action-ink); font: inherit; font-size: 13.5px; font-weight: 750;
}
.report-open::after { content: "→"; font-weight: 700; }
.report-open:hover, .report-card:hover .report-open { background: var(--grad-action); color: #fff; }
.report-shot { position: relative; }
.report-shot::after {
  content: "Open the sample report →"; position: absolute; left: 50%; bottom: 12px; transform: translate(-50%, 6px);
  background: rgba(22, 40, 78, .88); color: #fff; font-size: 12.5px; font-weight: 750; letter-spacing: .02em;
  padding: 8px 15px; border-radius: var(--radius-pill); white-space: nowrap;
  opacity: 0; transition: opacity .18s var(--ease-standard), transform .18s var(--ease-standard); pointer-events: none;
}
.report-card:has(.report-open):hover .report-shot::after { opacity: 1; transform: translate(-50%, 0); }
@media (prefers-reduced-motion: reduce) {
  .report-card, .report-shot::after { transition: none; }
}

/* ---- The sample-report modal ------------------------------------------ */
/* One shared <dialog>: the card's link opens here in an iframe instead of a
   new tab, with the direct URL kept in the header for anyone who wants the
   full window. The iframe's src is set on open and cleared on close so a
   hidden report isn't left running. */
.samplewin {
  border: 0; padding: 0; margin: auto; background: var(--white);
  border-radius: var(--radius-2xl); overflow: hidden;
  width: min(1160px, 96vw); height: min(92vh, 1400px);
  box-shadow: 0 30px 80px rgba(18, 28, 52, .35);
}
.samplewin::backdrop { background: rgba(18, 28, 52, .55); }
.samplewin-frame { display: flex; flex-direction: column; height: 100%; }
.samplewin-head {
  display: flex; align-items: center; gap: 14px; padding: 12px 16px 12px 22px;
  border-bottom: 1px solid var(--cloud); background: var(--white);
}
.samplewin-title { flex: 1 1 auto; min-width: 0; font-size: 15px; font-weight: 750; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.samplewin-title span { font-weight: 600; color: var(--steel); }
.samplewin-full { flex: 0 0 auto; font-size: 13px; font-weight: 700; color: var(--action-ink); text-decoration: underline; text-underline-offset: 3px; }
.samplewin-close {
  flex: 0 0 auto; border: 1px solid var(--cloud); background: var(--white); color: var(--slate); cursor: pointer;
  border-radius: 50%; width: 34px; height: 34px; font-size: 16px; line-height: 1;
}
.samplewin-close:hover { color: var(--ink); border-color: var(--slate); }
.samplewin iframe { flex: 1 1 auto; width: 100%; border: 0; display: block; background: var(--mist); }

/* ---- The pricing band -------------------------------------------------- */
.price-band {
  border-radius: var(--radius-2xl); overflow: hidden; color: #fff;
  background: linear-gradient(120deg, #16284E 0%, #24467F 100%);
  padding: clamp(28px, 3.6vw, 46px);
}
.price-band .eyebrow { color: #7FD0F5; }
.price-fig { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px 16px; margin-top: 14px; }
.price-num { font-family: var(--font-mono); font-size: clamp(44px, 6vw, 64px); font-weight: 700; letter-spacing: -0.04em; line-height: 1; }
.price-unit { font-size: clamp(15px, 1.6vw, 18px); font-weight: 650; color: #C9D6EA; max-width: 300px; line-height: 1.4; }
.price-note { margin-top: 14px; font-size: 14.5px; line-height: 1.65; color: #C9D6EA; max-width: 640px; }
.price-note b { color: #fff; }
.price-examples { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.price-example {
  border: 1px solid rgba(255,255,255,.26); border-radius: var(--radius-lg); padding: 12px 16px;
  font-size: 13.5px; color: #C9D6EA;
}
.price-example b { display: block; font-family: var(--font-mono); font-size: 19px; font-weight: 700; color: #fff; margin-bottom: 2px; }

/* ============================================================
   Timeline — a left spine with dots.

   Shared by the changelog release list and the "Monday morning" figure on
   the EchoAnalyst page. The spine is drawn on the list, not per item, so a
   filtered-out item leaves no gap in the line.
   ============================================================ */
.timeline { position: relative; margin: 0; padding: 0 0 0 30px; list-style: none; }
.timeline::before { content: ""; position: absolute; inset-inline-start: 5px; top: 8px; bottom: 8px; width: 2px; background: var(--cloud); }
.timeline > li { position: relative; padding-bottom: clamp(20px, 2.4vw, 28px); }
.timeline > li::before {
  content: ""; position: absolute; inset-inline-start: -30px; top: 6px; width: 12px; height: 12px;
  border-radius: 50%; background: var(--white); border: 2px solid var(--echo-cyan);
}
.timeline > li:last-child { padding-bottom: 0; }
.timeline-when { font-family: var(--font-mono); font-size: 12.5px; font-weight: 700; color: var(--action-ink); }
.timeline-what { margin: 5px 0 0; font-size: 15px; line-height: 1.65; color: var(--slate); }
[dir="rtl"] .timeline { padding: 0 30px 0 0; }

/* ============================================================
   Changelog releases
   ============================================================ */
.release { background: var(--white); border: 1px solid var(--cloud); border-radius: var(--radius-2xl); overflow: hidden; }
.release + .release { margin-top: clamp(18px, 2.2vw, 26px); }
.release-art { display: block; width: 100%; height: clamp(140px, 17vw, 210px); object-fit: cover; }
.release-body { padding: clamp(20px, 2.4vw, 30px); }
.release-head { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: baseline; justify-content: space-between; }
.release-date { font-family: var(--font-mono); font-size: 12.5px; font-weight: 700; letter-spacing: .02em; color: var(--action-ink); }
.release-title { margin: 10px 0 0; font-size: clamp(21px, 2.2vw, 28px); }
.release-lede { margin: 12px 0 0; font-size: 15.5px; line-height: 1.7; color: var(--slate); max-width: 62ch; }
.release-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 16px; }
.release-permalink { font-size: 13px; font-weight: 650; color: var(--steel); }
.release-permalink:hover { color: var(--action-ink); }

.release-items { margin: 18px 0 0; padding: 0; list-style: none; }
/* Grid, not flex: an item can carry an image and a help-article link under its
   text, and those stack in the second column while the tag keeps the first. */
.release-item { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; align-items: start; padding: 12px 0; border-top: 1px solid var(--cloud); }
.release-item p { grid-column: 2; margin: 0; font-size: 15px; line-height: 1.6; color: var(--slate); }
.release-item p b { color: var(--ink); font-weight: 700; }
.release-item[hidden] { display: none; }
.release-item-art { grid-column: 2; justify-self: start; max-width: min(100%, 560px); border: 1px solid var(--cloud); border-radius: var(--radius-md); margin-top: 2px; }
.release-item-link { grid-column: 2; justify-self: start; font-size: 14px; font-weight: 650; color: var(--action-ink); text-decoration: underline; text-underline-offset: 3px; }
.release-item-link:hover { color: var(--ink); }

/* "EchoAnalyst add-on" — the entries a ministry has to buy separately.
   Outlined rather than filled, so it reads as a different kind of thing from
   the added/improved/fixed tags beside it and cannot be mistaken for one. The
   word is always printed; the dot is only a glance-cue, and it is drawn in the
   text's own ink rather than in cyan, which is too pale at 6px to stand on
   white. Deliberately not a tinted panel with a bar down its edge. */
.release-addon {
  grid-column: 2; justify-self: start; display: inline-flex; align-items: center;
  gap: 7px; margin-top: 4px; padding: 3px 11px 3px 9px;
  border: 1px solid var(--cloud); border-radius: var(--radius-pill); background: var(--white);
  font-size: 12px; font-weight: 700; letter-spacing: .01em; color: var(--action-ink);
}
.release-addon::before {
  content: ""; flex: 0 0 auto; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
}
.release-feature .release-addon { margin-top: 10px; }

/* The legend under the filter chips, explaining what the marker means. */
.log-addon-note { margin: -14px 0 clamp(24px,3vw,36px); font-size: 14px; color: var(--slate); }
.log-addon-note b { color: var(--ink); font-weight: 700; }

/* added / improved / fixed. Colour alone never carries the meaning — the
   word is always printed. */
.tag {
  flex: 0 0 auto; min-width: 74px; text-align: center; font-size: 10.5px; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; border-radius: var(--radius-pill);
  padding: 4px 9px; margin-top: 1px;
}
.tag-added { background: var(--success-tint); color: var(--good-ink); }
.tag-improved { background: var(--ice); color: var(--action-ink); }
.tag-fixed { background: var(--panel); color: var(--slate); }

.release-more { margin-top: 16px; }
.release-more > summary {
  cursor: pointer; font-size: 14.5px; font-weight: 700; color: var(--action-ink);
  list-style: none; display: inline-flex; align-items: center; gap: 7px;
}
.release-more > summary::-webkit-details-marker { display: none; }
.release-more > summary::after { content: "\25BE"; font-size: 11px; transition: transform var(--dur-base) var(--ease-standard); }
.release-more[open] > summary::after { transform: rotate(180deg); }
.release-more > summary:focus-visible { outline: 0; box-shadow: 0 0 0 3px rgba(23,111,154,.35); border-radius: var(--radius-sm); }

/* ------------------------------------------------------------
   The changelog layout: a date rail beside the release stream.
   Under 1100px the rail folds into a wrapping strip of date
   links above the stream and the idea card steps aside.
   ------------------------------------------------------------ */
.log-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(22px, 3vw, 40px); align-items: start; }
.log-main { max-width: 900px; min-width: 0; }
.log-rail-head { margin-bottom: 10px; }
.log-rail-year { font-family: var(--font-mono); font-size: 12px; font-weight: 700; letter-spacing: .04em; color: var(--ink); margin: 16px 0 4px; }
.log-rail-year:first-of-type { margin-top: 0; }
.log-rail-link {
  display: flex; align-items: center; gap: 8px; padding: 7px 10px; margin: 0 -10px;
  border-radius: var(--radius-md); font-size: 14px; font-weight: 600; color: var(--slate); text-decoration: none;
}
/* A class that sets display needs a [hidden] companion, or `node.hidden = true`
   silently does nothing — the same trap that left the contact form's
   conditional fields permanently visible. The rail hides links whose release a
   filter has taken off the page. */
.log-rail-link[hidden] { display: none; }
.log-rail-link:hover { background: var(--panel); color: var(--ink); }
.log-rail-link[aria-current="true"] { background: var(--ice); color: var(--action-ink); font-weight: 750; }
/* The newest release wears a small "live" dot; the word next to it still
   carries the meaning. */
.log-rail-link.is-latest::before { content: ""; flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%; background: var(--success); }
.log-rail-idea { margin-top: 22px; }
.log-rail-idea .link { display: inline-block; margin-top: 10px; font-size: 14px; }

@media (min-width: 1100px) {
  .log-layout { grid-template-columns: 212px minmax(0, 1fr); }
  /* Seventy-two releases are taller than any screen. The rail sticks, and the
     list inside it scrolls on its own — reaching 2020 should not mean scrolling
     six years of the page to get there. `min-height: 0` is what allows the list
     to shrink inside the flex column; without it the rail grows to fit its
     content and the scrollbar never appears. */
  .log-rail {
    position: sticky; top: 96px;
    max-height: calc(100vh - 132px);
    display: flex; flex-direction: column; gap: 12px;
  }
  .log-rail-head { margin: 0; }
  .log-rail-nav {
    min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    padding-right: 8px;
    scrollbar-width: thin; scrollbar-color: var(--cloud) transparent;
  }
  .log-rail-nav:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 3px; border-radius: var(--radius-md); }
  /* The year holds still while its own months scroll under it, so you always
     know where you are in a six-year list. */
  /* The year headings were tried as sticky and taken back out: pinning one
     leaves a half-hidden month sitting under it, which reads as a rendering
     fault rather than as a list mid-scroll. They scroll with their months. */
  .log-rail-idea { flex: 0 0 auto; margin-top: 0; }
}
@media (max-width: 1099px) {
  /* Wrapped, seventy-two pills would be a wall above the first release. One
     swipeable row instead, newest first. */
  .log-rail-head { margin: 0 0 8px; }
  .log-rail-nav {
    display: flex; flex-wrap: nowrap; align-items: center; gap: 8px;
    overflow-x: auto; overscroll-behavior-x: contain;
    padding-bottom: 8px; scroll-snap-type: x proximity;
  }
  .log-rail-nav > * { flex: 0 0 auto; scroll-snap-align: start; }
  .log-rail-nav:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 3px; border-radius: var(--radius-md); }
  .log-rail-year { margin: 0; padding-left: 4px; color: var(--slate); }
  .log-rail-link { margin: 0; padding: 6px 10px; border: 1px solid var(--cloud); border-radius: var(--radius-pill); white-space: nowrap; }
  .log-rail-idea { display: none; }
}

/* The at-a-glance band: how much of each kind shipped. */
.release-stats { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 0; padding: 0; list-style: none; }
.release-stat {
  display: flex; align-items: baseline; gap: 8px;
  border: 1px solid var(--cloud); border-radius: var(--radius-lg); background: var(--white); padding: 10px 16px;
}
.release-stat-num { font-family: var(--font-mono); font-size: 22px; font-weight: 750; line-height: 1; color: var(--ink); }
.release-stat-label { font-size: 13px; font-weight: 650; }
.release-stat-label.is-added { color: var(--good-ink); }
.release-stat-label.is-improved { color: var(--action-ink); }
.release-stat-label.is-fixed { color: var(--slate); }

/* Highlight cards — an item that carries artwork. */
.release-features { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); margin-top: 18px; }
.release-features[hidden] { display: none; }
.release-feature { margin: 0; border: 1px solid var(--cloud); border-radius: var(--radius-lg); background: var(--white); overflow: hidden; }
.release-feature[hidden] { display: none; }
.release-feature > img { display: block; width: 100%; aspect-ratio: 16 / 10; object-fit: cover; border-bottom: 1px solid var(--cloud); }
.release-feature figcaption { padding: 14px 16px 16px; }
.release-feature p { margin: 9px 0 0; font-size: 14.5px; line-height: 1.55; color: var(--slate); }
.release-feature p b { display: block; color: var(--ink); font-weight: 700; margin-bottom: 2px; }
.release-feature .release-item-link { display: inline-block; margin-top: 8px; }

/* What else changed — the per-category folds. */
.release-group { border: 1px solid var(--cloud); border-radius: var(--radius-lg); background: var(--white); margin-top: 12px; }
.release-group[hidden] { display: none; }
.release-group > summary {
  display: flex; align-items: center; gap: 10px; padding: 14px 18px; cursor: pointer;
  list-style: none; font-size: 15.5px; font-weight: 700; color: var(--ink);
}
.release-group > summary::-webkit-details-marker { display: none; }
.release-group > summary::after { content: "\25BE"; margin-left: auto; font-size: 11px; color: var(--slate); transition: transform var(--dur-base) var(--ease-standard); }
.release-group[open] > summary::after { transform: rotate(180deg); }
.release-group > summary:focus-visible { outline: 0; box-shadow: 0 0 0 3px rgba(23,111,154,.35); border-radius: var(--radius-md); }
.release-group-count { font-family: var(--font-mono); font-size: 12px; font-weight: 650; color: var(--slate); background: var(--panel); border-radius: var(--radius-pill); padding: 3px 10px; }
.release-group .release-items { margin: 0; padding: 0 18px; }
.release-group .release-items .release-item:last-child { padding-bottom: 16px; }
[dir="rtl"] .release-group > summary::after { margin-left: 0; margin-right: auto; }

/* ============================================================
   Tabs, FAQ, tables
   ============================================================ */
.tabs { display: flex; flex-wrap: wrap; gap: 8px; }
.tab {
  font: inherit; font-size: 15px; font-weight: 650; padding: 11px 18px; cursor: pointer;
  border-radius: var(--radius-pill); border: 1px solid var(--cloud); background: var(--white); color: var(--slate);
}
.tab[aria-selected="true"] { background: var(--grad-action); border-color: transparent; color: var(--on-action); box-shadow: var(--shadow-action); }
.tabpanel[hidden] { display: none; }

.faq { border-top: 1px solid var(--cloud); }
.faq-item { border-bottom: 1px solid var(--cloud); }
.faq-q {
  width: 100%; display: flex; gap: 16px; align-items: flex-start; justify-content: space-between;
  font: inherit; font-size: 17px; font-weight: 750; letter-spacing: -0.01em; line-height: 1.4;
  text-align: left; background: none; border: 0; padding: 22px 0; cursor: pointer; color: var(--ink);
}
.faq-q:hover { color: var(--action-ink); }
.faq-q svg { flex: 0 0 auto; margin-top: 4px; transition: transform var(--dur-base) var(--ease-standard); color: var(--steel); }
.faq-q[aria-expanded="true"] svg { transform: rotate(45deg); }
.faq-a { padding: 0 0 22px; max-width: 720px; }
.faq-a[hidden] { display: none; }
.faq-a p { margin: 0 0 12px; font-size: 15.5px; line-height: 1.7; color: var(--slate); }
.faq-a p:last-child { margin-bottom: 0; }

.table-wrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: 15px; min-width: 560px; }
table.data th, table.data td { text-align: left; padding: 15px 16px; border-bottom: 1px solid var(--cloud); vertical-align: top; }
table.data th { font-size: 12.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--steel); }
table.data td { color: var(--slate); line-height: 1.6; }
table.data td:first-child { color: var(--ink); font-weight: 650; }

/* ============================================================
   Forms
   ============================================================ */
.field { display: block; margin-bottom: 18px; }
/* Required companion. A normal author `display:block` beats the user agent's
   [hidden]{display:none}, so without this every conditional contact field is
   permanently visible and the data-when mechanism silently does nothing.
   Every other display-setting class here already carries its own [hidden]
   rule — .mega, .drawer, .chat-panel, .tabpanel, .faq-a. .field was missed. */
.field[hidden] { display: none; }
.field > span { display: block; font-size: 13.5px; font-weight: 650; color: var(--ink); margin-bottom: 7px; }
.field .hint { display: block; font-weight: 400; font-size: 13px; color: var(--steel); margin-top: 6px; }
.input, .select, .textarea {
  width: 100%; font: inherit; font-size: 15.5px; color: var(--ink); background: var(--white);
  border: 1px solid var(--cloud); border-radius: var(--radius-sm); padding: 13px 15px;
}
.input:focus, .select:focus, .textarea:focus { outline: 0; border-color: var(--echo-cyan); box-shadow: var(--ring-focus); }
.textarea { min-height: 140px; resize: vertical; line-height: 1.6; }
.form-row { display: grid; gap: 0 18px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
.form-note { font-size: 13px; color: var(--steel); line-height: 1.6; }
.email-capture { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.email-capture .field { flex: 1 1 240px; margin-bottom: 0; }

/* The attachment drop zone.

   Built out of surfaces the site already owns: the hairline border of
   .card-flat, dashed to say "put something here", and the rounded .icon-tile
   so the only colour in the panel lives inside 32px. No tinted panel and no
   bar down the edge.

   The <input type="file"> inside stays a real native input on purpose. It is
   the keyboard path, the screen-reader path, and the path that works if site.js
   never arrives — dropping is the shortcut layered on top of it, not a
   replacement for it. Only its appearance is dropped, and only here: the whole
   zone is inside the <label>, so the native "Choose file" button was a second
   control doing what a click anywhere already did. Because the hiding lives in
   this stylesheet rather than in the markup, a page that loads without CSS
   still shows the plain native input. */
.dropzone {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  text-align: center; padding: 22px 18px;
  border: 1px dashed var(--cloud); border-radius: var(--radius-sm);
  background: var(--white);
  cursor: pointer;
  transition: border-color .14s ease, background-color .14s ease;
}
.dropzone .icon-tile { flex: none; }
.dropzone-say { font-size: 14px; font-weight: 400; color: var(--slate); margin: 0; }
/* Visually hidden, never display:none — the same pattern the type picker's
   radios use, and for the same reason: a display:none input cannot be focused,
   which would leave the attachment unreachable from a keyboard. The whole zone
   is inside the <label>, so a click anywhere on it already opens the picker;
   the browser's own "Choose file" button was a second, uglier way to do the
   same thing. Tab still lands here and :focus-within below draws the ring. */
.dropzone .input-file { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
/* Chrome will not focus-ring the control itself, so the box carries it. */
.dropzone:focus-within { border-color: var(--echo-cyan); box-shadow: var(--ring-focus); }
/* Dragging over. Solid border and a wash of the page ground, so the state is
   carried by the same box rather than by a new one appearing. */
.dropzone[data-dragging] { border-style: solid; border-color: var(--echo-cyan); background: var(--mist); }
.dropzone-picked {
  font-size: 13.5px; font-weight: 650; color: var(--ink); margin: 0;
  max-width: 100%; overflow-wrap: anywhere;
}
.dropzone-picked[hidden] { display: none; }

/* ============================================================
   Contact

   The type picker is radios, not buttons. Arrow-key navigation, form
   semantics and group labelling all come free from a radio group and would
   all have to be rebuilt by hand on buttons. The input is visually hidden
   but never display:none — a display:none input cannot be focused, which
   would make the picker unreachable from a keyboard.
   ============================================================ */
.contact-grid {
  display: grid; gap: clamp(24px, 3vw, 44px); align-items: start;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
}
@media (max-width: 900px) { .contact-grid { grid-template-columns: minmax(0, 1fr); } }

/* Step 1 is four buttons, not four cards.

   The cards they replaced cost ~330px of page at desktop and ~700px at 390 —
   most of the first screen spent on a question with four short answers. The
   row names the four; the line under it carries the description and the
   routing for whichever is chosen.

   Nothing leaves the page with them: the "what happens to your message"
   panel beside the form still lists all four at once and highlights the
   active one, which is where comparing them belongs.

   Two shades carry the state, both already on this page. Unpicked is the
   --mist ground, which is what makes a button look pressable before anyone
   has touched it — on the white section behind it, an unfilled button reads
   as a label. Picked is --ice, a step darker, with the border and the ink in
   --action-ink. That is the same tint the active .expect-row uses beside the
   form, so the two halves of the page agree about what "selected" looks
   like. A tint on a control's own state, with no bar down its edge and no
   micro-label above it, is not the shape that is banned. */
.type-picker {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px;
}
.type-seg {
  position: relative; display: flex; align-items: center; justify-content: center;
  gap: 8px; min-width: 0; padding: 12px; cursor: pointer;
  background: var(--mist); border: 1px solid var(--cloud); border-radius: var(--radius-sm);
  box-shadow: 0 1px 2px rgba(32,48,88,.06);
  color: var(--slate); text-align: center;
  transition: background var(--dur-base) var(--ease-standard),
              border-color var(--dur-base) var(--ease-standard),
              color var(--dur-base) var(--ease-standard),
              box-shadow var(--dur-base) var(--ease-standard);
}
.type-seg input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.type-seg:hover { background: var(--white); border-color: var(--echo-cyan); color: var(--ink); box-shadow: 0 2px 7px rgba(32,48,88,.10); }
.type-seg:has(input:checked) {
  background: var(--ice); border-color: var(--action-ink); color: var(--action-ink);
  box-shadow: var(--shadow-card);
}
/* An outline rather than a box-shadow ring: the picked button already spends
   its box-shadow on the lift, and a ring would replace it. */
.type-seg:has(input:focus-visible) { outline: 2px solid var(--action-ink); outline-offset: 2px; }
.type-seg-icon { flex: none; display: grid; place-items: center; }
.type-name { font-size: 14.5px; font-weight: 700; }

/* Only the chosen row is laid out; the other three are display:none. */
.type-detail { margin-top: 13px; }
.type-detail-row { display: none; margin: 0; }
.type-picker:has(input[value="sales"]:checked)   ~ .type-detail [data-type="sales"],
.type-picker:has(input[value="billing"]:checked) ~ .type-detail [data-type="billing"],
.type-picker:has(input[value="support"]:checked) ~ .type-detail [data-type="support"],
.type-picker:has(input[value="general"]:checked) ~ .type-detail [data-type="general"] {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 18px;
}
.type-what { flex: 1 1 320px; font-size: 14px; line-height: 1.55; color: var(--slate); }

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

.form-step { margin-top: clamp(26px, 3vw, 36px); }
.form-step-head { display: flex; align-items: center; gap: 11px; margin-bottom: 16px; }
.form-step-n {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%; background: var(--ice);
  color: var(--action-ink); display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 12.5px; font-weight: 700;
}
.form-step-head h3 { font-size: 17px; font-weight: 750; }

/* One row per message type. The picker writes data-expect-active; this
   highlights the matching row rather than hiding the others, so a visitor
   can still see what happens to the kinds of message they did not pick. */
.expect-strip { display: flex; flex-direction: column; }
.expect-row {
  display: grid; gap: 4px 14px; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline;
  padding: 13px 14px; border-radius: var(--radius-md); border: 1px solid transparent;
  transition: background var(--dur-base) var(--ease-standard), border-color var(--dur-base) var(--ease-standard);
}
.expect-row b { font-size: 14.5px; font-weight: 700; color: var(--ink); }
.expect-row span { font-size: 13px; line-height: 1.5; color: var(--slate); grid-column: 1 / -1; }
.expect-when { font-family: var(--font-mono); font-size: 11.5px; font-weight: 700; color: var(--slate); white-space: nowrap; grid-column: 2; grid-row: 1; }
[data-expect-active="support"] .expect-row[data-type="support"],
[data-expect-active="sales"]   .expect-row[data-type="sales"],
[data-expect-active="billing"] .expect-row[data-type="billing"],
[data-expect-active="general"] .expect-row[data-type="general"] {
  background: var(--ice); border-color: rgba(23,111,154,.16);
}
/* Where every one of those rows actually lands. One address for all four
   until there is a team behind each — said once, under the strip, rather
   than repeated on every row. */
.expect-foot { margin-top: 12px; padding: 0 14px; font-size: 12.5px; line-height: 1.55; color: var(--slate); }

.contact-direct { display: flex; flex-direction: column; gap: 16px; margin-top: 14px; }
.contact-line { display: flex; gap: 12px; align-items: flex-start; }
.contact-line .icon-tile { width: 38px; height: 38px; }
.contact-line b { display: block; font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--slate); }
.contact-line p { margin: 4px 0 0; font-size: 15px; line-height: 1.55; color: var(--ink); }
.contact-line p a { color: var(--action-ink); font-weight: 650; }

/* Same shape as `.callout`, at form scale: a hairline card, no bar,
   no asymmetric radius, nothing to override in RTL. */
.demo-note {
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--panel); border: 1px solid var(--cloud);
  border-radius: var(--radius-md);
  padding: 14px 16px; font-size: 14px; line-height: 1.6; color: var(--slate);
}

/* ============================================================
   Article / prose
   ============================================================ */
/* overflow-wrap is load-bearing, not cosmetic: an unlinked URL in the copy
   ("https://YOURTENANT.echoglobal.org/admin/settings/tenant_settings") is one
   unbreakable word 540px wide, and at 390px it pushed the whole PAGE sideways —
   the defect audit.mjs fails a page for. `break-word` rather than `anywhere` so
   it only breaks a word that genuinely cannot fit. */
.prose { max-width: 720px; font-size: 16.5px; line-height: 1.75; color: var(--slate); overflow-wrap: break-word; }
.prose h2 { font-size: clamp(23px, 2.4vw, 30px); margin: 44px 0 0; color: var(--ink); }
.prose h3 { font-size: 20px; margin: 32px 0 0; color: var(--ink); }
.prose p { margin: 16px 0 0; }
.prose ul, .prose ol { margin: 16px 0 0; padding-left: 22px; }
.prose li { margin: 8px 0; }
.prose img { border-radius: var(--radius-lg); margin-top: 22px; }
.prose a { color: var(--action-ink); font-weight: 650; text-decoration: underline; text-underline-offset: 3px; }
.prose strong { color: var(--ink); font-weight: 700; }
.callout b { color: var(--ink); font-weight: 750; }

/* ------------------------------------------------------------
   Article shapes — the blocks the rich text editor produces.

   These rules are MIRRORED in admin/src/styles/app.css under
   `.ed-surface`, because the editor cannot load this stylesheet
   (site.css also defines .wrap and .grid, which collide with the
   admin's own layout). Change one, change the other; the editor's
   live preview renders through THIS file, so a drift shows up
   there rather than in production.
   ------------------------------------------------------------ */

/* Callouts. Three kinds, each with its own word and its own mark,
   because "note" and "this will break if you skip it" should not
   look the same.

   This used to be a tinted pastel panel with a coloured bar down the
   left edge. That is the shape every documentation tool and every
   chatbot ships by default, Andre banned it by name on 2026-08-04,
   and it is not allowed back in any form — not on callouts, not on
   quotes, not anywhere.

   What replaces it is built from surfaces this site already owns:
   the hairline card of `.card-flat`, and the rounded `.icon-tile`
   that carries an icon on the contact and pricing pages. The card
   stays white, so an aside reads as a considered object on the page
   rather than as a highlighter stripe through it, and the only
   colour left is inside a 32px tile — which is also the white
   paper's art direction, where the brightest element is the
   smallest one.

   Grid, not padding, for two reasons. The body text lines up with
   the label instead of ragging around the icon; and grid tracks
   follow the inline direction on their own, so the Arabic articles
   need no RTL override — the old left border needed one, and that
   is how the pattern spread. */
.callout {
  display: grid;
  grid-template-columns: 32px 1fr;
  column-gap: 13px;
  row-gap: 4px;
  align-items: start;
  margin: 28px 0 0;
  padding: 18px 20px;
  background: var(--white);
  border: 1px solid var(--cloud);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--ink);
}
/* The word. It sits in `::before` rather than `::after` so it comes
   first for a screen reader, and because probe.mjs reads this one to
   check a callout still says which kind it is. Sentence case at
   heading weight: the tracked-out 12px micro-caps were half of what
   made the old shape look generated. */
.callout::before {
  grid-column: 2; grid-row: 1; align-self: center;
  font-size: 14.5px; font-weight: 750; letter-spacing: 0; color: var(--ink);
  content: "Note";
}
/* The mark. 20px viewBox, 1.9–2.2 stroke, round caps — the same
   drawing style as the tick in `ul.ticks`, so the icons on this site
   look like one hand drew them. */
.callout::after {
  grid-column: 1; grid-row: 1;
  width: 32px; height: 32px; border-radius: var(--radius-md);
  background: var(--ice) var(--icon-note) center/18px no-repeat;
  content: "";
}
.callout.callout-note::before { content: "Note"; }
.callout.callout-tip::before { content: "Tip"; }
.callout.callout-tip::after {
  background-color: var(--success-tint);
  background-image: var(--icon-tip);
}
.callout.callout-warning::before { content: "Warning"; }
.callout.callout-warning::after {
  background-color: var(--warning-tint);
  background-image: var(--icon-warning);
}
/* The tile and the word are a header row; the body runs full width
   beneath them rather than indenting into the second column. At
   390px an indent costs 45px of a 300px measure, which was enough to
   add a line break to most paragraphs.

   row-gap does the spacing, because a paragraph's own top margin
   lands inside its grid cell and would stack on top of the gap. */
/* `:is()` takes the specificity of its most specific argument, so these
   land at (0,1,1) — the weight of `.prose p`, which the plain `.callout
   > *` this replaced could not reach. It lost, every paragraph kept its
   16px top margin, and the label floated 21px clear of its own body. */
.callout > * { grid-column: 1 / -1; }
.callout > :is(p, ul, ol, h3, h4, figure, table, pre, blockquote, div) { margin: 0; }
/* On top of the 4px gap, so the label sits closer to the body it
   introduces than two body paragraphs sit to each other — 4px under
   the header, 16px between paragraphs, which is what `.prose p` uses. */
.callout > * + :is(p, ul, ol, h3, h4, figure, table, pre, blockquote, div) { margin-top: 12px; }
.callout ul, .callout ol { padding-inline-start: 20px; }
/* A callout carrying its own bold lead line drops the generated word
   and takes the label slot itself, so it does not say "Note" twice. */
.callout:has(> b:first-child)::before { content: none; }
.callout > b:first-child { align-self: center; font-size: 14.5px; font-weight: 750; color: var(--ink); }

/* Figures. The screenshots are the substance of most of these articles,
   so they get real presentation rather than being left as bare images. */
.prose figure { margin: 30px 0 0; }
.prose figure img {
  display: block; margin: 0 auto; border-radius: var(--radius-lg);
  border: 1px solid var(--cloud); box-shadow: 0 10px 30px rgba(32,48,88,.08);
}
.prose figcaption {
  margin-top: 10px; text-align: center;
  font-size: 14px; line-height: 1.5; color: var(--steel);
}
.prose figure[data-align="left"] img  { margin-left: 0; }
.prose figure[data-align="right"] img { margin-right: 0; }
.prose figure[data-width="25%"] img  { width: 25%; }
.prose figure[data-width="50%"] img  { width: 50%; }
.prose figure[data-width="75%"] img  { width: 75%; }
.prose figure[data-width="100%"] img { width: 100%; }
/* Full-bleed within the article column, for a wide screenshot that would
   otherwise be unreadable at 720px. */
.prose figure[data-align="full"] { margin-inline: calc(var(--full-bleed, 0px) * -1); }

/* A video is a link until somebody asks for it: the article makes no
   third-party request on load, and works with no JavaScript at all.
   site.js upgrades this into a poster with a play button. */
.video-embed {
  margin: 30px 0 0; padding: 0; position: relative;
  border-radius: var(--radius-lg); overflow: hidden;
  background: var(--slab);
  aspect-ratio: 16 / 9;
}
.video-embed > a {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 20px; text-align: center;
  color: #fff; font-weight: 650; font-size: 16px; text-decoration: none;
  background-size: cover; background-position: center;
}
.video-embed > a::before {
  content: ""; width: 62px; height: 62px; border-radius: 50%;
  background: rgba(255,255,255,.94) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23203058'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E") center/26px no-repeat;
  box-shadow: 0 8px 26px rgba(0,0,0,.35);
  transition: transform .18s var(--ease-standard);
}
.video-embed > a:hover::before { transform: scale(1.08); }
.video-embed > a > span { text-shadow: 0 2px 12px rgba(0,0,0,.6); }
.video-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Tables. The imported ones had no header row markup at all; the importer
   promotes the first row, and this is what makes that visible. */
.prose table {
  width: 100%; margin: 26px 0 0; border-collapse: collapse; font-size: 15.5px;
}
.prose thead th {
  text-align: left; background: var(--mist); color: var(--ink); font-weight: 700;
  border-bottom: 2px solid var(--cloud);
}
.prose th, .prose td {
  padding: 11px 14px; border: 1px solid var(--cloud); vertical-align: top;
}
.prose td > p:first-child { margin-top: 0; }
/* A wide table scrolls inside its own box rather than pushing the page
   sideways — the overflow the audit fails a page for. */
.prose .table-scroll { overflow-x: auto; margin: 26px 0 0; -webkit-overflow-scrolling: touch; }
.prose .table-scroll > table { margin: 0; }

/* Collapsible sections. */
.prose details {
  margin: 26px 0 0; border: 1px solid var(--cloud); border-radius: var(--radius-lg);
  padding: 16px 20px; background: var(--panel);
}
.prose details[open] { background: var(--white); }
.prose summary {
  cursor: pointer; font-weight: 700; color: var(--ink); list-style: none;
  display: flex; align-items: center; gap: 10px;
}
.prose summary::-webkit-details-marker { display: none; }
.prose summary::before {
  content: ""; width: 8px; height: 8px; flex-shrink: 0;
  border-right: 2px solid var(--steel); border-bottom: 2px solid var(--steel);
  transform: rotate(-45deg); transition: transform .18s var(--ease-standard);
}
.prose details[open] > summary::before { transform: rotate(45deg); }

/* Code. */
.prose pre {
  margin: 24px 0 0; padding: 16px 18px; overflow-x: auto;
  background: var(--slab); color: var(--slab-ink); border-radius: var(--radius-lg);
  font-family: var(--font-mono); font-size: 13.5px; line-height: 1.7;
}
.prose :not(pre) > code {
  font-family: var(--font-mono); font-size: .88em;
  background: var(--mist); border: 1px solid var(--cloud);
  border-radius: 6px; padding: 1px 6px; color: var(--ink);
}
/* A quote gets a hanging quotation mark rather than the banned cyan
   bar. Logical properties throughout, so Arabic mirrors it for free.
   Italic is dropped: at 17.5px it was doing the same job as the
   indent and the mark, three times over. */
.prose blockquote {
  position: relative; margin: 28px 0 0;
  padding-block: 2px; padding-inline: 38px 0;
  font-size: 17.5px; line-height: 1.6; font-weight: 500; color: var(--ink);
}
.prose blockquote::before {
  content: "\201C"; position: absolute; inset-inline-start: 0; top: -10px;
  font-size: 46px; line-height: 1; font-weight: 800; color: var(--ice);
}
.prose h4 { font-size: 17px; margin: 26px 0 0; color: var(--ink); }
.prose hr { margin: 32px 0 0; border: 0; border-top: 1px solid var(--cloud); }
/* An ordered list that resumes a sequence — the importer moves `start` here
   from the <li> HelpDocs had put it on. */
.prose ol[start] { margin-top: 20px; }

/* ------------------------------------------------------------
   Help Center
   ------------------------------------------------------------ */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.hc-hero {
  padding: clamp(46px, 6vw, 84px) 0 clamp(34px, 4vw, 54px);
  background: linear-gradient(180deg, var(--white) 0%, var(--mist) 100%);
}
.hc-hero h1 { font-size: clamp(30px, 4.2vw, 46px); margin: 0 0 12px; }

/* A hero with artwork: copy on the left, the illustration bleeding off the
   right edge. Used by the Help Center hub AND by every category page, which is
   why it is `.hero-art` rather than a hub-only class — the category header
   carries that category's own card image.

   The art is absolutely positioned rather than a grid column so it can run past
   the .wrap to the viewport edge; the section clips it, which is also what
   keeps it out of the page's scrollWidth (audit.mjs measures horizontal
   overflow and a bleeding image is the classic way to trip it).

   min-height is the framing control. Without it the section is only as tall as
   its copy, the art column ends up far wider than 16:9, and `cover` crops the
   top off — which is exactly how the lighthouse lost its lamp on a wide screen.
   Tying the height to vw keeps the column near the source's own aspect at every
   width.

   It clips SIDEWAYS ONLY. `overflow: hidden` clipped both axes, and the search
   results panel hangs out of the bottom of this section — so the suggestions
   were cut off at the hero's edge and read as sitting behind the page. The
   one-axis form is `overflow-x: clip`, not `hidden`: setting `overflow-x:
   hidden` with `overflow-y: visible` makes the browser compute the visible axis
   to `auto` instead, which clips it again and adds a scrollbar. `clip` is the
   value that lets the other axis stay genuinely visible. */
.hero-art {
  position: relative;
  overflow-x: clip;
  overflow-y: visible;
  min-height: clamp(300px, 27vw, 480px);
}
.hero-art .wrap { position: relative; z-index: 1; }
.hero-art .hero-copy { max-width: 540px; text-align: left; }
.hero-art .hc-search { margin-inline: 0; }
.hero-shot {
  position: absolute; inset: 0 0 0 auto; margin: 0;
  width: min(56%, 980px); pointer-events: none;
}
/* Feathered with a MASK, not a white scrim painted on top. The scrim was the
   first attempt and it left a visible vertical seam: the section behind is a
   white-to-mist vertical gradient, so a flat white overlay matched it at the
   top of the hero and not at the bottom. Masking fades the image itself to
   transparent and lets whatever is behind show through, which cannot seam. */
.hero-shot img {
  width: 100%; height: 100%; object-fit: cover; object-position: 60% 38%; display: block;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.5) 22%, #000 58%);
  mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.5) 22%, #000 58%);
}

@media (max-width: 900px) {
  /* On a phone the art stays IN the header rather than becoming a separate
     banner under it — Andre's call. It fills the section and the copy sits on
     top, so the scrim has to do the legibility work that the side-by-side
     layout does on desktop: near-opaque under the text on the left, thinning
     to the right where the subject is. Measured with tools/contrast.mjs. */
  /* The art takes the lower band of the header and bleeds to both edges, with
     its top edge dissolved into the copy above — one header block, not a
     header plus a floating picture.

     Two earlier attempts are worth not repeating. Covering the whole section
     and scrimming it left-to-right ran the lead straight across the lighthouse.
     Scrimming it top-to-bottom instead fixed the text and hid the subject:
     on a portrait container `cover` scales by HEIGHT, so the full height of the
     source is always shown and the lighthouse — a quarter of the way down the
     source — lands under the opaque part of any vertical scrim no matter what
     object-position says. Giving the art its own shorter band is what actually
     puts the subject in clear space. */
  .hero-art { min-height: clamp(440px, 122vw, 580px); padding-bottom: 0; }
  .hero-shot { position: absolute; inset: auto 0 0 0; width: 100%; height: 56%; }
  .hero-shot img {
    object-position: 74% 50%;
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 26%);
    mask-image: linear-gradient(180deg, transparent 0%, #000 26%);
  }
  .hero-art .hero-copy { max-width: none; }
}

.hc-search { position: relative; max-width: 620px; margin: clamp(22px,3vw,34px) auto 0; }
.hc-search input {
  width: 100%; padding: 17px 22px; font-size: 16.5px; font-family: inherit;
  color: var(--ink); background: var(--white);
  border: 1px solid var(--cloud); border-radius: var(--radius-pill);
  box-shadow: 0 8px 26px rgba(32,48,88,.07);
}
.hc-search input::placeholder { color: var(--steel); }
.hc-search input:focus-visible {
  outline: none; border-color: var(--echo-cyan); box-shadow: var(--focus-ring);
}
.hc-results {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + 10px);
  max-height: 60vh; overflow-y: auto; text-align: left;
  background: var(--white); border: 1px solid var(--cloud);
  border-radius: var(--radius-xl); box-shadow: 0 18px 50px rgba(32,48,88,.16);
  padding: 8px;
}
.hc-results[hidden] { display: none; }
.hc-result { display: block; padding: 11px 14px; border-radius: var(--radius-md); }
.hc-result:hover, .hc-result:focus-visible { background: var(--mist); }
.hc-result b { display: block; color: var(--ink); font-weight: 650; }
.hc-result span { display: block; font-size: 13.5px; color: var(--slate); margin-top: 2px; }
.hc-result-snippet { line-height: 1.5; }
.hc-result em { font-style: normal; background: var(--ice); border-radius: 3px; padding: 0 2px; }
.hc-result-cat { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--steel); }
.hc-no-results { padding: 14px; color: var(--slate); font-size: 14.5px; }

.hc-cats {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
}
/* On a wide screen the auto-fill grid leaves the last row short — seven
   categories land as four then three, with a card's worth of white space
   hanging off the end. Above 1080px the grid becomes twelve columns and the
   renderer hands each card a span, widening the last row to fill the line.
   The spans are computed in help-render.mjs rather than written here as
   :nth-child rules, because the right answer depends on how many categories
   there are and that changes in the panel, not in this file. */
@media (min-width: 1081px) {
  .hc-cats { grid-template-columns: repeat(12, 1fr); }
  .hc-cat { grid-column: var(--col, auto) / span var(--span, 3); }
}
.hc-cat {
  display: block; padding: 26px; border-radius: var(--radius-2xl);
  border: 1px solid var(--cloud); background: var(--white);
  transition: transform .2s var(--ease-standard), box-shadow .2s var(--ease-standard), border-color .2s var(--ease-standard);
}
.hc-cat:hover {
  transform: translateY(-3px); border-color: var(--echo-cyan);
  box-shadow: 0 16px 40px rgba(93,174,227,.18);
}
.hc-cat h3 { margin: 16px 0 6px; font-size: 19px; color: var(--ink); }
.hc-cat p { color: var(--slate); margin: 0; }
.hc-cat-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: var(--radius-lg);
  background: var(--ice); color: var(--action-ink);
}
.hc-icon { width: 22px; height: 22px; }
.hc-cat-count {
  margin-top: 14px !important; font-size: 12px; font-weight: 650;
  letter-spacing: .08em; text-transform: uppercase; color: var(--steel) !important;
}

.hc-list { display: grid; gap: 2px; }
.hc-row {
  display: flex; align-items: center; gap: 18px; padding: 20px 22px;
  border-radius: var(--radius-lg); border: 1px solid transparent;
  transition: background .18s var(--ease-standard), border-color .18s var(--ease-standard);
}
.hc-row:hover { background: var(--mist); border-color: var(--cloud); }
.hc-row-main { flex: 1; min-width: 0; }
.hc-row-title { display: block; font-size: 17px; font-weight: 650; color: var(--ink); }
.hc-row-sub { display: block; margin-top: 4px; font-size: 14.5px; line-height: 1.55; color: var(--slate); }
.hc-row-go { color: var(--steel); font-size: 20px; flex-shrink: 0; }
.hc-row:hover .hc-row-go { color: var(--action-ink); }

.hc-article-head { padding: clamp(30px, 4vw, 52px) 0 clamp(20px, 2.4vw, 30px); background: var(--mist); }
.hc-article-head h1 { font-size: clamp(27px, 3.4vw, 40px); margin: 14px 0 0; }
.hc-article-head .lead { margin-top: 12px; }
.hc-meta { margin: 14px 0 0; font-size: 13.5px; color: var(--steel); }

.hc-layout { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: clamp(28px, 5vw, 64px); align-items: start; }
.hc-layout-single { grid-template-columns: minmax(0, 1fr); max-width: 760px; }
.hc-rail { position: relative; }
.hc-prose { max-width: 720px; }
.hc-prose > *:first-child { margin-top: 0; }
.toc a.on { color: var(--ink); font-weight: 700; }

.hc-helpful-wrap { max-width: 760px; }
.hc-helpful {
  border: 1px solid var(--cloud); border-radius: var(--radius-2xl);
  padding: clamp(22px, 3vw, 30px); background: var(--mist);
}
.hc-helpful p { margin: 0 0 6px; }
.hc-helpful .btn { margin-top: 16px; }

/* The two votes. Deliberately not a tinted panel with a coloured bar down
   one edge — see CLAUDE.md — so the buttons carry themselves on the white
   surface and their border, and the only colour arrives on hover. */
.hc-helpful-buttons { display: flex; gap: 10px; margin-top: 14px; }
.hc-helpful-buttons[hidden] { display: none; }
.hc-vote {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 20px; border-radius: var(--radius-xl);
  border: 1px solid var(--cloud); background: var(--white);
  color: var(--ink); font: inherit; font-weight: 600; font-size: 15px;
  cursor: pointer;
  transition: border-color .18s var(--ease-standard), color .18s var(--ease-standard),
    transform .18s var(--ease-standard);
}
.hc-vote svg { width: 18px; height: 18px; }
.hc-vote:hover { border-color: var(--echo-cyan); transform: translateY(-1px); }
.hc-vote:focus-visible { outline: 2px solid var(--echo-cyan); outline-offset: 2px; }

.hc-helpful-more { margin-top: 16px; }
/* A class that sets `display` needs a [hidden] companion, or `node.hidden =
   true` silently does nothing — an author declaration beats the user agent's
   [hidden]{display:none}. This cost a day on the contact form's conditional
   fields; it is not costing another one here. */
.hc-helpful-more[hidden] { display: none; }
.hc-helpful-more label { display: block; margin-bottom: 8px; font-weight: 600; font-size: 15px; }
.hc-helpful-more textarea {
  width: 100%; padding: 12px 14px; border-radius: var(--radius-lg);
  border: 1px solid var(--cloud); background: var(--white);
  font: inherit; font-size: 15px; color: var(--ink); resize: vertical;
}
.hc-helpful-more textarea:focus-visible { outline: 2px solid var(--echo-cyan); outline-offset: 1px; }
.hc-helpful-more .cta-row { margin-top: 14px; align-items: center; gap: 16px; }
.hc-helpful-thanks { margin-top: 14px; font-weight: 600; }
.hc-helpful-failed { margin-top: 12px; color: var(--bad, #9a2b2b); }

/* The article's image, beside the title rather than behind it (2026-08-13).
   It used to be a full-bleed background under a heavy navy scrim with the type
   reversed out; that suited the painterly abstracts the Help Center carried and
   ruins the light drawn miniatures that replaced them. Framed, it also cannot
   fight the words — so an uploaded photograph is safe here too, which the scrim
   was only ever guessing at. */
.hc-head-grid { display: grid; gap: 26px; align-items: center; }
.hc-head-text { min-width: 0; }
/* No border and no fill of its own: the drawn miniatures carry their own mist
   ground and their own white card, and a frame around that is a third nested
   rounded rectangle doing nothing. */
.hc-head-art { margin: 0; border-radius: var(--radius-xl); overflow: hidden; }
.hc-head-art img { display: block; width: 100%; height: auto; }
@media (min-width: 900px) {
  .hc-article-head-art .hc-head-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 360px); gap: 40px; }
}

.hc-related-title { font-size: clamp(20px, 2vw, 26px); margin: 0 0 20px; }
.hc-cards { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.hc-card {
  display: block; padding: 22px; border-radius: var(--radius-xl);
  background: var(--white); border: 1px solid var(--cloud);
  transition: border-color .18s var(--ease-standard), transform .18s var(--ease-standard);
}
.hc-card:hover { border-color: var(--echo-cyan); transform: translateY(-2px); }
/* Category listings render articles as cards with an image slot (2026-08-05).
   The image is the article's own header image; a card without one carries the
   category icon on an ice tile instead — an honest blank, never a fake shot.
   Framing follows the HelpDocs pattern Andre pointed at: the image bleeds to
   the card's edges and the text sits in a padded body below — so the media
   variants zero the card's own padding rather than inseting the image. */
.hc-card-media { padding: 0; overflow: hidden; }
.hc-card-shot { display: block; aspect-ratio: 16/9; overflow: hidden; background: var(--ice); }
.hc-card-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hc-card-shot-empty { display: grid; place-items: center; color: var(--echo-cyan); }
.hc-card-shot-empty svg { width: 30px; height: 30px; opacity: .8; }
.hc-card-body { display: block; padding: 16px 20px 20px; }
.hc-cat-media { padding: 0; overflow: hidden; }
.hc-cat-shot { display: block; aspect-ratio: 16/9; overflow: hidden; background: var(--ice); }
.hc-cat-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hc-cat-media .hc-cat-body { display: block; padding: 18px 24px 24px; }
.hc-cat-media h3 { margin-top: 0; }
.hc-card h4 { margin: 0 0 6px; font-size: 16.5px; color: var(--ink); }
.hc-card p { margin: 0; color: var(--slate); }

@media (max-width: 900px) {
  /* The rail becomes a disclosure above the article rather than a column,
     because 220px of sticky navigation on a 390px screen is most of it. */
  .hc-layout { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .hc-rail { position: static; }
  .toc { position: static; padding: 16px 18px; background: var(--mist); border-radius: var(--radius-lg); }
  .toc a { padding-block: 6px; }
}

.toc { position: sticky; top: calc(var(--header-h) + 24px); }
.toc h5 { margin: 0 0 12px; font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--steel); }
/* The contents rail used to be exactly the shape banned on the
   callout: a vertical line down the left of every link, grey for the
   rest and cyan for the one you are on. Position is carried by type
   alone now — weight and ink for the current section, slate for the
   others — which needs no gutter, no line, and no RTL override. */
.toc a { display: block; padding-block: 7px; font-size: 14.5px; color: var(--slate); }
.toc a:hover { color: var(--action-ink); }
[dir="rtl"] ul.ticks li { padding-left: 0; padding-right: 28px; }
[dir="rtl"] ul.ticks li::before { left: auto; right: 0; }
/* `.demo-note` had an override here for its left bar. The bar is gone
   and the card is symmetrical, so there is nothing left to mirror. */

/* ============================================================
   Status page
   ============================================================ */
.status-hero { border-radius: var(--radius-panel); padding: clamp(26px, 3.4vw, 44px); background: var(--success-tint); border: 1px solid rgba(34,176,125,.28); }
.status-hero.warn { background: var(--warning-tint); border-color: rgba(245,184,65,.4); }
.status-board { margin-top: 26px; display: grid; gap: clamp(40px, 5vw, 64px); }
/* A grid rather than a wrapping row since 2026-09-27: a partner row carries a
   description, sometimes the vendor's own words for what is wrong, and a
   ninety-day uptime strip under its name and state. */
.status-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: 16px; row-gap: 4px; padding: 17px 0; border-bottom: 1px solid var(--cloud); }
.status-row:first-child, .status-group + .status-row { border-top: 1px solid var(--cloud); }
.status-group { font-size: 16px; font-weight: 650; color: var(--ink); margin: 34px 0 12px; }
.status-group:first-child { margin-top: 0; }
.status-name { font-size: 15.5px; font-weight: 650; color: var(--ink); }
.status-desc { grid-column: 1 / -1; font-size: 14px; line-height: 1.5; color: var(--slate); }
.status-source { color: var(--slate); text-decoration: underline; text-underline-offset: 2px; white-space: nowrap; }
.status-source:hover { color: var(--ink); }
.status-detail { grid-column: 1 / -1; font-size: 14px; line-height: 1.5; color: var(--ink); }
.status-state { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 650; color: var(--good-ink); }
.status-state i { width: 8px; height: 8px; border-radius: 50%; background: var(--success); display: block; }
.status-state.warn { color: var(--warning-ink); }
.status-state.warn i { background: var(--warning); }
.status-state.out { color: var(--bad-ink); }
.status-state.out i { background: var(--error); }
.status-state.nd { color: var(--slate); }
.status-state.nd i { background: var(--steel); }

/* The uptime strip: one bar per UTC day, oldest on the left. A day nothing
   was checked is a hairline-grey bar, never a green one. On a phone the strip
   shows thirty days and the figure beside it says thirty days. */
.status-uptime { grid-column: 1 / -1; margin-top: 10px; }
.status-bars { display: flex; gap: 2px; height: 28px; }
.status-bars i { flex: 1 1 0; min-width: 0; border-radius: 2px; background: var(--success); }
.status-bars i.nd { background: var(--cloud); }
.status-bars i.dg { background: color-mix(in srgb, var(--warning) 50%, var(--white)); }
.status-bars i.mt { background: color-mix(in srgb, var(--deep-blue) 45%, var(--white)); }
.status-bars i.po { background: var(--warning); }
.status-bars i.mo { background: var(--error); }
.status-uptime-meta { display: flex; justify-content: space-between; gap: 12px; margin-top: 7px; font-size: 13px; color: var(--slate); }
.status-uptime-meta .w30 { display: none; }
@media (max-width: 640px) {
  .status-bars i:nth-child(-n+60) { display: none; }
  .status-uptime-meta .w90 { display: none; }
  .status-uptime-meta .w30 { display: inline; }
}

/* ============================================================
   Reveal on scroll
   ============================================================ */
.reveal { opacity: 0; transform: translateY(16px); transition: opacity .6s var(--ease-standard), transform .6s var(--ease-standard); }
.reveal.in { opacity: 1; transform: none; }
/* Somebody who has asked for less motion should not have to scroll a figure
   into view before it fills in. Under reduced motion the sized figures show
   their final state immediately, whatever the observer has or has not done. */
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
  .has-reveal .reveal:not(.in) .gapbar-fill { width: var(--w, 100%); }
  .has-reveal .reveal:not(.in) .funnel-band { max-width: var(--w, 100%); }
}

/* ============================================================
   Builder imagery & device sections — markup in
   tools/marketing-blocks.mjs. The scrim on .image-hero is part
   of the contract: white text over photography passes AA only
   because the gradient underneath it is guaranteed.
   ============================================================ */
.image-hero { position: relative; background-size: cover; background-position: center; }
.image-hero::before { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(11,18,32,.5), rgba(11,18,32,.74)); }
.image-hero > .wrap, .image-hero > .wrap-md { position: relative; padding-top: clamp(84px, 12vw, 180px); padding-bottom: clamp(84px, 12vw, 180px); }
.image-hero.is-full > .wrap, .image-hero.is-full > .wrap-md { min-height: min(86vh, 860px); display: flex; flex-direction: column; justify-content: center; }
.image-hero .eyebrow { color: rgba(255,255,255,.85); }
.image-hero h1, .image-hero .ih-title { color: #fff; font-size: clamp(34px, 5vw, 62px); line-height: 1.06; letter-spacing: -0.02em; }
.image-hero .lead { color: rgba(255,255,255,.93); }
.image-hero .cta-note { color: rgba(255,255,255,.82); }

.gallery-grid { display: grid; gap: clamp(10px, 1.6vw, 18px); }
.gallery-grid img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: var(--gallery-ratio, 4/3); border-radius: var(--radius-lg); display: block; box-shadow: var(--shadow-card); }
/* A gallery's settings.phone_strip: on a phone a row of three would be three
   thumbnails, so it scrolls sideways instead, bleeding to the screen edges
   with the next photo showing. The padding at the foot keeps the card shadow
   from being clipped by the scroll box. */
@media (max-width: 720px) {
  .gallery-grid.is-strip {
    display: flex; overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
    margin: 0 calc(-1 * clamp(20px, 3.5vw, 40px)); padding: 0 clamp(20px, 3.5vw, 40px) 14px;
    scroll-padding: 0 clamp(20px, 3.5vw, 40px); scrollbar-width: none;
  }
  .gallery-grid.is-strip::-webkit-scrollbar { display: none; }
  .gallery-grid.is-strip img { flex: 0 0 76%; height: auto; scroll-snap-align: start; }
}

/* A label/value card with a photograph across its top (a split's `stats`
   aside with `photo`). The card keeps its surface, radius and shadow; the
   picture runs to its edges and the words keep the card's own padding. */
.card.card-photo { padding: 0; overflow: hidden; }
.card-photo-img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; }
.card-photo-body { padding: clamp(22px, 2.4vw, 30px); }

.device { margin: 0 auto; }
.device-screen { overflow: hidden; background: #0b1220; display: block; }
.device-screen img, .device-screen video { width: 100%; height: 100%; object-fit: cover; display: block; }
.device-phone { width: min(320px, 86%); border-radius: 44px; padding: 14px; background: #0e1626; box-shadow: var(--shadow-float), inset 0 0 0 2px rgba(255,255,255,.08); }
.device-phone .device-screen { border-radius: 32px; aspect-ratio: 9 / 19.5; }
.device-laptop { width: min(720px, 100%); }
.device-laptop .device-body { border-radius: 18px 18px 0 0; padding: 16px 16px 0; background: #0e1626; box-shadow: var(--shadow-float), inset 0 0 0 2px rgba(255,255,255,.07); }
.device-laptop .device-screen { border-radius: 8px 8px 0 0; aspect-ratio: 16 / 10; }
.device-laptop .device-base { height: 15px; border-radius: 0 0 16px 16px; background: linear-gradient(180deg, #1b2740, #0c1424); box-shadow: var(--shadow-card); }

/* ============================================================
   The blog — listing cards and the reading scale. Markup in
   tools/blog-render.mjs; bodies reuse .prose (figures, callouts,
   the hanging-mark blockquote) at a larger, essay-grade measure.
   ============================================================ */
.blog-wrap { max-width: 720px; margin: 0 auto; padding: 0 22px; }
.blog-title { font-size: clamp(32px, 4.6vw, 54px); line-height: 1.08; letter-spacing: -0.022em; }
.blog-dek { font-size: clamp(18px, 1.9vw, 22px); line-height: 1.5; color: var(--slate); margin-top: 14px; }
.blog-byline { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; margin-top: 22px; font-size: 13.5px; color: var(--steel); }
.blog-hero-img { width: 100%; height: auto; display: block; border-radius: var(--radius-lg); box-shadow: var(--shadow-card); margin-top: clamp(26px, 3.4vw, 44px); }
.blog-prose { max-width: none; font-size: 19px; line-height: 1.78; }
.blog-prose h2 { font-size: clamp(24px, 2.6vw, 31px); margin-top: 52px; }
.blog-prose h3 { font-size: 21px; margin-top: 38px; }
.blog-prose p { margin-top: 20px; }

.blog-feature { display: block; color: inherit; text-decoration: none; }
.blog-feature img { width: 100%; aspect-ratio: 21 / 10; object-fit: cover; border-radius: var(--radius-lg); box-shadow: var(--shadow-card); display: block; }
.blog-feature h2 { font-size: clamp(26px, 3vw, 38px); letter-spacing: -0.018em; margin-top: 20px; }
.blog-feature:hover h2 { color: var(--action-ink); }

.blog-grid { display: grid; gap: clamp(22px, 3vw, 36px); grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); margin-top: clamp(30px, 4vw, 52px); }
.blog-card { display: block; color: inherit; text-decoration: none; }
.blog-card img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; border-radius: var(--radius-md); box-shadow: var(--shadow-sm); display: block; }
.blog-card h3 { font-size: 19px; line-height: 1.3; margin-top: 14px; }
.blog-card:hover h3 { color: var(--action-ink); }
.blog-card p { font-size: 14.5px; color: var(--slate); margin-top: 6px; }

/* The closing band under a release — "What this release means for your
   ministry". A hairline card with the site's own icon-tile; colour lives in
   the 32px tile and nowhere else. Replaces the old .release-more fold. */
.release-meaning {
  display: flex; gap: 14px; align-items: flex-start;
  margin-top: 22px; padding: clamp(18px, 2.2vw, 26px);
  border: 1px solid var(--cloud); border-radius: var(--radius-lg); background: var(--white);
}
.release-meaning[hidden] { display: none; }
.release-meaning .icon-tile { flex: 0 0 auto; }
.release-meaning-title { font-size: 17px; margin: 2px 0 8px; }
.release-meaning-body p { margin: 0; }
.release-meaning-body p + p { margin-top: 10px; }

/* ============================================================
   Code blocks on a marketing page — product/graphql.html.
   The Help Center already dresses code inside `.prose`; this is
   the same surface pulled out so a product page can show a real
   query next to its real response without pulling in the whole
   article scale.

   Colour is carried by the ink ground and two token classes, not
   by a tint and a rule down one edge. Both tokens were measured
   against `--ink` #203058: string gold 8.2:1, comment 5.9:1,
   the body #E9EEF7 11.1:1 — all clear of AA.

   `direction: ltr` is deliberate and load-bearing: GraphQL and
   curl are left-to-right whatever the surrounding page is, and
   the Arabic mirror would otherwise scramble every line.
   ============================================================ */
.codeblock {
  margin: 0; border-radius: var(--radius-lg); overflow: hidden;
  background: var(--slab); box-shadow: var(--shadow-card);
}
.codeblock-head {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 18px; border-bottom: 1px solid rgba(255,255,255,.10);
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--slab-dim);
}
.codeblock-head span { margin-inline-start: auto; text-transform: none; letter-spacing: .02em; font-weight: 500; }
.codeblock pre {
  margin: 0; padding: 16px 18px; overflow-x: auto; direction: ltr; text-align: left;
  color: #E9EEF7; font-family: var(--font-mono); font-size: 13px; line-height: 1.72;
  -webkit-text-size-adjust: 100%;
}
.codeblock pre code { font: inherit; color: inherit; background: none; border: 0; padding: 0; }
.tok-s { color: #F2C879; }   /* strings and numbers */
.tok-c { color: #9FB0CC; }   /* comments */
.tok-o { color: #7FD0F5; }   /* operation keyword and field alias */

/* A query and the answer it returns, read as one thing. Stacked on a
   phone (the query first, which is the order you write them in), side
   by side once there is room for two 40-character lines. */
.code-pair { display: grid; gap: 14px; }
@media (min-width: 940px) { .code-pair { grid-template-columns: 1fr 1fr; align-items: start; } }

/* Inline code outside `.prose` — a field name in a table cell or a
   sentence. Same shape as the article version. */
.code-inline {
  font-family: var(--font-mono); font-size: .88em; direction: ltr; unicode-bidi: isolate;
  background: var(--mist); border: 1px solid var(--cloud);
  border-radius: 6px; padding: 1px 6px; color: var(--ink);
}
.bg-mist .code-inline { background: var(--white); }

/* ---------------------------------------------------------------------------
   Full-screen view for a Help Center picture
   ---------------------------------------------------------------------------
   Help Center screenshots are admin screens shrunk into a text column. Clicking
   one opens it at whatever size the viewport allows. Built in site.js, styled
   here; both are inert on any page without .hc-prose.
--------------------------------------------------------------------------- */
.hc-prose figure img { cursor: zoom-in; transition: box-shadow .16s ease; }
.hc-prose figure img:hover,
.hc-prose figure img:focus-visible { box-shadow: 0 0 0 3px var(--echo-cyan, #5DAEE3); outline: none; }

body.is-lightboxed { position: fixed; left: 0; right: 0; width: 100%; overflow: hidden; }

.hc-lightbox {
  position: fixed; inset: 0; z-index: 3000;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(16px, 4vw, 48px);
  background: rgba(9, 17, 30, .88);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  animation: hcLightboxIn .14s ease-out;
}
@keyframes hcLightboxIn { from { opacity: 0 } to { opacity: 1 } }
@media (prefers-reduced-motion: reduce) {
  .hc-lightbox { animation: none; }
  .hc-prose figure img { transition: none; }
}

.hc-lightbox-frame {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  max-width: 100%; max-height: 100%;
}
.hc-lightbox-frame img {
  max-width: 100%;
  /* Room for the caption under it without the picture ever overflowing. */
  max-height: calc(100vh - clamp(96px, 18vw, 160px));
  width: auto; height: auto;
  object-fit: contain;
  background: #fff; border-radius: 8px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .45);
}
.hc-lightbox-caption {
  margin: 0; max-width: 70ch; text-align: center;
  color: #e8eef7; font-size: 14px; line-height: 1.5;
}
.hc-lightbox-close {
  position: absolute; top: 14px; right: 16px;
  width: 44px; height: 44px; /* a real touch target */
  display: flex; align-items: center; justify-content: center;
  font-size: 30px; line-height: 1;
  color: #fff; background: rgba(255, 255, 255, .12);
  border: 0; border-radius: 50%; cursor: pointer;
}
.hc-lightbox-close:hover { background: rgba(255, 255, 255, .22); }
.hc-lightbox-close:focus-visible { outline: 3px solid var(--echo-cyan, #5DAEE3); outline-offset: 2px; }

/* ---------------------------------------------------------------------------
   The category's art, washed across an article head
   ---------------------------------------------------------------------------
   Every article in a category carries its category's picture behind the header,
   so the category is recognisable from any article in it.

   It never sits under the words. The head's text has to stay legible against
   art that no one has measured, and the only reliable way to promise that is to
   keep the art out from under it: the wash is anchored to the right, faded, and
   a scrim runs across the left where the title and breadcrumb are. On a phone
   there is no room for both, so the wash goes.
--------------------------------------------------------------------------- */
.hc-article-head-wash { position: relative; overflow: hidden; }
.hc-article-head-wash > .wrap { position: relative; z-index: 1; }

.hc-head-wash {
  position: absolute; inset: 0;
  background-image: var(--hc-wash);
  background-repeat: no-repeat;
  background-position: right -4% center;
  background-size: auto 128%;
  opacity: .16;
  pointer-events: none;
  z-index: 0;
}
/* The scrim. Solid under the text column, clearing only over the right third,
   so the measured contrast of the title is the same as it was with no art. */
.hc-head-wash::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(
    to right,
    var(--hc-head-bg, #f7f9fc) 0%,
    var(--hc-head-bg, #f7f9fc) 46%,
    rgba(247, 249, 252, .55) 68%,
    rgba(247, 249, 252, 0) 100%);
}
@media (max-width: 900px) {
  /* No room to keep the art clear of the words, so it does not appear. */
  .hc-head-wash { display: none; }
}

/* ============================================================
   EchoAnalyst premium blocks — the cinematic reveal (.cine),
   the plan trio (.plan-trio) and the value-math band (.vm).

   The reveal is the site's one Apple-style scroll sequence: a
   deep-navy stage that pins for a few viewport heights while a
   drawn laptop rises, straightens and zooms until its screen,
   a real sample report photographed from the product, fills
   the frame. Everything is progressive enhancement: the markup
   reads top to bottom as a normal page, and only site.js
   adding .is-live turns on the pinning and the transforms, so
   no-JS, reduced-motion and the audit's at-rest pass all see a
   complete static composition.

   The dark surfaces here are deliberately literal and the same
   in both themes, like .reports-hero and .price-band above: a
   permanently dark stage is a drawing, not a themed panel.
   #7FD0F5 and #C9D6EA are the accents the report hero already
   uses on navy.
   ============================================================ */
.cine {
  position: relative;
  background:
    radial-gradient(1100px 540px at 78% -8%, rgba(36, 70, 127, .55), transparent 70%),
    radial-gradient(900px 480px at 12% 104%, rgba(36, 70, 127, .32), transparent 72%),
    #0A1224;
  color: #F2F6FC;
  overflow: clip;
}
.cine-stage {
  max-width: 1240px; margin: 0 auto;
  padding: clamp(64px, 8vw, 120px) clamp(20px, 3.5vw, 40px) clamp(44px, 5vw, 76px);
}
.cine-copy { max-width: 820px; margin: 0 auto; text-align: center; }
.cine-eyebrow {
  display: inline-flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: center;
  font-size: 13px; font-weight: 750; letter-spacing: .14em; text-transform: uppercase; color: #7FD0F5;
}
.cine-badge {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .1em;
  color: #C9D6EA; border: 1px solid rgba(255, 255, 255, .28);
  border-radius: var(--radius-pill); padding: 4px 11px;
}
.cine-badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: #7FD0F5; }
.cine-h {
  margin: 18px 0 0; color: #fff;
  /* Sized so "Every conversation." holds one line down to a 390px phone. */
  font-size: clamp(36px, 6.5vw, 84px); line-height: 1.04;
  letter-spacing: -0.035em; font-weight: 800; text-wrap: balance;
}
.cine-copy .cine-h:first-child { margin-top: 0; }
.cine-lead {
  margin: clamp(18px, 2.2vw, 26px) auto 0; max-width: 640px;
  font-size: clamp(16.5px, 1.6vw, 20px); line-height: 1.55; color: #C9D6EA; text-wrap: pretty;
}
.cine-lead b { color: #fff; }
.cine-hint {
  margin: clamp(22px, 3vw, 34px) 0 0; font-size: 12.5px; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase; color: #8B9BBD;
}
.cine-beat { margin-top: clamp(48px, 6vw, 84px); }
.cine-beat h2 { margin: 0; color: #fff; font-size: clamp(26px, 3.2vw, 44px); letter-spacing: -0.025em; line-height: 1.12; text-wrap: balance; }
.cine-beat p { margin: 14px auto 0; max-width: 580px; font-size: clamp(15.5px, 1.4vw, 18px); line-height: 1.55; color: #C9D6EA; }

/* The laptop: a drawn device, face on — a dark bezel around the real
   screenshot and a slim aluminium base. It is ours to draw (the screen
   content is the product's own report), so no trademark rules apply. */
.cine-laptop { position: relative; width: min(88vw, 920px); margin: clamp(44px, 5.5vw, 72px) auto 0; }
.cine-lid {
  display: block; position: relative;
  background: #0D1118; border: 1px solid rgba(255, 255, 255, .14);
  border-radius: clamp(12px, 1.4vw, 20px);
  padding: clamp(9px, 1.1vw, 16px);
  box-shadow: 0 46px 130px rgba(2, 6, 16, .7), 0 10px 34px rgba(2, 6, 16, .5);
}
.cine-lid img {
  /* height:auto lets aspect-ratio beat the img's height attribute. */
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 10;
  object-fit: cover; object-position: top;
  border-radius: clamp(5px, .6vw, 9px);
  background: #fff;
}
.cine-base {
  display: block; height: clamp(9px, 1.2vw, 16px);
  margin: 0 calc(-1 * clamp(14px, 2vw, 30px));
  background: linear-gradient(180deg, #39415A 0%, #232A3E 55%, #161C2C 100%);
  border-radius: 3px 3px clamp(9px, 1.2vw, 16px) clamp(9px, 1.2vw, 16px);
}
.cine-base::before {
  content: ""; display: block; width: clamp(90px, 12vw, 150px); height: 42%;
  margin: 0 auto; background: rgba(10, 14, 24, .5);
  border-radius: 0 0 10px 10px;
}
.cine-cap {
  margin: clamp(16px, 2vw, 24px) auto 0; text-align: center;
  font-size: 13px; font-weight: 650; letter-spacing: .04em; color: #8B9BBD;
}
.cine-close { padding: clamp(28px, 3.5vw, 48px) 0 clamp(56px, 7vw, 96px); }
.cine-close .cta-row { justify-content: center; }
.cine-close .link-arrow { color: #7FD0F5; }
.cine-note { margin: 16px auto 0; max-width: 560px; text-align: center; font-size: 13.5px; line-height: 1.6; color: #8B9BBD; }

/* The live (scroll-driven) state. site.js adds .is-live only when JS is
   running and the visitor has not asked for reduced motion. The stage pins;
   the copy layers stack in the centre; the laptop is driven by transform.
   Heights and opacities are set inline by the driver every frame. */
.cine.is-live { min-height: 0; }
.cine.is-live .cine-track { height: 420vh; }
.cine.is-live .cine-stage {
  position: sticky; top: 0; height: 100dvh; max-width: none;
  padding: 0; overflow: clip;
}
.cine.is-live .cine-copy {
  position: absolute; inset: 0; z-index: 2; margin: 0;
  /* inset:0 plus the base rule's max-width anchored the box to the LEFT edge
     — the copy read off-centre. The stage owns the width here. */
  max-width: none;
  display: grid; place-content: center; justify-items: center;
  padding: 0 clamp(20px, 3.5vw, 40px);
  pointer-events: none;
}
.cine.is-live .cine-beat {
  margin: 0; place-content: start center;
  padding-top: clamp(44px, 9vh, 110px);
}
.cine.is-live .cine-laptop {
  position: absolute; left: 50%; top: 50%; z-index: 1;
  width: min(78vw, 880px); margin: 0;
  transform: translate(-50%, -50%);
  will-change: transform;
}
@media (max-width: 640px) {
  /* A phone's stage is tall and narrow — a fuller device keeps the resting
     beat from floating in empty navy. */
  .cine.is-live .cine-laptop { width: 92vw; }
}
.cine.is-live .cine-cap {
  position: absolute; left: 50%; bottom: clamp(18px, 3vh, 34px); z-index: 2;
  transform: translateX(-50%);
  margin: 0; opacity: 0; pointer-events: none;
  /* By the time it fades in, the white report fills the frame — the pill
     keeps the label readable over it. */
  background: rgba(10, 18, 36, .8); color: #E7EEF9;
  border-radius: var(--radius-pill); padding: 8px 16px; white-space: nowrap;
}
@media (max-width: 640px) {
  /* Clear of the chat launcher, which owns the phone's bottom-right corner. */
  .cine.is-live .cine-cap { bottom: 96px; max-width: 86vw; white-space: normal; text-align: center; }
}

/* ============================================================
   EchoAnalyst page sections added 2026-08-29 — the rubric, the
   alert tiers and the wall of reports.

   The page sells a paid add-on and had never shown the rubric it
   scores against, the alerts it raises or the reports it makes.
   These three carry that, and only the rubric goes dark: it is
   the engine room of the page and the band that has to look
   expensive. Alerts and reports stay on the site's own light
   surfaces, because a safety section painted like a warning is
   a different message from the one it is making.
   ============================================================ */

/* ---- The rubric: eleven numbered dimensions, deep stage ----
   Named .dims-*, not .rubric-*, because site.css already has a .rubric-grid
   and a .rubric-n belonging to the white paper's own small rubric table. The
   collision was found the same way the .tier one below it was: this block is
   later in the sheet, so at equal specificity it would have silently restyled
   the other component instead of erroring. Check the file before taking a
   class name that describes a concept two sections can both have. */
.dims {
  position: relative;
  background:
    radial-gradient(1200px 620px at 82% -12%, rgba(36, 70, 127, .55), transparent 68%),
    radial-gradient(900px 480px at 8% 108%, rgba(36, 70, 127, .30), transparent 70%),
    #0A1224;
  color: #F2F6FC;
  padding: clamp(64px, 8vw, 116px) 0;
  overflow: clip;
}
.dims-head { max-width: 760px; }
.dims .eyebrow { color: #7FD0F5; }
.dims h2 { color: #fff; margin-top: 12px; }
.dims-lead { margin: 16px 0 0; font-size: clamp(16px, 1.5vw, 19px); line-height: 1.6; color: #C9D6EA; }
.dims-lead b { color: #fff; }
.dims-grid {
  list-style: none; margin: clamp(34px, 4.4vw, 58px) 0 0; padding: 0;
  display: grid; gap: clamp(18px, 2.2vw, 28px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 268px), 1fr));
  align-items: start;
}
.dims-item {
  border-top: 1px solid rgba(255, 255, 255, .16);
  padding-top: clamp(14px, 1.6vw, 20px);
}
.dims-n {
  display: block; font-size: 12.5px; font-weight: 800; letter-spacing: .14em;
  color: #7FD0F5; font-variant-numeric: tabular-nums;
}
.dims-item h3 { margin: 8px 0 0; font-size: clamp(17px, 1.7vw, 20px); letter-spacing: -0.015em; color: #fff; }
.dims-item p { margin: 8px 0 0; font-size: 14.5px; line-height: 1.6; color: #B9C7DE; }
/* Three of the eleven are only scored when their situation arises. That is a
   fact about the rubric, so it is a word, on a hairline — not a tint. */
.dims-when {
  display: inline-block; margin-top: 12px; padding: 3px 10px;
  border: 1px solid rgba(255, 255, 255, .26); border-radius: var(--radius-pill);
  font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: #9FB4D4;
}
.dims-note {
  margin: clamp(32px, 4vw, 52px) 0 0; max-width: 900px;
  font-size: 14.5px; line-height: 1.7; color: #B9C7DE;
  border-top: 1px solid rgba(255, 255, 255, .16); padding-top: clamp(18px, 2.2vw, 26px);
}
.dims-note b { color: #fff; }
.dims-link { margin: 18px 0 0; }
.dims-link .link-arrow { color: #7FD0F5; }

/* ---- The alert tiers ----
   Named .atier-*, not .tier-*: site.css already has a .tier component whose
   `.tier span { flex: 1 1 220px }` collapsed this block's dot to zero width
   the first time it rendered. Nothing errored; the dot simply vanished. */
.atiers { list-style: none; margin: clamp(24px, 3vw, 36px) 0 0; padding: 0; max-width: 880px; }
.atier { display: flex; gap: 16px; align-items: flex-start; padding: clamp(15px, 1.8vw, 20px) 0; border-top: 1px solid var(--cloud); }
.atier:first-child { border-top: 0; padding-top: 0; }
/* Weight down the list, not five hues. Only the top tier is warm; the rest
   step down through the brand blue into the page's own hairline grey. */
.atier-dot { flex: 0 0 auto; margin-top: 6px; border-radius: 50%; width: 14px; height: 14px; background: var(--warning); box-shadow: 0 0 0 5px color-mix(in srgb, var(--warning) 22%, transparent); }
.atier-2 .atier-dot { width: 12px; height: 12px; background: var(--action-ink); box-shadow: none; }
.atier-3 .atier-dot { width: 11px; height: 11px; background: var(--echo-cyan); box-shadow: none; }
.atier-4 .atier-dot { width: 10px; height: 10px; background: var(--steel); box-shadow: none; }
.atier-5 .atier-dot { width: 9px; height: 9px; background: var(--cloud); box-shadow: none; }
.atier-main { min-width: 0; }
.atier-name { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0; font-size: 16.5px; font-weight: 750; color: var(--ink); letter-spacing: -0.01em; }
/* What the tier obliges somebody to do is a WORD, on a hairline. */
.atier-flag {
  padding: 3px 9px; border: 1px solid var(--cloud); border-radius: var(--radius-pill);
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--steel);
}
.atier-body { margin: 6px 0 0; font-size: 14.5px; line-height: 1.6; color: var(--slate); }
.atier-note { margin: clamp(22px, 2.6vw, 30px) 0 0; max-width: 820px; font-size: 14px; line-height: 1.7; color: var(--steel); }

/* ---- The wall of reports ---- */
.rwall {
  list-style: none; margin: clamp(24px, 3vw, 38px) 0 0; padding: 0;
  display: grid; gap: clamp(12px, 1.4vw, 18px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 232px), 1fr));
  align-items: start;
}
.rwall-card {
  background: var(--white); border: 1px solid var(--cloud); border-radius: var(--radius-xl);
  padding: clamp(16px, 1.8vw, 20px); box-shadow: var(--shadow-sm);
}
/* The two kinds of report differ in how they are made, so the marker is the
   dot again, and the words beside it say which. */
.rwall-kind {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--steel);
}
.rwall-kind::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--echo-cyan); }
.rwall-card.is-narrative .rwall-kind::before { background: var(--action-ink); }
.rwall-card h3 { margin: 10px 0 0; font-size: 17px; letter-spacing: -0.015em; }
.rwall-card p { margin: 7px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--slate); }
.rwall-cta { margin-top: clamp(26px, 3.2vw, 38px); }

/* ============================================================
   Four more page headers — 2026-08-28.

   Nine product pages opened with the same block, so every one
   of them painted the same picture: near-white gradient, left
   column of copy, pale object floating on the right. These
   change the three things a reader clocks before reading —
   the ground, the composition, and whether anything moves.

   All four are ordinary sections. Nothing here is a rule that
   the plain .page-hero may not be used; it is a set so that
   the set does not rhyme.
   ============================================================ */

/* ---- The photographic stage --------------------------------
   Full-bleed picture, copy on it. The veil is heavy on purpose:
   text over a photograph is the one contrast case tools/
   contrast.mjs cannot measure (it reads a computed background
   colour, and a picture is not one), so this is checked with a
   screenshot and the veil is sized for the worst frame, not the
   average one. Do not thin it without taking that screenshot.

   Permanently dark in both themes, like .cine and .reports-hero:
   a photograph with a night in it is a drawing, not a themed
   surface. */
.hero-stage {
  position: relative; isolation: isolate; overflow: clip;
  /* A column, not a row: the fact rail is a SIBLING of the wrap and has to
     span the band. As a row it became a flex item beside the copy and sat in
     a box on the right, which is not a rail. */
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: clamp(460px, 62vh, 660px);
  background: #0A1224; color: #F2F6FC;
  padding: clamp(56px, 8vw, 104px) 0 0;
}
.hero-stage-photo {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover; object-position: 62% 45%;
  display: block;
}
.hero-stage-veil {
  position: absolute; inset: 0; z-index: -1; display: block;
  background:
    linear-gradient(90deg, rgba(6, 11, 24, .93) 0%, rgba(6, 11, 24, .84) 38%, rgba(6, 11, 24, .42) 72%, rgba(6, 11, 24, .30) 100%),
    linear-gradient(180deg, rgba(6, 11, 24, .55) 0%, rgba(6, 11, 24, .10) 34%, rgba(6, 11, 24, .78) 100%);
}
.hero-stage > .wrap { position: relative; width: 100%; padding-bottom: clamp(40px, 5vw, 68px); }
.hero-stage .breadcrumbs, .hero-stage .breadcrumbs a { color: #9FB4D4; }
.hero-stage .breadcrumbs a:hover { color: #fff; }
.hero-stage-copy { max-width: 660px; }
.hero-stage .eyebrow { color: #7FD0F5; }
.hero-stage h1 {
  margin-top: 14px; color: #fff;
  font-size: clamp(34px, 5.2vw, 62px); line-height: 1.06;
  letter-spacing: -0.032em; text-wrap: balance;
}
.hero-stage .lead { color: #D3DEEF; max-width: 560px; }
.hero-stage-aside { font-size: 14.5px; color: #C0CDE4; }
.hero-stage-aside a { color: #7FD0F5; }
.hero-stage-note { margin-top: 16px; font-size: 13.5px; line-height: 1.6; color: #94A6C4; max-width: 520px; }
/* The fact rail: three short numbers along the foot of the picture, on a
   hairline of their own so they read as a caption to the photograph rather
   than as a second stat band. */
.hero-stage-facts {
  position: relative; border-top: 1px solid rgba(255, 255, 255, .16);
  background: rgba(6, 11, 24, .58);
}
.hero-stage-facts .wrap {
  display: flex; flex-wrap: wrap; gap: clamp(20px, 4vw, 56px);
  padding-top: 18px; padding-bottom: 18px;
}
.hero-stage-facts b { display: block; font-size: clamp(19px, 2.1vw, 26px); font-weight: 750; color: #fff; letter-spacing: -0.02em; }
.hero-stage-facts span { display: block; margin-top: 3px; font-size: 13px; color: #9FB4D4; }
@media (max-width: 720px) {
  .hero-stage { min-height: clamp(420px, 76vh, 620px); }
  .hero-stage-photo { object-position: 66% 38%; }
  .hero-stage-veil {
    background:
      linear-gradient(180deg, rgba(6, 11, 24, .58) 0%, rgba(6, 11, 24, .30) 26%, rgba(6, 11, 24, .92) 74%);
  }
}

/* ---- The converging header ---------------------------------
   Centred and symmetric: the channel marks in an arc, one
   hairline dropping from each into a single point, the headline
   under the point. The marks and the paths are positioned from
   the same numbers in the renderer — see the note there. */
.hero-conv { background: var(--grad-ice-fade); padding: clamp(30px, 4vw, 54px) 0 clamp(44px, 5.5vw, 84px); overflow: clip; }
.hero-conv-sky {
  position: relative; width: min(100%, 780px); margin: clamp(18px, 3vw, 34px) auto 0;
  height: clamp(120px, 17vw, 190px);
}
.hero-conv-marks { list-style: none; margin: 0; padding: 0; }
.hero-conv-marks li { position: absolute; transform: translate(-50%, -50%); }
/* No card behind the mark. Every one of these files is already a square with
   its own ground baked in, so a white tile around it is a square inside a
   square — which is what it looked like the first time. The shadow is on the
   image so it follows the mark's own edge. */
.hero-conv-marks .provider-mark {
  width: clamp(34px, 4.4vw, 48px); height: clamp(34px, 4.4vw, 48px);
}
.hero-conv-marks .provider-mark img { filter: drop-shadow(0 6px 16px rgba(32, 48, 88, .18)); }
.hero-conv-lines { position: absolute; inset: 0; width: 100%; height: 100%; }
.hero-conv-lines path {
  stroke: var(--echo-cyan); opacity: .5;
  /* preserveAspectRatio is none, so the stroke is scaled unevenly with the
     box; vector-effect keeps it a hairline at every width instead of a wedge. */
  vector-effect: non-scaling-stroke; stroke-width: 1.25px;
}
.hero-conv-point {
  position: absolute; left: 50%; bottom: 0; transform: translate(-50%, 50%);
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--echo-cyan); box-shadow: 0 0 0 6px rgba(93, 174, 227, .18);
}
.hero-conv-copy { max-width: 760px; margin: clamp(26px, 3.4vw, 44px) auto 0; text-align: center; }
.hero-conv-copy h1 { margin-top: 14px; text-wrap: balance; }
.hero-conv-copy .lead { margin-left: auto; margin-right: auto; max-width: 620px; }
.hero-conv-copy .cta-note {
  /* .cta-note is a 480px box and only `.center .cta-note` supplies the auto
     side margins. This header centres through .hero-conv-copy instead, so the
     note was pinned to the left of a 760px column and sat 140px left of the
     h1 and lead above it — text centred inside a box that was not. */
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}
.hero-conv-cap { margin-top: 18px; font-size: 13px; color: var(--steel); }
@media (max-width: 720px) {
  /* The arc flattens rather than crowding: fewer pixels between marks than a
     40px tile needs is a row of overlapping logos, which is worse than a
     shallower curve. */
  .hero-conv-sky { height: clamp(104px, 30vw, 150px); }
  .hero-conv-marks .provider-mark { width: 30px; height: 30px; }
}

/* ---- The figure header -------------------------------------
   No picture. Three numbers, set large enough to be the artwork,
   on the recessed band. */
.hero-figs { background: var(--mist); padding: clamp(40px, 5vw, 78px) 0 clamp(44px, 5.5vw, 84px); }
.hero-figs-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .82fr);
  gap: clamp(28px, 5vw, 72px); align-items: center;
  margin-top: clamp(16px, 2vw, 26px);
}
.hero-figs-copy h1 { margin-top: 14px; }
.hero-figs-list { list-style: none; margin: 0; padding: 0; }
.hero-figs-list li { padding: clamp(14px, 1.8vw, 22px) 0; border-top: 1px solid var(--cloud); }
.hero-figs-list li:first-child { border-top: 0; padding-top: 0; }
.hero-figs-list li:last-child { padding-bottom: 0; }
.hero-figs-list b {
  display: block; font-size: clamp(38px, 6.4vw, 82px); line-height: .96;
  font-weight: 750; letter-spacing: -0.04em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.hero-figs-list span { display: block; margin-top: 8px; font-size: 14.5px; color: var(--slate); }
.hero-figs-cap { margin-top: clamp(22px, 3vw, 34px); font-size: 13px; color: var(--steel); max-width: 720px; }
@media (max-width: 860px) {
  .hero-figs-grid { grid-template-columns: 1fr; gap: clamp(26px, 5vw, 40px); }
  .hero-figs-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; }
  .hero-figs-list li { border-top: 0; border-left: 1px solid var(--cloud); padding: 0 0 0 14px; }
  .hero-figs-list li:first-child { border-left: 0; padding-left: 0; }
  .hero-figs-list b { font-size: clamp(26px, 7.4vw, 40px); }
  .hero-figs-list span { font-size: 13px; }
}

/* ---- The queue header --------------------------------------
   Short copy, then the product's own queue across the width of
   the page. The panel is the dark surface the site already owns
   for a device screen (--slab), so the header's weight sits at
   the bottom of the band rather than in a floating card. */
.hero-queue { background: var(--grad-ice-fade); padding: clamp(40px, 5vw, 74px) 0 0; }
.hero-queue-copy { max-width: 720px; }
.hero-queue-copy h1 { margin-top: 14px; }
/* The line under a header's headline. 23px is the largest size at which a
   three-phrase line still fits the 720px copy column on one line. */
.hero-sub {
  margin: 18px 0 0; font-size: clamp(19px, 2.2vw, 23px); line-height: 1.4;
  font-weight: 600; letter-spacing: -0.012em; color: var(--ink); text-wrap: balance;
}
.hero-sub-part { white-space: nowrap; }
@media (max-width: 640px) {
  .hero-sub-part { display: block; }
  .hero-sub-sep { display: none; }
}
.hero-queue-panel {
  margin-top: clamp(34px, 4.4vw, 60px);
  background: var(--slab); color: var(--slab-ink);
  border-radius: clamp(16px, 2vw, 26px) clamp(16px, 2vw, 26px) 0 0;
  padding: clamp(20px, 2.6vw, 32px) 0 clamp(24px, 3vw, 38px);
  box-shadow: 0 -18px 60px rgba(32, 48, 88, .16);
}
.hero-queue-inner {
  width: min(100% - clamp(28px, 5vw, 64px), 1120px); margin: 0 auto;
}
.hero-queue-title {
  margin: 0 0 clamp(14px, 1.8vw, 20px);
  font-size: 12.5px; font-weight: 750; letter-spacing: .14em; text-transform: uppercase;
  color: var(--slab-dim);
}
/* The rows stay exactly the light cards they are everywhere else, on the
   slab. Inverting their ink was tried first and put white names on a white
   card — the row's own background is --white, and only the four ink colours
   had been overridden. Light cards on a deep ground is also the truer
   picture: it is what the product looks like. */
/* The panel sets a light ink for its own title, and .conv-name has no colour
   of its own — so without this the names inherit near-white onto a white
   card and vanish. The row re-asserts the page's ink. */
.hero-queue-panel .conv { color: var(--ink); }
.hero-queue-panel .rule { border-color: rgba(255, 255, 255, .16); }
/* A real capture of the Inbox in the panel instead of drawn rows (2026-09-16).
   Rounded like the cards it replaces, its own edge so the app's dark sidebar
   does not bleed into the slab, and never wider than the panel's measure. */
.hero-queue-shot { margin: 0; border-radius: 12px; overflow: hidden; border: 1px solid rgba(255, 255, 255, .14); box-shadow: 0 24px 70px rgba(0, 0, 0, .35); }
.hero-queue-shot img { display: block; width: 100%; height: auto; }
.hero-queue-note { margin: 14px 0 0; font-size: 14.5px; line-height: 1.5; color: var(--slab-dim); }
/* A real capture inside a card, between its eyebrow and its note (2026-09-16,
   the Claimed section on /product/inbox). Shown near the app's own size and
   centred, because a 258px sidebar blown up to the card's width is a blur, not
   a screenshot. */
.card-shot { margin: 14px auto 0; max-width: 360px; border-radius: 10px; overflow: hidden; border: 1px solid var(--cloud); box-shadow: 0 10px 30px rgba(32, 48, 88, .14); }
.card-shot img { display: block; width: 100%; height: auto; }

/* ------------------------------------------------------------
   The photographic reveal (.cinep) — the same opening act as
   .cine above, with the drawn laptop replaced by a photograph
   of a real desk at night. It reuses .cine's stage, copy and
   close entirely; only the thing being zoomed is different.

   One idea holds the whole thing together: the report screen
   is a CHILD of the same box as the photograph, placed on the
   laptop's screen by four fractions measured off the picture
   (--sr-*). Scaling the box scales both, so the report cannot
   slide off the laptop at some viewport width nobody tested.

   In the live state the box is sized to COVER the stage and
   centred with auto margins rather than a translate, because
   the driver writes `transform` every frame and an element
   positioned with transform loses that position the moment an
   animation touches the property. That trap has been paid for
   here once already (see the .mega note in this file).
   ------------------------------------------------------------ */
.cinep-frame {
  position: relative; display: block;
  width: min(88vw, 1040px); height: auto; aspect-ratio: 2048 / 1152;
  margin: clamp(40px, 5.5vw, 72px) auto 0;
  border-radius: clamp(10px, 1.3vw, 18px); overflow: hidden;
  background: #0A0F1A;
  box-shadow: 0 46px 130px rgba(2, 6, 16, .7), 0 10px 34px rgba(2, 6, 16, .5);
}
.cinep-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* The laptop's screen: a box on the picture, at the measured rectangle. What
   goes IN it is either the mark or a product capture.

   The mark is the stronger opening and the reason this box is a box rather
   than an <img>. It is drawn by the browser, so it stays vector-crisp all the
   way up to a full-screen title card, and its ground is one flat colour — so
   the push-in can simply carry on until the screen IS the viewport. Nothing
   dissolves, nothing is cropped, and there is no second picture to match. */
/* place-CONTENT as well as place-items, and it is load-bearing. The lockup is
   a fixed 420px box and the screen it sits in is narrower than that at rest,
   so the auto grid track is wider than its container. place-items centres the
   item in its track; only place-content centres the track in the container.
   Without it the track sat at the left edge, the lockup ran off to the right,
   and the counter-scale then shrank it toward a point that was not the middle
   of the screen — on a phone it read as half a word in the corner. */
.cinep-screen {
  position: absolute; display: grid; place-items: center; place-content: center;
  overflow: hidden; container-type: inline-size;
  left: var(--sr-l); top: var(--sr-t); width: var(--sr-w); height: var(--sr-h);
  background: #070C18;
}
.cinep-shot { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top; background: #fff; }

/* The lockup. 420px wide by construction — the driver reads that width back
   and counter-scales this element so its size on the visitor's screen follows
   its own curve rather than the photograph's: sitting on the laptop at the
   start, a title card at the end. Everything inside is sized against it. */
/* Everything in the lockup is sized against the SCREEN it sits on, in
   container units, rather than in fixed pixels. Fixed pixels were tried first
   and the fallback gave it away: with no JavaScript nothing counter-scales it,
   so a 420px lockup on a phone's 218px screen was clipped to half a word. In
   cqw it fits every rectangle, at rest and at full zoom, and the driver's
   counter-scale starts from a value that is already right. */
.cinep-mark {
  display: grid; justify-items: center; gap: 5cqw;
  width: max-content; transform-origin: 50% 50%;
}
.cinep-mark-icon { width: 20cqw; height: 20cqw; display: block; }
.cinep-mark-word { font-size: 12cqw; }
/* The shell's wordmark is ink-on-white. This one is on a switched-on screen. */
.cinep-mark-word b { color: #fff; }
.cinep-mark-word span { color: #9FC6E4; }
.cinep-mark-cap {
  font-size: 3.2cqw; font-weight: 700; letter-spacing: .18em; text-transform: uppercase;
  color: #7FD0F5; text-align: center;
}
/* Only ever painted in the live state — at rest the photograph is the
   picture, not a ground for copy to sit on, and the report is already on the
   laptop rather than over the whole stage. */
.cinep-scrim, .cinep-final { display: none; }

/* Four and a bit viewports of scroll for the whole reveal. It was 480vh when
   it carried a mid-scroll beat; without one the same move over the same
   distance is slower than it needs to be. */
.cinep.is-live .cine-track { height: 400vh; }
.cinep.is-live .cinep-frame {
  /* Cover the stage: the box keeps the photograph's own aspect so the four
     fractions still describe where the screen is. Centred with auto margins,
     never a transform. */
  /* Centred with left/top 50% and a NEGATIVE HALF-SIZE MARGIN, not with
     `inset: 0; margin: auto`. Auto margins only centre a box that FITS its
     container; this one is deliberately bigger than the viewport, and an
     over-constrained absolute box resolves its auto margins to zero and sits
     at `left` instead. It rendered at the stage's left edge, so the laptop —
     and with it the whole push-in — was about a hundred pixels right of centre
     on a phone, which is why the lockup ran off the edge of the screen.
     Centring with a transform would have worked and is not available: the
     driver writes `transform` every frame. The two sizes are named once as
     --fw/--fh so the margins cannot disagree with the widths. */
  --fw: max(100vw, 177.778dvh);
  --fh: max(56.25vw, 100dvh);
  position: absolute; left: 50%; top: 50%; z-index: 1;
  width: var(--fw); height: var(--fh);
  margin-left: calc(var(--fw) / -2); margin-top: calc(var(--fh) / -2);
  aspect-ratio: auto; border-radius: 0; box-shadow: none;
  transform-origin: var(--sr-cx) var(--sr-cy);
  /* Deliberately NOT will-change: transform. Promoting this layer makes
     Chrome rasterise it at its SCALED size, and at the end of the push-in
     that is a texture several times the viewport in each direction — enough
     to hang a headless screenshot outright, which is how it was found. Let
     the compositor scale the layer it already has. */
}
/* A 16:9 photograph COVERING a portrait stage is a 1500px-wide picture behind
   a 390px window: you see one shoulder, the laptop is off frame, and the
   push-in zooms into a neck. So a tall viewport gets a framed wide shot
   instead of a cover — big enough to carry weight, small enough that the
   whole desk is in it, which is the composition the whole sequence is for.
   Measured at 390x844: 624px wide, so the screen sits just right of centre
   exactly as it does on a desktop. */
@media (max-aspect-ratio: 1 / 1) {
  .cinep.is-live .cinep-frame { --fw: min(160vw, 177.778dvh); --fh: min(90vw, 100dvh); }
}
.cinep.is-live .cinep-scrim {
  display: block; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  /* Nearly closed at rest, and lifted by the driver in two steps. This is
     heavier than it first was, and the reason is compositional: the laptop is
     centred in the photograph and so is the opening headline, so at rest they
     sit on top of each other. Starting almost dark means the first thing the
     visitor sees is the sentence, and the room arrives underneath it — which
     is the better order anyway. */
  background:
    radial-gradient(130% 100% at 50% 46%, rgba(8, 14, 30, .88), rgba(5, 9, 20, .97) 74%);
}
/* The last beat hands over from the screen-in-a-room to the report itself,
   full frame. Without it the push has to magnify the laptop until its screen
   fills the viewport, and on a phone that is a five-times blow-up of one
   statistic — the screen rect is a wide crop and a tall viewport can only
   fill it by going absurdly close. The dissolve ends the sequence on the
   report at a size a person can actually read, at every aspect ratio. */
.cinep.is-live .cinep-final {
  display: block; position: absolute; inset: 0; z-index: 2; opacity: 0;
  width: 100%; height: 100%; object-fit: cover; object-position: top;
  background: #fff; pointer-events: none;
}

/* A lit screen throws light into the room. Without this whatever is on the
   screen reads as a bright rectangle pasted onto a dark photograph, which is
   the one thing that gives a composite away. It rides the screen's own
   opacity, so it arrives as the screen wakes. */
.cinep.is-live .cinep-screen {
  box-shadow: 0 0 16vh rgba(120, 175, 255, .34), 0 0 5vh rgba(190, 220, 255, .24);
}
/* Once the screen has filled the frame the glow is a halo around nothing —
   the driver has taken it past the viewport's edges — so it is dropped at the
   same point the mark settles into its title card. */
.cinep.is-live .cinep-screen.is-full { box-shadow: none; }
.cinep.is-live .cine-copy { z-index: 3; }
.cinep.is-live .cine-cap { z-index: 4; }

/* The plan trio — which of the three names comes with the plan. The state
   marker is the house dot, never a tint or an edge bar. */
.plan-trio {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr));
  gap: 14px; margin-top: clamp(24px, 3vw, 36px);
}
.plan-trio .card-flat { display: flex; flex-direction: column; }
.plan-badge {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 750; letter-spacing: .09em; text-transform: uppercase;
  color: var(--slate);
}
.plan-badge::before { content: ""; flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%; background: var(--success); }
.plan-badge.is-addon::before { background: var(--wordmark-blue); }
.plan-name { margin: 12px 0 0; font-size: 20px; letter-spacing: -0.015em; }
.plan-body { margin: 10px 0 0; font-size: 14.5px; line-height: 1.62; color: var(--slate); flex: 1 1 auto; }
.plan-link { margin-top: 16px; align-self: flex-start; }
.plan-note { margin: clamp(18px, 2.2vw, 26px) auto 0; max-width: 720px; text-align: center; font-size: 14px; line-height: 1.65; color: var(--slate); }

/* The value-math band — the same permanently dark stage as the reveal, so
   the page's two dark moments read as one material. */
.vm {
  background:
    radial-gradient(1000px 500px at 84% 0%, rgba(36, 70, 127, .5), transparent 70%),
    #0A1224;
  color: #F2F6FC;
  padding: clamp(64px, 8vw, 120px) 0;
}
.vm .eyebrow { color: #7FD0F5; }
.vm h2 { color: #fff; }
.vm-lead { margin: 14px 0 0; max-width: 640px; font-size: clamp(16px, 1.5vw, 19px); line-height: 1.6; color: #C9D6EA; }
.vm-fig { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px 16px; margin-top: clamp(22px, 2.6vw, 32px); }
.vm-fig .price-num { color: #fff; }
.vm-fig .price-unit { color: #C9D6EA; }
.vm-compare {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 14px; margin-top: clamp(26px, 3.2vw, 40px);
}
.vm-compare > div {
  border: 1px solid rgba(255, 255, 255, .18); border-radius: var(--radius-xl);
  padding: clamp(18px, 2.2vw, 26px);
}
.vm-compare .eyebrow { font-size: 12px; }
.vm-compare b { display: block; margin-top: 10px; font-family: var(--font-mono); font-size: clamp(26px, 3vw, 38px); font-weight: 700; letter-spacing: -0.03em; color: #fff; }
.vm-compare p { margin: 10px 0 0; font-size: 14.5px; line-height: 1.62; color: #C9D6EA; }
.vm-tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  gap: 14px; margin-top: clamp(26px, 3.2vw, 40px);
}
.vm-tiles > div { border-top: 1px solid rgba(255, 255, 255, .18); padding-top: 14px; }
.vm-tiles b { display: block; font-family: var(--font-mono); font-size: clamp(22px, 2.4vw, 30px); font-weight: 700; letter-spacing: -0.02em; color: #fff; }
.vm-tiles span { display: block; margin-top: 6px; font-size: 13.5px; line-height: 1.55; color: #C9D6EA; }
.vm-note { margin: clamp(22px, 2.6vw, 32px) 0 0; font-size: 13.5px; line-height: 1.6; color: #8B9BBD; max-width: 640px; }

/* ============================================================
   The GraphQL + MCP premium blocks — the two-door header
   (.ports) and the MCP receipt (.rcpt).

   .ports is the site's SECOND premium opening and it is
   deliberately not the first one. /product/echoanalyst pins a
   stage and scrubs a laptop through it; this page does not
   take the scroll at all. It states an offer as a picture —
   two panels, the Echo mark between them, a wire running in
   from each side — and then gets out of the way. Two premium
   pages doing the same gesture would read as one trick used
   twice, which is the opposite of what a paid add-on should
   feel like.

   Like .cine and .price-band, the dark ground here is literal
   in both themes rather than tokenised: a permanently dark
   stage is a drawing, not a themed surface, and the accents
   (#7FD0F5, #C9D6EA, #8B9BBD) are the ones the other dark
   bands already use, so the two premium pages are recognisably
   the same family without being the same layout.

   Everything animated is transform and opacity only, and the
   markup with no JS and with reduced motion is the finished
   composition — nothing is revealed by the animation that is
   not already on the page.
   ============================================================ */
.ports {
  position: relative;
  background:
    radial-gradient(760px 420px at 50% 62%, rgba(45, 96, 168, .38), transparent 70%),
    radial-gradient(1200px 520px at 50% -14%, rgba(30, 58, 110, .5), transparent 72%),
    #080F1E;
  color: #F2F6FC;
  overflow: clip;
}
.ports-wrap {
  max-width: 1240px; margin: 0 auto;
  padding: clamp(24px, 3.2vw, 40px) clamp(20px, 3.5vw, 40px) clamp(48px, 5.4vw, 78px);
  text-align: center;
}
.ports-crumb { justify-content: center; color: #8B9BBD; margin-bottom: clamp(22px, 3vw, 34px); }
.ports-crumb a { color: #C9D6EA; }
.ports-crumb a:hover { color: #7FD0F5; }
.ports-crumb span { color: #55688C; }
.ports-eyebrow {
  display: inline-flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: center;
  margin: 0; font-size: 13px; font-weight: 750; letter-spacing: .14em;
  text-transform: uppercase; color: #7FD0F5;
}
.ports-badge {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: none;
  color: #C9D6EA; border: 1px solid rgba(255, 255, 255, .28);
  border-radius: var(--radius-pill); padding: 4px 11px;
}
.ports-badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: #7FD0F5; }
.ports-h {
  margin: 16px auto 0; max-width: 20ch; color: #fff;
  font-size: clamp(32px, 4.6vw, 58px); line-height: 1.06;
  letter-spacing: -0.035em; font-weight: 800; text-wrap: balance;
}
.ports-lead {
  margin: clamp(15px, 1.8vw, 21px) auto 0; max-width: 630px;
  font-size: clamp(16px, 1.5vw, 18px); line-height: 1.55; color: #C9D6EA; text-wrap: pretty;
}
.ports-lead b { color: #fff; }

/* The rig: door — hub — door. On a phone it stacks in that same order, so
   the sentence the row tells left to right is the one it tells top to
   bottom, and the wires simply turn ninety degrees. */
.ports-rig {
  display: grid; gap: clamp(18px, 2vw, 26px);
  margin-top: clamp(26px, 3.2vw, 42px); text-align: start;
}
@media (min-width: 900px) {
  .ports-rig { grid-template-columns: 1fr minmax(140px, 210px) 1fr; align-items: stretch; gap: 0; }
}
.port {
  position: relative; display: flex; flex-direction: column;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .13);
  border-radius: var(--radius-2xl);
  padding: clamp(20px, 2.2vw, 30px);
  box-shadow: 0 30px 90px rgba(2, 6, 16, .5);
}
.port-kicker {
  margin: 0; font-size: 11px; font-weight: 750; letter-spacing: .13em;
  text-transform: uppercase; color: #8B9BBD;
}
.port-name {
  margin: 8px 0 0; color: #fff; font-size: clamp(21px, 2.1vw, 27px);
  letter-spacing: -0.02em; line-height: 1.15;
}
.port-say { margin: 10px 0 0; font-size: 14.5px; line-height: 1.55; color: #C9D6EA; }
.port-say b { color: #fff; }

/* A code door. Scrolls sideways in its own box rather than widening the
   panel — the two doors must stay the same width or the picture tilts. */
.port-code {
  margin: clamp(16px, 1.8vw, 22px) 0 0; flex: 1;
  background: rgba(2, 6, 16, .5);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: var(--radius-lg);
  padding: 14px 16px; overflow-x: auto;
  font-family: var(--font-mono); font-size: 12.5px; line-height: 1.65;
  color: #DCE6F5; white-space: pre;
}

/* An ask door. Three lines, and the middle one is the point: the question
   is English, the answer is English, and between them sits the named tool
   that was actually run. */
.port-thread {
  margin: clamp(16px, 1.8vw, 22px) 0 0; flex: 1;
  display: flex; flex-direction: column; gap: 10px; justify-content: center;
}
.port-line { margin: 0; font-size: 14.5px; line-height: 1.5; }
.port-ask {
  color: #fff; font-weight: 600;
  background: rgba(255, 255, 255, .07);
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) 5px;
  padding: 11px 14px;
}
.port-call {
  align-self: center; display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .02em;
  color: #7FD0F5; background: rgba(127, 208, 245, .09);
  border: 1px solid rgba(127, 208, 245, .22);
  border-radius: var(--radius-pill); padding: 4px 12px;
}
.port-call::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: #7FD0F5; flex: 0 0 auto; }
.port-answer {
  color: #C9D6EA;
  background: rgba(2, 6, 16, .45);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: var(--radius-lg) var(--radius-lg) 5px var(--radius-lg);
  padding: 11px 14px;
}

/* The hub. Both doors reach the same Echo, which is the whole reason the
   add-on is one price rather than two. */
.ports-core { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0; }
@media (min-width: 900px) { .ports-core { flex-direction: row; } }
.ports-wire {
  position: relative; flex: 1 1 auto; overflow: hidden;
  width: 1px; min-height: 34px;
  background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, .3) 22%, rgba(255, 255, 255, .3) 78%, transparent);
}
@media (min-width: 900px) {
  .ports-wire {
    width: auto; height: 1px; min-height: 0; min-width: 24px;
    background: linear-gradient(to right, transparent, rgba(255, 255, 255, .3) 22%, rgba(255, 255, 255, .3) 78%, transparent);
  }
}
/* The travelling light. It always runs TOWARD the hub, which is why the
   second wire's animation is reversed rather than being a second keyframe
   set: the direction is the meaning here, not decoration. */
.ports-wire::after {
  content: ""; position: absolute; border-radius: 50%;
  width: 5px; height: 5px; left: 50%; margin-left: -2.5px; top: -6px;
  background: #7FD0F5; box-shadow: 0 0 10px 3px rgba(127, 208, 245, .55);
  opacity: 0;
}
.ports-hub {
  position: relative; flex: 0 0 auto;
  width: clamp(62px, 7vw, 78px); aspect-ratio: 1;
  display: grid; place-items: center;
  border-radius: 50%; background: #0D1830;
  border: 1px solid rgba(127, 208, 245, .38);
  box-shadow: 0 0 0 9px rgba(127, 208, 245, .06), 0 0 44px rgba(127, 208, 245, .3);
}
.ports-hub img { width: 54%; height: auto; display: block; }
.ports-hubcap {
  margin: clamp(16px, 2vw, 22px) auto 0; max-width: 42ch;
  font-size: 13.5px; line-height: 1.55; color: #8B9BBD;
}
.ports-hubcap b { color: #C9D6EA; }
.ports-cta { justify-content: center; margin-top: clamp(30px, 3.6vw, 44px); }
.ports-aside { font-size: 14.5px; color: #C9D6EA; }
.ports-aside a { color: #7FD0F5; }
.ports-note { margin: 14px auto 0; font-size: 13.5px; color: #8B9BBD; }
.ports-note a { color: #7FD0F5; }

/* Motion. site.js adds .is-live only when it is safe to; without it the
   panels are already in place and the wires are already lit. */
.ports.is-live .port { opacity: 0; transform: translateY(14px); }
.ports.is-live .ports-core { opacity: 0; }
.ports.is-live.is-in .port { opacity: 1; transform: none; transition: opacity .7s ease, transform .7s cubic-bezier(.2, .7, .3, 1); }
.ports.is-live.is-in .port:nth-of-type(2) { transition-delay: .12s; }
.ports.is-live.is-in .ports-core { opacity: 1; transition: opacity .6s ease .3s; }
.ports.is-live.is-in .ports-wire::after { animation: portsPulse 3.6s cubic-bezier(.4, 0, .5, 1) .9s infinite; }
.ports.is-live.is-in .ports-core .ports-wire:last-child::after { animation-direction: reverse; animation-delay: 2.7s; }
@keyframes portsPulse {
  0%   { opacity: 0; transform: translateY(0); }
  12%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(var(--wire-run, 130px)); }
}
@media (min-width: 900px) {
  @keyframes portsPulse {
    0%   { opacity: 0; transform: translateX(calc(-1 * var(--wire-run, 90px))); }
    12%  { opacity: 1; }
    70%  { opacity: 1; }
    100% { opacity: 0; transform: translateX(0); }
  }
  .ports-wire::after { top: 50%; margin-top: -2.5px; left: auto; right: -3px; margin-left: 0; }
  .ports-core .ports-wire:last-child::after { right: auto; left: -3px; }
}
@media (prefers-reduced-motion: reduce) {
  .ports.is-live .port,
  .ports.is-live .ports-core { opacity: 1; transform: none; }
  .ports.is-live.is-in .ports-wire::after { animation: none; opacity: .8; }
}

/* ------------------------------------------------------------
   The MCP receipt. A chat transcript is the most generic
   picture on the internet this year, so the picture here is
   the thing no other product page shows: the trace the
   assistant left behind. Ruled mono rows on a hairline card,
   read like a lab result — which is also the only form in
   which "we let an AI near conversations with seekers in them"
   is a sentence a ministry can actually evaluate.

   The exchange beside it is set editorially, not as bubbles:
   the question is a quotation with the house hanging mark, the
   answer is prose. No avatars and no typing dots.
   ------------------------------------------------------------ */
.rcpt-grid {
  display: grid; gap: clamp(26px, 3.4vw, 46px);
  margin-top: clamp(26px, 3.2vw, 40px); align-items: start;
}
@media (min-width: 900px) { .rcpt-grid { grid-template-columns: 1fr minmax(330px, .82fr); } }
.rcpt-who {
  margin: 0; font-size: 11px; font-weight: 750; letter-spacing: .13em;
  text-transform: uppercase; color: var(--steel);
}
.rcpt-who-b { margin-top: clamp(24px, 3vw, 34px); }
.rcpt-q {
  position: relative; margin: 12px 0 0; padding: 0;
  border: 0; font-size: clamp(21px, 2.4vw, 30px); line-height: 1.3;
  letter-spacing: -0.02em; font-weight: 650; color: var(--ink); text-wrap: pretty;
}
.rcpt-q::before {
  content: "\201C"; position: absolute; left: -.5em; top: -.08em;
  font-size: 1.7em; line-height: 1; font-weight: 800; color: var(--ice);
}
.rcpt-a { margin: 12px 0 0; font-size: clamp(15.5px, 1.5vw, 17px); line-height: 1.62; color: var(--slate); }
.rcpt-a b { color: var(--ink); font-weight: 650; }
.rcpt-anote {
  margin: 14px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--steel);
  padding-inline-start: 16px; position: relative;
}
.rcpt-anote::before {
  content: ""; position: absolute; inset-inline-start: 0; top: .58em;
  width: 7px; height: 7px; border-radius: 50%; background: var(--echo-cyan);
}
.rcpt {
  margin: 0; background: var(--white);
  border: 1px solid var(--cloud); border-radius: var(--radius-2xl);
  box-shadow: var(--shadow-float); overflow: hidden;
}
.rcpt-head {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 18px; border-bottom: 1px solid var(--cloud);
  background: var(--mist);
  font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--slate);
}
.rcpt-head span {
  margin-inline-start: auto; display: inline-flex; align-items: center; gap: 7px;
  text-transform: none; letter-spacing: .02em; font-weight: 500; color: var(--steel);
}
.rcpt-head span::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--good-ink); }
.rcpt-rows { margin: 0; padding: 0 18px; }
.rcpt-row {
  display: grid; gap: 2px 18px; padding: 12px 0;
  border-bottom: 1px solid var(--cloud);
}
@media (min-width: 460px) { .rcpt-row { grid-template-columns: 8.5rem 1fr; gap: 18px; align-items: baseline; } }
.rcpt-row:last-child { border-bottom: 0; }
.rcpt-row dt {
  margin: 0; font-size: 11.5px; font-weight: 750; letter-spacing: .06em;
  text-transform: uppercase; color: var(--steel);
}
.rcpt-row dd {
  margin: 0; font-family: var(--font-mono); font-size: 13px; line-height: 1.55;
  color: var(--ink); overflow-wrap: anywhere;
}
.rcpt-row dd b { font-family: var(--font-sans); font-weight: 650; }
.rcpt-foot {
  margin: 0; padding: 13px 18px; border-top: 1px solid var(--cloud);
  background: var(--mist); font-size: 13px; line-height: 1.5; color: var(--slate);
}
.rcpt-note {
  margin: clamp(22px, 2.6vw, 32px) auto 0; max-width: 62ch; text-align: center;
  font-size: 13.5px; line-height: 1.55; color: var(--steel);
}

/* The attribution under a stage header's fact row. Added 2026-08-29 with the
   phone page's photographic opening: the platform totals are platform-wide,
   and three large numbers on a hero with nothing under them read as the
   visitor's own. */
.hero-stage-factnote {
  margin: 14px 0 0; font-size: 12.5px; line-height: 1.5;
  color: rgba(255, 255, 255, .62); max-width: 62ch;
}


/* ============================================================================
   The plan/21 homepage section types
   ============================================================================
   Slice 2 of plan/21, promoted out of design/lab/lab.css where they were
   prototyped by hand. Seven bands: the film opening and its photographic
   close, a statement, a showcase, plain steps, a photograph with the copy
   beside it, and a price line. Every one of them is a block type in
   tools/marketing-blocks.mjs and edits in the page builder.

   Two rules carried over from the lab, both load-bearing:

   1. A band with copy OVER a picture is a drawing, not a themed surface.
      Ground #0A1224 under the image, a literal veil sized for the darkest
      frame, white and #D3DEEF text, identical in both themes -- written the
      same way .hero-stage is, for the reason written there: text over a
      photograph is the one contrast case tools/contrast.mjs cannot measure,
      so the veil is checked with a screenshot and a pixel sample.
   2. A band with the copy BESIDE the picture uses the ramp only, so it
      flips with the theme and the contrast harness can measure every word.
   ============================================================================ */

/* ---- 1. Photographic band, copy OVER the picture -------------------------
   Used by filmopen (the homepage film) and filmclose (the photographic close). */
.fs {
  position: relative; isolation: isolate; overflow: clip;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: clamp(560px, 92vh, 960px);
  background: #0A1224; color: #F2F6FC;
}
.fs-close { min-height: clamp(520px, 74vh, 800px); }

.fs-photo {
  position: absolute; inset: 0; display: block;
  width: 100%; height: 100%; object-fit: cover;
  /* The focus rule: where the face is, so a 390px portrait crop keeps it.
     Set per picture on the section, never guessed. */
  object-position: var(--fx, 50%) var(--fy, 38%);
}
.fs[data-focus="right"]  { --fx: 70%; --fy: 32%; }
.fs[data-focus="left"]   { --fx: 32%; --fy: 26%; }
.fs[data-focus="center"] { --fx: 50%; --fy: 35%; }
/* The playing film: same box as the poster. The chapters put their person on
   different thirds, so the crop favours the centre-right where four of the
   six faces sit. */
.fs[data-focus="film"]   { --fx: 58%; --fy: 36%; }

/* The stack inside .fs, which is its own isolated context. It is written out
   explicitly because the film driver sets a z-index on the film copies to put
   the incoming one on top during a dissolve, and any positive value there
   would otherwise paint the film OVER the veil and the copy -- which is what
   made the headline disappear once the loop started.
     0  the poster        1  the outgoing film copy, 2 the incoming one
    10  the veil         11  the copy */
.fs-photo { z-index: 0; }
.fs-video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  object-position: var(--fx, 50%) var(--fy, 38%);
  opacity: 0; transition: opacity 800ms ease; pointer-events: none; z-index: 1;
}
.fs-veil { z-index: 10; }
.fs > .wrap { z-index: 11; }
.fs-video.is-up { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .fs-video { display: none; } }

/* The veil. Two literal gradients: one across, heaviest under the copy and
   lightest over the face; one down, so the foot of the band where the button
   sits is always dark and the top stays open. */
.fs-veil {
  position: absolute; inset: 0; display: block;
  background:
    linear-gradient(90deg,  rgba(6, 11, 24, .82) 0%, rgba(6, 11, 24, .66) 38%, rgba(6, 11, 24, .22) 70%, rgba(6, 11, 24, .08) 100%),
    linear-gradient(180deg, rgba(6, 11, 24, .30) 0%, rgba(6, 11, 24, .06) 36%, rgba(6, 11, 24, .74) 100%);
}
/* Copy on the right, face on the left: the same veil, mirrored. */
.fs.copy-right .fs-veil {
  background:
    linear-gradient(270deg, rgba(6, 11, 24, .82) 0%, rgba(6, 11, 24, .66) 38%, rgba(6, 11, 24, .22) 70%, rgba(6, 11, 24, .08) 100%),
    linear-gradient(180deg, rgba(6, 11, 24, .30) 0%, rgba(6, 11, 24, .06) 36%, rgba(6, 11, 24, .74) 100%);
}
/* A playing film has no fixed dark region, so the film band's copy zone
   carries its own: the left 60% darkens to a stop measured for the brightest
   frame, the right side stays open for the picture. */
.fs-film .fs-veil {
  background:
    linear-gradient(90deg, rgba(10,18,36,.88) 0%, rgba(10,18,36,.8) 40%, rgba(10,18,36,.3) 66%, rgba(10,18,36,0) 84%),
    linear-gradient(180deg, rgba(10,18,36,0) 55%, rgba(10,18,36,.45) 100%);
}

.fs > .wrap { position: relative; width: 100%; padding-top: clamp(40px, 6vw, 80px); padding-bottom: clamp(44px, 6vw, 88px); }
.fs-copy { max-width: 640px; }
.fs.copy-right .fs-copy { margin-left: auto; }

/* Measured at 390px: the .hero-stage breadcrumb blue reached only 2.0:1
   against the brightest pixel under it. */
.fs .breadcrumbs, .fs .breadcrumbs a { color: #D3DEEF; }
.fs .breadcrumbs a:hover { color: #fff; }

/* The display pairing at page-top size: the wordmark's own 750 then 300. */
.fs-h { margin: 0; color: #fff; font-size: clamp(38px, 5.4vw, 68px); line-height: 1.02; letter-spacing: -0.032em; font-weight: 750; }
.fs-h > span { display: block; text-wrap: balance; }
.fs-h .light { font-weight: 300; }
.fs-h2 { margin: 0; color: #fff; font-size: clamp(32px, 4.2vw, 54px); line-height: 1.06; letter-spacing: -0.03em; font-weight: 750; text-wrap: balance; }
.fs .lead { color: #D3DEEF; max-width: 560px; }
.fs-link { color: #fff; font-weight: 650; text-decoration: underline; text-underline-offset: 4px; }
.fs-link:hover { color: #fff; text-decoration-thickness: 2px; }
.fs-note { margin: 14px 0 0; font-size: 14.5px; line-height: 1.5; color: #C0CDE4; }
/* The white button on a photographic band is literal too: .btn-white paints
   var(--white), which is the card surface (#131C2B) in the dark theme, and on
   the hospital still that came out as a dark slab with blue text. #1A6B94 is
   the light theme's --action-ink, 5.8:1 on white. */
.fs .btn-white { background: #fff; color: #1A6B94; }
.fs .btn-white:hover { background: #fff; color: #0F5273; }

/* A phone crops the 16:9 frame to a portrait; the copy sits under the face,
   so the veil runs top to bottom instead of left to right. */
@media (max-width: 720px) {
  .fs { min-height: clamp(560px, 92vh, 820px); }
  .fs-close { min-height: clamp(520px, 78vh, 720px); }
  .fs-veil, .fs.copy-right .fs-veil {
    background: linear-gradient(180deg, rgba(6, 11, 24, .26) 0%, rgba(6, 11, 24, .12) 20%, rgba(6, 11, 24, .84) 38%, rgba(6, 11, 24, .94) 100%);
  }
  .fs-film .fs-veil {
    background: linear-gradient(180deg, rgba(10,18,36,.22) 0%, rgba(10,18,36,.55) 42%, rgba(10,18,36,.86) 100%);
  }
  .fs.copy-right .fs-copy { margin-left: 0; }
}

/* ---- 2. Statement -------------------------------------------------------
   A display heading and one paragraph on the page ground, nothing else in the
   band. The plan's display is 100px; at 1040 that holds about 20 characters a
   line. It sits at 76 since 2026-09-15, sized to the homepage heading
   "Messages from everywhere / Someone gets missed": the longer line
   measures 13.2em in the 750 weight, so 76 holds it on one line in 1040 with
   a little to spare, and 6.6vw keeps it there down to about 670px wide, below
   which it wraps and text-wrap balances it. A longer heading tried the same
   day ("People reach out from everywhere.", 16.1em) only fitted at 63; if the
   words get longer again, this number has to come down with them. */
.stm { max-width: 1040px; }
.stm .display { font-size: clamp(38px, 6.6vw, 76px); }
.stm .display > span { display: block; text-wrap: balance; }
.stm-body { margin: clamp(22px, 3vw, 36px) 0 0; max-width: 720px; font-size: clamp(19px, 1.7vw, 22px); line-height: 1.55; color: var(--slate); text-wrap: pretty; }

/* ---- 3. Showcase --------------------------------------------------------
   The dark slab band with one real capture of the product. --slab and
   --slab-ink are dark in BOTH themes by design, so this band never flips.
   The capture's rounded top corners run off the bottom of the band. */
.sc { background: var(--slab); color: var(--slab-ink); padding: clamp(72px, 9vw, 140px) 0 0; overflow: clip; }
.sc-head { max-width: 820px; }
.sc h2 { color: var(--slab-ink); }
.sc .lead { color: var(--slab-dim); }
.sc-link { margin: 18px 0 0; }
/* A note about the capture, and it sits ABOVE the picture on purpose: the frame
   runs off the bottom of the band, so there is no room under it for a caption.
   --slab-dim is the lead's own colour, so the note reads as the quiet end of
   the same paragraph rather than as a second voice. */
.sc-note { margin: 14px 0 0; font-size: 14.5px; line-height: 1.5; color: var(--slab-dim); }
.sc .link { color: var(--slab-ink); }
.sc .link:hover { color: var(--slab-ink); }
.sc-frame {
  margin: clamp(36px, 5vw, 64px) auto 0; max-width: 1040px;
  border-radius: 20px 20px 0 0; overflow: hidden; background: var(--white);
  box-shadow: 0 -16px 56px rgba(0, 0, 0, .32);
}
/* A capture taller than wide is cropped to the band it is meant to show and
   runs off the bottom. An explicit height, not max-height: object-position
   only crops against a box that has one, and with max-height the picture
   simply showed its top. */
.sc-frame-crop { height: clamp(360px, 52vw, 640px); }
.sc-frame-crop img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 43%; display: block; }
/* Under 720px a <picture> may swap in a tight crop that is already the band
   wanted, so the frame takes the crop's own height instead of cover-cropping
   it a second time and trimming its outer tiles. */
@media (max-width: 720px) {
  .sc-frame-crop { height: auto; }
  .sc-frame-crop img { height: auto; object-fit: fill; }
}
/* The honest "Screenshot to come" state runs off the band the way a capture
   would, rather than holding a whole 16:10 of stripes. Capped at 400: at 520
   the plate was two thirds of the third screen a visitor sees at 1280x800 and
   the page read as unfinished before it had said anything. */
.sc-frame:has(.shot) { max-height: clamp(260px, 30vw, 400px); }
.sc-frame .shot { margin: 0; }
.sc-frame .shot-frame { border: 0; border-radius: 0; box-shadow: none; }

/* ---- 3b. The live inbox (showcase with `inbox`) -------------------------
   The homepage's answer to the statement band above it: every channel a
   seeker uses, feeding one inbox, worked by a named team. It is a picture of
   the product, not a capture of it, so every word in it is illustrative and
   the note under it says so.

   It is the finished picture WITHOUT JavaScript. The server renders one
   moment of the story (a new WhatsApp message waiting, the rest answered, the
   last exchange open), and site.js only ever plays it forward from there.
   .is-live is added by the driver alone, so reduced motion, no JS or an old
   browser all get exactly that still.

   It is the same scene in both themes: the band is --slab, which never
   flips, and the window is a screen, which is dark in both. Colour lives
   inside the provider marks, the avatars and the dots; no surface is tinted
   and nothing carries a bar down one edge (CLAUDE.md, "The banned shape"). */
.sc-ix { padding-bottom: clamp(72px, 9vw, 132px); }
.ix {
  --ix-win: #101A2C;
  --ix-list: #0D1625;
  --ix-line: rgba(233, 238, 247, .08);
  --ix-ink: #EEF2F8;
  --ix-dim: #A9B6CC;
  --ix-faint: #8795AE;
  --ix-bubble: #1C2940;
  --ix-good: #43D6A0;
  --ix-new: #6CC4F2;
  --ix-ease: cubic-bezier(.2, .7, .2, 1);
  position: relative;
  margin: clamp(44px, 5.5vw, 80px) auto 0;
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  column-gap: clamp(64px, 8vw, 120px);
  align-items: center;
  isolation: isolate;
}
/* The light the window sits in. A blurred wash, not a border or a tint on
   the window itself, so the window stays one flat screen. */
.ix::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: 4% -6% -10% 14%;
  background:
    radial-gradient(50% 55% at 60% 40%, rgba(61, 180, 232, .34), transparent 70%),
    radial-gradient(42% 45% at 22% 78%, rgba(0, 112, 248, .22), transparent 72%);
  filter: blur(28px);
}

/* The channels. Other companies' marks, shown exactly as supplied: never
   recoloured, never filtered. Each sits on the same glass tile so a mark
   that is mostly white or mostly dark still reads. Four channels have no
   brand (text, phone, email, web chat) and carry a plain line glyph. */
.ix-rail { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; position: relative; z-index: 1; }
.ix-src {
  width: 52px; height: 52px; border-radius: 15px; display: grid; place-items: center;
  background: linear-gradient(180deg, rgba(255, 255, 255, .09), rgba(255, 255, 255, .04));
  border: 1px solid rgba(233, 238, 247, .12);
  box-shadow: 0 10px 24px -12px rgba(0, 0, 0, .6);
  transition: transform .5s var(--ix-ease), border-color .5s, box-shadow .5s;
}
.ix-src img { width: 30px; height: 30px; object-fit: contain; }
.ix-src svg, .ix-mark svg { width: 24px; height: 24px; color: #D3DCEA; }
.ix-src.is-live {
  transform: scale(1.1);
  border-color: rgba(108, 196, 242, .7);
  box-shadow: 0 0 0 4px rgba(108, 196, 242, .14), 0 0 32px rgba(108, 196, 242, .4);
}

/* The wires from each channel into the inbox. Drawn by site.js from the
   measured positions, so nothing here knows a coordinate. */
.ix-wires { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 0; }
.ix-wire { fill: none; stroke: rgba(169, 182, 204, .16); stroke-width: 1.25; }
.ix-pulse { fill: none; stroke: #8FD3F7; stroke-width: 2.5; stroke-linecap: round; opacity: 0; filter: drop-shadow(0 0 6px rgba(108, 196, 242, .9)); }
.ix-pulse.is-run { opacity: 1; animation: ix-run .95s var(--ix-ease) forwards; }
@keyframes ix-run { from { stroke-dashoffset: var(--run); } to { stroke-dashoffset: 0; } }
.ix-port {
  position: absolute; z-index: 2; left: -6px; top: 118px; width: 11px; height: 11px; border-radius: 50%;
  background: #0D1625; border: 2px solid rgba(108, 196, 242, .8); box-shadow: 0 0 12px rgba(108, 196, 242, .6);
}

/* The window. */
.ix-win {
  position: relative; z-index: 1; min-width: 0;
  background: var(--ix-win); color: var(--ix-ink);
  border-radius: 22px; border: 1px solid rgba(233, 238, 247, .11);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06), 0 50px 100px -40px rgba(0, 0, 0, .85), 0 0 0 1px rgba(0, 0, 0, .3);
  font-size: 14px; line-height: 1.4;
  /* start, never left: a line marked dir="auto" then aligns by its own
     script, so an Arabic reply types in from the right edge and grows
     leftward with the caret on its left, the way it would be written.
     (Andre, 2026-09-26: right-to-left has to animate right to left.) */
  text-align: start;
}
.ix-clip { border-radius: inherit; overflow: hidden; }
.ix-bar { display: flex; align-items: center; gap: 14px; height: 60px; padding: 0 22px; border-bottom: 1px solid var(--ix-line); }
.ix-brand { display: flex; align-items: center; gap: 10px; font-weight: 650; font-size: 15px; letter-spacing: -.005em; }
.ix-brand img { width: 24px; height: 24px; }
.ix-brand span { color: var(--ix-dim); font-weight: 500; }
.ix-team { margin-left: auto; display: flex; align-items: center; gap: 12px; font-size: 13px; color: var(--ix-dim); white-space: nowrap; }
.ix-team b { color: var(--ix-ink); font-weight: 600; }
.ix-avs { display: flex; }
.ix-avs .ix-av { box-shadow: 0 0 0 2px var(--ix-win); transition: transform .45s var(--ix-ease), box-shadow .45s; }
.ix-avs .ix-av + .ix-av { margin-left: -7px; }
.ix-avs .ix-av.is-live { transform: translateY(-3px); box-shadow: 0 0 0 2px var(--ix-win), 0 0 0 4px rgba(108, 196, 242, .8); position: relative; z-index: 1; }

/* Avatars: an initial on a colour. The colours are the scene's own and each
   one carries white text at 4.5:1 or better. */
.ix-av {
  flex: none; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  font-size: 12px; font-weight: 700; color: #fff; letter-spacing: 0;
}
.ix-av.sm { width: 22px; height: 22px; font-size: 10.5px; }
.ix-av.t1 { background: #2A6FB8; }
.ix-av.t2 { background: #177A5B; }
.ix-av.t3 { background: #A8531B; }
.ix-av.t4 { background: #5E4FC4; }
.ix-av.t5 { background: #B03A69; }
.ix-av.t6 { background: #197A86; }

.ix-body { display: grid; grid-template-columns: minmax(0, 43fr) minmax(0, 57fr); height: 468px; }

/* The inbox list. */
.ix-list { background: var(--ix-list); border-right: 1px solid var(--ix-line); display: flex; flex-direction: column; min-height: 0; }
.ix-list-head { display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 10px; font-size: 13.5px; font-weight: 650; }
.ix-wait { display: inline-flex; align-items: center; gap: 8px; font-weight: 500; color: var(--ix-dim); font-variant-numeric: tabular-nums; }
.ix-wait b { color: var(--ix-ink); font-weight: 650; }
.ix-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ix-new); flex: none; box-shadow: 0 0 10px rgba(108, 196, 242, .8); }
.ix-wait.is-clear .ix-dot { background: var(--ix-good); box-shadow: 0 0 10px rgba(67, 214, 160, .7); }
.ix-rows {
  list-style: none; margin: 0; padding: 0 10px 10px; flex: 1; min-height: 0; overflow: hidden;
  -webkit-mask-image: linear-gradient(#000 80%, transparent); mask-image: linear-gradient(#000 80%, transparent);
}
.ix-row { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .6s var(--ix-ease), opacity .5s var(--ix-ease); }
.ix-row > div { min-height: 0; overflow: hidden; }
.ix-row.is-entering { grid-template-rows: 0fr; opacity: 0; }
.ix-card {
  display: grid; grid-template-columns: 38px minmax(0, 1fr) auto; column-gap: 12px; align-items: center;
  padding: 12px 12px; margin-bottom: 2px; border-radius: 14px; transition: background-color .5s;
}
.ix-row.is-focus .ix-card { background: rgba(233, 238, 247, .06); }
.ix-mark {
  width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center;
  background: rgba(233, 238, 247, .06); border: 1px solid rgba(233, 238, 247, .07);
}
.ix-mark img { width: 22px; height: 22px; object-fit: contain; }
.ix-mark svg { width: 19px; height: 19px; }
.ix-who { min-width: 0; }
.ix-name { display: block; font-size: 14px; font-weight: 600; color: var(--ix-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ix-prev { display: block; margin-top: 2px; font-size: 13px; color: var(--ix-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ix-state { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 550; color: var(--ix-dim); white-space: nowrap; }
.ix-state.is-new { color: var(--ix-ink); }
.ix-state svg { width: 15px; height: 15px; color: var(--ix-good); }
.ix-state > * { animation: ix-pop .45s var(--ix-ease); }
@keyframes ix-pop { from { opacity: 0; transform: translateY(4px) scale(.96); } }

/* The open conversation. */
.ix-thread { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.ix-th-head { display: flex; align-items: center; gap: 12px; min-height: 68px; padding: 12px 22px; border-bottom: 1px solid var(--ix-line); }
.ix-th-head .ix-mark { width: 34px; height: 34px; border-radius: 10px; }
.ix-th-head .ix-mark img { width: 20px; height: 20px; }
.ix-th-name { font-size: 14.5px; font-weight: 650; }
.ix-th-ch { display: block; font-size: 12.5px; color: var(--ix-dim); }
.ix-th-by { margin-left: auto; display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ix-dim); white-space: nowrap; }
.ix-th-by b { color: var(--ix-ink); font-weight: 600; }
.ix-msgs {
  flex: 1; min-height: 0; overflow: hidden; padding: 20px 22px 6px; display: flex; flex-direction: column; justify-content: flex-end; gap: 10px;
  -webkit-mask-image: linear-gradient(transparent, #000 56px); mask-image: linear-gradient(transparent, #000 56px);
}
.ix-msg { max-width: 84%; padding: 11px 15px; border-radius: 19px; font-size: 14.5px; line-height: 1.45; animation: ix-in .5s var(--ix-ease) both; }
.ix-msg.is-in { align-self: flex-start; background: var(--ix-bubble); color: var(--ix-ink); border-bottom-left-radius: 6px; }
.ix-msg.is-out { align-self: flex-end; background: linear-gradient(135deg, #2A7B9F 0%, #176F9A 100%); color: #fff; border-bottom-right-radius: 6px; }
.ix-meta { font-size: 11.5px; color: var(--ix-faint); margin: -2px 6px 0; animation: ix-in .5s var(--ix-ease) both; }
.ix-meta.is-out { align-self: flex-end; }
@keyframes ix-in { from { opacity: 0; transform: translateY(10px); } }
/* Switching conversations: the header and the messages fade as two elements
   on one curve, so the header can never name the last seeker over a thread
   that has already emptied (it did, for a third of a second, when only the
   bubbles faded). */
.ix-th-head, .ix-msgs { transition: opacity .25s var(--ix-ease); }
.ix-thread.is-switching .ix-th-head,
.ix-thread.is-switching .ix-msgs { opacity: 0; }
/* A voicemail, played inside the conversation. */
.ix-vm { display: flex; align-items: center; gap: 12px; }
.ix-vm-play { width: 30px; height: 30px; border-radius: 50%; background: rgba(233, 238, 247, .12); display: grid; place-items: center; flex: none; }
.ix-vm-play svg { width: 12px; height: 12px; margin-left: 2px; color: var(--ix-ink); }
.ix-vm-wave { display: flex; align-items: center; gap: 3px; height: 26px; }
.ix-vm-wave i { width: 3px; border-radius: 2px; background: rgba(233, 238, 247, .55); }
.ix-sys { align-self: center; display: inline-flex; align-items: center; gap: 8px; margin: 2px 0; font-size: 12.5px; color: var(--ix-faint); animation: ix-in .5s var(--ix-ease) both; }
.ix-sys b { color: var(--ix-dim); font-weight: 600; }
.ix-sys svg { width: 14px; height: 14px; color: var(--ix-good); }
.ix-sys .ix-av.sm { width: 18px; height: 18px; font-size: 9.5px; }
.ix-compose {
  display: flex; align-items: center; gap: 10px; margin: 10px 18px 18px; padding: 7px 7px 7px 16px;
  border-radius: 15px; background: rgba(233, 238, 247, .045); border: 1px solid var(--ix-line);
}
.ix-input { flex: 1; min-width: 0; font-size: 14px; color: var(--ix-faint); white-space: nowrap; overflow: hidden; text-overflow: clip; }
.ix-input.is-typing { color: var(--ix-ink); }
.ix-input.is-typing::after { content: ''; display: inline-block; width: 1.5px; height: 1.05em; margin-left: 2px; vertical-align: -2px; background: var(--ix-new); animation: ix-caret 1s steps(1) infinite; }
@keyframes ix-caret { 50% { opacity: 0; } }
.ix-send {
  flex: none; width: 36px; height: 36px; border-radius: 11px; display: grid; place-items: center;
  background: linear-gradient(135deg, #2A7B9F 0%, #176F9A 100%); transition: transform .25s var(--ix-ease), box-shadow .25s;
}
.ix-send svg { width: 16px; height: 16px; color: #fff; }
.ix-send.is-hit { transform: scale(.9); box-shadow: 0 0 0 5px rgba(108, 196, 242, .25); }

.ix-note { margin-top: clamp(20px, 2.4vw, 28px); text-align: center; }

/* The entrance, only when something is present to play it. */
.ix.is-live .ix-win { opacity: 0; transform: translateY(28px) scale(.985); transition: opacity .9s var(--ix-ease), transform 1.1s var(--ix-ease); }
.ix.is-live .ix-src { opacity: 0; transform: translateX(-10px); transition: opacity .6s var(--ix-ease), transform .6s var(--ix-ease), border-color .5s, box-shadow .5s; }
.ix.is-live .ix-wire { stroke-dasharray: var(--len); stroke-dashoffset: var(--len); transition: stroke-dashoffset 1.2s var(--ix-ease); }
.ix.is-in .ix-win { opacity: 1; transform: none; }
.ix.is-in .ix-src { opacity: 1; transform: none; }
.ix.is-in .ix-src.is-live { transform: scale(1.1); }
.ix.is-in .ix-wire { stroke-dashoffset: 0; }

/* Tablet and down: the channels become a row above the window, and the
   wires go (there is no room for a curve worth drawing). */
@media (max-width: 1023px) {
  .ix { grid-template-columns: minmax(0, 1fr); row-gap: 26px; }
  .ix-rail { flex-direction: row; justify-content: center; flex-wrap: wrap; gap: 10px; }
  .ix-src { width: 46px; height: 46px; border-radius: 14px; }
  .ix-src img { width: 26px; height: 26px; }
  .ix-wires, .ix-port { display: none; }
  .ix::before { inset: 10% -4% -6% -4%; }
  .ix.is-live .ix-src { transform: translateY(8px); }
}
@media (max-width: 720px) {
  .ix-rail { display: grid; grid-template-columns: repeat(9, minmax(0, 1fr)); gap: 6px; }
  .ix-src { width: auto; height: auto; aspect-ratio: 1; border-radius: 10px; }
  .ix-src img { width: 58%; height: 58%; }
  .ix-src svg { width: 50%; height: 50%; }
  .ix-bar { height: 54px; padding: 0 16px; }
  .ix-brand span { display: none; }
  .ix-team .ix-avs .ix-av:nth-child(n+5) { display: none; }
  .ix-body { grid-template-columns: minmax(0, 1fr); height: auto; }
  .ix-list { border-right: 0; border-bottom: 1px solid var(--ix-line); }
  .ix-list-head { padding: 14px 16px 8px; }
  .ix-rows { height: 262px; flex: none; padding: 0 6px 6px; }
  .ix-card { padding: 10px; column-gap: 11px; grid-template-columns: 34px minmax(0, 1fr) auto; }
  .ix-mark { width: 34px; height: 34px; }
  .ix-th-head { min-height: 60px; padding: 10px 16px; }
  .ix-th-by > span:first-child { display: none; }
  .ix-msgs { height: 250px; flex: none; padding: 16px 16px 4px; }
  .ix-msg { font-size: 14px; max-width: 88%; }
  .ix-compose { margin: 8px 12px 12px; }
}

/* ---- 4. Steps, plain ----------------------------------------------------
   A large light numeral above one sentence each, hairline-separated. No
   cards, no ticks. The ask sits under the row. */
.stp-list { list-style: none; margin: clamp(32px, 4vw, 56px) 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.stp-list li { padding: 0 clamp(22px, 3vw, 44px); border-left: 1px solid var(--cloud); }
.stp-list li:first-child { padding-left: 0; border-left: 0; }
.stp-num { display: block; font-size: clamp(56px, 5.6vw, 72px); font-weight: 300; line-height: 1; letter-spacing: -0.03em; color: var(--ink); font-variant-numeric: tabular-nums; }
.stp-list p { margin: 18px 0 0; font-size: 18px; line-height: 1.5; color: var(--slate); max-width: 300px; }
.stp .cta-row { margin-top: clamp(32px, 4vw, 52px); }
@media (max-width: 760px) {
  .stp-list { grid-template-columns: 1fr; gap: 22px; }
  .stp-list li { display: grid; grid-template-columns: 60px 1fr; gap: 14px; align-items: start; padding: 22px 0 0; border-left: 0; border-top: 1px solid var(--cloud); }
  .stp-list li:first-child { padding-top: 0; border-top: 0; }
  .stp-num { font-size: 48px; }
  .stp-list p { margin-top: 8px; }
}

/* ---- 5. Photographic band, copy BESIDE the picture ----------------------
   The photograph bleeds to one edge; the copy sits on the page ground next to
   it, so this band uses the ramp only, flips with the theme, and
   tools/contrast.mjs can measure every word of it. */
.fsb { background: var(--white); overflow: clip; }
.fsb-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; min-height: clamp(480px, 66vh, 760px); }
.fsb-photo { position: relative; margin: 0; height: 100%; min-height: 100%; }
.fsb-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: var(--fx, 50%) 40%; display: block; }
.fsb-copy { padding: clamp(56px, 7vw, 112px) clamp(24px, 3.5vw, 40px) clamp(56px, 7vw, 112px) clamp(32px, 5.5vw, 88px); max-width: 720px; }
.fsb-copy .body { max-width: 560px; }
.fsb.flip .fsb-photo { order: 2; }
.fsb.flip .fsb-copy { padding-left: clamp(24px, 3.5vw, 40px); padding-right: clamp(32px, 5.5vw, 88px); }
@media (max-width: 820px) {
  .fsb-grid { grid-template-columns: 1fr; min-height: 0; }
  .fsb-photo, .fsb.flip .fsb-photo { height: auto; min-height: 0; aspect-ratio: 4 / 3; order: 0; }
  .fsb-copy { padding: clamp(36px, 7vw, 64px) clamp(20px, 3.5vw, 40px) clamp(48px, 8vw, 80px); }
}

/* ---- 6. The figures band ------------------------------------------------
   The shared statband, restyled: its box taken away so three real totals sit
   on one hairline under a plain sentence. The block's markup is still
   site.js's -- only its surface changes here. */
.figs .statband { background: transparent; border: 0; border-radius: 0; padding: 0; }
.figs .statband-head { font-size: clamp(19px, 1.7vw, 22px); font-weight: 500; color: var(--ink); }
.figs .stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(20px, 3vw, 44px); margin-top: clamp(24px, 3vw, 36px); padding-top: clamp(24px, 3vw, 36px); border-top: 1px solid var(--cloud); }
.figs .stat-num { font-size: clamp(40px, 5.6vw, 72px); letter-spacing: -0.035em; }
.figs .stat-label { font-size: 16px; margin-top: 8px; }
.figs .statband > .meta { margin-top: clamp(20px, 2.6vw, 30px); font-size: 14.5px; color: var(--slate); }
@media (max-width: 560px) { .figs .stat-grid { grid-template-columns: 1fr; gap: 18px; } }

/* ---- 7. Priceline -------------------------------------------------------
   Three plan lines separated by hairlines. Name, price, seats. No cards, no
   ticks, no buttons -- the page it links to has all three. */
.pl { list-style: none; margin: clamp(28px, 3.5vw, 44px) 0 0; padding: 0; border-top: 1px solid var(--cloud); }
.pl li { display: grid; grid-template-columns: minmax(110px, .7fr) minmax(150px, .9fr) 2fr; gap: 12px 28px; align-items: baseline; padding: clamp(18px, 2.4vw, 28px) 0; border-bottom: 1px solid var(--cloud); }
.pl-name { font-size: 19px; font-weight: 700; color: var(--ink); }
.pl-price { font-size: clamp(22px, 2.2vw, 28px); font-weight: 650; letter-spacing: -0.02em; color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
.pl-price small { font-size: 14.5px; font-weight: 500; letter-spacing: 0; color: var(--slate); margin-left: 6px; }
.pl-seats { font-size: 18px; line-height: 1.5; color: var(--slate); }
/* The closing line spans the same width as the plan rows above it. It was capped at
   640px until 2026-09-16, which wrapped a four-sentence line into a narrow column
   under a table that runs the whole block. */
.pl-after { margin-top: clamp(22px, 2.8vw, 32px); }
@media (max-width: 560px) {
  .pl li { grid-template-columns: 1fr auto; }
  .pl-seats { grid-column: 1 / -1; font-size: 16px; }
}

/* ---- The photographic page header (2026-09-15) --------------------------
   `hero` with content.photo: a still from the homepage film behind the band,
   the ordinary header's words over it. Permanently dark in both themes, like
   .hero-stage and the homepage film, because the picture is a night or a dawn
   whatever the visitor's theme. Colours are literal for the same reason
   .fs .btn-white is: --white is the card surface in dark, not white.

   Text over a photograph is invisible to tools/contrast.mjs, so the veil is
   measured by screenshot: heaviest under the copy, lightest over the person,
   and the foot always dark. Do not thin it without sampling the brightest
   frame pixels under the words again. */
.page-hero.hero-photo {
  position: relative; isolation: isolate; overflow: clip;
  display: flex; flex-direction: column; justify-content: center;
  min-height: clamp(500px, 72vh, 760px);
  background: #0A1224; color: #F2F6FC;
  padding: clamp(40px, 6vw, 88px) 0;
}
.hero-photo-img {
  position: absolute; inset: 0; z-index: -3; display: block;
  width: 100%; height: 100%; object-fit: cover;
  object-position: var(--fp, 50% 40%);
}
/* The optional loop sits between the still and the veil, on the same crop, so
   it fades in over its own first frame and a refused autoplay shows nothing at
   all. The still keeps the lower level: it is the page, the clip is a bonus. */
.hero-photo-video {
  position: absolute; inset: 0; z-index: -2; display: block;
  width: 100%; height: 100%; object-fit: cover;
  object-position: var(--fp, 50% 40%);
  opacity: 0; transition: opacity 700ms ease; pointer-events: none;
}
.hero-photo-video.is-up { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .hero-photo-video { display: none; } }
.hero-photo-veil {
  position: absolute; inset: 0; z-index: -1; display: block;
  background:
    linear-gradient(90deg, rgba(6, 11, 24, .86) 0%, rgba(6, 11, 24, .72) 34%, rgba(6, 11, 24, .26) 58%, rgba(6, 11, 24, .04) 100%),
    linear-gradient(180deg, rgba(6, 11, 24, .3) 0%, rgba(6, 11, 24, 0) 26%, rgba(6, 11, 24, .5) 100%);
}
.hero-photo.copy-right .hero-photo-veil {
  background:
    linear-gradient(270deg, rgba(6, 11, 24, .86) 0%, rgba(6, 11, 24, .72) 34%, rgba(6, 11, 24, .26) 58%, rgba(6, 11, 24, .04) 100%),
    linear-gradient(180deg, rgba(6, 11, 24, .3) 0%, rgba(6, 11, 24, 0) 26%, rgba(6, 11, 24, .5) 100%);
}
/* Centred words have no side to hide on, so the veil is even across. */
.hero-photo.is-center .hero-photo-veil {
  background:
    radial-gradient(ellipse 70% 80% at 50% 55%, rgba(6, 11, 24, .74) 0%, rgba(6, 11, 24, .5) 60%, rgba(6, 11, 24, .36) 100%);
}
.hero-photo > .wrap { position: relative; width: 100%; }
.hero-photo-copy { max-width: 600px; }
.hero-photo.copy-right .hero-photo-copy { margin-left: auto; }
.hero-photo.is-center .hero-photo-copy { max-width: 760px; margin-inline: auto; text-align: center; }
.hero-photo.is-center .cta-row { justify-content: center; }
.hero-photo.is-center .cta-note,
.hero-photo.is-center [data-filter-input] { margin-inline: auto; }
.hero-photo.copy-right .breadcrumbs { justify-content: flex-end; }
/* Near-white: at the top of a long header on a phone the #D3DEEF crumb measured 4.3:1. */
.hero-photo .breadcrumbs, .hero-photo .breadcrumbs a, .hero-photo .breadcrumbs span { color: #EEF3FA; }
.hero-photo .breadcrumbs a:hover { color: #fff; }
/* Near-white, not the cyan eyebrow: 13px over a dawn sky measured 4.0:1 in cyan. */
.hero-photo .eyebrow { color: #E3F4FD; }
.hero-photo h1 {
  margin-top: 14px; color: #fff;
  font-size: clamp(36px, 5vw, 62px); line-height: 1.05;
  letter-spacing: -0.032em; text-wrap: balance;
}
.hero-photo .lead { color: #D3DEEF; max-width: 560px; }
.hero-photo.is-center .lead { margin-inline: auto; }
.hero-photo .lead a, .hero-photo-aside a { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.page-hero.hero-photo .lead strong, .page-hero.hero-photo .lead b { color: #fff; }
.hero-photo-aside { font-size: 14.5px; color: #C0CDE4; }
.hero-photo-link { color: #fff; font-weight: 650; font-size: 15px; text-decoration: underline; text-underline-offset: 4px; }
.hero-photo .cta-note { color: #B4C3DB; }
.hero-photo .meta { color: #B4C3DB; }
.hero-photo .btn-white { background: #fff; color: #1A6B94; }
.hero-photo .btn-white:hover { background: #fff; color: #0F5273; }
.hero-photo .input { background: rgba(255, 255, 255, .96); color: #0E1726; border-color: transparent; }
.hero-photo .input::placeholder { color: #5A6B85; }
@media (max-width: 720px) {
  .page-hero.hero-photo { justify-content: flex-end; min-height: clamp(560px, 88vh, 780px); padding-bottom: 36px; }
  .hero-photo-veil, .hero-photo.copy-right .hero-photo-veil, .hero-photo.is-center .hero-photo-veil {
    /* A long header's breadcrumb sits a fifth of the way down a phone, so the
       veil is already heavy there: at .14 it measured 1.9:1 over a bright sky. */
    background: linear-gradient(180deg, rgba(6, 11, 24, .38) 0%, rgba(6, 11, 24, .58) 14%, rgba(6, 11, 24, .86) 34%, rgba(6, 11, 24, .94) 100%);
  }
  .hero-photo.copy-right .hero-photo-copy { margin-left: 0; }
  .hero-photo.copy-right .breadcrumbs { justify-content: flex-start; }
}

/* How EchoGlobal Works: the queue header with a photograph. The words sit on
   the film still exactly as they do on every other photographic header, and
   the inbox panel follows on the page ground, so the section loses its own top
   padding (the photograph is the top) and keeps the panel's. */
.hero-queue.has-photo { padding-top: 0; }
/* The queue header's copy column is 720px because its three-phrase subheading
   is sized to fit exactly that; at the photo header's 600 it broke after the
   first bullet. */
.hero-queue.has-photo .hero-photo-copy { max-width: 720px; }
.hero-photo .hero-sub { color: #fff; }

/* ── Echo Academy: the classroom (2026-09-22) ─────────────────────────────
   A course page with videos, after Andre's OneSocially "Whiteboard" lesson
   page: the video large on a dark band, the course's lessons as a strip of
   thumbnails under it, the lesson's words below. The band is dark in BOTH
   themes, like a cinema, so its colours are fixed rather than themed; each
   was measured on #0B1220 (#EEF1F6 16.5:1, #A3AEC2 8.4:1). A course of one
   lesson has no strip: it is the video. */
.classroom { background: #0B1220; color: #EEF1F6; padding: clamp(18px, 2.4vw, 30px) 0 clamp(26px, 3.4vw, 44px); }
.classroom .breadcrumbs, .classroom .breadcrumbs a { color: #A3AEC2; }
.classroom .breadcrumbs a:hover { color: #EEF1F6; }
.classroom-player {
  position: relative; margin: 0 auto; aspect-ratio: 16 / 9; overflow: hidden;
  width: min(100%, 1120px, calc((100svh - 350px) * 16 / 9)); min-width: min(100%, 560px);
  border-radius: 14px; background: #000; box-shadow: 0 30px 80px rgba(0, 0, 0, .45);
}
/* No strip under it, so the video takes the room the strip would have. */
.classroom.is-single .classroom-player { width: min(100%, 1120px, calc((100svh - 200px) * 16 / 9)); }
.classroom-poster { position: absolute; inset: 0; z-index: 1; cursor: pointer; color: #FFFFFF; text-decoration: none; }
.classroom-poster img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Bottom left, so it never sits on the words the thumbnail carries. */
.classroom-play {
  position: absolute; left: clamp(14px, 2.4vw, 28px); bottom: clamp(14px, 2.4vw, 28px);
  display: inline-flex; align-items: center; gap: 10px; padding: 12px 22px 12px 18px; border-radius: 999px;
  background: var(--grad-action); color: #FFFFFF; font-weight: 650; font-size: 17px;
  box-shadow: 0 14px 34px rgba(0, 0, 0, .45); transition: transform .2s ease;
}
.classroom-play svg { width: 14px; height: 16px; }
.classroom-poster:hover .classroom-play, .classroom-poster:focus-visible .classroom-play { transform: scale(1.05); }
.classroom-poster:focus-visible { outline: 3px solid #3DB4E8; outline-offset: -3px; }
.classroom-poster[hidden] { display: none; }
.classroom-player iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.classroom-strip {
  display: flex; gap: 16px; margin: clamp(18px, 2.4vw, 28px) auto 0; padding: 6px 4px 10px;
  width: fit-content; max-width: 100%; overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: thin; scrollbar-color: #2A3549 transparent;
}
.classroom-tile { flex: 0 0 208px; scroll-snap-align: start; color: #A3AEC2; text-decoration: none; }
.classroom-thumb { position: relative; display: block; aspect-ratio: 16 / 9; border-radius: 10px; overflow: hidden; background: #1A2436; }
.classroom-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: .62; transition: opacity .2s; }
.classroom-thumb::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08); }
.classroom-tile:hover .classroom-thumb img, .classroom-tile:focus-visible .classroom-thumb img, .classroom-tile[aria-current] .classroom-thumb img { opacity: 1; }
.classroom-tile[aria-current] .classroom-thumb::after { box-shadow: inset 0 0 0 3px #3DB4E8; }
.classroom-tile:focus-visible { outline: none; }
.classroom-tile:focus-visible .classroom-thumb { outline: 2px solid #3DB4E8; outline-offset: 3px; }
.classroom-tile-title { display: block; margin-top: 10px; font-size: 14.5px; font-weight: 600; line-height: 1.3; color: #EEF1F6; }
.classroom-tile-meta { display: block; margin-top: 2px; font-size: 13px; color: #A3AEC2; }
.classroom-tile[aria-current] .classroom-tile-meta::before { content: "Playing · "; color: #3DB4E8; font-weight: 600; }
.classroom-info { display: grid; gap: clamp(26px, 3.4vw, 56px); grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); align-items: start; }
.classroom-info h1 { font-size: clamp(28px, 3.4vw, 44px); margin-top: 10px; }
.classroom-info .lead { margin-top: 12px; }
.classroom-next { margin-top: 22px; }
.classroom-next[hidden] { display: none; }
@media (max-width: 640px) {
  .classroom-player { border-radius: 10px; min-width: 100%; }
  .classroom-tile { flex-basis: 168px; }
}

/* "Watch the video" on a Help Center article (2026-09-22): each Echo Academy
   lesson that names this article, as the video's own thumbnail with its
   title beside it. A card on the site's hairline surface; no tint, no bar. */
.hc-watch { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 18px; }
.hc-watch-card {
  display: flex; align-items: center; gap: 14px; padding: 8px 18px 8px 8px; max-width: 100%;
  background: var(--white); border: 1px solid var(--cloud); border-radius: 14px;
  box-shadow: 0 6px 18px rgba(16, 24, 48, .08); color: var(--ink); text-decoration: none;
  transition: border-color .2s, transform .2s;
}
.hc-watch-card:hover { border-color: var(--echo-cyan); transform: translateY(-2px); }
.hc-watch-thumb { position: relative; flex: 0 0 128px; aspect-ratio: 16 / 9; border-radius: 9px; overflow: hidden; background: #0B1220; }
.hc-watch-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hc-watch-play {
  position: absolute; left: 6px; bottom: 6px; width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center; background: var(--grad-action); color: #FFFFFF; box-shadow: 0 6px 16px rgba(0, 0, 0, .35);
}
.hc-watch-play svg { width: 10px; height: 12px; margin-left: 2px; }
.hc-watch-text { display: grid; gap: 2px; min-width: 0; }
.hc-watch-label { font-size: 12.5px; font-weight: 600; color: var(--action-ink); }
.hc-watch-text b { font-size: 15.5px; line-height: 1.25; }
.hc-watch-min { font-size: 13px; color: var(--steel); }

/* A lesson's Help Center articles (2026-09-22): the Help Center's own
   picture cards, in a band under the lesson, swapped with the lesson. */
.classroom-reading { margin-top: clamp(28px, 3vw, 40px); }
.classroom-reading[hidden] { display: none; }
.classroom-reading h4 { margin: 0 0 14px; }
.classroom-reading-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
.classroom-article {
  display: flex; align-items: center; gap: 14px; padding: 8px 14px 8px 8px;
  background: var(--white); border: 1px solid var(--cloud); border-radius: 14px;
  box-shadow: 0 6px 18px rgba(16, 24, 48, .07); color: var(--ink); text-decoration: none;
  transition: border-color .2s, transform .2s;
}
.classroom-article:hover { border-color: var(--echo-cyan); transform: translateY(-2px); }
.classroom-article-shot { flex: 0 0 76px; aspect-ratio: 4 / 3; border-radius: 9px; overflow: hidden; background: var(--panel); }
.classroom-article-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.classroom-article-title { font-size: 15px; font-weight: 600; line-height: 1.3; }
.hc-hero-watch { margin: 16px 0 0; font-size: 15px; }


/* ============================================================
   The jump row: "On this page", under the header of a long page
   ============================================================
   Words and a hairline, nothing else: no pills, no tint, no bar. It stays
   under the site header while the page scrolls, so on a 1,900-word page the
   way to the next part is never more than a glance away. The current part is
   carried by weight and ink alone, the way the Help Center's contents rail
   does it. On a phone the links run sideways in one line. */
.page-jump {
  position: sticky; top: var(--header-h); z-index: 60;
  background: var(--header-bg); backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--cloud);
}
.page-jump .wrap { display: flex; align-items: center; gap: clamp(14px, 2vw, 26px); min-height: 52px; }
.pj-label { flex: 0 0 auto; font-size: 14px; font-weight: 600; color: var(--slate); white-space: nowrap; }
.pj-links {
  display: flex; align-items: center; gap: clamp(16px, 2.2vw, 30px); min-width: 0;
  overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
}
.pj-links::-webkit-scrollbar { display: none; }
.pj-links a { flex: 0 0 auto; padding: 15px 0; font-size: 15px; font-weight: 550; color: var(--slate); white-space: nowrap; }
.pj-links a:hover { color: var(--ink); }
.pj-links a[aria-current="true"] { color: var(--ink); font-weight: 700; }
.jump-target { height: 0; }
/* An anchor has to clear the site header AND this row. */
html:has(.page-jump) { scroll-padding-top: calc(var(--header-h) + 52px + 18px); }
@media (max-width: 640px) {
  .pj-label { display: none; }
}

/* ============================================================
   The integrations page, redrawn (2026-09-27)
   Andre: "very dense and difficult to consume, let's make this much
   prettier". Three new section types and four optional extensions, all
   drawn from surfaces the site already owns: hairlines, round wells for
   marks, the house dot for a state, and the permanently dark stage the
   value-math band uses. No tinted panel, no bar down an edge, no grid of
   icon cards.
   ============================================================ */

/* The converging header can end in the Echo mark instead of a dot. */
.hero-conv-hub {
  position: absolute; left: 50%; bottom: 0; transform: translate(-50%, 50%);
  width: clamp(44px, 5vw, 60px); height: clamp(44px, 5vw, 60px);
  display: grid; place-items: center;
}
.hero-conv-hub::before {
  content: ""; position: absolute; inset: -8px; border-radius: 50%;
  background: rgba(93, 174, 227, .16);
}
.hero-conv-hub img { position: relative; width: auto; height: 82%; display: block; filter: drop-shadow(0 8px 18px rgba(32, 48, 88, .22)); }
.hero-conv-sky:has(.hero-conv-hub) + .hero-conv-copy { margin-top: clamp(44px, 5vw, 68px); }

/* ---- The orbit header -------------------------------------------------
   heroconverge with settings.layout 'orbit' (tools/marketing-blocks.mjs,
   orbitHero). Permanently dark in both themes, like the photographic
   headers, so every colour here is a literal rather than a ramp token.
   tools/contrast.mjs cannot read a gradient ground, so it was measured by
   pixel (hero-contrast.mjs's method) at 390, 1280 and 1920: worst
   breadcrumb 6.2:1, eyebrow 8.4:1, lead 11:1, headline 14.8:1.
   Two traps kept out on purpose. Nothing positioned with a transform is
   ever animated with one: the marks and the core are placed with margins or
   the translate property, and the spin, the counter-spin, the ripple and
   the light each animate a property nothing else sets. And no disc sits
   behind the Echo mark: Andre took it off. */
.hero-orbit {
  background:
    radial-gradient(760px 620px at 76% 52%, rgba(61, 180, 232, .16), transparent 62%),
    radial-gradient(900px 520px at 8% 0%, rgba(36, 70, 127, .55), transparent 70%),
    #0A1224;
  color: #F2F6FC;
  padding: clamp(26px, 3.4vw, 44px) 0 clamp(56px, 7vw, 104px);
  overflow: clip;
}
.hero-orbit .breadcrumbs, .hero-orbit .breadcrumbs a { color: #9FB0CC; }
.hero-orbit .breadcrumbs a:hover { color: #fff; }
.hero-orbit-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);
  gap: clamp(24px, 4vw, 64px); align-items: center;
}
.hero-orbit-copy .eyebrow { color: #7FD0F5; }
.hero-orbit-copy h1 { margin-top: 14px; color: #fff; }
.hero-orbit-copy .lead { color: #C9D6EA; max-width: 560px; }
.hero-orbit-copy .lead b { color: #fff; }
.hero-orbit-copy .lead a, .hero-orbit-note a { color: #7FD0F5; }
.hero-orbit-aside { font-size: 14.5px; color: #C9D6EA; }
.hero-orbit-aside a { color: #7FD0F5; }
.hero-orbit-note { margin: 16px 0 0; font-size: 14.5px; line-height: 1.55; color: #9FB0CC; max-width: 520px; }
.hero-orbit-stage { position: relative; width: min(100%, 600px); aspect-ratio: 1; margin-left: auto; }
.hero-orbit-circle { position: absolute; left: 50%; top: 50%; translate: -50% -50%; border-radius: 50%; }
.hero-orbit-circle.o1 { width: 52%; height: 52%; border: 1px solid rgba(159, 176, 204, .20); }
.hero-orbit-circle.o2 { width: 84%; height: 84%; border: 1px dashed rgba(159, 176, 204, .18); }
.hero-orbit-circle.o3 { width: 100%; height: 100%; border: 1px solid rgba(159, 176, 204, .07); }
.hero-orbit-spin { position: absolute; inset: 0; }
.hero-orbit-spin.s-in { animation: orbitSpin 110s linear infinite; }
.hero-orbit-spin.s-out { animation: orbitSpin 170s linear infinite reverse; }
@keyframes orbitSpin { to { rotate: 360deg; } }
.hero-orbit-mark { position: absolute; translate: -50% -50%; z-index: 2; }
/* White chips on purpose: a provider mark is never filtered or recoloured,
   and several are dark (TikTok's reversed mark is a black disc). */
.hero-orbit-chip {
  display: grid; place-items: center; border-radius: 50%; background: #fff; color: #203058;
  width: clamp(44px, 5.2vw, 64px); height: clamp(44px, 5.2vw, 64px);
  box-shadow: 0 14px 34px rgba(0, 0, 0, .38), 0 0 0 1px rgba(255, 255, 255, .06);
  transition: box-shadow .5s ease;
  animation: orbitSpin 170s linear infinite;
}
.s-in .hero-orbit-chip {
  width: clamp(38px, 4.4vw, 54px); height: clamp(38px, 4.4vw, 54px);
  animation: orbitSpin 110s linear infinite reverse;
}
.hero-orbit-chip img, .hero-orbit-chip svg { width: 58%; height: 58%; object-fit: contain; display: block; }
.hero-orbit-chip .is-letter { font-weight: 750; font-size: 15px; letter-spacing: -0.01em; }
.hero-orbit-chip.is-lit {
  box-shadow: 0 14px 34px rgba(0, 0, 0, .38), 0 0 0 6px rgba(127, 208, 245, .22), 0 0 36px rgba(127, 208, 245, .55);
}
/* The light a conversation travels as: the same for every app. site.js
   makes it and flies it; it is centred with margins because its flight
   animates translate and scale. */
.hero-orbit-light {
  position: absolute; z-index: 4; pointer-events: none; border-radius: 50%;
  background: radial-gradient(circle at 38% 36%, #FFFFFF 0 18%, #CFF1FF 34%, #62C6F2 62%, rgba(61, 180, 232, 0) 100%);
  box-shadow: 0 0 14px 4px rgba(127, 208, 245, .75), 0 0 36px 10px rgba(61, 180, 232, .35);
}
.hero-orbit-light.is-trail { box-shadow: 0 0 12px 3px rgba(127, 208, 245, .5); }
/* The Echo mark itself, its bubble's centre (52, 52 of 105 x 120) on the
   orbit's centre. */
.hero-orbit-core {
  position: absolute; left: 50%; top: 50%; z-index: 3;
  width: 26%; aspect-ratio: 105 / 120; margin: -12.88% 0 0 -12.88%;
}
.hero-orbit-core::before {
  content: ""; position: absolute; left: 49.5%; top: 43.3%; width: 230%; aspect-ratio: 1;
  translate: -50% -50%; border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(61, 180, 232, .30), rgba(61, 180, 232, .10) 55%, transparent);
  animation: orbitBreathe 5s ease-in-out infinite;
}
@keyframes orbitBreathe { 0%, 100% { opacity: .75; } 50% { opacity: 1; } }
.hero-orbit-logo, .hero-orbit-ripple { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.hero-orbit-logo { filter: drop-shadow(0 16px 30px rgba(0, 0, 0, .45)); }
.hero-orbit-logo .wv { transform-box: fill-box; transform-origin: 50% 50%; }
.hero-orbit-logo.is-speaking .wv { animation: orbitSpeak .95s cubic-bezier(.4, 0, .3, 1); }
.hero-orbit-logo.is-speaking .b1 { animation-delay: 50ms; }
.hero-orbit-logo.is-speaking .c { animation-delay: 100ms; }
.hero-orbit-logo.is-speaking .b2 { animation-delay: 150ms; }
.hero-orbit-logo.is-speaking .d2 { animation-delay: 200ms; }
.hero-orbit-logo .d1, .hero-orbit-logo .d2 { --h1: 2.9; --h2: 1.5; --h3: 2.2; }
.hero-orbit-logo .b1, .hero-orbit-logo .b2 { --h1: 1.7; --h2: .75; --h3: 1.35; }
.hero-orbit-logo .c { --h1: 1.34; --h2: .78; --h3: 1.16; }
@keyframes orbitSpeak {
  0% { transform: scaleY(1); } 22% { transform: scaleY(var(--h1)); } 48% { transform: scaleY(var(--h2)); }
  72% { transform: scaleY(var(--h3)); } 100% { transform: scaleY(1); }
}
/* An arrival ripples out in the mark's own shape, blurred rather than drawn
   (Andre: "blurred and not a hard line"). */
.hero-orbit-ripple { opacity: 0; transform-origin: 49.5% 43.3%; filter: blur(7px); }
.hero-orbit-ripple path { fill: none; stroke: #7FD0F5; stroke-width: 7px; vector-effect: non-scaling-stroke; }
.hero-orbit-ripple.is-going { animation: orbitRipple 1.5s cubic-bezier(.2, .7, .3, 1); }
.hero-orbit-ripple.r-b.is-going { animation-delay: .22s; }
@keyframes orbitRipple { 0% { opacity: .9; scale: .96; } 100% { opacity: 0; scale: 1.85; } }
@media (max-width: 900px) {
  .hero-orbit-grid { grid-template-columns: 1fr; gap: 8px; }
  .hero-orbit-stage { order: -1; width: min(88vw, 420px); margin: 0 auto; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-orbit-spin, .hero-orbit-chip, .hero-orbit-core::before { animation: none !important; }
}

/* ---- Channel families ------------------------------------------------- */
.chf {
  list-style: none; margin: clamp(32px, 4vw, 56px) 0 0; padding: 0 clamp(20px, 3vw, 40px);
  background: var(--white); border: 1px solid var(--cloud); border-radius: 24px;
}
.chf-row {
  display: grid; grid-template-columns: 200px 240px minmax(0, 1fr); gap: 14px 32px;
  align-items: center; padding: 26px 0; border-top: 1px solid var(--cloud);
}
.chf-row:first-child { border-top: 0; }
.chf-marks { display: flex; flex-wrap: wrap; gap: 10px; }
.chf-mark {
  width: 44px; height: 44px; flex: 0 0 auto; border-radius: 50%;
  border: 1px solid var(--cloud); background: var(--white);
  display: grid; place-items: center;
}
.chf-mark img { width: 26px; height: 26px; object-fit: contain; display: block; }
.chf-mark.is-glyph { color: var(--slate); }
.chf-name { margin: 0; font-size: 21px; line-height: 1.25; font-weight: 650; letter-spacing: -0.015em; color: var(--ink); }
.chf-body { margin: 0; font-size: 16.5px; line-height: 1.6; color: var(--slate); max-width: 560px; }
.chf-foot { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px 64px; margin-top: 24px; }
.chf-also { margin: 0; font-size: 15.5px; line-height: 1.6; color: var(--slate); }
.chf-also b { color: var(--ink); }
.chf-legal { margin: 0; font-size: 13px; line-height: 1.6; color: var(--slate); }
@media (max-width: 1100px) {
  .chf-row { grid-template-columns: 170px minmax(0, 1fr); }
  .chf-marks { grid-row: span 2; align-self: start; padding-top: 2px; }
}
@media (max-width: 720px) {
  .chf-row { grid-template-columns: 1fr; gap: 12px; padding: 24px 0; }
  .chf-marks { grid-row: auto; }
  .chf-foot { grid-template-columns: 1fr; }
}

/* ---- Drawn scenes: small conversation mockups, composed ----------------
   One design unit is 1em = a tenth of the canvas's 56em width, so the whole
   picture scales with its column like an image and nothing inside it needs
   its own breakpoint. Surfaces come from the ramp and flip with the theme;
   the phone bezel, the video frames and the call screen are devices, so they
   stay dark in both themes like .rw. Provider marks sit in a white well in
   both themes, as everywhere else. Layouts are named by card shape: t is a
   phone, w a window. */
.scn {
  position: relative; margin: 0; width: 100%; container-type: inline-size; overflow: clip;
  border-radius: 28px;
  background: radial-gradient(72% 62% at 50% 42%, var(--ice), transparent 74%), var(--mist);
}
.scn-canvas { position: relative; width: 56em; height: 47em; font-size: calc(100cqw / 56); }
.scn-card { position: absolute; rotate: var(--r, 0deg); }
.scn-phone {
  width: 20em; height: 40em; padding: .55em; border-radius: 3.2em;
  background: #16213A; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .1), 0 2.2em 4.6em -1.6em rgba(10, 18, 36, .5);
}
.scn-screen {
  position: relative; height: 100%; border-radius: 2.65em; overflow: hidden;
  background: var(--white); display: flex; flex-direction: column;
}
.scn-screen::before {
  content: ""; position: absolute; z-index: 2; top: .9em; left: 50%; translate: -50% 0;
  width: 5.6em; height: 1.5em; border-radius: 1em; background: #16213A;
}
.scn-window {
  width: 32em; border-radius: 1.8em; overflow: hidden;
  background: var(--white); border: 1px solid var(--cloud);
  box-shadow: var(--shadow-float), 0 2.4em 5em -2em rgba(10, 18, 36, .32);
}
.scn-mark {
  flex: 0 0 auto; width: 2.8em; height: 2.8em; border-radius: 50%;
  background: #fff; border: 1px solid var(--cloud); display: grid; place-items: center;
}
.scn-mark img { width: 1.7em; height: 1.7em; object-fit: contain; display: block; }
.scn-mark.is-glyph { background: var(--panel); color: var(--slate); }
.scn-mark.is-glyph svg { width: 1.6em; height: 1.6em; }
.scn-bar { display: flex; align-items: center; gap: .8em; padding: 2.9em 1.2em 1em; border-bottom: 1px solid var(--cloud); }
.scn-who { display: flex; flex-direction: column; min-width: 0; }
.scn-who b { font-size: 1.3em; line-height: 1.25; font-weight: 650; color: var(--ink); }
.scn-who i { font-style: normal; font-size: 1.05em; line-height: 1.35; color: var(--slate); }
.scn-thread {
  flex: 1; display: flex; flex-direction: column; justify-content: flex-end; gap: .7em;
  padding: 1.3em 1.1em; background: var(--mist);
}
.scn-msg { margin: 0; max-width: 84%; padding: .7em .95em; border-radius: 1.2em; font-size: 1.2em; line-height: 1.4; }
.scn-msg.is-seeker { align-self: flex-end; background: var(--grad-action); color: var(--on-action); border-bottom-right-radius: .35em; }
.scn-msg.is-ministry { align-self: flex-start; background: var(--white); color: var(--ink); border: 1px solid var(--cloud); border-bottom-left-radius: .35em; }
.scn-compose { flex: 0 0 auto; height: 3em; margin: 1em 1em 1.6em; border-radius: 2em; border: 1px solid var(--cloud); }
.scn-av {
  flex: 0 0 auto; width: 2.1em; height: 2.1em; border-radius: 50%;
  display: grid; place-items: center; font-weight: 700; font-style: normal;
  background: var(--ice); color: var(--action-ink);
}
/* Posts: a window with the video and its comments, or a phone with a
   vertical video and the comment sheet pulled up over it. */
.scn-post .scn-bar { padding: 1.2em 1.4em; border-bottom: 0; }
.scn-media {
  position: relative; display: grid; place-items: center;
  background: linear-gradient(140deg, #3A5F9E 0%, #16305C 48%, #0A1224 100%);
}
.scn-window .scn-media { height: 11em; margin: 0 1.4em; border-radius: 1.2em; }
.scn-play { width: 3.6em; height: 3.6em; border-radius: 50%; background: rgba(255, 255, 255, .92); display: grid; place-items: center; }
.scn-play::after { content: ""; margin-left: .3em; border-left: 1.2em solid #16305C; border-top: .75em solid transparent; border-bottom: .75em solid transparent; }
.scn-caption { margin: .9em 1.12em 0; font-size: 1.25em; line-height: 1.35; font-weight: 650; color: var(--ink); }
.scn-comments {
  list-style: none; margin: 1em 0 0; padding: 1.1em 1.4em 1.4em; border-top: 1px solid var(--cloud);
  display: flex; flex-direction: column; gap: .8em;
}
.scn-comments li { display: flex; gap: .7em; align-items: flex-start; font-size: 1.15em; line-height: 1.4; color: var(--slate); }
.scn-comments li b { color: var(--ink); font-weight: 650; }
.scn-comments li.is-ministry { padding-left: 2.4em; }
.scn-comments li.is-ministry .scn-av { background: var(--grad-action); color: var(--on-action); }
.scn-post.is-tall .scn-screen { background: #0A1224; }
.scn-post.is-tall .scn-media { flex: 1; }
.scn-post.is-tall .scn-caption {
  position: absolute; left: 1.1em; right: 3em; bottom: 2.6em; margin: 0; color: #fff; font-size: 1.3em;
}
.scn-sheet { position: relative; margin-top: -1.6em; border-radius: 1.6em 1.6em 0 0; background: var(--white); padding-bottom: .8em; }
.scn-sheet-head { display: flex; align-items: center; gap: .7em; padding: 1.1em 1.2em .2em; }
.scn-sheet-head b { font-size: 1.2em; color: var(--ink); font-weight: 650; }
.scn-sheet .scn-comments { margin: 0; padding: .8em 1.2em .8em; border-top: 0; }
/* Email: one message and the reply that went back from the same address.
   A line that sets its own font-size divides the card's 1.6em edge by it,
   so every text edge in a card lines up. */
.scn-mail { width: 44em; }
.scn-mail .scn-bar { padding: 1.4em 1.6em; }
.scn-subject { margin: .15em 1.03em 0; font-size: 1.55em; line-height: 1.3; font-weight: 700; letter-spacing: -0.01em; color: var(--ink); }
.scn-text { margin: .5em 1.28em 0; font-size: 1.25em; line-height: 1.55; color: var(--slate); }
.scn-reply { margin: 1.4em 1.6em 1.6em; padding: 1.2em 1.4em; border-radius: 1.2em; background: var(--mist); }
.scn-reply i { display: block; font-style: normal; font-size: 1.05em; color: var(--slate); }
.scn-reply p { margin: .35em 0 0; font-size: 1.25em; line-height: 1.5; color: var(--ink); }
/* A call ringing: the responder's side, on a permanently dark screen. */
.scn-call .scn-screen { background: linear-gradient(180deg, #1B3868 0%, #0A1224 100%); align-items: center; text-align: center; }
.scn-call-top { display: flex; align-items: center; gap: .7em; padding: 3.2em 1.4em 0; color: #C9D6EA; }
.scn-call-top i { font-style: normal; font-size: 1.1em; }
.scn-call .scn-mark.is-glyph { background: rgba(255, 255, 255, .12); border-color: transparent; color: #fff; }
.scn-call-av { margin: 1.5em auto .5em; width: 2.5em; height: 2.5em; border-radius: 50%; display: grid; place-items: center; font-size: 2.8em; font-weight: 700; color: #fff; background: rgba(255, 255, 255, .14); }
.scn-call-av svg { width: 1.1em; height: 1.1em; }
.scn-call-name { display: block; font-size: 1.7em; font-weight: 700; color: #fff; }
.scn-call-sub { display: block; margin-top: .4em; padding: 0 1em; font-size: 1.15em; color: #A9B6CC; }
.scn-call-actions { margin-top: auto; width: 100%; display: flex; justify-content: space-around; padding: 0 1em 3.2em; }
.scn-call-actions span { display: flex; flex-direction: column; align-items: center; gap: .55em; font-size: 1.1em; color: #C9D6EA; }
.scn-call-actions i { width: 4.6em; height: 4.6em; border-radius: 50%; display: grid; place-items: center; color: #fff; }
.scn-call-actions svg { width: 2em; height: 2em; }
.scn-call-actions .is-decline i { background: #D93A55; }
.scn-call-actions .is-decline svg { rotate: 135deg; }
.scn-call-actions .is-answer i { background: #1E9E6F; }
/* Web chat: a page of the ministry's own site with the widget open on it. */
.scn-site { width: 46em; height: 36em; }
.scn-site-bar { display: flex; align-items: center; gap: .5em; padding: 1em 1.2em; border-bottom: 1px solid var(--cloud); background: var(--panel); }
.scn-site-bar i { width: .9em; height: .9em; border-radius: 50%; background: var(--cloud); }
.scn-site-bar span {
  flex: 1; margin-left: 1em; padding: .35em 1em; border-radius: 2em;
  font-size: 1.1em; color: var(--slate); background: var(--white); border: 1px solid var(--cloud);
}
.scn-site-page { width: 56%; padding: 2.6em 2.4em; display: flex; flex-direction: column; gap: 1em; }
.scn-site-page span { height: 1em; border-radius: .5em; background: var(--cloud); }
.scn-site-page .is-h { height: 2.2em; width: 82%; }
.scn-site-page .is-short { width: 58%; }
.scn-site-page .is-block { height: 9em; margin-top: .8em; border-radius: 1em; background: var(--mist); }
.scn-widget {
  position: absolute; right: 1.8em; bottom: 1.8em; width: 22em; overflow: hidden;
  border-radius: 1.6em; background: var(--white); border: 1px solid var(--cloud); box-shadow: var(--shadow-float);
}
.scn-widget .scn-bar { padding: 1.1em 1.2em; }
.scn-widget .scn-thread { padding: 1.2em 1.1em 1.4em; }
/* A panel: a titled list of people or accounts. */
.scn-panel-head { display: flex; align-items: center; gap: .9em; padding: 1.4em 1.6em; border-bottom: 1px solid var(--cloud); }
.scn-panel-head b { font-size: 1.35em; font-weight: 700; color: var(--ink); }
.scn-marks { display: flex; }
.scn-marks .scn-mark + .scn-mark { margin-left: -.7em; }
.scn-rows { list-style: none; margin: 0; padding: .4em 1.6em; }
.scn-rows li { display: flex; align-items: center; gap: 1em; padding: .9em 0; border-top: 1px solid var(--cloud); }
.scn-rows li:first-child { border-top: 0; }
.scn-rows .scn-av { font-size: 1.2em; }
.scn-panel-foot { display: flex; align-items: center; gap: .6em; margin: 0 1.39em 1.3em; font-size: 1.15em; line-height: 1.4; color: var(--slate); }
.scn-panel-foot::before { content: ""; flex: 0 0 auto; width: .6em; height: .6em; border-radius: 50%; background: var(--success); }
/* The compositions. */
.scn-t .scn-card:nth-child(1) { left: 18em; top: 3.5em; }
.scn-tt .scn-card:nth-child(1) { left: 8em; top: 3.5em; --r: -5deg; }
.scn-tt .scn-card:nth-child(2) { left: 28em; top: 3.5em; --r: 5deg; z-index: 2; }
/* Three phones side by side, a little smaller, the first raised in the
   middle and the other two tipped out to either side of it. */
.scn-ttt .scn-phone { width: 17.2em; height: 36em; }
.scn-ttt .scn-card:nth-child(1) { left: 19.4em; top: 3.4em; z-index: 2; }
.scn-ttt .scn-card:nth-child(2) { left: 1.3em; top: 7.2em; --r: -4deg; }
.scn-ttt .scn-card:nth-child(3) { left: 37.5em; top: 7.2em; --r: 4deg; }
.scn-tw .scn-card:nth-child(1) { left: 3em; top: 3.5em; --r: -4deg; z-index: 2; }
.scn-tw .scn-card:nth-child(2) { left: 22.2em; top: 8.5em; width: 32.4em; }
.scn-w .scn-card:nth-child(1) { inset: 0; margin: auto; height: fit-content; }
.scn-w .scn-card.scn-site { height: 36em; }
.scn-ww .scn-card:nth-child(1) { left: 2.5em; top: 3em; --r: -2.5deg; }
.scn-ww .scn-card:nth-child(2) { left: 21.5em; top: 19.5em; --r: 2deg; z-index: 2; }
/* On a phone the canvas is shown larger and cropped at the sides, so the
   words in the front card stay near a readable size; the fanned cards
   behind it bleed off the edge. */
@media (max-width: 640px) {
  .scn-canvas { font-size: calc(100cqw / 46); margin-left: -5em; }
}

/* ---- Channel families as a tour: each family's scene beside its words ----
   The static form is picture-and-words pairs. site.js's [data-chf-tour]
   driver adds .is-live on a wide screen with motion allowed: the words
   scroll, every scene sits in one pinned cell beside them, and the one for
   the family in view flips forward while the last flips away. */
.chf-tour { list-style: none; margin: clamp(40px, 5vw, 72px) 0 0; padding: 0; display: flex; flex-direction: column; gap: clamp(64px, 8vw, 112px); }
.chf-step { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); gap: 32px clamp(40px, 6vw, 96px); align-items: center; }
.chf-step .chf-copy { grid-column: 1; grid-row: 1; }
.chf-step .chf-scene { grid-column: 2; grid-row: 1; }
.chf-copy .chf-marks { margin-bottom: 20px; }
.chf-copy .chf-name { font-size: clamp(24px, 2.4vw, 30px); }
.chf-copy .chf-body { margin-top: 12px; font-size: 17.5px; max-width: 460px; }
.chf-tour + .chf-foot { margin-top: clamp(48px, 6vw, 80px); }
@media (max-width: 860px) {
  .chf-step { grid-template-columns: minmax(0, 1fr); }
  .chf-step .chf-scene { grid-column: 1; grid-row: 1; }
  .chf-step .chf-copy { grid-row: 2; }
}
.chf-tour.is-live {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
  grid-template-rows: repeat(var(--n), auto); column-gap: clamp(40px, 6vw, 96px); row-gap: 0;
}
.chf-tour.is-live .chf-step { display: contents; }
.chf-tour.is-live .chf-copy {
  grid-column: 1; grid-row: var(--i); min-height: 72vh; padding: 6vh 0;
  display: flex; flex-direction: column; justify-content: center;
}
.chf-tour.is-live .chf-scene {
  grid-column: 2; grid-row: 1 / -1; align-self: start; justify-self: end;
  position: sticky; top: var(--scn-top, calc(var(--header-h) + 40px));
  width: min(100%, calc((100vh - var(--header-h) - 96px) * 56 / 47));
  opacity: 0; pointer-events: none;
  transform: perspective(1600px) translateY(7%) rotateX(-18deg) scale(.94);
  transition: opacity .5s ease, transform .8s cubic-bezier(.2, .7, .2, 1);
}
.chf-tour.is-live .chf-scene.is-past { transform: perspective(1600px) translateY(-7%) rotateX(18deg) scale(.94); }
.chf-tour.is-live .chf-scene.is-active { opacity: 1; pointer-events: auto; transform: none; }
.chf-tour.is-live .chf-scene.is-active .scn-card { animation: scnDeal .8s cubic-bezier(.2, .7, .2, 1) both; animation-delay: calc(var(--k) * 110ms + 140ms); }
@keyframes scnDeal { from { opacity: 0; translate: 0 3.2em; } to { opacity: 1; translate: 0 0; } }

/* ---- Reply windows: bars on one scale, on the dark stage --------------- */
.rw {
  background:
    radial-gradient(1000px 500px at 84% 0%, rgba(36, 70, 127, .5), transparent 70%),
    #0A1224;
  color: #F2F6FC;
  padding: clamp(72px, 9vw, 128px) 0;
}
.rw .eyebrow { color: #7FD0F5; }
.rw h2 { margin-top: 14px; color: #fff; }
.rw-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 28px 64px; align-items: end; }
.rw-lead { margin: 18px 0 0; max-width: 620px; font-size: clamp(16px, 1.5vw, 19px); line-height: 1.6; color: #C9D6EA; }
.rw-sample {
  display: flex; align-items: center; gap: 12px; padding: 14px 18px 14px 14px;
  border-radius: 18px; border: 1px solid rgba(255, 255, 255, .16);
}
.rw-sample-main b { display: block; font-size: 15px; font-weight: 650; color: #fff; }
.rw-sample-main span { display: block; margin-top: 2px; font-size: 13px; color: #A9B6CC; }
.rw-sample-state { display: inline-flex; align-items: center; gap: 7px; margin-left: 10px; font-size: 13.5px; font-weight: 650; color: #F6B26B; white-space: nowrap; }
.rw-sample-state::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: #F6B26B; }
.rw-rows { list-style: none; margin: clamp(40px, 5vw, 72px) 0 0; padding: 0; }
.rw-row {
  display: grid; grid-template-columns: minmax(0, 340px) minmax(0, 1fr) 150px; gap: 14px 40px;
  align-items: center; padding: 26px 0; border-top: 1px solid rgba(255, 255, 255, .12);
}
.rw-row:last-child { border-bottom: 1px solid rgba(255, 255, 255, .12); }
.rw-scale { padding: 0 0 12px; border-top: 0; }
.rw-scale-track { position: relative; height: 18px; font-size: 12.5px; font-weight: 600; color: #8B9BBD; }
.rw-scale-track span { position: absolute; top: 0; white-space: nowrap; }
.rw-scale-track .is-mid { transform: translateX(-50%); }
.rw-scale-track .is-end { right: 0; }
.rw-label { display: flex; align-items: center; gap: 14px; min-width: 0; }
.rw-marks { display: flex; flex-wrap: wrap; gap: 5px; flex: 0 0 auto; max-width: 146px; }
.rw-mark { width: 30px; height: 30px; border-radius: 50%; background: #fff; display: grid; place-items: center; flex: 0 0 auto; }
.rw-mark img { width: 18px; height: 18px; object-fit: contain; display: block; }
.rw-mark.is-glyph { background: #1B2C55; color: #C9D6EA; }
.rw-mark.is-glyph svg { width: 16px; height: 16px; }
.rw-title { display: block; font-size: 17px; font-weight: 650; line-height: 1.3; color: #fff; }
.rw-note { display: block; margin-top: 3px; font-size: 14px; line-height: 1.45; color: #A9B6CC; }
.rw-track { position: relative; height: 14px; border-radius: 7px; background: rgba(255, 255, 255, .07); }
.rw-track i { position: absolute; top: -26px; bottom: -26px; width: 1px; background: rgba(255, 255, 255, .1); }
.rw-bar { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 7px; }
.rw-bar.is-hot { background: #F08A3E; }
.rw-bar.is-warm { background: #F4C06A; }
.rw-bar.is-open { box-sizing: border-box; border: 2px dashed #5DAEE3; }
.rw-bar.is-endless { right: 12px; width: auto !important; background: linear-gradient(90deg, #3DB4E8 0%, #0070F8 100%); }
.rw-bar.is-endless::after {
  content: ""; position: absolute; right: -9px; top: 50%; width: 10px; height: 10px;
  border-top: 3px solid #2F8EF2; border-right: 3px solid #2F8EF2; transform: translateY(-50%) rotate(45deg);
}
.rw-value { text-align: right; font-size: clamp(17px, 1.6vw, 20px); font-weight: 700; color: #fff; white-space: nowrap; }
@media (max-width: 860px) {
  .rw-head { grid-template-columns: 1fr; }
  .rw-sample { justify-self: start; }
  .rw-row { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "label value" "track track"; gap: 14px 16px; padding: 22px 0; }
  .rw-label { grid-area: label; }
  .rw-track { grid-area: track; }
  .rw-value { grid-area: value; }
  .rw-scale { grid-template-areas: "track track"; padding-bottom: 6px; }
  .rw-scale > span { display: none; }
  .rw-scale-track { grid-area: track; }
  .rw-track i { top: -4px; bottom: -4px; }
}
@media (max-width: 520px) {
  .rw-label { flex-direction: column; align-items: flex-start; gap: 10px; }
  .rw-scale-track { font-size: 11.5px; }
}
/* How the clock behaves, under the bars: three headed points on the same
   dark stage. A hairline over each, never a bar down its side. */
.rw-points {
  list-style: none; margin: clamp(44px, 5.5vw, 72px) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px clamp(28px, 4vw, 56px);
}
.rw-points li { padding-top: 22px; border-top: 1px solid rgba(255, 255, 255, .14); }
.rw-points h3 { margin: 0; font-size: 19px; line-height: 1.3; font-weight: 650; letter-spacing: -0.012em; color: #fff; }
.rw-points p { margin: 8px 0 0; font-size: 15.5px; line-height: 1.6; color: #C9D6EA; }
.rw-points p b { color: #fff; }
@media (max-width: 860px) {
  .rw-points { grid-template-columns: 1fr; }
}

/* ---- Photograph beside copy: the parts the phone section added -------- */
.fsb-copy .eyebrow + h2 { margin-top: 14px; }
.fsb-chip {
  position: absolute; left: clamp(16px, 3vw, 40px); top: clamp(16px, 3vw, 44px); z-index: 1;
  display: flex; align-items: center; gap: 12px; max-width: calc(100% - 32px);
  padding: 12px 18px 12px 12px; border-radius: 16px; background: var(--white);
  box-shadow: 0 2px 4px rgba(10, 18, 32, .08), 0 20px 44px rgba(10, 18, 32, .28);
}
.fsb-chip-icon { width: 38px; height: 38px; flex: 0 0 auto; border-radius: 50%; background: var(--mist); color: var(--ink); display: grid; place-items: center; }
.fsb-chip-main b { display: block; font-size: 14.5px; font-weight: 650; color: var(--ink); }
.fsb-chip-main span { display: block; margin-top: 1px; font-size: 13px; color: var(--slate); }
.fsb-chip-state { display: inline-flex; align-items: center; gap: 6px; margin-left: 6px; font-size: 12.5px; font-weight: 650; color: var(--action-ink); white-space: nowrap; }
.fsb-chip-state::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--echo-cyan); }
.fsb-points { list-style: none; margin: clamp(26px, 3vw, 34px) 0 0; padding: 0; display: flex; flex-direction: column; gap: 22px; max-width: 560px; }
.fsb-points li { display: grid; grid-template-columns: 40px minmax(0, 1fr); gap: 16px; align-items: start; }
.fsb-point-icon { width: 40px; height: 40px; border-radius: 50%; background: var(--mist); color: var(--action-ink); display: grid; place-items: center; }
.fsb-points h3 { margin: 2px 0 0; font-size: 18px; line-height: 1.35; font-weight: 650; letter-spacing: -0.01em; color: var(--ink); }
.fsb-points p { margin: 5px 0 0; font-size: 16px; line-height: 1.6; color: var(--slate); }
.fsb-stats { display: flex; flex-wrap: wrap; gap: 14px 48px; margin-top: clamp(28px, 3.4vw, 40px); padding-top: 24px; border-top: 1px solid var(--cloud); max-width: 560px; }
.fsb-stats b { display: block; font-size: clamp(30px, 3.2vw, 40px); font-weight: 750; letter-spacing: -0.03em; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.fsb-stats span { display: block; margin-top: 8px; font-size: 15px; color: var(--slate); }
.fsb-stats-note { margin: 12px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--slate); max-width: 560px; }

/* ---- Two facts and a figure ------------------------------------------- */
.tf { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 340px); gap: 40px clamp(40px, 6vw, 88px); align-items: center; }
.tf.no-figure { grid-template-columns: minmax(0, 1fr); }
.tf-main h2 { font-size: clamp(28px, 3.2vw, 40px); }
.tf-main .eyebrow + h2 { margin-top: 14px; }
.tf-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); gap: 28px 48px; margin-top: clamp(26px, 3.2vw, 40px); }
.tf-label { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 14px; font-weight: 650; color: var(--slate); }
.tf-label.is-good { color: var(--good-ink); }
.tf-label.is-warn { color: var(--warning-ink); }
.tf-label.is-good::before, .tf-label.is-warn::before { content: ""; width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; }
.tf-label.is-good::before { background: var(--success); }
.tf-label.is-warn::before { background: var(--warning); }
.tf-title { margin: 12px 0 0; font-size: clamp(20px, 2vw, 24px); line-height: 1.25; font-weight: 650; letter-spacing: -0.015em; color: var(--ink); }
.tf-body { margin: 8px 0 0; font-size: 16px; line-height: 1.6; color: var(--slate); }
.tf-link { margin: clamp(24px, 3vw, 32px) 0 0; }
.tf-figure { padding-left: clamp(32px, 4vw, 56px); border-left: 1px solid var(--cloud); }
.tf-num { display: block; font-size: clamp(88px, 10vw, 128px); font-weight: 750; letter-spacing: -0.05em; line-height: .9; color: var(--deep-blue); font-variant-numeric: tabular-nums; }
.tf-fig-label { margin: 14px 0 0; font-size: 21px; font-weight: 650; color: var(--ink); }
@media (max-width: 860px) {
  .tf { grid-template-columns: minmax(0, 1fr); }
  .tf-figure { padding: 32px 0 0; border-left: 0; border-top: 1px solid var(--cloud); }
}

/* ---- Steps, plain: a lead and titled steps ----------------------------- */
.stp-lead { max-width: 720px; }
.stp-title { margin: 18px 0 0; font-size: 20px; line-height: 1.3; font-weight: 650; letter-spacing: -0.012em; color: var(--ink); max-width: 320px; }
.stp.has-titles .stp-list p { margin-top: 8px; font-size: 16.5px; line-height: 1.6; max-width: 320px; }
@media (max-width: 760px) {
  .stp.has-titles .stp-list li > :not(.stp-num) { grid-column: 2; }
  .stp.has-titles .stp-num { grid-row: span 2; }
  .stp-title { margin-top: 4px; }
}

/* ---- An FAQ with its head beside the questions ------------------------- */
.faq-side { display: grid; grid-template-columns: minmax(0, 360px) minmax(0, 1fr); gap: 28px clamp(40px, 6vw, 96px); align-items: start; }
.faq-side .faq { margin: 0; }
@media (max-width: 860px) {
  .faq-side { grid-template-columns: minmax(0, 1fr); }
}

/* ---- The chapter: one idea a screen ------------------------------------
   Rendered by `chapter` in tools/marketing-blocks.mjs, played by site.js's
   [data-chapter] driver. Andre's pick for /product/inbox (2026-09-27, five
   rounds on a lab page, "How would Apple do this?"): a centred eyebrow, a
   very large heading with one phrase in the gradient, one sentence, one
   abstract symbol, and a paragraph or two of prose under it.

   Every colour is a token, so both themes come from the ramp: the chips,
   bubbles and card are --white (the card surface, not white), their words
   --ink, the coloured phrase runs --action-ink to --deep-blue (both lift in
   dark). The phrase is large text (40px and up), so it needs 3:1, and
   contrast.mjs cannot see text painted by a gradient, so it was measured by
   hand at every stop on both bands: worst 4.15:1 in light (#0070F8 on mist)
   and 7.06:1 in dark (#6BA8FF on the card surface). The responders'
   and the bars' colours are the scene's own and read on both grounds.

   A symbol lives in a fixed design space, 880 units wide on a desktop and
   440 on a phone, and every position is a unitless number times --u. --u is
   a length relative to .ch-stage, which is the size container, so the whole
   picture scales with its column and never overflows it. */
.hero-queue.is-bare { background: none; }

.chapter { padding: clamp(96px, 12vw, 176px) 0; text-align: center; --ch-ground: var(--white); }
.chapter.bg-mist { --ch-ground: var(--mist); }
.chapter .eyebrow { justify-content: center; }
.chapter h2 {
  margin: 14px auto 0; max-width: 13em; font-size: clamp(40px, 6.2vw, 88px);
  line-height: 1.02; letter-spacing: -.038em; font-weight: 750; text-wrap: balance;
}
.ch-grad {
  background: linear-gradient(120deg, var(--action-ink) 0%, var(--deep-blue) 90%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.chapter .lead { margin: 22px auto 0; max-width: 31em; font-size: clamp(18px, 1.6vw, 22px); color: var(--slate); }
.ch-more { margin: 16px 0 0; }
.ch-body {
  margin: clamp(12px, 1.5vw, 24px) auto 0; max-width: 960px; text-align: left;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 clamp(32px, 5vw, 64px);
}
.ch-body p { margin: 0; font-size: 17.5px; line-height: 1.6; color: var(--slate); }
.ch-body b { color: var(--ink); font-weight: 650; }
.ch-body.is-one { grid-template-columns: minmax(0, 1fr); max-width: 620px; text-align: center; }

.ch-stage { container-type: inline-size; max-width: 880px; margin: clamp(48px, 6vw, 88px) auto 0; }
.ch-sym { --u: calc(100cqw / 880); --ez: cubic-bezier(.2, .8, .2, 1); --spring: cubic-bezier(.34, 1.4, .5, 1);
  position: relative; width: 100%; aspect-ratio: 880 / 340; }
.ch-sym * { box-sizing: border-box; }
/* Moved without transitions, when the driver sets a symbol's starting pose. */
.ch-sym.is-set, .ch-sym.is-set * { transition: none !important; }

/* gather: the marks, bare and large, draw together under a soft light. */
.ch-gather .ch-mark {
  --x: var(--x0); --y: var(--y0); --r: var(--r0); --ms: 96;
  position: absolute; left: 50%; top: 50%; z-index: 1;
  width: calc(var(--ms) * var(--u)); height: calc(var(--ms) * var(--u));
  margin: calc(var(--ms) * var(--u) / -2) 0 0 calc(var(--ms) * var(--u) / -2);
  display: grid; place-items: center;
  translate: calc(var(--x) * var(--u)) calc(var(--y) * var(--u)); rotate: var(--r);
  transition: translate 1.25s var(--ez) var(--d), rotate 1.25s var(--ez) var(--d);
}
.ch-gather.is-one .ch-mark { --x: var(--x1); --y: 0; --r: 0deg; }
.ch-mark img { width: 100%; height: 100%; object-fit: contain; filter: drop-shadow(0 calc(14 * var(--u)) calc(22 * var(--u)) rgba(11, 18, 32, .18)); }
.ch-mark svg { width: 88%; height: 88%; color: var(--ink); }
.ch-glow {
  position: absolute; left: 50%; top: 50%; width: calc(760 * var(--u)); height: calc(200 * var(--u));
  margin: calc(-100 * var(--u)) 0 0 calc(-380 * var(--u)); border-radius: 50%;
  background: radial-gradient(closest-side, rgba(61, 180, 232, .34), rgba(0, 112, 248, .12) 60%, transparent);
  filter: blur(calc(22 * var(--u))); opacity: 0; scale: .6;
  transition: opacity 1s ease .5s, scale 1.3s var(--ez) .4s;
}
.ch-gather.is-one .ch-glow { opacity: 1; scale: 1; }

/* route: a message drops and lands on the group that answers it. */
.ch-home {
  position: absolute; left: 50%; top: 50%; width: calc(200 * var(--u)); margin-left: calc(-100 * var(--u));
  translate: calc(var(--x) * var(--u)) calc(70 * var(--u)); text-align: center; transition: scale .5s var(--spring);
}
.ch-avs { display: flex; justify-content: center; }
.ch-avs i { width: calc(50 * var(--u)); height: calc(50 * var(--u)); border-radius: 50%; background: var(--c); border: calc(3 * var(--u)) solid var(--ch-ground); }
.ch-avs i + i { margin-left: calc(-14 * var(--u)); }
.ch-home b { display: block; margin-top: calc(12 * var(--u)); font-size: calc(16 * var(--u)); font-weight: 600; color: var(--slate); }
.ch-home.is-got { scale: 1.1; }
.ch-bub {
  position: absolute; left: 50%; top: calc(20 * var(--u)); white-space: nowrap;
  padding: calc(16 * var(--u)) calc(24 * var(--u)); border-radius: calc(26 * var(--u)) calc(26 * var(--u)) calc(26 * var(--u)) calc(8 * var(--u));
  background: var(--white); color: var(--ink); font-size: calc(22 * var(--u)); font-weight: 600; letter-spacing: -.01em;
  box-shadow: 0 calc(24 * var(--u)) calc(48 * var(--u)) calc(-24 * var(--u)) rgba(11, 18, 32, .45), 0 0 0 1px rgba(11, 18, 32, .06);
  translate: -50% 0; opacity: 0; scale: .6;
  transition: translate 1s var(--ez), opacity .45s, scale .6s var(--spring);
}
.ch-bub[dir="rtl"] { border-radius: calc(26 * var(--u)) calc(26 * var(--u)) calc(8 * var(--u)) calc(26 * var(--u)); }
.ch-bub.is-up { opacity: 1; scale: 1; }
.ch-bub.is-in { opacity: 0; scale: .3; transition-duration: .5s; }

/* claim: two responders reach one conversation; the first claims it. */
.ch-card {
  position: absolute; left: 50%; top: 50%; width: calc(320 * var(--u)); height: calc(184 * var(--u));
  margin: calc(-92 * var(--u)) 0 0 calc(-160 * var(--u)); padding: calc(40 * var(--u)) calc(36 * var(--u));
  border-radius: calc(32 * var(--u)) calc(32 * var(--u)) calc(32 * var(--u)) calc(10 * var(--u)); background: var(--white);
  box-shadow: 0 calc(30 * var(--u)) calc(60 * var(--u)) calc(-30 * var(--u)) rgba(11, 18, 32, .45), 0 0 0 1px rgba(11, 18, 32, .06);
  transition: box-shadow .5s;
}
.ch-card i { display: block; height: calc(14 * var(--u)); border-radius: calc(7 * var(--u)); background: var(--cloud); }
.ch-card i:nth-of-type(1) { width: 80%; } .ch-card i:nth-of-type(2) { width: 62%; } .ch-card i:nth-of-type(3) { width: 40%; }
.ch-card i + i { margin-top: calc(16 * var(--u)); }
.ch-new { position: absolute; right: calc(22 * var(--u)); top: calc(22 * var(--u)); width: calc(16 * var(--u)); height: calc(16 * var(--u)); border-radius: 50%;
  background: #3DB4E8; box-shadow: 0 0 0 calc(6 * var(--u)) rgba(61, 180, 232, .2); transition: background .4s, box-shadow .4s; }
.ch-face {
  --x: -360; --y: 0; --s: 1;
  position: absolute; left: 50%; top: 50%; z-index: 2; width: calc(88 * var(--u)); height: calc(88 * var(--u));
  margin: calc(-44 * var(--u)) 0 0 calc(-44 * var(--u)); border-radius: 50%;
  box-shadow: 0 0 0 calc(4 * var(--u)) var(--c), 0 0 0 calc(8 * var(--u)) var(--ch-ground), 0 calc(18 * var(--u)) calc(34 * var(--u)) calc(-18 * var(--u)) rgba(11, 18, 32, .5);
  translate: calc(var(--x) * var(--u)) calc(var(--y) * var(--u)); scale: var(--s);
  transition: translate 1s var(--ez), scale .7s var(--ez), opacity .6s;
}
.ch-face img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
.ch-face.b { --x: 360; }
.ch-claim.is-near .ch-face.a { --x: -250; }
.ch-claim.is-near .ch-face.b { --x: 250; }
.ch-claim.is-mine .ch-face.a { --x: -160; --y: -92; --s: .74; }
.ch-claim.is-mine .ch-face.b { --x: 360; opacity: .3; }
.ch-claim.is-mine .ch-card { box-shadow: 0 calc(30 * var(--u)) calc(60 * var(--u)) calc(-30 * var(--u)) rgba(11, 18, 32, .45), 0 0 0 calc(4 * var(--u)) #2A6FB8; }
.ch-claim.is-mine .ch-new { background: #1FA971; box-shadow: 0 0 0 calc(6 * var(--u)) rgba(31, 169, 113, .18); }
.ch-ok {
  position: absolute; right: calc(-8 * var(--u)); bottom: calc(-8 * var(--u)); width: calc(38 * var(--u)); height: calc(38 * var(--u));
  border-radius: 50%; background: #1FA971; border: calc(4 * var(--u)) solid var(--ch-ground);
  display: grid; place-items: center; scale: 0; transition: scale .5s var(--spring) .2s;
}
.ch-ok svg { width: 50%; height: 50%; }
.ch-claim.is-mine .ch-ok { scale: 1; }

/* languages: one sentence in one language after another. The bubble turns
   for a right-to-left script, and the words enter from the side they are
   read from (Andre, 2026-09-26: right-to-left animates right to left). */
.ch-languages { aspect-ratio: 880 / 300; display: grid; place-content: center; justify-items: center; }
.ch-say {
  width: calc(800 * var(--u)); min-height: calc(150 * var(--u)); padding: calc(40 * var(--u)) calc(52 * var(--u)); overflow: hidden; text-align: start;
  border-radius: calc(44 * var(--u)) calc(44 * var(--u)) calc(44 * var(--u)) calc(12 * var(--u)); background: var(--white);
  box-shadow: 0 calc(34 * var(--u)) calc(70 * var(--u)) calc(-34 * var(--u)) rgba(11, 18, 32, .45), 0 0 0 1px rgba(11, 18, 32, .06);
}
.ch-say[dir="rtl"] { border-radius: calc(44 * var(--u)) calc(44 * var(--u)) calc(12 * var(--u)) calc(44 * var(--u)); }
.ch-line { display: block; font-size: calc(46 * var(--u)); font-weight: 650; letter-spacing: -.02em; line-height: 1.2; color: var(--ink);
  transition: opacity .45s, translate .6s var(--ez), filter .45s; }
.ch-line[hidden] { display: none; }
.ch-line.is-out { opacity: 0; filter: blur(6px); translate: var(--out, 40px) 0; }
.ch-line.is-pre { opacity: 0; filter: blur(6px); translate: var(--in, -48px) 0; transition: none; }
.ch-lang-name { margin: calc(18 * var(--u)) 0 0; font-size: max(13px, calc(16 * var(--u))); font-weight: 600; color: var(--steel); }

/* stack: one bar per channel, stacked into one over the Echo mark. */
.ch-stack { aspect-ratio: 880 / 380; --pitch: 116; --bw: 76; --mk: 60; }
.ch-bar {
  position: absolute; left: 50%; bottom: calc(96 * var(--u)); width: calc(var(--bw) * var(--u)); margin-left: calc(var(--bw) * var(--u) / -2);
  height: calc(var(--h) * var(--u)); border-radius: calc(18 * var(--u)); background: var(--c);
  translate: calc(var(--o) * var(--pitch) * var(--u)) 0;
  transition: height .9s var(--ez) var(--d), translate 1.1s var(--ez), border-radius .6s;
}
.ch-stack.is-low .ch-bar { height: 0; }
.ch-stack.is-one .ch-bar { height: calc(var(--hk) * var(--u)); translate: 0 calc(var(--yk) * var(--u)); border-radius: calc(10 * var(--u)); transition-delay: 0s; }
.ch-stack .ch-mark {
  position: absolute; left: 50%; bottom: calc(14 * var(--u)); width: calc(var(--mk) * var(--u)); height: calc(var(--mk) * var(--u));
  margin-left: calc(var(--mk) * var(--u) / -2); display: grid; place-items: center;
  translate: calc(var(--o) * var(--pitch) * var(--u)) 0; transition: opacity .5s, translate 1.1s var(--ez), scale .6s var(--spring);
}
.ch-stack.is-one .ch-mark { opacity: 0; translate: 0 0; scale: .5; }
.ch-echo { position: absolute; left: 50%; bottom: calc(12 * var(--u)); width: calc(64 * var(--u)); height: calc(64 * var(--u)); margin-left: calc(-32 * var(--u));
  opacity: 0; scale: .5; transition: opacity .5s, scale .6s var(--spring); }
.ch-echo img { width: 100%; height: 100%; }
.ch-stack.is-one .ch-echo { opacity: 1; scale: 1; transition-delay: .5s; }

/* A phone: a design space half as wide, so everything reads larger, and the
   marks and groups fold into rows. */
@media (max-width: 600px) {
  .ch-body { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .ch-sym { --u: calc(100cqw / 440); aspect-ratio: 440 / 300; }
  .ch-gather .ch-mark { --x: var(--x0m); --y: var(--y0m); --ms: 84; }
  .ch-gather.is-one .ch-mark { --x: var(--x1m); --y: var(--y1m); }
  .ch-glow { width: calc(420 * var(--u)); height: calc(280 * var(--u)); margin: calc(-140 * var(--u)) 0 0 calc(-210 * var(--u)); }
  .ch-route { aspect-ratio: 440 / 440; }
  .ch-home { translate: calc(var(--xm) * var(--u)) calc(var(--ym) * var(--u)); }
  .ch-claim { aspect-ratio: 440 / 300; }
  /* The card is narrower here so a face at either edge clears it: 135 + 38 < 180. */
  .ch-card { width: calc(270 * var(--u)); height: calc(160 * var(--u)); margin: calc(-80 * var(--u)) 0 0 calc(-135 * var(--u)); padding: calc(32 * var(--u)) calc(28 * var(--u)); }
  .ch-face { --x: -180; width: calc(76 * var(--u)); height: calc(76 * var(--u)); margin: calc(-38 * var(--u)) 0 0 calc(-38 * var(--u)); }
  .ch-face.b, .ch-claim.is-mine .ch-face.b { --x: 180; }
  .ch-claim.is-near .ch-face.a { --x: -180; }
  .ch-claim.is-near .ch-face.b { --x: 180; }
  .ch-claim.is-mine .ch-face.a { --x: -135; --y: -80; }
  .ch-languages { aspect-ratio: 440 / 260; }
  .ch-say { width: calc(424 * var(--u)); min-height: calc(120 * var(--u)); padding: calc(26 * var(--u)) calc(30 * var(--u)); }
  .ch-line { font-size: calc(30 * var(--u)); }
  .ch-stack { aspect-ratio: 440 / 380; --pitch: 70; --bw: 50; --mk: 48; }
}
@media (prefers-reduced-motion: reduce) {
  .ch-sym, .ch-sym * { transition: none !important; }
}

/* ---- The drawn symbols, and the layouts they came with -----------------
   /product/security's round-2 design (plan/25), rebuilt as blocks on
   2026-09-29. It had been a hand-built file with these rules in its own
   <style>; they are here now word for word, apart from two changes that
   leave every computed value where it was:
     * the page's class names became the blocks': .sc-intro is section's
       intro (.chapters-intro), .chapter.sc-ch is chapter's compact layout
       (.chapter.is-compact), .sr is chapter's row layout (.symrow), .sc-kept
       and .kept are cardgrid's statements layout, .sc-honest and .cannot are
       its ledger layout (.cg-ledger, .is-hollow);
     * every drawing rule sits under .sx-stage. Its class names are short
       and generic (.card, .dots, .msg, .node, .ok), and scoped they can never
       touch another page. Each rule gains the same one class, so which of
       them wins inside a drawing is exactly what it was on the lab page.
   Measured against the live hand-built page before it was replaced: every
   element of every drawing, at 1280 and 390, the same box and the same
   computed style.

   Rendered by `chapter` (symbols wall, bridge, sets, cipher, code, thread),
   `section` (settings.intro) and `cardgrid` (layouts statements, ledger) in
   tools/marketing-blocks.mjs, played by site.js's [data-sx] driver. The
   wall and the bridge carry a phone arrangement as a second copy; one of the
   two is shown, at the width the lab page switched on. */

/* The head that opens a run of chapters (section, settings.intro). */
.chapters-intro { padding: clamp(80px, 10vw, 136px) 0 0; text-align: center; }
.chapters-intro .eyebrow { justify-content: center; }
.chapters-intro h2 { margin: 12px auto 0; max-width: 16em; font-size: clamp(30px, 3.6vw, 46px); letter-spacing: -.03em; line-height: 1.06; }
.chapters-intro .lead { margin: 18px auto 0; max-width: 34em; color: var(--slate); }

/* The chapters are the site's own .chapter, set smaller (Kara: round 1's
   type was "really big for not a lot of detail") and carrying two
   paragraphs of substance under the picture. */
.chapter.is-compact { padding: clamp(72px, 9vw, 128px) 0; }
.chapter.is-compact h2 { font-size: clamp(34px, 4.6vw, 62px); max-width: 15em; }
.chapter.is-compact .lead { max-width: 33em; }
.chapters-intro + .chapter.is-compact { padding-top: clamp(48px, 5vw, 72px); }
.chapter .sx-stage { max-width: 900px; margin: clamp(36px, 4.5vw, 60px) auto clamp(30px, 3.6vw, 52px); }
.chapter.is-compact .ch-body { max-width: 980px; }

/* A compact row: words on one side, a smaller picture on the other. */
.symrow { padding: clamp(72px, 9vw, 124px) 0; }
.symrow > .wrap { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: 32px clamp(36px, 5.5vw, 88px); align-items: center; }
.symrow.is-flip .symrow-words { order: 2; }
.symrow h2 { margin-top: 12px; font-size: clamp(28px, 3vw, 40px); letter-spacing: -.028em; line-height: 1.1; }
.symrow-words p { margin: 16px 0 0; font-size: 17.5px; line-height: 1.6; color: var(--slate); max-width: 34em; }
.symrow-words p b { color: var(--ink); font-weight: 650; }
.symrow-words .link-arrow { display: inline-flex; margin-top: 20px; }
@media (max-width: 860px) {
  .symrow > .wrap { grid-template-columns: minmax(0, 1fr); }
  .symrow.is-flip .symrow-words { order: 0; }
}

/* Kept current: two statements across a hairline, the house dot on each. */
.cg-statements { padding: clamp(72px, 9vw, 124px) 0; }
.cg-statements .head { text-align: center; }
.cg-statements .head .eyebrow { justify-content: center; }
.cg-statements h2 { margin: 12px auto 0; max-width: 16em; font-size: clamp(28px, 3vw, 40px); letter-spacing: -.028em; line-height: 1.1; }
.statements { display: grid; grid-template-columns: 1fr 1fr; max-width: 980px; margin: clamp(36px, 4.4vw, 60px) auto 0; }
.statements > div { padding: 4px clamp(22px, 3.4vw, 48px); }
.statements > div + div { border-left: 1px solid var(--cloud); }
.statements h3 { position: relative; padding-left: 20px; font-size: 20px; letter-spacing: -.012em; line-height: 1.3; }
.statements h3::before { content: ""; position: absolute; left: 0; top: .5em; width: 7px; height: 7px; border-radius: 50%; background: var(--deep-blue); }
.statements p { margin: 10px 0 0; padding-left: 20px; font-size: 17px; line-height: 1.6; color: var(--slate); }
@media (max-width: 760px) {
  .statements { grid-template-columns: 1fr; }
  .statements > div { padding: 0; }
  .statements > div + div { border-left: 0; margin-top: 30px; }
}

/* The honest version: two lists across a hairline, from round 1 A. The dot
   is the house device: filled for what we control, hollow for what we cannot. */
.cg-ledger { padding: clamp(72px, 9vw, 124px) 0; text-align: center; }
.cg-ledger .eyebrow { justify-content: center; }
.cg-ledger h2 { margin: 12px auto 0; max-width: 16em; font-size: clamp(28px, 3vw, 40px); letter-spacing: -.028em; line-height: 1.1; }
.cg-ledger .lead { margin: 18px auto 0; max-width: 36em; color: var(--slate); }
.ledger { display: grid; grid-template-columns: 1fr 1fr; max-width: 1000px; margin: clamp(40px, 5vw, 64px) auto 0; text-align: left; }
.ledger > div { padding: 6px clamp(22px, 3.4vw, 48px); }
.ledger > div + div { border-left: 1px solid var(--cloud); }
.ledger h3 { font-size: 20px; letter-spacing: -.012em; }
.ledger ul { list-style: none; margin: 18px 0 0; padding: 0; }
.ledger li { position: relative; padding: 14px 0 14px 22px; border-top: 1px solid var(--cloud); font-size: 17px; line-height: 1.5; color: var(--ink); }
.ledger li::before { content: ""; position: absolute; left: 0; top: 23px; width: 7px; height: 7px; border-radius: 50%; background: var(--deep-blue); }
.ledger .is-hollow li { color: var(--slate); }
.ledger .is-hollow li::before { background: transparent; box-shadow: inset 0 0 0 1.5px var(--steel); }
.cg-ledger .cg-link { margin-top: 34px; }
@media (max-width: 760px) {
  .ledger { grid-template-columns: 1fr; }
  .ledger > div { padding: 0; }
  .ledger > div + div { border-left: 0; margin-top: 36px; }
}

.cg-statements .lead { margin: 18px auto 0; max-width: 36em; color: var(--slate); }

/* The drawings. */
.sx-stage { container-type: inline-size; width: 100%; }
.sx-stage .sx { --u: calc(100cqw / var(--dw)); --ez: cubic-bezier(.2, .8, .2, 1); --spring: cubic-bezier(.34, 1.4, .5, 1); --fly: cubic-bezier(.45, .05, .55, .95);
  --ground: var(--white); --bar: color-mix(in srgb, var(--steel) 26%, var(--white));
  position: relative; width: 100%; aspect-ratio: var(--dw) / var(--dh); color: var(--ink); text-align: left; }
.bg-mist .sx-stage .sx { --ground: var(--mist); }
.sx-stage .sx * { box-sizing: border-box; }
.sx-stage .sx > *, .sx-stage .sx .ab { position: absolute; }
/* Moved without transitions, when a symbol takes its starting pose. */
.sx-stage .sx.is-set, .sx-stage .sx.is-set * { transition: none !important; animation: none !important; }
.sx-stage .sx p { margin: 0; }
.sx-stage .sx .t { font-size: max(12px, calc(15 * var(--u))); font-weight: 600; line-height: 1.3; color: var(--steel); }
.sx-stage .sx .t b { color: var(--ink); font-weight: 650; }
.sx-stage .sx .cap { text-align: center; }

/* A message bubble: two bars of words, the seeker's or the team's. */
.sx-stage .wb { border-radius: calc(18 * var(--u)); padding: calc(14 * var(--u)) calc(16 * var(--u)); background: var(--panel);
  box-shadow: 0 0 0 calc(1 * var(--u)) var(--cloud), 0 calc(12 * var(--u)) calc(24 * var(--u)) calc(-16 * var(--u)) rgba(11, 18, 32, .35);
  transition: background .35s ease, box-shadow .35s ease, opacity .35s ease, scale .45s var(--spring), translate var(--D, 1.5s) var(--fly); }
.sx-stage .wb i { display: block; height: calc(9 * var(--u)); border-radius: calc(5 * var(--u)); background: var(--bar); transition: background .35s ease; }
.sx-stage .wb i + i { margin-top: calc(8 * var(--u)); }
.sx-stage .wb.is-me { background: var(--grad-deep-current); box-shadow: 0 calc(14 * var(--u)) calc(26 * var(--u)) calc(-16 * var(--u)) rgba(0, 112, 248, .55); }
.sx-stage .wb.is-me i { background: rgba(255, 255, 255, .62); }
.sx-stage .wb.is-hide { opacity: 0; scale: .7; }
.sx-stage .wb-who { position: absolute; right: calc(-12 * var(--u)); bottom: calc(-10 * var(--u)); width: calc(28 * var(--u)); height: calc(28 * var(--u)); }
.sx-stage .wb-who > span { position: absolute; inset: 0; border-radius: 50%; box-shadow: 0 0 0 calc(3 * var(--u)) var(--ground); transition: opacity .3s ease, scale .45s var(--spring); }
.sx-stage .wb-who .f { background: center / cover no-repeat; }
.sx-stage .wb-who .m { background: var(--grad-deep-current); opacity: 0; scale: .5; }
.sx-stage .wb.is-min .wb-who .f { opacity: 0; scale: .5; }
.sx-stage .wb.is-min .wb-who .m { opacity: 1; scale: 1; }
/* The ministry's avatar: the brand gradient with a plain initial-free face. */
.sx-stage .min-av { border-radius: 50%; background: var(--grad-deep-current); position: relative; }
.sx-stage .min-av::after { content: ""; position: absolute; inset: 22%; border-radius: 50%; border: calc(2.4 * var(--u)) solid rgba(255, 255, 255, .85); }

/* A phone, as the seeker holds it. */
.sx-stage .dev { border-radius: calc(30 * var(--u)); border: calc(2.5 * var(--u)) solid var(--ink); background: var(--white); }
.sx-stage .dev-notch { left: 50%; top: calc(11 * var(--u)); width: calc(40 * var(--u)); height: calc(6 * var(--u)); margin-left: calc(-20 * var(--u)); border-radius: calc(3 * var(--u)); background: var(--cloud); }
.sx-stage .dev .hr { height: 1px; background: var(--cloud); }
.sx-stage .dev .nm { font-size: max(12px, calc(14 * var(--u))); font-weight: 700; color: var(--ink); white-space: nowrap; }
.sx-stage .dev .mk { object-fit: contain; transition: opacity .3s ease; }

/* WALL: the seeker's phone on one side, Echo's window on the other, the
   wall between with the Echo mark in it. A message crosses; a reply
   crosses back and leaves the responder's face behind on the Echo side. */
.sx-stage .ww .wk { position: absolute; border-radius: calc(5 * var(--u)); background: var(--cloud); transition: background .5s ease; }
.sx-stage .sx-wall.is-pass .ww .wk { background: color-mix(in srgb, var(--echo-cyan) 32%, var(--cloud)); }
.sx-stage .wm { transition: filter .35s ease, scale .5s var(--spring); }
.sx-stage .sx-wall.is-pass .wm, .sx-stage .sx-bridge.is-pass .wm, .sx-stage .sx-cipher .node.is-on .wm { filter: drop-shadow(0 0 calc(18 * var(--u)) rgba(61, 180, 232, .9)); scale: 1.06; }
.sx-stage .wn { border-radius: calc(18 * var(--u)); background: var(--white); box-shadow: 0 0 0 1px var(--cloud), 0 calc(24 * var(--u)) calc(48 * var(--u)) calc(-28 * var(--u)) rgba(11, 18, 32, .45); }
.sx-stage .wn .hr { height: 1px; background: var(--cloud); }
.sx-stage .wn .nm { font-size: max(12px, calc(15 * var(--u))); font-weight: 700; color: var(--ink); }
.sx-stage .wn-face { border-radius: 50%; background: center / cover no-repeat; box-shadow: 0 0 0 calc(3 * var(--u)) var(--white); transition: box-shadow .45s ease; }
.sx-stage .wn.is-got .wn-face { box-shadow: 0 0 0 calc(3 * var(--u)) var(--white), 0 0 0 calc(6 * var(--u)) var(--deep-blue); }
.sx-stage .wp-lab { font-size: max(11px, calc(12.5 * var(--u))); font-weight: 600; color: var(--steel); opacity: 0; transition: opacity .4s ease; white-space: nowrap; }
.sx-stage .wp-lab.is-on { opacity: 1; }
.sx-stage .fly { z-index: 3; }
.sx-stage .fly.is-gone { opacity: 0; }

/* BRIDGE: the seeker's phone, Echo, the responder. Lights carry the call. */
.sx-stage .bs { text-align: center; }
.sx-stage .bs .ab { left: 0; right: 0; }
.sx-stage .bs-av { left: 50% !important; right: auto !important; margin-left: calc(-30 * var(--u)); width: calc(60 * var(--u)); height: calc(60 * var(--u)); transition: opacity .4s ease, scale .5s var(--spring); }
.sx-stage .bs-av.min-av::after { display: none; }
.sx-stage .bs-av svg { position: absolute; left: 50%; top: 50%; width: 44%; height: 44%; margin: -22% 0 0 -22%; color: #fff; }
.sx-stage .bs .nm { transition: opacity .4s ease; }
.sx-stage .bs-st { font-size: max(11px, calc(12.5 * var(--u))); font-weight: 600; color: var(--steel); transition: opacity .4s ease; font-variant-numeric: tabular-nums; }
.sx-stage .bs.is-blank .bs-av, .sx-stage .bs.is-blank .nm, .sx-stage .bs.is-blank .bs-st { opacity: 0; }
.sx-stage .bs.is-blank .bs-av { scale: .6; }
.sx-stage .sx-bridge .dev { transition: box-shadow .4s ease; }
.sx-stage .sx-bridge.s-seek-ring .dev { animation: sxRing 1s ease-in-out infinite; }
@keyframes sxRing { 0%, 100% { box-shadow: 0 0 0 0 rgba(61, 180, 232, 0); } 50% { box-shadow: 0 0 calc(34 * var(--u)) calc(4 * var(--u)) rgba(61, 180, 232, .55); } }
.sx-stage .bf { border-radius: 50%; background: center / cover no-repeat; box-shadow: 0 0 0 calc(4 * var(--u)) var(--ground), 0 calc(18 * var(--u)) calc(34 * var(--u)) calc(-16 * var(--u)) rgba(11, 18, 32, .5); }
.sx-stage .bf-glow { border-radius: 50%; background: radial-gradient(closest-side, rgba(61, 180, 232, .6), rgba(0, 112, 248, .18) 60%, transparent); filter: blur(calc(10 * var(--u))); opacity: 0; scale: .7; transition: opacity .5s ease, scale .6s ease; }
.sx-stage .sx-bridge.s-resp-ring .bf-glow { animation: sxGlow 1s ease-in-out infinite; }
.sx-stage .sx-bridge.s-on .bf-glow { opacity: .8; scale: 1; }
@keyframes sxGlow { 0%, 100% { opacity: .25; scale: .75; } 50% { opacity: .95; scale: 1; } }
.sx-stage .bb { border-radius: 50%; background: var(--grad-deep-current); box-shadow: 0 0 0 calc(4 * var(--u)) var(--ground); display: grid; place-items: center; color: #fff; transition: scale .45s var(--spring); }
.sx-stage .bb svg { width: 52%; height: 52%; }
.sx-stage .sx-bridge.s-press .bb { scale: 1.18; }
.sx-stage .bl { border-radius: 50%; background: radial-gradient(closest-side, #fff, #7FD0F5 45%, rgba(0, 112, 248, 0)); filter: blur(calc(1.5 * var(--u))); opacity: 0; transition: translate .9s var(--ez), opacity .25s ease; z-index: 2; }
.sx-stage .bl.is-on { opacity: 1; }
.sx-stage .bchip { display: flex; align-items: center; justify-content: center; }
.sx-stage .bchip span { display: inline-flex; align-items: center; gap: calc(8 * var(--u)); padding: 0 calc(14 * var(--u)); height: calc(32 * var(--u)); border-radius: calc(16 * var(--u));
  background: var(--white); box-shadow: 0 0 0 1px var(--cloud); font-size: max(12px, calc(14 * var(--u))); font-weight: 650; color: var(--ink); white-space: nowrap; transition: opacity .35s ease; }
.sx-stage .bchip span::before { content: ""; width: calc(7 * var(--u)); height: calc(7 * var(--u)); min-width: 6px; min-height: 6px; border-radius: 50%; background: var(--deep-blue); }

/* SETS: the ministry's conversations; each responder lights only their own. */
.sx-stage .cv { border-radius: calc(9 * var(--u)); background: var(--cloud); transition: background .55s ease, opacity .55s ease, filter .55s ease; }
.sx-stage .sx-sets.is-on .cv { opacity: .32; filter: blur(calc(1.4 * var(--u))); }
.sx-stage .sx-sets.is-on .cv.is-lit { opacity: 1; filter: none; background: var(--c); }
.sx-stage .who { border-radius: 50%; background: center / cover no-repeat; box-shadow: 0 0 0 calc(4 * var(--u)) var(--ground), 0 calc(16 * var(--u)) calc(30 * var(--u)) calc(-16 * var(--u)) rgba(11, 18, 32, .5);
  transition: box-shadow .45s ease, scale .6s var(--spring), opacity .45s ease; }
.sx-stage .sx-sets.is-on .who { opacity: .45; }
.sx-stage .sx-sets .who.is-me { opacity: 1; scale: 1.1; box-shadow: 0 0 0 calc(4 * var(--u)) var(--ground), 0 0 0 calc(7 * var(--u)) var(--c), 0 calc(18 * var(--u)) calc(34 * var(--u)) calc(-16 * var(--u)) rgba(11, 18, 32, .5); }
.sx-stage .sx-sets .t { transition: color .45s ease; }
.sx-stage .sx-sets .t.is-me { color: var(--ink); }

/* CIPHER: one message, readable on a screen and inside Echo, scrambled
   while it travels and while it is stored. */
.sx-stage .node { display: grid; place-items: center; }
.sx-stage .node .g { width: 100%; height: 100%; color: var(--steel); transition: color .4s ease, filter .4s ease; }
.sx-stage .node.is-on .g { color: var(--ink); filter: drop-shadow(0 0 calc(14 * var(--u)) rgba(61, 180, 232, .55)); }
.sx-stage .node-lab { text-align: center; transition: color .4s ease; }
.sx-stage .node-lab.is-on { color: var(--ink); }
.sx-stage .brw { border: calc(2.5 * var(--u)) solid currentColor; border-radius: calc(10 * var(--u)); position: relative; }
.sx-stage .brw::before { content: ""; position: absolute; left: 0; right: 0; top: calc(16 * var(--u)); height: calc(2.5 * var(--u)); background: currentColor; }
.sx-stage .brw::after { content: ""; position: absolute; left: calc(8 * var(--u)); top: calc(5 * var(--u)); width: calc(6 * var(--u)); height: calc(6 * var(--u)); border-radius: 50%; background: currentColor; box-shadow: calc(10 * var(--u)) 0 0 currentColor, calc(20 * var(--u)) 0 0 currentColor; }
.sx-stage .card { border-radius: calc(20 * var(--u)); background: var(--white); box-shadow: 0 0 0 1px var(--cloud), 0 calc(24 * var(--u)) calc(48 * var(--u)) calc(-30 * var(--u)) rgba(11, 18, 32, .45); }
.sx-stage .st { display: flex; align-items: center; gap: calc(9 * var(--u)); font-size: max(12px, calc(14 * var(--u))); font-weight: 650; color: var(--ink); white-space: nowrap; }
.sx-stage .st::before { content: ""; width: calc(8 * var(--u)); height: calc(8 * var(--u)); min-width: 6px; min-height: 6px; border-radius: 50%; background: var(--steel); transition: background .35s ease; }
.sx-stage .st.is-enc::before { background: var(--success); }
.sx-stage .st svg { width: calc(15 * var(--u)); height: calc(15 * var(--u)); min-width: 12px; min-height: 12px; color: var(--success); display: none; }
.sx-stage .st.is-enc svg { display: block; }
.sx-stage .msg { font-family: var(--font-mono); font-size: max(12px, calc(20 * var(--u))); font-weight: 600; letter-spacing: -.01em; color: var(--ink); white-space: pre; overflow: hidden; transition: color .3s ease; }
.sx-stage .msg.is-enc { color: var(--slate); }
.sx-stage .lk { width: calc(22 * var(--u)); height: calc(22 * var(--u)); margin: calc(-38 * var(--u)) 0 0 calc(-11 * var(--u)); color: var(--success); opacity: 0; transition: opacity .25s ease, translate 1s var(--ez); }
.sx-stage .lk.is-on { opacity: 1; }

/* CODE: signing in, and the six digits a second device supplies. */
.sx-stage .fld { border-radius: calc(10 * var(--u)); box-shadow: inset 0 0 0 calc(1.5 * var(--u)) var(--cloud); }
.sx-stage .fld .bar { left: calc(14 * var(--u)); top: calc(16 * var(--u)); height: calc(10 * var(--u)); border-radius: calc(5 * var(--u)); background: var(--bar); transition: width .5s var(--ez); }
.sx-stage .dots { left: calc(16 * var(--u)); top: calc(15 * var(--u)); display: flex; gap: calc(8 * var(--u)); }
.sx-stage .dots i { width: calc(11 * var(--u)); height: calc(11 * var(--u)); border-radius: 50%; background: var(--ink); opacity: 0; scale: .3; transition: opacity .15s ease, scale .25s var(--spring); }
.sx-stage .dots i.is-on { opacity: 1; scale: 1; }
.sx-stage .dg { border-radius: calc(10 * var(--u)); box-shadow: inset 0 0 0 calc(1.5 * var(--u)) var(--cloud); display: grid; place-items: center;
  font-family: var(--font-mono); font-size: max(13px, calc(24 * var(--u))); font-weight: 700; color: var(--ink); transition: box-shadow .3s ease; }
.sx-stage .dg span { opacity: 0; translate: 0 calc(8 * var(--u)); transition: opacity .2s ease, translate .3s var(--ez); }
.sx-stage .dg.is-on { box-shadow: inset 0 0 0 calc(2 * var(--u)) var(--deep-blue); }
.sx-stage .dg.is-on span { opacity: 1; translate: 0 0; }
.sx-stage .ok { display: flex; align-items: center; gap: calc(10 * var(--u)); font-size: max(12px, calc(15 * var(--u))); font-weight: 650; color: var(--ink); opacity: 0; translate: 0 calc(10 * var(--u)); transition: opacity .35s ease, translate .5s var(--spring); }
.sx-stage .ok i { width: calc(28 * var(--u)); height: calc(28 * var(--u)); min-width: 18px; min-height: 18px; border-radius: 50%; background: var(--success); display: grid; place-items: center; }
.sx-stage .ok svg { width: 58%; height: 58%; color: #fff; }
.sx-stage .ok.is-on { opacity: 1; translate: 0 0; }
.sx-stage .cd-src { text-align: center; }
.sx-stage .cd-src .ab { left: 0; right: 0; }
.sx-stage .cd-code { font-family: var(--font-mono); font-size: max(14px, calc(26 * var(--u))); font-weight: 700; color: var(--ink); letter-spacing: .02em; }
.sx-stage .cd-src .cd-in { opacity: 0; transition: opacity .4s ease, scale .5s var(--spring); scale: .9; }
.sx-stage .cd-src.is-on .cd-in { opacity: 1; scale: 1; }
.sx-stage .cd-src .ico { left: 50% !important; right: auto !important; color: var(--steel); }
.sx-stage .cd-timer { left: 50% !important; right: auto !important; height: calc(6 * var(--u)); border-radius: calc(3 * var(--u)); background: var(--cloud); overflow: hidden; }
.sx-stage .cd-timer i { display: block; height: 100%; width: 100%; background: var(--deep-blue); transform-origin: 0 50%; transition: scale 3.4s linear; }
.sx-stage .cd-src.is-on .cd-timer i { scale: .15 1; }
.sx-stage .sx-code .dev { transition: box-shadow .5s ease; }
.sx-stage .sx-code .dev.is-glow { box-shadow: 0 0 calc(30 * var(--u)) calc(2 * var(--u)) rgba(61, 180, 232, .5); }

/* THREAD: every conversation keeps who answered, and when. */
.sx-stage .th-col { display: flex; flex-direction: column; }
.sx-stage .th-row { display: flex; flex-direction: column; margin-top: calc(12 * var(--u)); opacity: 0; translate: 0 calc(14 * var(--u)); transition: opacity .5s ease, translate .6s var(--ez); }
.sx-stage .th-row.r { align-items: flex-end; }
.sx-stage .th-row.is-in { opacity: 1; translate: 0 0; }
.sx-stage .th-row .wb { position: relative; width: calc(250 * var(--u)); border-radius: calc(18 * var(--u)) calc(18 * var(--u)) calc(18 * var(--u)) calc(6 * var(--u)); }
.sx-stage .th-row.r .wb { border-radius: calc(18 * var(--u)) calc(18 * var(--u)) calc(6 * var(--u)) calc(18 * var(--u)); }
.sx-stage .th-meta { display: flex; align-items: center; gap: calc(8 * var(--u)); margin-top: calc(7 * var(--u)); font-size: max(12px, calc(13.5 * var(--u))); font-weight: 600; color: var(--steel); opacity: .6; transition: opacity .4s ease, color .4s ease; font-variant-numeric: tabular-nums; }
.sx-stage .th-meta .f { width: calc(22 * var(--u)); height: calc(22 * var(--u)); min-width: 16px; min-height: 16px; border-radius: 50%; background: center / cover no-repeat; }
.sx-stage .th-row.is-read .th-meta { opacity: 1; color: var(--ink); }
.sx-stage .th-scan { left: 0; width: 100%; height: calc(70 * var(--u)); border-radius: calc(40 * var(--u)); pointer-events: none;
  background: radial-gradient(closest-side, rgba(61, 180, 232, .28), rgba(61, 180, 232, 0)); filter: blur(calc(8 * var(--u))); opacity: 0; translate: 0 calc(-20 * var(--u)); }
.sx-stage .sx-thread.is-scan .th-scan { opacity: 1; translate: 0 calc(280 * var(--u)); transition: translate 2.2s cubic-bezier(.45, 0, .3, 1), opacity .4s ease; }

@media (prefers-reduced-motion: reduce) {
  .sx-stage .sx *, .sx-stage .sx { transition: none !important; animation: none !important; }
}

/* The wall and the bridge in their tall phone arrangement, one copy shown. */
.sx-stage .sx.is-phone { display: none; }
@media (max-width: 600px) {
  .sx-stage .sx.is-desk { display: none; }
  .sx-stage .sx.is-phone { display: block; }
}


/* ============================================================
   The Help Center, round 2 (2026-09-29)
   ============================================================
   The team's notes on three options (/lab/refine-help-center.html) and the
   round 2 they approved (/lab/refine-help-center-2.html): option A's top on
   the hub, because it works like the top of the FAQ; the topics listed as
   option B's big rows, each with its own picture; a topic page with its
   picture over its name and its articles as rows with no pictures; and
   option A's article, the site's big headline and no picture. Rendered by
   tools/help-render.mjs. Hairlines and type throughout: no card grid, no
   tint, no bar down an edge. */

/* ---- The hub's top: a film still, like the FAQ's -------------------------- */
.page-hero.hero-photo.hc-hero-photo { min-height: clamp(440px, 60vh, 600px); --fp: 68% 42%; }
/* On a phone the crop moves to the right edge, onto the man: at 68% (and
   still at 86%) the café lamp sat under the eyebrow and measured 4.0:1
   (tools/hero-contrast.mjs, 390x844). */
@media (max-width: 720px) { .page-hero.hero-photo.hc-hero-photo { --fp: 100% 45%; } }
.hc-hero-photo h1 { font-size: clamp(42px, 6vw, 76px); }
.hc-hero-photo .hc-search { max-width: 620px; margin: 28px auto 0; }
/* White on the photograph in both themes, like the FAQ's box. */
.hc-hero-photo .hc-search input {
  height: 58px; padding: 0 20px 0 52px; border: 0; border-radius: 16px; box-shadow: none;
  background: rgba(255, 255, 255, .97) no-repeat 20px 50% / 20px 20px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%235A6B85' stroke-width='1.8' stroke-linecap='round'%3E%3Ccircle cx='8.5' cy='8.5' r='5.5'/%3E%3Cpath d='m13 13 4 4'/%3E%3C/svg%3E");
  color: #0E1726; font-size: 17px;
}
.hc-hero-photo .hc-search input::placeholder { color: #5A6B85; }
.hc-hero-photo .hc-search input:focus-visible { border-color: transparent; box-shadow: 0 0 0 4px rgba(92, 196, 242, .45); }
.hc-try { margin: 16px 0 0; font-size: 14.5px; color: #D3DEEF; }
.hc-try button {
  appearance: none; background: none; border: 0; padding: 2px 4px; margin: 0 2px; cursor: pointer;
  font: inherit; font-weight: 650; color: #fff; text-decoration: underline; text-underline-offset: 3px;
}
.hc-try button:focus-visible { outline: 2px solid #5CC4F2; outline-offset: 2px; border-radius: 4px; }
.hc-try span { color: #B4C3DB; }
.hc-hero-photo .hc-hero-watch { margin: 12px 0 0; font-size: 14.5px; color: #C0CDE4; }
.hc-hero-photo .hc-hero-watch a { color: #fff; font-weight: 650; }

/* ---- The topics: big rows, each with its picture --------------------------- */
.hc-browse-title { margin: 0 0 clamp(18px, 2vw, 26px); font-size: clamp(24px, 2.4vw, 32px); letter-spacing: -.025em; }
.hc-topics { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--cloud); }
.hc-topics > li { border-bottom: 1px solid var(--cloud); }
.hc-topic {
  display: grid; grid-template-columns: 176px minmax(0, 1fr) auto 32px; gap: 6px clamp(20px, 2.6vw, 36px);
  align-items: center; padding: clamp(18px, 2.2vw, 26px) 0; color: inherit; text-decoration: none;
}
.hc-topic-shot {
  grid-row: 1 / span 2; display: grid; place-items: center; aspect-ratio: 4 / 3;
  border-radius: 14px; overflow: hidden; background: var(--mist); color: var(--echo-cyan);
}
.hc-topic-shot img { width: 100%; height: 100%; object-fit: cover; display: block; transition: scale .5s cubic-bezier(.2, .8, .2, 1); }
.hc-topic-shot .hc-icon { width: 34px; height: 34px; }
.hc-topic-name {
  grid-column: 2; align-self: end; margin: 0; font-size: clamp(26px, 3vw, 40px); font-weight: 700;
  letter-spacing: -.03em; line-height: 1.08; color: var(--ink); transition: color .2s;
}
.hc-topic-desc { grid-column: 2; align-self: start; margin: 0; font-size: 16px; line-height: 1.5; color: var(--slate); max-width: 56ch; }
.hc-topic-count { grid-column: 3; grid-row: 1 / span 2; font-family: var(--font-mono); font-size: 14px; font-weight: 600; color: var(--slate); white-space: nowrap; }
.hc-topic-arrow { grid-column: 4; grid-row: 1 / span 2; font-size: 22px; color: var(--slate); transition: translate .25s cubic-bezier(.2, .8, .2, 1), color .2s; }
.hc-topic:hover .hc-topic-name { color: var(--action-ink); }
.hc-topic:hover .hc-topic-arrow { translate: 6px 0; color: var(--action-ink); }
.hc-topic:hover .hc-topic-shot img { scale: 1.04; }
.hc-topic:focus-visible, .hc-row:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 4px; border-radius: 8px; }

/* ---- Articles in a list: big rows, no pictures ----------------------------- */
.hc-rows { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--cloud); }
.hc-rows > li { border-bottom: 1px solid var(--cloud); }
.hc-row {
  display: grid; grid-template-columns: 64px minmax(0, 1fr) 32px; gap: 6px 20px;
  align-items: baseline; padding: 20px 0; color: inherit; text-decoration: none;
}
.hc-row.no-num { grid-template-columns: minmax(0, 1fr) 28px; }
.hc-row-num { font-family: var(--font-mono); font-size: 14px; font-weight: 600; color: var(--slate); }
.hc-row-title { margin: 0; font-size: clamp(20px, 2vw, 26px); font-weight: 700; letter-spacing: -.02em; line-height: 1.15; color: var(--ink); transition: color .2s; }
.hc-row-arrow { font-size: 20px; color: var(--slate); transition: translate .25s cubic-bezier(.2, .8, .2, 1), color .2s; }
.hc-row-desc { grid-column: 2; margin: 0; font-size: 16px; line-height: 1.5; color: var(--slate); max-width: 64ch; }
.hc-row.no-num .hc-row-desc { grid-column: 1; }
.hc-row:hover .hc-row-title { color: var(--action-ink); }
.hc-row:hover .hc-row-arrow { translate: 6px 0; color: var(--action-ink); }
/* The shorter lists (the hub's rail, "More in" under an article) run two wide. */
.hc-rows.is-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(28px, 4vw, 56px); border-top: 0; }
.hc-rows.is-pair > li { border-top: 1px solid var(--cloud); border-bottom: 0; }
.hc-rows.is-pair .hc-row { padding: 16px 0; }
.hc-rows.is-pair .hc-row-title { font-size: clamp(18px, 1.6vw, 21px); }
.hc-rows.is-pair .hc-row-desc { font-size: 15px; }

/* ---- A topic page's head: its picture over its name ------------------------ */
.hc-cathead { padding: clamp(32px, 4.4vw, 64px) 0 clamp(24px, 3vw, 40px); background: var(--white); }
.hc-tile {
  display: grid; place-items: center; width: 168px; aspect-ratio: 4 / 3; margin: 0 0 22px;
  border-radius: 16px; overflow: hidden; background: var(--mist); color: var(--echo-cyan);
  box-shadow: 0 10px 30px rgba(6, 11, 24, .12);
}
.hc-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hc-tile .hc-icon { width: 40px; height: 40px; }
.hc-cathead h1 { margin: 12px 0 0; font-size: clamp(44px, 6.4vw, 92px); line-height: .98; letter-spacing: -.045em; font-weight: 750; }
.hc-cathead .lead { margin-top: 16px; max-width: 40em; }
.hc-cathead-n { margin: 12px 0 0; font-family: var(--font-mono); font-size: 14px; font-weight: 600; color: var(--slate); }
.hc-search.hc-search-topic { max-width: 560px; margin: 24px 0 0; }
.hc-search-topic input {
  padding: 14px 18px 14px 46px; border-radius: 14px; box-shadow: none;
  background: var(--white) no-repeat 17px 50% / 18px 18px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%238A9BB5' stroke-width='1.8' stroke-linecap='round'%3E%3Ccircle cx='8.5' cy='8.5' r='5.5'/%3E%3Cpath d='m13 13 4 4'/%3E%3C/svg%3E");
}
.hc-listing { padding-top: 0; }

/* ---- An article's head: the big headline, no picture ----------------------- */
.hc-article-head.hc-head-plain { background: var(--white); border-bottom: 1px solid var(--cloud); padding: clamp(28px, 3.6vw, 48px) 0 clamp(22px, 2.6vw, 34px); }
.hc-head-plain h1 { margin: 16px 0 0; font-size: clamp(36px, 5vw, 62px); line-height: 1.04; letter-spacing: -.035em; max-width: 16em; text-wrap: balance; }
.hc-head-plain .lead { margin-top: 16px; max-width: 40em; }
.hc-head-plain .hc-meta { margin-top: 12px; }
/* The article follows the head closely; the head's hairline is the break. */
.hc-head-plain + .sec { padding-top: clamp(32px, 4vw, 56px); }

@media (max-width: 760px) {
  .hc-rows.is-pair { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 720px) {
  .hc-topic { grid-template-columns: 96px minmax(0, 1fr) 20px; gap: 4px 16px; align-items: start; }
  .hc-topic-shot { grid-row: 1 / span 3; border-radius: 10px; }
  .hc-topic-name { font-size: 22px; align-self: start; }
  .hc-topic-desc { font-size: 14.5px; }
  .hc-topic-count { grid-column: 2; grid-row: auto; font-size: 13px; }
  .hc-topic-arrow { grid-column: 3; grid-row: 1; font-size: 20px; }
  .hc-tile { width: 128px; }
}
@media (max-width: 560px) {
  .hc-row { grid-template-columns: 36px minmax(0, 1fr) 20px; gap: 4px 12px; }
  .hc-row.no-num { grid-template-columns: minmax(0, 1fr) 20px; }
  .hc-row-title { font-size: 19px; }
  .hc-row-desc { font-size: 15px; }
}
@media (prefers-reduced-motion: reduce) {
  .hc-topic-shot img, .hc-topic-name, .hc-topic-arrow, .hc-row-title, .hc-row-arrow { transition: none; }
}
