/* --- fonts ---------------------------------------------------------------
   Self-hosted, not fetched from Google. Three reasons, in order of weight:

   1. The privacy policy says this site "loads nothing from a third-party
      host". Hotlinking fonts.googleapis.com sent every visitor's IP address
      to Google on every page view, which made that sentence false.
   2. It was the only external request on the page and it was render-blocking:
      a CSS round trip to one host before a font round trip to a second.
   3. It let the CSP drop two external origins. style-src and font-src are
      now 'self' with no exceptions.

   Subsets are latin and latin-ext only. Cyrillic and Vietnamese are dropped
   because this is a US English site; a character outside these ranges falls
   back to the system stack, which is graceful rather than broken. latin-ext
   is kept deliberately -- clinician and patient names carry accents.

   Archivo is requested with the weight axis only. The site never sets
   font-stretch or font-variation-settings, so the width axis was 106 KB of
   nothing: dropping it took the family from 170 KB to 65 KB.

   display: swap -- text renders immediately in the fallback and reflows once.
   For a text site that is the right trade against invisible text.

   These filenames are NOT content-hashed and they are served immutable for a
   year. If a face is ever re-subset or replaced, CHANGE THE FILENAME, or
   returning visitors keep the old one.
   --------------------------------------------------------------------- */

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/assets/fonts/archivo-400-800-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/assets/fonts/archivo-400-800-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Public Sans';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/assets/fonts/public-sans-300-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Public Sans';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/assets/fonts/public-sans-300-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   metaclinic.com
   One stylesheet. No framework, no reset library, no utility classes.

   Three typefaces: Archivo for display, Public Sans for text, IBM Plex Mono
   for the technical stamps. Release state is encoded by pattern as well as by
   colour, so the matrix survives greyscale and colour-vision deficiency.
   ========================================================================== */

/* The neutrals were tinted green (hue ~160) to sit under a green accent. They
   are now tinted to the accent's own hue (210) at exactly the same saturation
   and lightness, so the tonal structure of the design is unchanged and only the
   cast moves. Nothing in the interface reads green any more. */
:root {
  /* Dark since 2026-09-02: a near-black ground with a blue bias, the brand's
     light as the only accent, and the same traffic light for release state.
     The token names kept their meaning -- ink is text, paper is ground -- so
     every component styled through them re-themed without being touched. */
  --ink:      #f2f5f8;
  --ink-2:    #c6cfd8;
  --mute:     #8d99a6;
  --line:     rgba(255, 255, 255, 0.13);
  --line-2:   rgba(255, 255, 255, 0.07);
  --paper:    #070a0e;
  --pale:     #0f151c;
  --dark:     #04070a;
  --dark-2:   #0a0f15;   /* the footer: dark, but a step off the CTA above it */
  --sage:     #aeb8c2;
  --accent:   #5db4ff;
  --accent-d: #9ad0ff;
  /* The logo's own blue, the light end of the mark's gradient. */
  --brand:    #217df2;

  /* Release state is a traffic light, not brand colour: green means released,
     amber conditional, red withheld. Deliberately NOT re-tinted with the rest
     of the palette — recolouring it would destroy the encoding the matrix is
     built on. State is also carried by pattern, so it does not rely on hue. */
  --rel: #1b7a4d;
  --con: #a8710f;
  --wit: #a33b33;

  --sans:    "Public Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --display: "Archivo", var(--sans);
  --mono:    "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --wrap: 1180px;
  --text: 720px;
  --pad:  24px;
  --rail: 200px;
  --rail-gap: 56px;
}

/* --- base ---------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-2);
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* `video` belongs in this list. Without it a <video> renders at its intrinsic
   size no matter what contains it, and the two on /for-labs/ are 1600px wide
   inside a 796px figure -- which pushed the document to 1970px on a 1280px
   viewport and gave every page-width element a horizontal scrollbar. Stills
   never showed the fault because `img` was always here. */
img, svg, video { max-width: 100%; height: auto; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-d); }

h1, h2, h3, h4 {
  font-family: var(--display);
  color: var(--ink);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.03em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0 0 1.05em; }
p:last-child { margin-bottom: 0; }

b, strong { font-weight: 600; color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 18px;
  background: var(--ink);
  color: #fff;
  font: 500 14px/1 var(--mono);
  text-decoration: none;
}
.skip:focus {
  left: 12px;
  top: 12px;
}

.stamp {
  font: 400 12px/1.5 var(--mono);
  letter-spacing: 0.02em;
  color: var(--mute);
}

/* --- layout ------------------------------------------------------------- */

.wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}

.sec { padding: 88px 0; border-top: 1px solid var(--line-2); }
.sec:first-child { border-top: 0; }
.sec.pale {
  background: var(--pale);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.sec.dark {
  background: var(--dark);
  color: var(--sage);
  border-top: 0;
}
.sec.dark h2, .sec.dark h3 { color: #fff; }
.sec.dark a:not(.btn) { color: #9fbbd8; }

/* --- the document rail ---------------------------------------------------
   Long specification pages get a section index in the left margin, which is
   what the space to the left of a 720px measure inside a 1180px wrap is for.
   Emitted by build.py only when a page has RAIL_MIN or more h2 sections, and
   the .has-rail class states that rather than letting CSS infer it, for the
   same reason .has-lockup does. */

.doc.has-rail {
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr);
  column-gap: var(--rail-gap);
  align-items: start;
}

.rail {
  position: sticky;
  top: 90px;
  max-height: calc(100vh - 130px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.rail-t {
  margin: 0 0 14px;
  padding-left: 13px;
  color: var(--mute);
}

.rail-l {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: rail;
}

.rail-l li { margin: 0 0 2px; }

.rail-l a {
  display: block;
  padding: 6px 0 6px 13px;
  border-left: 2px solid var(--line);
  font-size: 13.5px;
  line-height: 1.35;
  color: var(--mute);
  text-decoration: none;
}

.rail-l a:hover,
.rail-l a:focus-visible {
  color: var(--accent);
  border-left-color: var(--accent);
  background: var(--pale);
}

/* The sticky header would otherwise sit on top of the section an anchor
   lands on. */
.art > h2 { scroll-margin-top: 88px; }

/* Below this the rail cannot hold its own column and the page is a single
   measure again. The h2s are still in the document, so nothing is lost. */
@media (max-width: 1040px) {
  .doc.has-rail { display: block; }
  .rail { display: none; }
}

/* Reading measure for prose, full bleed for the wide objects. */
.art > h2,
.art > h3,
.art > p,
.art > ul,
.art > ol,
.art > dl,
.art > .note,
.art > .codeblock,
.art > .h2stamp { max-width: var(--text); }

.art > .full, .art > .tri { max-width: none; }

.art > h2 { font-size: clamp(28px, 3.4vw, 40px); margin-top: 0; }
.art > h2 + .h2stamp { margin: 10px 0 22px; }
.art > * + h2 {
  margin-top: 68px;
  padding-top: 32px;
  border-top: 1px solid var(--line-2);
}
.art > h3 { font-size: 21px; margin: 34px 0 10px; }
.art > p + h3 { margin-top: 28px; }

.h2stamp { color: var(--mute); }

.lead {
  font-size: clamp(19px, 1.5vw, 21px);
  line-height: 1.55;
  color: var(--ink-2);
  font-weight: 380;
}
.sec.dark .lead { color: var(--sage); }

.art ul, .art ol { margin: 0 0 1.1em; padding-left: 1.35em; }
.art li { margin-bottom: 0.5em; }
.art li::marker { color: var(--mute); }
.art ol li::marker { font: 500 14px var(--mono); }

.art dl { margin: 0 0 1.2em; }
.art dt {
  font-family: var(--display);
  font-weight: 620;
  color: var(--ink);
  font-size: 17px;
  margin-top: 22px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.art dt:first-child { margin-top: 6px; }
.art dd { margin: 6px 0 0; }

.full { margin: 26px 0; }

/* --- header ------------------------------------------------------------- */

.top {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(7, 10, 14, 0.72);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line);
}
.top .wrap {
  display: flex;
  align-items: center;
  gap: 28px;
  min-height: 66px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--display);
  font-weight: 750;
  font-size: 20px;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-decoration: none;
  flex: none;
}
.brand .wm span { color: var(--brand); }
.mark { display: block; flex: none; }

/* .has-lockup is written by the build when assets/logo-lockup.svg exists. The
   brand is then that one wide image, with the square mark kept in the markup as
   the narrow-viewport substitute — exactly one of the two is displayed at any
   width. The hidden one leaves the accessibility tree with it, which is why
   both carry the same alt text. */
.lockup { display: block; flex: none; }
.has-lockup { gap: 0; }
.has-lockup .mark { display: none; }

/* The flat header nav is gone; see the header dropdown section at the end of
   this file. The rules that were here matched `.top nav a`, which out-specifies
   `.navlinks a`, so leaving them would have quietly won on padding inside the
   panel. */

/* Existing-customer route into app.metaclinic.com. Deliberately quieter than
   .cta-sm — it serves people who already pay, not the conversion path. */
.signin {
  flex: none;
  font: 500 14px/1 var(--mono);
  color: var(--ink-2);
  text-decoration: none;
  padding: 10px 0;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.signin:hover { color: var(--ink); border-bottom-color: var(--accent); }

.cta-sm {
  flex: none;
  font: 500 14px/1 var(--mono);
  color: var(--ink);
  text-decoration: none;
  border: 1px solid var(--ink);
  padding: 10px 14px;
  border-radius: 2px;
}
.cta-sm:hover { background: var(--ink); color: var(--paper); }

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

.hero {
  padding: 76px 0 64px;
  background: linear-gradient(180deg, var(--pale), var(--paper));
  border-bottom: 1px solid var(--line-2);
}
.hero.page { padding: 62px 0 40px; }

.eyebrow {
  font: 500 12.5px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 18px;
}

.hero h1 {
  font-size: clamp(38px, 5.6vw, 66px);
  font-weight: 700;
  letter-spacing: -0.035em;
  max-width: 18ch;
}
.hero.page h1 { font-size: clamp(32px, 4.4vw, 52px); max-width: 24ch; }

.hero .sub {
  margin: 24px 0 0;
  max-width: 62ch;
  font-size: clamp(17.5px, 1.5vw, 20px);
  line-height: 1.56;
}

.hero-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 34px;
  margin: 32px 0 0;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
.hero-foot .k {
  font: 400 13.5px/1.4 var(--mono);
  color: var(--mute);
}
/* The label that says what the counts are. Its own row, so the three counts
   and the link sit together beneath it instead of wrapping around it. */
.hero-foot .k.lbl { flex-basis: 100%; color: var(--ink-2); }
.hero-foot .k b {
  font-family: var(--display);
  font-size: 21px;
  font-weight: 700;
  color: var(--ink);
  margin-right: 5px;
}

/* The hero's closing statement and image.

   This replaced the release matrix, which used to sit here as the first thing
   on the page -- 81 cells asking a first-time reader to parse the argument
   before they had been given a reason to. The matrix still carries that
   argument in full in release.py, which generates the fan below. Here
   the job is to make the promise legible in one line and one picture. */
.heroline {
  font-family: var(--display);
  font-size: clamp(21px, 2.5vw, 29px);
  font-weight: 620;
  line-height: 1.3;
  letter-spacing: -0.022em;
  color: var(--ink);
  max-width: 34ch;
  margin: 40px 0 0;
  text-wrap: balance;
}
.heroart { margin: 30px 0 0; }
.heroart img { display: block; width: 100%; height: auto; }
.heroart figcaption {
  font: 400 13.5px/1.5 var(--mono);
  color: var(--mute);
  margin-top: 13px;
}

/* --- the split hero ------------------------------------------------------
   Audience pages open on the argument and its picture at once. A four-column
   grid: the outer columns are the margins, so the text column starts exactly
   where .wrap's content does, and the figure spans its half plus the right
   margin, bleeding to the viewport edge. The figure is absolutely filled so
   the text decides the row height and the image covers whatever that is --
   the subject of every piece of art sits centrally, so a side crop is safe.
   Below 900px it stacks: text, then the image at its own aspect. */

.hero.split {
  padding: 0;
  background: var(--pale);
}
.hero.split .hwrap {
  display: grid;
  grid-template-columns:
    minmax(var(--pad), 1fr)
    minmax(0, calc(var(--wrap) / 2 - var(--pad)))
    minmax(0, calc(var(--wrap) / 2 - var(--pad)))
    minmax(var(--pad), 1fr);
  align-items: stretch;
}
.hero.split .htxt {
  grid-column: 2;
  align-self: center;
  padding: 72px 56px 64px 0;
}
.hero.split .htxt .lead {
  margin: 22px 0 0;
  font-size: clamp(16.5px, 1.3vw, 18.5px);
  max-width: 46ch;
}
.hero.split .hfig {
  grid-column: 3 / 5;
  position: relative;
  margin: 0;
  min-height: 480px;
  background: var(--pale);
}
.hero.split .hfig img,
.hero.split .hfig video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.hero.split .hfig figcaption {
  position: absolute;
  left: 0;
  bottom: 0;
  max-width: 62%;
  padding: 9px 14px;
  background: rgba(7, 10, 14, 0.78);
  font: 400 12.5px/1.5 var(--mono);
  color: var(--ink-2);
}

@media (max-width: 900px) {
  .hero.split .hwrap { display: block; }
  .hero.split .htxt { padding: 54px var(--pad) 34px; }
  .hero.split .hfig { min-height: 0; }
  .hero.split .hfig img,
  .hero.split .hfig video {
    position: static;
    height: auto;
    aspect-ratio: 16 / 9;
  }
  .hero.split .hfig figcaption {
    position: static;
    max-width: none;
    padding: 10px var(--pad) 22px;
    background: none;
  }
}

/* --- the release matrix ------------------------------------------------- */

.mx {
  margin: 46px 0 0;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
}

.mx-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px 24px;
  padding: 18px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--pale);
}
.mx-title {
  font-family: var(--display);
  font-weight: 620;
  font-size: 16px;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.mx-legend {
  display: flex;
  gap: 18px;
  margin-left: auto;
  font: 400 12px/1 var(--mono);
  color: var(--mute);
}
.mx-legend span { display: inline-flex; align-items: center; gap: 7px; }
.mx-legend i {
  width: 13px;
  height: 13px;
  border-radius: 2px;
  border: 1px solid rgba(0, 0, 0, 0.16);
}

/* State fills. Colour AND pattern, so the grid reads without colour. */
.lg-r, .mx-cell[data-s="released"] { background: var(--rel); }
.lg-c, .mx-cell[data-s="conditional"] {
  background-color: #fff;
  background-image: repeating-linear-gradient(
    45deg, var(--con) 0 2.5px, rgba(255, 255, 255, 0) 2.5px 5.5px);
}
.lg-w, .mx-cell[data-s="withheld"] {
  background-color: #fff;
  background-image: radial-gradient(var(--wit) 1.1px, rgba(255, 255, 255, 0) 1.2px);
  background-size: 5px 5px;
}

.mx-grid {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}
.mx-grid caption {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.mx-grid th, .mx-grid td { border: 1px solid var(--line-2); }

.mx-grid thead th {
  font: 500 11.5px/1.25 var(--sans);
  color: var(--ink);
  text-align: center;
  vertical-align: bottom;
  padding: 12px 4px 10px;
  background: var(--pale);
  font-weight: 600;
}
.mx-grid th.corner {
  width: 15%;
  text-align: left;
  padding: 12px 10px 10px;
  vertical-align: bottom;
}
.mx-grid th.corner .stamp { font-size: 10.5px; line-height: 1.35; }

.mx-grid tbody th {
  font: 500 13px/1.3 var(--sans);
  color: var(--ink);
  text-align: left;
  padding: 10px;
  background: var(--paper);
}
.mx-grid tbody tr:hover th { background: var(--pale); }
.mx-grid td { padding: 0; height: 42px; }

.mx-cell {
  display: block;
  width: 100%;
  height: 42px;
  padding: 0;
  border: 0;
  cursor: pointer;
  background-clip: padding-box;
  transition: box-shadow 120ms ease, transform 120ms ease;
}
.mx-cell:hover {
  box-shadow: inset 0 0 0 2px var(--ink);
}
.mx-cell[aria-pressed="true"] {
  box-shadow: inset 0 0 0 3px var(--ink);
}
.mx-cell:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: -3px;
}

/* Detail panel. Server-rendered for one cell so it is never empty. */
.mx-detail {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 28px;
  padding: 22px 20px;
  border-top: 1px solid var(--line);
  background: var(--pale);
  font-size: 15px;
}
.mx-detail .who {
  font-family: var(--display);
  font-weight: 640;
  font-size: 16px;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-bottom: 10px;
}
.mx-detail .state {
  display: inline-block;
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 6px 10px;
  border-radius: 2px;
  margin-bottom: 12px;
  color: #fff;
}
.mx-detail .state.released    { background: var(--rel); }
.mx-detail .state.conditional { background: var(--con); }
.mx-detail .state.withheld    { background: var(--wit); }
.mx-detail p { margin: 0 0 10px; }

/* The same state pill inside a ("stake", ...) table, which is the release
   matrix for one party. Scoped separately because .mx-detail is the panel on
   the home page and this table is not inside it. The word is always present
   next to the colour -- see the note on /for-labs/ about colour never
   carrying the decision on its own. */
.dt .state {
  display: inline-block;
  font: 500 10.5px/1 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 5px 8px;
  border-radius: 2px;
  color: #fff;
  white-space: nowrap;
}
.dt .state.released    { background: var(--rel); }
.dt .state.conditional { background: var(--con); }
.dt .state.withheld    { background: var(--wit); }
.mx-detail .lbl {
  display: block;
  font: 500 10.5px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mute);
  margin: 14px 0 5px;
}
.mx-detail > div > .lbl:first-child { margin-top: 0; }
.mx-detail .cls { color: var(--ink); font-weight: 500; }

/* Mobile matrix: a real interface, not a scrolled table. */
.mx-pick { display: none; }
.pick-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 14px;
  border-bottom: 1px solid var(--line);
}
.pick-row button {
  font: 500 12.5px/1 var(--mono);
  color: var(--ink-2);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 9px 11px;
  cursor: pointer;
}
.pick-row button[aria-pressed="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

#mxList { list-style: none; margin: 0; padding: 0; }
#mxList li { border-bottom: 1px solid var(--line-2); }
#mxList button {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 13px 14px;
  cursor: pointer;
  font: inherit;
  font-size: 14.5px;
  color: var(--ink);
}
#mxList button[aria-pressed="true"] { background: var(--pale); }
#mxList .sw {
  flex: none;
  width: 15px;
  height: 15px;
  border-radius: 2px;
  border: 1px solid rgba(0, 0, 0, 0.16);
}
#mxList .st {
  margin-left: auto;
  font: 400 11px/1 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mute);
  flex: none;
}

/* --- three failures ----------------------------------------------------- */

.tri {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 30px;
  margin-top: 44px;
  padding-top: 34px;
  border-top: 1px solid var(--line);
}
.tri .n {
  display: block;
  font: 500 11.5px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mute);
  margin-bottom: 12px;
}
.tri h3 { font-size: 19px; margin-bottom: 9px; }
.tri p { font-size: 15.5px; margin: 0; color: var(--ink-2); }

/* --- tables: connections and generic data tables ------------------------ */

.conn, .dt {
  width: 100%;
  border-collapse: collapse;
  font-size: 15px;
  text-align: left;
}
.conn thead th, .dt thead th {
  font: 500 11px/1.2 var(--mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--mute);
  border-bottom: 1px solid var(--ink);
  padding: 0 14px 9px 0;
  vertical-align: bottom;
  font-weight: 500;
}
.conn td, .dt td, .dt tbody th {
  border-bottom: 1px solid var(--line);
  padding: 15px 14px 15px 0;
  vertical-align: top;
}
.conn tr:last-child td,
.dt tbody tr:last-child td,
.dt tbody tr:last-child th { border-bottom: 0; }

.conn .nm, .dt tbody th {
  font-family: var(--display);
  font-weight: 620;
  color: var(--ink);
  width: 20%;
  text-align: left;
}
.conn .kd {
  font: 400 12px/1.4 var(--mono);
  color: var(--mute);
  width: 13%;
}
.conn .hw { width: 36%; }
.conn .nt { width: 31%; color: var(--mute); }

/* Inline code: identifiers in prose and in table cells. Kept mono even where the
   surrounding cell is set in the display face. */
.art code,
.dt tbody th code,
.dt td code {
  font-family: var(--mono);
  font-size: 0.86em;
  font-weight: 500;
  color: var(--ink);
  background: var(--line-2);
  padding: 2px 5px;
  border-radius: 2px;
  overflow-wrap: break-word;
}
.codeblock code { font-size: 13px; background: none; padding: 0; border-radius: 0; }

.dt caption {
  caption-side: top;
  text-align: left;
  font: 400 12px/1.5 var(--mono);
  color: var(--mute);
  padding-bottom: 10px;
}

/* --- release trace ------------------------------------------------------ */

/* The rail runs between the time column and the content, and every dot is
   centred on it. Keep the three custom properties in step: the rail is placed
   from them, so changing a column width does not need a second edit. */
.trace {
  --t-col: 58px;
  --t-gap: 8px;
  --dot: 11px;
  position: relative;
}
.trace::before {
  content: "";
  position: absolute;
  top: 8px;
  bottom: 8px;
  left: calc(var(--t-col) + var(--t-gap) + (var(--dot) - 2px) / 2);
  width: 2px;
  background: var(--line);
}
.trace .ev {
  display: grid;
  grid-template-columns: var(--t-col) var(--dot) 1fr;
  align-items: start;
  gap: 0 var(--t-gap);
  padding: 0 0 22px;
}
.trace .ev:last-child { padding-bottom: 0; }
.trace .t {
  font: 500 12px/1.7 var(--mono);
  color: var(--mute);
  text-align: right;
}
.trace .dot {
  position: relative;
  z-index: 1;
  width: var(--dot);
  height: var(--dot);
  margin-top: 6px;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--mute);
}
.trace .ev.rel  .dot { border-color: var(--rel); background: var(--rel); }
.trace .ev.hold .dot { border-color: var(--wit); background: var(--wit); }
.trace .ev.bdy  .dot { border-color: var(--con); background: var(--con); }
.trace .ttl {
  font-family: var(--display);
  font-weight: 620;
  color: var(--ink);
  font-size: 16px;
  line-height: 1.3;
}
.trace .dsc { font-size: 15px; margin-top: 4px; }
.trace .tn {
  font: 400 11.5px/1.4 var(--mono);
  color: var(--mute);
  margin-top: 6px;
}

/* --- audience cards ----------------------------------------------------- */

.cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  margin-top: 34px;
}
.cards a {
  display: flex;
  flex-direction: column;
  padding: 28px 26px 26px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-top: 2px solid var(--ink);
  text-decoration: none;
  color: var(--ink-2);
  transition: border-color 140ms ease, background-color 140ms ease;
}
.cards a:hover { background: var(--pale); border-top-color: var(--accent); }
.cards .who {
  font: 500 11.5px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mute);
  margin-bottom: 14px;
}
.cards h3 { font-size: 20px; margin-bottom: 10px; }
.cards p { font-size: 15px; margin: 0 0 20px; }
.cards .go {
  margin-top: auto;
  font: 500 13px/1 var(--mono);
  color: var(--ink);
}
.cards a:hover .go { color: var(--accent); }
.cards .go::after { content: " \2192"; }

/* --- notes -------------------------------------------------------------- */

.note {
  margin: 28px 0;
  padding: 20px 22px;
  border: 1px solid var(--line);
  border-top: 2px solid var(--mute);
  background: var(--pale);
}
.note p { font-size: 15.5px; margin: 0; }
/* The note's label. Not a heading -- see build.py: as an <h4> it put an
   h2 -> h4 skip in the outline of nearly every page. Styled to look exactly
   as it did. This rule must stay after `.note p` above, or that shorthand
   resets the size and margin back. */
.note .nt {
  font-family: var(--display);
  color: var(--ink);
  font-size: 16px;
  font-weight: 640;
  line-height: 1.12;
  letter-spacing: -0.02em;
  margin: 0 0 8px;
  text-wrap: balance;
}
.note.flag { border-top-color: var(--wit); }
.note.ok   { border-top-color: var(--rel); }
.note.plain { border-top-color: var(--line); }
.sec.dark .note {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.14);
}
/* No note currently lands in a dark section, but the rule above exists for the
   case, and the label defaults to --ink -- which on a dark panel is invisible.
   Cheap insurance rather than a bug waiting for a content change. */
.sec.dark .note .nt { color: #fff; }

/* --- code --------------------------------------------------------------- */

.codeblock {
  margin: 26px 0;
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
  background: var(--pale);
}
.codeblock .stamp {
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--paper);
}
.codeblock pre {
  margin: 0;
  padding: 16px 14px;
  overflow-x: auto;
}
.codeblock code {
  font: 400 13px/1.65 var(--mono);
  color: var(--ink);
  white-space: pre;
}

/* --- movement gradients ---------------------------------------------------

   A slow brand-gradient wash behind the hero and the closing band. Deliberately
   very low alpha and a 26s cycle: at this size it reads as depth rather than as
   something happening, which is the only version of this that belongs on a site
   arguing for its own seriousness. Sits behind content via z-index, never
   intercepts pointer events, and is switched off entirely for reduced motion.
   -------------------------------------------------------------------------- */

.hero, .band { position: relative; overflow: hidden; }
.hero > .wrap, .band > .wrap { position: relative; z-index: 1; }

.hero::after, .band::after {
  content: "";
  position: absolute;
  inset: -45% -12% auto -12%;
  height: 190%;
  pointer-events: none;
  z-index: 0;
  animation: drift 26s ease-in-out infinite alternate;
}
.hero::after {
  background:
    radial-gradient(58% 48% at 18% 38%, rgba(33, 125, 242, 0.11), transparent 70%),
    radial-gradient(48% 40% at 82% 26%, rgba(63, 214, 255, 0.10), transparent 70%);
}
.band::after {
  background:
    radial-gradient(55% 45% at 22% 30%, rgba(33, 125, 242, 0.22), transparent 70%),
    radial-gradient(45% 38% at 78% 70%, rgba(63, 214, 255, 0.16), transparent 70%);
  animation-duration: 34s;
}

@keyframes drift {
  to { transform: translate3d(-4%, 3%, 0) scale(1.09); }
}

/* --- the release fan ------------------------------------------------------

   Inline SVG generated by flow_html(). Everything here rather than in the
   markup because the CSP is style-src 'self': no <style> blocks, no style=""
   attributes. SVG presentation attributes are not inline styles, so the
   per-path stroke-width and opacity stay on the elements.
   -------------------------------------------------------------------------- */

.mx-cap { margin-bottom: 8px; }

.flow {
  margin: 34px 0 0;
  padding: 0;
}
.flow svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}
.flow figcaption {
  margin-top: 14px;
  font: 400 12px/1.5 var(--mono);
  color: var(--mute);
  letter-spacing: 0.02em;
}

/* --- the release fan ------------------------------------------------------
   Inline SVG from flow_html(). NO paint lives here: fill and stroke are
   presentation attributes on every element. A browser that fails to apply this
   stylesheet to the SVG then still renders the figure correctly instead of
   filling every curve solid black, and WebKit's external-stylesheet url(#id)
   bug cannot bite. Only type, spacing, and motion belong in this block.
   -------------------------------------------------------------------------- */

.mx-cap { margin-bottom: 8px; }

.flow { margin: 36px 0 0; padding: 0; }
.flow svg { display: block; width: 100%; height: auto; overflow: visible; }
.flow figcaption {
  margin-top: 18px;
  font: 400 12px/1.6 var(--mono);
  color: var(--mute);
  letter-spacing: 0.02em;
  max-width: 78ch;
}

/* The moving packet: one short dash chased along an otherwise empty path. */
.fl-pulse {
  stroke-dasharray: 30 1200;
  stroke-dashoffset: 1230;
  animation: fl-run 4.8s linear infinite;
}
@keyframes fl-run { to { stroke-dashoffset: 0; } }

.fl-d0 { animation-delay: -0.20s; }
.fl-d1 { animation-delay: -1.35s; animation-duration: 5.3s; }
.fl-d2 { animation-delay: -2.60s; animation-duration: 4.4s; }
.fl-d3 { animation-delay: -0.85s; animation-duration: 5.8s; }
.fl-d4 { animation-delay: -3.40s; animation-duration: 4.9s; }
.fl-d5 { animation-delay: -1.90s; animation-duration: 5.5s; }
.fl-d6 { animation-delay: -4.10s; animation-duration: 4.6s; }
.fl-d7 { animation-delay: -2.15s; animation-duration: 6.1s; }
.fl-d8 { animation-delay: -3.05s; animation-duration: 5.1s; }

.fl-label { font: 600 14px var(--display); fill: var(--ink); }
.fl-count { font: 400 11px var(--mono); fill: var(--mute); }
.fl-cap   { font: 400 11.5px var(--mono); fill: var(--mute); letter-spacing: 0.04em; }

.sec.dark .fl-label { fill: #fff; }
.sec.dark .fl-count, .sec.dark .fl-cap { fill: var(--sage); }

@media (max-width: 720px) {
  .flow svg { overflow: hidden; }
  .fl-label, .fl-count { display: none; }
}

/* --- the many-to-many network -------------------------------------------

   Generated by network_html(). Nine data classes against nine stakeholders,
   with every connection that exists between them and none of the ones that do
   not. Released edges are solid, conditional edges dashed, withheld edges are
   simply absent.

   The reveal is opacity only, staggered by nine delay classes and switched on
   by mx.js adding .is-live when the figure enters the viewport. Nothing is
   styled from script: the CSP is style-src 'self', so class toggling is the
   only mechanism that is unambiguously permitted. Edges are visible by
   default and are only hidden once mx.js has armed them, so with JavaScript
   off the whole network is simply there. The arm/live pair is shared with the
   disclosure ledger via .js-reveal.
   -------------------------------------------------------------------------- */

.nx { margin: 36px 0 0; padding: 0; }
.nx svg { display: block; width: 100%; height: auto; overflow: visible; }
.nx figcaption {
  margin-top: 16px;
  font: 400 12px/1.5 var(--mono);
  color: var(--mute);
  letter-spacing: 0.02em;
}

.nx-pulse {
  stroke-dasharray: 26 1400;
  stroke-dashoffset: 1426;
  animation: nx-run 6s linear infinite;
}
@keyframes nx-run { to { stroke-dashoffset: 0; } }
.nx-p0 { animation-delay: -0.4s; }
.nx-p1 { animation-delay: -1.2s; animation-duration: 6.6s; }
.nx-p2 { animation-delay: -2.1s; animation-duration: 5.4s; }
.nx-p3 { animation-delay: -3.0s; animation-duration: 7.1s; }
.nx-p4 { animation-delay: -3.8s; animation-duration: 5.9s; }
.nx-p5 { animation-delay: -4.6s; animation-duration: 6.9s; }
.nx-p6 { animation-delay: -5.3s; animation-duration: 5.6s; }
.nx-p7 { animation-delay: -2.7s; animation-duration: 7.4s; }

.nx-l { font: 600 12.5px var(--sans); fill: var(--ink); }
.nx-l-a { text-anchor: end; }

.sec.dark .nx-l { fill: #fff; }
.sec.dark .nx-n { fill: rgba(255, 255, 255, 0.5); }
.sec.dark .nx figcaption { color: var(--sage); }

/* Armed by script, then released. Without JS neither class is ever added and
   the rules above stand on their own. */
.nx.is-armed .nx-edges,
.nx.is-armed .nx-packets { opacity: 0; transition: opacity 1.1s ease; }
.nx.is-armed.is-live .nx-edges,
.nx.is-armed.is-live .nx-packets { opacity: 1; }

.nx-d0 { transition-delay: 0s; }
.nx-d1 { transition-delay: 0.10s; }
.nx-d2 { transition-delay: 0.20s; }
.nx-d3 { transition-delay: 0.30s; }
.nx-d4 { transition-delay: 0.40s; }
.nx-d5 { transition-delay: 0.50s; }
.nx-d6 { transition-delay: 0.60s; }
.nx-d7 { transition-delay: 0.70s; }
.nx-d8 { transition-delay: 0.80s; }

/* Below this the two label columns collide with the graph. The shape is still
   worth showing, and the figcaption and <desc> carry the meaning. */
@media (max-width: 780px) {
  .nx svg { overflow: hidden; }
  .nx-l { display: none; }
}

/* --- the case pipeline ---------------------------------------------------
   The spine of the LIS features page. A row of linked stops on wide screens
   that wraps to a column on narrow ones; the connector is a pseudo-element so
   the markup stays an ordered list of links. */

.pipe-wrap { margin: 34px 0 30px; }

/* Grid rather than flex: with seven stops and a wrap, a flex last row
   stretches its orphan across the full width. Grid cells stay their column. */
.pipe {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(108px, 1fr));
  gap: 10px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.pipe li { margin: 0; }

.pipe a {
  display: block;
  height: 100%;
  padding: 14px 14px 16px;
  border: 1px solid var(--line);
  border-top: 2px solid var(--accent);
  background: var(--paper);
  text-decoration: none;
  color: var(--ink-2);
}

.pipe a:hover,
.pipe a:focus-visible { background: var(--pale); }

.pipe-n {
  display: block;
  font: 500 11px var(--mono);
  color: var(--accent);
  letter-spacing: 0.08em;
}

.pipe-l {
  display: block;
  margin-top: 6px;
  font-family: var(--display);
  font-weight: 620;
  font-size: 16px;
  color: var(--ink);
  line-height: 1.2;
}

.pipe-d {
  display: block;
  margin-top: 5px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--mute);
}

/* --- the capability index ------------------------------------------------
   Deliberately exhaustive and deliberately dense: this is the section a lab
   director searches rather than reads. CSS columns keep it one document in
   source order for Ctrl-F and for a screen reader. */

.cidx {
  margin: 30px 0 0;
  columns: 3 260px;
  column-gap: 40px;
}

.cidx-g {
  break-inside: avoid;
  page-break-inside: avoid;
  margin: 0 0 26px;
}

.cidx-g h3 {
  font-size: 14px;
  margin: 0 0 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
}

.cidx-g ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.cidx-g li {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink-2);
  margin: 0 0 5px;
  padding-left: 11px;
  text-indent: -11px;
}

.cidx-g li::before {
  content: "\2013\00a0";
  color: var(--mute);
}

@media (max-width: 620px) {
  .cidx { columns: 1; }
}

/* --- the disclosure ledger -----------------------------------------------
   One accession and every release made from it. The three states are the
   release matrix's own -- released, conditional, withheld -- so this reuses
   --rel/--con/--wit rather than introducing a second colour vocabulary for
   the same idea. Reveal uses the shared .js-reveal arm/live pair. */

.ledg {
  margin: 30px 0;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 2px;
  overflow: hidden;
}

.ledg-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  flex-wrap: wrap;
  padding: 13px 18px;
  background: var(--pale);
  border-bottom: 1px solid var(--line);
}
.ledg-head b { font: 500 13px var(--mono); color: var(--ink); letter-spacing: 0.02em; }
.ledg-head i {
  font: 400 11.5px var(--mono);
  font-style: normal;
  color: var(--mute);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.ledg-row {
  display: grid;
  grid-template-columns: 1.05fr 1.6fr auto;
  gap: 4px 18px;
  align-items: center;
  padding: 13px 18px;
  border-bottom: 1px solid var(--line-2);
}
.ledg-row:last-of-type { border-bottom: 0; }

.ledg-who { font-weight: 600; font-size: 15px; color: var(--ink); }
.ledg-auth { font: 400 12px/1.5 var(--mono); color: var(--mute); }

.ledg-chip {
  justify-self: start;
  font: 500 11px var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 8px;
  border: 1px solid currentColor;
  border-radius: 2px;
  white-space: nowrap;
}
.ledg-released    { color: var(--rel); }
.ledg-conditional { color: var(--con); }
.ledg-withheld    { color: var(--wit); }

.ledg-foot {
  margin: 0;
  padding: 12px 18px;
  background: var(--pale);
  border-top: 1px solid var(--line);
  font: 400 12px var(--mono);
  color: var(--mute);
}

.ledg.is-armed .ledg-row { opacity: 0; transition: opacity .5s ease; }
.ledg.is-armed.is-live .ledg-row { opacity: 1; }
.ledg-row:nth-of-type(2) { transition-delay: .06s; }
.ledg-row:nth-of-type(3) { transition-delay: .12s; }
.ledg-row:nth-of-type(4) { transition-delay: .18s; }
.ledg-row:nth-of-type(5) { transition-delay: .24s; }
.ledg-row:nth-of-type(6) { transition-delay: .30s; }
.ledg-row:nth-of-type(7) { transition-delay: .36s; }
.ledg-row:nth-of-type(8) { transition-delay: .42s; }

/* --- the worklist and the patient summary ---------------------------------
   Two more artifact figures in the ledger's idiom: what a practice sees on
   Monday, and what a patient sees above a result. Neither is a release state,
   so neither borrows --rel/--con/--wit; rank and weight carry the order, and
   the accent marks only the row that matters most. */

.wl {
  margin: 30px 0;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 2px;
  overflow: hidden;
}
.wl-row {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto;
  gap: 4px 16px;
  align-items: center;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line-2);
  border-left: 3px solid transparent;
}
.wl-row:last-of-type { border-bottom: 0; }
.wl-row.wl-top { border-left-color: var(--accent); background: rgba(45, 113, 182, 0.04); }
.wl-rank { font: 500 12px var(--mono); color: var(--mute); }
.wl-top .wl-rank { color: var(--accent); }
.wl-t { font-weight: 600; font-size: 15px; color: var(--ink); }
.wl-d { font-size: 13.5px; color: var(--ink-2); margin-top: 2px; }
.wl-act {
  font: 500 11px var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  padding: 3px 8px;
  border: 1px solid var(--line);
  border-radius: 2px;
  white-space: nowrap;
}
.wl-top .wl-act { color: var(--accent); border-color: var(--accent); }
.wl.is-armed .wl-row { opacity: 0; transition: opacity .5s ease; }
.wl.is-armed.is-live .wl-row { opacity: 1; }
.wl-row:nth-of-type(2) { transition-delay: .06s; }
.wl-row:nth-of-type(3) { transition-delay: .12s; }
.wl-row:nth-of-type(4) { transition-delay: .18s; }
.wl-row:nth-of-type(5) { transition-delay: .24s; }

.sumry {
  margin: 30px 0;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 2px;
  overflow: hidden;
}
.sumry-plain { padding: 20px 22px 18px; border-left: 3px solid var(--accent); }
.sumry-plain .stamp { display: block; margin-bottom: 8px; color: var(--accent); }
.sumry-plain p { margin: 0; font-size: 16.5px; line-height: 1.55; color: var(--ink); }
.sumry-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 22px;
  padding: 14px 22px;
  border-top: 1px solid var(--line);
  background: var(--pale);
}
.sumry-name { font-weight: 600; font-size: 15px; color: var(--ink); }
.sumry-val {
  font-family: var(--display);
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.sumry-val small { font: 400 12px var(--mono); color: var(--mute); }
.sumry-ref, .sumry-status { font: 400 12px/1.6 var(--mono); color: var(--mute); }
.sumry-flag {
  font: 500 11px var(--mono);
  letter-spacing: 0.08em;
  padding: 2px 7px;
  border: 1px solid currentColor;
  border-radius: 2px;
  color: var(--con);
}
.sumry-status { flex-basis: 100%; }
.sumry.is-armed .sumry-line { opacity: 0; transition: opacity .6s ease .15s; }
.sumry.is-armed.is-live .sumry-line { opacity: 1; }

.mled {
  margin: 30px 0;
  border: 1px solid var(--line);
  background: var(--paper);
  border-radius: 2px;
  overflow: hidden;
}
.mled-row {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) 96px 96px;
  gap: 4px 18px;
  align-items: baseline;
  padding: 12px 18px;
  border-bottom: 1px solid var(--line-2);
}
.mled-row:last-of-type { border-bottom: 0; }
.mled-hd {
  background: var(--pale);
  border-bottom: 1px solid var(--line);
}
.mled-hd span {
  font: 500 11px var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mute);
}
.mled-d { font: 400 12.5px/1.6 var(--mono); color: var(--mute); }
.mled-e { font-size: 15px; color: var(--ink); }
.mled-a, .mled-b {
  font: 500 14px/1.6 var(--mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--ink);
}
.mled-a { color: var(--ink-2); }
.mled-neg { color: var(--accent); }
.mled-hd .mled-a, .mled-hd .mled-b { text-align: right; }
.mled.is-armed .mled-row:not(.mled-hd) { opacity: 0; transition: opacity .5s ease; }
.mled.is-armed.is-live .mled-row { opacity: 1; }
.mled-row:nth-of-type(3) { transition-delay: .06s; }
.mled-row:nth-of-type(4) { transition-delay: .12s; }
.mled-row:nth-of-type(5) { transition-delay: .18s; }
.mled-row:nth-of-type(6) { transition-delay: .24s; }
.mled-row:nth-of-type(7) { transition-delay: .30s; }

@media (max-width: 620px) {
  .mled-row { grid-template-columns: minmax(0, 1fr) 84px; }
  .mled-d { grid-column: 1 / -1; }
  .mled-e { grid-column: 1; }
  .mled-a { grid-column: 2; grid-row: 2; }
  .mled-b { grid-column: 1 / -1; text-align: left; color: var(--mute); }
  .mled-b::before { content: "balance "; font-weight: 400; color: var(--mute); }
  .mled-hd { display: none; }
  .wl-row { grid-template-columns: 28px minmax(0, 1fr); }
  .wl-act { grid-column: 2; justify-self: start; }
  .ledg-row { grid-template-columns: 1fr auto; }
  .ledg-auth { grid-column: 1 / -1; }
}

/* --- buttons ------------------------------------------------------------ */

.btn {
  display: inline-block;
  font: 500 14px/1 var(--mono);
  text-decoration: none;
  padding: 14px 20px;
  border-radius: 2px;
  background: var(--ink);
  color: var(--paper);
  border: 1px solid var(--ink);
  margin: 0 10px 10px 0;
}
.btn:hover { background: var(--accent); border-color: var(--accent); color: var(--paper); }
/* Row emitted by the ("cta", …) block. margin-bottom absorbs the buttons' own
   10px so a CTA row does not sit tighter than the paragraphs around it. */
.ctarow { margin: 26px 0 16px; }
.btn.ghost { background: none; color: var(--ink); }
.btn.ghost:hover { background: var(--ink); color: var(--paper); }
.sec.dark .btn {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--dark);
}
.sec.dark .btn:hover { background: var(--sage); border-color: var(--sage); }

/* --- closing band ------------------------------------------------------- */

.band {
  padding: 82px 0;
  background: var(--dark);
  color: var(--sage);
  text-align: center;
}
.band h2 {
  color: #fff;
  font-size: clamp(26px, 3.2vw, 38px);
  max-width: 24ch;
  margin-inline: auto;
}
.band p {
  max-width: 56ch;
  margin: 20px auto 30px;
  font-size: 16.5px;
}
.band .btn { background: #fff; border-color: #fff; color: var(--dark); }
.band .btn:hover { background: var(--sage); border-color: var(--sage); }
.band .btn.ghost { background: none; color: #fff; border-color: rgba(255, 255, 255, 0.4); }
.band .btn.ghost:hover { background: #fff; color: var(--dark); border-color: #fff; }

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

/* The footer is dark. It reuses the tokens .sec.dark already uses -- --dark
   ground, --sage body, #fff for emphasis -- so it reads as the same surface
   the dark sections do rather than as a third palette. */
.btm {
  padding: 0 0 30px;
  background: var(--dark-2);
  color: var(--sage);
  font-size: 14.5px;
}
.fgrid {
  display: grid;
  grid-template-columns: 1.6fr repeat(3, 1fr);
  gap: 34px;
}
.fbrand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--display);
  font-weight: 750;
  font-size: 19px;
  letter-spacing: -0.03em;
  color: #fff;
  margin-bottom: 12px;
}
.fbrand .wm span { color: var(--brand); }
.fnote { color: rgba(255, 255, 255, 0.58); font-size: 14px; max-width: 34ch; margin: 0; }

/* The footer used to carry a full-bleed photographic band here. Two attempts
   failed for the same underlying reason and it is worth writing down: a fixed
   height plus object-fit: cover means the wider the viewport, the more the
   image is zoomed and the less of it you see -- 43% of the source height at
   1280px, 29% at 1920px -- so the composition degrades exactly where there is
   most room for it. And any subject that is a *row of things* collapses into a
   barcode at band height, which is what the generated 81-mark strip looked
   like and why it was replaced in the first place.

   If art comes back here it needs to survive both: a subject that is not a
   repeating row, and either a constrained figure with a fixed aspect ratio or
   a height that scales with the width. */
.btm > .wrap {
  padding-top: 64px;
}

.btm h2 {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.54);
  margin-bottom: 14px;
  font-weight: 500;
}
.btm ul { list-style: none; margin: 0; padding: 0; }
.btm li { margin-bottom: 9px; }
.btm li a { color: var(--sage); text-decoration: none; }
.btm li a:hover { color: #fff; text-decoration: underline; }

.fbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 26px;
  margin-top: 46px;
  padding-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  font: 400 12px/1.5 var(--mono);
  color: rgba(255, 255, 255, 0.56);
}

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

@media (max-width: 1080px) {
  .mx-grid thead th { font-size: 10.5px; }
  .fgrid { grid-template-columns: 1fr 1fr 1fr; }
  .fgrid > div:first-child { grid-column: 1 / -1; }
}

@media (max-width: 900px) {
  .tri, .cards { grid-template-columns: 1fr; gap: 26px; }
  .tri { margin-top: 32px; padding-top: 26px; }
  .mx-detail { grid-template-columns: 1fr; gap: 18px; }
  /* `.top nav { display: none }` used to live here, which is why a phone had no
     navigation at all. The burger and the panel below replace it. */
  /* .signin used to carry margin-left:auto here, because with the nav hidden it
     was the first element after the brand. It now lives inside the panel, where
     that rule right-aligned it against a full-width CTA. The burger owns the
     push instead. */
  .signin { margin-left: 0; }
  .top .wrap { gap: 16px; }
  .sec { padding: 64px 0; }
  .hero { padding: 54px 0 48px; }
}

/* Below this the 9x9 grid stops being usable, so swap in the picker. */
@media (max-width: 760px) {
  .mx-grid { display: none; }
  .mx-pick { display: block; }
  .mx-head { padding: 16px; }
  .mx-legend { margin-left: 0; }
  .mx { margin-top: 32px; }
}

@media (max-width: 620px) {
  body { font-size: 16.5px; }
  :root { --pad: 18px; }
  .conn thead { display: none; }
  .conn tr { display: block; padding: 16px 0; border-bottom: 1px solid var(--line); }
  .conn td { display: block; border: 0; padding: 0 0 6px; width: auto; }
  .conn .nm { font-size: 17px; }
  .dt thead { display: none; }
  .dt tr { display: block; padding: 14px 0; border-bottom: 1px solid var(--line); }
  .dt td, .dt tbody th { display: block; border: 0; padding: 0 0 5px; width: auto; }
  .trace { --t-col: 44px; --t-gap: 7px; }
  .trace .t { font-size: 11.5px; }
  .fgrid { grid-template-columns: 1fr; gap: 28px; }
  .band { padding: 62px 0; }
  .btn { display: block; text-align: center; margin-right: 0; }
  /* The header runs out of room around here: brand, sign-in, and the CTA
     together need more than the viewport. The mark alone identifies the site,
     so the wordmark goes visually hidden rather than display:none — the link
     keeps its accessible name because the image is decorative (alt=""). */
  .top .brand .wm {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .top .brand { gap: 0; }
  /* Same trade with the lockup: swap the wide image for the square mark, which
     is a real element swap rather than hiding text, so alt carries the name. */
  .top .has-lockup .lockup { display: none; }
  .top .has-lockup .mark { display: block; }
}

/* --- preferences and print --------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* No cascade, and no waiting to be scrolled into view either: the network
     is simply present, in its final state, from the first paint. */
  .nx.is-armed .nx-edges,
  .nx.is-armed .nx-packets { opacity: 1; transition: none; }
  .fl-pulse, .nx-pulse { animation: none; opacity: 0; }
  .ledg.is-armed .ledg-row { opacity: 1; transition: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .cards a:hover { transform: none; }
  /* The blanket rule above sets a 0.01ms duration, which would leave the wash
     frozen at the end of its travel. Switch it off outright instead. */
  .hero::after, .band::after { animation: none !important; transform: none; }
}

@media (prefers-contrast: more) {
  :root { --mute: #c8d0d8; --line: rgba(255, 255, 255, 0.4); }
  .mx-grid th, .mx-grid td { border-color: #7d848b; }
  /* The dark footer's secondary text is set in rgba white, which is exactly
     the kind of low-contrast copy this query exists to rescue. */
  .btm { color: #fff; }
  .fnote { color: rgba(255, 255, 255, 0.85); }
  .btm h2 { color: rgba(255, 255, 255, 0.8); }
  .btm li a { color: #fff; }
  .fbar { color: rgba(255, 255, 255, 0.8); border-top-color: rgba(255, 255, 255, 0.35); }
}

@media print {
  .top, .band, .skip, .mx-pick, .cta-sm { display: none; }
  body { font-size: 11pt; }
  .sec, .hero { padding: 18pt 0; border: 0; }
  .sec.dark, .band { background: none; color: #000; }
  .sec.dark h2, .sec.dark h3 { color: #000; }
  /* The footer went dark, so it needs the same treatment the dark sections
     get here, or it prints as a slab of ink. The band is decoration and is
     dropped outright. */
  .btm { background: none; color: #000; }
  .btm h2, .btm li a, .fnote, .fbar, .fbrand { color: #000; }
  .fbar { border-top-color: #999; }
  .mx { break-inside: avoid; }
  a { text-decoration: underline; }
}


/* --- header dropdown -----------------------------------------------------
   Built on <details name="nav">: the exclusive-accordion behaviour, Escape,
   and keyboard activation are the browser's rather than ours. mx.js adds .js
   to <html>, and only then may the panel hide behind the burger -- with the
   script blocked the nav renders as a plain stacked list, which is usable
   rather than absent. The chevron is a rotated border, so there is no paint
   value in this file; see HANDOFF.md rules 2 and 3. */

.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.nav { display: flex; align-items: center; gap: 22px; margin-left: auto; }

.navgrp { position: relative; }

.navgrp > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 14.5px;
  color: var(--ink-2);
  padding: 4px 0;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  user-select: none;
}
.navgrp > summary::-webkit-details-marker { display: none; }
.navgrp > summary::marker { content: ""; }
.navgrp > summary::after {
  content: "";
  width: 5px;
  height: 5px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  opacity: 0.55;
  transition: transform 120ms ease;
}
.navgrp > summary:hover { color: var(--ink); border-bottom-color: var(--accent); }
.navgrp[open] > summary { color: var(--ink); border-bottom-color: var(--accent); }
.navgrp[open] > summary::after { transform: translateY(1px) rotate(225deg); }
.navgrp > summary:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

.navpanel {
  position: absolute;
  top: calc(100% + 12px);
  left: -18px;
  min-width: 272px;
  background: #121a24;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 3px;
  box-shadow: 0 24px 60px -16px rgba(0, 0, 0, 0.7);
  padding: 16px 18px 14px;
  z-index: 60;
}

.navblurb {
  font: 400 11px/1.4 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #9fb3c8;
  margin: 0 0 12px;
  padding-bottom: 11px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}

.navlinks { display: grid; gap: 2px; }
.navlinks a {
  display: block;
  font-size: 15px;
  color: #eef2f6;
  text-decoration: none;
  padding: 7px 10px;
  margin: 0 -10px;
  border-radius: 2px;
  white-space: nowrap;
}
.navlinks a:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }

.navtail { display: flex; align-items: center; gap: 22px; }

/* 44x44 is the platform minimum tap target on both iOS and Android, and this
   was 42. Two pixels is not a design decision, it is a miss. */
.burger {
  display: none;
  margin-left: auto;
  flex: none;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 1px solid var(--line);
  border-radius: 3px;
  cursor: pointer;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
}
.burger .bl {
  display: block;
  width: 17px;
  height: 1.5px;
  background: var(--ink);
  transition: transform 140ms ease, opacity 140ms ease;
}
.burger[aria-expanded="true"] .bl:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.burger[aria-expanded="true"] .bl:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] .bl:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

@media (max-width: 900px) {
  .burger { display: inline-flex; }

  .nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    display: block;
    margin: 0;
    background: #0d141c;
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    box-shadow: 0 24px 48px -18px rgba(0, 0, 0, 0.7);
    padding: 6px var(--pad) 18px;
    max-height: calc(100vh - 66px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* Hidden by default and opened by mx.js. assets/nojs.css, linked from a
     <noscript> in the head, reverses this when the script cannot run. */
  .nav { display: none; }
  .nav.open { display: block; }

  .navgrp { border-bottom: 1px solid var(--line-2); }
  .navgrp > summary {
    display: flex;
    justify-content: space-between;
    width: 100%;
    padding: 15px 0;
    font-size: 16px;
    border-bottom: none;
  }
  .navgrp[open] > summary { border-bottom: none; }

  .navpanel {
    position: static;
    min-width: 0;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0 0 12px 2px;
  }
  .navlinks a { padding: 11px 0; margin: 0; font-size: 15.5px; white-space: normal; }
  .navlinks a:hover { background: none; }

  .navtail { display: grid; gap: 14px; padding-top: 18px; }
  /* 14px mono line + 4px padding measured 22px tall in the panel, half the
     44px minimum. Every other target in the panel already cleared it. */
  .navtail .signin { padding: 15px 0; }
  .navtail .cta-sm { text-align: center; padding: 14px 16px; }
}


/* --- cinematic panels ------------------------------------------------------
   The SpaceX register, adopted 2026-09-02: one full-bleed picture or loop per
   screen, one headline, one line, one button. The media covers the panel, a
   gradient from the bottom keeps the type legible on any frame, and the text
   sits bottom-left inside the site wrap. Panels are min-height rather than
   fixed so a long headline can never overflow its picture. Every video keeps
   class="figvid" so mx.js plays it on the same terms as any other figure. */

.panel {
  position: relative;
  min-height: 88svh;
  display: flex;
  align-items: flex-end;
  background: var(--paper);
  overflow: hidden;
  isolation: isolate;
}
.panel.hero1 { min-height: 100svh; }
.panel.short { min-height: 72svh; }
.panel-media,
.panel-media img,
.panel-media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.panel-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(7, 10, 14, 0.40) 0%, rgba(7, 10, 14, 0) 26%, rgba(7, 10, 14, 0.30) 52%, rgba(7, 10, 14, 0.82) 74%, rgba(7, 10, 14, 0.96) 100%);
}
.panel-body {
  position: relative;
  z-index: 1;
  width: 100%;
  padding: 0 0 clamp(48px, 7vh, 96px);
}
.panel .eyebrow {
  margin-bottom: 14px;
  color: #a9dcff;
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.7), 0 0 2px rgba(0, 0, 0, 0.6);
}
.panel h1, .panel h2, .panel .line { text-shadow: 0 2px 22px rgba(0, 0, 0, 0.45); }
.panel h1, .panel h2 {
  font-size: clamp(36px, 5.4vw, 74px);
  line-height: 1.02;
  letter-spacing: -0.035em;
  max-width: 16ch;
  color: #fff;
}
.panel.hero1 h1 { font-size: clamp(40px, 6.4vw, 88px); }
.panel .line {
  margin: 20px 0 0;
  max-width: 44ch;
  font-size: clamp(16.5px, 1.35vw, 19.5px);
  line-height: 1.5;
  color: var(--ink-2);
}
.panel .ctarow { margin: 28px 0 0; }
.panel .btn { margin-bottom: 0; }
.panel .btn.ghost { color: #fff; border-color: rgba(255, 255, 255, 0.45); }
.panel .btn.ghost:hover { background: #fff; color: var(--dark); border-color: #fff; }
.panel figcaption {
  position: absolute;
  right: var(--pad);
  bottom: 14px;
  z-index: 1;
  max-width: 34ch;
  text-align: right;
  font: 400 11.5px/1.5 var(--mono);
  color: rgba(255, 255, 255, 0.55);
}

/* A panel emitted inside a page body breaks out of the text column to the
   viewport edges. 50% here is half the column; 50vw is half the viewport. */
.art > .panel {
  max-width: none;
  width: 100vw;
  margin: 56px 0 56px calc(50% - 50vw);
}
.doc.has-rail .art > .panel { margin-left: calc(50% - 50vw); }

/* Stats: three figures, the only place numbers lead. */
.stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
  padding: 72px 0;
  border-top: 1px solid var(--line-2);
  border-bottom: 1px solid var(--line-2);
}
.stats b {
  display: block;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(38px, 4.6vw, 64px);
  letter-spacing: -0.04em;
  line-height: 1;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
.stats span {
  display: block;
  margin-top: 12px;
  font: 400 14px/1.5 var(--sans);
  color: var(--mute);
  max-width: 26ch;
}

/* Three points, one sentence each. Reuses .tri's grid. */
.three { margin-top: 40px; padding-top: 0; border-top: 0; }
.three h3 { color: #fff; }

/* The audience index on the home page: six lines, not six paragraphs. */
.who-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0 40px;
  border-top: 1px solid var(--line);
  margin-top: 36px;
}
.who-list a {
  display: block;
  padding: 22px 0;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
  color: var(--ink);
}
.who-list a b {
  display: block;
  font-family: var(--display);
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.025em;
  color: #fff;
}
.who-list a span { display: block; margin-top: 6px; font-size: 14.5px; color: var(--mute); }
.who-list a:hover b { color: var(--accent); }

/* Interior body copy sits on the ground, narrower and quieter than before. */
.cine + .sec { border-top: 0; }
.doc .lead { color: var(--ink); }

@media (max-width: 900px) {
  .panel { min-height: 78svh; }
  .panel.hero1 { min-height: 92svh; }
  .panel h1, .panel h2 { max-width: 14ch; }
  .stats { grid-template-columns: 1fr; gap: 28px; padding: 48px 0; }
  .who-list { grid-template-columns: 1fr; gap: 0; }
  .panel figcaption { display: none; }
}
