/* Variant B — "the chill room spec sheet".
 *
 * Variant A dressed the project as warm bulletin paper: cream stock, a serif
 * display face, violet inspection ink. This one argues the opposite case.
 * The subject is not a farm, it is a measuring problem — losses compounding
 * down a processing line — so the page is built as an instrument rather than
 * a document: cold stock, a condensed industrial grotesque, and one accent
 * borrowed from chill-tank water.
 *
 * The warm ambers survive untouched, and that is the point of the palette.
 * They are now the ONLY warm thing on the page, so every chart reads as
 * chicken against an instrument that reads as cold steel. Colour tells you
 * what is data and what is chrome, before you have read a word.
 */

:root {
  /* Cold stock. Deliberately blue-grey rather than cream: the whole page is
     a reading taken in a refrigerated room. */
  --paper: #E8EDEE; --card: #F7F9F9; --well: #DDE4E6;
  --line: #C6D0D2; --rule: #9DAAAD;
  --ink: #101619; --dim: #4A585D; --faint: #7B888C;

  /* Chill-tank teal marks provenance and interaction. */
  --stamp: #0B5C63; --stamp-soft: #4A9098;

  /* Evidence grades. Violet moved from the old accent slot to `industry`,
     which frees the accent for teal and keeps the four grades far enough
     apart in hue to survive a colour-blind reader. 'derived' shares
     measured's ink deliberately — both are figures we stand behind — so
     there is no --derived to fall out of sync. */
  --measured: #17683C; --study: #2A4FBF;
  --industry: #8A5CD6; --estimate: #A85B10; --bad: #B93A34;

  --field: #FFFFFF; --hatch: rgba(168,91,16,.14);

  /* Warm series, carried over from the original page. The charts are the
     one place this page is allowed to be warm. */
  --amber: #C58A2E; --amber2: #d97706; --amber-bright: #E0A93E;
  --scale-lo: #EFE7D6; --scale-hi: #54350F; --brown: #7c2d12;
  --bar-muted: #B3AC9D; --bar-recede: #C6BFAF;
  --grey: #7E7869; --grey2: #9A948A;

  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --display: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
}

/* Night shift. The room is the same room with the lights down: the teal
   brightens to stay legible on dark stock, and the choropleth scale flips so
   "more" is always the end that stands off the ground. */
:root[data-theme="dark"] {
  --paper: #0E1416; --card: #151D20; --well: #1D272A;
  --line: #2A3639; --rule: #4A5A5E;
  --ink: #E6EDEE; --dim: #9AA9AD; --faint: #75858A;

  --stamp: #5FD3DC; --stamp-soft: #3E9BA3;

  --measured: #4FBF85; --study: #7DA2F5;
  --industry: #B39BF0; --estimate: #D3924C; --bad: #E4756B;

  --field: #0A0F11; --hatch: rgba(211,146,76,.16);

  --amber: #D19A3E; --amber2: #E8912D; --amber-bright: #E8B65A;
  --scale-lo: #1B2226; --scale-hi: #F2C879; --brown: #B65B32;
  --bar-muted: #55605F; --bar-recede: #3C4547;
  --grey: #8A9296; --grey2: #949CA0;
}

* { box-sizing: border-box; }

/* The UA default for [hidden] is `display: none`, but several rules below
   set `display: flex` on elements that also carry `hidden` (`.check`,
   `footer.build`) -- an author display rule always wins over the UA one, so
   `hidden` silently stopped hiding anything. This must win over every other
   display rule in the sheet, which is what !important is for here: it is not
   a specificity shortcut, it is restoring the one behaviour `hidden` is
   supposed to guarantee regardless of what else targets the element. */
[hidden] { display: none !important; }

body {
  margin: 0; background: var(--paper); color: var(--ink);
  font: 15.5px/1.62 'Public Sans', system-ui, -apple-system, sans-serif;
}
a { color: var(--stamp); }
:focus-visible { outline: 2px solid var(--stamp); outline-offset: 2px; }


/* Quiet family bar — hub chrome in this instrument's tokens. */
.chrome {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0.85rem 22px 0.7rem;
  border-bottom: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 0.78rem;
}
.chrome .home {
  color: var(--ink);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}
.chrome .home:hover { color: var(--stamp); }
.chrome .home svg { width: 0.95rem; height: 0.95rem; }
.chrome nav { display: flex; flex: 1; align-items: center; gap: 1.1rem; min-width: 0; }
.chrome nav a { color: var(--dim); text-decoration: none; white-space: nowrap; }
.chrome nav a:hover { color: var(--ink); }
#swampid-link { flex: none; }
@media (max-width: 400px) {
  .chrome { gap: 0.5rem; }
  .chrome nav { gap: 0.55rem; }
}

/* --------------------------------------------------------------- shell
   Two columns: a sticky instrument rail and the readout beside it. Variant
   A ran a horizontal tab strip over eleven views, which wrapped to three
   rows on a laptop and put the current view's name in a different place
   depending on the window width. Eleven items is a list, so this sets them
   as one. */
.shell {
  display: grid; grid-template-columns: 232px minmax(0, 1fr);
  gap: 0 38px; max-width: 1180px; margin: 0 auto; padding: 0 22px 90px;
  align-items: start;
}
@media (max-width: 900px) {
  .shell { grid-template-columns: minmax(0, 1fr); gap: 0; }
}

.rail { position: sticky; top: 0; padding: 30px 0 40px; }
@media (max-width: 900px) {
  .rail { position: relative; padding: 26px 0 4px; }
  .sub { max-width: 46ch; padding-right: 96px; }
}

.brand { display: flex; flex-direction: column; gap: 14px; }
#logo {
  margin: 0; color: var(--stamp); font-size: 10px; line-height: 1.15;
  white-space: pre; font-family: var(--mono);
  border-left: 2px solid var(--stamp); padding: 2px 0 2px 10px; opacity: .9;
}
@media (max-width: 900px) { #logo { display: none; } }

h1 {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(25px, 2.6vw, 31px); margin: 0; line-height: 1.05;
  letter-spacing: -0.025em;
}
.sub { color: var(--dim); margin: 0; font-size: 13.5px; max-width: 34ch; }

/* The strapline. One size down from .sub and separated by a rule rather than
   by a box: it is a pointer, not a banner, and this page does not do banners.
   `.lnk` is a button because it moves the view rather than following a URL --
   the page is one document with no per-view address, so an <a href> would be
   lying about what happens. Styled as a link because that is what it does. */
.spot { color: var(--dim); margin: 0; font-size: 12.5px; max-width: 34ch;
        line-height: 1.55; padding-top: 12px;
        border-top: 1px solid var(--line); }
.lnk {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--stamp);
  border-bottom: 1px solid var(--stamp-soft);
}
.lnk:hover { color: var(--ink); border-bottom-color: var(--ink); }

/* The anchor sentence sits under the strapline as a continuation of it, so it
   takes the same size and colour and drops the second rule — two stacked
   hairlines in a 34ch column read as a table of contents rather than as one
   thought. */
.spot.anchor { border-top: 0; padding-top: 6px; }
.spot.anchor b { color: var(--ink); font-weight: 600; }

/* The view index. Numbers are deliberately absent: these are eleven ways of
   asking one question, not eleven steps of anything. */
nav { display: flex; flex-direction: column; margin: 26px 0 22px;
      border-left: 1px solid var(--line); }
nav button {
  background: none; border: 0; border-left: 2px solid transparent;
  margin-left: -1px; text-align: left;
  color: var(--dim); padding: 6px 0 6px 13px; cursor: pointer;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .03em;
  text-transform: uppercase; line-height: 1.35;
}
nav button:hover { color: var(--ink); }
nav button.on { color: var(--stamp); border-left-color: var(--stamp);
                font-weight: 500; }
/* On a phone the rail becomes a header, and eleven wrapped items pushed the
   answer most of a screen down. One scrolling row keeps the whole index
   reachable without spending vertical space the calculator needs. */
@media (max-width: 900px) {
  nav {
    flex-direction: row; flex-wrap: nowrap; border-left: 0;
    border-bottom: 1px solid var(--line); margin: 16px 0 16px;
    overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
    /* Eleven items in one hidden-scrollbar row read as "half the tabs are
       missing" with no other cue that six through eleven exist off-screen.
       A mask, not a background gradient, so it fades the buttons themselves
       (any theme's colours) rather than requiring a second gradient to keep
       in sync with light/dark. Right edge only: the row opens scrolled all
       the way left, so a left-side fade would clip the very first tab
       ("Calculator") before anyone has scrolled anywhere. Stationary on the
       element while its content scrolls underneath, which is what makes it
       read as an edge rather than a highlight on whichever button happens
       to be there. */
    mask-image: linear-gradient(to right,
      #000, #000 calc(100% - 28px), transparent);
    -webkit-mask-image: linear-gradient(to right,
      #000, #000 calc(100% - 28px), transparent);
  }
  nav::-webkit-scrollbar { display: none; }
  nav button {
    border-left: 0; border-bottom: 2px solid transparent;
    margin: 0 0 -1px; padding: 7px 14px 7px 0; white-space: nowrap; flex: none;
  }
  nav button.on { border-bottom-color: var(--stamp); }
}

.main { padding: 30px 0 0; min-width: 0; }
@media (max-width: 900px) { .main { padding-top: 4px; } }

/* ---------------------------------------------------------- scope marker
   Sits above the panels, in the mono face the badges and labels use, because
   it is metadata about the view rather than part of its argument. Deliberately
   NOT a panel: a bordered box here would read as the first result on the page,
   and it has to be readable before a chart is interpreted, not instead of it.

   The mismatch state — you picked a product from one species and this view
   answers for another — borrows the estimate stamp's colour, which is the
   page's one signal for "do not read this as settled". */
.scope {
  font-family: var(--mono); font-size: 11px; letter-spacing: .04em;
  color: var(--faint); margin: 0 0 14px; line-height: 1.5;
  border-left: 2px solid var(--line); padding: 2px 0 2px 10px;
}
.scope b { color: var(--dim); font-weight: 500; }
.scope.mismatch { color: var(--estimate); border-left-color: var(--estimate); }
.scope.mismatch b { color: var(--estimate); font-weight: 700; }

/* --------------------------------------------------------------- panels
   Flat, hairline-ruled, no shadow and no radius. A panel here is a field on
   a form, not a floating card. */
.panel {
  background: var(--card); border: 1px solid var(--line);
  padding: 20px 22px; margin-bottom: 14px;
}
.view { display: none; } .view.on { display: block; }

.controls { display: flex; gap: 15px; flex-wrap: wrap; align-items: flex-end; }
label {
  display: block; font-family: var(--mono); font-size: 10.5px;
  color: var(--faint); text-transform: uppercase; letter-spacing: .09em;
  margin-bottom: 5px;
}
input[type=number], select {
  background: var(--field); color: var(--ink); border: 1px solid var(--rule);
  border-radius: 0; padding: 9px 11px; font-size: 15px; min-width: 90px;
  font-family: var(--mono);
}
input[type=number]:hover, select:hover { border-color: var(--stamp-soft); }
select { min-width: 200px; font-family: 'Public Sans', system-ui, sans-serif; }
.check {
  display: flex; align-items: center; gap: 7px; font-size: 14px;
  color: var(--dim); cursor: pointer; text-transform: none; letter-spacing: 0;
  font-family: 'Public Sans', system-ui, sans-serif;
}
.check input { accent-color: var(--stamp); }

/* ------------------------------------------------------------- the readout
   THE SIGNATURE ELEMENT. On the page this replaced the answer was a big
   centred number and the floor..ceiling band a thin decoration below it. Here
   they are one object, left-aligned against a ruled gutter, because the
   claim this project actually makes is not "12" — it is "12, and here is the
   span it had to fall inside". A number without its band is not the answer.  */
.readout {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 0 20px; align-items: start; padding: 6px 0 4px;
}
@media (max-width: 620px) {
  .readout { grid-template-columns: minmax(0, 1fr); gap: 0; }
}
.headline {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(52px, 9vw, 92px); letter-spacing: -0.045em;
  color: var(--ink); line-height: .86; font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.headline-label {
  color: var(--dim); margin-top: 10px; font-size: 15px; max-width: 30ch;
}

/* The scale. Ticks every 10%, a hard-edged fill, ends labelled in mono —
   an instrument face, not a progress bar. */
.band { padding-top: 12px; }
@media (max-width: 620px) { .band { padding-top: 22px; } }
.bandbar {
  position: relative; height: 34px; background: var(--well);
  border: 1px solid var(--rule);
  background-image: repeating-linear-gradient(to right,
    transparent 0, transparent calc(10% - 1px),
    var(--rule) calc(10% - 1px), var(--rule) 10%);
}
.bandfill {
  position: absolute; top: 3px; bottom: 3px; left: 3px;
  background: var(--stamp); min-width: 2px;
  transition: width .35s cubic-bezier(.22,.61,.36,1);
}
/* The leading edge is the reading. It is drawn heavier than the fill so the
   eye lands on the value rather than on the length of the bar. */
.bandfill::after {
  content: ""; position: absolute; top: -3px; bottom: -3px; right: -1px;
  width: 3px; background: var(--ink);
}
@media (prefers-reduced-motion: reduce) { .bandfill { transition: none; } }
.bandends {
  display: flex; justify-content: space-between; gap: 12px;
  font-family: var(--mono); font-size: 11px; color: var(--faint);
  margin-top: 7px; text-transform: uppercase; letter-spacing: .05em;
}

.floorline {
  margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--line);
  color: var(--dim); max-width: 64ch;
}
.floorline b { color: var(--ink); font-weight: 600; }

/* ------------------------------------------------------------ reasoning */
details { margin-top: 18px; border-top: 1px solid var(--line); padding-top: 14px; }
summary {
  cursor: pointer; color: var(--stamp); font-family: var(--mono);
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em;
  list-style: none; user-select: none;
}
summary::-webkit-details-marker { display: none; }
summary::before { content: "+ "; }
details[open] summary::before { content: "\2212 "; }

.step { border-left: 2px solid var(--line); padding: 9px 0 9px 15px; margin: 13px 0; }
.step.count { border-left-color: var(--stamp); }
.step h4 { margin: 0 0 4px; font-size: 14.5px; display: flex; gap: 9px;
           align-items: center; flex-wrap: wrap; }
.step p { margin: 0; color: var(--dim); font-size: 14px; }
.cite { font-family: var(--mono); font-size: 11px; color: var(--faint);
        margin-top: 5px; line-height: 1.5; }

/* Evidence grades stay stamps — square, inked in their own colour, sitting
   flat rather than rotated. An estimate is the one grade that is not fully
   inked: dashed and hatched, so a guessed figure is visibly different from a
   sourced one everywhere it appears. That rule is the product. */
.badge {
  font-family: var(--mono); font-size: 9.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .1em;
  padding: 2px 6px; border-radius: 0; border: 1px solid; background: transparent;
}
.b-measured, .b-derived { color: var(--measured); border-color: var(--measured); }
.b-study { color: var(--study); border-color: var(--study); }
.b-industry { color: var(--industry); border-color: var(--industry); }
.b-estimate {
  color: var(--estimate); border-color: var(--estimate); border-style: dashed;
  background: repeating-linear-gradient(45deg,
    transparent 0 3px, var(--hatch) 3px 4px);
}

.fact { border-left: 2px solid var(--stamp); padding: 11px 0 11px 15px; margin: 15px 0; }
.fact h4 { margin: 0 0 5px; font-size: 16px; font-family: var(--display);
           font-weight: 700; letter-spacing: -0.01em; }
.fact p { margin: 0; color: var(--dim); font-size: 14px; }

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 800px) { .grid2 { grid-template-columns: 1fr; } }
.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
@media (max-width: 720px) { .grid3 { grid-template-columns: 1fr; } }

.verdict { border: 1px solid var(--line); padding: 15px; text-align: left;
           background: var(--well); }
.verdict .v-val {
  font-family: var(--mono); font-size: 20px; font-weight: 700;
  margin-bottom: 3px; font-variant-numeric: tabular-nums;
}
.verdict .v-key {
  font-family: var(--mono); font-size: 10.5px; color: var(--faint);
  text-transform: uppercase; letter-spacing: .08em;
}
.v-better { color: var(--measured); }
.v-worse  { color: var(--bad); }
.v-same   { color: var(--dim); }
/* An unanswered leg of a verdict is not a bad result, it is no result. It
   borrows the estimate stamp's hatch so "we have not sourced this" looks the
   same everywhere, and it is set in the body face rather than mono because
   it is prose, not a value. Must out-specify `.verdict .v-val`. */
.verdict .v-open {
  color: var(--estimate); font-family: 'Public Sans', system-ui, sans-serif;
  font-size: 15px; font-weight: 600; font-style: italic;
  text-decoration: underline; text-decoration-style: dashed;
  text-underline-offset: 4px; text-decoration-thickness: 1px;
}
/* A species whose axis has no figures behind it stays pickable — the empty
   answer is worth reading — but says so before you click. */
.chips button[data-thin]::after { content: " ·"; color: var(--estimate); font-weight: 700; }

/* A species with no size question recorded at all. Still offered, still
   pickable: it used to be omitted from the picker entirely, so a view
   grading "every species" showed half of them and gave no sign the rest
   existed. Dashed, like every other unsourced thing on this page, so the
   difference between "we asked and the answer is nothing" and "nobody has
   asked yet" is visible before the click rather than after it. */
.chips button[data-unasked] {
  border-style: dashed; color: var(--faint);
}
.chips button[data-unasked]:hover { color: var(--dim); }

/* ---------------------------------------------------------------- busy */
#busy { position: fixed; top: 0; left: 0; right: 0; height: 2px;
        background: transparent; z-index: 99; pointer-events: none; }
#busy.on::after {
  content: ""; position: absolute; top: 0; height: 2px; width: 30%;
  background: var(--stamp); animation: slide 1.1s ease-in-out infinite;
}
@keyframes slide { 0% { left: -30%; } 100% { left: 100%; } }
@media (prefers-reduced-motion: reduce) {
  #busy.on::after { animation: none; left: 0; width: 100%; opacity: .5; }
}

/* ----------------------------------------------------------- fact deck */
.btn {
  background: transparent; color: var(--dim);
  border: 1px solid var(--rule); border-radius: 0;
  padding: 8px 13px; font-family: var(--mono); font-size: 11px;
  text-transform: uppercase; letter-spacing: .07em; cursor: pointer;
}
.btn:hover { border-color: var(--stamp); color: var(--stamp); }
#theme-toggle { margin-top: 20px; width: 100%; }
/* As a header the rail has room beside the title, and the toggle is chrome:
   it should not sit in the reading order between the index and the answer. */
@media (max-width: 900px) {
  #theme-toggle { position: absolute; top: 28px; right: 0; width: auto;
                  margin-top: 0; }
}

.card-wrap { display: flex; align-items: stretch; gap: 12px; }
.nav-arrow {
  background: none; border: 1px solid var(--rule); border-radius: 0;
  color: var(--dim); font-size: 22px; line-height: 1; width: 42px;
  flex: 0 0 42px; cursor: pointer;
}
.nav-arrow:hover { color: var(--stamp); border-color: var(--stamp); }
.nav-arrow:disabled { opacity: .3; cursor: default; }
.nav-arrow:disabled:hover { color: var(--dim); border-color: var(--rule); }
.card { flex: 1; min-height: 220px; padding: 6px 4px; }
.card h2 {
  margin: 5px 0 12px; font-family: var(--display); font-weight: 700;
  font-size: clamp(20px, 2.8vw, 25px); letter-spacing: -0.02em; line-height: 1.22;
}
.card p { margin: 0; color: var(--dim); font-size: 15.5px; line-height: 1.62; }
.card-stars { color: var(--stamp); letter-spacing: 3px; font-size: 12px; }
.card .cite { margin-top: 15px; }
.dots { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; }
.dot { width: 7px; height: 7px; border-radius: 0; background: var(--line);
       border: 0; padding: 0; cursor: pointer; }
.dot.on { background: var(--stamp); }

/* --------------------------------------------------------------- tables */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--line); }
th { font-family: var(--mono); color: var(--faint); font-size: 10.5px;
     font-weight: 500; text-transform: uppercase; letter-spacing: .08em; }
td.num { text-align: right; font-family: var(--mono); font-size: 13.5px;
         font-variant-numeric: tabular-nums; }
/* The census-only state table sits below the survey table in the same
   panel, and needs visible separation from it -- otherwise the two tables'
   header rows run together as if they were one table. */
#states-census-table table { margin-top: 18px; }

.slider { width: 100%; accent-color: var(--stamp); }
.big { font-family: var(--display); font-size: clamp(27px, 4vw, 38px);
       font-weight: 800; color: var(--ink); letter-spacing: -0.035em;
       font-variant-numeric: tabular-nums; }
.note { color: var(--faint); font-size: 13px; }
.warn { color: var(--estimate); }
/* Legend swatch for a map layer whose fill is a category rather than a
   value -- the presence-only census states. The same --grey the trace is
   drawn in, so the legend cannot drift from the map. */
.swatch {
  display: inline-block; width: 12px; height: 12px; border-radius: 2px;
  background: var(--grey); vertical-align: -1px; margin-right: 5px;
}
/* Inline affordance for a rejected request (usually a 422): small and near
   the control it belongs to, not a modal -- cleared on the next success so
   it cannot outlive the problem it described. */
.err {
  color: var(--bad); font-size: 13px; margin: 10px 0 0;
  border-left: 2px solid var(--bad); padding-left: 10px;
}
#boot-error {
  margin: 14px 22px 0; color: var(--bad); font-size: 14px;
  border: 1px solid var(--bad); padding: 12px 14px;
}

/* -------------------------------------------------------- country picker */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chips button {
  background: none; border: 1px solid var(--rule); color: var(--dim);
  padding: 7px 13px; border-radius: 0; font: inherit; font-size: 14px;
  cursor: pointer;
}
.chips button:hover { color: var(--ink); border-color: var(--faint); }
.chips button.on { color: var(--stamp); border-color: var(--stamp);
                   box-shadow: inset 0 0 0 1px var(--stamp); }
/* A country with nothing loaded is still worth showing — the absence is part
   of the story — but it must not look selectable-and-broken. */
.chips button:disabled { opacity: .45; cursor: not-allowed; }

.can { display: flex; flex-wrap: wrap; gap: 8px 20px; margin: 0; padding: 0;
       list-style: none; font-size: 14px; }
.can li::before { margin-right: 6px; }
.can li.yes::before { content: '\2713'; color: var(--measured); }
.can li.no::before { content: '\2717'; color: var(--estimate); }
.can li.no { color: var(--dim); }

h3 { margin: 0 0 5px; font-family: var(--display); font-weight: 700;
     font-size: 17px; letter-spacing: -0.015em; }
.muted { color: var(--dim); font-size: 14px; margin: 0 0 16px; max-width: 72ch; }

/* Build stamp. The deploy tracks master rather than tags, so the running
   site is normally ahead of the latest release — the commit is the honest
   answer to "what am I looking at?" and the version alone is not. */
footer.build {
  margin-top: 32px; padding-top: 14px; border-top: 1px solid var(--line);
  color: var(--faint); font-size: 12px; display: flex; flex-wrap: wrap;
  gap: 6px 14px; align-items: baseline;
}
footer.build .sep { color: var(--line); }
footer.build code { font-family: var(--mono); font-size: 11px; color: var(--dim); }
footer.build .ver { color: var(--dim); font-weight: 600; }
