/* Mini-PC Index — phosphor-terminal styling. Hand-written, no framework, no web font, no
 * third-party request. Dark is the canonical look; light is a paper-terminal variant that keeps
 * the same monospace, blocky structure rather than degrading into a generic tech blog.
 *
 * THE PIXEL LOOK COMES FROM STRUCTURE, NOT FROM A PIXEL FONT: hard 1px rules, zero border-radius
 * anywhere, block and box-drawing characters for bars, meters and sparklines, blocky focus
 * outlines, a restrained scanline wash, one blinking block cursor. All of that is system-font
 * text, so it renders crisply at every size and costs no payload — unlike a bitmap font, which
 * only looks right at exact multiples of its design size and would be a download besides.
 *
 * LEGIBILITY IS THE RISK THIS AESTHETIC CARRIES, so the rule is: the terminal treatment dresses
 * the CHROME — brand, headings, labels, rules, buttons — while dense table text stays a plain
 * system monospace at full contrast. No glow on body text (a text-shadow on a number is how a
 * data site becomes unreadable); glow only on the masthead, where nothing has to be read closely.
 *
 * WHAT EACH COLOUR MEANS. Kept disciplined on purpose — if a colour means two things it encodes
 * nothing:
 *   --green   INTERFACE. Brand, links, focus rings, the active filter, section rules, the fact
 *             that a value is sourced and clickable. It NEVER means "good" or "cheap".
 *   --amber   DATA. Magnitude bars, sparkline strokes, a price moving UP. The second channel,
 *             period-correct for a CRT and distinct from the interface colour at a glance.
 *   --red     ALERT. A price DROP (the thing a buyer wants flagged) and genuine errors. Nothing
 *             decorative is ever red.
 *   --ink/--muted  Values and labels. Data text wears ink, never a channel colour.
 * Amber and red are separated by the ▲/▼ glyph and the signed number in every place they appear,
 * so direction never rests on hue alone — protanopia and deuteranopia cannot separate that pair.
 */

:root{
  color-scheme:dark;
  --bg:#070a07; --panel:#0b0f0b; --panel-2:#0e140e; --sunken:#040604;
  --rule:#1b2e1f; --rule-2:#2f5238;
  --ink:#d7f5db; --ink-2:#8fc79a; --muted:#67976f;
  --green:#33ff33; --green-dim:#1f8a2a; --green-wash:#0d2411;
  --amber:#ffb000; --amber-dim:#8a6000; --amber-wash:#241a00;
  --red:#ff5555; --red-wash:#2a0e0e;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"DejaVu Sans Mono","Liberation Mono",monospace;
  --scan:rgba(0,0,0,.30);
}
@media (prefers-color-scheme:light){
  :root{
    color-scheme:light;
    /* Paper terminal: cream stock, dark phosphor-green ink. The colour ROLES do not swap — green
       is still the interface, amber is still the data channel, red is still the alert — because a
       reader who learns the encoding in one mode must not have to relearn it in the other. */
    --bg:#f2eee1; --panel:#fbf8ef; --panel-2:#f6f2e5; --sunken:#e8e3d3;
    --rule:#d5cbb2; --rule-2:#ab9f81;
    --ink:#1b2a1e; --ink-2:#3d5a43; --muted:#63755f;
    --green:#0e6b1c; --green-dim:#4a8a53; --green-wash:#e2edd9;
    --amber:#8a5200; --amber-dim:#b08c4a; --amber-wash:#f2e7cd;
    --red:#a81f1f; --red-wash:#f4dede;
    --scan:rgba(90,80,50,.05);
  }
}

*,*::before,*::after{box-sizing:border-box;border-radius:0}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--ink);
  font:14px/1.55 var(--mono);-webkit-font-smoothing:antialiased;font-variant-ligatures:none}
/* Scanline wash. Deliberately weak — it must read as texture at arm's length and disappear at
   reading distance. Removed entirely for anyone asking for more contrast. */
body::after{content:"";position:fixed;inset:0;pointer-events:none;z-index:900;
  background:repeating-linear-gradient(to bottom,var(--scan) 0 1px,transparent 1px 3px);opacity:.5}
@media (prefers-contrast:more){body::after{display:none}}
a{color:var(--green);text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px}
a:hover{background:var(--green-wash)}
:where(a,button,input,select,summary,th,[tabindex]):focus-visible{
  outline:2px solid var(--green);outline-offset:1px}
.skip{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);
  background:var(--green);color:var(--bg);padding:8px 14px;font-weight:700;z-index:999}
.skip:focus{width:auto;height:auto;clip-path:none;left:0;top:0}
::selection{background:var(--green);color:var(--bg)}

/* ---------------------------------------------------------------- masthead */
header.site{border-bottom:1px solid var(--rule-2);background:var(--panel);position:sticky;top:0;z-index:40}
header.site .wrap{display:flex;gap:18px;align-items:center;padding:0 16px;min-height:46px;flex-wrap:wrap}
header.site h1{margin:0;padding:11px 0;font:700 15px/1 var(--mono);letter-spacing:.02em}
header.site h1 a{color:var(--green);text-decoration:none;text-shadow:0 0 9px color-mix(in srgb,var(--green) 45%,transparent)}
header.site h1 a:hover{background:none;color:var(--green);filter:brightness(1.18)}
.cursor{display:inline-block;width:.62em;height:1em;vertical-align:-.14em;margin-left:.28em;
  background:var(--green);animation:blink 1.15s steps(1) infinite}
@keyframes blink{50%{opacity:0}}
@media (prefers-reduced-motion:reduce){.cursor{animation:none;opacity:.55}}
header.site nav{display:flex;gap:0;margin-left:auto;flex-wrap:wrap;font-size:12.5px}
header.site nav a{color:var(--ink-2);text-decoration:none;padding:6px 11px;border:1px solid transparent;
  text-transform:uppercase;letter-spacing:.08em}
header.site nav a:hover{color:var(--green);background:var(--green-wash);border-color:var(--rule)}
header.site nav a[aria-current=page]{color:var(--bg);background:var(--green);font-weight:700}
.wrap{max-width:1560px;margin:0 auto}
main{padding:16px}

/* ---------------------------------------------------------------- disclosure */
.disclosure{border:1px solid var(--rule);border-left:3px solid var(--amber-dim);background:var(--panel);
  padding:9px 12px;font-size:12px;line-height:1.55;color:var(--ink-2);margin:0 0 14px}
.disclosure::before{content:"[!] ";color:var(--amber);font-weight:700}
.disclosure strong{color:var(--ink)}

/* ---------------------------------------------------------------- filters */
.controls{background:var(--panel);border:1px solid var(--rule-2);padding:12px 14px 10px;margin-bottom:12px}
.controls .row{display:flex;gap:10px 14px;flex-wrap:wrap;align-items:flex-end}
.controls .row+.row{margin-top:11px;padding-top:11px;border-top:1px dashed var(--rule)}
.f{display:flex;flex-direction:column;gap:4px;min-width:0}
.f>label,.grouplabel{font:700 10px/1.35 var(--mono);text-transform:uppercase;letter-spacing:.14em;
  color:var(--muted)}
.f>label:not(.checkline){white-space:nowrap}
/* The group labels carry a sentence ("Use case — each is a published rule, not an opinion"), so
   they must wrap. Left at nowrap this one label was 393px wide in a 344px column and was the
   entire cause of the page scrolling horizontally on a phone. */
.grouplabel{white-space:normal}
.f>label:not(.checkline)::before,.grouplabel::before{content:"› ";color:var(--green-dim)}
.f select,.f input[type=search]{background:var(--sunken);color:var(--ink);border:1px solid var(--rule-2);
  padding:6px 8px;font:inherit;font-size:13px;min-height:31px;appearance:none}
.f select{padding-right:24px;
  background-image:linear-gradient(var(--muted),var(--muted)),linear-gradient(var(--muted),var(--muted));
  background-size:6px 1px,1px 6px;background-position:calc(100% - 11px) 16px,calc(100% - 8.5px) 13px;
  background-repeat:no-repeat}
.f input[type=search]{min-width:220px}
.f input[type=search]::placeholder{color:var(--muted)}
.f select:hover,.f input:hover{border-color:var(--green-dim)}
.f select[data-on="1"]{border-color:var(--green);color:var(--green);background-color:var(--green-wash);font-weight:700}
.checkline{display:flex;gap:7px;align-items:center;min-width:0;
  font-size:13px;min-height:31px;cursor:pointer}
/* Controls with no caption of their own still have to sit on the row's baseline. */
.f.end{justify-content:flex-end}
.checkline input{accent-color:var(--green);width:14px;height:14px;margin:0}
.chips{display:flex;gap:4px;flex-wrap:wrap}
details.brands>summary{cursor:pointer;list-style:none;display:inline-block;padding:2px 0}
details.brands>summary::-webkit-details-marker{display:none}
details.brands>summary .grouplabel::before{content:"▸ ";color:var(--green-dim)}
details.brands[open]>summary .grouplabel::before{content:"▾ ";color:var(--green-dim)}
details.brands>summary:hover .grouplabel{color:var(--green)}
details.brands>.chips{margin-top:6px}
#brandCount{color:var(--green-dim)}
.chip{border:1px solid var(--rule-2);background:var(--sunken);color:var(--ink-2);
  padding:3px 9px;font:400 12px/1.5 var(--mono);cursor:pointer;user-select:none}
.chip:hover{border-color:var(--green-dim);color:var(--green)}
.chip[aria-pressed=true]{background:var(--green);border-color:var(--green);color:var(--bg);font-weight:700}
.chip[aria-pressed=true]::before{content:"■ "}
.chip[aria-pressed=false]::before{content:"□ ";color:var(--muted)}
.chip.ghost{border-style:dashed;color:var(--muted)}
.chip.ghost::before{content:"× ";color:var(--red)}

/* ---------------------------------------------------------------- summary bar */
.summary{display:flex;gap:6px 16px;flex-wrap:wrap;align-items:baseline;font-size:12px;
  color:var(--muted);margin:0 0 8px;padding:0 1px}
.summary b{color:var(--green);font-size:13px}
.summary .spacer{margin-left:auto}
.hidden-note{color:var(--amber);border:1px solid var(--amber-dim);padding:1px 8px}
.hidden-note::before{content:"! "}

/* ---------------------------------------------------------------- the table */
/* SCROLL MODEL — read this before touching any overflow rule on this page.
 *
 * The table is ~1900px wide at every viewport we support, so horizontal scrolling is not an edge
 * case here, it is the normal way the table is read. That makes WHERE the horizontal scrollbar
 * sits a primary design constraint, not a detail.
 *
 * The database page is therefore an APP SHELL: below, in a media query, the table pane becomes the
 * only scroller on the page and the chrome above it is fixed. One scrollbar, a header row that
 * stays put, and a horizontal scrollbar pinned to the bottom of the viewport where it can always
 * be reached. Flexbox computes the pane's height, so there is no magic number to keep in sync with
 * the masthead — the previous `max-height: calc(100dvh - 128px)` was exactly that, and it was
 * wrong at every desktop size: it put the pane's bottom edge 359px below the fold at 1920x1080,
 * which is why the horizontal scrollbar could not be reached at all.
 *
 * The rule HERE is the fallback, and it is the plain page-scroll model: horizontal overflow only,
 * no height cap, no `overscroll-behavior`. It applies wherever the shell cannot fit — narrow
 * viewports, where the table is replaced by cards anyway, and short ones. `overscroll-behavior:
 * contain` is gone entirely: it trapped the wheel inside the table so the page stopped scrolling
 * when the pointer was over it, which is the part that read as "stuck". */
.tablewrap{overflow-x:auto;border:1px solid var(--rule-2);background:var(--panel);
  scrollbar-width:thin;scrollbar-color:var(--rule-2) var(--sunken)}
table{border-collapse:separate;border-spacing:0;width:100%;font-size:12.5px}
th,td{padding:0 9px;height:28px;text-align:left;white-space:nowrap;
  border-bottom:1px solid var(--rule);background:var(--panel)}
thead th{position:sticky;background:var(--panel-2);color:var(--muted);
  font:700 10px/1 var(--mono);text-transform:uppercase;letter-spacing:.1em;z-index:5}
thead tr.groups th{top:0;height:22px;color:var(--green-dim);letter-spacing:.18em;font-size:9.5px;
  border-bottom:1px solid var(--rule);border-left:1px solid var(--rule-2)}
thead tr.cols th{top:22px;height:26px;cursor:pointer;user-select:none;border-bottom:1px solid var(--rule-2)}
thead tr.cols th:hover{color:var(--green);background:var(--green-wash)}
thead th[aria-sort]{color:var(--bg);background:var(--green)}
thead th[aria-sort=ascending]::after{content:" ▲"}
thead th[aria-sort=descending]::after{content:" ▼"}
tbody tr:nth-child(even) td{background:var(--panel-2)}
tbody tr:hover td{background:var(--green-wash)}
tbody tr.hit td{background:var(--green-wash);box-shadow:inset 0 0 0 1px var(--green)}
td.name,th.name{position:sticky;left:0;z-index:4;white-space:normal;min-width:206px;max-width:270px;
  line-height:1.28;padding-top:5px;padding-bottom:5px;color:var(--ink);
  border-right:1px solid var(--rule-2)}
thead th.name{z-index:6}
td.num{text-align:right;font-variant-numeric:tabular-nums}
/* Magnitude bar on the SORTED column only — the comparison you asked for, drawn where you are
   looking and nowhere else. Square-ended and amber: the data channel, never the interface green.
   Length is the encoding; the hue is constant. */
td.bar{background-image:linear-gradient(to left,var(--amber-wash) 0 var(--w,0%),transparent var(--w,0%));
  background-repeat:no-repeat;background-size:100% 15px;background-position:right center;
  box-shadow:inset -1px 0 0 0 transparent}
tbody tr:hover td.bar{background-image:linear-gradient(to left,color-mix(in srgb,var(--amber) 26%,transparent) 0 var(--w,0%),transparent var(--w,0%))}

/* Sourced vs unknown: the credibility encoding, and the reason anyone should believe the other
   numbers. A sourced value is underlined in the interface colour and opens its citation; an
   unknown value is a dither block that can never be misread as a zero or a dash in a number. */
.sourced{border-bottom:1px solid var(--green-dim);cursor:pointer;padding-bottom:1px}
.sourced:hover{border-bottom-color:var(--green);color:var(--green)}
.derived{border-bottom:1px dotted var(--amber-dim);cursor:pointer;padding-bottom:1px}
.derived:hover{border-bottom-color:var(--amber);color:var(--amber)}
.sronly{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.unknown{color:var(--muted);opacity:.75;letter-spacing:-.05em}
.unknown::before{content:"░░"}
.card .unknown::before,.prose .unknown::before{content:"░░ unknown"}
/* Per-row source coverage, as a block meter. Sortable, so "show me the machines you actually
   know something about" is one click. */
.meter{color:var(--green-dim);letter-spacing:-.08em}
.meter b{color:var(--green);font-weight:400}
.meterlabel{color:var(--muted);margin-left:5px;font-size:11px}

/* Block sparkline: our own capture log, drawn in the row out of ▁▂▃▄▅▆▇█. Zero payload, pixel
   native, and it lines up because the whole page is monospace. Direction is carried by the ▼/▲
   glyph and the signed number as well as the colour. */
.spark{white-space:nowrap}
.spark .plot{letter-spacing:-.06em}
.dn{color:var(--red)} .up{color:var(--amber)} .flat{color:var(--muted)}
.trend{font-size:11.5px;margin-left:5px;font-variant-numeric:tabular-nums}
.collecting{color:var(--muted);font-size:11px;letter-spacing:.02em}
.collecting::before{content:"░ "}

.tags{display:inline-flex;gap:3px;flex-wrap:wrap;padding:3px 0}
.tag{font-size:10.5px;border:1px solid var(--rule-2);padding:0 5px;color:var(--ink-2);white-space:nowrap}

/* ---------------------------------------------------------------- states */
.empty,.loading{border:1px dashed var(--rule-2);padding:38px 20px;text-align:center;
  color:var(--muted);background:var(--panel)}
.empty h3{margin:0 0 6px;font:700 15px/1.3 var(--mono);color:var(--amber);text-transform:uppercase;letter-spacing:.1em}
.empty p{margin:0 0 14px;max-width:52ch;margin-inline:auto;font-size:13px;line-height:1.6}
.skeleton{height:12px;background:repeating-linear-gradient(90deg,var(--rule) 0 8px,transparent 8px 16px);
  margin:0 auto 9px;max-width:520px;animation:sk 1.1s steps(8) infinite}
@keyframes sk{to{background-position:16px 0}}
@media (prefers-reduced-motion:reduce){.skeleton{animation:none}}

/* ---------------------------------------------------------------- source popover */
.pop{position:fixed;z-index:950;max-width:350px;background:var(--panel);border:1px solid var(--green-dim);
  padding:11px 13px;font-size:12.5px;line-height:1.55;box-shadow:0 0 0 1px var(--bg),6px 6px 0 var(--sunken)}
.pop h4{margin:0 0 6px;font:700 10px/1 var(--mono);text-transform:uppercase;letter-spacing:.14em;color:var(--green)}
.pop h4::before{content:"┌ "}
.pop .val{font:700 18px/1.2 var(--mono);margin:0 0 8px;color:var(--ink);font-variant-numeric:tabular-nums}
.pop p{margin:0 0 7px;color:var(--ink-2)}
.pop p:last-child{margin-bottom:0}
.pop a{word-break:break-word;font-size:11.5px}
.pop .rule{background:var(--sunken);padding:6px 8px;color:var(--ink-2);border-left:2px solid var(--amber-dim)}

/* ---------------------------------------------------------------- mobile cards */
.cards{display:none}
.card{background:var(--panel);border:1px solid var(--rule-2);padding:12px 13px;margin-bottom:9px}
.card h3{margin:0 0 3px;font:700 14.5px/1.35 var(--mono);color:var(--ink)}
.card .sub{color:var(--muted);font-size:11.5px;margin:0 0 10px}
.keyrow{display:grid;grid-template-columns:repeat(3,1fr);gap:0;border:1px solid var(--rule);margin-bottom:10px}
.keyrow div{background:var(--panel-2);padding:7px 9px;min-width:0;border-right:1px solid var(--rule)}
.keyrow div:last-child{border-right:0}
.keyrow dt{font:700 9px/1.2 var(--mono);text-transform:uppercase;letter-spacing:.12em;color:var(--muted);margin-bottom:3px}
.keyrow dd{margin:0;font:700 15px/1.2 var(--mono);color:var(--green);font-variant-numeric:tabular-nums;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.card dl.specs{display:grid;grid-template-columns:auto 1fr;gap:2px 12px;margin:0;font-size:12.5px}
.card dl.specs dt{color:var(--muted);min-width:0;overflow-wrap:anywhere}
.card dl.specs dd{margin:0;text-align:right;font-variant-numeric:tabular-nums;min-width:0;overflow-wrap:anywhere}
.card .links a{overflow-wrap:anywhere}
.card details{margin-top:9px;border-top:1px dashed var(--rule);padding-top:8px}
.card summary{cursor:pointer;font-size:11.5px;color:var(--green);list-style:none;text-transform:uppercase;letter-spacing:.1em}
.card summary::-webkit-details-marker{display:none}
.card summary::before{content:"[+] "}
.card details[open] summary::before{content:"[−] "}
.card .links{margin:10px 0 0;font-size:12.5px;display:flex;gap:14px;flex-wrap:wrap}

/* ---------------------------------------------------------------- editorial */
.prose{max-width:82ch;font-size:14.5px;line-height:1.75;color:var(--ink)}
.prose h1{font:700 22px/1.3 var(--mono);letter-spacing:.01em;margin:4px 0 12px;color:var(--ink)}
.prose h2{font:700 13px/1.4 var(--mono);text-transform:uppercase;letter-spacing:.16em;color:var(--green);
  margin:34px 0 12px;padding-bottom:6px;border-bottom:1px solid var(--rule-2)}
.prose h2::before{content:"▍"}
.prose h3{font:700 14px/1.4 var(--mono);margin:22px 0 8px;color:var(--ink)}
.prose p{margin:0 0 14px}
.prose ul,.prose ol{margin:0 0 14px;padding-left:20px}
.prose ul{list-style:none;padding-left:16px}
.prose ul li::before{content:"▸ ";color:var(--green-dim);margin-left:-16px}
.prose li{margin-bottom:6px}
.prose code{background:var(--sunken);padding:1px 5px;color:var(--amber)}
.prose .tablewrap{max-height:none;margin:14px 0}
.prose table{font-size:12.5px}
.prose th,.prose td{white-space:normal;height:auto;padding:7px 10px;line-height:1.5}
.prose thead tr.cols th{position:static;cursor:default;top:auto}
.lede{font-size:15px;line-height:1.7;color:var(--ink-2);margin:0 0 20px;
  border-left:2px solid var(--green-dim);padding-left:12px}
.note{background:var(--panel);border:1px solid var(--rule);border-left:3px solid var(--green-dim);
  padding:11px 14px;margin:18px 0;font-size:13.5px;line-height:1.65;color:var(--ink-2)}
.note strong{color:var(--ink)}

/* ---------------------------------------------------------------- posts */
.dateline{font:700 10.5px/1 var(--mono);text-transform:uppercase;letter-spacing:.14em;
  color:var(--muted);margin:0 0 12px;display:flex;gap:9px;flex-wrap:wrap;align-items:center}
.kind{padding:3px 7px;border:1px solid currentColor;font-weight:700}
.kind.new_model{color:var(--green)}
.kind.price_move{color:var(--ink-2)}
.kind.down{color:var(--red)} .kind.up{color:var(--amber)}
.kind.unsourced{color:var(--muted);border-style:dashed}
.postlist{list-style:none;padding:0;margin:0}
.postlist li{border-bottom:1px solid var(--rule);padding:15px 0}
.postlist li:first-child{border-top:1px solid var(--rule-2)}
.postlist li::before{content:none}
.postlist h3{margin:4px 0 5px;font:700 15px/1.4 var(--mono)}
.postlist h3 a{color:var(--ink);text-decoration:none}
.postlist h3 a::before{content:"> ";color:var(--green)}
.postlist h3 a:hover{color:var(--green);background:none;text-decoration:underline}
.postlist p{margin:0;color:var(--ink-2);font-size:13px;line-height:1.65;max-width:88ch}
.factgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:0;
  border:1px solid var(--rule-2);margin:16px 0}
.factgrid .fact{background:var(--panel);padding:9px 11px;min-width:0;
  border-right:1px solid var(--rule);border-bottom:1px solid var(--rule)}
.factgrid dt{font:700 9.5px/1.2 var(--mono);text-transform:uppercase;letter-spacing:.13em;color:var(--muted);margin-bottom:4px}
.factgrid dd{margin:0;font:700 14px/1.35 var(--mono);color:var(--ink);font-variant-numeric:tabular-nums;word-break:break-word}
.factgrid .src{display:block;font:400 10.5px/1.45 var(--mono);color:var(--muted);margin-top:4px}
.factgrid .src::before{content:"└ "}
.factgrid .src a{color:var(--muted);text-decoration:none;border-bottom:1px solid var(--rule-2)}
.factgrid .src a:hover{color:var(--green);background:none}
.claim{border:1px solid var(--rule);border-left:3px solid var(--green-dim);background:var(--panel);
  padding:12px 14px;margin:11px 0;font-size:13.5px;line-height:1.65}
.claim p{margin:0 0 8px;color:var(--ink)}
.claim .basis{font-size:11px;color:var(--muted);margin:0;line-height:1.55}
.claim a.deep{display:inline-block;font-size:11.5px;text-transform:uppercase;letter-spacing:.1em;
  text-decoration:none;border:1px solid var(--green-dim);color:var(--green);padding:4px 9px;margin-bottom:9px}
.claim a.deep:hover{background:var(--green);color:var(--bg);border-color:var(--green)}
.bigmove{display:flex;gap:26px;align-items:center;flex-wrap:wrap;border:1px solid var(--rule-2);
  padding:15px 17px;margin:16px 0;background:var(--panel)}
.bigmove .now{font:700 30px/1 var(--mono);color:var(--ink);font-variant-numeric:tabular-nums}
.bigmove .delta{font:700 17px/1 var(--mono)}
.bigmove .delta.down{color:var(--red)} .bigmove .delta.up{color:var(--amber)}
.bigmove .was{color:var(--muted);font-size:11px;margin-top:5px;text-transform:uppercase;letter-spacing:.1em}
.bigmove .plot{font-size:17px;line-height:1;letter-spacing:-.02em;display:block}
.warnbox{border:1px dashed var(--amber-dim);background:var(--amber-wash);color:var(--ink-2);
  padding:12px 14px;margin:16px 0;font-size:13px;line-height:1.65}
.warnbox::before{content:"[!] ";color:var(--amber);font-weight:700}
.legend{font-size:11.5px;color:var(--muted);display:flex;gap:16px;flex-wrap:wrap;margin:10px 0 0}

footer{border-top:1px solid var(--rule-2);margin-top:40px;padding:18px 16px;font-size:11.5px;
  color:var(--muted);line-height:1.7;background:var(--panel)}
footer .wrap{display:flex;gap:8px 34px;flex-wrap:wrap}
footer p{margin:0;max-width:70ch}
footer a{color:var(--ink-2)}

/* ---------------------------------------------------------------- the app shell
 * Applied only to the database page (`body.app`) and only where it genuinely fits. Below 901px
 * the table is replaced by cards, so there is nothing to pin; below 640px tall there is not enough
 * room for chrome plus a usable pane, and forcing a shell there would produce a two-row table. In
 * both cases the page simply scrolls, which is the fallback defined above.
 *
 * The height threshold is 520px, not something rounder, because 1366x768 is still a common laptop
 * and leaves roughly a 620px viewport once browser chrome is subtracted. A shell that fell back at
 * 640px would have dropped exactly those users onto the fallback. The density rules below buy the
 * pane back the room that needs. */
@media (min-width:901px) and (min-height:520px){
  body.app{height:100dvh;overflow:hidden;display:flex;flex-direction:column}
  body.app header.site{position:static;flex:0 0 auto}
  /* `.wrap` centres with `margin:0 auto`. On a flex item that is a trap: auto margins in the
     cross axis suppress stretching and make the item size to fit-content, so `main` resolved to
     its own 1560px max-width inside a 1440px body and pushed the entire PAGE 120px wide. Centre
     with align-self instead and let width:100% do the sizing. */
  body.app main{flex:1 1 auto;min-height:0;min-width:0;width:100%;align-self:center;margin:0;
    display:flex;flex-direction:column;overflow:hidden;padding-bottom:0}
  body.app main>*{flex:0 0 auto}
  body.app main>.tablewrap{flex:1 1 auto;min-height:0;overflow:auto;margin-bottom:16px}
  /* While the dataset is loading, and when a filter matches nothing, the pane holds no rows —
     give the height to the message instead of to an empty bordered box. */
  body.app main>.tablewrap:has(tbody:empty){display:none}
  body.app main>.loading,body.app main>.empty:not([hidden]){flex:1 1 auto;min-height:0;overflow:auto;margin-bottom:16px}
  /* Every pixel of chrome is a row of the table the reader cannot see. At 1440x900 the chrome was
     577px and the pane 323px — eleven rows. These three rules give the pane back ~140px. */
  body.app .disclosure{padding:6px 11px;margin-bottom:9px;font-size:11.5px}
  body.app .controls{padding:9px 11px 8px;margin-bottom:9px}
  body.app .controls .row+.row{margin-top:8px;padding-top:8px}
  body.app footer{flex:0 0 auto;margin-top:0;padding:8px 16px;font-size:11px}
  body.app footer .wrap{gap:4px 24px}
  body.app .tip{display:none}
  body.app main>.tablewrap{min-height:150px}
}
/* Short viewports: the chrome is squeezed rather than the pane, because the pane is the product.
   Measured at 1280x620 this takes the chrome from 473px to ~370px — six visible rows to eleven. */
@media (min-width:901px) and (max-height:820px){
  body.app header.site .wrap{min-height:38px}
  body.app header.site h1{padding:8px 0;font-size:14px}
  body.app .disclosure{padding:4px 10px;font-size:11px;margin-bottom:7px;line-height:1.45}
  body.app .controls{padding:8px 10px 6px;margin-bottom:7px}
  body.app .controls .row{gap:6px 11px}
  body.app .controls .row+.row{margin-top:6px;padding-top:6px}
  body.app .f{gap:2px}
  body.app .f select,body.app .f input[type=search]{min-height:27px;padding:3px 7px;font-size:12.5px}
  body.app .f select{background-position:calc(100% - 11px) 14px,calc(100% - 8.5px) 11px}
  body.app .checkline{min-height:27px}
  body.app .summary{margin-bottom:6px}
  body.app footer{padding:5px 16px;font-size:10.5px}
  body.app footer p:nth-child(2){display:none}
}

/* ---------------------------------------------------------------- responsive */
@media (max-width:900px){
  body{font-size:13.5px}
  main{padding:11px}
  .tablewrap{display:none}
  .cards{display:block}
  .controls{padding:11px}
  .f{flex:1 1 128px}
  .f input[type=search]{min-width:100%}
  .f select{width:100%}
  .bigmove .now{font-size:25px}
  .bigmove .plot{font-size:14px}
  header.site .wrap{padding:0 11px}
  header.site nav{width:100%;margin-left:0;border-top:1px solid var(--rule);
    padding:3px 0;overflow-x:auto;scrollbar-width:none}
  header.site nav a{padding:6px 9px;border-color:transparent}
  .summary{padding:7px 1px;margin:0 0 7px;border-bottom:1px solid var(--rule)}
  .factgrid{grid-template-columns:1fr}
}
@media print{
  header.site,.controls,body::after{display:none}
  .tablewrap{max-height:none;overflow:visible}
  body{background:#fff;color:#000}
}
