:root {
  color-scheme: light;
  --surface-0: #f4f4f2;
  --surface-1: #fcfcfb;
  --border:    #dedcd6;
  --grid:      #e8e6e0;
  --text-primary:   #0b0b0b;
  --text-secondary: #52514e;
  --text-muted:     #78766f;
  --series-1: #2a78d6;   /* modelled / DNDC */
  --series-2: #eb6834;   /* observed */
  --series-3: #1baf7a;   /* third suite in comparison */
  --accent:   #2a78d6;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --surface-0: #121211;
    --surface-1: #1a1a19;
    --border:    #34342f;
    --grid:      #2b2b27;
    --text-primary:   #ffffff;
    --text-secondary: #c3c2b7;
    --text-muted:     #93918a;
    --series-1: #3987e5;
    --series-2: #d95926;
    --series-3: #199e70;
    --accent:   #3987e5;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--surface-0);
  color: var(--text-primary);
  font: 15px/1.55 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}

a { color: var(--accent); }

header.app {
  display: flex; align-items: baseline; gap: 1.25rem;
  padding: .85rem 1.5rem;
  background: var(--surface-1);
  border-bottom: 1px solid var(--border);
}
header.app h1 { font-size: 1rem; margin: 0; letter-spacing: .01em; }
header.app nav { display: flex; gap: 1rem; font-size: .9rem; }
header.app .spacer { margin-left: auto; }

main { max-width: 1400px; margin: 0 auto; padding: 1.5rem; }

h2 { font-size: 1.15rem; margin: 2rem 0 .35rem; }
h2:first-child { margin-top: 0; }
.sub { color: var(--text-muted); font-size: .875rem; margin: 0 0 1rem; }

.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.1rem 1.25rem;
  margin-bottom: 1.25rem;
}

/* ---- tables ---- */
.table-wrap { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: .875rem; }
th, td { padding: .45rem .7rem; text-align: right; white-space: nowrap; }
th:first-child, td:first-child,
th.left, td.left { text-align: left; }
thead th {
  border-bottom: 1px solid var(--border);
  color: var(--text-secondary); font-weight: 600;
  position: sticky; top: 0; background: var(--surface-1);
}
tbody tr { border-bottom: 1px solid var(--grid); }
tbody tr:hover { background: var(--surface-0); }
td.num { font-variant-numeric: tabular-nums; }
.muted { color: var(--text-muted); }
.best { font-weight: 700; color: var(--accent); }

/* ---- charts ---- */
.chart { max-width: 100%; height: auto; display: block; }
.chart .tick { fill: var(--text-muted); font-size: 11px; }
.chart .axis-title { fill: var(--text-secondary); font-size: 12px; }
.chart .panel-title { fill: var(--text-secondary); font-size: 10px; font-weight: 600; }

.panels {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: .4rem;
}
.panels svg.panel { width: 100%; }

.legend { display: flex; gap: 1.1rem; margin: .1rem 0 .9rem; font-size: .85rem;
          color: var(--text-secondary); flex-wrap: wrap; }
.legend-item { display: inline-flex; align-items: center; gap: .4rem; }
.swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }

/* ---- metric tiles ---- */
.tiles { display: flex; gap: 1.75rem; flex-wrap: wrap; }
.tile .label { font-size: .75rem; color: var(--text-muted);
               text-transform: uppercase; letter-spacing: .04em; }
.tile .value { font-size: 1.5rem; font-variant-numeric: tabular-nums; }

/* ---- controls ---- */
.controls { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap;
            margin-bottom: 1rem; font-size: .875rem; }
.controls a, .pill {
  padding: .22rem .6rem; border: 1px solid var(--border);
  border-radius: 999px; text-decoration: none; color: var(--text-secondary);
  background: var(--surface-1);
}
.controls a.on { background: var(--accent); color: #fff; border-color: var(--accent); }
/* A count or qualifier inside an active pill: --text-muted is a grey chosen
   against the page background and all but vanishes on the accent fill. */
.controls a.on .muted { color: rgba(255, 255, 255, .78); }
button {
  font: inherit; padding: .35rem .9rem; border-radius: 7px;
  border: 1px solid var(--accent); background: var(--accent); color: #fff;
  cursor: pointer;
}
.empty { color: var(--text-muted); font-style: italic; }
.chips { display: flex; flex-wrap: wrap; gap: .3rem .7rem; font-size: .8rem; }
.chips label { display: inline-flex; gap: .3rem; align-items: center; }

form.auth { max-width: 320px; }
form.auth input { width: 100%; padding: .5rem; margin-bottom: .7rem;
  border: 1px solid var(--border); border-radius: 7px;
  background: var(--surface-1); color: var(--text-primary); }
form.auth input[type="submit"] { width: auto; margin-bottom: 0;
  border-color: var(--accent); background: var(--accent); color: #fff;
  padding: .4rem 1rem; cursor: pointer; }

/* Signed-out pages: one card, centred, no nav to speak of. */
.auth-card { max-width: 420px; margin: 3.5rem auto; }
.auth-card h2 { margin-top: 0; }
.auth-foot { margin: 1rem 0 0; }
.flash { padding: .6rem 1rem; border-radius: 8px; background: var(--surface-1);
  border: 1px solid var(--border); margin-bottom: 1rem; }

.section-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
}
.section-head .sub { margin-bottom: .4rem; }

.side-by-side {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
  gap: 1.25rem; align-items: start;
}
.side-by-side h3 { font-size: 1rem; margin: 0 0 .2rem; }
.controls a.disabled { opacity: .4; pointer-events: none; }
.inline-picker { display: inline; }
.inline-picker select {
  font: inherit; font-size: .875rem; padding: .2rem .4rem;
  border: 1px solid var(--border); border-radius: 7px;
  background: var(--surface-1); color: var(--text-primary);
}
a.panel-link { text-decoration: none; display: block; }
a.panel-link:hover { outline: 2px solid var(--accent); border-radius: 6px; }

.pickers { display: flex; flex-direction: column; gap: .35rem; align-items: flex-end; }
.pickers .pick-label { min-width: 4.2rem; text-align: right; }
.pickers select { max-width: 22rem; }
.nav-picker {
  font: inherit; font-size: .875rem; padding: .2rem .4rem;
  border: 1px solid var(--border); border-radius: 7px;
  background: var(--surface-1); color: var(--text-primary);
}

/* ---- suite description ---- */
/* Chips are tinted with colour-mix over the existing tokens so they stay
   legible in both themes without a second hand-tuned palette. */
.chips { display: inline-flex; gap: .25rem; flex-wrap: wrap; }
.chip {
  display: inline-block; padding: .08rem .4rem; border-radius: 5px;
  font-size: .75rem; line-height: 1.45; white-space: nowrap;
  border: 1px solid var(--border); color: var(--text-secondary);
  background: var(--surface-0); cursor: help;
}
.chip-target { border-color: color-mix(in srgb, var(--series-1) 45%, var(--border));
               color: var(--series-1);
               background: color-mix(in srgb, var(--series-1) 9%, transparent); }
.chip-shape  { border-color: color-mix(in srgb, var(--series-2) 45%, var(--border));
               color: var(--series-2);
               background: color-mix(in srgb, var(--series-2) 9%, transparent); }
.chip-dim    { border-color: color-mix(in srgb, var(--series-3) 45%, var(--border));
               color: var(--series-3);
               background: color-mix(in srgb, var(--series-3) 9%, transparent); }
.chip-mod, .chip-init { color: var(--text-muted); }

.what-head { font-size: .95rem; margin: 0 0 .3rem; }
.what-line { margin: 0 0 .5rem; font-size: 1rem; color: var(--text-primary); }

table.terms { font-size: .85rem; margin-top: .5rem; }
table.terms td { vertical-align: top; }
table.terms td.left:nth-child(5) { max-width: 34rem; }

.chip-key { font-size: .85rem; color: var(--text-secondary); }
.chip-key ul { margin: .5rem 0 0; padding-left: 1.1rem; }
.chip-key li { margin-bottom: .3rem; }
.chip-key .chip { margin-right: .25rem; cursor: default; }

/* ---- design-grid cell (B x P) ---- */
.cell-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8rem; font-weight: 600; color: var(--text-primary);
  cursor: help;
}
.rnd { font-size: .72rem; margin-left: .15rem; }
/* The OSU capped ladder re-runs round 1's cells under a denitrifier_grow
   bound, so a suite and its twin print identical labels; this is the only
   thing that tells them apart at a glance. */
.capped {
  font-size: .68rem; font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase; margin-left: .3rem;
  padding: .06rem .34rem; border-radius: 999px; white-space: nowrap;
  color: #8a5300; background: #fdf0d5; border: 1px solid #f0d9a8;
  cursor: help;
}
@media (prefers-color-scheme: dark) {
  .capped { color: #f0c674; background: #3a2d14; border-color: #5c4720; }
}
.grid-cell { font-size: .875rem; margin: .1rem 0 .6rem;
             color: var(--text-secondary); }

/* ---- grid comparison ---- */
svg.param-bars { margin-bottom: .4rem; }
.chart .param-group-label { fill: var(--text-muted); font-size: 10px;
                            font-weight: 700; letter-spacing: .05em; }
td .swatch, h3 .swatch, p .swatch { margin-right: .35rem; vertical-align: baseline; }
.empty { color: var(--text-muted); font-size: .9rem; margin: .3rem 0; }

/* ---- site-year focus ---- */
.sy-form { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap;
           font-size: .875rem; }
.sy-form select { font: inherit; padding: .25rem .4rem; border-radius: 6px;
                  border: 1px solid var(--border); background: var(--surface-0);
                  color: var(--text-primary); max-width: 15rem; }
/* Mirrors the chart marks so the table rows are readable as the same encoding. */
.sy-mark { display: inline-block; width: 11px; height: 11px; margin-right: .35rem;
           vertical-align: -1px; }
.sy-bar { background: var(--c); height: 8px; }
.sy-diamond { background: var(--surface-1); border: 1.8px solid var(--c);
              transform: rotate(45deg) scale(.72); }
.chart .row-code { font-size: 9.5px; font-weight: 600; opacity: .95; }
.sy-suites { display: flex; gap: .55rem; align-items: center; flex-wrap: wrap;
             flex-basis: 100%; margin-top: .6rem; padding-top: .6rem;
             border-top: 1px solid var(--grid); }
.sy-pick { display: inline-flex; align-items: center; gap: .3rem;
           padding: .12rem .45rem .12rem .3rem; border-radius: 999px;
           border: 1px solid var(--border); cursor: pointer; font-size: .8rem; }
.sy-pick:hover { background: var(--surface-0); }
.sy-pick .cell-code { color: var(--c); }
.sy-pick input { accent-color: var(--c); margin: 0; }
.chip-suite { color: var(--c); border-color: var(--c);
              background: color-mix(in srgb, var(--c) 10%, transparent); }
.sy-current { font-size: .9rem; margin: 0 0 1rem; color: var(--text-secondary); }
.sy-current .sy-mark { margin: 0 .15rem 0 .25rem; }

/* ---- OSU matrix: rungs down, stations across ---- */
.osu-matrix { display: grid; gap: .55rem; align-items: start; }
.osu-corner { }
.osu-colhead { font-weight: 600; font-size: .95rem; padding: .2rem 0 .1rem;
               border-bottom: 1px solid var(--border); }
.osu-colhead .muted { font-weight: 400; font-size: .8rem; display: block; }
.osu-rowhead { font-size: .8rem; padding-top: 1.6rem; }
.osu-rowhead .muted { display: block; margin-top: .2rem; line-height: 1.25; }
.osu-cell { background: var(--surface-1); border: 1px solid var(--border);
            border-radius: 10px; padding: .5rem .6rem; min-width: 0; }
.osu-cell .chart { width: 100%; }
.osu-cellhead { font-size: .8rem; margin-bottom: .2rem; }
.osu-cellhead .muted { display: block; font-size: .75rem; }
@media (max-width: 900px) {
  .osu-matrix { grid-template-columns: 1fr !important; }
  .osu-rowhead { padding-top: .8rem; }
}

/* ---- site x year matrix on the suite page ---- */
.matrix-wrap { overflow-x: auto; }
.site-matrix { display: grid; gap: .4rem; align-items: start; }
.sm-corner { position: sticky; left: 0; background: var(--surface-1); z-index: 2; }
.sm-colhead { font-size: .78rem; font-weight: 600; color: var(--text-secondary);
              padding-bottom: .2rem; border-bottom: 1px solid var(--border);
              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Row labels stay readable while the other axis scrolls past. */
.sm-rowhead { position: sticky; left: 0; z-index: 2; background: var(--surface-1);
              font-weight: 600; font-size: .9rem; padding: .6rem .4rem 0 0; }
/* Site names in the gutter: longer than a year and they must not wrap, or the
   row head grows taller than its panels and the row stops lining up. */
.sm-wide-rows .sm-rowhead { font-size: .82rem; padding-right: .5rem;
              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sm-cell { min-width: 0; }
/* Matched to the 220x160 panel so rows line up instead of stepping. */
.sm-empty { min-height: 160px; border: 1px dashed var(--grid);
            border-radius: 8px; }
/* The five QP quantities side by side. Wider track than the response panels:
   a scatter needs room for two tick-labelled axes, where a response curve does
   not, so 200px would crush the axis labels into the marks. */
.qp-panels { grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: .8rem; }
.qp-head { font-size: .95rem; margin: 0 0 .2rem; }
.qp-head .muted { font-weight: 400; font-size: .8rem; }
/* The blurbs run to different lengths — the plateau carries a caveat the slope
   does not — so pin the chart to the bottom of the card and the scatters line
   up across a row instead of stepping with the prose above them. */
.qp-panels .card { display: flex; flex-direction: column; }
.qp-panels .chart { margin-top: auto; }

/* The pinned-on-bound counts ride just outside each rail: smaller than the
   tick text around them so a column of them reads as annotation, not axis. */
.chart .bound-count { font-size: 9px; font-weight: 600; }

/* Many sites: keep the legend compact so 31 entries do not dwarf the chart. */
.site-legend { gap: .5rem .9rem; font-size: .78rem; margin-top: .6rem; }
.site-legend .swatch { width: 9px; height: 9px; }
.row-link { display: block; margin-top: .35rem; font-size: .75rem; }
.ratio-badge { font-size: .78rem; font-weight: 700; color: var(--series-2);
               border: 1px solid var(--series-2); border-radius: 999px;
               padding: .02rem .38rem; margin-left: .3rem; }
svg.density, svg.trajectory { width: 100%; }
.fwd-chip { font-size: .7rem; border: 1px solid var(--border); border-radius: 999px;
            padding: .02rem .34rem; margin-left: .25rem; text-decoration: none; }
table.compression td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
table.compression tr.rung-first td { border-top: 1px solid var(--border); }
.cmp { display: inline-block; min-width: 2.4rem; text-align: right; }
.cmp-link { margin-left: .3rem; text-decoration: none; font-weight: 700; }
/* Compression heat map: shading carries magnitude, the number stays readable. */
.cmp { padding: .1rem .3rem; border-radius: 4px; margin-left: .12rem; }
.cmp-key { display: inline-flex; gap: .2rem; align-items: center; margin-left: .3rem;
           vertical-align: middle; }
.cmp-swatch { display: inline-block; min-width: 2rem; text-align: center;
              padding: .06rem .25rem; border-radius: 4px; font-size: .72rem; }

/* ---- chapter pages ----------------------------------------------------- */
/* Two audiences share these pages: a coauthor reading beside the PDF, who
   needs to know instantly whether a number is the manuscript's, and Luke, who
   needs the rest of the experiment still reachable. Hence the provenance
   banner at the top and the hard rule before the extras. */

header.app nav a.nav-chapter { font-weight: 600; color: var(--text-primary); }
header.app .nav-sep {
  width: 1px; align-self: stretch; background: var(--border); margin: 0 .25rem;
}

.provenance { font-size: .875rem; line-height: 1.5; margin-bottom: 1.25rem; }
.provenance p { margin: .5rem 0 0; }
.provenance ul { margin: .5rem 0 0; padding-left: 1.1rem; }
.provenance li { margin: .25rem 0; }
.provenance code { font-size: .82em; }
.prov-tag {
  display: inline-block; font-size: .7rem; text-transform: uppercase;
  letter-spacing: .05em; padding: .15rem .5rem; border-radius: 999px;
  margin-right: .5rem; font-weight: 600;
}
.prov-ok   { background: rgba(27,175,122,.16); color: #0d7a52; }
.prov-warn { background: rgba(235,104,52,.18); color: #b5451a; }
.prov-warn-card { border-color: rgba(235,104,52,.5); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .prov-ok   { color: #57d3a4; }
  :root:not([data-theme="light"]) .prov-warn { color: #ff9a6b; }
}

/* Manuscript sections carry a rule; the extras carry a heavier one, so the
   boundary between "in the paper" and "not in the paper" is visible while
   scrolling rather than only in the heading text. */
h3.ms-head {
  font-size: 1rem; margin: 2rem 0 .35rem; padding-bottom: .3rem;
  border-bottom: 1px solid var(--border);
}
hr.extras-rule {
  border: 0; border-top: 3px double var(--border); margin: 3rem 0 1.25rem;
}
h3.extras-head { font-size: 1rem; margin: 0 0 .35rem; color: var(--text-secondary); }
h4 { font-size: .9rem; margin: 1.5rem 0 .35rem; }

.tile-label { display: block; font-size: .75rem; color: var(--text-muted);
              text-transform: uppercase; letter-spacing: .04em; }
.tile-value { display: block; font-size: 1.5rem; font-variant-numeric: tabular-nums;
              line-height: 1.3; }
.tile-note  { display: block; font-size: .78rem; color: var(--text-muted); }
.tiles { margin-bottom: 1rem; }

/* The matrix. Colour carries magnitude, but every cell also prints its number
   and links to the suite, so the shading is never the only encoding. */
table.heat td.heat-cell { padding: 0; }
table.heat .heat-link {
  display: block; padding: .35rem .55rem; text-decoration: none;
  color: var(--text-primary); font-variant-numeric: tabular-nums;
}
table.heat .heat-link:hover { text-decoration: underline; }
table.heat tr.heat-foot td { border-top: 2px solid var(--border); font-size: .8rem; }

th.grp { font-size: .75rem; color: var(--text-muted); font-weight: 500;
         border-bottom: 1px solid var(--border); }
td.canon, th.canon { color: var(--text-muted); font-style: italic; }
tr.primary-row { outline: 2px solid var(--accent); outline-offset: -2px; }

.cmp-block { padding: .75rem 0; border-bottom: 1px solid var(--border); }
.cmp-block:last-child { border-bottom: 0; }
.cmp-q { font-weight: 600; font-size: .9rem; margin-bottom: .3rem; }
.cmp-n { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap;
         font-size: .85rem; margin-bottom: .3rem; }
.cmp-delta { font-variant-numeric: tabular-nums; font-weight: 600; }
.cmp-f { font-size: .85rem; color: var(--text-secondary); line-height: 1.5; }
.better { color: #0d7a52; }
.worse  { color: #b5451a; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .better { color: #57d3a4; }
  :root:not([data-theme="light"]) .worse  { color: #ff9a6b; }
}

/* ---- grouped suite picker (compare) ------------------------------------ */
/* 187 suites is only choosable if the list is broken up and each row says
   what it is. Groups collapse; the description under each name is derived
   from the run config, so it cannot drift from what the suite actually did. */

.picker-state {
  margin: 0 0 .9rem; font-size: .85rem; color: var(--text-secondary);
  line-height: 1.5;
}
.clear-link { font-size: .8rem; }

details.suite-group {
  border: 1px solid var(--border); border-radius: 8px;
  margin-bottom: .5rem; background: var(--surface-0);
}
details.suite-group > summary {
  cursor: pointer; padding: .55rem .75rem; display: flex; gap: .6rem;
  align-items: center; flex-wrap: wrap; font-size: .875rem;
  list-style-position: inside;
}
details.suite-group > summary:hover { background: var(--surface-1); }
details.suite-group[open] > summary { border-bottom: 1px solid var(--border); }
.grp-title { font-weight: 600; }
.grp-count {
  font-size: .72rem; color: var(--text-muted); background: var(--surface-1);
  border: 1px solid var(--border); border-radius: 999px; padding: .05rem .45rem;
}
.grp-picked {
  font-size: .72rem; color: #fff; background: var(--accent);
  border-radius: 999px; padding: .05rem .45rem;
}
.grp-note {
  margin: .6rem .75rem .25rem; font-size: .8rem; color: var(--text-muted);
  line-height: 1.5; max-width: 78ch;
}

/* One column below 900px, two above: the description needs the width more
   than the list needs density. */
.grp-list {
  display: grid; grid-template-columns: 1fr; gap: .1rem; padding: .25rem .5rem .6rem;
}
@media (min-width: 900px) { .grp-list { grid-template-columns: 1fr 1fr; } }

label.suite-pick {
  display: flex; gap: .5rem; align-items: baseline;
  padding: .35rem .5rem; border-radius: 6px; cursor: pointer;
}
label.suite-pick:hover { background: var(--surface-1); }
label.suite-pick.on { background: rgba(42,120,214,.09); }
label.suite-pick input { margin: 0; flex: none; position: relative; top: .15rem; }
.pick-body { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.pick-name { font-size: .85rem; }
.pick-desc {
  font-size: .76rem; color: var(--text-muted); line-height: 1.4;
  overflow-wrap: anywhere;
}
