/* PROTOTYPE — The Broadsheet, chosen 2026-09-05. Monochrome base; the colour
   arrived later and lives in one block at the foot of this file, with its own
   exits. Everything between here and that banner is still black and white, and
   changing that is a change to invariant 1 in docs/site-redesign-2026-09-spec.md.
   Levels are desks: the Scotland desk, the Islay desk, the Lagavulin desk. The eleven bottles are the whole universe. */
:root{--display:"Bricolage Grotesque","Helvetica Neue",Arial,sans-serif;--body:"Newsreader",Georgia,serif;--mono:"IBM Plex Mono",ui-monospace,Menlo,monospace;
  --g:#FFFFFF;--ink:#111111;--mu:#666666;--rule:#E2E2E2;--rs:#BDBDBD;--wash:#F5F5F5;--sunk:#EBEBEB}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{background:var(--g);color:var(--ink);font-family:var(--body);font-size:17px;line-height:1.55;font-variant-numeric:tabular-nums;min-height:100vh}
a{color:inherit}
img{max-width:100%;height:auto;display:block;filter:grayscale(1)}
svg text{font-family:var(--mono)}
details>summary{cursor:pointer}
:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.tblwrap{overflow-x:auto}
.mast{padding:26px 32px 12px;border-bottom:3px double var(--ink);display:flex;justify-content:space-between;align-items:flex-end;gap:20px;flex-wrap:wrap}
.mast .name{font:800 40px/1 var(--display);letter-spacing:-.03em}
.mast .name a{text-decoration:none}
.mast .tag{font-style:italic;color:var(--mu);font-size:15px;margin-top:4px}
.mast .asof{font:500 11px var(--mono);color:var(--mu);letter-spacing:.06em;text-transform:uppercase;text-align:right;line-height:1.6}
nav.desks{padding:10px 32px;border-bottom:1px solid var(--ink);font:500 11px var(--mono);letter-spacing:.08em;text-transform:uppercase;display:flex;gap:6px 22px;flex-wrap:wrap;align-items:baseline}
nav.desks a{text-decoration:none;padding-bottom:2px;border-bottom:2px solid transparent}
nav.desks a.cur{border-bottom-color:var(--ink)}
nav.desks a:hover{border-bottom-color:var(--rs)}
/* Three navigational levels, three weights: regions in ink, distilleries a step down,
   the wire held out at the right edge. The eleven bottles are reached from the grid. */
nav.desks.top{border-bottom-color:var(--rule);padding-bottom:7px}
nav.desks.sub{padding-top:7px;gap:6px 18px}
nav.desks.sub a{color:var(--mu)}
nav.desks.sub a.cur,nav.desks.sub a:hover{color:var(--ink)}
nav.desks .wire{margin-left:auto;color:var(--mu)}
nav.crumbs{padding:8px 32px;border-bottom:1px solid var(--rule);font:400 11px var(--mono);letter-spacing:.06em;text-transform:uppercase;color:var(--mu)}
nav.crumbs a{text-decoration:none}
nav.crumbs a:hover{text-decoration:underline}
.wrap{max-width:1120px;margin:0 auto;padding:0 32px}
.front{display:grid;grid-template-columns:1.55fr 1fr;gap:40px;padding:28px 0 20px;border-bottom:1px solid var(--rule)}
.kicker{font:500 11px var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ink);margin-bottom:8px;display:block}
.kicker.mu{color:var(--mu)}
.article h1,h1.big{font:800 clamp(30px,3.6vw,42px)/1.02 var(--display);letter-spacing:-.03em;margin:0 0 12px;text-wrap:balance}
.article .stand{font-size:21px;line-height:1.4;font-weight:500;margin:0 0 14px}
.article img{margin:14px 0;border:1px solid var(--rule)}
.article .body{max-width:66ch}
.article .body h2,.article .body h3{font:700 22px/1.15 var(--display);letter-spacing:-.02em;margin:26px 0 8px}
.article .body p{margin:0 0 14px}
.article .body blockquote{margin:12px 0;padding-left:16px;border-left:2px solid var(--ink);color:var(--mu);font-style:italic}
.article .foot{font-size:14px;color:var(--mu);border-top:1px solid var(--rule);padding-top:10px;margin-top:16px}
.article .body table{font-family:var(--mono);font-size:12px;border-collapse:collapse}
.article .body td,.article .body th{padding:4px 8px;border-bottom:1px solid var(--rule);text-align:left}
.side{display:flex;flex-direction:column;gap:22px}
.tweet{border:1px solid var(--ink);padding:14px 16px;background:var(--g)}
.tweet .who{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.tweet .av{width:34px;height:34px;border-radius:50%;background:var(--ink);color:#fff;font:800 14px var(--display);display:flex;align-items:center;justify-content:center}
.tweet .nm{font:600 14px var(--display)}
.tweet .hn{font:400 11px var(--mono);color:var(--mu)}
.tweet .tx{font-size:17px;line-height:1.45}
.tweet .tm{font:400 11px var(--mono);color:var(--mu);margin-top:8px}
.thr .t{font:600 18px/1.25 var(--display);margin:0 0 8px;letter-spacing:-.01em}
.thr .t a{text-decoration:none}
.thr p{font-size:15.5px;line-height:1.45;margin:0 0 10px;padding-left:28px;position:relative}
.thr p b{position:absolute;left:0;top:3px;font:400 10px var(--mono);color:var(--mu)}
.thr p.card{padding-left:0;font-family:var(--mono);font-size:12px;color:var(--mu)}
.thr p.card b{position:static;color:var(--ink);font:600 13px var(--display)}
.thr .more{font:500 11px var(--mono);color:var(--mu)}
.thr .more a{text-decoration:none;border-bottom:1px solid var(--rs)}
h2.sec{font:800 22px/1.1 var(--display);letter-spacing:-.02em;margin:30px 0 12px;padding-top:10px;border-top:1px solid var(--ink)}
h2.sec small{font:500 11px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--mu);margin-left:12px}
.strip{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:18px 22px}
.tk{border-top:2px solid var(--ink);padding-top:6px}
.tk a{text-decoration:none}
.tk .n{font:600 14px var(--display);line-height:1.2}
.tk .p{font:600 20px var(--mono);margin:2px 0}
.tk .p small{font-size:10px;font-weight:400;color:var(--mu);margin-left:6px;letter-spacing:.06em;text-transform:uppercase}
.tk .r{font:400 11px var(--mono);color:var(--mu)}
.tk .c{font:400 10px var(--mono);color:var(--ink);letter-spacing:.06em;text-transform:uppercase;margin-top:3px}
.cards{display:grid;grid-template-columns:1fr 1fr;gap:0 32px}
.card{padding:14px 0;border-bottom:1px solid var(--rule)}
.card .fmt{font:500 10px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--mu)}
.card h3{font:600 18px/1.25 var(--display);margin:4px 0 6px;letter-spacing:-.01em}
.card h3 a{text-decoration:none}
.card p{margin:0 0 6px;font-size:15.5px}
.card .meta{font:400 11px var(--mono);color:var(--mu)}
.cardsB{display:grid;grid-template-columns:1fr 1fr;gap:22px;margin:12px 0 18px}
.cardB h4{font:800 22px/1.05 var(--display);letter-spacing:-.02em;margin:0 0 8px;border-bottom:2px solid var(--ink);padding-bottom:6px}
.cardB ul{list-style:none;margin:0;padding:0}
.cardB li{padding:4px 0;border-bottom:1px solid var(--rule);font-size:15px}
.cardB li b{font:500 10px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--mu);display:block}
.stat{font-family:var(--mono);font-size:13px;background:var(--wash);padding:10px 14px;margin:0 0 16px;list-style:none}
.stat li{margin:4px 0}
.analysis{font-size:18px;line-height:1.55;font-weight:500}
.fn{border-top:1px solid var(--ink);margin-top:22px;padding-top:10px;font-size:13.5px;color:var(--mu)}
.fn h4{font:500 10px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--mu);margin:12px 0 6px}
.fn li{margin:3px 0}
.fn details{margin:6px 0}
.fn details summary{font:500 10px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--mu)}
table{border-collapse:collapse;width:100%;font-family:var(--mono);font-size:12px}
th{text-align:left;font-weight:500;color:var(--mu);font-size:10px;letter-spacing:.06em;text-transform:uppercase;padding:6px 8px;border-bottom:1px solid var(--rs)}
td{padding:6px 8px;border-bottom:1px solid var(--rule)}
td.num,th.num{text-align:right}
tr.ref td{background:var(--wash)}
.ph{font-family:var(--mono);font-size:12px}
.ph .note{font-family:var(--body);font-size:14px;color:var(--mu);margin-top:8px}
.empty{font-style:italic;color:var(--mu);padding:6px 0}
.ch{display:inline-block;font:500 10px var(--mono);letter-spacing:.06em;text-transform:uppercase;padding:2px 6px;border:1px solid var(--rs);margin-right:4px;color:var(--mu);white-space:nowrap}
.ch.dark{background:var(--ink);color:#fff;border-color:var(--ink)}
.prov{font-family:var(--mono);font-size:10px;letter-spacing:.04em;color:var(--mu)}
details.shelf{margin:20px 0}
details.shelf summary{font:600 14px var(--display);padding:10px 0;border-top:1px solid var(--ink);border-bottom:1px solid var(--rule)}
.sparkline{display:inline-block;vertical-align:middle}
footer{border-top:3px double var(--ink);margin-top:40px;padding:14px 32px 60px;font:400 11px var(--mono);color:var(--mu);letter-spacing:.04em}
@media (max-width:1000px){.front,.cards,.cardsB{grid-template-columns:1fr}.mast{padding:18px 18px 10px}.wrap,nav.desks,nav.crumbs,footer{padding-left:18px;padding-right:18px}nav.desks{gap:4px 14px}}

/* publish.sh stamps the ref it built; a nightly page must never pass for main */
.asof .build{font-family:"IBM Plex Mono",monospace;font-size:.72rem;letter-spacing:.02em}

/* ═══════════════════════════════════════════════════════════════════════════
   COLOUR — the scheme system. See site/lib/colour.js for the registry and
   docs/reference/2026-08-13-ten-drafts-brief.css for where the palettes came
   from.

   What ships: SCHEME=mark, MARK=carried. The page is black and white and one
   element carries a vermilion — the price that was not observed this week.
   The precedent is the vermilion seal on an ink painting: small, off to the
   side, and unexplained until you go looking. Systematic colour was tried
   first (every kicker, every rule, three rounds of raising the hue) and went
   invisible, because a legend stops being looked at. One mark does not.

   Switching is an env var, never an edit:
     SCHEME=tufte INTENSITY=washes npm run build:guy
   The accent machinery below is inert while SCHEME=mark and costs nothing;
   it is kept so a different answer is a build flag away.

   Invariant 1 holds: the word "carried" is printed in ink beside the mark, so
   the meaning survives the colour being removed.
   ═══════════════════════════════════════════════════════════════════════════ */
:root{
  /* The mark is not a palette token. It is one fixed vermilion, adjusted only
     enough to hold on a dark ground, and it never participates in a scheme. */
  --mark:oklch(0.505 0.185 33);
  /* Accent tokens default to ink, so every rule below is a no-op until a
     scheme sets them. This is what makes SCHEME=mark cost nothing. */
  --accent:var(--ink);
  --accent-soft:var(--wash);
  --paper:var(--g);
}
body{background:var(--paper)}

/* ── The one mark ──────────────────────────────────────────────────────── */
.tk[data-mark]{border-top-color:var(--mark)}
.tk[data-mark] .c{color:var(--mark);font-weight:600}
.tk[data-mark] .c::before{content:"";display:inline-block;width:6px;height:6px;
  background:var(--mark);margin-right:5px;vertical-align:1px}
.ch[data-mark]{background:var(--mark);border-color:var(--mark);color:var(--g)}

/* ── Systematic accent, for the schemes that are not `mark` ─────────────── */
[data-scheme="tufte"],[data-scheme="taxonomy"],[data-scheme="flavour"]{
  --accent:#1A7A4C; --accent-soft:#E7F2EC; --paper:#FFFFF8;
}
[data-scheme]:not([data-scheme="mark"]) .mast{border-bottom-color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) .kicker{color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) nav.desks a.cur,
[data-scheme]:not([data-scheme="mark"]) nav.desks a:hover{border-bottom-color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) nav.desks.sub a.cur,
[data-scheme]:not([data-scheme="mark"]) nav.desks.sub a:hover{color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) details.shelf summary,
[data-scheme]:not([data-scheme="mark"]) .fn details summary{color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) h2.sec{border-top-color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) .tk{border-top-color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) footer{border-top-color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) .article .body blockquote{border-left-color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) .ch.dark{background:var(--accent);border-color:var(--accent)}
[data-scheme]:not([data-scheme="mark"]) tr.ref td,
[data-scheme]:not([data-scheme="mark"]) .stat{background:var(--accent-soft)}
/* washes and blocks give the accent area — the lesson of 2026-09-06 */
[data-intensity="washes"] h2.sec,[data-intensity="blocks"] h2.sec{background:var(--accent-soft);padding:10px 12px}
[data-intensity="washes"] .kicker,[data-intensity="blocks"] .kicker{background:var(--accent-soft);display:inline-block;padding:3px 7px}
[data-intensity="blocks"] .mast{background:var(--accent);border-bottom-color:var(--accent)}
[data-intensity="blocks"] h2.sec{background:var(--accent)}

/* Reversed-out text takes the ground, never a literal white, so it survives
   the theme flip. Identical to #fff while --g is #FFFFFF. */
.tweet .av{color:var(--g)}

/* ── Dark ────────────────────────────────────────────────────────────────
   The whole monochrome scale inverts, not just the accent. Declared twice on
   purpose: the media query is guarded so an explicit light choice beats a dark
   device, and the attribute block repeats it so an explicit dark choice beats
   a light device. CSS cannot say both in one rule. */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    color-scheme:dark;
    --g:#151C1A; --ink:#E8EEEB; --mu:#8B9791; --rule:#26302D; --rs:#3A4642;
    --wash:#161E1C; --sunk:#1B2422; --paper:#0D1211;
    --mark:oklch(0.735 0.165 36);
  }
  :root:not([data-theme="light"])[data-scheme="tufte"],
  :root:not([data-theme="light"])[data-scheme="taxonomy"],
  :root:not([data-theme="light"])[data-scheme="flavour"]{
    --accent:#6FBE87; --accent-soft:#16241C; --paper:#12140F;
  }
  /* The ten cohort PNGs are raster black-on-white and cannot follow a token.
     T07 retires them and this rule goes with them. */
  :root:not([data-theme="light"]) img[src*="/charts/"]{filter:grayscale(1) invert(1)}
}
:root[data-theme="dark"]{
  color-scheme:dark;
  --g:#151C1A; --ink:#E8EEEB; --mu:#8B9791; --rule:#26302D; --rs:#3A4642;
  --wash:#161E1C; --sunk:#1B2422; --paper:#0D1211;
  --mark:oklch(0.735 0.165 36);
}
:root[data-theme="dark"][data-scheme="tufte"],
:root[data-theme="dark"][data-scheme="taxonomy"],
:root[data-theme="dark"][data-scheme="flavour"]{
  --accent:#6FBE87; --accent-soft:#16241C; --paper:#12140F;
}
:root[data-theme="dark"] img[src*="/charts/"]{filter:grayscale(1) invert(1)}

/* ── The toggle ──────────────────────────────────────────────────────────
   Cycles auto → light → dark → auto, so the device setting stays the resting
   state. Hidden unless the head script ran: with JavaScript off there is no
   dead control, just the device setting. */
.theme{font:500 11px var(--mono);letter-spacing:.06em;text-transform:uppercase;color:var(--mu);
  background:none;border:0;border-bottom:2px solid transparent;padding:0 0 2px;margin-top:2px;
  cursor:pointer;display:none}
:root.js .theme{display:inline-block}
.theme:hover{color:var(--ink);border-bottom-color:var(--mu)}
.theme::before{content:"◐ "}

/* ── The word-cloud plate ────────────────────────────────────────────────
   Built from the review corpus as amber type on a navy ground, which is the
   opposite of everything else here. Rather than regenerate them, invert: in
   light they become ink on paper, and in dark they are already right. Exactly
   the charts rule, the other way up. */
figure.cloud{margin:22px 0 6px;padding-top:10px;border-top:1px solid var(--ink)}
figure.cloud img{filter:grayscale(1) invert(1);border:1px solid var(--rule);
  width:100%;max-width:800px;height:auto}  /* never past native, or the type goes soft */
figure.cloud figcaption{font:400 11px var(--mono);color:var(--mu);letter-spacing:.04em;margin-top:7px}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) figure.cloud img{filter:grayscale(1)}
}
:root[data-theme="dark"] figure.cloud img{filter:grayscale(1)}

/* ── Furniture: sidebars and the advertising slots ───────────────────────
   A layout that has never held a 300×250 has not been tested. The slots below
   are the real IAB units at true size, so switching furniture on is a genuine
   stress test of the grid rather than a mock-up. The control in the masthead
   hides only [data-ad] — editorial furniture such as the word clouds stays,
   so a page can be read with and without the advertising. */
.slot{margin:16px 0}
.slot-in{position:relative;display:flex;align-items:center;justify-content:center;
  width:100%;max-width:var(--sw);aspect-ratio:var(--ar);  /* unitless, or it collapses */
  border:1px dashed var(--rs);background:var(--wash)}
.slot-lbl{font:500 9px var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--mu)}
.slot-in::after{content:attr(data-size);position:absolute;bottom:5px;right:7px;
  font:400 8px var(--mono);color:var(--rs)}
.slot-strip,.slot-foot{display:flex;justify-content:center}
/* off is the whole point of the control: the slot leaves the flow entirely,
   so the page reflows as if it had never been sold */
:root[data-furniture="off"] [data-ad]{display:none}
/* ...which T03 made load-bearing. Removing the sidebar's "nothing here yet"
   placeholders means the side column can now hold ONLY the rail slot — four
   pages today, /country/scotland/ among them — and with the reader's control
   off that leaves an empty 1fr track beside the hero, which reads as a
   mistake rather than as a choice. Collapse to one column when nothing
   visible is left. Scoped to furniture-off: with ads on the slot is content
   and the two-column grid is correct.

   NOTE the shape of the selector: `:has()` may not be nested inside another
   `:has()` — the first version of this rule was
   `.front:has(> .side:not(:has(> :not([data-ad]))))`, which is invalid, so the
   whole declaration was dropped and the column stayed. Ask instead whether the
   side holds anything that is NOT an ad, and negate that. */
:root[data-furniture="off"] .front:not(:has(> .side > :not([data-ad]))){grid-template-columns:1fr}
:root[data-furniture="off"] .front:not(:has(> .side > :not([data-ad]))) .side{display:none}

.furn{font:500 11px var(--mono);letter-spacing:.06em;text-transform:uppercase;color:var(--mu);
  background:none;border:0;border-bottom:2px solid transparent;padding:0 0 2px;margin-top:2px;
  cursor:pointer;display:none}
:root.js .furn{display:inline-block}
.furn:hover{color:var(--ink);border-bottom-color:var(--mu)}
.furn::before{content:"▤ "}

/* ── Word clouds as type ─────────────────────────────────────────────────
   Not a picture: spans in the page's own faces, so they follow the theme,
   reflow at any width, and can be selected and searched. Size follows rank —
   the dossiers order these words but do not weight them, and the caption says
   so rather than inventing a number. */
.cloudfig{margin:18px 0 0;padding-top:10px;border-top:1px solid var(--ink)}
.cloudfig figcaption{font:500 10px var(--mono);letter-spacing:.1em;text-transform:uppercase;
  color:var(--mu);margin-bottom:8px}
.cloudfig small{display:block;font:400 10px var(--mono);color:var(--mu);margin-top:8px;
  letter-spacing:.03em}
.cloudwords{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 12px;
  font-family:var(--display);font-weight:600;line-height:1.15}
.cloudwords span{white-space:nowrap}

/* ── The cohort chart (T07) ──────────────────────────────────────────────
   Drawn, not shipped: this replaces ten hand-committed PNGs. The SVG's
   viewBox is 380 wide so it scales UP into the measure on a desktop and sits
   at roughly 1:1 on a phone — a chart designed at 640 and shrunk is the one
   whose labels go unreadable at 390px. Type inside it inherits the mono face
   from the `svg text` rule above, so it needs no palette of its own. */
figure.cohortfig{margin:14px 0 16px;padding-top:10px;border-top:1px solid var(--rule)}
figure.cohortfig svg{display:block;width:100%;max-width:620px;height:auto}

/* ── The deviation bar (T08) ─────────────────────────────────────────────
   The premium, as one bar per ticket on one scale shared across the eleven,
   so the grid reads as a small multiple instead of eleven sentences. D2 is
   decided as density: solid over, hairline under (see the SVG). No hue is
   involved, so the meaning survives invariant D-2's test by construction.

   preserveAspectRatio="none" on the SVG is deliberate — the bar should span
   whatever width the card has, and stretching a rectangle horizontally is
   lossless. The zero rule lands at the same fraction of every card, and the
   cards are equal width in the grid, so the rules align across the row. */
.tk svg.dev{display:block;width:100%;height:12px;margin:4px 0 2px}
.scalenote{font:400 10px var(--mono);color:var(--mu);letter-spacing:.06em;
  text-transform:uppercase;margin:-6px 0 12px}
/* The sparkline is real but secondary — price history, not the premium. */
.tk .sparkline{opacity:.55}

/* ── The approvals-bypass marker (T06) ───────────────────────────────────
   A bypass build shows every unapproved draft, so it must never be mistakable
   for the real public site. Unconditional — NOT behind model.operator — because
   the public+bypass build is precisely the one with no operator chrome to warn
   you. Reversed out of the ink rather than coloured: --mark is spoken for and
   invariant D-1 allows one live hue, so the emphasis here is weight. */
.bypass{display:inline-block;background:var(--ink);color:var(--g);
  font:600 10px var(--mono);letter-spacing:.1em;text-transform:uppercase;
  padding:2px 6px;margin-top:3px}

/* ── The river's day rules, and the cut (T09) ────────────────────────────
   The front page carries 8 cards and says how many it did not. A river that
   simply stops reads as truncation; one that names the remainder and links it
   reads as an issue with an archive behind it. */
.dayrule{font:500 10px var(--mono);letter-spacing:.14em;text-transform:uppercase;
  color:var(--mu);border-top:1px solid var(--rule);padding-top:6px;margin:18px 0 12px}
.dayrule:first-of-type{margin-top:10px}
p.more{font:500 11px var(--mono);letter-spacing:.06em;text-transform:uppercase;margin:16px 0 0}
p.more a{border-bottom:1px solid var(--rs)}
/* The reader's wire: an index, not the operator's evidence table. */
.wirerow{display:flex;justify-content:space-between;gap:20px;align-items:baseline;
  padding:7px 0;border-bottom:1px solid var(--rule)}
.wirerow a{font:600 15px var(--body);line-height:1.25}
.wirerow span{font:400 10px var(--mono);color:var(--mu);letter-spacing:.05em;
  text-transform:uppercase;white-space:nowrap}
@media (max-width:640px){.wirerow{flex-direction:column;gap:3px}
  .wirerow span{white-space:normal}}
/* The portal (operator content summary, 2026-09-11): three tables over the wire's list. */
.portal h3.sub{font:600 14px/1.2 var(--display);margin:24px 0 8px}
.portal .sites{display:flex;flex-wrap:wrap;gap:6px 28px;font:12px var(--mono);color:var(--mu);margin:8px 0 4px}
.portal .sites b{color:var(--ink);font-weight:500}
.portal .bar{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;margin:10px 0 8px;font:12px var(--mono)}
.portal .bar input,.portal .bar select{font:12px var(--mono);padding:4px 6px;border:1px solid var(--rs);background:transparent;color:var(--ink);border-radius:0}
.portal .bar input{min-width:26ch}
.portal .bar .count{margin-left:auto;color:var(--mu)}
.portal td.lk{white-space:nowrap}
.portal td.tt{max-width:38ch}
.portal td.tt a{font-family:var(--body);font-size:13px}
.portal tr[hidden]{display:none}

/* /vintages/ — the vintage price series (ask 3), an operator instrument over every Stockcode */
.vintages td.slot{font-size:11px;white-space:nowrap;line-height:1.2}
.vintages th.slot{font-size:10px}
.vintages td.slot small{color:var(--mu)}
.vintages td.slot i{color:var(--mu);font-style:normal;font-size:9px}
.vintages td.slot b{color:var(--ink);margin-left:2px}
.vintages td.empty{opacity:.4}
.vintages td.shelf_checked{border-bottom:1px dashed var(--rs)}
.vintages tr.nameonly td:first-child{border-left:2px dashed var(--rs)}
.vintages td.code{font:11px var(--mono);color:var(--mu)}
.vintages td.sp svg{vertical-align:middle}
.vintages td.down{color:var(--mu)}
.vintages td.tt{max-width:30ch;font-size:12px}
