:root {
  --bg: #fbfaf8;  --panel: #fff;  --ink: #1b1a18;  --mute: #6f6a63;  --line: #e4e0d9;
  --accent: #2f6f5e;  --accent-soft: #e3efe9;  --warn: #a8541c;  --bad: #9c2f2f;
  --gold: #b8860b;
  --radius: 7px;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #16181a;  --panel: #1e2124;  --ink: #e9e6e1;  --mute: #9a948c;  --line: #2f3438;
    --accent: #5fbfa3;  --accent-soft: #22403a;  --warn: #d99553;  --bad: #e0776f;
    --gold: #e8c25a;
  }
}
* { box-sizing: border-box; }
/* An author `display` beats the UA stylesheet's [hidden] rule, so say it explicitly. */
[hidden] { display: none !important; }
body { margin: 0; background: var(--bg); color: var(--ink); font: 14px/1.5 var(--sans); }
a { color: var(--accent); }
h1 { font-size: 22px; margin: 0 0 6px; letter-spacing: -0.01em; }
h2 { font-size: 15px; margin: 0 0 8px; }
code { font-family: var(--mono); font-size: 12px; background: var(--accent-soft);
       padding: 1px 5px; border-radius: 4px; }

/* ---------------------------------------------------------------- chrome */
.topbar { display: flex; align-items: center; gap: 22px; padding: 0 22px; height: 52px;
  background: var(--panel); border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 30; }
.brand { font-weight: 650; letter-spacing: -0.02em; }
.topbar nav { display: flex; gap: 4px; }
.topbar nav a { padding: 5px 12px; border-radius: var(--radius); text-decoration: none;
  color: var(--mute); font-weight: 500; }
.topbar nav a.active, .topbar nav a:hover { background: var(--accent-soft); color: var(--accent); }
.topbar .status { margin-left: auto; color: var(--mute); font: 12px var(--mono); }
.warn { color: var(--warn); }
main { padding: 26px 22px 60px; max-width: 1500px; margin: 0 auto; }
.intro { margin-bottom: 22px; max-width: 780px; }
.intro p { color: var(--mute); margin: 0; }
footer { border-top: 1px solid var(--line); padding: 16px 22px; color: var(--mute); font-size: 12px; }

/* ---------------------------------------------------------------- controls */
.controls { display: flex; flex-wrap: wrap; gap: 16px 22px; align-items: flex-start;
  padding: 16px 18px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); margin-bottom: 18px; }
.ctl { display: flex; flex-direction: column; gap: 6px; }
.ctl.grow { flex: 1; min-width: 200px; }
.ctl > label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--mute); font-weight: 600; }
.hint { text-transform: none; letter-spacing: 0; font-weight: 400; opacity: .75; }
input[type=search], select, button { font: inherit; color: var(--ink); background: var(--bg);
  border: 1px solid var(--line); border-radius: var(--radius); padding: 6px 10px; }
input[type=search] { width: 100%; }
button { cursor: pointer; }
button:hover { border-color: var(--accent); color: var(--accent); }
input[type=range] { accent-color: var(--accent); }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip { padding: 5px 11px; border-radius: 99px; border: 1px solid var(--line);
  background: var(--bg); color: var(--mute); cursor: pointer; font-size: 13px; }
.chip.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent);
  font-weight: 500; }

/* ---------------------------------------------------------------- summary cards */
.summary { display: grid; gap: 12px; margin-bottom: 20px;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 13px 15px; }
.card-h { display: flex; justify-content: space-between; font-size: 11px; font-weight: 650;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--mute); }
.card-t { font-weight: 600; margin: 3px 0 10px; }
.nums { display: flex; flex-wrap: wrap; gap: 10px 16px; }
.nums div { display: flex; flex-direction: column; }
.nums b { font: 600 19px/1.1 var(--mono); }
.nums span { font-size: 10px; color: var(--mute); text-transform: uppercase; letter-spacing: .04em; }
.nums .bad b { color: var(--bad); }
.nums .good b { color: var(--accent); }

/* Measured against the claim. The bar is scaled to whichever of the two is larger, so the
   filled part is what the panel actually measures and the marked-off part is the distance
   to the marketing number. Calculated indices are deliberately absent from it. */
.claimbar { margin-top: 2px; }
.bar { position: relative; height: 10px; border-radius: 3px; overflow: hidden;
  background: var(--line); }
.bar > div { position: absolute; top: 0; bottom: 0; }
.bar .fill { left: 0; background: var(--accent); }
.bar .over { background: var(--accent); opacity: .45; }
.bar .short { background: repeating-linear-gradient(-45deg,
    var(--bad) 0 2px, transparent 2px 5px); opacity: .8; }
.bar .tick { width: 2px; margin-left: -1px; background: var(--ink); opacity: .55; }
.barfoot { display: flex; justify-content: space-between; gap: 10px; margin-top: 6px;
  font-size: 11px; color: var(--mute); }
.barfoot b { font: 600 15px/1 var(--mono); color: var(--ink); }
.barfoot span:first-child { display: flex; align-items: baseline; gap: 5px; }
.barfoot .bad { color: var(--bad); }
.barfoot .good { color: var(--accent); }
.alsocalc { margin-top: 8px; font-size: 11px; color: var(--mute); }
.price { margin-top: 10px; font-size: 12px; color: var(--mute); }

/* ---------------------------------------------------------------- legend + matrix */
.legend { display: flex; align-items: center; gap: 16px; color: var(--mute); font-size: 12px;
  margin-bottom: 10px; }
.legend span { display: flex; align-items: center; gap: 6px; }
.legend .sep { border-left: 1px solid var(--line); height: 14px; }
i.cell { width: 13px; height: 13px; border-radius: 3px; display: inline-block; }
i.cell.inc { background: var(--accent); }
i.cell.abs { border: 1px solid var(--line); }

.kindblock { margin-bottom: 26px; }
.kindhead { display: flex; align-items: center; gap: 9px; font-size: 15px; margin: 0 0 9px; }
.kindhead span { font: 400 12px var(--mono); color: var(--mute); }
.kindhead abbr { display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%; border: 1px solid var(--line);
  font-size: 10px; color: var(--mute); cursor: help; text-decoration: none; }
.kindhead abbr:hover { border-color: var(--accent); color: var(--accent); }

.matrix-wrap { overflow: auto; max-height: 74vh; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--panel); }
table.matrix { border-collapse: separate; border-spacing: 0; font-size: 13px;
  min-width: 100%; }
.matrix th, .matrix td { border-bottom: 1px solid var(--line); }
.matrix thead th { position: sticky; top: 0; z-index: 20; background: var(--panel);
  padding: 9px 12px; text-align: left; vertical-align: bottom; min-width: 116px;
  border-bottom: 2px solid var(--line); }
.matrix thead th.rowhead { z-index: 25; }
.matrix .rowhead { position: sticky; left: 0; background: var(--panel); z-index: 10;
  padding: 6px 12px; min-width: 250px; white-space: nowrap; }
.th-analyte { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--mute); }
.th-org { font-size: 11px; color: var(--mute); }
.th-panel { font-weight: 600; }
.th-meta { font: 11px var(--mono); color: var(--mute); margin-top: 2px; }
.catrow td { background: var(--bg); font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; color: var(--mute); padding: 7px 12px !important; }
.catrow .rowhead { background: var(--bg); }
.matrix tbody tr:hover .rowhead { background: var(--accent-soft); }
.matrix tbody tr:hover td.c { background: color-mix(in srgb, var(--accent-soft) 45%, transparent); }
.an { font-weight: 500; }
.tag { font: 10px var(--mono); border: 1px solid var(--line); border-radius: 3px;
  padding: 0 4px; margin-left: 7px; color: var(--mute); }
td.c { text-align: center; position: relative; }
td.c::after { content: ""; position: absolute; inset: 50% auto auto 50%;
  transform: translate(-50%, -50%); width: 13px; height: 13px; border-radius: 3px; }
td.c.inc::after { background: var(--accent); }
td.c.abs::after { border: 1px solid var(--line); opacity: .5; }
/* Included, but not everywhere the panel is sold. The block is hollowed out and the markets
   that DO get it are printed inside, because "included" and "included if you are in the United
   States" are different answers and a solid square would give the first for the second. */
td.c.part::after { background: none; border: 1.5px solid var(--accent); width: 22px;
  border-radius: 3px; }
td.c.part { font: 9px/1 var(--mono); color: var(--accent); letter-spacing: -.2px;
  position: relative; z-index: 1; }
.empty { padding: 26px; color: var(--mute); text-align: center; }

/* ---------------------------------------------------------------- unmapped */
.unmapped { margin-top: 26px; padding: 16px 18px; background: var(--panel);
  border: 1px solid var(--line); border-left: 3px solid var(--warn);
  border-radius: var(--radius); max-width: 900px; }
.unmapped p { color: var(--mute); margin: 0 0 10px; }
.unmapped ul { list-style: none; padding: 0; margin: 0 0 12px; }
.unmapped li { display: flex; gap: 10px; align-items: center; padding: 4px 0; }
.unmapped li { flex-wrap: wrap; }
.unmapped li b { font-weight: 600; }
.unmapped li span { color: var(--mute); font: 11px var(--mono); }
.unmapped li em { flex-basis: 100%; color: var(--mute); font-size: 12px; font-style: normal;
  padding-left: 2px; }
.unmapped .fix { font-size: 12px; margin: 0; }

/* ---------------------------------------------------------------- basket page */
.basket-grid { display: grid; grid-template-columns: 1fr 320px; gap: 20px; align-items: start; }
@media (max-width: 940px) { .basket-grid { grid-template-columns: 1fr; } }
.box { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 18px; margin-bottom: 16px; }
table.lines { width: 100%; border-collapse: collapse; font-size: 13px; }
table.lines th { text-align: left; font-size: 11px; text-transform: uppercase; color: var(--mute);
  letter-spacing: .06em; padding: 0 10px 8px 0; border-bottom: 1px solid var(--line); }
table.lines td { padding: 9px 10px 9px 0; border-bottom: 1px solid var(--line);
  vertical-align: top; }
table.lines tr:last-child td { border-bottom: 0; }
/* The visit fee leads the list and is not a product: it is charged once by this lab in this
   country, whatever is run on the sample, so it reads as a heading row rather than a line. */
/* How the line is ordered: the lab's catalogue code, or the NABM act number. It has a column
   of its own because at a counter these are read as a set -- one finger down one column --
   rather than hunted for one product name at a time. Outlined rather than filled, because it
   sits on every row and a table of coloured chips reads as decoration.
   Scoped to the two elements that ARE codes, `code` and `a`: the tooltip writes an indicator's
   name as `b.ref`, which the bare class selector would also have boxed -- and a chip's 4px of
   padding on the name that opens every tooltip reads as an indent nothing else on the line has. */
code.ref, a.ref { font: 11px/1.4 var(--mono); color: var(--mute); background: none; font-weight: 400;
  border: 1px solid var(--line); border-radius: 4px; padding: 0 4px; white-space: nowrap;
  display: inline-block; }
code.ref { cursor: help; }
/* The code is the link, not the product name. What opens is the page this price was read from,
   which is the page selling this reference -- so the arrow belongs on the reference. It is part
   of the anchor, not a label beside it: it means "opens elsewhere". */
table.lines td a.ref { color: var(--ink); text-decoration: none;
  border: 1px solid var(--line); }
table.lines td a.ref:hover, table.lines td a.ref:focus-visible { border-color: var(--accent);
  color: var(--accent); }
/* Not every product has a reference to order it on: a compound cotation is a billing breakdown
   rather than a thing, and some catalogues publish no code at all. Where there is a page but no
   code, the link goes out unboxed -- an outlined chip on forty such rows would frame the absence
   and read as a column of codes that are not there. */
table.lines td a.ref.plain { font: italic 11px/1.4 var(--sans); color: var(--mute);
  border: 0; padding: 0; }
.ext { font-size: 10px; margin-left: 3px; }
table.lines td a { text-decoration: none; border-bottom: 1px solid var(--accent-soft); }
table.lines td a:hover { border-bottom-color: var(--accent); }
/* Five columns on a table that has to survive a phone and a printer. Counts are words, not
   figures, so they stay left-aligned. Each count holds together -- "2 biomarkers" split over
   two lines is a column of noise -- but a line delivering two kinds at once may wrap BETWEEN
   them rather than widen the column for every row that does not. Only the price is a number
   and only the price is right-aligned. */
.table-wrap { overflow-x: auto; }
table.lines td.code { white-space: nowrap; }
table.lines td.count .n { white-space: nowrap; }
table.lines td.count .unit { color: var(--mute); }
.none { color: var(--mute); }
/* A line whose only delivery is a substitution would otherwise read "—" against a name the
   cell beside it lists in full. The count stays markers delivered AS ASKED -- the number the
   rest of the page quotes -- and the swap is stated under it rather than folded into it. */
.subst-note { color: var(--warn); font-size: 11px; margin-top: 3px; white-space: normal; }

table.lines tr.visit td { background: var(--accent-soft); }
table.lines tr.visit td:first-child { border-left: 2px solid var(--accent); padding-left: 8px; }
table.lines tfoot td { border-top: 2px solid var(--line); border-bottom: 0; font-size: 14px; }
.num { text-align: right; font-family: var(--mono); white-space: nowrap; }
.covers { color: var(--mute); font-size: 12px; margin-top: 3px; }
.covers .extra { color: var(--warn); }
.verdict { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.verdict .big { font: 650 30px/1 var(--mono); }
.verdict .vs { color: var(--mute); }
.pill { display: inline-block; padding: 3px 10px; border-radius: 99px; font-size: 12px;
  font-weight: 600; }
.pill.win { background: var(--accent-soft); color: var(--accent); }
.pill.lose { background: color-mix(in srgb, var(--bad) 14%, transparent); color: var(--bad); }
.kv { display: flex; justify-content: space-between; padding: 6px 0;
  border-bottom: 1px solid var(--line); font-size: 13px; }
.kv:last-child { border-bottom: 0; }
.kv span:first-child { color: var(--mute); }
.kv span:last-child { font-family: var(--mono); }
.taglist { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.taglist b, .taglist .tag-b { font: 500 12px var(--sans); background: var(--bg);
  border: 1px solid var(--line); border-radius: 4px; padding: 2px 8px; }
.gapbox { border-left: 3px solid var(--bad); }
.gapbox h2 { color: var(--bad); }

/* A SUBSTITUTION is neither a hit nor a gap, and it must not be able to pass for either.
   `--warn` rather than `--bad`, because nothing went wrong: the lab sold something BETTER
   than the panel asked for. But it is bordered and set apart from the plain covered names,
   because the reader is owed the fact that what arrives is not what was listed. */
.substbox { border-left: 3px solid var(--warn); }
.substbox h2 { color: var(--warn); }
ul.substlist { list-style: none; margin: 10px 0 0; padding: 0; font-size: 13px; }
ul.substlist li { padding: 7px 0; border-bottom: 1px solid var(--line); }
ul.substlist li:last-child { border-bottom: 0; }
ul.substlist .extra { color: var(--mute); font-size: 12px; margin-top: 3px; }

/* On the shopping-list row a substitution is NOT set apart: it reads inline among the names
   the product covers, in the same grey, because it is one of them -- something was delivered,
   and nothing was lost. The warning sign is the whole of the visible signal and the tooltip
   carries the rest, which keeps a row about one swapped test one line tall. */
.tip p { margin: 0 0 6px; }
.tip p:last-child { margin-bottom: 0; }
.subst-tag { color: var(--warn); font-size: 12px; margin-left: 6px; white-space: nowrap;
  border-bottom: 1px dotted currentColor; cursor: help; }

/* A box that splits into named halves -- "you get free" and "you still lose". The rule above
   each half is what keeps the two lists from reading as one. */
.box h3 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--mute);
  margin: 16px 0 0; padding-top: 12px; border-top: 1px solid var(--line); }
.box h3:first-of-type { margin-top: 12px; }
ul.blocked { list-style: none; margin: 8px 0 0; padding: 0; font-size: 13px; }
ul.blocked li { padding: 5px 0; border-bottom: 1px solid var(--line); }
ul.blocked li:last-child { border-bottom: 0; }
ul.blocked .extra { color: var(--warn); font-size: 12px; margin-left: 6px; }

/* ---------------------------------------------------------------- indicator tooltips */
/* The cue is a dotted underline on the name itself: the matrix is dense, and a badge per
   row would be 220 of them. Focusable, because a tooltip only reachable by mouse is a
   tooltip half the readers of a table never see. */
[data-tip] { cursor: help; text-decoration: underline dotted;
  text-decoration-color: color-mix(in srgb, var(--mute) 60%, transparent);
  text-decoration-thickness: 1px; text-underline-offset: 3px; }
[data-tip]:hover, [data-tip]:focus-visible { text-decoration-color: var(--accent); }
/* The same dotted rule, standing alone in the legend so the cue can be pointed at. */
i.cue { width: 13px; border-bottom: 1px dotted var(--mute); display: inline-block; }
[data-tip]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tip { position: fixed; left: 0; top: 0; z-index: 60; max-width: 350px;
  padding: 10px 13px; background: var(--panel); color: var(--ink);
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--radius); box-shadow: 0 8px 26px rgb(0 0 0 / 16%);
  font-size: 12.5px; line-height: 1.55; white-space: normal; pointer-events: none; }
.tip code { font-size: 11px; padding: 0 4px; }
.tip .ref { font-weight: 600; color: var(--accent); }

/* ---------------------------------------------------------------- panels × labs grid */
/* Page 1's matrix is 220 rows of one bit each, so its cell is a square. This one is 28 cells
   of four numbers, so the cell is a card: a figure, a bar and a foot line, sized to be read
   down a column rather than across a row -- comparing labs for one panel is the question, and
   the row is where that comparison happens. */
i.cell.part { background: linear-gradient(90deg, var(--accent) 55%, var(--line) 55%); }
i.cell.star { background: none; color: var(--gold); font-size: 13px; line-height: 1;
  width: auto; }

table.grid { width: 100%; }
table.grid thead th { min-width: 168px; }
table.grid .rowhead { min-width: 260px; white-space: normal; padding: 10px 12px; }
table.grid .rowhead .th-meta { white-space: nowrap; }
td.g { padding: 6px; vertical-align: top; border-left: 1px solid var(--line); }
/* The cell is the link, filling it: a target the size of the card rather than of the number
   inside it, on a table where every cell goes somewhere. */
a.gc { display: block; padding: 9px 11px 8px; border-radius: var(--radius); text-decoration: none;
  color: var(--ink); border: 1px solid transparent; background: var(--bg); }
a.gc:hover, a.gc:focus-visible { border-color: var(--accent); background: var(--accent-soft); }
a.gc:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.gc-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.gc-top .big { font: 650 18px/1.2 var(--mono); letter-spacing: -0.02em; }
.gc-top .big .per { font: 400 10px var(--sans); color: var(--mute); margin-left: 2px; }
.gc-top .big .na { font: 400 12px var(--sans); color: var(--mute); }
/* The saving sits beside the price rather than under it, because it is the same fact read a
   second way and the two are meant to be taken in together. It is a phrase rather than a
   figure -- "51% more" -- so it is set in the text face, where the price is not. */
.delta { font: 600 11.5px var(--sans); color: var(--mute); border: 1px solid var(--line);
  border-radius: 4px; padding: 1px 5px; white-space: nowrap; }
.delta.hot { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 40%, transparent); }
.delta.cold { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
a.gc .bar { height: 5px; margin: 7px 0 5px; }
a.gc .bar .fill { position: absolute; top: 0; bottom: 0; left: 0; background: var(--accent); }
/* Short of the list is hatched, not merely shorter: the same mark page 1 puts on a panel that
   measures less than it claims, for the same reason -- a bar can be read as a magnitude, and
   this one is a shortfall. */
a.gc .bar .fill.short { background: repeating-linear-gradient(-45deg,
  var(--warn) 0 3px, color-mix(in srgb, var(--warn) 45%, transparent) 3px 6px); }
.gc-foot { display: flex; justify-content: space-between; gap: 8px; font-size: 11px;
  color: var(--mute); font-family: var(--mono); }
.gc-foot .of { opacity: .75; }
.gc-foot .sub { color: var(--warn); }
.gc-foot .xtra { color: var(--accent); }
.gc-note { margin-top: 5px; font-size: 11px; color: var(--warn); }
.gc.err { font-size: 12px; color: var(--mute); padding: 9px 11px; }
/* The star leads the price rather than floating over the cell's corner, where it crossed the
   border the same cell draws for being the leader -- two marks for one fact, overlapping. Inline
   it cannot collide with anything: it takes its own space on the line it belongs to, and the
   corner it used to occupy belongs to the saving. Gold, because green is already spoken for on
   this page: it means coverage, on the bar directly underneath. */
td.g.lead a.gc { border-color: color-mix(in srgb, var(--gold) 55%, transparent); }
td.g.lead a.gc:hover, td.g.lead a.gc:focus-visible { border-color: var(--accent); }
.gc-top .big .best { color: var(--gold); font-size: 13px; margin-right: 5px; cursor: help; }
/* An unsolved cell is a shape, not a spinner: 28 of them turning at once is a page that looks
   broken while it is merely working. */
td.g.wait .ghost { height: 62px; border-radius: var(--radius); background: var(--bg);
  border: 1px dashed var(--line); }
table.grid .rowhead .th-meta.per { color: var(--ink); }
.notes { max-width: 900px; margin-top: 22px; }
.notes p { color: var(--mute); margin: 0 0 10px; }
.notes p:last-child { margin-bottom: 0; }
.notes b { color: var(--ink); font-weight: 600; }
