/* BlackSnow Intelligence — marketing site (blacksnowintel.com mock)
   Brand: Electric Blue #2563EB · Deep Navy #0B1220 · Light Gray #F5F7FA · White (BSI brand guide).
   Red is the approved design's CTA colour only — it never carries data.
   Signal colours (frozen, V1-gated in the platform round) appear ONLY on signal surfaces:
   Adverse #d03b3b · Partial #fab219 · Strong #0ca30c · Neutral #3987e5 · Not Measured #898781,
   always paired with a glyph (never colour alone). No composite scores anywhere. */

/* THE PAGE MOVES WHEN THIS FONT ARRIVES, SO IT IS NEVER ALLOWED TO ARRIVE LATE.
   Inter is 344 KB and is fetched only once the sheet has parsed, which is around the time
   the first paint happens. Under `swap` the browser paints the whole page in the system
   face and then repaints it in Inter — and Inter is 14.9% wider than SF Pro Text and 4.4%
   wider than system-ui at the same size (measured, 17px, over the bar's own wording). So
   every line got wider a moment after it appeared: the nine items in the header bar all
   moved, headings re-wrapped, and the page settled a second time. That is one load, so it
   happened on every page, which is why it happened on every menu tab.

   `optional` ends it. The browser gives the file a short head start: if it wins, Inter is
   used from the first paint and nothing ever repaints; if it loses, the fallback is used
   for that whole load and Inter is NOT swapped in behind the reader's eyes. A late repaint
   is no longer one of the outcomes. The preload in shell.js starts the fetch earlier so it
   almost always wins, and in production the file is cached and always wins. */
@font-face {
  font-family: "Inter";
  src: url("assets/fonts/InterVariable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: optional;
}
/* The face the page uses when Inter loses that race. It is a local face with Inter's
   measurements written over it: not Inter, and not pretending to be, but occupying the same
   space, so a page set in it is laid out identically and nothing is in a different place.

   SF Pro is deliberately not named here. macOS will not hand its system face to local(),
   so naming it only adds a step that always fails. Helvetica Neue is what actually answers
   on a Mac and Arial is what answers on Windows, and the two are within 0.6% of each other,
   so one figure serves both: 103.4% is Inter's measured width over theirs at 17px across
   the header bar's own wording. The vertical figures are Inter's own — ascender 1984,
   descender 494, line gap 0, over 2048 units — so the line box matches as well as the
   line length does. */
@font-face {
  font-family: "Inter Fallback";
  src: local("Helvetica Neue"), local("Arial");
  size-adjust: 103.4%;
  ascent-override: 96.88%;
  descent-override: 24.12%;
  line-gap-override: 0%;
}

:root {
  /* The measure scale. Three numbers, and every capped block uses one of them. Before this
     the site carried eighteen different max-widths across twenty-nine pages, so the content
     edge could land at 760, 840, 880, 1040 and 1320 inside a single screen and the eye had
     nothing to track. Characters, not pixels, because the thing being limited is a line of
     text and a line is counted in characters. */
  --m-lede: 52ch;   /* a standfirst sitting beside a heading */
  --m-read: 74ch;   /* one column of body prose - the readable maximum */
  --m-wide: 1080px; /* lists, callouts, tables: read in fragments, not in lines */

  --bg0: #05070D;
  --bg1: #0B1220;
  --bg2: #101A2E;
  --well: #080F1B;
  --tx: #F5F7FA;
  --tx2: #A9B4C8;
  --tx3: #71809A;
  --line: rgba(245, 247, 250, 0.09);
  --line2: rgba(245, 247, 250, 0.17);
  --acc: #2563EB;
  --acc2: #3B75F1;
  --acc-wash: rgba(37, 99, 235, 0.14);
  --focus: #6AA1FF;
  --red: #D8222F;
  --red2: #BB1B26;
  --lt-bg: #F5F7FA;
  --lt-pale: #E9EEF5;
  --lt-card: #FFFFFF;
  --lt-tx: #0B1220;
  --lt-tx2: #46536E;
  --lt-tx3: #8792A6;
  --lt-line: rgba(11, 18, 32, 0.10);
  --lt-line2: rgba(11, 18, 32, 0.18);
  --sr: #d03b3b;
  --sa: #fab219;
  --sg: #0ca30c;
  --sb: #3987e5;
  --sy: #898781;
  /* BRAND — the identity blue, sampled from the mark itself. The logo's blue is a
     gradient (hue 200-223 at full chroma), so there is no single flat hex in the
     artwork; --bsi-blue is the centre of that ramp and the other two are the steps
     that clear 4.5:1 on the surfaces each theme actually puts them on:
       ink  on --lt-bg #F5F7FA 4.86:1   ·   lift on --bg #0B1220 6.88:1
     ADDITIVE. --sb above is the blue diamond Consistent BAND and does not move —
     a brand blue a few degrees away from a band colour on a data surface is exactly
     the ambiguity the five-colour rule exists to prevent, so --bsi-accent is used
     for brand chrome and focus only, never to colour a value. */
  --bsi-blue: #0079fa;
  --bsi-blue-ink: #006adb;
  --bsi-blue-lift: #4d9fff;
  --bsi-accent: var(--bsi-blue-lift);
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 18px;
}

* { box-sizing: border-box; }
html {
  /* NOT smooth. Nine of the menu items are anchors on a page — the Solutions list and the
     Research list — so with smooth scrolling every one of them slid the page under the fixed
     bar instead of arriving at it, which is the writing under the bar dropping or rising.
     scroll-padding-top still keeps the target clear of the bar; it just gets there in one
     frame. */
  scroll-behavior: auto;
  /* Exactly the fixed header's height (.hd-in 72px + 1px border). scroll-padding
     here and scroll-margin on the target ADD UP, so the offset lives in one place
     only — otherwise an anchor lands showing the tail of the previous section. */
  scroll-padding-top: 73px;
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  background: var(--bg0);
  color: var(--tx);
  font-family: Inter, "Inter Fallback", "SF Pro Text", -apple-system, system-ui, "Segoe UI", Arial, sans-serif;
  font-size: 17px;
  line-height: 1.65;
  font-feature-settings: "tnum";
}
img { max-width: 100%; display: block; }
a { color: inherit; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; padding: 0; }
h1, h2, h3, h4 { margin: 0; font-weight: 700; letter-spacing: -0.015em; }
p { margin: 0 0 18px; }
ul { margin: 0; padding: 0; list-style: none; }
/* No scroll-margin here — the offset is scroll-padding-top on html alone. */
/* 1320, up from 1200. On a 1512px laptop the old cap left 312px of empty gutter and then
   capped the text inside it AGAIN at 780–990px, so a heading used ~52% of the screen while
   the card grid beside it used 76%. Two nested caps is what made the page read as half
   empty. The container widens here; the per-block caps below are the other half of the fix. */
.wrap { max-width: 1320px; margin-inline: auto; padding-inline: 28px; }
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--acc); color: #fff; padding: 10px 18px; border-radius: 0 0 10px 0;
  font-weight: 600; text-decoration: none;
}
.skip:focus { left: 0; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 4px; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 13px 22px; border-radius: var(--r-sm);
  font-weight: 600; font-size: 15px; line-height: 1.2;
  text-decoration: none; border: 1px solid transparent;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
  white-space: nowrap;
}
.btn svg { flex: none; }
.btn.red { background: var(--red); color: #fff; }
.btn.red:hover { background: var(--red2); transform: translateY(-1px); }
.btn.ghost { border-color: var(--line2); color: var(--tx); }
.btn.ghost:hover { border-color: var(--tx3); background: rgba(245, 247, 250, 0.05); }
.btn.blue { background: var(--acc); color: #fff; }
.btn.blue:hover { background: var(--acc2); }
.sec-light .btn.ghost, .sec-pale .btn.ghost { border-color: var(--lt-line2); color: var(--lt-tx); }
.sec-light .btn.ghost:hover, .sec-pale .btn.ghost:hover { background: rgba(11, 18, 32, 0.05); }
.linkline {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--acc2); font-weight: 600; font-size: 15px; text-decoration: none;
}
.linkline:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- header ---------- */
.hd {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  /* Solid #000, no transparency and no backdrop-filter: the logo asset is an
     opaque black plate, so anything showing through the bar makes its edges
     visible as the page scrolls under it. */
  background: #000;
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease;
}
.hd.scrolled { border-bottom-color: var(--line); }
.hd-in { display: flex; align-items: center; gap: 22px; height: 72px; }
.hd-logo { flex: none; display: flex; align-items: center; text-decoration: none; }
.hd-logo img { height: 44px; width: auto; }
/* The bar carries nine destinations inside a content column capped at 1200px, so the
   spacing is measured rather than chosen: logo + nav + actions need 1,152px at these
   values, leaving 48px of slack. At the previous 13px padding / 6px offset it needed
   1,206px, which is why two entries — BSI Calculator and About Us — were silently
   folding onto a second line rather than overflowing where a check could see them. */
.hd-nav { display: flex; align-items: center; gap: 0; margin-left: 0; }
.nav-a {
  display: inline-flex; align-items: center; gap: 6px;
  /* A menu entry never wraps. Wrapping is how a bar that does not fit hides the fact:
     the width still measures inside its container while the words break in half. */
  white-space: nowrap;
  padding: 9px 11px; border-radius: 9px;
  color: var(--tx2); font-size: 14.5px; font-weight: 500; text-decoration: none;
  transition: color 0.15s ease, background 0.15s ease;
}
.nav-a:hover { color: var(--tx); background: rgba(245, 247, 250, 0.06); }
.nav-a.is-active { color: var(--tx); background: var(--acc-wash); box-shadow: inset 0 -2px 0 var(--acc2); }
/* The two entries on the bar that give something away rather than asking for something.
   Marked by ink alone: full-strength white against the muted grey every other entry
   wears, so they read as the bright pair without anything being drawn around them.
   THEY CARRIED A 1px RING UNTIL 2026-08-25 AND IT WAS WRONG. A box around a menu word
   reads as a button, so the bar looked like two buttons wearing menu labels sitting in
   a row of links — and on this page's own entry the ring landed on top of the active
   wash and the active underline, three marks on one word. Nothing on a nav bar is
   outlined now; weight and colour carry it, and hover is the only state that paints. */
.nav-a.is-free { color: var(--tx); }
.nav-a.is-free:hover { background: var(--acc-wash); }
.nav-a .caret { transition: transform 0.15s ease; opacity: 0.65; }
.nav-dd { position: relative; }
.nav-dd.open > .nav-a { color: var(--tx); background: rgba(245, 247, 250, 0.06); }
.nav-dd.open > .nav-a .caret { transform: rotate(180deg); }
.dd {
  position: absolute; top: calc(100% + 10px); left: 0; min-width: 288px;
  background: #0C1424; border: 1px solid var(--line2); border-radius: var(--r-md);
  padding: 8px; box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  display: none; z-index: 110;
}
.nav-dd.open .dd { display: block; }
.dd::before { content: ""; position: absolute; left: -8px; right: -8px; top: -14px; height: 14px; }
.dd a {
  display: block; padding: 10px 12px; border-radius: 10px; text-decoration: none;
}
.dd a:hover { background: var(--acc-wash); }
.dd .t { display: block; font-size: 14px; font-weight: 600; color: var(--tx); }
.dd .s { display: block; font-size: 12.5px; color: var(--tx3); margin-top: 1px; }
.hd-act { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.hd-act .btn { padding: 10px 16px; font-size: 14px; }
.hd-burger {
  display: none; width: 42px; height: 42px; border-radius: 10px;
  border: 1px solid var(--line2); align-items: center; justify-content: center;
}
.hd-burger svg { display: block; }
.hd-burger .ic-x { display: none; }
.nav-open .hd-burger .ic-x { display: block; }
.nav-open .hd-burger .ic-menu { display: none; }

/* ---------- section shells ---------- */
/* THE PAGE'S BLOCK RHYTHM, AND IT IS THE ONLY PLACE IT IS SET. Top and bottom padding both
   land between two blocks, so this number is really half of what a reader sees: at the old 104
   a block boundary was 208px of nothing, which at a 900px-tall screen is most of a screen
   spent on a gap. 68 keeps the blocks obviously separate and gives that space back to the
   content. Anything with its own composition overrides it — see .obs. */
.sec { padding: 68px 0; }
.sec-dark { background: var(--bg0); }
.sec-navy { background: var(--bg1); }
.sec-light { background: var(--lt-bg); color: var(--lt-tx); }
.sec-pale { background: var(--lt-pale); color: var(--lt-tx); }
.sec-light p, .sec-pale p { color: var(--lt-tx2); }
.sec-dark p, .sec-navy p { color: var(--tx2); }
.eyebrow {
  display: inline-block; margin-bottom: 16px;
  font-size: 12px; font-weight: 600; letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--acc2);
}
.sec-light .eyebrow, .sec-pale .eyebrow { color: var(--acc); }
.h2 { font-size: clamp(30px, 3.6vw, 45px); line-height: 1.12; max-width: 26em; }
.h2 + .sub { margin-top: 18px; }
.lead { font-size: 19px; }

/* Section head as a masthead band, not a narrow left column.
   It was a single 780px block inside a 1200px wrap, so every section opened with 420px of
   dead space to the right of the heading and then a card grid underneath that used the full
   measure — the mismatch is what read as "not using the screen". Heading and lede now sit
   side by side and fill the band, bottoms aligned, and each keeps a sane line length:
   ~55 characters of heading, ~48 of lede. A sechead with no lede falls back to a plain
   block, because a lone heading in a 1.75fr column would just recreate the empty half. */
/* Was 52, which stacked on top of the block padding above it — a heading could sit 156px
   clear of the thing it introduces. A heading belongs near its content. */
.sechead { margin-bottom: 34px; display: grid; grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr); column-gap: 64px; align-items: start; }
.sechead .eyebrow { grid-column: 1 / -1; }
.sechead .h2 { grid-column: 1; max-width: none; }
.sechead .sub { grid-column: 2; margin: 0; padding-top: 7px; }
.sechead:not(:has(> .sub)), .sechead.center { display: block; max-width: 900px; }
.sechead.center { margin-inline: auto; text-align: center; }
.strongline { color: var(--tx); font-weight: 600; }
.sec-light .strongline, .sec-pale .strongline { color: var(--lt-tx); }

/* ---------- the measure, and the other half of the .wrap fix ----------
   The container was widened to 1320 and the section heads were put side by side, and the
   note at .wrap says the per-block caps are the rest of the job. This is that rest. A run
   of body copy still stopped at 760-880px inside a 1264px band, so a reader coming off a
   full-width card grid met four paragraphs with a third of the screen empty beside them —
   the same "half empty" reading the wrap fix was aimed at, one level further in.

   Widening the paragraph is not the answer: past about 75 characters the eye loses the
   start of the next line on the way back to the left margin, so a 1264px line is worse to
   read than an 840px one, not better. The run fills the band in two measures instead, which
   is what a newspaper does with the same problem. Below 1180px there is no room for two, so
   it folds back to one and keeps the cap it always had. */
.runon { columns: 2; column-gap: 68px; }
.runon > * { max-width: none; }
.runon > :first-child { margin-top: 0; }
/* A list is a unit — split across a column break its numbers read as two lists. */
.runon > ol, .runon > ul, .runon > .callout { break-inside: avoid; }
@media (max-width: 1180px) {
  .runon { columns: 1; }
  .runon > * { max-width: var(--m-read); }
}

/* A lone block with nothing beside it: no run to set in two columns, so it takes the
   fragment measure rather than the reading one. Lists and callouts are read a line at a
   time, so the 75-character limit does not bind them the way a paragraph is bound. */
.wide { max-width: var(--m-wide); }

/* A run that contains a list does not belong in .runon — CSS columns balance by height, so
   an unbreakable list drops to one side and leaves a hole under the other. Put the prose in
   one column and the list in the other and both read top to bottom, which is how a set of
   numbered steps is meant to be read anyway. */
.proselist { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 68px; align-items: start; }
.proselist > .proselist-a > :first-child, .proselist > .proselist-b > :first-child { margin-top: 0; }
@media (max-width: 1180px) {
  .proselist { display: block; }
  .proselist > div > * { max-width: var(--m-read); }
}

/* ---------- hero ---------- */
.hero {
  position: relative; overflow: hidden;
  padding: 168px 0 96px;
  background:
    radial-gradient(720px 420px at 82% 8%, rgba(37, 99, 235, 0.16), transparent 65%),
    radial-gradient(560px 380px at 8% 92%, rgba(37, 99, 235, 0.07), transparent 60%),
    var(--bg0);
}
.hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(circle at 1px 1px, rgba(245, 247, 250, 0.05) 1px, transparent 1.6px);
  background-size: 26px 26px;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 72%);
  mask-image: linear-gradient(180deg, #000 0%, transparent 72%);
}
.hero .wrap { position: relative; display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr); gap: 56px; align-items: center; }
.hero h1 { font-size: clamp(40px, 4.6vw, 63px); line-height: 1.05; letter-spacing: -0.022em; }
.hero .lead { margin-top: 26px; }
.hero .invest { color: var(--tx); font-weight: 600; }

/* ---------- page masthead (every page except Home) ---------- */
.phero {
  position: relative; overflow: hidden;
  padding: 150px 0 66px;
  background:
    radial-gradient(760px 380px at 80% 6%, rgba(37, 99, 235, 0.15), transparent 66%),
    var(--bg0);
  border-bottom: 1px solid var(--line);
}
.phero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(circle at 1px 1px, rgba(245, 247, 250, 0.05) 1px, transparent 1.6px);
  background-size: 26px 26px;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 78%);
  mask-image: linear-gradient(180deg, #000 0%, transparent 78%);
}
/* Same band treatment as .sechead. Every page masthead is exactly eyebrow + h1 + lede, so
   the two-column split is safe across all eight of them. */
.phero .wrap { position: relative; display: grid; grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr); column-gap: 64px; align-items: start; }
.phero .eyebrow { grid-column: 1 / -1; }
.phero h1 { grid-column: 1; font-size: clamp(34px, 3.9vw, 52px); line-height: 1.08; letter-spacing: -0.02em; }
.phero .lead { grid-column: 2; margin: 0; padding-top: 8px; color: var(--tx2); }
.cta-row { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 32px; }
.trust { display: flex; flex-wrap: wrap; gap: 10px 26px; margin-top: 34px; }
.trust li { display: inline-flex; align-items: center; gap: 9px; font-size: 13.5px; color: var(--tx3); font-weight: 500; }
.trust svg { color: var(--acc2); flex: none; }

/* ---------- hero chain panel ---------- */
.chainpanel {
  margin: 0; min-width: 0;
  background: linear-gradient(180deg, #0D1628, #0A111F);
  border: 1px solid var(--line2); border-radius: var(--r-lg);
  box-shadow: 0 36px 90px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(245, 247, 250, 0.06);
  padding: 20px 22px 16px;
}
.cp-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
.cp-title { font-size: 12px; font-weight: 600; letter-spacing: 0.13em; text-transform: uppercase; color: var(--tx2); }
.tag {
  display: inline-block; padding: 3px 9px; border-radius: 999px;
  border: 1px solid var(--line2); color: var(--tx3);
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  white-space: nowrap;
}
.cp-chain { display: flex; align-items: stretch; gap: 4px; }
.cp-node { flex: 1 1 0; min-width: 0; text-align: center; }
.cp-hex { display: flex; justify-content: center; margin-bottom: 7px; color: var(--acc2); }
.cp-kind { display: block; font-size: 9px; font-weight: 600; letter-spacing: 0.09em; text-transform: uppercase; color: var(--tx3); }
.cp-name { display: block; font-size: 11px; font-weight: 600; color: var(--tx); margin-top: 2px; line-height: 1.3; }
.cp-arrow { align-self: center; color: var(--tx3); flex: none; padding-bottom: 26px; }
.cp-grid {
  display: grid; grid-template-columns: 1fr 1.05fr 1.25fr; gap: 14px;
  border-top: 1px solid var(--line); margin-top: 18px; padding-top: 16px;
}
.cp-cell h3 { font-size: 10.5px; font-weight: 600; letter-spacing: 0.11em; text-transform: uppercase; color: var(--tx3); margin-bottom: 10px; }
.cp-facts li { display: flex; align-items: baseline; gap: 7px; font-size: 12px; color: var(--tx2); padding: 3px 0; }
.cp-facts b { color: var(--tx); font-weight: 700; font-size: 13px; }
.cp-facts li::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--acc2); flex: none; align-self: center; }
.cp-bars li { display: block; padding: 2.5px 0 5px; }
.cp-bars .bl { display: block; font-size: 11px; color: var(--tx2); white-space: nowrap; margin-bottom: 4px; }
.cp-bars .bar { display: block; height: 7px; border-radius: 4px; background: rgba(245, 247, 250, 0.07); overflow: hidden; }
.cp-bars .bar i { display: block; height: 100%; border-radius: 4px; background: linear-gradient(90deg, var(--acc), var(--acc2)); }
.cp-snap { display: flex; align-items: center; gap: 14px; }
.cp-donut { flex: none; position: relative; }
.cp-donut .ctr { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; }
.cp-donut .ctr b { font-size: 17px; font-weight: 700; line-height: 1; }
.cp-donut .ctr span { display: block; max-width: 58px; line-height: 1.35; font-size: 9px; color: var(--tx3); letter-spacing: 0.08em; text-transform: uppercase; }
.cp-legend { min-width: 0; }
.cp-legend li { display: flex; align-items: center; gap: 7px; font-size: 11px; color: var(--tx2); padding: 2px 0; white-space: nowrap; }
.cp-legend .g { width: 13px; text-align: center; flex: none; font-size: 10px; }
.cp-legend b { color: var(--tx); margin-left: auto; padding-left: 10px; }
.cp-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  border-top: 1px solid var(--line); margin-top: 16px; padding-top: 13px;
  font-size: 12px; color: var(--tx3);
}
.cp-foot a { color: var(--acc2); font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; gap: 6px; }
.cp-foot a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* signal glyph colours (dark surfaces) — glyph + word always together */
.g-r { color: var(--sr); } .g-a { color: var(--sa); } .g-g { color: var(--sg); }
.g-b { color: var(--sb); } .g-y { color: var(--sy); }

/* ---------- section 2: the field ---------- */
.field-grid { display: grid; grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr); gap: 60px; align-items: center; }
.fieldbox { position: relative; aspect-ratio: 560 / 470; min-width: 0; }
.fieldbox .flines { position: absolute; inset: 0; width: 100%; height: 100%; }
.fieldbox .flines line { stroke: var(--line2); stroke-dasharray: 2 4; }
.fcenter {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 128px; height: 128px; border-radius: 26px;
  display: grid; place-content: center;
  background: radial-gradient(closest-side, rgba(37, 99, 235, 0.22), rgba(37, 99, 235, 0.02) 78%);
}
/* logo-mark-alpha.png is keyed transparent, so it needs no blend. The source
   logo-mark.png sits on a white plate, and screen cannot hide white — only
   black — which is what put a white square behind the mark. */
.fcenter img { width: 104px; height: 104px; object-fit: contain; filter: drop-shadow(0 0 24px rgba(37, 99, 235, 0.45)); }
.fnode { position: absolute; max-width: 168px; }
.fnode .fdot {
  display: block; width: 10px; height: 10px; border-radius: 50%;
  background: var(--bg0); border: 2px solid var(--acc2);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.14);
  margin-bottom: 8px;
}
.fnode h3 { font-size: 14px; font-weight: 600; }
.fnode p { font-size: 12.5px; color: var(--tx3); margin: 2px 0 0; line-height: 1.45; }
.fnode.r { text-align: right; }
.fnode.r .fdot { margin-left: auto; }
.callout {
  margin-top: 64px; padding: 30px 34px;
  background: var(--bg2); border: 1px solid var(--line); border-left: 3px solid var(--acc);
  border-radius: var(--r-md);
  font-size: clamp(19px, 2vw, 24px); line-height: 1.45; font-weight: 500; color: var(--tx2);
  max-width: 1080px;
}
.callout b { color: var(--tx); font-weight: 700; }

/* ---------- section 3: the problem ---------- */
.prob-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 24px 56px; }
.flowart { margin: 46px 0 40px; }
.scrollx { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.scrollx svg { min-width: 880px; width: 100%; height: auto; display: block; }
.reconstruct { font-size: 20px; font-weight: 600; color: var(--lt-tx); margin: 8px 0 0; }
/* 34, matching .sechead, because these two margins collapse and the larger one wins — at 52
   this component silently reinstated the old heading gap on the three blocks that use it, so
   the page had two different heading-to-content distances. */
.quote {
  margin: 34px 0 0; padding: 34px 38px 30px;
  background: var(--lt-card); border: 1px solid var(--lt-line); border-radius: var(--r-lg);
  box-shadow: 0 18px 50px rgba(11, 18, 32, 0.07);
  position: relative;
}
.quote::before {
  content: "\201C"; position: absolute; top: 6px; left: 22px;
  font-size: 74px; line-height: 1; color: var(--acc); opacity: 0.85; font-weight: 800;
}
.quote p { margin: 0; padding-left: 46px; font-size: 19px; line-height: 1.6; color: var(--lt-tx); font-weight: 500; }
.quote-by {
  padding-left: 46px; margin: 18px 0 0; display: flex; flex-wrap: wrap;
  align-items: baseline; gap: 4px 10px;
}
.qb-name { font-size: 16px; font-weight: 700; color: var(--lt-tx); }
.qb-name::before { content: "\2014\00a0"; color: var(--lt-tx3); font-weight: 500; }
.qb-role { font-size: 15px; color: var(--lt-tx2); }
@media (max-width: 640px) {
  .quote p, .quote-by { padding-left: 0; }
}

/* ---------- section 4: the key question ---------- */
.qcall {
  margin: 30px 0 38px; padding: 28px 32px;
  background: var(--bg2); border: 1px solid var(--line2); border-radius: var(--r-md);
  font-size: clamp(19px, 2.1vw, 25px); font-weight: 600; line-height: 1.45; color: var(--tx);
  max-width: 1080px;
}
.qcall span { color: var(--acc2); }
.becomes { max-width: var(--m-wide); margin-bottom: 34px; }
.becomes li {
  display: flex; align-items: baseline; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--line);
  font-size: 16.5px; color: var(--tx2);
}
.becomes li:last-child { border-bottom: 0; }
.becomes svg { flex: none; color: var(--acc2); align-self: center; }
.becomes b { color: var(--tx); font-weight: 600; }
.pillars { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin: 40px 0 34px; }
.pillar { background: var(--bg2); border: 1px solid var(--line); border-radius: var(--r-md); padding: 24px; }
.pillar .num { font-size: 11px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--acc2); }
.pillar h3 { font-size: 21px; margin: 8px 0 8px; }
.pillar p { font-size: 14.5px; color: var(--tx3); margin: 0; }
/* A pillar is a dark card and keeps dark-surface ink even inside a light section. Without
   this its h3 inherits the section's near-black (#0b1220) and lands on the card's navy
   (#101a2e) at about 1.05:1 — a heading nobody can read. */
.sec-light .pillar, .sec-pale .pillar { color: var(--tx); }
.sec-light .pillar h3, .sec-pale .pillar h3 { color: var(--tx); }
.exposure-line { font-size: 19px; font-weight: 600; color: var(--tx); }

/* ---------- section 5: method ---------- */
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 8px; }
.step {
  position: relative; background: var(--lt-card); border: 1px solid var(--lt-line);
  border-radius: var(--r-md); padding: 26px 22px 24px;
  box-shadow: 0 14px 40px rgba(11, 18, 32, 0.06);
}
.step .icon {
  width: 52px; height: 52px; display: grid; place-content: center;
  color: var(--acc); margin-bottom: 16px;
}
.step .n { position: absolute; top: 20px; right: 22px; font-size: 26px; font-weight: 700; color: var(--acc); opacity: 0.22; }
.step h3 { font-size: 17.5px; margin-bottom: 8px; }
.step p { font-size: 14px; color: var(--lt-tx2); margin: 0; line-height: 1.6; }
.method-line { text-align: center; margin-top: 46px; font-size: 18px; font-weight: 600; color: var(--lt-tx); }
.method-line span { border-bottom: 3px solid var(--acc); padding-bottom: 6px; }

/* ---------- section 6: inconsistencies ---------- */
.incon-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 56px; align-items: start; }
.maylist li {
  position: relative; padding: 13px 0 13px 26px;
  border-bottom: 1px solid var(--line); font-size: 16px; color: var(--tx2);
}
.maylist li:last-child { border-bottom: 0; }
.maylist li::before {
  content: ""; position: absolute; left: 2px; top: 22px;
  width: 8px; height: 8px; border: 2px solid var(--acc2); border-radius: 2px; transform: rotate(45deg);
}
.docdemo { display: grid; gap: 12px; }
.doccard {
  background: var(--bg2); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 18px 20px;
}
.doccard .dh { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.doccard .dt { font-size: 11px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--tx3); display: inline-flex; align-items: center; gap: 8px; }
.doccard .dt svg { color: var(--acc2); }
.doccard p { margin: 0; font-size: 15px; color: var(--tx); }
.doccard.finding { border-color: rgba(250, 178, 25, 0.35); background: linear-gradient(180deg, rgba(250, 178, 25, 0.06), rgba(250, 178, 25, 0.02)), var(--bg2); }
.doccard.finding p { color: var(--tx2); font-size: 14.5px; }
.doccard.finding .verdict { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 15.5px; color: var(--tx); margin-bottom: 7px; }
.vs { text-align: center; font-size: 11px; font-weight: 600; letter-spacing: 0.14em; color: var(--tx3); }
.incon-close { margin-top: 44px; max-width: 1040px; }
.clarify {
  margin-top: 26px; padding: 24px 28px;
  border: 1px solid var(--line2); border-left: 3px solid var(--acc); border-radius: var(--r-md);
  background: rgba(37, 99, 235, 0.05);
}
.clarify .cl-k { font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--acc2); display: block; margin-bottom: 8px; }
.clarify p { margin: 0; font-size: 15.5px; color: var(--tx2); }
.clarify b { color: var(--tx); }

/* ---------- section 7: map ---------- */
.map-grid { display: grid; grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.55fr); gap: 48px; align-items: start; }
.map-controls { display: flex; flex-wrap: wrap; gap: 10px 18px; margin: 26px 0 14px; }
.tgl { display: inline-flex; align-items: center; gap: 9px; font-size: 14px; color: var(--tx2); cursor: pointer; user-select: none; }
.tgl input { position: absolute; opacity: 0; width: 0; height: 0; }
.tgl .box {
  width: 18px; height: 18px; border-radius: 5px; border: 1.5px solid var(--line2);
  display: grid; place-content: center; color: transparent; transition: all 0.12s ease;
}
.tgl input:checked + .box { background: var(--acc); border-color: var(--acc); color: #fff; }
.tgl input:focus-visible + .box { outline: 2px solid var(--focus); outline-offset: 2px; }
.tgl .k { display: inline-flex; align-items: center; gap: 7px; }
.tgl .swatch { width: 22px; height: 0; border-top: 2.5px solid var(--acc2); border-radius: 2px; }
.tgl .swatch.dash { border-top-style: dashed; border-top-color: #8FC2FF; }
.map-caption { font-size: 13px; color: var(--tx3); }
.map-caption b { color: var(--tx2); }
.map-shell {
  background: var(--well); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 14px; position: relative; overflow: hidden;
}
.map-shell svg { width: 100%; height: auto; display: block; }
.jmap .cty { fill: #101A2E; stroke: #1B2740; stroke-width: 0.45; }
.jmap .cty.on { fill: rgba(37, 99, 235, 0.20); stroke: rgba(107, 154, 244, 0.65); stroke-width: 0.7; }
.jmap .arc { fill: none; stroke: #5B8DEF; stroke-width: 1.5; stroke-linecap: round; }
.jmap .arc.glow { stroke-width: 5.5; opacity: 0.13; }
.jmap .arc.flow { stroke-dasharray: 7 9; animation: arcflow 1.3s linear infinite; }
.jmap g[data-kind="ai"] .arc { stroke: #8FC2FF; }
.jmap g[data-kind="ai"] .arc.flow { stroke-dasharray: 2.5 7; }
.jmap .nd { fill: #EAF1FF; stroke: var(--acc2); stroke-width: 2; }
.jmap .nd-ring { fill: none; stroke: var(--acc2); opacity: 0.5; animation: ndpulse 2.4s ease-out infinite; transform-box: fill-box; transform-origin: center; }
.jmap .chip-bg { fill: rgba(11, 18, 32, 0.88); stroke: rgba(245, 247, 250, 0.22); rx: 6; }
.jmap .chip-role { fill: #F5F7FA; font-size: 10px; font-weight: 600; font-family: inherit; }
.jmap .chip-cty { fill: #A9B4C8; font-size: 8.6px; font-weight: 500; font-family: inherit; }
@keyframes arcflow { to { stroke-dashoffset: -16; } }
@keyframes ndpulse { 0% { transform: scale(0.6); opacity: 0.7; } 80% { transform: scale(1.9); opacity: 0; } 100% { opacity: 0; } }
.map-note { margin-top: 12px; font-size: 12.5px; color: var(--tx3); }
.support-line { margin-top: 22px; font-weight: 600; color: var(--tx); font-size: 16.5px; }

/* ---------- homepage: the three business uses ----------
   Three cards carrying ONE state. The band glyph and the band colour are identical in
   every column on purpose — the whole claim of the section is that a use changes the
   question and never the answer — so nothing here may key colour off the column. The
   glyph is always accompanied by its band word in ink, so identity is never colour
   alone, which also keeps Amber legible where #fab219 on white is not. */
.uses { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.use {
  display: flex; flex-direction: column;
  background: var(--lt-card); border: 1px solid var(--lt-line); border-radius: var(--r-md);
  padding: 20px 20px 18px; text-decoration: none;
  box-shadow: 0 14px 40px rgba(11, 18, 32, 0.06);
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.use:hover { transform: translateY(-3px); border-color: var(--acc); box-shadow: 0 22px 54px rgba(11, 18, 32, 0.10); }
.use-k { font-size: 19px; font-weight: 700; color: var(--lt-tx); letter-spacing: -0.01em; }
.use-w { font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--acc); margin-top: 7px; }
.use .use-q { font-size: 15.5px; color: var(--lt-tx); margin: 15px 0 0; font-style: italic; }
.use-state {
  display: inline-flex; align-items: center; gap: 8px; align-self: flex-start;
  margin: 15px 0 13px; padding: 6px 13px; border-radius: 999px;
  border: 1px solid var(--lt-line2); background: rgba(11, 18, 32, 0.03);
  font-size: 14px; font-weight: 700; color: var(--lt-tx);
}
.use-state span { font-size: 13px; }
.use > p:last-of-type { font-size: 13.5px; color: var(--lt-tx2); line-height: 1.55; margin: 0 0 16px; flex: 1; }
.use .linkline { font-size: 14px; margin-top: auto; }
.uses-foot { margin-top: 26px; font-size: 14.5px; max-width: var(--m-wide); }
.uses-foot .linkline { margin-left: 8px; font-size: 14.5px; }

/* ---------- section 8: the six layers ----------
   Three across, two rows. It was repeat(5, 1fr) for the five-product ladder; six layers
   in one row would be 190px of card, which is narrower than the vignette needs and puts
   the second half of the ladder off the right edge on a laptop. Two rows of three also
   reads the way the ladder actually splits: layers 1-3 are the public record, layers 4-6
   need evidence a client supplies. */
.prods { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.prod {
  display: flex; flex-direction: column;
  background: var(--lt-card); border: 1px solid var(--lt-line); border-radius: var(--r-md);
  padding: 14px 14px 18px;
  box-shadow: 0 14px 40px rgba(11, 18, 32, 0.06);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.prod:hover { transform: translateY(-3px); box-shadow: 0 22px 54px rgba(11, 18, 32, 0.10); }
.vig {
  height: 148px; border-radius: 10px; background: var(--bg1);
  border: 1px solid rgba(11, 18, 32, 0.14);
  padding: 12px; overflow: hidden; position: relative;
  color: var(--tx); font-size: 10px;
}
.prod h3 { font-size: 17px; margin: 15px 4px 7px; }
.prod > p { font-size: 13.5px; color: var(--lt-tx2); margin: 0 4px 14px; line-height: 1.55; flex: 1; }
.prod .linkline { margin: 0 4px; font-size: 14px; }
/* vignette primitives */
/* List vignettes are a fixed-height crop of a longer list, so the bottom edge
   fades rather than slicing a row of text in half. Only the list variants get
   this — the diagram vignettes draw right down to the edge. */
.vig.vg-crop::after, .vig.vg-feed::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 26px;
  background: linear-gradient(to bottom, rgba(11, 18, 32, 0), var(--bg1));
  pointer-events: none;
}
.vig .vg-row { display: flex; align-items: center; gap: 7px; padding: 4.5px 0; border-bottom: 1px solid rgba(245, 247, 250, 0.07); }
.vig .vg-row:last-child { border-bottom: 0; }
.vig .vg-sq { width: 18px; height: 18px; border-radius: 5px; background: var(--bg2); border: 1px solid var(--line2); display: grid; place-content: center; font-size: 8.5px; font-weight: 700; color: var(--tx2); flex: none; }
.vig .vg-ln { height: 6px; border-radius: 3px; background: rgba(245, 247, 250, 0.16); }
.vig .vg-glyphs { margin-left: auto; display: flex; gap: 4px; font-size: 8.5px; }
.vig .vg-search { display: flex; align-items: center; gap: 6px; border: 1px solid var(--line2); border-radius: 7px; padding: 5px 8px; color: var(--tx3); margin-bottom: 7px; }
.vig .vg-search .vg-ln { flex: 1; height: 5px; }
.vig .vg-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.vig .vg-title { font-size: 11.5px; font-weight: 700; color: var(--tx); }
.vig .vg-chip { font-size: 8px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; border: 1px solid var(--line2); border-radius: 999px; padding: 2px 7px; color: var(--tx3); }
.vig .vg-share { font-size: 20px; font-weight: 700; color: var(--tx); }
.vig .vg-share small { font-size: 9px; font-weight: 600; color: var(--tx3); display: block; letter-spacing: 0.07em; text-transform: uppercase; margin-top: 2px; }
.vig .vg-strip { display: flex; gap: 8px; margin-top: 10px; font-size: 9.5px; flex-wrap: wrap; }
.vig .vg-strip span { display: inline-flex; gap: 4px; align-items: center; color: var(--tx2); }
.vig .vg-bars5 { display: flex; height: 8px; border-radius: 4px; overflow: hidden; gap: 2px; margin-top: 10px; }
.vig .vg-bars5 i { display: block; height: 100%; }
/* vg-feed is a SECOND CLASS on the vignette, not a child of it (`class="vig vg-feed"`),
   so these were written as descendant selectors and matched nothing — the feed rows were
   rendering unstyled, dots included. Compounded, not nested. */
.vig.vg-feed { font-size: 9.5px; }
.vig.vg-feed .vg-row { gap: 8px; }
.vig.vg-feed .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--acc2); flex: none; }
.vig.vg-feed .t { color: var(--tx); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vig.vg-feed .s { color: var(--tx3); margin-left: auto; flex: none; }
.vig svg { display: block; }

/* Layer number, current state and evidence depth on each ladder card.
   The state chip is deliberately NEUTRAL and never a band colour: Live Now / By Request /
   By Engagement are stages of availability, not findings about an organisation, and the
   five band colours are reserved for findings. Only Layer 1 gets the accent treatment,
   because "free, and you can use it right now" is the one state a stranger acts on. */
.lay-h { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 15px 4px 0; }
.lay-n { font-size: 10.5px; font-weight: 700; letter-spacing: 0.11em; text-transform: uppercase; color: var(--acc); flex: none; }
.lay-s {
  font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  border: 1px solid var(--lt-line2); border-radius: 999px; padding: 3px 9px;
  color: var(--lt-tx2); background: rgba(11, 18, 32, 0.03); text-align: right;
}
.lay-s.now { border-color: var(--acc); color: var(--acc); background: rgba(59, 117, 241, 0.08); }
.prod .lay-h + h3 { margin-top: 8px; margin-bottom: 3px; }
.lay-d { display: block; font-size: 12px; font-weight: 600; color: var(--lt-tx2); margin: 0 4px 11px; }

/* LIVE, below the ladder. Copy leads because the claim is the point; the feed vignette is
   supporting, so it is capped rather than stretched to the height of the paragraphs. */
.livegrid { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 30px; align-items: start; }
.livecopy p { max-width: 56em; }
.livecopy .linkline { margin-top: 6px; }

/* ---------- section 9: audiences ---------- */
/* SIX COLUMNS FOR FIVE CARDS, BECAUSE THE CARDS ARE NOT ALL ONE CELL WIDE. Three at
   two columns fill the first row and two at three columns fill the second, so the
   section is two full rows with no card's width of nothing anywhere in it. On five
   columns the same spans laid out as 2+2, then 2+3, then a lone 3 — three ragged rows
   with 240px empty at the end of the first and 496px empty at the end of the last,
   which reads as a card that failed to load. tools/page-width-check.mjs measures the
   cells the spans actually occupy and holds this. */
.auds { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 16px; }
.aud { grid-column: span 2; }
/* Exactly five cards: the last two widen to thirds so the final row fills the
   measure instead of leaving an orphan gap on the right. */
.aud:nth-child(4):nth-last-child(2),
.aud:nth-child(4):nth-last-child(2) ~ .aud { grid-column: span 3; }
.aud {
  background: var(--lt-card); border: 1px solid var(--lt-line); border-radius: var(--r-md);
  padding: 28px 26px;
}
.aud h3 { font-size: 19px; margin-bottom: 9px; }
.aud p { font-size: 14.5px; color: var(--lt-tx2); margin: 0; }
.aud .k { display: inline-block; width: 34px; height: 3px; border-radius: 2px; background: var(--acc); margin-bottom: 18px; }

/* ---------- section 10: research ---------- */
.res-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 56px; align-items: start; }
.res-copy .engine { font-size: 19px; font-weight: 600; color: var(--tx); margin-top: 6px; }
.res-links { display: flex; flex-wrap: wrap; gap: 18px 28px; margin-top: 28px; }
.stats { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.stat {
  background: var(--bg2); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 20px 22px;
}
.stat b { display: block; font-size: 33px; font-weight: 700; letter-spacing: -0.02em; }
.stat span { font-size: 12px; color: var(--tx3); letter-spacing: 0.09em; text-transform: uppercase; font-weight: 600; }
.stats-date { grid-column: 1 / -1; font-size: 12.5px; color: var(--tx3); text-align: right; }

/* The home page's live band. Same tile, three across in two rows, and each one
   goes somewhere — a number with nothing behind it is a dead end, and every figure
   here has a page that explains what it counted. grid-auto-rows: 1fr so the second
   row is the same height as the first: the labels are different lengths and without
   it the two rows sit at different heights for no reason a reader can see. */
.stats.band { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: 1fr; gap: 14px; }
a.stat { text-decoration: none; color: var(--tx); transition: border-color 0.15s ease, background 0.15s ease; }
a.stat:hover { border-color: var(--acc); background: var(--bg1); }

/* THE ICON SITS BESIDE THE WRITING, NOT ABOVE IT. Stacked, the glyph is a decoration
   the eye skips on its way to the number; beside it, the glyph and the figure are one
   object and the icon is what the eye lands on first. The tile is a two-column grid
   with the icon spanning both rows, so the number and its label stay a tight pair
   against a single chip rather than three separate lines. */
.stats.band .stat {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr);
  grid-template-areas: "icon num" "icon label";
  column-gap: 16px;
  align-items: center;
  align-content: center;
}
/* The icon is a span inside a tile whose spans are 12px uppercase labels, so every
   one of those inherited rules has to be turned off here or the chip inherits the
   label's letter-spacing and sits off-centre. */
.stats.band .stat .icon {
  grid-area: icon;
  display: grid; place-items: center;
  width: 58px; height: 58px; border-radius: 17px;
  background: var(--ic-bg); border: 1px solid var(--ic-line); color: var(--ic);
  margin: 0; font-size: 0; line-height: 0; letter-spacing: 0; text-transform: none;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.stats.band .stat .icon svg { width: 30px; height: 30px; }
.stats.band .stat b { grid-area: num; }
/* TWO LINES OF LABEL, RESERVED, WHETHER OR NOT THE SECOND ONE IS USED. The tiles are
   centred, so a tile whose label wraps has a taller content block and its figure rides
   about half a line higher than the figures either side of it. Reserving the second line
   puts every content block on the same height, and the six numbers sit on one line. */
.stats.band .stat > span:not(.icon) { grid-area: label; display: block; margin-top: 3px; min-height: 38px; }
a.stat:hover .icon { background: var(--ic-line); border-color: var(--ic); }

/* SIX HUES, AND NOT ONE OF THEM GREEN, AMBER OR RED. Those three are the verdict
   colours everywhere else on this site, and a count is not a verdict — an Amber chip
   beside "28,974 Scans" would read as a warning about the number. So the band runs on
   a cool set plus pink, ordered so no two touching tiles share a neighbour's hue. */
.stats.band .stat:nth-child(1) { --ic: #4C8DFF; --ic-bg: rgba(76,141,255,0.14);  --ic-line: rgba(76,141,255,0.32); }
.stats.band .stat:nth-child(2) { --ic: #F472B6; --ic-bg: rgba(244,114,182,0.14); --ic-line: rgba(244,114,182,0.32); }
.stats.band .stat:nth-child(3) { --ic: #22D3EE; --ic-bg: rgba(34,211,238,0.14);  --ic-line: rgba(34,211,238,0.32); }
.stats.band .stat:nth-child(4) { --ic: #A78BFA; --ic-bg: rgba(167,139,250,0.14); --ic-line: rgba(167,139,250,0.32); }
.stats.band .stat:nth-child(5) { --ic: #38BDF8; --ic-bg: rgba(56,189,248,0.14);  --ic-line: rgba(56,189,248,0.32); }
.stats.band .stat:nth-child(6) { --ic: #C084FC; --ic-bg: rgba(192,132,252,0.14); --ic-line: rgba(192,132,252,0.32); }

/* The figures arrive after the page does. Reserving the line's height stops the band
   from growing by a row the moment the read lands and shoving the section below it. */
.stats.band .stat b { min-height: 40px; }
/* Not the standard .sec 104px. This is a band between two full sections, not a section
   of its own, and at 104px it stops reading as a strip under the hero and starts reading
   as a page the visitor has to scroll past. */
.livestats { padding: 56px 0 60px; }
.livestats .eyebrow { display: block; margin-bottom: 20px; }
.livestats .ls-foot { display: flex; gap: 28px; justify-content: space-between; align-items: baseline; margin-top: 18px; }
/* THE LEFT COLUMN IS A DIV, NOT THE NOTE ITSELF. The foot is a flex row of note-left,
   as-of-right, and the attempts line has to sit UNDER the note, not between it and the
   as-of. Wrapping both paragraphs in .ls-text keeps the row at two children, so the
   as-of stays on the note's first baseline exactly as it did with one paragraph.
   min-width: 0 so the column may shrink below its content width and the nowrap as-of
   never pushes the section wider than the viewport. */
.livestats .ls-text { min-width: 0; }
.livestats .note { font-size: 13.5px; color: var(--tx3); margin: 0; max-width: 74ch; }
/* THE ATTEMPTS LINE IS A LINE, NOT A SEVENTH TILE. Same voice as the note — size,
   colour, measure — with its two figures in the tile figures' colour (a.stat sets
   var(--tx); .stat b sets no colour of its own) so the eye reads them as counts of
   the same family, one row down. It is outside .stats.band on purpose: the band's
   hues stop at nth-child(6), tools/live-stats-check.mjs holds the band to six tiles,
   and a seventh grid child measures as two empty cells in page-width-check. */
.livestats .attempts { font-size: 13.5px; color: var(--tx3); margin: 0; margin-top: 10px; max-width: 74ch; }
.livestats .attempts a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--line); transition: border-color 0.15s ease; }
.livestats .attempts a:hover { border-color: var(--acc); }
.livestats .attempts b { color: var(--tx); font-weight: 700; }
.livestats .asof { font-size: 12.5px; color: var(--tx3); margin: 0; text-align: right; white-space: nowrap; flex: none; }
@media (max-width: 900px) {
  /* Two across, and rows size to their own content again. Equal-height rows are worth it
     at three across, where the six tiles read as one block; at two across they hand the
     tallest label's height to all three rows and leave a screen of empty tile below the
     short ones. */
  .stats.band { grid-template-columns: 1fr 1fr; grid-auto-rows: auto; }
  .stats.band .stat { grid-template-columns: 48px minmax(0, 1fr); column-gap: 13px; }
  .stats.band .stat .icon { width: 48px; height: 48px; border-radius: 14px; }
  .stats.band .stat .icon svg { width: 25px; height: 25px; }
  .livestats .ls-foot { display: block; }
  .livestats .asof { text-align: left; white-space: normal; margin-top: 12px; }
}
@media (max-width: 560px) {
  .stat { padding: 16px 16px; }
  .stat b { font-size: 27px; }
  /* ONE COLUMN, BECAUSE BESIDE NEEDS ROOM. At two across on a phone the chip eats a
     third of the tile and leaves the label about 70px to wrap an eight-word phrase
     into. One across gives the writing its full width and the band gets SHORTER, not
     taller, because the tiles stop being mostly wrapped text. */
  .stats.band { grid-template-columns: 1fr; }
  .stats.band .stat b { min-height: 34px; }
  /* One across gives every label its own full width, so nothing wraps and the reserved
     second line is 38px of nothing on all six tiles. */
  .stats.band .stat > span:not(.icon) { min-height: 0; }
}
.res-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; margin-top: 34px; }
.res-tiles.four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.res-tile {
  display: block; text-decoration: none;
  /* The tile carries a dark surface even inside .sec-light, so it must own its
     ink — otherwise the heading inherits the light section's dark text colour. */
  background: var(--bg1); color: var(--tx);
  border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 22px 24px; transition: border-color 0.15s ease, background 0.15s ease;
}
.res-tile:hover { border-color: var(--acc); background: var(--bg2); }
.res-tile .icon { color: var(--acc2); margin-bottom: 14px; }
.res-tile h3 { font-size: 16.5px; margin-bottom: 6px; color: var(--tx); }
.sec-light .res-tile p, .sec-pale .res-tile p { color: var(--tx3); }
.res-tile p { font-size: 13.5px; color: var(--tx3); margin: 0; }

/* ---------- section 11: closing CTA ---------- */
.cta-sec {
  position: relative; overflow: hidden;
  background:
    radial-gradient(640px 380px at 50% 0%, rgba(37, 99, 235, 0.14), transparent 68%),
    var(--bg0);
  border-top: 1px solid var(--line);
}
.cta-sec .wrap { max-width: 880px; text-align: center; }
.cta-sec .h2 { max-width: none; }
.cta-sec .cta-copy { margin-top: 24px; }
.litany { margin: 34px auto 38px; max-width: 420px; text-align: left; }
.litany li {
  padding: 9px 0 9px 26px; position: relative;
  font-size: 17px; font-weight: 500; color: var(--tx2);
  border-bottom: 1px solid var(--line);
}
.litany li:last-child { border-bottom: 0; color: var(--tx); font-weight: 600; }
.litany li::before {
  content: ""; position: absolute; left: 2px; top: 18px;
  width: 7px; height: 7px; border-radius: 50%; background: var(--acc2);
}
.cta-sec .cta-row { justify-content: center; }

/* ---------- footer ---------- */
/* 64px OF BOTTOM PADDING, NOT 30. The Trust Signals pill is fixed at bottom:18px and
   stands 36px tall, so it occupies a band 18px to 54px off the bottom of the viewport for
   as long as the page is open. At 30px the base line sat inside that band and the pill
   covered the copyright sentence on every page of the site, at every width — measured, not
   guessed. 64px puts the base line 10px clear of it. */
.ft { background: #070C16; border-top: 1px solid var(--line); padding: 64px 0 64px; }
/* SIX COLUMNS, because Legal & Trust became one of them. It was five, and the seven claim
   documents were reachable from the homepage and from each other and from nowhere else on
   the site. The gap paid for the extra track: at a 1,320px wrap the content box is 1,264px,
   so five gaps at 28 leave 1,124px for six tracks against the 1,120px that four gaps at 36
   left for five. The sixth column costs nothing at all, because the gap gave it back.

   THE FRACTIONS ARE THE MEASURED LABELS, NOT A GUESS. Every link was rendered with
   white-space:nowrap and its width read off the page: Platform needs 112px ("BSI
   Calculator"), Solutions 187px ("Technology Companies"), Company 214px ("The Second
   Balance Sheet"), Legal & Trust 184px ("Data Processing Terms"), and Stay Informed 226px
   for the mailto with its icon. The gap came down 36 -> 28 to buy that space back; the
   fractions are those five numbers plus 195 for
   the brand, divided by 100, so at full width every column is its own longest line plus a
   few pixels of slack.

   ONE LABEL STILL WRAPS AND IT IS MEANT TO. "The Second Balance Sheet" is an essay title
   at 214px; giving Company the width to hold it would take that width off Solutions and
   Legal, which each carry seven and eight links rather than one. It wrapped in the
   five-column footer too, so nothing about it is new here.

   min-width:0 on the children is what stops the mailto address — one long unbreakable
   token — from pushing the last track wider than its share and overflowing the footer at
   the narrow end of the six-column band. */
.ft-grid { display: grid; grid-template-columns: 1.95fr 1.18fr 1.92fr 1.9fr 1.9fr 2.39fr; gap: 28px; }
.ft-grid > * { min-width: 0; }
/* `mix-blend-mode: screen` used to live here and has been removed. It was a workaround for
   a logo file with a black rectangle baked in behind it — screen blending made the box
   disappear into a dark footer. The file is genuinely transparent now, so the blend has
   nothing left to hide and only does damage: it lightens every dark pixel of the artwork
   against whatever is behind it, which flattens the mark's outline. The header never had
   the hack, which is why the two logos rendered differently on the same page. */
.ft-brand img { height: 46px; width: auto; }
.ft-brand p { font-size: 13.5px; color: var(--tx3); margin: 16px 0 0; max-width: 240px; }
.ft h4 { font-size: 12px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--tx3); margin-bottom: 14px; }
.ft-col li { padding: 4.5px 0; }
.ft-col a { font-size: 14px; color: var(--tx2); text-decoration: none; }
.ft-col a:hover { color: var(--tx); }
.ft-stay p { font-size: 13.5px; color: var(--tx3); margin: 0 0 14px; }
.ft-stay .mailto { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; color: var(--tx2); text-decoration: none; margin-bottom: 16px; max-width: 100%; overflow-wrap: anywhere; }
.ft-stay .mailto:hover { color: var(--tx); }
.ft-stay .mailto svg { color: var(--acc2); }
/* THE SAME EIGHT DOCUMENTS, ON THE PAGES THAT HAVE NO SITE FOOTER.

   /self-check, /method and /my-list each carry a slim one-line footer instead of the
   six-column one, for reasons argued where those footers are built. This is that line's
   legal run: it flows as ordinary text so eight labels wrap across two or three lines on a
   phone rather than forcing a horizontal scroll, and the separator is an <i> carrying a
   middot with aria-hidden, so a screen reader announces eight links and not eight links
   with a dot between each pair. flex-basis:100% puts it on its own row beneath the rest of
   the line, because it is a list and the rest of that line is a sentence. */
.ft-legal-line { flex: 1 0 100%; margin-top: 4px; line-height: 1.9; }
/* AND THE FLOATING RECORD DOES NOT SIT ON TOP OF THEM. The Trust Signals pill is fixed at
   left:18px bottom:18px and stands 36px tall, so it occupies a band from 18px to 54px off
   the bottom of the viewport for as long as the page is open. The legal run is the last row
   of these slim footers, so that band was landing on Privacy Notice and Terms of Service —
   the first two links in it, and the two a reader is most likely to have come looking for.
   40px of bottom padding becomes 72px, which clears the band with 18px to spare.

   /my-list gets the padding without needing it: it does not load shell.js, so it has no
   pill to clear. Thirty-two pixels of whitespace is a smaller price than two .pc-foot pages
   that do not match each other. Higher specificity than .pc-foot in calc.css on purpose —
   site.css loads first, so a bare class would lose the cascade. */
footer.pc-foot, footer.mt-foot { padding-bottom: 72px; }
.ft-legal-line a { color: var(--tx3); text-decoration: none; }
.ft-legal-line a:hover { color: var(--tx); text-decoration: underline; }
.ft-legal-line i { font-style: normal; color: var(--line); margin: 0 2px; }
.ft-base {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px;
  border-top: 1px solid var(--line); margin-top: 48px; padding-top: 22px;
  font-size: 12.5px; color: var(--tx3);
}

/* The operator door. Quieter than a footer column link on purpose — it is for the handful
   of people who run this, not for a visitor, and dressing it up would advertise it. */
.ft-admin { color: var(--tx3); text-decoration: none; }
.ft-admin:hover { color: var(--tx2); text-decoration: underline; text-underline-offset: 3px; }
/* On the slim footers the door is pushed to the far end of the identity row, so it sits in
   the same place the site footer puts it instead of joining the run of legal documents. */
.ft-admin-slot { margin-left: auto; }
/* AND IT STAYS THE QUIETEST THING IN THE ROW ON THE METHOD PAGE TOO. That page styles its
   own footer links with `.mt-foot-in a { color: var(--tx2) }`, which outranks a bare
   `.ft-admin` on specificity — so the one link meant to recede was rendering LIGHTER than
   the text around it. Measured, not assumed: rgb(169,180,200) against neighbours at
   rgb(113,128,154). Two classes beat one class and one element, and nothing else on that
   page changes. */
.pc-foot-in .ft-admin,
.mt-foot-in .ft-admin { color: var(--tx3); }
.pc-foot-in .ft-admin:hover,
.mt-foot-in .ft-admin:hover { color: var(--tx2); }

/* ---------- modal ---------- */
.modal { position: fixed; inset: 0; z-index: 160; display: grid; place-items: center; padding: 24px; }
.modal[hidden] { display: none; }
.m-overlay { position: absolute; inset: 0; background: rgba(4, 6, 11, 0.68); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); }
.m-card {
  position: relative; width: min(460px, 100%);
  background: #0D1626; border: 1px solid var(--line2); border-radius: var(--r-lg);
  box-shadow: 0 40px 110px rgba(0, 0, 0, 0.6);
  padding: 30px 30px 26px;
}
.m-x {
  position: absolute; top: 14px; right: 14px; width: 36px; height: 36px;
  display: grid; place-content: center; border-radius: 9px; color: var(--tx3);
}
.m-x:hover { background: rgba(245, 247, 250, 0.07); color: var(--tx); }
.m-card h3 { font-size: 22px; margin-bottom: 8px; }
.m-card .m-sub { font-size: 14.5px; color: var(--tx2); margin: 0 0 20px; }
.m-view[hidden] { display: none; }
.m-field { margin-bottom: 14px; }
.m-field label { display: block; font-size: 12.5px; font-weight: 600; color: var(--tx2); margin-bottom: 6px; }
.m-field input {
  width: 100%; padding: 11px 13px; border-radius: 10px;
  background: var(--well); border: 1px solid var(--line2); color: var(--tx);
  font: inherit; font-size: 15px;
}
.m-field input:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; border-color: transparent; }
.m-note { font-size: 12px; color: var(--tx3); margin: 14px 0 18px; }
.m-note a { color: var(--acc2); text-decoration: none; }
.m-note a:hover { text-decoration: underline; }
.m-actions { display: flex; gap: 10px; }
.m-done-ic { width: 54px; height: 54px; border-radius: 50%; background: var(--acc-wash); color: var(--acc2); display: grid; place-content: center; margin-bottom: 16px; }

/* ---------- responsive ---------- */
@media (max-width: 1060px) {
  .hero .wrap { grid-template-columns: 1fr; gap: 48px; }
  /* The masthead and section-head bands stack here alongside every other two-column grid.
     Below this width the heading column is too narrow to hold a 52px headline without
     breaking it into four lines, which is worse than the stack. */
  .phero .wrap, .sechead { display: block; }
  .phero .lead { margin: 20px 0 0; padding-top: 0; max-width: 46em; }
  .sechead .sub { margin-top: 18px; padding-top: 0; }
  .chainpanel { max-width: 640px; }
  .field-grid, .incon-grid, .map-grid, .res-grid { grid-template-columns: 1fr; gap: 44px; }
  /* Stacks with the other two-column grids. The feed vignette truncates its rows, so a
     narrow second column would show five ellipses and say nothing. */
  .livegrid { grid-template-columns: minmax(0, 1fr); gap: 30px; }
  .livegrid .vig { max-width: 420px; }
  .steps { grid-template-columns: repeat(2, 1fr); }
  .res-tiles, .res-tiles.four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* The bar between the mobile breakpoint and a roomy laptop, where the content column is the
   window rather than the 1200px cap. It was ALREADY too wide here before the calculator was
   added — 1,092px of bar in a 1,024px window — which pushed Request Access off the right edge
   with no scrollbar to reach it, because .hd is fixed and fixed overflow does not extend the
   document. The sweep read documentElement.scrollWidth and so could never see it; site-sweep
   now measures .hd-in directly. Sign In steps off here rather than the bar getting tighter
   still: it only opens a modal saying access moves by correspondence, while Request Access —
   the action that actually does something — stays. Sized at 981px, the tightest desktop there
   is and the hardest case: 850px of bar inside 925px of content box, nothing wrapped and
   Request Access wholly on screen.

   THE BREAKPOINT MOVED FROM 1240px TO 1120px when Consulting left the bar for the Solutions
   menu. Eight entries needed 1,151px at full size; seven need 1,083px. Measured across ten
   window widths with the tightening switched off: the bar still fits at 1,090px with 7px to
   spare and overflows by 23px at 1,060px. So everything from 1,121px upwards can now carry
   the roomy bar — 14.5px type, 11px padding, and Sign In present — where before it was
   squeezed to 13px and Sign In disappeared. 1,120px rather than 1,090px because the number
   worth having is slack, not range: it leaves 38px of it at the boundary, which is enough to
   absorb a font falling back on a machine that is not this one.

   AND IT MOVED BACK TO 1240px ON 2026-08-25, when the Security Pet took the eighth place
   Consulting had vacated. The paragraph above is the whole argument for it: the breakpoint
   is a function of how many entries the bar carries, and it went to 1,120px because there
   were seven. There are eight again, and at 1,152px the untightened bar overflowed .hd-in
   by 48px with 22px of air left beside Request Access — the same failure, in the same
   place, that this block exists to prevent. Re-measured with tools/nav-width-check.mjs
   rather than reasoned about, because the last two times this number moved the measurement
   was taken and then thrown away, which is why it had to be taken again. */
@media (max-width: 1240px) {
  .hd-in { gap: 14px; }
  .nav-a { padding: 9px 6px; font-size: 13px; }
  .hd-act .js-signin { display: none; }
}
@media (max-width: 980px) {
  .hd-nav {
    /* absolute against the fixed header, which is its containing block; an
       inset box collapsed here, so top/left/right + an explicit height */
    position: absolute; top: 100%; left: 0; right: 0; height: calc(100vh - 73px); z-index: 105;
    display: none; flex-direction: column; align-items: stretch; gap: 2px;
    background: #000; padding: 18px 22px 40px; overflow: auto;
    border-top: 1px solid var(--line);
  }
  .nav-open .hd-nav { display: flex; }
  .nav-a { font-size: 17px; padding: 13px 12px; border-radius: 12px; }
  .nav-a.is-active { box-shadow: inset 2px 0 0 var(--acc2); }
  .nav-dd .dd { position: static; min-width: 0; box-shadow: none; border: 0; background: transparent; padding: 0 0 6px 14px; }
  .dd a { padding: 10px 12px; }
  .hd-burger { display: grid; }
  .nav-open { overflow: hidden; }
}
/* THE FOOTER LEAVES SIX COLUMNS AT 1,120px, WHICH IS EARLIER THAN THE REST OF THE PAGE.
   Measured, not chosen: at 1,024px the six tracks come out at 103px each and four labels
   wrap — including the mailto address, which cannot break cleanly. Three-up at that width
   gives each column about 333px, which is more than any label in the footer needs.

   THREE-UP, NOT TWO. With six blocks a two-up footer runs to three tall rows and puts the
   claim documents below the fold on a tablet, which is exactly where a buyer checking them
   is most likely to be reading. Three-up keeps it to two rows. */
@media (max-width: 1120px) {
  .ft-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 30px 28px; }
}
@media (max-width: 760px) {
  /* Below the desktop value now, not above it. This override predates the cut above and
     would otherwise give a phone MORE space between blocks than a 27-inch monitor. */
  .sec { padding: 52px 0; }
  .hero { padding: 138px 0 72px; }
  .phero { padding: 124px 0 52px; }
  .contact-litany { padding: 24px 22px 28px; }
  .prob-cols { grid-template-columns: 1fr; }
  .pillars { grid-template-columns: 1fr; }
  .prods { grid-template-columns: 1fr 1fr; }
  /* The three uses stack rather than shrink. Three 230px columns would wrap the band
     word onto two lines in one column and not the others, and the row's whole argument
     is that the three states are visibly identical. */
  .uses { grid-template-columns: minmax(0, 1fr); }
  .res-tiles, .res-tiles.four { grid-template-columns: minmax(0, 1fr); }
  .auds { grid-template-columns: minmax(0, 1fr); }
  .aud, .aud:nth-child(4):nth-last-child(2),
  .aud:nth-child(4):nth-last-child(2) ~ .aud { grid-column: auto; }
  .stats { grid-template-columns: 1fr 1fr; }
  .cp-grid { grid-template-columns: 1fr; }
  .cp-chain { flex-wrap: wrap; gap: 10px 4px; }
  .cp-node { flex: 1 1 28%; }
  .cp-arrow { display: none; }
}
@media (max-width: 560px) {
  .hd-act .js-signin { display: none; }
  .prods { grid-template-columns: 1fr; }
  .hero h1 { font-size: 36px; }
  .phero h1 { font-size: 32px; }
  .cta-row .btn { width: 100%; justify-content: center; }
  /* TWO-UP ON A PHONE, NOT ONE. A single column stacks six headings and thirty-one links
     into one very long scroll and pushes Legal & Trust to the bottom of it. Two keeps the
     lists beside each other and roughly halves the height; the brand block and the Stay
     Informed block span both, because a 160px-wide column cannot hold the mail address. */
  .ft-grid { grid-template-columns: 1fr 1fr; gap: 26px 20px; }
  .ft-brand, .ft-stay { grid-column: 1 / -1; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .jmap .arc.flow, .jmap .nd-ring { animation: none; }
  .btn, .prod { transition: none; }
}

/* ---------- FAQ (Key Question section) ---------- */
/* The rule strip and the questions fill the band. A 1040px cap inside a 1264px band drew
   a border-top that stopped 224px short of the section it belonged to, which is the one
   place on a page where a short line reads as a rendering fault rather than a measure.
   The answers keep the reading measure inside the row, where the reading actually happens. */
.faq-wrap { margin-top: 38px; padding-top: 34px; border-top: 1px solid var(--line); }
.faq-wrap h3 { font-size: 21px; font-weight: 600; margin: 0 0 18px; }
/* Two columns on a wide screen. An answer is a couple of sentences, so a single-column
   accordion in a 1264px band drew a full-width box round a 676px line and left half the
   row blank on every open. The items are self-contained boxes, so a grid splits them
   cleanly where CSS columns would not, and align-items:start keeps an opened answer from
   stretching the closed item beside it. Row-major, so the reading order is still 1..6. */
.faq { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; align-items: start; }
@media (max-width: 1180px) { .faq { grid-template-columns: 1fr; } }
.faq-item {
  border: 1px solid var(--line); border-radius: 12px;
  background: rgba(245, 247, 250, 0.02); overflow: hidden;
}
.faq-item.open { border-color: var(--line2); background: rgba(245, 247, 250, 0.035); }
.faq-q {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 15px 18px; background: none; border: 0; cursor: pointer; text-align: left;
  font: inherit; font-size: 15.5px; font-weight: 600; color: var(--tx);
}
.faq-q:hover { color: var(--acc2); }
.faq-ico {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid var(--line2); display: grid; place-items: center;
  font-size: 14px; font-weight: 500; color: var(--tx2);
  transition: transform 0.25s ease;
}
.faq-item.open .faq-ico { transform: rotate(45deg); color: var(--acc2); border-color: var(--acc); }
.faq-a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.3s ease; }
.faq-item.open .faq-a { grid-template-rows: 1fr; }
.faq-a-in { overflow: hidden; }
.faq-a-in p { margin: 0; padding: 0 18px 16px; font-size: 14.5px; line-height: 1.65; color: var(--tx2); max-width: var(--m-read); }
.faq-a-in p + p { padding-top: 0; }
.faq-a-in .g-r, .faq-a-in .g-a, .faq-a-in .g-g, .faq-a-in .g-b, .faq-a-in .g-y { font-size: 12px; }
.faq-a-in .linkline { margin: 0 18px 16px; font-size: 14px; }

/* ---------- About Us ---------- */
.about-grid {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: 56px; align-items: center;
}
.about-copy p { margin: 0 0 16px; font-size: 15.5px; line-height: 1.7; }
.about-copy p:last-child { margin-bottom: 0; }
.about-stats { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; }
.about-stats .stat b { font-size: 29px; }
@media (max-width: 1060px) {
  .about-grid { grid-template-columns: minmax(0, 1fr); gap: 36px; }
}
.about-copy .h2 { margin-bottom: 22px; }
.inl { color: var(--acc2); text-decoration: none; border-bottom: 1px solid rgba(59, 117, 241, 0.4); }
.inl:hover { border-bottom-color: var(--acc2); }

/* ---------- Contact ---------- */
.contact-litany {
  background: var(--well); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 30px 32px 34px;
}
.contact-litany h3 { font-size: 15px; letter-spacing: 0.02em; color: var(--tx); }
.contact-litany .litany { margin: 18px 0 0; max-width: none; }

/* ---------- Scroll / load animations (all initial-hidden states gated on .js) ---------- */
/* Hero chain panel: nodes + arrows rise in, bars sweep, donut fills (donut handled in JS via dasharray) */
.js .chainpanel .cp-node, .js .chainpanel .cp-arrow { opacity: 0; transform: translateY(9px); }
.chainpanel.anim .cp-node, .chainpanel.anim .cp-arrow {
  opacity: 1; transform: none;
  transition: opacity 0.5s ease calc(var(--i, 0) * 95ms), transform 0.5s ease calc(var(--i, 0) * 95ms);
}
.js .chainpanel .cp-bars .bar i { transform: scaleX(0); transform-origin: left; }
.chainpanel.anim .cp-bars .bar i { transform: scaleX(1); transition: transform 0.7s cubic-bezier(0.22, 0.9, 0.35, 1); }
.chainpanel.anim .cp-bars li:nth-child(1) .bar i { transition-delay: 0.35s; }
.chainpanel.anim .cp-bars li:nth-child(2) .bar i { transition-delay: 0.44s; }
.chainpanel.anim .cp-bars li:nth-child(3) .bar i { transition-delay: 0.53s; }
.chainpanel.anim .cp-bars li:nth-child(4) .bar i { transition-delay: 0.62s; }
.chainpanel.anim .cp-bars li:nth-child(5) .bar i { transition-delay: 0.71s; }
#cp-donut circle { transition: stroke-dasharray 0.9s ease 0.45s; }

/* Second Balance Sheet field graphic: lines fade in + march, nodes rise, dots and centre pulse */
.js .fieldbox .flines line { opacity: 0; }
.fieldbox.vis .flines line { opacity: 1; transition: opacity 0.5s ease; animation: fmarch 1.4s linear infinite; }
.fieldbox.vis .flines line:nth-child(2) { transition-delay: 0.08s; }
.fieldbox.vis .flines line:nth-child(3) { transition-delay: 0.16s; }
.fieldbox.vis .flines line:nth-child(4) { transition-delay: 0.24s; }
.fieldbox.vis .flines line:nth-child(5) { transition-delay: 0.32s; }
.fieldbox.vis .flines line:nth-child(6) { transition-delay: 0.4s; }
.fieldbox.vis .flines line:nth-child(7) { transition-delay: 0.48s; }
.fieldbox.vis .flines line:nth-child(8) { transition-delay: 0.56s; }
@keyframes fmarch { to { stroke-dashoffset: -6; } }
.js .fieldbox .fnode { opacity: 0; transform: translateY(10px); }
.fieldbox.vis .fnode { opacity: 1; transform: none; transition: opacity 0.55s ease, transform 0.55s ease; }
.fieldbox.vis .fnode:nth-of-type(2) { transition-delay: 0.09s; }
.fieldbox.vis .fnode:nth-of-type(3) { transition-delay: 0.18s; }
.fieldbox.vis .fnode:nth-of-type(4) { transition-delay: 0.27s; }
.fieldbox.vis .fnode:nth-of-type(5) { transition-delay: 0.36s; }
.fieldbox.vis .fnode:nth-of-type(6) { transition-delay: 0.45s; }
.fieldbox.vis .fnode:nth-of-type(7) { transition-delay: 0.54s; }
.fieldbox.vis .fnode:nth-of-type(8) { transition-delay: 0.63s; }
.fieldbox.vis .fnode:nth-of-type(9) { transition-delay: 0.72s; }
.fieldbox.vis .fdot { animation: fdotpulse 2.8s ease-in-out infinite; }
@keyframes fdotpulse {
  0%, 100% { box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.14); }
  50% { box-shadow: 0 0 0 7px rgba(37, 99, 235, 0.05); }
}
.fieldbox.vis .fcenter img { animation: fglow 4.5s ease-in-out infinite; }
@keyframes fglow {
  0%, 100% { filter: drop-shadow(0 0 24px rgba(37, 99, 235, 0.45)); }
  50% { filter: drop-shadow(0 0 40px rgba(37, 99, 235, 0.7)); }
}

/* Problem flowart: waves draw in, dots twinkle, stage circles pulse, labels fade.
   NOTE: only opacity on .fa-labels > g and .fa-stage children — CSS transforms would
   override the SVG transform attributes and collapse every group onto the origin. */
.js .flowart .fa-wave { stroke-dasharray: 1200; stroke-dashoffset: 1200; }
.flowart.vis .fa-wave { animation: wavedraw 1.1s ease-out forwards; }
.flowart.vis .fa-wave:nth-of-type(2) { animation-delay: 0.15s; }
.flowart.vis .fa-wave:nth-of-type(3) { animation-delay: 0.3s; }
@keyframes wavedraw { to { stroke-dashoffset: 0; } }
.js .fa-dots circle { opacity: 0; }
.flowart.vis .fa-dots circle { animation: dottwinkle 3.2s ease-in-out infinite; }
.flowart.vis .fa-dots circle:nth-of-type(1) { animation-delay: 0.9s; }
.flowart.vis .fa-dots circle:nth-of-type(2) { animation-delay: 1.25s; }
.flowart.vis .fa-dots circle:nth-of-type(3) { animation-delay: 1.6s; }
.flowart.vis .fa-dots circle:nth-of-type(4) { animation-delay: 1.95s; }
.flowart.vis .fa-dots circle:nth-of-type(5) { animation-delay: 2.3s; }
.flowart.vis .fa-dots circle:nth-of-type(6) { animation-delay: 2.65s; }
.flowart.vis .fa-dots circle:nth-of-type(7) { animation-delay: 3s; }
.flowart.vis .fa-dots circle:nth-of-type(8) { animation-delay: 3.35s; }
.flowart.vis .fa-dots circle:nth-of-type(9) { animation-delay: 3.7s; }
@keyframes dottwinkle { 0%, 100% { opacity: 0.15; } 50% { opacity: 0.85; } }
.flowart.vis .fa-stage > circle {
  animation: stagepulse 3.6s ease-in-out infinite;
  transform-box: fill-box; transform-origin: center;
}
.flowart.vis .fa-stage:nth-of-type(1) > circle { animation-delay: 0.2s; }
.flowart.vis .fa-stage:nth-of-type(2) > circle { animation-delay: 1s; }
.flowart.vis .fa-stage:nth-of-type(3) > circle { animation-delay: 1.8s; }
.flowart.vis .fa-stage:nth-of-type(4) > circle { animation-delay: 2.6s; }
@keyframes stagepulse { 0%, 100% { transform: scale(1); } 12% { transform: scale(1.07); } 24% { transform: scale(1); } }
.js .fa-labels > g { opacity: 0; }
.flowart.vis .fa-labels > g { animation: labelfade 0.6s ease-out forwards; }
.flowart.vis .fa-labels > g:nth-of-type(1) { animation-delay: 0.5s; }
.flowart.vis .fa-labels > g:nth-of-type(2) { animation-delay: 0.7s; }
.flowart.vis .fa-labels > g:nth-of-type(3) { animation-delay: 0.9s; }
.flowart.vis .fa-labels > g:nth-of-type(4) { animation-delay: 1.1s; }
.flowart.vis .fa-labels > g:nth-of-type(5) { animation-delay: 1.3s; }
@keyframes labelfade { from { opacity: 0; } to { opacity: 1; } }

/* ---------- homepage: the Observatory band ----------

   THIS FILE STYLES THE BOX, NEVER WHAT IS INSIDE IT. The band embeds /observatory, and that
   page loads assets/obs/observatory.css for itself. Reaching into the frame from here is not
   possible and should not be wanted: one page, one stylesheet, and the home page decides only
   how big a window it opens onto it.

   NEAR-BLACK ON PURPOSE, AND IT COST NOTHING TO GET THERE. The Observatory's own background is
   #05070D, which is already this site's --bg0, so the frame meets the section with no seam. The
   glow behind the heading is the same atmosphere the Observatory puts behind its globe, drawn
   as a gradient rather than fetched as an image.

   THE DISPLAY FACE IS A STACK, NOT A DOWNLOAD. The Observatory sets its headline in Instrument
   Serif, which it fetches from Google. The heading here is the reader's own best serif instead,
   so the section costs this page no font request even while the frame inside it makes its own. */
/* Tighter still than the rhythm above, and the heading sits directly on the frame. On a band
   whose whole point is the instrument, any gap before it starts is a screen the reader paid for
   and got nothing back. */
.obs { position: relative; background: var(--bg0); overflow: hidden; padding: 58px 0 64px; }
.obs .sechead { margin-bottom: 0; }
.obs::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(115% 85% at 50% 4%, rgba(37, 99, 235, 0.17), transparent 62%),
    linear-gradient(180deg, rgba(5, 7, 13, 0) 0%, rgba(5, 7, 13, 0.72) 100%);
}
.obs > .wrap, .obs > .obs-stage { position: relative; }
.obs-h2 {
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
  font-weight: 400; letter-spacing: -0.015em;
}

/* Nearly the whole window. The Observatory is a landscape composition with a rail down one
   side and a director rail along the bottom, and it was built against a full screen — given a
   1600px column it has to compress both rails to fit. The thin inset is only so the border and
   the shadow read as a window rather than a seam. */
.obs-stage {
  margin: 22px auto 0; padding: 0;
  width: min(2100px, calc(100% - 24px));
  border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; background: var(--bg0);
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.55);
}
/* FULL SCREEN, MINUS THE HEADER, AND THAT NUMBER IS NOT ARBITRARY. The Observatory's HUD is
   position: fixed against its own viewport, which inside a frame means the frame's own height —
   so handing it a full screen makes the embedded page lay itself out identically to the
   standalone one. 76px is the fixed header (73px) plus this stage's two borders, so when
   initObservatoryFrame() scrolls the stage up under the header the instrument fills exactly the
   screen that is left. Capped at 1400px because a 4K monitor otherwise buys a scroll block
   nobody can see the ends of, and floored at 700px because under about 1080px wide the HUD
   stacks into a column that a short frame would cut off with no scrollbar to explain it.
   The plain vh line above is the fallback for browsers with no svh. */
.obs-frame {
  display: block; width: 100%; border: 0; background: var(--bg0);
  height: 76vh;
  height: min(calc(100svh - 76px), 1400px);
  min-height: 700px;
  /* Inert until asked. See .obs-tap below and initObservatoryFrame() in site.js. */
  pointer-events: none;
}
.obs-stage.live .obs-frame { pointer-events: auto; }

/* The cover sits over the whole frame and is a plain link, so it is reachable by keyboard,
   readable by a screen reader and useful with no scripting at all. It carries no dimming
   layer: the point is to let the globe be seen, not to hide it behind a play button. */
.obs-tap {
  position: absolute; inset: 0; z-index: 2;
  /* TOP, NOT BOTTOM, AND THAT IS THE WHOLE POINT OF MEASURING IT. The stage is nearly a full
     screen now and the band is arrived at by anchor, which lands the section top under the site
     header — so the stage bottom is off the screen and a pill pinned there is an invitation
     nobody can see. Measured at the bottom: 279px below the fold at 1440x900 and at 1920x1080,
     451px on a 390x844 phone. At the top it is the first thing the band shows. */
  display: flex; align-items: flex-start; justify-content: center;
  padding: 14px 0 0; text-decoration: none;
}
.obs-stage.live .obs-tap { display: none; }
.obs-tap-pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 17px; border-radius: 999px;
  border: 1px solid var(--line2); background: rgba(8, 15, 27, 0.86);
  backdrop-filter: blur(6px);
  color: var(--tx2); font-size: 13px; font-weight: 600; letter-spacing: 0.01em;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.obs-tap:hover .obs-tap-pill { border-color: var(--acc2); color: var(--tx); background: rgba(37, 99, 235, 0.28); }
.obs-tap:focus-visible { outline: 2px solid var(--focus); outline-offset: -3px; border-radius: var(--r-lg); }

/* Only ever on screen while the frame holds the controls, and above it, because the frame it
   sits over is the thing it is rescuing the reader from. */
.obs-release {
  /* THE SAME SPOT THE COVER PILL OCCUPIED, DELIBERATELY. The control does not move when its
     job changes from take to release, so the reader never has to look for it twice. Top right
     was measured sitting on the Observatory's own Readouts chip — a control that puts a dead
     spot over another control. Top centre is measured empty at both ends: the frame's own top
     row holds the brand out to x=237 and its chips from x=990, and on a phone the brand stops
     at x=105. */
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%); z-index: 3;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line2); background: rgba(8, 15, 27, 0.9);
  backdrop-filter: blur(6px);
  color: var(--tx2); font: inherit; font-size: 12.5px; font-weight: 600; letter-spacing: 0.01em;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.obs-release:hover { border-color: var(--acc2); color: var(--tx); background: rgba(37, 99, 235, 0.3); }
.obs-release:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* THE HIDE HAS TO BE RESTATED HERE OR IT DOES NOT HAPPEN. `hidden` only hides because the browser's
   own sheet says [hidden] { display: none }, and any author display wins over that — so the
   display: inline-flex above painted this pill over the frame from page load, offering to release
   controls nobody had taken. The element's .hidden property read true the whole time, which is why
   only a screenshot found it. */
.obs-release[hidden] { display: none; }

.obs-cap { margin: 14px 0 0; font-size: 13.5px; line-height: 1.65; color: var(--tx3); max-width: var(--m-read); }
.obs-cap b { color: var(--tx); font-weight: 700; }
.obs-cap a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--line); transition: border-color 0.15s ease; }
.obs-cap a:hover { border-color: var(--acc); }
.obs-cta { margin-top: 16px; }

@media (max-width: 900px) {
  .obs { padding: 42px 0 48px; }
  .obs-stage { width: calc(100% - 16px); }
  /* Still the screen it is given, just capped lower — a phone frame taller than about 900px is
     a scroll block with no ends. The cover lifts here exactly as it does on a desktop, and the
     Release pill is what makes that safe on a touch screen. */
  .obs-frame { height: 78vh; height: min(calc(100svh - 76px), 900px); min-height: 600px; }
  .obs-h2 { letter-spacing: -0.01em; }
  .obs-tap-pill { font-size: 12.5px; }
  .obs-release { top: 10px; padding: 6px 11px; font-size: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .obs-cap a, .obs-tap-pill, .obs-release { transition: none; }
}

/* Reduced motion: every gated initial state forced visible, every new animation killed */
@media (prefers-reduced-motion: reduce) {
  .js .chainpanel .cp-node, .js .chainpanel .cp-arrow,
  .js .fieldbox .fnode { opacity: 1; transform: none; transition: none; }
  .js .chainpanel .cp-bars .bar i { transform: none; transition: none; }
  .js .fieldbox .flines line, .js .fa-dots circle, .js .fa-labels > g { opacity: 1; animation: none; transition: none; }
  .js .flowart .fa-wave { stroke-dasharray: none; stroke-dashoffset: 0; animation: none; }
  .fieldbox.vis .flines line, .fieldbox.vis .fdot, .fieldbox.vis .fcenter img,
  .flowart.vis .fa-dots circle, .flowart.vis .fa-stage > circle, .flowart.vis .fa-labels > g,
  .flowart.vis .fa-wave { animation: none; }
  #cp-donut circle { transition: none; }
  .faq-a, .faq-ico { transition: none; }
}
