/* ============================================================================
   bento.css — THE shell every Insights board wears (Sep 2026).

   Phil picked the "bento" out of three mockups for the outbound freight board
   ("it looks like a spreadsheet on steroids"; he wanted it sexy, sleek, easy,
   with speed top priority) and settled that the shell is for EVERY board. So
   it lives here rather than inline on one page: four boards with four copies
   of these tokens is the two-sources trap this repo keeps re-learning, and it
   surfaces as two boards disagreeing about what "good" is coloured.

   What a board supplies for itself: its metrics, its data, its pages. What it
   gets from here: the ground, the type, the blocks, the page bar, the filter
   drawer, the tables, the charts, the paste dialog and the print sheet.

   Charts are hand-drawn SVG — there is deliberately no chart library and no
   CDN round trip anywhere in this shell.
   ========================================================================== */
:root{
  color-scheme:light;
  --ground:#F4F5FA;--paper:#FFFFFF;--paper2:#EDEFF6;--ink:#0E0F1A;--ink2:#4A4D5E;--ink3:#7B7F92;--edge:#0E0F1A;
  --ot:#00A862;--if:#2B4CFF;--cost:#E63F33;--cases:#E09400;
  --on-ot:#fff;--on-if:#fff;--on-cost:#fff;--on-cases:#0E0F1A;
  --good:#00A862;--warn:#E09400;--bad:#E63F33;
  /* categorical series — one per series, fixed order, never cycled */
  --s1:#2a78d6;--s2:#eb6834;--s3:#1baf7a;--s4:#eda100;--s5:#e87ba4;
  --spring:cubic-bezier(.34,1.56,.64,1);--ease:cubic-bezier(.2,.8,.2,1);
}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){color-scheme:dark;
  --ground:#0B0B12;--paper:#15161F;--paper2:#1E1F2B;--ink:#F4F5FA;--ink2:#B3B6C6;--ink3:#868AA0;--edge:#F4F5FA;
  --ot:#00C974;--if:#5A74FF;--cost:#FF5A4E;--cases:#FFBE2E;--on-if:#0B0B12;
  --good:#00C974;--warn:#FFBE2E;--bad:#FF5A4E;
  --s1:#3987e5;--s2:#e3703f;--s3:#25c98a;--s4:#e0a72b;--s5:#e894b5;}}
:root[data-theme="dark"]{color-scheme:dark;
  --ground:#0B0B12;--paper:#15161F;--paper2:#1E1F2B;--ink:#F4F5FA;--ink2:#B3B6C6;--ink3:#868AA0;--edge:#F4F5FA;
  --ot:#00C974;--if:#5A74FF;--cost:#FF5A4E;--cases:#FFBE2E;--on-if:#0B0B12;
  --good:#00C974;--warn:#FFBE2E;--bad:#FF5A4E;
  --s1:#3987e5;--s2:#e3703f;--s3:#25c98a;--s4:#e0a72b;--s5:#e894b5;}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--ground);color:var(--ink);font-family:'DM Sans','Segoe UI',system-ui,sans-serif;font-size:16px;line-height:1.35;
  padding-block:0 12px;padding-inline:clamp(14px,2.4vw,32px);font-variant-numeric:tabular-nums;overflow-x:hidden;-webkit-font-smoothing:antialiased;min-height:100vh}
h1,h2,h3,.num,.big,.mv,.flag b{font-family:'Bricolage Grotesque','DM Sans',system-ui,sans-serif}
button,select,input,textarea{font-family:inherit;color:inherit}
button{cursor:pointer;border:0;background:none}
button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid var(--if);outline-offset:2px}
a{color:inherit}
::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:var(--ink3);border-radius:4px}
.stage{position:relative;max-width:1400px;margin:0 auto}

/* ── the way out (Phil, Sep 2026: no way back to Insights or The Hive from in
      here). It is also the way ACROSS: the boards that share a feed name each
      other, so nobody has to go out to the menu to change lane. Sticky, so it
      is in reach from the foot of a long board. ── */
.hivenav{position:sticky;top:0;z-index:21;background:var(--ground);display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-block:10px 8px}
.hivenav a{display:inline-flex;align-items:center;gap:7px;padding:7px 14px;border:3px solid var(--edge);border-radius:999px;background:var(--paper);color:var(--ink);
  font-weight:800;font-size:13.5px;text-decoration:none;box-shadow:3px 3px 0 var(--edge);white-space:nowrap;
  transition:transform .18s var(--spring),box-shadow .18s,background .12s,color .12s}
.hivenav a:hover{transform:translate(-1px,-2px);box-shadow:5px 6px 0 var(--edge)}
.hivenav a:active{transform:translate(3px,3px);box-shadow:0 0 0 var(--edge)}
.hivenav a.here{background:var(--edge);color:var(--ground);cursor:default;transform:none;box-shadow:3px 3px 0 var(--edge)}
.hivenav a .e{font-size:15px;line-height:1}
.hivenav .sep{flex:1 1 12px;min-width:12px;height:3px;background:var(--edge);border-radius:2px;opacity:.22}
/* ONLY LIVE BOARDS ARE DESTINATIONS — a mockup sitting beside a live one in the
   same row says they are peers. A board on sample data still has to answer
   "where am I", so on its own page it appears as this: not a link, and saying
   what it is. */
.hivenav .mock{display:inline-flex;align-items:center;gap:7px;padding:7px 14px;border:3px dashed var(--cost);border-radius:999px;
  background:var(--paper);font-weight:800;font-size:13.5px;color:var(--ink2);white-space:nowrap}
.hivenav .mock b{background:var(--cost);color:#fff;border-radius:999px;padding:1px 9px;font-size:11px;letter-spacing:.06em;text-transform:uppercase}

/* ── header ── */
.bar{display:flex;align-items:flex-end;justify-content:space-between;gap:14px;flex-wrap:wrap;padding-block:18px 14px}
.bar h1{font-size:clamp(26px,3.2vw,42px);font-weight:800;letter-spacing:-.03em;line-height:.98}
.bar .when{font-weight:600;color:var(--ink2);margin-top:6px;font-size:15px}
.bar .when b{color:var(--ink);font-weight:700}
.bar .lede{font-size:13px;color:var(--ink3);font-weight:600;margin-top:3px}
.bar .lede a{text-decoration:none;border-bottom:1px dotted var(--ink3)}
.ctl{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.seg{display:inline-flex;border:3px solid var(--edge);border-radius:13px;overflow:hidden;background:var(--paper)}
.seg button{padding:8px 13px;color:var(--ink);font-weight:700;font-size:14px;border-right:3px solid var(--edge);transition:background .12s,color .12s;white-space:nowrap}
.seg button:last-child{border-right:0}
.seg button.on{background:var(--edge);color:var(--ground)}
/* SAY THE COLOUR. `button{color:inherit}` above is not enough on its own:
   a button does not inherit colour per spec — it takes `buttontext` from the
   browser's own stylesheet — and an engine that ignores the inherit (iOS
   Safari has, for years) paints black text on a dark panel. Phil, Sep 2026:
   the paste dialog's Cancel button and title were unreadable on his machine
   and reproduced on none of mine, which is the signature of exactly that.
   A colour this page can state is a colour no browser gets to decide. */
.sq{min-width:42px;height:42px;padding:0 10px;border:3px solid var(--edge);border-radius:13px;background:var(--paper);color:var(--ink);font-weight:800;font-size:16px;
  display:inline-grid;place-items:center;box-shadow:3px 3px 0 var(--edge);transition:transform .18s var(--spring),box-shadow .18s}
.sq:hover{transform:translate(-1px,-1px);box-shadow:4px 4px 0 var(--edge)}
.sq:active{transform:translate(3px,3px);box-shadow:0 0 0 var(--edge)}
.sq:disabled{opacity:.35;cursor:default;transform:none;box-shadow:3px 3px 0 var(--edge)}
.sq.go{background:var(--if);color:var(--on-if)}
.dt{border:3px solid var(--edge);border-radius:11px;background:var(--paper);color:var(--ink);padding:7px 9px;font-size:14px;font-weight:600;color-scheme:light dark}
.sel{border:3px solid var(--edge);border-radius:11px;background:var(--paper);color:var(--ink);padding:7px 9px;font-size:14px;font-weight:700;
  max-width:190px;text-overflow:ellipsis}
/* A nested .ctl (a board grouping its period controls) must NOT shrink: as a
   flex item it would drop to min-content and stack every button onto its own
   line, which is worse than the wrap it was meant to tidy. */
.ctl .ctl{flex:0 1 auto;min-width:0}

/* ── filter bar + drawer ── */
.fbar{position:sticky;top:var(--navh,58px);z-index:20;display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding-block:10px;margin-bottom:8px;
  background:var(--ground);border-bottom:3px solid var(--edge)}
.fbtn{display:inline-flex;align-items:center;gap:8px;padding:9px 16px;border:3px solid var(--edge);border-radius:999px;background:var(--paper);color:var(--ink);
  font-weight:800;font-size:14px;box-shadow:3px 3px 0 var(--edge);transition:transform .18s var(--spring),box-shadow .18s}
.fbtn:hover{transform:translate(-1px,-2px);box-shadow:5px 6px 0 var(--edge)}
.fbtn .n{min-width:22px;height:22px;padding:0 6px;border-radius:999px;background:var(--cost);color:#fff;display:grid;place-items:center;font-size:12px}
.fsum{font-weight:600;color:var(--ink2);font-size:14px;display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.fsum b{color:var(--ink);background:var(--paper2);border:2px solid var(--edge);border-radius:8px;padding:2px 8px;font-weight:700}
.fsum .reset{font-weight:800;color:var(--cost);text-decoration:underline;text-underline-offset:3px;padding:2px 4px;font-size:14px}
.veil{position:fixed;inset:0;background:rgba(14,15,26,.45);opacity:0;pointer-events:none;transition:opacity .22s;z-index:30}
.veil.on{opacity:1;pointer-events:auto}
.drawer{position:fixed;top:0;right:0;bottom:0;width:min(460px,100vw);background:var(--paper);border-left:3px solid var(--edge);z-index:40;
  transform:translateX(105%);transition:transform .3s var(--ease);overflow:auto;padding:20px 20px 0;display:flex;flex-direction:column;gap:18px}
.drawer.on{transform:none}
.drawer h2{font-size:24px;font-weight:800;letter-spacing:-.02em;display:flex;justify-content:space-between;align-items:center}
.grp{display:flex;flex-direction:column;gap:8px}
.grp .lbl{font-size:12px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--ink3);display:flex;justify-content:space-between;align-items:center;gap:10px}
.grp .lbl .acts{display:flex;gap:10px}
.grp .lbl button{font-size:12px;font-weight:800;color:var(--ink2);text-decoration:underline;text-underline-offset:2px;text-transform:none;letter-spacing:0}
.chips{display:flex;gap:8px;flex-wrap:wrap}
.chip{padding:6px 13px;border:3px solid var(--edge);border-radius:999px;font-weight:700;font-size:14px;background:var(--paper);color:var(--ink);
  transition:transform .2s var(--spring),background .12s,color .12s}
.chip.on{background:var(--edge);color:var(--ground)}
.chip:hover{transform:translateY(-2px)}
.chip:active{transform:scale(.94)}
.chip.sm{font-size:13px;padding:5px 11px}
.done{padding:12px 18px;border:3px solid var(--edge);border-radius:14px;background:var(--edge);color:var(--ground);font-weight:800;font-size:15px}
.hint{font-size:13px;color:var(--ink3);font-weight:600}
/* A LONG LIST NEEDS A WAY IN, NOT JUST A WAY DOWN (Phil, Sep 2026: the drawer
   "looks cluttered with supplier buttons taking it all up" — 78 of them, and
   every other filter pushed off the screen under them). Searching beats
   scrolling past 78 names to find one, and capping the list keeps whatever
   sits below it reachable. The cap is in rows rather than pixels so it holds
   at any chip size. */
.fsearch{width:100%;border:3px solid var(--edge);border-radius:12px;background:var(--paper2);color:var(--ink);
  padding:9px 12px;font-size:14px;font-weight:600;font-family:inherit}
.fsearch::placeholder{color:var(--ink3);font-weight:600}
/* THE PANEL IS THE ONLY SCROLL AREA (Phil, Sep 2026: "when you scroll to the
   end, it then scrolls the small supplier box, and the Done and Reset all are
   covering it"). A capped list inside a scrolling panel is two scroll areas
   under one thumb: reaching the panel's end hands the drag to the inner box,
   which is a trap rather than a feature. The first fix gave the supplier group
   the leftover height (`.grow`) — fine while the drawer fit, and wrong the
   moment the nested category tree made it overflow: a `flex:1 1 auto` child
   SHRINKS, hit its own `min-height`, and the footer landed on top of the chips.
   Both lists are searchable, which is what makes a long panel workable. */

/* THE FOOTER IS STICKY, not pushed. `.done{margin-top:auto}` pinned it to the
   bottom only while nothing overflowed — the moment the panel scrolled it went
   back into the flow and sat over whatever was under it. Sticky keeps Reset and
   Done in reach without scrolling past 36 categories and 78 suppliers first,
   and it carries the panel's own background and a rule so it reads as a floor
   rather than as something floating. It owns the padding the panel gave up. */
.drawer .dact{position:sticky;bottom:0;z-index:2;display:flex;gap:10px;
  margin-top:4px;padding:14px 0 20px;background:var(--paper);border-top:3px solid var(--edge)}
/* A NESTED PILL LIST. `.chips` is a wrapping row, so a family has to be its own
   row that wraps inside it — hence column direction on the tree and a wrapping
   row per family. Without `align-items:stretch` the families shrink to their
   content and the headings stop lining up. */
/* NOT `.scrolly`. A window inside a panel that already scrolls is two scroll
   areas under one thumb, and on a phone the inner one steals the drag. The
   families and the search are what make a long list readable; the panel
   itself is what scrolls. */
.tytree{flex-direction:column;align-items:stretch;gap:9px}
/* The tree stretches its ROWS, so a bare chip child (the way back) would
   stretch into a full-width slab that reads as a heading, not a pill. */
.tytree>.chip{align-self:flex-start}
.tytree>.fam{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.tytree .famh{background:var(--paper2);border-style:dashed;font-size:11px;letter-spacing:.08em;text-transform:uppercase}
.tytree .famh.on{background:var(--ink);color:var(--paper);border-style:solid}
.tytree .famh .n{margin-left:6px;opacity:.65;font-weight:700;letter-spacing:0}
.tytree .famh .caret{margin-right:6px;opacity:.7;font-size:9px;display:inline-block;width:8px}
/* A SHUT FAMILY IS ITS HEADING ALONE. `.searching` overrides it so a term can
   reach inside without the search having to open anything — clearing the box
   then puts the drawer back exactly as it was. Per-chip `hidden` does the
   filtering, so the two compose: a chip shows when its family is open AND it
   matches. */
.tytree:not(.searching) .fam.shut>[data-ty],
.tytree:not(.searching) .fam.shut>[data-fam]{display:none}
.chips.scrolly{max-height:216px;overflow-y:auto;align-content:flex-start;padding:3px;
  border:2px dashed color-mix(in srgb,var(--ink3) 45%,transparent);border-radius:12px}
.chips.scrolly:empty::after,.chips .noneleft{content:'';color:var(--ink3);font-size:13px;font-weight:600;padding:6px 4px}
.grp .lbl .ct{font-weight:700;letter-spacing:0;text-transform:none;color:var(--ink3);font-size:12px}
/* One column picked out of a table, without hiding the rest. A tint rather
   than a border: a border on a middle column reads as the table splitting in
   two. Built from --if so it lands on both grounds. */
.mcol{background:color-mix(in srgb,var(--if) 13%,transparent)}
th.mcol{background:color-mix(in srgb,var(--if) 20%,transparent)}

/* ── feed bar ── */
#feed-bar{display:flex;gap:10px;align-items:center;flex-wrap:wrap;font-size:14px;color:var(--ink2);font-weight:600;padding-block:0 14px}
#feed-bar strong{color:var(--ink);font-weight:700}
#feed-bar.empty{border:3px solid var(--cost);border-radius:14px;padding:12px 16px;background:var(--paper);color:var(--ink)}

/* ── pages ── */
.page{display:none}
.page.on{display:block}
.pnav{position:sticky;bottom:10px;z-index:5;display:flex;justify-content:center;margin-top:22px;pointer-events:none}
.pnav .in{pointer-events:auto;display:inline-flex;align-items:center;gap:3px;padding:6px;border:3px solid var(--edge);border-radius:999px;
  background:var(--paper);box-shadow:5px 5px 0 var(--edge);flex-wrap:wrap;justify-content:center;max-width:100%}
.pnav button{padding:8px 13px;border-radius:999px;font-weight:800;font-size:13px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink2);
  transition:background .12s,color .12s,transform .18s var(--spring);white-space:nowrap}
.pnav button:hover{transform:translateY(-2px)}
.pnav button.on{background:var(--edge);color:var(--ground)}
.pnav button.arrow{font-size:17px;padding:4px 9px;line-height:1}
.pnav button:disabled{opacity:.3;cursor:default;transform:none}
.kbd{font-size:12px;color:var(--ink3);font-weight:700;padding-block:10px 0;text-align:center}
.kbd kbd{border:2px solid var(--ink3);border-radius:5px;padding:0 5px;font-family:inherit;color:var(--ink2)}

/* ── the bento ── */
.bento{display:grid;grid-template-columns:repeat(12,1fr);gap:15px}
.blk{border:3px solid var(--edge);border-radius:24px;box-shadow:6px 6px 0 var(--edge);background:var(--paper);padding:20px 22px;position:relative;overflow:hidden;text-align:left}
.hero{grid-column:span 3;min-height:268px;background:var(--h);color:var(--on);display:flex;flex-direction:column;justify-content:space-between;width:100%;
  transition:transform .26s var(--spring),box-shadow .26s var(--spring)}
.hero:hover{transform:translate(-3px,-4px) rotate(-.5deg);box-shadow:10px 11px 0 var(--edge)}
.hero:active{transform:translate(3px,3px);box-shadow:2px 2px 0 var(--edge)}
.hero .lab{display:flex;justify-content:space-between;align-items:center;font-weight:700;font-size:14px;letter-spacing:.03em;text-transform:uppercase;gap:8px}
.hero .arrow{width:32px;height:32px;flex:none;border-radius:50%;border:3px solid currentColor;display:grid;place-items:center;font-size:17px;font-weight:800;transition:transform .26s var(--spring)}
.hero:hover .arrow{transform:translateX(4px)}
.hero .num{font-size:clamp(42px,4.4vw,76px);font-weight:800;letter-spacing:-.05em;line-height:.92;margin-block:8px 6px;min-width:0}
.hero .num small{font-size:.4em;font-weight:700;letter-spacing:-.01em;margin-left:2px}
.hero .cols{display:flex;align-items:flex-end;gap:3px;height:42px;margin-block:4px 10px}
.hero .cols i{flex:1;display:block;background:currentColor;opacity:.42;border-radius:3px 3px 0 0;transform-origin:bottom;animation:rise .5s var(--ease) both}
.hero .cols i:last-child{opacity:1}
@keyframes rise{from{transform:scaleY(0)}}
.hero .foot{display:flex;gap:9px;align-items:center;flex-wrap:wrap;font-weight:600;font-size:14px}
.delta{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:999px;font-weight:800;font-size:13px;border:2px solid currentColor;letter-spacing:0;white-space:nowrap}
.delta.dn{background:var(--edge);color:var(--ground);border-color:transparent}
.delta.na{opacity:.72}
/* the same up/down as PLAIN TEXT, for the deltas that sit inside a table cell.
   :not(.delta) is load-bearing: a hero block is a solid colour and its pill
   borrows the block's own ink (`--on`), so colouring it green here puts green
   text on a blue block. */
.up:not(.delta){color:var(--good);font-weight:800}
.dn:not(.delta){color:var(--bad);font-weight:800}
.flat:not(.delta){color:var(--ink3);font-weight:700}
@media (max-width:1080px){.hero{grid-column:span 6}}
@media (max-width:600px){.hero{grid-column:span 12;min-height:210px}}
.wide{grid-column:span 12;display:flex;align-items:center;gap:11px;flex-wrap:wrap;padding-block:15px}
.wide h2{font-size:18px;font-weight:800;margin-right:6px;letter-spacing:-.01em}
.flag{display:inline-flex;align-items:center;gap:9px;padding:9px 14px;border:3px solid var(--edge);border-radius:14px;background:var(--paper2);
  font-weight:700;font-size:14px;box-shadow:3px 3px 0 var(--edge);transition:transform .2s var(--spring),box-shadow .2s}
.flag:hover{transform:translate(-1px,-2px);box-shadow:5px 6px 0 var(--edge)}
.flag b{font-size:18px;font-weight:800}
.flag .sv{width:12px;height:12px;flex:none;border-radius:4px;border:2px solid var(--edge)}
.flag.bad .sv{background:var(--bad)}.flag.warn .sv{background:var(--warn)}.flag.ok .sv{background:var(--good)}.flag.na .sv{background:var(--paper)}
.mini{grid-column:span 12;display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:12px;padding:0;border:0;box-shadow:none;background:transparent;overflow:visible}
.mini>div{display:flex;flex-direction:column;justify-content:flex-end;gap:2px;padding:13px 15px;border:3px solid var(--edge);border-radius:16px;background:var(--paper);box-shadow:4px 4px 0 var(--edge)}
.mini .ml{font-size:12px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;color:var(--ink3)}
.mini .mv{font-size:27px;font-weight:800;letter-spacing:-.03em;white-space:nowrap}
.span12{grid-column:span 12}
.span6{grid-column:span 6}
@media (max-width:900px){.span6{grid-column:span 12}}

/* ── page head ── */
.phead{border:3px solid var(--edge);border-radius:24px;box-shadow:6px 6px 0 var(--edge);background:var(--h,var(--paper));color:var(--on,var(--ink));
  padding:20px 24px;display:flex;justify-content:space-between;align-items:flex-end;gap:16px;flex-wrap:wrap;margin-bottom:15px}
.phead .lab{font-weight:700;letter-spacing:.03em;text-transform:uppercase;font-size:14px}
.phead .big{font-size:clamp(44px,6vw,96px);font-weight:800;letter-spacing:-.05em;line-height:.92;margin-top:6px}
.phead .big small{font-size:.38em;font-weight:700}
.phead .rhs{text-align:right;font-weight:600;display:flex;flex-direction:column;align-items:flex-end;gap:9px;font-size:14px}
.part{display:inline-block;border:2px solid currentColor;border-radius:999px;padding:1px 9px;font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;vertical-align:middle;opacity:.85}
#pt-h .part{border-color:var(--cost);color:var(--cost)}
.cut{display:flex;gap:7px;flex-wrap:wrap;align-items:center;font-size:13px;font-weight:600;opacity:.92;justify-content:flex-end}
.cut b{border:2px solid currentColor;border-radius:8px;padding:1px 8px;font-weight:700}
.cut .edit{border:2px solid currentColor;border-radius:999px;padding:2px 10px;font-weight:800;font-size:12px;text-transform:uppercase;letter-spacing:.05em;transition:transform .2s var(--spring)}
.cut .edit:hover{transform:translateY(-2px)}
.back{display:inline-flex;align-items:center;gap:7px;padding:8px 15px;border:3px solid currentColor;border-radius:999px;font-weight:800;font-size:14px;transition:transform .2s var(--spring)}
.back:hover{transform:translateX(-4px)}
.phead .seg{border-color:currentColor;background:transparent;box-shadow:none}
.phead .seg button{border-color:currentColor;color:inherit}
.phead .seg button.on{background:var(--on);color:var(--h)}

/* ── cards, tables, bars ── */
.card{border:3px solid var(--edge);border-radius:24px;box-shadow:6px 6px 0 var(--edge);background:var(--paper);padding:18px 20px}
.card h3{font-size:13px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;color:var(--ink3);margin-bottom:11px}
.card p.note{font-size:13px;color:var(--ink2);font-weight:600;margin-top:10px}
.rows{display:grid;gap:9px}
/* THE LABEL COLUMN HOLDS A REAL NAME (Phil, Sep 2026: "Landmark Packa",
   "Royal Crest Dair", "What Chefs War"). Two faults, and the second is why it
   read as broken rather than tight: the column was capped at 132px, and
   `text-overflow:ellipsis` does nothing on a FLEX container — it applies to a
   block's inline content, so the name was hard-clipped mid-word with no "…"
   to say anything was missing. A cut-off name reads as a data error; an
   ellipsis reads as a narrow column. The swatch goes inline instead, which
   lets the whole label truncate as one run of text. */
.row{display:grid;grid-template-columns:minmax(104px,190px) 1fr minmax(58px,auto);gap:10px;align-items:center;font-weight:700;font-size:14px}
.row .lab{display:block;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.row .sw{display:inline-block;vertical-align:-1px;margin-right:8px;width:13px;height:13px;border-radius:4px;border:2px solid var(--edge)}
.row .trk{display:block;height:24px;border:3px solid var(--edge);border-radius:8px;overflow:hidden;background:var(--paper2)}
.row .fil{display:block;height:100%;transform-origin:left;animation:grow .5s var(--ease) both}
@keyframes grow{from{transform:scaleX(0)}}
.row .n{text-align:right;color:var(--ink2);white-space:nowrap}
.tbl{overflow:auto;max-height:min(70vh,720px)}
table{width:100%;border-collapse:collapse;font-size:14px}
th{text-align:left;font-size:12px;letter-spacing:.07em;text-transform:uppercase;color:var(--ink3);font-weight:800;padding:9px 8px;
  border-bottom:3px solid var(--edge);position:sticky;top:0;background:var(--paper);z-index:1}
td{padding:9px 8px;border-bottom:2px solid var(--paper2);white-space:nowrap}
tbody tr:hover td{background:var(--paper2)}
td.r,th.r{text-align:right}
td.wrap{white-space:normal}
tfoot td{border-top:3px solid var(--edge);border-bottom:0;font-weight:800}
.pill{display:inline-block;padding:2px 9px;border-radius:999px;font-size:12px;font-weight:800;border:2px solid var(--edge);white-space:nowrap}
.pill.bad{background:var(--bad);color:#fff}.pill.ok{background:var(--good);color:#fff}
.pill.warn{background:var(--warn);color:#0E0F1A}.pill.na{color:var(--ink3);border-color:var(--ink3)}
.cname{display:inline-flex;align-items:center;gap:7px;font-weight:700}
.dot{width:11px;height:11px;border-radius:50%;display:inline-block;flex-shrink:0;border:2px solid var(--edge)}
.empty{padding:26px;text-align:center;color:var(--ink3);font-weight:700}

/* ── charts ── */
.chart{position:relative}
.chart svg{width:100%;height:300px;display:block;overflow:visible}
.chart svg.short{height:230px}
.tip{position:absolute;left:0;top:0;pointer-events:none;background:var(--edge);color:var(--ground);padding:9px 12px;border-radius:10px;font-weight:700;font-size:13px;
  white-space:nowrap;opacity:0;transition:opacity .1s;z-index:3;box-shadow:0 6px 20px rgba(0,0,0,.25);max-width:100%;overflow:hidden}
.tip.on{opacity:1}
.tip .tl{display:flex;align-items:center;gap:6px}
.tip i{width:9px;height:9px;border-radius:2px;display:inline-block}
.legend{display:flex;gap:14px;flex-wrap:wrap;font-size:13px;color:var(--ink2);font-weight:700;padding:10px 2px 0}
.legend span{display:inline-flex;align-items:center;gap:6px}
.legend i{width:12px;height:12px;border-radius:3px;border:2px solid var(--edge)}

/* ── issues ── */
.iss{display:grid;gap:9px}
.iss-row{border:3px solid var(--edge);border-radius:16px;background:var(--paper2);padding:11px 14px;display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap}
.iss-meta{flex:none;min-width:132px}
.iss-c{font-weight:800;font-size:15px}
.iss-d{font-size:13px;color:var(--ink2);font-weight:600}
.iss-b{flex:1;min-width:220px;font-size:14px;line-height:1.5}
.iss-b .who{color:var(--ink2);font-size:13px;font-weight:600}
.iss-cost{flex:none;font-weight:800;color:var(--ink)}

/* ── orders search ── */
.tools{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:12px}
.tools input[type=search]{border:3px solid var(--edge);border-radius:12px;background:var(--paper);color:var(--ink);padding:9px 13px;font-size:14px;font-weight:600;min-width:min(300px,100%)}

/* ── paste dialog ── */
#upd-modal{display:none;position:fixed;inset:0;background:rgba(14,15,26,.6);z-index:50;align-items:center;justify-content:center;padding:16px}
#upd-modal.show{display:flex}
#upd-inner{background:var(--paper);color:var(--ink);border:3px solid var(--edge);border-radius:24px;box-shadow:8px 8px 0 var(--edge);padding:22px;width:660px;max-width:100%;max-height:92vh;overflow:auto}
#upd-inner h3{font-size:22px;font-weight:800;margin-bottom:12px;letter-spacing:-.02em;color:var(--ink)}
.upd-steps{font-size:15px;color:var(--ink2);margin:0 0 10px 20px;line-height:1.8;font-weight:600}
.upd-steps strong{color:var(--ink)}
.upd-fine{font-size:13px;color:var(--ink3);margin-bottom:12px;font-weight:600}
#upd-ta{width:100%;height:190px;background:var(--paper2);border:3px solid var(--edge);border-radius:14px;color:var(--ink);font-size:12px;padding:10px;resize:vertical;font-family:ui-monospace,monospace}
.upd-btns{display:flex;gap:9px;margin-top:11px;flex-wrap:wrap}
#upd-msg{font-size:14px;margin-top:11px;line-height:1.6;font-weight:600}
#upd-msg:empty{display:none}
#upd-inner.done .upd-steps,#upd-inner.done .upd-fine,#upd-inner.done #upd-ta,#upd-inner.done .upd-apply{display:none}
/* THE LAST BUTTON STANDING MUST NOT SAY "CANCEL" (Phil, Sep 2026: "after
   updating, there is no way to close this box other than Cancel"). The rule
   above hides everything marked .upd-apply on success, which leaves exactly one
   button — and it was the cancel one. Somebody who has just imported 1,436 POs
   is then offered a single action that reads as "undo that". Two labels in the
   markup, so the swap is CSS and the button keeps its text for a screen reader
   rather than being relabelled by a pseudo-element. */
.upd-cancel .d-lbl{display:none}
#upd-inner.done .upd-cancel .c-lbl{display:none}
#upd-inner.done .upd-cancel .d-lbl{display:inline}
#upd-inner.done .upd-cancel{background:var(--if);color:var(--on-if)}
.upd-ok{color:var(--good);font-size:19px;font-weight:800;margin-bottom:8px}
.upd-list{margin:0 0 8px 18px;color:var(--ink2)}
.upd-list li{margin:3px 0}
.upd-list strong{color:var(--ink)}
/* A named-row disclosure inside a paste result. A COUNT starts an argument and
   a row number ends one — "132 rows had no supplier" against somebody who
   knows every line has one is a stand-off; "row 418 · PO 24-1092" is something
   to go and look at. Folded, so the good case stays short. */
.rowlist{margin:4px 0 2px}
.rowlist summary{cursor:pointer;font-size:13px;font-weight:700;color:var(--if);list-style:none;display:inline-block;
  border-bottom:1.5px dotted var(--if);line-height:1.3}
.rowlist summary::-webkit-details-marker{display:none}
.rowlist summary:focus-visible{outline:3px solid var(--if);outline-offset:2px}
.rowlist ul{margin:7px 0 4px 16px;padding:0;font-size:13.5px;line-height:1.6;font-variant-numeric:tabular-nums}
.rowlist li{margin:2px 0}
.rowlist b{color:var(--bad);font-weight:800}
.rowlist .muted{color:var(--ink3);font-style:italic}
#upd-msg details{margin-top:9px}
#upd-msg summary{cursor:pointer;color:var(--cost);font-weight:800}
#upd-msg details ul{margin:6px 0 0 18px;color:var(--ink2)}

/* A PHONE. The 5-button grain segment ran 21px past the viewport at 390px wide
   (found Sep 2026 while measuring the scorecard's control row): .seg is
   inline-flex with overflow:hidden, so it cannot wrap and simply pushed off the
   edge. Tightened rather than wrapped — a segmented control broken across two
   lines stops reading as one choice. */
@media (max-width:520px){
  .bar{padding-block:12px 10px}
  .ctl{gap:6px}
  .seg button{padding:8px 9px;font-size:13px}
  .sq{min-width:38px;height:38px;padding:0 8px;font-size:15px}
  .sel,.dt{padding:6px 7px;font-size:13px;max-width:150px}
}

@media print{
  .ctl,.hivenav,.fbar,.pnav,.kbd,#upd-modal,.drawer,.veil,#feed-bar{display:none!important}
  .page{display:block!important}
  body{background:#fff;color:#000;padding:0}
  .blk,.card,.phead{box-shadow:none;break-inside:avoid;background:#fff}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ── extra spans: boards that are not four-across ── */
.span4{grid-column:span 4}
.span8{grid-column:span 8}
@media (max-width:1080px){.span4,.span8{grid-column:span 12}}

/* ── prose: the "what this still needs" blocks the half-built boards carry ── */
.prose{border:3px solid var(--edge);border-radius:16px;background:var(--paper2);padding:14px 16px;font-size:14px;line-height:1.6;font-weight:600;color:var(--ink2)}
.prose+.prose{margin-top:11px}
.prose b,.prose strong{color:var(--ink);font-weight:800}
.prose ul{margin:7px 0 0 20px}
.prose li{margin:4px 0}
.bl{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:12px;margin-top:13px}
.bl-card{border:3px solid var(--edge);border-radius:16px;background:var(--paper);padding:13px 15px;box-shadow:4px 4px 0 var(--edge)}
.bl-card h4{font-size:12px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;margin-bottom:9px;display:flex;align-items:center;gap:7px}
.bl-card h4 .sv{width:12px;height:12px;border-radius:4px;border:2px solid var(--edge)}
.bl-card li{font-size:14px;font-weight:600;color:var(--ink2);margin:5px 0 5px 17px;line-height:1.45}
.bl-card li b{color:var(--ink);font-weight:800}

/* ── the sample-data banner. A board on invented numbers says so at the top,
      in the loudest thing on the page that is not a number, and says what it
      is waiting for. Never a quiet grey footnote. ── */
.sample{border:3px solid var(--cost);border-radius:20px;background:var(--paper);box-shadow:6px 6px 0 var(--cost);padding:15px 18px;margin-bottom:15px;display:flex;gap:14px;align-items:flex-start;flex-wrap:wrap}
.sample .tagx{flex:none;background:var(--cost);color:#fff;border-radius:999px;padding:4px 13px;font-weight:800;font-size:13px;letter-spacing:.06em;text-transform:uppercase}
.sample .say{flex:1;min-width:250px;font-size:14px;font-weight:600;color:var(--ink2);line-height:1.55}
.sample .say b{color:var(--ink);font-weight:800}
@media print{.sample{box-shadow:none}}
