/* ==========================================================================
   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 {
  --ink:      #10161d;
  --ink-2:    #2c333b;
  --mute:     #646c75;
  --line:     #dde0e4;
  --line-2:   #eaecef;
  --paper:    #ffffff;
  --pale:     #f3f4f6;
  --dark:     #101923;
  --sage:     #c7cdd3;
  --accent:   #2d71b6;
  --accent-d: #23578c;
  /* 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;
}

img, svg { 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: 650;
  line-height: 1.12;
  letter-spacing: -0.02em;
  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(255, 255, 255, 0.92);
  backdrop-filter: saturate(140%) blur(8px);
  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; }

.top nav {
  display: flex;
  gap: 22px;
  margin-left: auto;
  flex-wrap: wrap;
}
.top nav a {
  font-size: 14.5px;
  color: var(--ink-2);
  text-decoration: none;
  padding: 4px 0;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.top nav a:hover { color: var(--ink); border-bottom-color: var(--accent); }

/* 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: #fff; }

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

.hero {
  padding: 76px 0 64px;
  background: linear-gradient(180deg, var(--pale), var(--paper));
  border-bottom: 1px solid var(--line);
}
.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);
}
.hero-foot .k b {
  font-family: var(--display);
  font-size: 21px;
  font-weight: 700;
  color: var(--ink);
  margin-right: 5px;
}

/* --- 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; }
.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 h4 {
  font-size: 16px;
  font-weight: 640;
  margin-bottom: 8px;
}
.note p { font-size: 15.5px; margin: 0; }
.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);
}

/* --- 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; }

@media (max-width: 620px) {
  .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: #fff;
  border: 1px solid var(--ink);
  margin: 0 10px 10px 0;
}
.btn:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
/* 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: #fff; }
.sec.dark .btn {
  background: #fff;
  border-color: #fff;
  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 ------------------------------------------------------------- */

.btm {
  padding: 62px 0 30px;
  background: var(--paper);
  border-top: 1px solid var(--line);
  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: var(--ink);
  margin-bottom: 12px;
}
.fbrand .wm span { color: var(--brand); }
.fnote { color: var(--mute); font-size: 14px; max-width: 34ch; margin: 0; }

.btm h4 {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mute);
  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(--ink-2); text-decoration: none; }
.btm li a:hover { color: var(--accent); text-decoration: underline; }

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

/* --- 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; }
  /* nav carried the margin-left:auto that pushed the header right; with it
     hidden, .signin becomes the first element after the brand and takes over. */
  .signin { margin-left: auto; }
  .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: #3f464d; --line: #9aa1a8; }
  .mx-grid th, .mx-grid td { border-color: #7d848b; }
}

@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; }
  .mx { break-inside: avoid; }
  a { text-decoration: underline; }
}
