/* Jara design system.
 *
 * One stylesheet for every page, so the product teaches one visual language
 * instead of seven. Pages adopt it by linking it and using its classes; nothing
 * here depends on a page, and nothing here is page-specific.
 *
 * The organising idea is that this is operations software, not a reporting tool.
 * A buyer opens it to decide something, so the hierarchy is always
 *   (1) what needs attention  (2) what the decision is  (3) the numbers behind it
 * and never the reverse. Tables are decision tables: the action comes first,
 * because a row's purpose is to be acted on, not read left to right.
 */

/* ── tokens ─────────────────────────────────────────────────────────────────
 * Neutrals carry a slight blue bias rather than being pure grey -- a pure grey
 * reads as unconsidered, and this palette sits next to status colour all day.
 * Semantic colour (go / hold / stop / risk) is kept separate from the accent so
 * a brand refresh cannot accidentally change what "stop" looks like.
 */
:root{
  --bg:#0d1017; --bg-sunk:#090b10;
  --panel:#141922; --panel-2:#1a2028; --panel-3:#212936;
  --line:#232b39; --line-soft:#1b2230; --line-strong:#2e394b;
  --ink:#e8ecf3; --ink-2:#a3aec1; --ink-3:#6f7c92; --ink-4:#4d586b;

  --accent:#4d9fff; --accent-soft:#1b2f4d; --accent-ink:#9cc9ff;

  --go:#34d399;      --go-soft:#0f2f26;      --go-ink:#6ee7b7;
  --hold:#7c8798;    --hold-soft:#1c2230;    --hold-ink:#a3aec1;
  --stop:#fbbf24;    --stop-soft:#33270a;    --stop-ink:#fcd34d;
  --risk:#fb7185;    --risk-soft:#3a1420;    --risk-ink:#fda4af;

  --r-sm:6px; --r:10px; --r-lg:14px;
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px; --sp-6:32px;
  --shadow:0 1px 2px rgba(0,0,0,.4), 0 8px 24px -12px rgba(0,0,0,.5);

  --f-sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;
  --f-num:"SF Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
}
@media (prefers-color-scheme: light){
  :root{
    --bg:#f5f7fa; --bg-sunk:#eceff4;
    --panel:#ffffff; --panel-2:#f8fafc; --panel-3:#f1f4f8;
    --line:#dfe4ec; --line-soft:#eaeef4; --line-strong:#c8d1de;
    --ink:#111826; --ink-2:#4a5568; --ink-3:#71809a; --ink-4:#94a1b5;

    --accent:#0b6bdb; --accent-soft:#e4efff; --accent-ink:#0b52a8;

    --go:#0f9d63;   --go-soft:#e2f7ed;   --go-ink:#077549;
    --hold:#7a869a; --hold-soft:#eef1f6; --hold-ink:#59657a;
    --stop:#b4770a; --stop-soft:#fdf3dc; --stop-ink:#8a5a06;
    --risk:#d64560; --risk-soft:#fdeaee; --risk-ink:#a82c44;

    --shadow:0 1px 2px rgba(16,24,40,.06), 0 8px 24px -14px rgba(16,24,40,.16);
  }
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font:14px/1.5 var(--f-sans); -webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none}
h1,h2,h3{margin:0;text-wrap:balance}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--r-sm)}
.num{font-variant-numeric:tabular-nums}
.muted{color:var(--ink-3)}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}

/* ── app chrome ─────────────────────────────────────────────────────────── */
.topbar{
  position:sticky; top:0; z-index:40; display:flex; align-items:center;
  gap:var(--sp-4); padding:0 var(--sp-5); height:52px;
  background:color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter:saturate(150%) blur(12px);
  border-bottom:1px solid var(--line);
}
.logo{font-weight:680;letter-spacing:-.015em;font-size:15px;white-space:nowrap}
.logo em{font-style:normal;color:var(--ink-3);font-weight:450}
.nav{display:flex;gap:2px;overflow-x:auto;scrollbar-width:none}
.nav::-webkit-scrollbar{display:none}
.nav a{
  padding:6px 12px;border-radius:var(--r-sm);color:var(--ink-2);
  font-weight:520;font-size:13.5px;white-space:nowrap;
  transition:background .12s, color .12s;
}
.nav a:hover{background:var(--panel-3);color:var(--ink)}
.nav a[aria-current]{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}
.spacer{flex:1}

/* ── page header: title, purpose, freshness, status ─────────────────────────
 * Four things, always in this order. The one-line purpose is not decoration --
 * it is the difference between a page a new buyer can use and one that needs a
 * colleague to explain it. The status badge is last because it is the thing the
 * eye should land on after reading the title.
 */
.page-head{padding:var(--sp-5) var(--sp-5) var(--sp-4)}
.page-head h1{font-size:23px;font-weight:660;letter-spacing:-.02em}
.page-head .purpose{margin:5px 0 0;color:var(--ink-2);font-size:14px;max-width:68ch}
.page-meta{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-3);margin-top:var(--sp-3)}
.stamp{font-size:12.5px;color:var(--ink-3)}
.stamp b{color:var(--ink-2);font-weight:550}

/* ── badges ──────────────────────────────────────────────────────────────── */
.badge{
  display:inline-flex;align-items:center;gap:5px;
  padding:3px 9px;border-radius:999px;font-size:12px;font-weight:600;
  border:1px solid transparent;white-space:nowrap;
}
.badge::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.badge.plain::before{display:none}
.badge-go{background:var(--go-soft);color:var(--go-ink);border-color:color-mix(in srgb,var(--go) 30%,transparent)}
.badge-hold{background:var(--hold-soft);color:var(--hold-ink);border-color:var(--line)}
.badge-stop{background:var(--stop-soft);color:var(--stop-ink);border-color:color-mix(in srgb,var(--stop) 30%,transparent)}
.badge-risk{background:var(--risk-soft);color:var(--risk-ink);border-color:color-mix(in srgb,var(--risk) 32%,transparent)}
.badge-info{background:var(--accent-soft);color:var(--accent-ink);border-color:color-mix(in srgb,var(--accent) 28%,transparent)}

/* Confidence is a three-step scale, so it reads as a scale: filled pips, not
 * three unrelated colours a reader has to memorise. */
.conf{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:600;color:var(--ink-2)}
.conf i{display:flex;gap:2px}
.conf i span{width:5px;height:11px;border-radius:1.5px;background:var(--line-strong)}
.conf.high i span{background:var(--go)}
.conf.medium i span:nth-child(-n+2){background:var(--stop)}
.conf.low i span:nth-child(1){background:var(--risk)}
.conf.high{color:var(--go-ink)} .conf.medium{color:var(--stop-ink)} .conf.low{color:var(--risk-ink)}

/* ── layout ──────────────────────────────────────────────────────────────── */
main{padding:0 var(--sp-5) var(--sp-6);display:flex;flex-direction:column;gap:var(--sp-4)}
.grid{display:grid;gap:var(--sp-3)}
.grid.cards{grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
.grid.two{grid-template-columns:repeat(auto-fit,minmax(340px,1fr))}

/* ── cards ───────────────────────────────────────────────────────────────── */
.card{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow);overflow:hidden;
}
.card-head{
  display:flex;align-items:center;gap:var(--sp-2);
  padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--line-soft);
}
.card-head h2{
  font-size:12px;font-weight:660;letter-spacing:.055em;text-transform:uppercase;
  color:var(--ink-3);
}
.card-body{padding:var(--sp-4)}

/* A metric card leads with the number, because that is what is being scanned.
 * The left stripe encodes urgency without spending a colour on the number
 * itself, which keeps big figures legible in both themes. */
.metric{
  position:relative;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r);padding:var(--sp-4) var(--sp-4) var(--sp-4) calc(var(--sp-4) + 3px);
  box-shadow:var(--shadow);display:flex;flex-direction:column;gap:2px;min-width:0;
}
.metric::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--line-strong);
}
.metric.go::before{background:var(--go)}
.metric.stop::before{background:var(--stop)}
.metric.risk::before{background:var(--risk)}
.metric.info::before{background:var(--accent)}
.metric .k{font-size:11.5px;font-weight:620;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3)}
.metric .v{font-size:30px;font-weight:670;letter-spacing:-.025em;line-height:1.1;margin-top:3px}
.metric .v small{font-size:15px;font-weight:550;color:var(--ink-3);letter-spacing:0}
.metric .s{font-size:12.5px;color:var(--ink-2);margin-top:3px}
.metric .lead{
  margin-top:var(--sp-3);padding-top:var(--sp-3);border-top:1px solid var(--line-soft);
  font-size:12.5px;color:var(--ink-2);
}
.metric .lead b{color:var(--ink);font-weight:600}
.metric.quiet .v{color:var(--ink-3)}

/* ── notices ─────────────────────────────────────────────────────────────── */
.notice{
  display:flex;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);
  border:1px solid var(--line);border-left:3px solid var(--ink-4);
  border-radius:var(--r);background:var(--panel);font-size:13px;color:var(--ink-2);
}
.notice b{color:var(--ink);font-weight:600}
.notice.info{border-left-color:var(--accent)}
.notice.stop{border-left-color:var(--stop)}
.notice.risk{border-left-color:var(--risk)}

/* ── tabs ────────────────────────────────────────────────────────────────── */
.tabs{
  display:flex;gap:var(--sp-5);padding:0 var(--sp-5);
  border-bottom:1px solid var(--line);background:var(--panel);
  overflow-x:auto;scrollbar-width:none;
}
.tabs::-webkit-scrollbar{display:none}
.tabs button{
  appearance:none;background:none;border:0;border-bottom:2px solid transparent;
  padding:13px 0 11px;font:inherit;font-weight:600;font-size:14px;
  color:var(--ink-3);cursor:pointer;white-space:nowrap;text-align:left;
}
.tabs button:hover{color:var(--ink-2)}
.tabs button[aria-selected="true"]{color:var(--ink);border-bottom-color:var(--accent)}
.tabs button .q{display:block;font-weight:450;font-size:11.5px;color:var(--ink-4);margin-top:1px}
.tabs button[aria-selected="true"] .q{color:var(--ink-3)}

/* ── decision table ─────────────────────────────────────────────────────────
 * The action is the first column and the widest-weight thing in the row. Rows
 * that need nothing are dimmed rather than hidden, so the page stays honest
 * about how much it looked at.
 */
.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.tablewrap.sticky{overflow:auto;max-height:calc(100vh - 250px);overscroll-behavior:contain}
.tablewrap.sticky table.decisions th{top:0}
table.decisions{width:100%;border-collapse:separate;border-spacing:0;font-size:13.5px}
table.decisions th{
  position:sticky;top:52px;z-index:5;background:var(--panel-2);
  text-align:left;padding:9px var(--sp-3);white-space:nowrap;
  font-size:11px;font-weight:660;letter-spacing:.05em;text-transform:uppercase;
  color:var(--ink-3);border-bottom:1px solid var(--line);
}
table.decisions td{
  padding:11px var(--sp-3);border-bottom:1px solid var(--line-soft);
  vertical-align:top;
}
table.decisions tbody tr:hover{background:var(--panel-2)}
table.decisions tbody tr.quiet td{color:var(--ink-3)}
table.decisions tbody tr.quiet .sku-name{color:var(--ink-2)}
table.decisions .r{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
table.decisions .act{white-space:nowrap}
.sku-name{font-weight:560;color:var(--ink)}
.sku-code{font-size:11.5px;color:var(--ink-4);font-family:var(--f-num);margin-top:1px}
table.decisions.sup .sku-meta .sku-code{margin-top:0}
.why{color:var(--ink-2);font-size:13px;max-width:46ch;line-height:1.45}
.why .extra{display:block;margin-top:4px;color:var(--ink-3);font-size:12.5px}
.big{font-weight:640;font-size:15px}

/* Never-merged lanes. Three columns, visually equal, no arithmetic between them.
 * Equal weight is the point: a wider or bolder column would imply precedence
 * this layout exists to deny. */
.lanes3{display:grid;gap:var(--sp-3);grid-template-columns:repeat(auto-fit,minmax(210px,1fr))}
.lane{border:1px solid var(--line);border-radius:var(--r);padding:var(--sp-4);background:var(--panel-2)}
.lane .k{font-size:11.5px;font-weight:620;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3)}
.lane .v{font-size:26px;font-weight:670;letter-spacing:-.02em;margin-top:4px}
.lane .v.empty{color:var(--ink-4);font-weight:500;font-size:19px}
.lane .s{font-size:12.5px;color:var(--ink-3);margin-top:4px}

/* ── controls ────────────────────────────────────────────────────────────── */
button.btn,select,input[type=text],input[type=number],input[type=search]{
  font:inherit;font-size:13.5px;color:var(--ink);background:var(--panel);
  border:1px solid var(--line-strong);border-radius:var(--r-sm);padding:6px 10px;
}
button.btn{cursor:pointer;font-weight:560;transition:background .12s,border-color .12s}
button.btn:hover{background:var(--panel-3)}
button.btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
button.btn.primary:hover{filter:brightness(1.08)}
button.btn.ghost{background:none;border-color:transparent;color:var(--ink-2)}
button.btn.ghost:hover{background:var(--panel-3);color:var(--ink)}
.toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);
  padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--line-soft)}
.chipset{display:flex;gap:var(--sp-1);flex-wrap:wrap}
.chip{appearance:none;cursor:pointer;font:inherit;font-size:12.5px;font-weight:560;
  padding:4px 11px;border-radius:999px;border:1px solid var(--line-strong);
  background:var(--panel);color:var(--ink-2)}
.chip:hover{background:var(--panel-3);color:var(--ink)}
.chip[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--bg)}

.empty-state{padding:var(--sp-6) var(--sp-4);text-align:center;color:var(--ink-3);font-size:13.5px}
.prose{max-width:74ch;color:var(--ink-2);font-size:13.5px;line-height:1.62}
.prose h3{color:var(--ink);font-size:14.5px;margin:0 0 var(--sp-2);font-weight:620}
.prose p{margin:0 0 var(--sp-3)}
.prose ul{margin:0 0 var(--sp-3);padding-left:20px}
.prose li{margin:4px 0}
.prose code{font-family:var(--f-num);font-size:12.5px;background:var(--panel-3);
  padding:1px 5px;border-radius:4px;color:var(--ink)}

@media (max-width:640px){
  main{padding:0 var(--sp-3) var(--sp-5)}
  .page-head{padding:var(--sp-4) var(--sp-3) var(--sp-3)}
  .page-head h1{font-size:20px}
  .topbar{padding:0 var(--sp-3);gap:var(--sp-3)}
  .tabs{padding:0 var(--sp-3);gap:var(--sp-4)}
  .metric .v{font-size:26px}
  table.decisions th{top:0}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ── legacy token aliases ───────────────────────────────────────────────────
 * Overview, Sales, Forecast and Stock were each written with their own :root
 * block and their own names for the same ideas. Rewriting four pages' component
 * CSS to the new vocabulary in one pass would be a large, untestable diff across
 * pages whose behaviour has nothing to do with colour.
 *
 * So the vocabulary is aliased instead. A page adopts the system by linking this
 * file and DELETING its own :root block -- nothing else. It immediately inherits
 * the shared palette, spacing scale and both themes, and its existing classes
 * keep working. Components then move to .card / .metric / .decisions page by
 * page, on their own schedule, with the palette already consistent.
 *
 * These are deliberately aliases and not duplicates: there is one definition of
 * each colour, above. A second literal would drift.
 */
:root{
  --ink-dim:var(--ink-2);
  --ink-faint:var(--ink-3);
  --row:var(--panel);
  --hover:var(--panel-2);
  --up:var(--go);
  --down:var(--risk);
  --crit:var(--risk);
  --warn:var(--stop);
  /* Forecast/planning additions: backtested months are evidence, extrapolated
     months are inference, and the pair must stay visually distinguishable. */
  --backtested:var(--go);
  --extrap:var(--stop);
  /* Sales uses a second row tone for banding; Forecast calls its panel a card.
     Both were defined in the token blocks those pages no longer carry, and an
     undefined custom property makes the whole declaration invalid -- so the
     element renders with NO background rather than a wrong one. Silent, and
     obvious only on the page. */
  --row-alt:var(--panel-2);
  --card:var(--panel);
}

/* ── command centre ─────────────────────────────────────────────────────────
 * Three lanes side by side, each self-contained. Deliberately NOT one merged
 * list: a buyer works supplier decisions and transfer decisions at different
 * moments, and interleaving them would force a choice about precedence that
 * neither lane should win.
 */
.attn-head{padding:var(--sp-2) 0 var(--sp-3)}
.attn-head h2{font-size:17px;font-weight:660;letter-spacing:-.015em}
.attn-head p{margin:4px 0 0;font-size:12.5px;max-width:80ch}
.attn-grid{display:grid;gap:var(--sp-3);grid-template-columns:repeat(auto-fit,minmax(330px,1fr));align-items:start}
.card.attn{display:flex;flex-direction:column}
.card.attn .card-head{justify-content:space-between;flex-wrap:wrap;gap:var(--sp-1)}
.attn-metrics{display:grid;gap:1px;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
  background:var(--line-soft);border-bottom:1px solid var(--line-soft)}
/* Four metrics wrapped 3 + 1, leaving one stranded beside a gap. Two rows of two
   is a shape, three and an orphan is an accident. */
.attn-metrics.four{grid-template-columns:repeat(2,1fr)}
.attn-metrics .metric{border:0;border-radius:0;box-shadow:none;padding:var(--sp-3) var(--sp-3) var(--sp-3) calc(var(--sp-3) + 3px)}
.attn-metrics .metric .v{font-size:24px}
.attn-metrics .metric .s{font-size:11.5px;line-height:1.35}

.attn-list{display:flex;flex-direction:column}
.attn-row{display:grid;grid-template-columns:auto 1fr auto;gap:var(--sp-3);
  align-items:start;padding:11px var(--sp-4);border-bottom:1px solid var(--line-soft)}
.attn-row:last-child{border-bottom:0}
.attn-row:hover{background:var(--panel-2)}
.attn-act{padding-top:1px}
.attn-name{font-weight:570;font-size:13.5px;color:var(--ink)}
.attn-name:hover{color:var(--accent-ink);text-decoration:underline}
.attn-why{color:var(--ink-3);font-size:12.5px;line-height:1.45;margin-top:2px;max-width:52ch}
.attn-num{font-size:13px;color:var(--ink-2);white-space:nowrap;text-align:right;
  font-variant-numeric:tabular-nums;padding-top:1px}
.attn-sub{border-top:1px solid var(--line);background:var(--panel-2)}
.attn-sub-h{font-size:11px;font-weight:640;letter-spacing:.05em;text-transform:uppercase;
  color:var(--ink-4);padding:9px var(--sp-4) 4px}

/* The trading figures are still here, one fold down. Action before data, not
   action instead of data. */
.attn-more{margin-top:var(--sp-2)}
.attn-more summary{cursor:pointer;font-size:12.5px;font-weight:600;color:var(--ink-3);
  padding:var(--sp-2) 0;list-style:none}
.attn-more summary::-webkit-details-marker{display:none}
.attn-more summary::before{content:"▸ ";color:var(--ink-4)}
.attn-more[open] summary::before{content:"▾ "}
.attn-more summary:hover{color:var(--ink)}


/* ── basis cell ─────────────────────────────────────────────────────────────
 * Which parts of a recommendation are measured and which are assumed. Assumed
 * entries are amber so the eye finds them; measured ones stay quiet. The point
 * is not to make every row look uncertain -- it is that a buyer should never
 * have to ask what a number rests on.
 */
.basis{display:flex;flex-direction:column;gap:1px;font-size:11px;line-height:1.35}
.basis-row{color:var(--ink-4);white-space:nowrap}
.basis-row i{display:inline-block;min-width:44px;font-style:normal;
  color:var(--ink-4);opacity:.75}
.basis-row.weak{color:var(--stop-ink);font-weight:560}
.basis-row.weak i{color:var(--stop-ink);opacity:.7}

/* The confidence reason stays visible -- hiding uncertainty is the thing this
   column exists to prevent -- but clamped to two lines, with the full sentence
   on hover. At 22 characters wide it was unreadable, which hides it just as
   effectively as omitting it. */
.conf-why{margin-top:3px;font-size:11px;line-height:1.35;color:var(--ink-4);
  max-width:26ch;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden}

/* Gross, net and basis as three labelled facts rather than one number and a
   sentence. A single "sales value" is the thing that caused the VAT incident:
   it looked authoritative and was on the wrong side of tax. */
.triple{display:flex;gap:6px;font-size:12px;line-height:1.5}
.triple i{font-style:normal;color:var(--ink-4);min-width:42px;flex:none}

/* ── the five-minute answer ─────────────────────────────────────────────────
 * Four blocks, four units, and deliberately no total across them: a combined
 * "N things to do" would mix committing money with moving stock we already own.
 * Each block is a link into the lane that owns it, because the next thing a
 * buyer does after reading a count is open it.
 */
.mon-grid{display:grid;gap:var(--sp-3);
  grid-template-columns:repeat(auto-fit,minmax(215px,1fr));margin-bottom:var(--sp-4)}
.mon{position:relative;display:block;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r);padding:var(--sp-4) var(--sp-4) var(--sp-4) calc(var(--sp-4) + 4px);
  box-shadow:var(--shadow);transition:border-color .12s, transform .12s}
.mon::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;
  border-radius:var(--r) 0 0 var(--r);background:var(--line-strong)}
.mon.risk::before{background:var(--risk)}
.mon.stop::before{background:var(--stop)}
.mon.go::before{background:var(--go)}
.mon:hover{border-color:var(--line-strong);transform:translateY(-1px)}
.mon-act{font-size:11.5px;font-weight:680;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-3)}
.mon.risk .mon-act{color:var(--risk-ink)}
.mon.stop .mon-act{color:var(--stop-ink)}
.mon.go .mon-act{color:var(--go-ink)}
.mon-n{font-size:34px;font-weight:670;letter-spacing:-.03em;line-height:1.05;
  margin:5px 0 6px;display:flex;align-items:baseline;gap:7px}
.mon-n small{font-size:12.5px;font-weight:500;color:var(--ink-3);letter-spacing:0}
.mon-l{font-size:12.5px;color:var(--ink-2);line-height:1.5}
@media (max-width:640px){ .mon-n{font-size:28px} }

/* The channel verdict as numbers, not a label. A buyer overriding "keep SFP"
   needs to see what the override costs per unit; a badge cannot be argued with. */
.chan{display:flex;flex-direction:column;gap:1px;font-size:11.5px;line-height:1.4}
.chan-row{display:flex;gap:5px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.chan-row i{font-style:normal;min-width:26px;opacity:.75}
.chan-row b{color:var(--ink-2);font-weight:560}
.chan-diff{margin-top:2px;font-weight:640;font-variant-numeric:tabular-nums}
.chan-diff.go{color:var(--go-ink)}
.chan-diff.risk{color:var(--risk-ink)}
.chan-diff.hold{color:var(--ink-4)}

.chan-win{font-size:10.5px;font-weight:650;letter-spacing:.03em;text-transform:uppercase;
  margin-top:1px}
.chan-win.go{color:var(--go-ink)}
.chan-win.risk{color:var(--risk-ink)}
.chan-win.hold{color:var(--ink-4)}

/* ── review panel ───────────────────────────────────────────────────────────
 * The decision is taken over the row it was read on. A separate approvals
 * screen would mean re-finding the SKU, and a buyer who has to do that approves
 * from memory -- which defeats the point of freezing the evidence they saw.
 */
.rev-back{position:fixed;inset:0;z-index:60;background:rgba(9,11,16,.55);
  display:flex;align-items:flex-start;justify-content:center;padding:6vh 16px;
  overflow-y:auto}
@media (prefers-color-scheme: light){ .rev-back{background:rgba(16,24,40,.32)} }
.rev-panel{background:var(--panel);border:1px solid var(--line-strong);
  border-radius:var(--r-lg);box-shadow:0 24px 64px -20px rgba(0,0,0,.6);
  width:100%;max-width:520px;overflow:hidden}
.rev-head{display:flex;align-items:flex-start;justify-content:space-between;
  gap:var(--sp-3);padding:var(--sp-4);border-bottom:1px solid var(--line-soft)}
.rev-sku{font-size:15px;font-weight:640;letter-spacing:-.01em}

/* What the system said, and what it rests on -- beside the field, not on a
   previous screen. A reviewer overriding a number needs the reason in view. */
.rev-rec{padding:var(--sp-4);background:var(--panel-2);
  border-bottom:1px solid var(--line-soft)}
.rev-rec-act{font-size:11.5px;font-weight:680;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3)}
.rev-rec-qty{font-size:26px;font-weight:670;letter-spacing:-.02em;margin:3px 0 5px}
.rev-rec-qty small{font-size:13px;font-weight:500;color:var(--ink-3)}
.rev-why{font-size:12.5px;color:var(--ink-2);line-height:1.5;max-width:56ch}
.rev-basis{display:flex;flex-wrap:wrap;gap:2px 14px;margin-top:var(--sp-3)}

.rev-form{padding:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-2)}
.rev-lbl{font-size:11.5px;font-weight:620;letter-spacing:.04em;
  text-transform:uppercase;color:var(--ink-3);margin-top:var(--sp-2)}
.rev-lbl .muted{font-weight:400;text-transform:none;letter-spacing:0}
.rev-form input{width:100%}
.rev-actions{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-3)}
.rev-err{font-size:12.5px;color:var(--risk-ink);line-height:1.4}

/* A row already decided reads as decided, rather than inviting a second answer. */
.rev-done{display:flex;flex-direction:column;gap:2px;align-items:flex-start}


/* -- supplier working table -------------------------------------------------
 * The buyer's operating view. Each cell carries one primary figure and its
 * qualifiers underneath, so a row can be read at a glance or interrogated,
 * without the qualifiers competing with the number they qualify.
 */
table.decisions.sup td{vertical-align:top;padding:8px 12px;line-height:1.3}
table.decisions.sup .sku{min-width:17ch;max-width:24ch}
table.decisions.sup .sku-meta{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:2px}
table.decisions.sup .sku-name{line-height:1.25}
table.decisions.sup .big{font-size:15.5px;line-height:1.15}
.unit{font-size:11px;color:var(--ink-4);margin-left:2px}
.sub{font-size:11.5px;color:var(--ink-3);margin-top:2px;font-variant-numeric:tabular-nums}
.sub.stop{color:var(--stop-ink)}
.sub.incl{color:var(--ink-2)}
.sub .dim{color:var(--ink-4)}

/* Where the stock physically is. Two places, never summed away. */
.split{display:flex;gap:8px;justify-content:flex-end;margin-top:3px;
  font-size:11.5px;color:var(--ink-3)}
.split b{color:var(--ink-2);font-weight:600}

/* A qualifier that changes what the number means -- late inbound, an empty
 * window. Deliberately louder than .sub and quieter than the figure itself. */
.flag{display:inline-block;margin-top:4px;font-size:11px;font-weight:600;
  padding:1px 5px;border-radius:var(--r-sm);background:var(--panel-3);
  color:var(--ink-2);font-variant-numeric:tabular-nums}
.flag.stop{background:var(--stop-soft);color:var(--stop-ink)}

.trend{display:inline-block;margin-top:3px;font-size:10.5px;font-weight:600;
  letter-spacing:.03em;text-transform:uppercase}
.trend.up{color:var(--go-ink)} .trend.down{color:var(--ink-4)}

.chip-season{display:inline-block;font-size:10.5px;font-weight:600;
  padding:1px 6px;border-radius:999px;background:var(--accent-soft);
  color:var(--accent-ink)}

/* Why, clamped. The full text stays in the title attribute and the drawer. */
.why-text{color:var(--ink-2);font-size:12.5px;line-height:1.4;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.why-extra{color:var(--ink-3);font-size:11.5px;margin-top:3px;
  display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
.why-meta{display:flex;align-items:center;gap:8px;margin-top:4px;flex-wrap:wrap}
table.decisions.sup .why{min-width:26ch;max-width:34ch}

.basis-chip{font-size:10.5px;font-weight:600;padding:1px 6px;border-radius:999px;
  background:var(--panel-3);color:var(--ink-3);cursor:help;white-space:nowrap}
.basis-chip.weak{background:var(--stop-soft);color:var(--stop-ink)}

/* A row already at risk of going empty gets a rail, so it is findable while
 * scrolling rather than only when its action column is read. */
table.decisions.sup tr.at-risk td:first-child{box-shadow:inset 3px 0 0 var(--risk)}

/* ACTION and SKU stay put while the operational columns scroll under them.
 * Widths are fixed because column two's offset is column one's width -- a
 * content-sized first column would put the second one in the wrong place.
 * Backgrounds must be opaque: a sticky cell with a transparent background
 * shows the scrolling content sliding beneath it. */
table.decisions.sup th:nth-child(1),
table.decisions.sup td:nth-child(1){position:sticky;left:0}
table.decisions.sup th:nth-child(2),
table.decisions.sup td:nth-child(2){position:sticky;left:var(--pin-2,148px);
  min-width:17ch}
table.decisions.sup td:nth-child(1),
table.decisions.sup td:nth-child(2){background:var(--panel);z-index:2}
table.decisions.sup tbody tr:hover td:nth-child(1),
table.decisions.sup tbody tr:hover td:nth-child(2){background:var(--panel-2)}
/* The two pinned headers are sticky on BOTH axes, so they must sit above the
 * row-sticky cells and above the rest of the header row. */
table.decisions.sup th:nth-child(1),
table.decisions.sup th:nth-child(2){z-index:7;background:var(--panel-2)}
/* A seam so the frozen pair reads as a separate pane once the table moves. */
table.decisions.sup th:nth-child(2),
table.decisions.sup td:nth-child(2){border-right:1px solid var(--line)}

/* The usable total: the sum a buyer can check, not a figure to be trusted. */
.usable{margin-top:6px;padding-top:5px;border-top:1px dashed var(--line-strong)}
.usable-sum{display:block;font-size:10.5px;color:var(--ink-4);
  font-variant-numeric:tabular-nums}
.usable b{font-size:12.5px;color:var(--ink-2);font-weight:640}
.excluded{font-size:10.5px;color:var(--stop-ink);margin-top:2px;
  font-variant-numeric:tabular-nums}


/* FBA fulfilment fee provenance. The basis is part of the number, not a note. */
.feebasis{display:inline-block;font:700 9px/1 var(--sans,inherit);letter-spacing:.08em;
  text-transform:uppercase;border-radius:3px;padding:3px 5px;margin-right:6px}
.feebasis.ok{color:#166534;background:#dcfce7}
.feebasis.est{color:#92400e;background:#fef3c7}
.feebasis.na{color:#991b1b;background:#fee2e2}
.pm2{display:block;font:400 10.5px/1.45 var(--mono,monospace);color:#6b7280;margin-top:3px}
.feeaudit{margin-top:6px;border-top:1px solid #e5e7eb;padding-top:5px;text-align:left}
.feeaudit div{display:flex;justify-content:space-between;gap:12px;
  font:400 10px/1.6 var(--mono,monospace);color:#6b7280}
.feeaudit b{font-weight:600;color:#374151}
.feeaudit .strike{text-decoration:line-through;color:#9ca3af}

/* FBA Restock table geometry.
   The table was 2,141px wide in a 1,440px viewport with table-layout:auto, so
   the browser gave Forecast-LY 382px and the Why column 87px. Explanatory
   sentences then wrapped one word per line and drove every one of 58 rows past
   150px -- median 580, worst 834. A width in CSS is only a suggestion under
   auto layout; fixed layout is what makes these hold. */
table.decisions.fba { table-layout: fixed; width: 100%; }
table.decisions.fba th, table.decisions.fba td { overflow: hidden; }
table.decisions.fba th:nth-child(1),  table.decisions.fba td:nth-child(1)  { width: 6.0%; }
table.decisions.fba th:nth-child(2),  table.decisions.fba td:nth-child(2)  { width: 14.0%; }
table.decisions.fba th:nth-child(3),  table.decisions.fba td:nth-child(3)  { width: 5.6%; }
table.decisions.fba th:nth-child(4),  table.decisions.fba td:nth-child(4)  { width: 4.6%; }
table.decisions.fba th:nth-child(5),  table.decisions.fba td:nth-child(5)  { width: 6.6%; }
table.decisions.fba th:nth-child(6),  table.decisions.fba td:nth-child(6)  { width: 7.0%; }
table.decisions.fba th:nth-child(7),  table.decisions.fba td:nth-child(7)  { width: 5.6%; }
table.decisions.fba th:nth-child(8),  table.decisions.fba td:nth-child(8)  { width: 5.4%; }
table.decisions.fba th:nth-child(9),  table.decisions.fba td:nth-child(9)  { width: 10.6%; }
table.decisions.fba th:nth-child(10), table.decisions.fba td:nth-child(10) { width: 8.8%; }
table.decisions.fba th:nth-child(11), table.decisions.fba td:nth-child(11) { width: 9.4%; }
table.decisions.fba th:nth-child(12), table.decisions.fba td:nth-child(12) { width: 10.6%; }
table.decisions.fba th:nth-child(13), table.decisions.fba td:nth-child(13) { width: 5.4%; }
table.decisions.fba th:nth-child(14), table.decisions.fba td:nth-child(14) { width: 5.4%; }

/* No single cell may set the height of the row. Three lines, then an ellipsis;
   the full sentence is on the title attribute and in the review panel. */
table.decisions.fba td.why .clamp {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 11.5px; line-height: 1.42;
}
table.decisions.fba td { vertical-align: top; padding-top: 8px; padding-bottom: 8px; }
table.decisions.fba .sku-name {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; word-break: break-word;
}
table.decisions.fba .sku-code { word-break: break-all; font-size: 10px; line-height: 1.35; }

/* Forecast and last year: three compact stacked pairs, not a 382px ribbon. */
table.decisions.fba td.fc { padding-left: 4px; padding-right: 4px; }
table.decisions.fba td.fc .fcm {
  display: inline-block; width: 32%; text-align: center; vertical-align: top;
  font: 500 11px/1.3 var(--mono, monospace);
}
table.decisions.fba td.fc .fcm b { display: block; font-weight: 600; font-size: 9.5px;
  letter-spacing: .04em; text-transform: uppercase; opacity: .6; }
table.decisions.fba td.fc .fcm i { display: block; font-style: normal; font-size: 9.5px; opacity: .55; }

/* Economics: the numbers on their own lines so 9% of width is enough. */
table.decisions.fba td.chanc { font-size: 11px; line-height: 1.4; }
table.decisions.fba td.chanc .cf { display: block; margin-top: 3px; }
table.decisions.fba td.season, table.decisions.fba td:nth-child(13) { font-size: 10px; }

/* The economics cell was stacking five blocks to 132px and setting the height of
   every row on the page. Same information, laid out across the column instead of
   down it: the two prices share a line, the verdict and evidence are one line
   each. Nothing is removed. */
/* .chan is display:flex/column globally, so inline-block children still stacked.
   The container has to become a normal block before the two prices can share a
   line -- this is why the first attempt changed nothing. */
table.decisions.fba td.chanc .chan { display: block; font-size: 11px; }
table.decisions.fba td.chanc .chan-row {
  display: inline-block; width: 49%; margin: 0; line-height: 1.35; font-size: 11px;
}
table.decisions.fba td.chanc .chan-row i { font-style: normal; opacity: .6; margin-right: 3px; }
table.decisions.fba td.chanc .chan-diff {
  margin: 2px 0 0; padding: 0; line-height: 1.4; font-size: 12px; font-weight: 600;
}
table.decisions.fba td.chanc .chan-win {
  margin: 1px 0 0; padding: 0; line-height: 1.35; font-size: 10px;
  letter-spacing: .03em; text-transform: uppercase;
}
table.decisions.fba td.chanc .conf { margin: 2px 0 0 !important; font-size: 9.5px !important;
  line-height: 1.3; display: block; }
table.decisions.fba td.chanc .conf i { display: none; }

/* Second pass. The first set of percentages summed to 105 and left FBA vs SFP
   at 127px, which is narrower than "-£0.48/unit" plus "KEEP SFP" can sit on one
   line; the content collapsed and wrapped, and the cell was still 120px tall.
   These sum to 100, the economics column gets the width it actually needs, and
   the short numeric strings are told not to wrap. */
table.decisions.fba th:nth-child(1),  table.decisions.fba td:nth-child(1)  { width: 5.6%; }
table.decisions.fba th:nth-child(2),  table.decisions.fba td:nth-child(2)  { width: 12.6%; }
table.decisions.fba th:nth-child(3),  table.decisions.fba td:nth-child(3)  { width: 5.4%; }
table.decisions.fba th:nth-child(4),  table.decisions.fba td:nth-child(4)  { width: 4.4%; }
table.decisions.fba th:nth-child(5),  table.decisions.fba td:nth-child(5)  { width: 6.4%; }
table.decisions.fba th:nth-child(6),  table.decisions.fba td:nth-child(6)  { width: 6.0%; }
table.decisions.fba th:nth-child(7),  table.decisions.fba td:nth-child(7)  { width: 5.4%; }
table.decisions.fba th:nth-child(8),  table.decisions.fba td:nth-child(8)  { width: 5.2%; }
table.decisions.fba th:nth-child(9),  table.decisions.fba td:nth-child(9)  { width: 9.6%; }
table.decisions.fba th:nth-child(10), table.decisions.fba td:nth-child(10) { width: 8.6%; }
table.decisions.fba th:nth-child(11), table.decisions.fba td:nth-child(11) { width: 11.6%; }
table.decisions.fba th:nth-child(12), table.decisions.fba td:nth-child(12) { width: 9.4%; }
table.decisions.fba th:nth-child(13), table.decisions.fba td:nth-child(13) { width: 4.8%; }
table.decisions.fba th:nth-child(14), table.decisions.fba td:nth-child(14) { width: 5.0%; }

table.decisions.fba td.chanc .chan-row,
table.decisions.fba td.chanc .chan-diff,
table.decisions.fba td.chanc .chan-win,
table.decisions.fba td.chanc .conf { white-space: nowrap; }
table.decisions.fba td.chanc .chan-row { width: auto; margin-right: 8px; }
table.decisions.fba td.chanc .chan-diff { display: inline-block; margin: 1px 6px 0 0; }
table.decisions.fba td.chanc .chan-win { display: inline-block; margin: 1px 0 0; }

/* Confidence in the RECOMMENDATION sits under the action badge. It is a
   different fact from the confidence inside the economics cell, which is
   confidence in the FBA-vs-SFP comparison -- removing it as a duplicate lost
   an answer the page is contracted to give. */
table.decisions.fba td.act .conf {
  display: block; margin-top: 4px; font-size: 9.5px; line-height: 1.25;
  white-space: normal;
}
table.decisions.fba td.act .conf i { display: none; }

/* .tablewrap sets overflow:auto, which makes it the scrollport. The sticky
   header then resolves against a container that never scrolls, so its top:52px
   was ADDED to the natural position (thead 69 + 52 = 121) and the header landed
   inside the first row -- a row visibly painted above the header. The FBA table
   now fits the viewport at 1,375px, so this wrap does not need to scroll and the
   header can stick to the page instead. */
.tablewrap.fbawrap { overflow: visible; }
.tablewrap.fbawrap table.decisions.fba thead th {
  position: sticky; top: 52px; z-index: 6; background: var(--paper, #fff);
  box-shadow: 0 1px 0 var(--line, #e5e7eb);
}

/* .card sets overflow:hidden for its rounded corners, which makes it the sticky
   containing block -- the header could only stick inside a 5,899px card, so it
   scrolled away with the page. Only the FBA card is opened up; every other card
   keeps its clipping. */
.card.fbacard { overflow: visible; }

/* Trading stock state: a status, not a day count. Three lines in one cell so a
   trader reads the problem and the answer without leaving the row. */
.stockstate { display: block; line-height: 1.25; }
.stockstate b { display: block; font-size: 10.5px; font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase; }
.stockstate i { display: block; font-style: normal; font-size: 9.5px;
  font-weight: 600; opacity: .75; letter-spacing: .02em; }
.stockstate u { display: block; text-decoration: none; font-size: 9.5px;
  font-family: var(--mono, monospace); opacity: .6; margin-top: 1px; }
/* Bounded so replacing a ~60px day-count with a three-line status does not push
   more columns off the right edge. The overall table width is a separate
   question, owned by the Signal / at-risk / opportunity work. */
td .stockstate { max-width: 118px; }
.stockstate b { white-space: normal; word-break: normal; }
.stockstate u { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
