/* ============================================================
   ShopGlobal OMS — Mockup stylesheet (Slice 1)
   Brand: shopglobal.sg — orange #FF6600, navy #131921, logo blue.
   Typeface: Montserrat. Minimalist: white surfaces, hairline
   borders, no heavy shadows, generous whitespace.
   ============================================================ */


/* ---------- 0. Typeface (self-hosted) ----------
   Montserrat is served from fonts/ rather than fonts.googleapis.com.
   The Google link cost a render-blocking round trip to googleapis
   (~180 ms cold) and a second one to gstatic for the font files, and
   it meant the deck degraded to system-ui with no network at all —
   which is exactly the situation a client demo tends to be in.

   These are the VARIABLE files (wght 100..900), so 550 / 620 / 650
   now render as themselves; the old static request only shipped
   400/500/600/700/800 and rounded the in-between weights.
   ------------------------------------------------ */
@font-face {
  font-family: "Montserrat";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/montserrat-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Montserrat";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/montserrat-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


/* ---------- 1. Tokens ---------- */
:root {
  /* brand (from shopglobal.sg) */
  --orange:        #FF6600;
  --orange-deep:   #E05A00;
  --orange-wash:   #FFF4EC;
  --blue:          #2B7CD8;
  --blue-deep:     #1F5FA9;
  --blue-wash:     #EEF5FC;
  --navy:          #131921;

  /* surfaces & ink */
  --page:          #FAFAF8;
  --surface:       #FFFFFF;
  --ink:           #0F1111;
  --ink-2:         #555555;
  --muted:         #9A9A96;
  --line:          #ECECEA;
  --line-strong:   #DDDDDA;

  /* status (icon/label always paired with colour) */
  --good:          #188038;
  --good-wash:     #E9F5EC;
  --warn:          #9A6B00;
  --warn-wash:     #FBF3DF;
  --serious:       #B3450E;
  --serious-wash:  #FCEEE6;
  --critical:      #C5221F;
  --critical-wash: #FCEAEA;
  --neutral-wash:  #F3F3F1;

  --radius:        12px;
  --radius-sm:     8px;
  --font:          "Montserrat", system-ui, -apple-system, sans-serif;

  /* aliases kept for inline styles in pages */
  --grid:          var(--line);
  --brand:         var(--blue);
  --good-text:     var(--good);
  --warning-text:  var(--warn);
  --serious-text:  var(--serious);
  --critical-text: var(--critical);
}

/* ---------- 2. Base ---------- */
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { min-height: 100%; }
body {
  font-family: var(--font);
  font-size: 15px;
  color: var(--ink);
  background: var(--page);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--blue-deep); text-decoration: none; font-weight: 600; }
a:hover { color: var(--orange); }
h1 { font-size: 19px; font-weight: 700; letter-spacing: -0.2px; }
h2 { font-size: 15.5px; font-weight: 700; letter-spacing: -0.1px; }
h3 { font-size: 14.5px; font-weight: 700; }
small, .muted { color: var(--muted); }
.num { font-variant-numeric: tabular-nums; }
svg.ic { width: 16px; height: 16px; stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; flex: 0 0 auto; }

/* ---------- 3. App shell ---------- */
.app { display: flex; min-height: 100vh; }

/* Sidebar — white, minimal */
.sidebar {
  width: 248px; flex: 0 0 248px;
  background: var(--surface);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.brand { padding: 24px 20px 18px; }
.brand .wordmark { font-size: 20px; font-weight: 800; letter-spacing: -0.4px; }
.brand .wordmark .shop { color: var(--blue); }
.brand .wordmark .global { color: var(--orange); }
.brand .wordmark .oms {
  display: inline-block; margin-left: 7px; vertical-align: 2px;
  font-size: 10px; font-weight: 700; letter-spacing: 1.5px;
  color: #fff; background: var(--navy); border-radius: 4px; padding: 2.5px 6px;
}
.brand small { display: block; margin-top: 5px; font-size: 10.5px; font-weight: 600; letter-spacing: 1.6px; color: var(--muted); text-transform: uppercase; }

.nav { padding: 0 12px 28px; }
.nav .section {
  font-size: 11px; letter-spacing: 1.8px; text-transform: uppercase;
  color: var(--muted); font-weight: 700; padding: 20px 10px 8px;
}
.nav a {
  display: flex; align-items: center; gap: 11px;
  padding: 8px 10px; margin: 1px 0;
  border-radius: 8px; color: var(--ink-2);
  font-size: 14.5px; font-weight: 500; white-space: nowrap;
  border-left: 3px solid transparent;
}
.nav a .ico { display: flex; color: var(--muted); }
.nav a:hover { background: var(--page); color: var(--ink); }
.nav a.active {
  background: var(--orange-wash); color: var(--navy); font-weight: 700;
  border-left-color: var(--orange);
}
.nav a.active .ico { color: var(--orange); }
.nav a .slice {
  margin-left: auto; font-size: 10.5px; font-weight: 600;
  color: var(--muted); border: 1px solid var(--line-strong);
  border-radius: 99px; padding: 1px 6px; white-space: nowrap;
}

/* Main column */
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* Topbar */
.topbar {
  display: flex; align-items: center; gap: 16px;
  padding: 14px 28px;
  background: var(--surface); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 20;
}
.topbar h1 { margin-right: auto; color: var(--navy); }
.topbar .crumb { color: var(--muted); font-size: 13.5px; }
.search {
  display: flex; align-items: center; gap: 9px;
  background: var(--page); border: 1px solid var(--line);
  border-radius: 99px; padding: 8px 16px; width: 300px; color: var(--muted);
}
.search input { border: 0; outline: 0; background: transparent; font: inherit; font-size: 14px; width: 100%; color: var(--ink); }
.search input::placeholder { color: var(--muted); }
.topbar select {
  font: inherit; font-size: 14px; font-weight: 500; padding: 8px 12px;
  border: 1px solid var(--line); border-radius: 99px;
  background: var(--surface); color: var(--ink-2);
}
.bell { position: relative; color: var(--ink-2); display: flex; }
.bell .badge {
  position: absolute; top: -7px; right: -9px;
  background: var(--orange); color: #fff; font-size: 9.5px; font-weight: 700;
  border-radius: 99px; padding: 1.5px 5px;
}
.avatar { display: flex; align-items: center; gap: 9px; font-weight: 600; font-size: 14px; }
.avatar .pic {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--navy); color: #fff;
  display: grid; place-items: center; font-size: 11.5px; font-weight: 700;
}

/* Content */
.content { padding: 26px 28px 56px; display: grid; gap: 18px; }
.page-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.page-head .spacer { flex: 1; }

/* ---------- 4. Components ---------- */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); }
.card .card-head {
  display: flex; align-items: center; gap: 10px;
  padding: 15px 18px; border-bottom: 1px solid var(--line);
}
.card .card-head .spacer { flex: 1; }
.card .card-body { padding: 18px; }
.card .card-body.flush { padding: 0; }

.grid { display: grid; gap: 18px; }
/* grid items default to min-width:auto, letting wide tables blow out the page;
   force them shrinkable so .table-wrap scrolls internally instead */
.content > *, .grid > *, .card-body > * { min-width: 0; }
.cols-2 { grid-template-columns: 1fr 1fr; }
.cols-3 { grid-template-columns: repeat(3, 1fr); }
.cols-4 { grid-template-columns: repeat(4, 1fr); }
.span-2 { grid-column: span 2; }
.span-full { grid-column: 1 / -1; }
@media (max-width: 1100px) { .cols-3, .cols-4 { grid-template-columns: 1fr 1fr; } }

/* KPI stat tile */
.kpis { display: grid; grid-template-columns: repeat(6, 1fr); gap: 14px; }
@media (max-width: 1280px) { .kpis { grid-template-columns: repeat(3, 1fr); } }
.kpi { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px; min-width: 0; }
.kpi .label { font-size: 11.5px; color: var(--muted); font-weight: 700; letter-spacing: 1.2px; }
.kpi .value { font-size: 26px; font-weight: 700; letter-spacing: -0.5px; margin-top: 7px; color: var(--navy); }
.kpi .delta { font-size: 12.5px; margin-top: 5px; font-weight: 600; color: var(--muted); }
.kpi .delta.up { color: var(--good); }
.kpi .delta.down { color: var(--critical); }
.kpi .delta.flat { color: var(--muted); }

/* Status pill */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 700; border-radius: 99px;
  padding: 3.5px 11px; white-space: nowrap;
}
.pill::before { content: "●"; font-size: 6px; }
.pill.good     { background: var(--good-wash);     color: var(--good); }
.pill.warn     { background: var(--warn-wash);     color: var(--warn); }
.pill.serious  { background: var(--serious-wash);  color: var(--serious); }
.pill.critical { background: var(--critical-wash); color: var(--critical); }
.pill.neutral  { background: var(--neutral-wash);  color: var(--ink-2); }
.pill.brand    { background: var(--blue-wash);     color: var(--blue-deep); }

/* Tag (source codes) */
.tag {
  display: inline-block; font-size: 11.5px; font-weight: 700; letter-spacing: .5px;
  border: 1px solid var(--line-strong); border-radius: 5px;
  padding: 2px 7px; color: var(--ink-2); background: var(--surface);
}
.tag.inz { color: #A05A00; border-color: #F0DCBE; background: #FDF7ED; }
.tag.usz { color: var(--blue-deep); border-color: #C9DEF4; background: var(--blue-wash); }
.tag.aez { color: #0E6E4C; border-color: #C2E3D4; background: #EDF7F2; }

/* Buttons */
.btn {
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit; font-size: 13.5px; font-weight: 600;
  padding: 8px 16px; border-radius: 99px; cursor: pointer;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink-2);
  transition: border-color .12s, background .12s;
}
.btn:hover { border-color: var(--navy); color: var(--navy); }
.btn.primary { background: var(--orange); border-color: var(--orange); color: #fff; }
.btn.primary:hover { background: var(--orange-deep); border-color: var(--orange-deep); color: #fff; }
.btn.danger { color: var(--critical); border-color: #F2CBCB; background: var(--surface); }
.btn.danger:hover { border-color: var(--critical); }
.btn.sm { padding: 5px 12px; font-size: 12.5px; }

/* Tabs */
.tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--line); padding: 0 12px; overflow-x: auto; }
.tabs button {
  font: inherit; font-size: 13.5px; font-weight: 600; color: var(--ink-2);
  background: none; border: 0; border-bottom: 2px solid transparent;
  padding: 13px 12px; cursor: pointer; display: flex; gap: 7px; align-items: center; white-space: nowrap;
}
.tabs button:hover { color: var(--navy); }
.tabs button.active { color: var(--navy); font-weight: 700; border-bottom-color: var(--orange); }
.tabs .count {
  font-size: 11.5px; font-weight: 700; background: var(--neutral-wash);
  color: var(--ink-2); border-radius: 99px; padding: 1.5px 7px;
}
.tabs button.active .count { background: var(--orange-wash); color: var(--orange-deep); }
.tabs .count.alert { background: var(--critical-wash); color: var(--critical); }
.tab-pane { display: none; }
.tab-pane.active { display: block; }

/* Filter row */
.filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.filters select, .filters input {
  font: inherit; font-size: 13px; font-weight: 500; padding: 7px 12px;
  border: 1px solid var(--line); border-radius: 99px; background: var(--surface); color: var(--ink-2);
}

/* Alert strip */
.alert {
  display: flex; gap: 10px; align-items: flex-start;
  border-radius: var(--radius-sm); padding: 12px 14px; font-size: 13.5px; line-height: 1.55;
  border: 1px solid transparent;
}
.alert .t { font-weight: 700; }
.alert > span:first-child:empty { display: none; }
.alert.critical { background: var(--critical-wash); color: #8C1D1B; border-color: #F5D5D5; }
.alert.warn     { background: var(--warn-wash);     color: #6E4D00; border-color: #EFE0BC; }
.alert.serious  { background: var(--serious-wash);  color: #833209; border-color: #F2D7C6; }
.alert.info     { background: var(--blue-wash);     color: var(--blue-deep); border-color: #D4E5F7; }

/* Timeline */
.timeline { display: flex; align-items: flex-start; padding: 6px 0 2px; }
.timeline .step { flex: 1; text-align: center; position: relative; padding-top: 4px; }
.timeline .dot {
  width: 24px; height: 24px; border-radius: 50%; margin: 0 auto 8px;
  display: grid; place-items: center; font-size: 11.5px; font-weight: 700;
  background: var(--surface); color: var(--muted); border: 1.5px solid var(--line-strong);
  position: relative; z-index: 2;
}
.timeline .step::before {
  content: ""; position: absolute; top: 15px; left: -50%; width: 100%;
  height: 1.5px; background: var(--line-strong); z-index: 1;
}
.timeline .step:first-child::before { display: none; }
.timeline .step.done .dot { background: var(--navy); border-color: var(--navy); color: #fff; }
.timeline .step.done::before { background: var(--navy); }
.timeline .step.now .dot { background: var(--orange); border-color: var(--orange); color: #fff; }
.timeline .step.now::before { background: var(--navy); }
.timeline .step.fail .dot { background: var(--critical); border-color: var(--critical); color: #fff; }
.timeline .lbl { font-size: 12.5px; font-weight: 700; color: var(--ink); }
.timeline .sub { font-size: 11.5px; color: var(--muted); margin-top: 2px; }

/* PO chain cards */
.po-card { border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.po-card + .po-card { margin-top: 12px; }
.po-card .po-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 14px; background: var(--page); border-bottom: 1px solid var(--line);
  font-size: 14px;
}
.po-card .po-body { padding: 12px 14px; display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px 18px; font-size: 13.5px; line-height: 1.5; }
.po-card .po-body .f .k { color: var(--muted); font-size: 11px; font-weight: 700; letter-spacing: 1px; margin-bottom: 2px; }
.po-card.failed { border-color: #F2CFCF; }
.po-card.failed .po-head { background: var(--critical-wash); }

/* Key-value list */
.kv { display: grid; grid-template-columns: 145px 1fr; gap: 9px 16px; font-size: 14px; }
.kv dt { color: var(--muted); font-weight: 600; }
.kv dd { color: var(--ink); font-weight: 500; }

/* Placeholder page */
.placeholder { display: grid; place-items: center; text-align: center; padding: 90px 24px; gap: 10px; }
.placeholder .big {
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--orange-wash); color: var(--orange);
  display: grid; place-items: center; font-size: 23px; font-weight: 800;
}

.mock-note { font-size: 12.5px; color: var(--muted); font-style: italic; font-weight: 500; }

/* ---------- 5. Tables ---------- */
.table-wrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: 14px; }
table.data th {
  text-align: left; font-size: 11px; letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--muted); font-weight: 700; white-space: nowrap;
  padding: 11px 14px; border-bottom: 1px solid var(--line);
}
table.data td { padding: 11px 14px; border-bottom: 1px solid var(--line); vertical-align: middle; white-space: nowrap; font-weight: 500; }
table.data tr:last-child td { border-bottom: 0; }
table.data tr:hover td { background: var(--page); }
table.data td .sub { display: block; font-size: 12.5px; color: var(--muted); margin-top: 2px; font-weight: 500; }
table.data .right { text-align: right; }
table.data td.wrap { white-space: normal; }
td.actions { text-align: right; }

/* row accent for exception rows */
tr.row-critical td:first-child { box-shadow: inset 3px 0 0 var(--critical); }
tr.row-warn td:first-child     { box-shadow: inset 3px 0 0 #E0A800; }
tr.row-serious td:first-child  { box-shadow: inset 3px 0 0 var(--serious); }

/* ---------- 6. Charts (static SVG) ---------- */
.card-body > svg { display: block; width: 100%; height: auto; }
.chart-legend { display: flex; gap: 16px; font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.chart-legend .li { display: flex; align-items: center; gap: 6px; }
.chart-legend .sw { width: 9px; height: 9px; border-radius: 3px; }
.bars { display: grid; gap: 11px; }
.bars .row { display: grid; grid-template-columns: 195px 1fr 52px; gap: 12px; align-items: center; font-size: 13.5px; }
.bars .row .name { color: var(--ink-2); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bars .row .track { background: var(--neutral-wash); border-radius: 4px; height: 12px; position: relative; }
.bars .row .fill { position: absolute; inset: 0 auto 0 0; border-radius: 4px; background: var(--blue); }
.bars .row .val { text-align: right; font-weight: 700; color: var(--navy); }


/* ============================================================
   7. Refinement layer — v3, 2026-07-26  ·  minimalist pass
   ------------------------------------------------------------
   Rules, held without exception:
     · ONE data hue (logo blue). Red only where something is
       genuinely breaching. Everything else is greyscale.
     · Orange is reserved for the active nav item and the primary
       button. It is never decoration.
     · No shadows on static surfaces, no gradients, no fills
       behind text. A hairline or a gap does the separating.
     · Type carries the hierarchy: size and colour, not weight
       piled on colour piled on a box.
   ============================================================ */
:root {
  --shadow-pop:   0 12px 34px rgba(19, 25, 33, .12);
  --shadow-focus: 0 0 0 3px rgba(43, 124, 216, .14);
  --ease: cubic-bezier(.2, .75, .25, 1);

  --page:       #FBFBFA;
  --hair:       #EFEFEC;   /* structural hairline */
  --hair-soft:  #F5F5F2;   /* in-list separator   */
  --track:      #ECECE9;

  --series:     #2B7CD8;   /* the one data hue */
  --series-dim: #BFD5EE;
  --ghost:      #D2D4D7;   /* comparison / previous period */

  /* validated categorical slots, used once — source split only */
  --cat-in:     #C2410C;
  --cat-us:     #1F5FA9;
  --cat-ae:     #0F9488;
}

html { scroll-behavior: smooth; }
body { background: var(--page); }
::selection { color: var(--navy); background: #FFE0CB; }
button, input, select { accent-color: var(--orange); }
a, button, input, select { -webkit-tap-highlight-color: transparent; }
:focus-visible { outline: 1.5px solid var(--blue); outline-offset: 3px; border-radius: 3px; }

/* ---------- 7.1 Shell ---------- */
.sidebar {
  width: 238px; flex-basis: 238px;
  background: var(--surface);
  border-right: 1px solid var(--hair);
  box-shadow: none;
  z-index: 40;
}
.brand { display: flex; align-items: center; gap: 11px; padding: 22px 20px 20px; border-bottom: 0; }
.brand-mark {
  width: 30px; height: 30px; flex: 0 0 30px;
  display: grid; place-items: center;
  border-radius: 8px; color: #fff;
  background: linear-gradient(145deg, var(--blue) 0 55%, var(--orange) 55% 100%);
  font-size: 10.5px; font-weight: 800; letter-spacing: .4px;
}
.brand-copy { min-width: 0; }
.brand .wordmark { font-size: 17.5px; font-weight: 700; letter-spacing: -.3px; line-height: 1; }
.brand .wordmark .oms {
  margin-left: 6px; padding: 2px 5px; vertical-align: 1px;
  font-size: 9px; letter-spacing: 1.2px; background: var(--navy);
}
.brand small {
  /* the one label that must not grow — it already fills the sidebar width */
  margin-top: 5px; font-size: 9px; font-weight: 600; letter-spacing: .8px; color: #A9A9A4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.nav { flex: 1; padding: 10px 12px 18px; }
.nav .section {
  padding: 22px 12px 8px; font-size: 10px; font-weight: 700;
  letter-spacing: 1.5px; color: #ADADA8;
}
.nav a {
  position: relative; min-height: 34px; gap: 11px; padding: 7px 12px;
  border: 0; border-radius: 7px; font-size: 14px; font-weight: 500; color: #56575A;
  transition: color .15s var(--ease), background .15s var(--ease);
}
.nav a .ico { width: 17px; height: 17px; display: grid; place-items: center; color: #A6A6A1; }
.nav a svg.ic { width: 15.5px; height: 15.5px; stroke-width: 1.7; }
.nav a:hover { background: var(--page); color: var(--navy); }
.nav a:hover .ico { color: #6B6C6F; }
.nav a.active { color: var(--navy); font-weight: 600; background: #F6F6F3; box-shadow: none; }
.nav a.active::before {
  content: ""; position: absolute; left: 0; top: 9px; bottom: 9px;
  width: 2.5px; border-radius: 99px; background: var(--orange);
}
.nav a.active .ico { color: var(--orange); }

.sidebar-foot {
  margin: 0 14px 16px; padding: 0; border: 0; border-radius: 0;
  display: flex; align-items: center; gap: 8px; background: none; box-shadow: none;
}
.sync-dot { width: 6px; height: 6px; flex: 0 0 auto; border-radius: 50%; background: var(--good); box-shadow: none; }
.sidebar-foot b { display: block; color: #6B6C6F; font-size: 10.5px; font-weight: 600; line-height: 1.3; }
.sidebar-foot span:last-child { display: block; margin-top: 1px; color: #ADADA8; font-size: 10px; font-weight: 500; }

.main { min-height: 100vh; background: transparent; }
.topbar {
  min-height: 60px; gap: 14px; padding: 11px 32px;
  background: rgba(251, 251, 250, .92);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid var(--hair);
  box-shadow: none;
}
.topbar-title { min-width: 130px; margin-right: auto; }
.topbar-title .eyebrow { display: none; }
.topbar h1 { font-size: 18px; font-weight: 650; letter-spacing: -.25px; line-height: 1.2; color: var(--navy); }
.search {
  min-height: 34px; width: 260px; padding: 7px 14px;
  background: transparent; border: 1px solid var(--hair); color: #A6A6A1;
  transition: border-color .15s, box-shadow .15s;
}
.search input { font-size: 13.5px; }
.search:focus-within { background: #fff; border-color: var(--blue); box-shadow: var(--shadow-focus); }
.search-kbd {
  padding: 1.5px 5px; border: 1px solid var(--hair); border-radius: 4px;
  background: transparent; color: #B4B4AF; font-size: 9.5px; font-weight: 700;
}
.topbar select {
  min-height: 34px; max-width: 180px; font-size: 13.5px;
  background-color: transparent; border-color: var(--hair); color: #56575A;
}
.bell, .menu-toggle {
  width: 34px; height: 34px; padding: 0; display: grid; place-items: center;
  border: 0; border-radius: 8px; background: transparent; color: #7A7B7E; cursor: pointer;
  transition: color .15s, background .15s;
}
.bell:hover, .menu-toggle:hover { color: var(--navy); background: #F3F3F0; }
.bell .badge { top: -2px; right: -2px; border: 2px solid var(--page); font-size: 9px; }
.avatar { padding: 0; border: 0; border-radius: 99px; background: none; font-size: 13.5px; font-weight: 600; }
.avatar .pic { width: 27px; height: 27px; position: relative; background: var(--navy); font-size: 10.5px; }
.avatar .pic::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 7px; height: 7px; border: 2px solid var(--page); border-radius: 50%; background: var(--good);
}
.menu-toggle { display: none; }
.nav-overlay { display: none; }

.content { width: 100%; max-width: 1640px; margin: 0 auto; padding: 26px 32px 72px; gap: 22px; }

/* ---------- 7.2 Surfaces ---------- */
.card {
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--hair);
  border-radius: 14px;
  box-shadow: none;
  transition: none;
}
.card:hover { border-color: var(--hair); box-shadow: none; }
.card .card-head {
  min-height: 0; align-items: baseline; gap: 9px;
  padding: 19px 22px 15px; background: transparent; border-bottom: 0;
}
.card .card-head h2 {
  font-size: 14px; font-weight: 650; letter-spacing: -.05px; color: var(--navy);
}
.card .card-head h2::before { content: none; }
.card .card-head .sub {
  padding: 0; margin: 0; border: 0;
  font-size: 12.5px; font-weight: 500; color: #A6A6A1;
}
.card .card-head .sub::before { content: "·"; margin-right: 8px; color: #CFCFCA; }
.card .card-head a:not(.btn) { font-size: 12.5px; font-weight: 600; color: #7A7B7E; }
.card .card-head a:not(.btn):hover { color: var(--orange); }
.card .card-body { padding: 4px 22px 22px; }
.card .card-body.flush { padding: 0; border-top: 1px solid var(--hair); }
.grid { gap: 22px; }

/* ---------- 7.3 Page toolbar ---------- */
.toolbar { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 2px 2px 2px; }
.toolbar .when { color: #7A7B7E; font-size: 13.5px; font-weight: 500; }
.toolbar .when b { color: var(--navy); font-weight: 650; }
.toolbar .rule { display: none; }
.toolbar .live {
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--critical); font-size: 13px; font-weight: 600;
}
.toolbar .live::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.toolbar .live.calm { color: var(--good); }
.toolbar .spacer { flex: 1; }

.seg { display: inline-flex; gap: 2px; padding: 0; border: 0; background: none; }
.seg button {
  font: inherit; font-size: 12.5px; font-weight: 500; color: #9A9A96;
  padding: 5px 11px; border: 0; border-radius: 99px; background: none; cursor: pointer;
  transition: color .15s, background .15s;
}
.seg button:hover { color: var(--navy); }
.seg button.active { color: var(--navy); font-weight: 650; background: #F1F1EE; box-shadow: none; }

/* ---------- 7.4 Stat tiles ---------- */
/* Raised rounded boxes. This is the one place the "no shadows on static
   surfaces" rule is deliberately set aside — Gaurav asked for 3D tiles, so
   the depth is built properly: a stacked shadow (contact + ambient + cast),
   a top inner highlight, and a slightly darker bottom edge for the lip. */
.kpis { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 16px; }
.kpi {
  display: flex; flex-direction: column; position: relative;
  min-height: 112px; padding: 17px 18px 18px; margin: 0;
  border: 1px solid var(--hair); border-bottom-color: #E3E3DF;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  color: inherit; text-decoration: none;
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), border-color .18s;
}
.kpi::after { content: none; }
a.kpi:hover {
  transform: translateY(-2px);
  border-color: #DCDCD7;
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 4px 8px rgba(19, 25, 33, .05),
    0 14px 28px rgba(19, 25, 33, .08),
    inset 0 1px 0 rgba(255, 255, 255, .9);
}
a.kpi:active { transform: translateY(0); }

.kpi .label {
  display: block; color: var(--navy);
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.15px;
}
.kpi .label .flag { display: none; }
.kpi .figure { display: flex; align-items: center; gap: 12px; margin-top: auto; padding-top: 14px; }
.kpi .value {
  margin: 0; font-size: 30px; font-weight: 600; line-height: 1;
  letter-spacing: -1.1px; color: var(--navy); font-variant-numeric: normal;
}
.kpi .value .unit { font-size: 14px; font-weight: 600; color: #A6A6A1; letter-spacing: 0; margin-right: 5px; }
/* the sub-line is gone, so the figure itself has to carry "this one is a problem" */
.kpi.is-critical .value, .kpi.is-serious .value { color: var(--critical); }

/* the tile's subject, seated in its own recessed square. Beside the figure
   rather than in the corner, so the label always gets the full tile width —
   "OPEN FOR PURCHASE" wrapped when it had to dodge a corner icon. */
.kpi-ic {
  margin-left: auto; flex: 0 0 34px;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 11px; color: #8E8F92;
  background: linear-gradient(180deg, #F7F8F9, #F1F2F3);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(19, 25, 33, .045);
  transition: color .18s, background .18s;
}
.kpi-ic svg.ic { display: block; width: 18px; height: 18px; stroke-width: 1.7; }
.kpi.is-critical .kpi-ic, .kpi.is-serious .kpi-ic {
  color: var(--critical);
  background: linear-gradient(180deg, #FDF3F3, #FBEBEB);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(197, 34, 31, .09);
}
a.kpi:hover .kpi-ic { color: var(--navy); }

/* ---------- 7.5 Order journey ---------- */
/* The rail gives every milestone equal weight. Counts show cumulative progress;
   the small branches show the live work owned by each stage. */
.journey {
  position: relative; isolation: isolate;
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  padding: 24px 20px 20px;
}
.journey-rail {
  position: absolute; z-index: 0;
  top: 72px; left: calc(20px + (100% - 40px) / 14); right: calc(20px + (100% - 40px) / 14);
  height: 1px; background: #BFD6F1;
}
.journey-stage {
  position: relative; z-index: 1; min-width: 0;
  display: grid; grid-template-rows: 24px 36px 18px minmax(48px, auto);
  justify-items: center; align-items: start;
  padding: 0 7px; color: inherit; text-align: center; text-decoration: none;
}
.journey-count {
  color: var(--navy); font-size: 18px; font-weight: 650;
  line-height: 1; letter-spacing: -.35px; font-variant-numeric: tabular-nums;
}
.journey-node {
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 1px solid #BFD6F1; border-radius: 50%;
  color: var(--blue-deep); background: #fff;
  transition: border-color .15s, color .15s, transform .15s;
}
.journey-node .ic { width: 15px; height: 15px; stroke-width: 1.7; }
.journey-stage:hover .journey-node {
  color: var(--blue); border-color: var(--blue); transform: translateY(-1px);
}
.journey-name {
  align-self: end; color: var(--navy);
  font-size: 10px; font-weight: 650; line-height: 1;
  letter-spacing: 1.05px; text-transform: uppercase; white-space: nowrap;
}
.journey-branch {
  position: relative; display: block; width: 100%; margin-top: 19px; padding-top: 4px;
  color: #7A7B7E; line-height: 1.35;
}
.journey-branch::before {
  content: ""; position: absolute; left: 50%; top: -17px;
  width: 1px; height: 13px; background: #DCDCD8;
}
.journey-branch::after {
  content: ""; position: absolute; left: calc(50% - 2px); top: -5px;
  width: 5px; height: 5px; border-radius: 50%; background: #C4C6C2;
}
.journey-live {
  display: block; min-height: 16px;
  color: #66676A; font-size: 11.5px; font-weight: 500; white-space: nowrap;
}
.journey-live b {
  color: var(--navy); font-size: 13.5px; font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.journey-stage.critical .journey-branch::after { background: var(--critical); }
.journey-stage.warn .journey-branch::after { background: #C9A227; }


/* ---------- 7.6 Line chart ---------- */
.chart { position: relative; }
.chart svg { display: block; width: 100%; height: auto; touch-action: pan-y; }
.chart .hit { fill: transparent; cursor: crosshair; }
.chart .crosshair { stroke: #DCDCD8; stroke-width: 1; opacity: 0; }
.chart .focus-dot { opacity: 0; }
.chart.is-live .crosshair, .chart.is-live .focus-dot { opacity: 1; }
.chart-tip {
  position: absolute; z-index: 5; top: 0; left: 0;
  min-width: 144px; padding: 10px 12px;
  border: 1px solid var(--hair); border-radius: 10px;
  background: #fff; box-shadow: var(--shadow-pop);
  font-size: 12.5px; pointer-events: none;
  opacity: 0; visibility: hidden; transform: translate(-50%, -100%);
  transition: opacity .12s;
}
.chart.is-live .chart-tip { opacity: 1; visibility: visible; }
.chart-tip .tip-date { color: #A6A6A1; font-size: 10.5px; font-weight: 600; letter-spacing: .9px; text-transform: uppercase; }
.chart-tip .tip-row { display: flex; align-items: center; gap: 9px; margin-top: 7px; }
.chart-tip .tip-row .sw { width: 9px; height: 2.5px; flex: 0 0 9px; border-radius: 99px; }
.chart-tip .tip-row .k { color: #7A7B7E; font-weight: 500; }
.chart-tip .tip-row .v { margin-left: auto; font-weight: 650; color: var(--navy); font-variant-numeric: tabular-nums; }
.chart-legend { gap: 15px; font-size: 12px; font-weight: 500; color: #7A7B7E; }
.chart-legend .sw { width: 11px; height: 2.5px; border-radius: 99px; }
.chart-note { margin-top: 16px; color: #9A9A96; font-size: 12.5px; font-weight: 500; line-height: 1.6; }
.chart-note b { color: var(--navy); font-weight: 650; }

.viewswap { display: inline-flex; gap: 2px; }
.viewswap button {
  font: inherit; font-size: 12px; font-weight: 500; color: #A6A6A1;
  padding: 4px 9px; border: 0; border-radius: 99px; background: none; cursor: pointer;
  transition: color .15s, background .15s;
}
.viewswap button:hover { color: var(--navy); }
.viewswap button.active { color: var(--navy); font-weight: 650; background: #F1F1EE; }
[data-view-pane] { display: none; }
[data-view-pane].active { display: block; }

/* ---------- 7.7 Meters ---------- */
.meters { display: grid; gap: 18px; }
.meter-head { display: flex; align-items: baseline; gap: 10px; font-size: 13.5px; }
.meter-head .m-name { font-weight: 500; color: var(--ink); }
.meter-head .m-val { margin-left: auto; font-weight: 650; color: var(--navy); font-variant-numeric: tabular-nums; }
.meter-track { position: relative; height: 3px; margin-top: 9px; border-radius: 99px; background: var(--track); }
.meter-track .fill { position: absolute; inset: 0 auto 0 0; border-radius: 99px; background: var(--series); }
.meter-track .fill.warn { background: var(--series-dim); }
.meter-track .fill.serious, .meter-track .fill.critical { background: var(--critical); }
.meter-track .target { position: absolute; top: -3.5px; bottom: -3.5px; width: 1.5px; border-radius: 2px; background: #9A9A96; }
.meter-sub { margin-top: 8px; color: #A6A6A1; font-size: 11.5px; font-weight: 500; }
.meter-sub b { color: #7A7B7E; font-weight: 600; }

/* ---------- 7.7b SLA gauges ---------- */
/* Half-circle per milestone. The arc is the achieved figure; the tick across
   it is the configured target — so the number and "is that good" read as one. */
.gauges {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  padding: 10px 12px 8px;
}
.gauge { text-align: center; padding: 10px 10px 12px; border-left: 1px solid var(--hair); }
.gauge:first-child { border-left: 0; }
.gauge svg { display: block; width: 100%; max-width: 156px; margin: 0 auto; height: auto; overflow: visible; }
.g-track { fill: none; stroke: var(--track); stroke-linecap: round; }
.g-fill  { fill: none; stroke: var(--series); stroke-linecap: round; }
.gauge.short .g-fill { stroke: var(--critical); }
.g-tick  { stroke: var(--navy); stroke-width: 2; stroke-linecap: butt; }
.g-val {
  font-family: var(--font); font-size: 27px; font-weight: 650;
  letter-spacing: -1px; fill: var(--navy);
}
.gauge.short .g-val { fill: var(--critical); }
.g-pc { font-size: 15px; font-weight: 600; letter-spacing: 0; }
.g-tgt { font-family: var(--font); font-size: 11px; font-weight: 500; fill: #B4B4AF; }
.g-name {
  display: block; margin-top: 12px; color: var(--navy);
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.15px; text-transform: uppercase;
}

/* ---------- 7.7c Flags, marketplace marks, source rings ---------- */
.flag {
  display: block; width: 26px; height: 26px; flex: 0 0 26px;
  border-radius: 50%; overflow: hidden;
  box-shadow: 0 0 0 1px rgba(19, 25, 33, .07);
}
.flag svg { display: block; width: 100%; height: 100%; }

.source-rings { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.ring { text-align: center; }
.ring-art { position: relative; display: block; width: 84px; height: 84px; margin: 0 auto; }
.ring-art > svg { display: block; width: 84px; height: 84px; }
.r-track { fill: none; stroke: var(--track); stroke-width: 5; }
.r-fill  { fill: none; stroke: var(--series); stroke-width: 5; stroke-linecap: round; }
.ring-art .flag {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 46px; height: 46px; flex: 0 0 46px;
  box-shadow: 0 0 0 1px rgba(19, 25, 33, .06);
}
.ring-name { display: block; margin-top: 13px; color: var(--navy); font-size: 13.5px; font-weight: 650; }
.ring-sub  { display: block; margin-top: 3px; color: #ADADA8; font-size: 11px; font-weight: 600; letter-spacing: .7px; }
.ring-val  { display: block; margin-top: 8px; color: var(--navy); font-size: 16px; font-weight: 650; font-variant-numeric: tabular-nums; }
.ring-val em { display: block; margin-top: 3px; font-style: normal; font-size: 12px; font-weight: 500; color: #A6A6A1; }

.mk { position: relative; display: block; width: 30px; height: 30px; flex: 0 0 30px; }
.mk-mark {
  display: grid; place-items: center; width: 30px; height: 30px;
  border-radius: 50%; font-size: 16px; font-weight: 800; line-height: 1;
  box-shadow: 0 0 0 1px rgba(19, 25, 33, .07);
}
.mk .flag {
  position: absolute; right: -3px; bottom: -3px;
  width: 15px; height: 15px; flex: 0 0 15px;
  box-shadow: 0 0 0 2px var(--surface);
}

.accounts { display: grid; gap: 12px; }
.acct { display: grid; grid-template-columns: 30px minmax(0, 1fr) 1fr 48px; gap: 14px; align-items: center; }
.acct-name { min-width: 0; color: var(--ink); font-size: 13.5px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.acct-name em { font-style: normal; color: #B4B4AF; font-weight: 500; margin-left: 7px; font-size: 12px; }
.acct-track { height: 3px; border-radius: 99px; background: var(--track); overflow: hidden; }
.acct-track i { display: block; height: 100%; border-radius: 99px; background: var(--series); }
.acct-val { text-align: right; font-size: 13.5px; font-weight: 650; color: var(--navy); font-variant-numeric: tabular-nums; }

/* ---------- 7.7d Inline row icons ---------- */
.row-ic { display: inline-flex; color: #C2C2BD; vertical-align: -3px; margin-right: 10px; }
.row-ic svg.ic { width: 15px; height: 15px; stroke-width: 1.6; }
.bars .row .name { display: flex; align-items: center; gap: 0; }
table.data td .row-ic { margin-right: 11px; }
table.data tr:hover .row-ic { color: #8E8F92; }

/* ---------- 7.7e Work queues — triage board ---------- */
/* Three lanes, and which lane a queue lands in is computed from
   oldest-item age ÷ that queue's own SLA window, not hand-assigned. */
.board { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; padding: 18px 22px 22px; }
.lane { min-width: 0; }
.lane-head {
  display: flex; align-items: baseline; gap: 9px;
  padding-bottom: 11px; margin-bottom: 13px; border-bottom: 1px solid var(--hair);
}
.lane-title {
  display: inline-flex; align-items: baseline; gap: 8px;
  color: var(--navy); font-size: 10.5px; font-weight: 700; letter-spacing: 1.15px; text-transform: uppercase;
}
.lane-title::before {
  content: ""; align-self: center; width: 6px; height: 6px; flex: 0 0 6px;
  border-radius: 50%; background: #C4C6C2;
}
.lane.breach .lane-title::before { background: var(--critical); }
.lane.risk   .lane-title::before { background: #C9A227; }
.lane-count {
  min-width: 18px; padding: 1px 6px; border-radius: 99px;
  background: #F1F1EE; color: #7A7B7E;
  font-size: 11px; font-weight: 700; text-align: center; font-variant-numeric: tabular-nums;
}
.lane.breach .lane-count { background: var(--critical-wash); color: var(--critical); }
.lane-items { margin-left: auto; color: #B4B4AF; font-size: 11.5px; font-weight: 500; font-variant-numeric: tabular-nums; }
.lane-empty { color: #C2C2BD; font-size: 12.5px; font-weight: 500; padding: 6px 2px; }

.q-card {
  display: block; padding: 13px 15px 14px; margin-bottom: 10px;
  border: 1px solid var(--hair); border-radius: 10px;
  color: inherit; text-decoration: none;
  transition: border-color .15s, background .15s;
}
.q-card:last-child { margin-bottom: 0; }
.q-card:hover { border-color: var(--line-strong); background: #FCFCFB; }
.q-card.breach { box-shadow: inset 2.5px 0 0 var(--critical); }

.q-top { display: flex; align-items: center; gap: 9px; }
.q-ic { display: inline-flex; color: #C2C2BD; }
.q-ic svg.ic { width: 15px; height: 15px; stroke-width: 1.6; }
.q-card.breach .q-ic { color: var(--critical); }
.q-name {
  min-width: 0; color: var(--navy); font-size: 13.5px; font-weight: 650;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.q-items {
  margin-left: auto; color: var(--navy);
  font-size: 18px; font-weight: 650; letter-spacing: -.4px; font-variant-numeric: tabular-nums;
}
.q-team { display: block; margin-top: 3px; color: #A6A6A1; font-size: 11.5px; font-weight: 500; }

/* age of the oldest item as a share of that queue's SLA window */
.q-track { display: block; height: 3px; margin-top: 12px; border-radius: 99px; background: var(--track); overflow: hidden; }
.q-track i { display: block; height: 100%; border-radius: 99px; background: var(--series); }
.q-card.breach .q-track i { background: var(--critical); }
.q-card.risk .q-track i { background: #C9A227; }

.q-age { display: flex; align-items: baseline; gap: 10px; margin-top: 8px; font-variant-numeric: tabular-nums; }
.q-old { color: #7A7B7E; font-size: 12px; font-weight: 600; }
.q-sla { margin-left: auto; color: #ADADA8; font-size: 11.5px; font-weight: 500; }
.q-card.breach .q-sla { color: var(--critical); font-weight: 600; }

.q-action {
  display: block; margin-top: 11px; padding-top: 10px;
  border-top: 1px solid var(--hair-soft);
  color: #7A7B7E; font-size: 12px; font-weight: 500;
}
.q-card:hover .q-action { color: var(--blue-deep); }
.q-action::after { content: " →"; color: #C2C2BD; }
.q-card:hover .q-action::after { color: var(--blue-deep); }

/* ---------- 7.8 Exception feed ---------- */
.feed { list-style: none; display: grid; }
/* full width, so the entries flow into columns instead of stretching a
   40px timestamp across 1,500px — chronology still reads down each column */
.card.span-full .feed {
  display: block; column-count: 3; column-gap: 44px;
  column-rule: 1px solid var(--hair-soft);   /* same weight as the row separators */
}
.card.span-full .feed li { break-inside: avoid; }
.card.span-full .feed li:first-child { border-top: 1px solid var(--hair-soft); padding-top: 15px; }
@media (max-width: 1240px) { .card.span-full .feed { column-count: 2; } }
@media (max-width: 820px)  { .card.span-full .feed { column-count: 1; } }
.feed li {
  display: grid; grid-template-columns: 46px 1fr; gap: 0 13px;
  padding: 15px 0; border-top: 1px solid var(--hair-soft); font-size: 13.5px;
}
.feed li:first-child { border-top: 0; padding-top: 4px; }
.feed li time { color: #B4B4AF; font-size: 11.5px; font-weight: 600; font-variant-numeric: tabular-nums; padding-top: 2px; }
.feed li .body { min-width: 0; }
.feed li .body b { display: inline-flex; align-items: baseline; gap: 8px; font-size: 13.5px; font-weight: 650; color: var(--navy); }
.feed li .body b::before {
  content: ""; align-self: center; width: 5px; height: 5px; flex: 0 0 5px;
  border-radius: 50%; background: #CFCFCA;
}
.feed li.critical .body b::before, .feed li.serious .body b::before { background: var(--critical); }
.feed li.warn .body b::before { background: #C9A227; }
.feed li.info .body b::before { background: var(--series-dim); }
.feed li .body p { margin-top: 5px; color: #7A7B7E; font-size: 12.5px; line-height: 1.6; font-weight: 500; }
.feed li .body p a { color: var(--blue-deep); font-weight: 600; }

/* ---------- 7.9 Bars & split ---------- */
.bars { gap: 13px; }
.bars .row { grid-template-columns: 172px 1fr 44px; font-size: 13px; gap: 14px; }
.bars .row .name { color: #56575A; font-weight: 500; }
.bars .row .track { height: 3px; border-radius: 99px; background: var(--track); overflow: hidden; }
.bars .row .fill { border-radius: 99px; background: var(--series); box-shadow: none; }
.bars .row .fill.muted { background: var(--series-dim); }
.bars .row .val { font-weight: 600; color: var(--navy); font-variant-numeric: tabular-nums; }


.sub-head {
  font-size: 10.5px; font-weight: 600; letter-spacing: 1.15px;
  color: #A6A6A1; text-transform: uppercase;
}

/* ---------- 7.10 Controls & data ---------- */
.btn {
  min-height: 32px; justify-content: center; font-size: 13px; font-weight: 600;
  padding: 7px 15px; border-color: var(--hair); color: #56575A;
  box-shadow: none; transition: color .15s, background .15s, border-color .15s;
}
.btn:hover { transform: none; box-shadow: none; border-color: #D9D9D4; background: #FBFBFA; color: var(--navy); }
.btn.primary { background: var(--orange); border-color: var(--orange); color: #fff; box-shadow: none; }
.btn.primary:hover { background: var(--orange-deep); border-color: var(--orange-deep); color: #fff; }
.btn.sm { min-height: 27px; padding: 4px 12px; font-size: 12px; }
.btn.ghost { border-color: transparent; background: transparent; color: #7A7B7E; }
.btn.ghost:hover { border-color: transparent; background: #F3F3F0; color: var(--navy); }
/* icons inside controls and alert strips — the 16px default reads oversized
   against a 12px .btn.sm, so scope them like .nav/.row-ic/.q-ic do */
.btn svg.ic { width: 14px; height: 14px; stroke-width: 1.7; }
.btn.sm svg.ic { width: 13px; height: 13px; }
.alert > span:first-child svg.ic { width: 15px; height: 15px; margin-top: 3px; }

.tabs { gap: 4px; padding: 0 20px; background: transparent; border-bottom-color: var(--hair); }
.tabs button {
  position: relative; min-height: 44px; border-radius: 0; font-size: 13.5px; font-weight: 500;
  color: #7A7B7E; border-bottom: 2px solid transparent; transition: color .15s;
}
.tabs button:hover { background: transparent; color: var(--navy); }
.tabs button.active { background: transparent; color: var(--navy); font-weight: 650; border-bottom-color: var(--orange); }
.tabs button.active::after { content: none; }
.tabs .count { background: #F1F1EE; color: #7A7B7E; font-weight: 600; }
.tabs button.active .count { background: var(--orange-wash); color: var(--orange-deep); }

.filters { gap: 8px; padding: 14px 20px; background: transparent; border-bottom-color: var(--hair); }
.filters select, .filters input,
.form-grid input, .form-grid select, .form-grid textarea,
td input, td select { min-height: 31px; font-size: 12.5px; border-color: var(--hair); transition: border-color .15s, box-shadow .15s; }
.filters select:hover, .filters input:hover,
.form-grid input:hover, .form-grid select:hover, .form-grid textarea:hover,
td input:hover, td select:hover { border-color: #D9D9D4; }
.filters select:focus, .filters input:focus,
.form-grid input:focus, .form-grid select:focus, .form-grid textarea:focus,
td input:focus, td select:focus { outline: 0; border-color: var(--blue); background: #fff; box-shadow: var(--shadow-focus); }

.table-wrap { scrollbar-width: thin; scrollbar-color: #DEDEDA transparent; }
.table-wrap::-webkit-scrollbar { height: 6px; }
.table-wrap::-webkit-scrollbar-thumb { background: #DEDEDA; border-radius: 99px; }
table.data { font-size: 13.5px; }
table.data th {
  position: sticky; top: 0; z-index: 2;
  padding: 13px 20px; color: #ADADA8; background: var(--surface);
  border-bottom: 1px solid var(--hair);
  font-size: 10px; font-weight: 600; letter-spacing: 1.25px;
}
table.data td {
  height: 50px; padding: 12px 20px; font-weight: 500;
  border-bottom: 1px solid var(--hair-soft); transition: background .12s;
}
table.data tbody tr:last-child td { border-bottom: 0; }
table.data tbody tr:nth-child(even) td { background: transparent; }
table.data tbody tr:hover td { background: #FBFBFA; }
table.data td.num, table.data td .num { font-variant-numeric: tabular-nums; }
table.data a:not(.btn) { text-decoration: none; }
table.data a:not(.btn):hover { text-decoration: underline; text-underline-offset: 3px; }
table.data td .sub { color: #ADADA8; }

/* status accents stay as text + a dot, never a filled row */
tr.row-critical td:first-child { box-shadow: inset 2px 0 0 var(--critical); }
tr.row-serious  td:first-child { box-shadow: inset 2px 0 0 var(--critical); }
tr.row-warn     td:first-child { box-shadow: inset 2px 0 0 #DCDCD8; }

.pill {
  border: 0; padding: 0; background: none !important;
  font-size: 12px; font-weight: 500; gap: 7px; color: #7A7B7E;
}
.pill::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; font-size: 0; }
.pill.good     { color: #6B6C6F; }
.pill.good::before { background: var(--good); }
.pill.warn     { color: #7A7B7E; }
.pill.warn::before { background: #C9A227; }
.pill.serious, .pill.critical { color: var(--critical); font-weight: 600; }
.pill.neutral  { color: #A6A6A1; }
.pill.brand    { color: var(--blue-deep); }
.tag { border-radius: 5px; padding: 2px 6px; font-size: 11px; border-color: var(--hair); }

.alert { box-shadow: inset 2px 0 0 currentColor; border-color: transparent; }
.timeline .dot { width: 24px; height: 24px; box-shadow: 0 0 0 4px #fff; }
.timeline .step::before { top: 15px; }
.po-card { border-radius: 10px; border-color: var(--hair); box-shadow: none; }
.po-card .po-head { background: #FCFCFB; border-bottom-color: var(--hair); }
.kv dt { color: #A6A6A1; }
.mock-note { font-size: 12px; color: #B4B4AF; font-style: normal; }

/* ---------- 7.11 Toast ---------- */
.toast {
  position: fixed; right: 22px; bottom: 22px; z-index: 100;
  width: min(340px, calc(100vw - 32px));
  display: flex; align-items: flex-start; gap: 11px; padding: 13px 15px;
  border: 1px solid var(--hair); border-radius: 12px;
  color: var(--navy); background: #fff; box-shadow: var(--shadow-pop);
  opacity: 0; visibility: hidden; transform: translateY(8px);
  transition: opacity .18s, visibility .18s, transform .22s var(--ease);
}
.toast.show { opacity: 1; visibility: visible; transform: translateY(0); }
.toast-mark {
  width: 20px; height: 20px; flex: 0 0 20px; display: grid; place-items: center;
  border-radius: 6px; color: #fff; background: var(--navy); font-size: 11px; font-weight: 700;
}
.toast b { display: block; font-size: 12.5px; font-weight: 650; }
.toast span { display: block; margin-top: 3px; color: #7A7B7E; font-size: 11.5px; line-height: 1.5; }

/* ---------- 7.12 Responsive ---------- */
@media (max-width: 1400px) {
  .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .journey { padding-inline: 18px; }
  .journey-rail { left: calc(18px + (100% - 36px) / 14); right: calc(18px + (100% - 36px) / 14); }
  }

@media (max-width: 1240px) {
  /* three columns squeeze the chart card until its head wraps — go to two */
  .cols-3, .cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gauges { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .board { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gauge:nth-child(3n + 1) { border-left: 0; }
  .gauge:nth-child(n + 4) { border-top: 1px solid var(--hair); padding-top: 18px; }
}

@media (max-width: 1180px) {
  /* keep the toolbar on one line rather than orphaning the export button */
  .toolbar { gap: 12px; }
  .toolbar .when { font-size: 13px; }
  .topbar { gap: 10px; padding-inline: 20px; }
  .search { width: 200px; }
  .topbar select { max-width: 140px; }
  .content { padding-inline: 22px; }
  .bars .row { grid-template-columns: 142px 1fr 46px; }
}

@media (max-width: 960px) {
  .sidebar {
    position: fixed; left: 0; transform: translateX(-105%);
    transition: transform .24s var(--ease);
    box-shadow: 16px 0 44px rgba(19, 25, 33, .12);
  }
  body.nav-open { overflow: hidden; }
  body.nav-open .sidebar { transform: translateX(0); }
  .nav-overlay {
    position: fixed; inset: 0; z-index: 35; display: block; border: 0;
    background: rgba(19, 25, 33, .32);
    opacity: 0; visibility: hidden; transition: opacity .2s, visibility .2s;
  }
  body.nav-open .nav-overlay { opacity: 1; visibility: visible; }
  .menu-toggle { display: grid; flex: 0 0 34px; }
  .topbar-title { min-width: 100px; }
  .topbar select { display: none; }
  .search { margin-left: auto; }
}

@media (max-width: 720px) {
  body { font-size: 14px; }
  /* On phones the same journey turns into a vertical route; nothing shrinks
     into illegibility and every stage remains a comfortable link target. */
  .journey {
    grid-template-columns: minmax(0, 1fr); padding: 8px 17px 4px;
  }
  .journey-rail {
    top: 30px; bottom: 30px; left: 34px; right: auto; width: 1px; height: auto;
  }
  .journey-stage {
    grid-template: "node count branch" 22px "node name branch" 18px / 34px minmax(0, 1fr) minmax(118px, .9fr);
    gap: 0 13px; min-height: 66px; padding: 10px 0; text-align: left;
    justify-items: stretch; align-items: center;
  }
  .journey-count { grid-area: count; align-self: end; font-size: 17px; }
  .journey-node { grid-area: node; align-self: center; }
  .journey-name { grid-area: name; align-self: start; white-space: normal; }
  .journey-branch {
    grid-area: branch; align-self: center;
    margin: 0; padding: 2px 0 2px 13px; border-left: 1px solid var(--hair);
  }
  .journey-branch::before, .journey-branch::after { content: none; }
  .journey-live { white-space: normal; }
      .topbar { min-height: 56px; flex-wrap: wrap; padding: 9px 16px; }
  .topbar-title { flex: 1; }
  .topbar h1 { font-size: 17px; }
  .search { order: 5; width: 100%; }
  .search-kbd, .avatar > span { display: none; }
  .content { padding: 20px 16px 52px; gap: 18px; }
  .grid, .cols-2, .cols-3, .cols-4 { grid-template-columns: minmax(0, 1fr) !important; }
  .span-2, .span-full { grid-column: auto; }
  .kpis, .kpis[style] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 13px; }
  .kpi .value { font-size: 24px; }
  .kpi-ic svg.ic { width: 17px; height: 17px; }
  .toolbar { gap: 12px; }
  .toolbar .spacer { display: none; }
  .seg { width: 100%; }
  .seg button { flex: 1; }
  .page-head { align-items: stretch; }
  .page-head .crumb { width: 100%; margin-bottom: 2px; }
  .page-head .spacer { display: none; }
  .page-head .btn { flex: 1 1 auto; }
  .filters { align-items: stretch; }
  .filters select, .filters input { flex: 1 1 145px; min-width: 0; }
  .mock-note { flex-basis: 100%; margin-left: 0 !important; }
  /* the head wraps here, so the leading separator would start a line */
  .card .card-head { padding: 17px 17px 13px; flex-wrap: wrap; }
  .card .card-head .sub::before { content: none; }
  .card .card-body { padding: 4px 17px 18px; }
  table.data th, table.data td { padding-inline: 17px; }
  .po-card .po-body { grid-template-columns: 1fr 1fr; }
  .timeline { min-width: 560px; }
  .timeline + * { min-width: 0; }
  .bars .row { grid-template-columns: minmax(96px, 1fr) minmax(70px, 1.3fr) 38px; gap: 10px; }
}

@media (max-width: 440px) {
  .bell { display: none; }
  /* two columns still beats one here — the trend line is what gives way,
     not the number or the exception note under it */
  .kpis, .kpis[style] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 11px; }
  .kpi .value { font-size: 22px; }
  .kpi .delta { font-size: 11.5px; }
  .toolbar { gap: 10px 14px; }
  .toolbar .when { flex-basis: 100%; }
  .seg { width: auto; margin-right: auto; }
  .seg button { flex: 0 0 auto; padding-inline: 9px; }
  .tabs { padding-inline: 10px; }
  .tabs button { padding-inline: 10px; }
  .po-card .po-body, .kv { grid-template-columns: 1fr; }
  .toast { right: 14px; bottom: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    scroll-behavior: auto !important;
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* ============================================================
   8. Order detail
   One order reads as one operational story: health, fulfilment,
   purchase attempts, then the context that needs a decision.
   Scoped to this route so the shared v3 system remains stable.
   ============================================================ */
body[data-view="order-detail"] .content { gap: 20px; }
body[data-view="order-detail"] .card { overflow: visible; }

.od-toolbar {
  min-height: 34px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.od-toolbar .spacer { flex: 1; }
.od-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: #56575A;
  font-size: 13px;
  font-weight: 600;
}
.od-back:hover { color: var(--navy); }
.od-back span { color: #A6A6A1; font-size: 17px; line-height: 1; }
.od-toolbar-rule { width: 1px; height: 17px; margin: 0 4px; background: var(--hair); }
.od-sync {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: #A6A6A1;
  font-size: 12px;
}
.od-sync > span { width: 5px; height: 5px; border-radius: 50%; background: var(--good); }

.od-eyebrow {
  display: block;
  margin-bottom: 6px;
  color: #A6A6A1;
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: 1.2px;
  line-height: 1;
  text-transform: uppercase;
}

.od-hero {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(280px, .58fr);
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--hair);
  border-radius: 16px;
}
.od-identity { padding: 28px 30px 25px; }
.od-title-row { display: flex; align-items: center; gap: 9px; }
.od-title-row h1 {
  color: var(--navy);
  font-size: clamp(25px, 2.3vw, 34px);
  font-weight: 620;
  letter-spacing: -.8px;
  line-height: 1.15;
}
.od-copy {
  width: 29px;
  height: 29px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: #B4B4AF;
  cursor: pointer;
}
.od-copy:hover { background: var(--hair-soft); color: var(--navy); }
.od-copy svg.ic { width: 14px; height: 14px; }
.od-state-line {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 11px;
  color: #7A7B7E;
  font-size: 12.5px;
  font-weight: 500;
}
.od-separator { width: 1px; height: 13px; background: var(--hair); }
.od-state {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: #7A7B7E;
  font-size: 12px;
  font-weight: 550;
  white-space: nowrap;
}
.od-state > span {
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: #C8C8C3;
}
.od-state.active { color: var(--blue-deep); }
.od-state.active > span { background: var(--series); box-shadow: 0 0 0 3px rgba(43,124,216,.09); }
.od-state.on-track > span { background: var(--good); }
.od-state.failed { color: var(--critical); }
.od-state.failed > span { background: var(--critical); }

.od-product {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 23px;
  padding-top: 20px;
  border-top: 1px solid var(--hair-soft);
}
.od-product-art {
  width: 38px;
  height: 38px;
  flex: 0 0 38px;
  display: grid;
  place-items: center;
  border: 1px solid var(--hair);
  border-radius: 10px;
  color: #A6A6A1;
}
.od-product-art svg.ic { width: 17px; height: 17px; }
.od-product strong { display: block; color: var(--navy); font-size: 13.5px; font-weight: 620; }
.od-product div span { display: block; margin-top: 4px; color: #A6A6A1; font-size: 11.5px; }

.od-health {
  padding: 28px 28px 25px;
  border-left: 1px solid var(--hair);
}
.od-health-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.od-health-days { display: flex; align-items: baseline; gap: 9px; margin-top: 15px; }
.od-health-days strong {
  color: var(--navy);
  font-size: 34px;
  font-weight: 600;
  letter-spacing: -.8px;
  line-height: 1;
}
.od-health-days > span { color: #7A7B7E; font-size: 12px; }
.od-progress { height: 3px; margin: 17px 0 19px; overflow: hidden; border-radius: 99px; background: var(--track); }
.od-progress span { display: block; height: 100%; border-radius: inherit; background: var(--series); }
.od-health dl { display: grid; gap: 10px; }
.od-health dl div { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.od-health dt { color: #A6A6A1; font-size: 11.5px; }
.od-health dd { color: #56575A; font-size: 12px; font-weight: 600; }

.od-summary {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 1.08fr .75fr .78fr .72fr 1.35fr;
  border-top: 1px solid var(--hair);
}
.od-summary > div { min-width: 0; padding: 17px 24px 18px; border-left: 1px solid var(--hair-soft); }
.od-summary > div:first-child { border-left: 0; }
.od-summary span,
.od-summary small { display: block; color: #A6A6A1; font-size: 10.5px; }
.od-summary span { margin-bottom: 7px; font-weight: 600; letter-spacing: .25px; }
.od-summary strong {
  display: block;
  overflow: hidden;
  color: var(--navy);
  font-size: 13px;
  font-weight: 620;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.od-summary small { margin-top: 4px; }

.od-section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  padding: 21px 22px 17px;
}
.od-section-head h2 { color: var(--navy); font-size: 15px; font-weight: 630; letter-spacing: -.1px; }
.od-section-head .od-eyebrow { margin-bottom: 5px; }
.od-section-meta,
.od-route-label { color: #A6A6A1; font-size: 11.5px; }
.od-section-head > a { color: #7A7B7E; font-size: 11.5px; font-weight: 600; }
.od-section-head > a:hover { color: var(--navy); }
.od-count {
  min-width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 1px solid var(--hair);
  border-radius: 99px;
  color: #7A7B7E;
  font-size: 10.5px;
  font-weight: 650;
}

.od-journey { padding-bottom: 6px; }
.od-steps {
  position: relative;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  margin: 0;
  padding: 14px 27px 20px;
  list-style: none;
}
.od-steps::before {
  content: "";
  position: absolute;
  top: 30px;
  left: calc(27px + (100% - 54px) / 14);
  right: calc(27px + (100% - 54px) / 14);
  height: 1px;
  background: var(--hair);
}
.od-steps li {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: center;
  gap: 10px;
  text-align: center;
}
.od-step-node {
  width: 33px;
  height: 33px;
  display: grid;
  place-items: center;
  border: 1px solid var(--hair);
  border-radius: 50%;
  color: #B4B4AF;
  background: #fff;
}
.od-step-node svg.ic { width: 14px; height: 14px; stroke-width: 1.8; }
.od-steps li.done .od-step-node { color: #7A7B7E; border-color: #DCDCD8; }
.od-steps li.current .od-step-node {
  color: var(--series);
  border-color: var(--series);
  box-shadow: 0 0 0 4px rgba(43,124,216,.07);
}
.od-step-copy strong { display: block; color: #7A7B7E; font-size: 11.5px; font-weight: 600; white-space: nowrap; }
.od-step-copy small { display: block; margin-top: 4px; color: #B4B4AF; font-size: 10.5px; white-space: nowrap; }
.od-steps li.current .od-step-copy strong { color: var(--blue-deep); }

.od-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.85fr) minmax(320px, .72fr);
  gap: 20px;
  align-items: start;
}
.od-primary,
.od-secondary { display: grid; gap: 20px; min-width: 0; }

.od-detail-groups {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid var(--hair);
}
.od-detail-group { min-width: 0; padding: 20px 22px 22px; border-left: 1px solid var(--hair-soft); }
.od-detail-group:first-child { border-left: 0; }
.od-detail-group h3 {
  margin-bottom: 17px;
  color: #7A7B7E;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .45px;
  text-transform: uppercase;
}
.od-detail-group dl { display: grid; gap: 12px; }
.od-detail-group dl div { display: grid; grid-template-columns: minmax(92px, .8fr) minmax(0, 1.25fr); gap: 12px; }
.od-detail-group dt { color: #A6A6A1; font-size: 11.5px; }
.od-detail-group dd {
  overflow: hidden;
  color: #56575A;
  font-size: 11.5px;
  font-weight: 550;
  text-align: right;
  text-overflow: ellipsis;
}

.od-attempts { padding: 2px 22px 5px; border-top: 1px solid var(--hair); }
.od-attempt {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  gap: 16px;
  padding: 22px 0;
  border-bottom: 1px solid var(--hair-soft);
}
.od-attempt:last-child { border-bottom: 0; }
.od-attempt-rail { position: relative; display: flex; justify-content: center; }
.od-attempt-rail > span {
  position: relative;
  z-index: 1;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border: 1px solid var(--hair);
  border-radius: 50%;
  color: #A6A6A1;
  background: #fff;
  font-size: 9.5px;
  font-weight: 650;
}
.od-attempt.current .od-attempt-rail > span { color: var(--blue-deep); border-color: var(--series); }
.od-attempt.failed .od-attempt-rail > span { color: var(--critical); border-color: #EDC7C6; }
.od-attempt-rail i { position: absolute; top: 28px; bottom: -23px; width: 1px; background: var(--hair); }
.od-attempt-main header { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; }
.od-attempt-main header > div { min-width: 0; }
.od-po { color: var(--navy); font-size: 13.5px; font-weight: 650; }
.od-po:hover { text-decoration: underline; text-underline-offset: 3px; }
.od-attempt-main header > div > span { margin-left: 8px; color: #A6A6A1; font-size: 11.5px; }
.od-attempt-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 18px;
  margin-top: 18px;
}
.od-attempt-grid > div { min-width: 0; }
.od-attempt-grid span,
.od-attempt-grid strong,
.od-attempt-grid small { display: block; }
.od-attempt-grid span { margin-bottom: 6px; color: #A6A6A1; font-size: 10.5px; }
.od-attempt-grid strong {
  overflow: hidden;
  color: #56575A;
  font-size: 11.5px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.od-attempt-grid small { margin-top: 4px; color: #B4B4AF; font-size: 10.5px; line-height: 1.4; }
.od-attempt-foot {
  display: flex;
  align-items: center;
  gap: 12px 22px;
  flex-wrap: wrap;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--hair-soft);
  color: #7A7B7E;
  font-size: 11px;
}
.od-attempt-foot b { color: #56575A; font-weight: 620; }
.od-attempt-foot a { margin-left: auto; color: #56575A; font-weight: 600; }
.od-attempt-foot a:hover { color: var(--navy); }
.od-archive-note {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0 22px 22px;
  padding-top: 15px;
  border-top: 1px solid var(--hair);
  color: #A6A6A1;
}
.od-archive-note svg.ic { width: 14px; height: 14px; margin-top: 1px; }
.od-archive-note p { font-size: 10.5px; line-height: 1.55; }

.od-secondary .od-section-head { padding-bottom: 16px; }
.od-focus-list { padding: 0 22px 20px; }
.od-focus-item {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: 12px;
  padding: 16px 0;
  border-top: 1px solid var(--hair-soft);
}
.od-focus-item:first-child { border-top-color: var(--hair); }
.od-focus-icon {
  width: 31px;
  height: 31px;
  display: grid;
  place-items: center;
  border: 1px solid var(--hair);
  border-radius: 9px;
  color: #A6A6A1;
}
.od-focus-icon svg.ic { width: 14px; height: 14px; }
.od-focus-icon.critical { color: var(--critical); border-color: #EDC7C6; }
.od-focus-item strong { color: var(--navy); font-size: 11.5px; font-weight: 620; }
.od-focus-item p { margin-top: 5px; color: #7A7B7E; font-size: 10.5px; line-height: 1.55; }
.od-focus-item a { display: inline-block; margin-top: 8px; color: #56575A; font-size: 10.5px; font-weight: 600; }
.od-focus-item a:hover { color: var(--navy); }

.od-route-map { padding: 0 22px 21px; }
.od-route-map > div {
  position: relative;
  display: grid;
  grid-template-columns: 31px minmax(0, 1fr);
  gap: 12px;
  min-height: 54px;
}
.od-route-map > div::before {
  content: "";
  position: absolute;
  top: 29px;
  bottom: 0;
  left: 15px;
  width: 1px;
  background: var(--hair);
}
.od-route-map > div:last-child::before { display: none; }
.od-route-map > div > span {
  width: 31px;
  height: 31px;
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  border: 1px solid var(--hair);
  border-radius: 50%;
  color: #B4B4AF;
  background: #fff;
}
.od-route-map > div > span svg.ic { width: 13px; height: 13px; }
.od-route-map > div.complete > span { color: #7A7B7E; border-color: #DCDCD8; }
.od-route-map > div.current > span { color: var(--series); border-color: var(--series); }
.od-route-map strong,
.od-route-map small { display: block; }
.od-route-map strong { padding-top: 1px; color: #56575A; font-size: 11.5px; font-weight: 600; }
.od-route-map small { margin-top: 4px; color: #A6A6A1; font-size: 10.5px; }

.od-econ dl { padding: 0 22px; }
.od-econ dl div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 0;
  border-top: 1px solid var(--hair-soft);
}
.od-econ dl div:first-child { border-top-color: var(--hair); }
.od-econ dt { display: flex; align-items: center; gap: 7px; color: #A6A6A1; font-size: 11px; }
.od-econ dd { color: #56575A; font-size: 11.5px; font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }
.od-econ .od-dot { width: 5px; height: 5px; border-radius: 50%; background: #C8C8C3; }
.od-econ .pending dt,
.od-econ .pending dd { color: #A6A6A1; }
.od-econ .total { border-top: 1px solid var(--hair); }
.od-econ .total dt { color: #56575A; font-weight: 620; }
.od-econ .total dd { color: var(--navy); font-size: 12.5px; font-weight: 650; }
.od-econ-note { margin: 8px 22px 20px; color: #A6A6A1; font-size: 10.5px; line-height: 1.55; }

.od-activity ol { margin: 0; padding: 0 22px 18px; list-style: none; }
.od-primary .od-activity ol {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 44px;
}
.od-primary .od-activity li:nth-child(2) { border-top-color: var(--hair); }
@media (max-width: 840px) {
  .od-primary .od-activity ol { grid-template-columns: minmax(0, 1fr); }
  .od-primary .od-activity li:nth-child(2) { border-top-color: var(--hair-soft); }
}
.od-activity li {
  position: relative;
  display: grid;
  grid-template-columns: 87px minmax(0, 1fr);
  gap: 15px;
  padding: 11px 0 11px 15px;
  border-top: 1px solid var(--hair-soft);
}
.od-activity li:first-child { border-top-color: var(--hair); }
.od-activity li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 17px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #C8C8C3;
}
.od-activity time { color: #A6A6A1; font-size: 10px; white-space: nowrap; }
.od-activity strong,
.od-activity li span { display: block; }
.od-activity strong { color: #56575A; font-size: 10.5px; font-weight: 600; }
.od-activity li span { margin-top: 3px; color: #B4B4AF; font-size: 10px; line-height: 1.4; }

@media (max-width: 1360px) {
  .od-layout { grid-template-columns: minmax(0, 1.6fr) minmax(300px, .72fr); }
  .od-attempt-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 1120px) {
  .od-hero { grid-template-columns: minmax(0, 1fr) minmax(260px, .55fr); }
  .od-summary { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .od-summary > div:nth-child(4) { border-left: 0; border-top: 1px solid var(--hair-soft); }
  .od-summary > div:nth-child(5) { grid-column: span 2; border-top: 1px solid var(--hair-soft); }
  .od-layout { grid-template-columns: minmax(0, 1fr); }
  .od-secondary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .od-activity { grid-column: 1 / -1; }
}

@media (max-width: 840px) {
  .od-toolbar-rule,
  .od-sync { display: none; }
  .od-hero { grid-template-columns: minmax(0, 1fr); }
  .od-health { border-top: 1px solid var(--hair); border-left: 0; }
  .od-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .od-summary > div { border-top: 1px solid var(--hair-soft); }
  .od-summary > div:nth-child(odd) { border-left: 0; }
  .od-summary > div:nth-child(5) { grid-column: 1 / -1; }
  .od-journey { overflow: hidden !important; }
  .od-steps {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    padding: 4px 22px 19px;
  }
  .od-steps::before {
    top: 20px;
    bottom: 35px;
    left: 38px;
    right: auto;
    width: 1px;
    height: auto;
  }
  .od-steps li {
    grid-template-columns: 33px minmax(0, 1fr);
    justify-items: start;
    gap: 13px;
    padding: 8px 0;
    text-align: left;
  }
  .od-step-copy { align-self: center; }
  .od-step-copy strong,
  .od-step-copy small { white-space: normal; }
  .od-detail-groups { grid-template-columns: minmax(0, 1fr); }
  .od-detail-group { border-top: 1px solid var(--hair-soft); border-left: 0; }
  .od-secondary { grid-template-columns: minmax(0, 1fr); }
  .od-activity { grid-column: auto; }
}

@media (max-width: 560px) {
  .od-toolbar .spacer { display: none; }
  .od-toolbar .od-back { width: 100%; margin-bottom: 3px; }
  .od-toolbar .btn { flex: 1 1 auto; }
  .od-identity,
  .od-health { padding: 23px 20px 21px; }
  .od-title-row h1 { font-size: 23px; letter-spacing: -.4px; }
  .od-state-line { align-items: flex-start; }
  .od-separator { display: none; }
  .od-state-line > * { flex-basis: 100%; }
  .od-summary { grid-template-columns: minmax(0, 1fr); }
  .od-summary > div,
  .od-summary > div:nth-child(4) { border-top: 1px solid var(--hair-soft); border-left: 0; }
  .od-summary > div:nth-child(5) { grid-column: auto; }
  .od-section-head { align-items: flex-start; flex-wrap: wrap; padding-inline: 18px; }
  .od-route-label,
  .od-section-meta { flex-basis: 100%; }
  .od-attempts { padding-inline: 18px; }
  .od-attempt { grid-template-columns: 28px minmax(0, 1fr); gap: 12px; }
  .od-attempt-main header { display: grid; }
  .od-attempt-main header > div > span { display: block; margin: 4px 0 0; }
  .od-attempt-grid { grid-template-columns: minmax(0, 1fr); gap: 13px; }
  .od-attempt-foot { align-items: flex-start; }
  .od-attempt-foot > * { flex-basis: 100%; margin-left: 0 !important; }
  .od-archive-note { margin-inline: 18px; }
  .od-detail-group,
  .od-focus-list,
  .od-route-map,
  .od-econ dl,
  .od-activity ol { padding-inline: 18px; }
  .od-activity li { grid-template-columns: minmax(0, 1fr); gap: 5px; }
}

/* ============================================================
   8. Orders workspace — 2026-07-26
   ------------------------------------------------------------
   Extends §7 rather than bending it: one data hue for the
   window ramp (a sequential blue, since "how soon" is ordered),
   red only where a deadline has actually passed, orange only on
   the active filter — the same treatment the tabs already use.
   ============================================================ */

/* ---------- 8.1 Purchase-window rail ---------- */
.window-rail { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); }
.wcell {
  display: block; padding: 16px 20px 17px; text-align: left; cursor: pointer;
  font: inherit; color: inherit; background: none;
  border: 0; border-left: 1px solid var(--hair);
  transition: background .15s, box-shadow .15s;
}
.wcell:first-child { border-left: 0; }
.wcell:hover { background: #FCFCFB; }
.wcell.active { box-shadow: inset 0 -2px 0 var(--orange); }
.w-label {
  display: block; color: var(--navy);
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.15px; text-transform: uppercase;
}
.w-val {
  display: block; margin-top: 11px; color: var(--navy);
  font-size: 27px; font-weight: 600; line-height: 1; letter-spacing: -.9px;
  font-variant-numeric: tabular-nums;
}
.w-val.breach { color: var(--critical); }
.w-sub { display: block; margin-top: 6px; color: #A6A6A1; font-size: 11.5px; font-weight: 500; }
.w-track {
  display: block; height: 3px; margin-top: 13px;
  border-radius: 99px; background: var(--track); overflow: hidden;
}
.w-track i { display: block; height: 100%; border-radius: 99px; }

/* ---------- 8.2 Filter row ---------- */
.fsearch {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 31px; padding: 0 13px; width: 268px;
  border: 1px solid var(--hair); border-radius: 99px;
  background: var(--surface); color: #B4B4AF;
  transition: border-color .15s, box-shadow .15s;
}
.fsearch:focus-within { border-color: var(--blue); box-shadow: var(--shadow-focus); }
.fsearch svg.ic { width: 14px; height: 14px; }
.fsearch input {
  width: 100%; border: 0; outline: 0; background: none;
  font: inherit; font-size: 12.5px; font-weight: 500; color: var(--ink);
}
.fsearch input::placeholder { color: #B4B4AF; }
.fsearch input::-webkit-search-cancel-button { cursor: pointer; }

/* ---------- 8.3 Scope + selection bars ---------- */
.scoped, .selbar {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 20px; border-bottom: 1px solid var(--hair);
  font-size: 12.5px; font-weight: 500; color: #7A7B7E;
}
.scoped { background: #FBFBFA; }
.scoped b { color: var(--navy); font-weight: 650; }
.selbar { background: #FBFBFA; }
.selbar > b { color: var(--navy); font-size: 13px; font-weight: 650; margin-right: 4px; }

/* ---------- 8.4 Order table ---------- */
table.data.otable { min-width: 1060px; }
/* 13px gutters rather than §7's 20px: these views carry up to nine columns and
   have to stay inside the card at 1600px before the wrap starts scrolling */
table.data.otable th, table.data.otable td { padding: 11px 13px; }
table.data.otable td { height: auto; }
table.data.otable tr.is-open td { background: #FBFBFA; border-bottom-color: transparent; }
table.data.otable tr.is-sel td { background: #FAFBFD; }
th.o-sel, td.o-sel { width: 34px; padding-right: 0; }
td.o-sel input, th.o-sel input { width: 14px; height: 14px; cursor: pointer; }

.o-id { display: block; }
.o-id a { font-size: 13px; font-weight: 600; color: var(--navy); }
.o-id a:hover { color: var(--orange); }
.o-meta {
  display: flex; align-items: center; gap: 8px; margin-top: 4px;
  color: #B4B4AF; font-size: 11px; font-weight: 500;
}
.o-mod {
  padding: 1px 5px; border: 1px solid var(--hair); border-radius: 4px;
  color: #7A7B7E; font-size: 9.5px; font-weight: 700; letter-spacing: .7px;
}

.o-mp { display: flex; align-items: center; gap: 10px; }
.o-mp .mk { width: 26px; height: 26px; flex: 0 0 26px; }
.o-mp .mk-mark { width: 26px; height: 26px; font-size: 14px; }
.o-mp .mk .flag { width: 13px; height: 13px; flex: 0 0 13px; right: -2px; bottom: -2px; }
.o-mp-name { min-width: 0; }
.o-mp-name b { display: block; color: var(--ink); font-size: 12.5px; font-weight: 600; }
.o-mp-name span { display: block; margin-top: 2px; color: #B4B4AF; font-size: 11px; font-weight: 500; }

.o-item { display: block; }
.o-item b { display: block; color: var(--ink); font-size: 12.5px; font-weight: 600; }
.o-item span { display: block; margin-top: 3px; color: #ADADA8; font-size: 11.5px; font-weight: 500; font-variant-numeric: tabular-nums; }

.o-src { display: inline-flex; align-items: center; gap: 8px; }
.o-src .flag { width: 17px; height: 17px; flex: 0 0 17px; }
.o-route { display: flex; align-items: center; gap: 9px; }
.o-arrow { color: var(--ink); font-size: 12.5px; font-weight: 500; }
.o-rt b { display: block; color: var(--ink); font-size: 12.5px; font-weight: 500; }
.o-rt > span { display: block; margin-top: 3px; color: #ADADA8; font-size: 11px; font-weight: 500; }
.o-stage { display: block; }
.o-loc { display: block; color: var(--ink); font-size: 12.5px; font-weight: 500; }
.o-loc span { display: block; margin-top: 3px; color: #ADADA8; font-size: 11px; font-weight: 500; }
.o-over { color: var(--critical); font-weight: 650; }
.o-sync { color: var(--blue-deep); font-size: 12px; font-weight: 500; }
.o-why {
  display: block; max-width: 300px; white-space: normal;
  color: #7A7B7E; font-size: 11.5px; font-weight: 500; line-height: 1.5;
}

/* the clock that currently governs the row — map-by SLA before mapping,
   purchase window before buying, customer EDD after */
.dl { display: block; min-width: 148px; }
.dl-top { display: flex; align-items: baseline; gap: 10px; }
.dl-k { color: #ADADA8; font-size: 9.5px; font-weight: 700; letter-spacing: .95px; text-transform: uppercase; }
.dl-v { margin-left: auto; color: var(--navy); font-size: 12.5px; font-weight: 650; font-variant-numeric: tabular-nums; }
.dl-track { display: block; height: 3px; margin-top: 8px; border-radius: 99px; background: var(--track); overflow: hidden; }
.dl-track i { display: block; height: 100%; border-radius: 99px; background: var(--series); }
.dl-note { display: block; margin-top: 6px; color: #A6A6A1; font-size: 11px; font-weight: 500; }
.dl.warn .dl-track i { background: #C9A227; }
.dl.breach .dl-track i { background: var(--critical); }
.dl.breach .dl-v, .dl.breach .dl-note { color: var(--critical); font-weight: 600; }

.chev {
  width: 26px; height: 26px; display: grid; place-items: center;
  border: 0; border-radius: 7px; background: none; color: #C2C2BD; cursor: pointer;
  transition: color .15s, background .15s, transform .18s var(--ease);
}
.chev:hover { color: var(--navy); background: #F3F3F0; }
.chev.open { transform: rotate(180deg); color: var(--navy); }
.chev svg.ic { width: 15px; height: 15px; }

/* ---------- 8.5 Row peek ---------- */
/* the peek is prose and stacked fields, so it has to escape the table's nowrap */
tr.peek-row > td { padding: 0; background: #FBFBFA; white-space: normal; }
tr.peek-row:hover > td { background: #FBFBFA; }
.peek {
  display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: 34px; padding: 6px 22px 26px;
}
.peek .sub-head { margin-bottom: 14px; }
.peek-scroll { overflow-x: auto; padding-bottom: 4px; }
.peek-scroll .timeline { min-width: 620px; }
.peek .timeline .dot { box-shadow: 0 0 0 4px #FBFBFA; }
.peek .po-card { background: var(--surface); }
.peek .po-card .po-head { background: #FCFCFB; font-size: 13px; }
.peek .po-card .po-head b { color: var(--navy); font-weight: 650; font-variant-numeric: tabular-nums; }
.peek .po-card .po-body { font-size: 12.5px; }
.qc-fail { color: var(--critical); font-weight: 600; }
.peek .kv { grid-template-columns: 134px 1fr; gap: 8px 14px; font-size: 12.5px; }
.peek .kv dt { font-size: 12px; font-weight: 500; }
.peek-note { color: #7A7B7E; font-size: 12.5px; font-weight: 500; line-height: 1.65; }
.peek-none {
  padding: 14px 16px; border: 1px dashed var(--line-strong); border-radius: 10px;
  color: #A6A6A1; font-size: 12.5px; font-weight: 500;
}

/* ---------- 8.6 Table foot + empty ---------- */
.tfoot {
  display: flex; align-items: center; gap: 14px;
  padding: 13px 20px; border-top: 1px solid var(--hair);
  color: #A6A6A1; font-size: 11.5px; font-weight: 500;
}
.tfoot .mock-note b { color: #7A7B7E; font-weight: 650; }
.tfoot-sort { color: #B4B4AF; }
.o-empty { display: grid; justify-items: center; gap: 5px; padding: 54px 20px; text-align: center; }
.o-empty svg.ic { width: 20px; height: 20px; color: #D2D4D7; margin-bottom: 6px; }
.o-empty b { color: var(--navy); font-size: 13.5px; font-weight: 650; }
.o-empty span { color: #A6A6A1; font-size: 12.5px; font-weight: 500; }

/* ---------- 8.7 Responsive ---------- */
@media (max-width: 1240px) {
  .window-rail { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .wcell:nth-child(3n + 1) { border-left: 0; }
  .wcell:nth-child(n + 4) { border-top: 1px solid var(--hair); }
  .peek { grid-template-columns: minmax(0, 1fr); gap: 24px; }
}
@media (max-width: 720px) {
  .window-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .wcell:nth-child(3n + 1) { border-left: 1px solid var(--hair); }
  .wcell:nth-child(odd) { border-left: 0; }
  .wcell:nth-child(n + 3) { border-top: 1px solid var(--hair); }
  /* "closes tomorrow" wraps at this width — reserve the second line so the
     figures and bars stay on a common baseline across the pair */
  .w-label { min-height: 26px; }
  .w-val { font-size: 23px; }
  .fsearch { width: 100%; }
  .selbar, .scoped { flex-wrap: wrap; }
  .peek { padding-inline: 17px; }
}

/* ============================================================
   9. Purchase workbench — 2026-07-26 (v2, data-driven)
   ------------------------------------------------------------
   The buying decision desk. Same discipline as §8: one dataset,
   five views, every row computes its own urgency. Blue carries
   the decisions chart and the deadline meters; the categorical
   source hues appear once, on the committed-spend strip; red is
   only a tripped guard or a passed deadline.
   ============================================================ */

body[data-view="purchase"] .content { gap: 20px; }

/* ---------- 9.1 Committed-spend strip (under the chart) ---------- */
.spend { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--hair); }
.sp { min-width: 0; padding: 15px 22px 17px; border-left: 1px solid var(--hair); }
.sp:first-child { border-left: 0; }
.sp-top { display: flex; align-items: center; gap: 8px; }
.sp-top .flag { width: 15px; height: 15px; flex: 0 0 15px; }
.sp-top b {
  color: var(--navy); font-size: 10.5px; font-weight: 700;
  letter-spacing: 1.1px; text-transform: uppercase;
}
.sp-top span { color: #B4B4AF; font-size: 11px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-val {
  display: block; margin-top: 10px; color: var(--navy);
  font-size: 19px; font-weight: 600; letter-spacing: -.4px; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.sp-sub { display: block; margin-top: 6px; color: #A6A6A1; font-size: 11.5px; font-weight: 500; font-variant-numeric: tabular-nums; }
.sp-track { display: block; height: 3px; margin-top: 12px; border-radius: 99px; background: var(--track); overflow: hidden; }
.sp-track i { display: block; height: 100%; border-radius: 99px; }

/* ---------- 9.2 Held-for-review card ---------- */
.engine {
  display: flex; align-items: center; gap: 9px;
  margin-top: 20px; padding-top: 15px; border-top: 1px solid var(--hair);
  color: #A6A6A1; font-size: 11.5px; font-weight: 500;
}
.engine::before { content: ""; width: 6px; height: 6px; flex: 0 0 6px; border-radius: 50%; background: var(--good); }
.engine b { color: var(--ink-2); font-weight: 600; }

/* ---------- 9.3 Workbench cells ---------- */
/* best offer — source tag, then seller + availability */
.p-offer { display: flex; align-items: center; gap: 9px; }
.p-offer-t { min-width: 0; }
.p-offer-t b { display: block; color: var(--ink); font-size: 12.5px; font-weight: 600; }
.p-offer-t span { display: block; margin-top: 3px; color: #ADADA8; font-size: 11px; font-weight: 500; font-variant-numeric: tabular-nums; }

/* economics — the margin is the figure, the buy/sell pair is the working */
.econ b {
  display: block; color: var(--navy); font-size: 13.5px; font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.econ.neg b { color: var(--critical); }
.econ span { display: block; margin-top: 3px; color: #ADADA8; font-size: 11px; font-weight: 500; font-variant-numeric: tabular-nums; }

/* engine verdict — seven guard dots, then what the engine will do next */
.g-cell { display: block; min-width: 158px; }
.gd { display: inline-flex; gap: 4px; }
.gd i { width: 6px; height: 6px; border-radius: 50%; background: #C4D7EF; }
.gd i.fail { background: var(--critical); }
.g-note { display: block; margin-top: 7px; color: #A6A6A1; font-size: 11px; font-weight: 500; }
.g-cell.held .g-note { color: var(--ink-2); font-weight: 600; }

/* manual-review evidence — two lines, allowed to wrap */
.ev { display: block; max-width: 280px; white-space: normal; color: var(--ink); font-size: 12px; font-weight: 500; line-height: 1.45; }
.ev small { display: block; margin-top: 3px; color: #ADADA8; font-size: 11px; font-weight: 500; }

/* partial-quantity progress */
.qprog { display: block; min-width: 150px; }
.qprog b { color: var(--navy); font-size: 12.5px; font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; }
.qprog i { display: block; height: 3px; margin-top: 8px; border-radius: 99px; background: var(--track); overflow: hidden; }
.qprog i em { display: block; height: 100%; border-radius: 99px; background: var(--series); }

/* purchased-today PO cell */
.p-po b { display: block; color: var(--navy); font-size: 12.5px; font-weight: 650; font-variant-numeric: tabular-nums; }
.p-po span { display: block; margin-top: 3px; color: #ADADA8; font-size: 11px; font-weight: 500; }

/* ---------- 9.4 Responsive ---------- */
@media (max-width: 1240px) {
  .ev { max-width: 220px; }
}
@media (max-width: 720px) {
  .spend { grid-template-columns: minmax(0, 1fr); }
  .sp { border-left: 0; border-top: 1px solid var(--hair); }
  .sp:first-child { border-top: 0; }
}

/* ============================================================
   10. Tracking workspace — 2026-07-26
   ------------------------------------------------------------
   Reuses §8's table anatomy (.otable, .dl, .chev, .peek, .tfoot,
   .fsearch, .scoped) and §7.7's meters. Only what tracking adds
   is defined here: the route cell, the last-event cell with its
   silence flag, the scan history in the peek, and the corridor /
   carrier meter details.
   ============================================================ */

/* shipment id when the row is a consolidation, not a sales order */
.o-id .t-idb { display: block; color: var(--navy); font-size: 13px; font-weight: 600; }

/* route — two small flags and the leg, one line */
.t-route { display: flex; align-items: center; gap: 10px; }
.t-route .t-flags { display: flex; align-items: center; gap: 5px; flex: 0 0 auto; }
.t-route .flag { width: 17px; height: 17px; flex: 0 0 17px; }
.t-route .t-arr { color: #C2C2BD; font-size: 11px; font-weight: 500; }
.t-names { min-width: 0; }
.t-names b { display: block; color: var(--ink); font-size: 12.5px; font-weight: 500; white-space: nowrap; }
.t-names > span { display: block; margin-top: 3px; color: var(--ink); font-size: 12.5px; font-weight: 500; white-space: nowrap; }
.t-names > span i { font-style: normal; color: #C2C2BD; margin-right: 2px; }

/* last courier event + how it reached us; silence is the operational signal */
.t-ev { display: block; min-width: 160px; max-width: 205px; }
.t-ev b { display: block; color: var(--ink); font-size: 12.5px; font-weight: 500; white-space: normal; line-height: 1.4; }
.t-ev > span { display: block; margin-top: 3px; color: #ADADA8; font-size: 11px; font-weight: 500; font-variant-numeric: tabular-nums; }
.t-silent { color: var(--critical) !important; font-weight: 600 !important; }

/* scan history in the row peek */
.scans { list-style: none; margin: 0; padding: 2px 0 0; }
.scans li { position: relative; padding: 0 0 16px 24px; }
.scans li::before {
  content: ""; position: absolute; left: 4px; top: 4px;
  width: 7px; height: 7px; border-radius: 50%;
  background: #C4C6C2; box-shadow: 0 0 0 3px #FBFBFA;
}
.scans li:first-child::before { background: var(--series); }
.scans li::after {
  content: ""; position: absolute; left: 7px; top: 14px; bottom: 0;
  width: 1px; background: var(--hair);
}
.scans li:last-child { padding-bottom: 2px; }
.scans li:last-child::after { display: none; }
.scans .s-t { display: block; color: #ADADA8; font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; }
.scans .s-x { display: block; margin-top: 2px; color: var(--ink); font-size: 12.5px; font-weight: 500; }

/* corridor + carrier meters — names may carry flags, values may breach */
.meters .meter { min-width: 0; }
.meters .m-name.t-lane { display: inline-flex; align-items: center; gap: 7px; }
.meters .m-name .flag { width: 16px; height: 16px; flex: 0 0 16px; }
.meters .m-val.bad { color: var(--critical); }
.meter-sub .m-over { color: var(--critical); font-weight: 600; }

@media (max-width: 720px) {
  .t-ev { min-width: 150px; }
}

/* engine notes wrap rather than widening the table */
.g-cell { max-width: 170px; }
.g-cell .g-note { white-space: normal; line-height: 1.45; }
/* nine columns at 1600px — the deadline meter gives back what §8 allowed it */
body[data-view="purchase"] .dl { min-width: 128px; }
body[data-view="purchase"] table.data.otable th,
body[data-view="purchase"] table.data.otable td { padding: 11px; }

/* ============================================================
   11. QC workspace — 2026-07-26
   ------------------------------------------------------------
   Reuses §8/§10 anatomy (.window-rail, .otable, .dl, .fsearch,
   .pane-context, .meters, .tfoot). Defined here: the warehouse
   scope select, the inscan panel, the bench with its verdict
   buttons, and the filter-row note.
   ============================================================ */

/* context strip between a card's head and its table — §9 v1 had this;
   the v2 rewrite dropped it, so the QC bench owns it now */
.pane-context {
  display: flex; align-items: center; gap: 11px;
  min-height: 44px; padding: 10px 20px;
  border-top: 1px solid var(--hair); border-bottom: 1px solid var(--hair);
  background: #FBFBFA; color: #7A7B7E;
  font-size: 12px; font-weight: 500; line-height: 1.5;
}
.pane-context .context-ic {
  display: grid; place-items: center; width: 24px; height: 24px; flex: 0 0 24px;
  border: 1px solid var(--hair); border-radius: 8px; color: #8E8F92; background: #fff;
}
.pane-context .context-ic svg.ic { width: 13px; height: 13px; }
.pane-context b { color: var(--navy); font-weight: 650; }
.pane-context > span:not(.context-ic) { min-width: 0; }
.pane-context > a { margin-left: auto; color: #7A7B7E; font-size: 11.5px; white-space: nowrap; }
.pane-context > a:hover { color: var(--orange); }

/* warehouse scope — a toolbar control, styled like the ghost buttons */
.tool-select {
  font: inherit; font-size: 12.5px; font-weight: 600; color: #56575A;
  min-height: 27px; padding: 4px 12px; cursor: pointer;
  border: 1px solid var(--hair); border-radius: 99px; background: var(--surface);
  transition: border-color .15s, color .15s;
}
.tool-select:hover { border-color: #D9D9D4; color: var(--navy); }

/* inscan panel */
.inscan { display: grid; gap: 12px; }
.inscan .fsearch { width: 100%; min-height: 36px; }
.inscan .fsearch input { font-size: 13px; font-variant-numeric: tabular-nums; }
.inscan > .btn { justify-content: center; }
.inscan-alt { color: #A6A6A1; font-size: 11.5px; font-weight: 500; line-height: 1.6; }
.inscan-alt b { color: #7A7B7E; font-weight: 600; }
.inscan h4.sub-head { margin-top: 10px; padding-top: 14px; border-top: 1px solid var(--hair-soft); }
.inscan .kv { grid-template-columns: 138px 1fr; gap: 8px 14px; font-size: 12.5px; }
.inscan .kv dt { font-size: 12px; font-weight: 500; }

/* bench */
#bench .card-head h2 { flex-shrink: 0; white-space: nowrap; }
/* The head carries three things: the title, the inscan → inventory → QC trail
   and the SLA clock. h2 and .bench-due are both nowrap, and the .spacer takes
   flex:1, so the trail was the only item that could give — it collapsed to a
   75px column and wrapped six times, forcing a 140px-tall header. Give it a
   floor and let the head wrap, so it drops to its own line instead. */
#bench .card-head { flex-wrap: wrap; }
#bench .card-head .sub { flex: 1 1 auto; min-width: 230px; }
.bench-due { color: #7A7B7E; font-size: 12px; font-weight: 500; font-variant-numeric: tabular-nums; white-space: nowrap; }
.bench-due b { color: var(--critical); font-weight: 650; }
table.data.bench-table td { height: auto; vertical-align: middle; }
.bench-actions {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 14px 20px 18px;
}
.bench-actions .mock-note { margin-left: auto; }

/* verdict buttons — Good | Not Good | Damaged | Short Received */
.qmark { display: inline-flex; gap: 5px; }
.qmark .mark {
  font: inherit; font-size: 11.5px; font-weight: 600; color: #7A7B7E;
  padding: 4px 11px; border: 1px solid var(--hair); border-radius: 99px;
  background: none; cursor: pointer; white-space: nowrap;
  transition: border-color .15s, color .15s;
}
.qmark .mark:hover { border-color: #D9D9D4; color: var(--navy); }
.qmark .mark[aria-pressed="true"] { border-color: var(--good); color: var(--good); }
.qmark .mark.bad[aria-pressed="true"] { border-color: var(--critical); color: var(--critical); }

/* failure verdict inside a sub-line */
.q-verdict { color: var(--critical); font-weight: 600; }

/* note at the right end of a filter row */
.filters .feed-note { color: #A6A6A1; font-size: 11.5px; font-weight: 500; white-space: nowrap; }
.filters .feed-note b { color: #7A7B7E; font-weight: 600; }

@media (max-width: 1240px) {
  .bench-actions { padding-inline: 17px; }
  .bench-actions .mock-note { flex-basis: 100%; margin-left: 0; }
}

/* ============================================================
   11. Catalog, approvals & integrations — 2026-07-26
   ------------------------------------------------------------
   Three pages joined the deck to close PRD gaps, and between
   them they needed exactly three new components. Everything
   else is §5 tables, §7 pills and §8's .tfoot. Held to the
   one-hue rule: the listing chain uses greyscale for a dead
   hop and red only where the chain has actually run out.
   ============================================================ */

/* Fixed-vocabulary strings — a Master SKU pattern, a PO mask.
   Tabular figures, not a monospace face: the deck is Montserrat
   throughout and a second family would read as a bug. */
.mono { font-variant-numeric: tabular-nums; letter-spacing: .3px; }

/* Two decisions in one cell. td.actions only right-aligns, so
   without this the buttons collapse onto whitespace spacing. */
.row-actions { display: inline-flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }

/* ---------- 11.1 Listing chain (catalog → Listing health) ----------
   The offer we were buying, then where the purchase actually went.
   Stacked rather than side by side: laid out horizontally it wraps
   unpredictably inside a table cell, and a chain that sometimes
   reads across and sometimes down is worse than one that always
   reads down. A hop is a fact, not a magnitude — so no bar, just
   two nodes and the link between them. */
.chain { display: grid; justify-items: start; gap: 0; }
.ch-node {
  display: grid; gap: 2px;
  padding: 7px 11px; min-width: 148px;
  border: 1px solid var(--hair); border-radius: 9px;
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.ch-node i { font-style: normal; font-size: 10.5px; font-weight: 500; color: #9A9A96; letter-spacing: .2px; }
.ch-node.dead  { color: #9A9A96; background: var(--hair-soft); border-color: transparent; }
.ch-node.live  { color: var(--navy); border-color: var(--series-dim); }
.ch-node.live i { color: var(--series); }
.ch-node.empty { color: var(--critical-text); border-style: dashed; border-color: var(--critical); }

/* the connector: a hairline drop with the link glyph sitting on it */
.ch-arrow {
  display: grid; place-items: center;
  width: 148px; height: 20px; color: #C2C2BD; position: relative;
}
.ch-arrow::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 17px;
  border-left: 1px solid var(--hair);
}
.ch-arrow svg { width: 14px; height: 14px; position: relative; background: var(--surface); }

@media (max-width: 1240px) {
  .ch-node, .ch-arrow { min-width: 128px; width: auto; }
}

/* ---------- 11.2 Approvals table budget ----------
   Six columns and two decision buttons have to fit the 1296px
   inside the card at 1600px — the same budget §8 set for the
   orders table. §7.10's 20px gutters spend 240px on air, which
   pushes Approve/Reject off-canvas, so this route uses 13px
   like .otable does and for the same reason. */
body[data-view="approvals"] table.data th,
body[data-view="approvals"] table.data td { padding-left: 13px; padding-right: 13px; }
body[data-view="approvals"] table.data td { height: auto; }

/* ---------- 11.3 Integrations table (settings → Integrations) ----------
   Two of these columns are prose — what moves, and what happens when
   the API is down. Left nowrap they force a ~2.5k-wide table, so they
   wrap inside a fixed measure instead. Fixed layout keeps the two
   prose columns from starving the rest. */
#pane-integrations table.data { table-layout: fixed; }
#pane-integrations table.data td.wrap { white-space: normal; line-height: 1.5; }
#pane-integrations table.data td .sub { white-space: normal; line-height: 1.45; }
#pane-integrations col.i-name  { width: 18%; }
#pane-integrations col.i-dir   { width: 8%; }
#pane-integrations col.i-moves { width: 23%; }
#pane-integrations col.i-back  { width: 19%; }
#pane-integrations col.i-sync  { width: 11%; }
#pane-integrations col.i-stat  { width: 12%; }
#pane-integrations col.i-act   { width: 9%; }

/* ---------- 11.4 Purchase guard bars ----------
   §7.9's 195px name column was set when this row read "Listing
   mismatch". It now names the guard it actually is — "Title /
   image mismatch" — which is 20px longer and was ellipsing. The
   track gives the width back; the figures stay aligned. */
body[data-view="purchase"] .bars .row { grid-template-columns: 215px 1fr 52px; }

/* ---------- 11.5 Catalog table budget ----------
   Same 1296px-at-1600px budget as §8 and §11.2, reached the same
   way: 13px gutters instead of §7.10's 20px. The handling-tags
   view additionally carries two prose columns, which wrap inside
   a fixed measure rather than setting the table's width. */
body[data-view="catalog"] table.data th,
body[data-view="catalog"] table.data td { padding-left: 13px; padding-right: 13px; }
body[data-view="catalog"] table.data td { height: auto; }
body[data-view="catalog"] table.data td.wrap { white-space: normal; line-height: 1.5; }

#pane-tags table.data { table-layout: fixed; }
#pane-tags col.t-tag { width: 18%; }
#pane-tags col.t-by  { width: 12%; }
#pane-tags col.t-trg { width: 25%; }
#pane-tags col.t-qty { width: 8%; }
#pane-tags col.t-eff { width: 29%; }
#pane-tags col.t-act { width: 8%; }

/* Product master and SKU mapping both run eight columns. Trimming
   copy to fit was moving the clip around rather than removing it,
   so both are fixed-layout with declared widths and wrapping cells
   — the Edit control is the point of the row and must not clip. */
#pane-products table.data,
#pane-mapping  table.data { table-layout: fixed; }
#pane-products table.data td,
#pane-mapping  table.data td { white-space: normal; }
#pane-products table.data td .sub,
#pane-mapping  table.data td .sub { white-space: normal; line-height: 1.45; }

#pane-products col.p-sku  { width: 15%; }
#pane-products col.p-prod { width: 18%; }
#pane-products col.p-src  { width: 13%; }
#pane-products col.p-ids  { width: 15%; }
#pane-products col.p-dim  { width: 11%; }
#pane-products col.p-hand { width: 13%; }
#pane-products col.p-tally{ width: 8%;  }
#pane-products col.p-act  { width: 7%;  }

#pane-mapping col.m-sku   { width: 15%; }
#pane-mapping col.m-mkt   { width: 17%; }
#pane-mapping col.m-asin  { width: 11%; }
#pane-mapping col.m-master{ width: 16%; }
#pane-mapping col.m-src   { width: 11%; }
#pane-mapping col.m-sla   { width: 15%; }
#pane-mapping col.m-held  { width: 7%;  }
#pane-mapping col.m-act   { width: 8%;  }

/* ============================================================
   12. Customs & duty — 2026-07-26
   ------------------------------------------------------------
   The client asked for the customs field group after sign-off
   scoping, and it splits cleanly in two: an export declaration
   (outbound from India, feeding report 1) and an import duty
   build-up (inbound, the Indian duty stack).

   Deliberately NOT a stacked bar. The duty components are
   categorical, not ordered, so charting them would need six
   hues and break §7's one-hue rule — and an accountant reads a
   duty computation as a vertical build-up anyway, because each
   cess sits on a different base. So: a ladder of numbers with
   the bases called out, which is auditable in a way a bar is not.
   ============================================================ */

/* ---------- 12.1 Duty build-up ladder ---------- */
.ladder { display: grid; }
.ldr {
  display: grid; grid-template-columns: 168px 1fr 116px;
  gap: 16px; align-items: baseline;
  padding: 9px 0; border-bottom: 1px solid var(--hair-soft);
  font-size: 13px;
}
.ldr .k { color: var(--ink-2); font-weight: 600; }
.ldr .b { color: #9A9A96; font-size: 12px; }
.ldr .v { text-align: right; font-weight: 600; color: var(--navy); font-variant-numeric: tabular-nums; }
.ldr .v.nil { color: #C2C2BD; font-weight: 500; }

/* a base is a subtotal others are computed from — hairline above it */
.ldr.is-base { border-top: 1px solid var(--hair); }
.ldr.is-base .k { color: var(--navy); font-weight: 650; }

/* the inputs above the assessable value: supplier invoice, FX rate */
.ldr.is-sub .k { color: #9A9A96; font-weight: 500; }
.ldr.is-sub .v { color: var(--ink-2); font-weight: 500; }

.ldr.is-total { border-top: 1px solid var(--line-strong); border-bottom: 0; padding-top: 12px; }
.ldr.is-total + .ldr.is-total { border-top: 1px solid var(--hair); padding-top: 9px; }
.ldr.is-total .k { color: var(--navy); font-weight: 650; }
.ldr.is-total .v { font-size: 15.5px; font-weight: 650; }

/* a nil duty line is information, not absence — greyed, never blank */
body[data-view="customs"] table.data td.nil,
body[data-view="customs"] table.data .nil { color: #C2C2BD; font-weight: 500; }

/* ---------- 12.2 Table budgets ----------
   Four views, two of them eleven and ten columns wide because the
   client's register carries every duty component as its own field.
   Fixed layout with declared widths, same as §11.2/§11.5. The
   component columns drop the currency prefix — the filter row
   states "all amounts INR" once, which buys back ~40px a column. */
body[data-view="customs"] table.data th,
body[data-view="customs"] table.data td { padding-left: 12px; padding-right: 12px; }
body[data-view="customs"] table.data td { height: auto; white-space: normal; }
body[data-view="customs"] table.data td .sub { white-space: normal; line-height: 1.45; }
body[data-view="customs"] table.data { table-layout: fixed; }

#pane-export col.x-ship { width: 16%; } #pane-export col.x-route { width: 15%; }
#pane-export col.x-inv  { width: 16%; } #pane-export col.x-fob   { width: 11%; }
#pane-export col.x-decl { width: 11%; } #pane-export col.x-hs    { width: 11%; }
#pane-export col.x-wt   { width: 12%; } #pane-export col.x-act   { width: 8%;  }

#pane-import col.d-cons { width: 15%; } #pane-import col.d-hs   { width: 9%;  }
#pane-import col.d-av   { width: 11%; } #pane-import col.d-bcd  { width: 8%;  }
#pane-import col.d-aidc { width: 7%;  } #pane-import col.d-hlth { width: 7%;  }
#pane-import col.d-sws  { width: 9%;  } #pane-import col.d-igst { width: 8%;  }
#pane-import col.d-cmp  { width: 9%;  } #pane-import col.d-tot  { width: 10%; }
#pane-import col.d-act  { width: 7%;  }

#pane-charged col.c-cons { width: 14%; } #pane-charged col.c-what { width: 20%; }
#pane-charged col.c-exp  { width: 10%; } #pane-charged col.c-chg  { width: 10%; }
#pane-charged col.c-var  { width: 9%;  } #pane-charged col.c-imp  { width: 19%; }
#pane-charged col.c-st   { width: 10%; } #pane-charged col.c-act  { width: 8%;  }

#pane-rates col.r-hs   { width: 13%; } #pane-rates col.r-desc { width: 26%; }
#pane-rates col.r-bcd  { width: 7%;  } #pane-rates col.r-aidc { width: 7%;  }
#pane-rates col.r-hlth { width: 7%;  } #pane-rates col.r-sws  { width: 10%; }
#pane-rates col.r-igst { width: 7%;  } #pane-rates col.r-cmp  { width: 10%; }
#pane-rates col.r-sku  { width: 7%;  } #pane-rates col.r-act  { width: 6%;  }

@media (max-width: 1240px) {
  .ldr { grid-template-columns: 140px 1fr 100px; gap: 12px; }
}

/* Inventory centres: the Notes column is prose and was forcing the table
   64px past the card, clipping every Edit button. Fixed layout + a wrapping
   notes cell, same fix as §11.2/§11.5 and §12.2. */
#pane-warehouses table.data { table-layout: fixed; }
#pane-warehouses table.data td:nth-child(4) { white-space: normal; line-height: 1.5; }
#pane-warehouses col.w-name { width: 26%; }
#pane-warehouses col.w-ctry { width: 11%; }
#pane-warehouses col.w-kind { width: 15%; }
#pane-warehouses col.w-note { width: 27%; }
#pane-warehouses col.w-qc   { width: 13%; }
#pane-warehouses col.w-act  { width: 8%;  }

/* ============================================================
   13. Column budget — slice 2–5 pages  ·  2026-07-29
   ------------------------------------------------------------
   These pages predate the 1296px budget §8 set. Their tables ran
   40–460px past the card, which cut the Edit / View / Open button
   off the right edge of every row — the one failure mode the deck
   must not ship with. Same fix already used on catalog, approvals,
   customs and settings: fixed layout, a declared <colgroup> per
   table, and cells allowed to wrap so prose costs height, not width.
   Widths are inline on the <col> elements — 30 tables would
   otherwise need 30 near-identical class sets for no gain.
   ============================================================ */
body[data-page="inventory"] table.data,
body[data-page="returns"]   table.data,
body[data-page="cs"]        table.data,
body[data-page="tickets"]   table.data,
body[data-page="jit"]       table.data,
body[data-page="recon"]     table.data,
body[data-page="dispatch"]  table.data { table-layout: fixed; }

body[data-page="inventory"] table.data td,
body[data-page="returns"]   table.data td,
body[data-page="cs"]        table.data td,
body[data-page="tickets"]   table.data td,
body[data-page="jit"]       table.data td,
body[data-page="recon"]     table.data td,
body[data-page="dispatch"]  table.data td { white-space: normal; height: auto; }

body[data-page="inventory"] table.data td .sub,
body[data-page="returns"]   table.data td .sub,
body[data-page="cs"]        table.data td .sub,
body[data-page="tickets"]   table.data td .sub,
body[data-page="jit"]       table.data td .sub,
body[data-page="recon"]     table.data td .sub,
body[data-page="dispatch"]  table.data td .sub { white-space: normal; line-height: 1.45; }

/* Pills here are §7 pills — a coloured dot plus a label, not a filled
   chip — so a long one wrapping onto a second line is fine. Held on one
   line they were spilling up to 104px into the neighbouring column and
   printing over its text, which is far worse than two lines. */
body[data-page="inventory"] table.data td .pill,
body[data-page="returns"]   table.data td .pill,
body[data-page="cs"]        table.data td .pill,
body[data-page="tickets"]   table.data td .pill,
body[data-page="jit"]       table.data td .pill,
body[data-page="recon"]     table.data td .pill,
body[data-page="dispatch"]  table.data td .pill { white-space: normal; }

/* Long unbreakable tokens — AWBs, Master SKUs, PO numbers — were the last
   thing pushing content past the card once the table itself was fixed.
   break-word, not anywhere: anywhere also drives min-content sizing and
   split "USZ_B0BOOK2231" across two lines even where it fit. */
body[data-page="inventory"] table.data td,
body[data-page="returns"]   table.data td,
body[data-page="cs"]        table.data td,
body[data-page="tickets"]   table.data td,
body[data-page="jit"]       table.data td,
body[data-page="recon"]     table.data td,
body[data-page="dispatch"]  table.data td { overflow-wrap: break-word; }

/* §5 keeps headers on one line; with a fixed layout a long header
   ("Variance breakdown", "Lost — reimb. pending") then overflows its
   column and drags the scroll width with it. Let them wrap here. */
body[data-page="inventory"] table.data th,
body[data-page="returns"]   table.data th,
body[data-page="cs"]        table.data th,
body[data-page="tickets"]   table.data th,
body[data-page="jit"]       table.data th,
body[data-page="recon"]     table.data th,
body[data-page="dispatch"]  table.data th { white-space: normal; line-height: 1.35; }

/* Rows carrying two actions stack them rather than overflow the cell.
   A wrapped button is still clickable; a clipped one is not. */
body[data-page="inventory"] table.data td.actions,
body[data-page="returns"]   table.data td.actions,
body[data-page="cs"]        table.data td.actions,
body[data-page="tickets"]   table.data td.actions,
body[data-page="jit"]       table.data td.actions,
body[data-page="recon"]     table.data td.actions,
body[data-page="dispatch"]  table.data td.actions {
  padding-left: 8px; padding-right: 12px;
  display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; align-items: center;
}
body[data-page="inventory"] table.data td.actions .btn,
body[data-page="returns"]   table.data td.actions .btn,
body[data-page="cs"]        table.data td.actions .btn,
body[data-page="tickets"]   table.data td.actions .btn,
body[data-page="jit"]       table.data td.actions .btn,
body[data-page="recon"]     table.data td.actions .btn,
body[data-page="dispatch"]  table.data td.actions .btn { white-space: nowrap; }
#pane-integrations table.data td .pill { white-space: normal; }


/* ============================================================
   14. IRA — Intelligent Robo Assistant  ·  2026-07-29
   ------------------------------------------------------------
   Scoped to body[data-page="ira"] wherever a name is generic
   enough to collide. Reuses §8's anatomy throughout — .window-rail
   for the permission ladder, .otable for the registry, .scoped,
   .fsearch, .tfoot — so this page inherits every later fix to
   those rather than forking them.

   Two colour decisions worth keeping:
   · Permission is an ORDERED dimension (risk rises Read → Act),
     so the sequential blue ramp is allowed under §7's one-hue
     rule — the same exemption the purchase-window rail uses.
   · Phase is ordered too, but it competes with permission in the
     same table, so it is greyscale: navy = live now, fading to
     light grey = furthest away. Two ramps, one hue between them.
   ============================================================ */

/* ---------- 14.1 Toolbar ---------- */
.tool-label {
  color: #A6A6A1; font-size: 11px; font-weight: 700;
  letter-spacing: 1.05px; text-transform: uppercase;
}
.ira-badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border: 1px solid var(--hair); border-radius: 99px;
  color: #7A7B7E; font-size: 11px; font-weight: 650; letter-spacing: .3px;
}
.ira-badge::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--series);
}

/* ---------- 14.2 Permission tag ----------
   Dot + label, per §7 — never a filled pill. The dot carries the ramp,
   the label stays greyscale so a column of these does not read as colour. */
.perm {
  display: inline-flex; align-items: center; gap: 7px;
  color: #7A7B7E; font-size: 11.5px; font-weight: 600; white-space: nowrap;
}
.perm i {
  width: 7px; height: 7px; flex: 0 0 7px; border-radius: 50%;
  background: var(--series); box-shadow: inset 0 0 0 1px rgba(19, 25, 33, .07);
}
.perm.p-read i    { background: #CFE0F5; }
.perm.p-watch i   { background: #A9C8EC; }
.perm.p-suggest i { background: #7FACE0; }
.perm.p-draft i   { background: #4E8FD4; }
.perm.p-act i     { background: #2B7CD8; }

/* ---------- 14.3 Ask ---------- */
.ask { display: flex; gap: 10px; align-items: center; margin-top: 4px; }
.ask-field {
  flex: 1; display: flex; align-items: center; gap: 11px;
  min-height: 44px; padding: 0 17px;
  border: 1px solid var(--hair); border-radius: 99px; background: var(--surface);
  transition: border-color .15s, box-shadow .15s;
}
.ask-field:focus-within { border-color: var(--blue); box-shadow: var(--shadow-focus); }
.ask-field input {
  width: 100%; border: 0; outline: 0; background: none;
  font: inherit; font-size: 14px; font-weight: 500; color: var(--ink);
}
.ask-field input::placeholder { color: #B4B4AF; font-weight: 500; }
.ask .btn.primary { min-height: 44px; border-radius: 99px; padding: 0 22px; gap: 9px; display: inline-flex; align-items: center; }
.ask-send { display: inline-flex; }
.ask-send svg.ic { width: 15px; height: 15px; }

/* Scoped to .ask-chips deliberately. `.chip` is NOT free: jit-po-new.html
   already uses it for its source-code selector, with a `.chip.on` selected
   state that has no rule anywhere in this stylesheet. A bare `.chip` here
   would restyle that page into looking interactive while its selection
   stayed invisible — worse than the unstyled spans it has today. */
.ask-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.ask-chips .chip {
  padding: 6px 13px; border: 1px solid var(--hair); border-radius: 99px;
  background: var(--surface); color: #555; cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 500; text-align: left;
  transition: border-color .15s, color .15s;
}
.ask-chips .chip:hover { border-color: var(--blue); color: var(--navy); }
.ask-chips .chip-alt { color: #A6A6A1; font-style: italic; }
.ask-chips .chip-alt:hover { border-color: #C9A227; color: #7A7B7E; }

/* ---------- 14.4 The answer ---------- */
.ans { margin-top: 20px; padding-top: 19px; border-top: 1px solid var(--hair); }
.ans-head { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
.ans-head .spacer { flex: 1; }
.ans-mark {
  display: inline-flex; flex: 0 0 20px; width: 20px; height: 20px;
  border-radius: 50%; overflow: hidden; background: #000;
}
.ans-q { color: var(--navy); font-size: 13.5px; font-weight: 650; }
.conf {
  display: inline-flex; align-items: center; gap: 9px;
  color: #A6A6A1; font-size: 11px; font-weight: 600; white-space: nowrap;
}
.conf b { color: var(--navy); font-weight: 650; font-variant-numeric: tabular-nums; }
.conf-track {
  display: block; width: 62px; height: 3px; border-radius: 99px;
  background: var(--track); overflow: hidden;
}
.conf-track em { display: block; height: 100%; border-radius: 99px; background: var(--series); }
.conf.low b { color: #9A6B00; }
.conf.low .conf-track em { background: var(--series-dim); }
.conf-none { color: #9A6B00; font-size: 11px; font-weight: 650; }

.ans-verdict {
  margin: 13px 0 0; color: var(--ink);
  font-size: 14px; font-weight: 500; line-height: 1.58;
}
.ans-verdict b { color: var(--navy); font-weight: 650; }

.ans-ev { list-style: none; margin: 16px 0 0; padding: 0; }
.ans-ev li {
  display: grid; grid-template-columns: 168px 1fr 52px; gap: 16px; align-items: baseline;
  padding: 9px 0; border-top: 1px solid var(--hair-soft);
}
.ans-ev li:first-child { border-top: 0; }
.e-k {
  color: #A6A6A1; font-size: 10.5px; font-weight: 700;
  letter-spacing: .95px; text-transform: uppercase;
}
.e-v { color: var(--ink); font-size: 12.5px; font-weight: 500; line-height: 1.5; }
.e-v b { color: var(--navy); font-weight: 650; }
.e-a { justify-self: end; color: #B4B4AF; font-size: 11.5px; font-weight: 600; }
a.e-a:hover { color: var(--orange); }
.e-none { color: #DCDCD8; }

.ans-act {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 17px; padding-top: 15px; border-top: 1px solid var(--hair);
}
.ans-act .spacer { flex: 1; }
.ans-note {
  display: flex; align-items: flex-start; gap: 9px;
  margin: 13px 0 0; color: #A6A6A1;
  font-size: 11.5px; font-weight: 500; font-style: italic; line-height: 1.55;
}
/* No mark on the note. A full-colour logo cannot be greyed down to a
   footnote's weight the way the old line icon could, and three marks in one
   answer was two too many — the head already says who is speaking. */

/* The "I don't know" answer is a designed state, so it gets a treatment —
   an amber hairline, not a red one. Declining to answer is not a breach. */
.ans.is-unknown { border-top-color: #E8D9A8; }
.ans.is-unknown .ans-verdict b { color: #9A6B00; }

/* ---------- 14.5 The watch feed ---------- */
.nudges { display: block; }
.nudge {
  display: flex; gap: 13px; align-items: flex-start;
  padding: 15px 20px 16px; border-top: 1px solid var(--hair-soft);
  border-left: 2px solid transparent;
}
.nudge:first-child { border-top: 0; }
.n-ic { display: inline-flex; margin-top: 1px; color: #C2C2BD; }
.n-ic svg.ic { width: 16px; height: 16px; }
.n-body { min-width: 0; flex: 1; }
.n-top { display: flex; align-items: baseline; gap: 10px; }
.n-top b { color: var(--navy); font-size: 12.5px; font-weight: 650; line-height: 1.42; }
.n-w {
  margin-left: auto; color: #B4B4AF; font-size: 10.5px; font-weight: 600;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.nudge p {
  margin: 6px 0 0; color: #6E6F72;
  font-size: 12px; font-weight: 500; line-height: 1.55;
}
.nudge p b { color: var(--ink); font-weight: 650; }
.n-act { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 10px; }
.n-go { color: var(--navy); font-size: 11.5px; font-weight: 650; }
.n-go:hover { color: var(--orange); }

/* Tone is carried by the icon and a 2px edge — a hairline, not a wash.
   Red is reserved for something genuinely breaching, per §7. */
.nudge.tone-breach { border-left-color: var(--critical); }
.nudge.tone-breach .n-ic { color: var(--critical); }
.nudge.tone-breach .n-w  { color: var(--critical); }
.nudge.tone-warn .n-ic   { color: #9A6B00; }
.nudge.tone-calm .n-ic   { color: #D2D4D7; }

/* ---------- 14.6 Registry table ----------
   §13's lesson: fixed layout + a declared colgroup, so trimming copy is
   never the thing keeping a column inside the card. */
body[data-page="ira"] table.data.otable.reg { min-width: 940px; table-layout: fixed; }
body[data-page="ira"] table.data.otable.reg th,
body[data-page="ira"] table.data.otable.reg td { padding: 11px 14px; vertical-align: top; }

tr.reg-grp td {
  padding: 17px 14px 8px !important;
  background: var(--surface); border-bottom: 1px solid var(--hair) !important;
}
tr.reg-grp .row-ic { display: inline-flex; vertical-align: -2px; margin-right: 9px; color: #C2C2BD; }
tr.reg-grp .row-ic svg.ic { width: 15px; height: 15px; }
tr.reg-grp b {
  color: var(--navy); font-size: 11px; font-weight: 700;
  letter-spacing: 1.15px; text-transform: uppercase;
}
tr.reg-grp span:not(.row-ic):not(.reg-n) {
  margin-left: 11px; color: #A6A6A1; font-size: 11.5px; font-weight: 500;
}
tr.reg-grp .reg-n {
  float: right; color: #B4B4AF; font-size: 11.5px; font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.reg-n-cell { color: var(--navy); font-size: 12.5px; font-weight: 650; line-height: 1.42; }
.reg-d { color: #6E6F72; font-size: 12px; font-weight: 500; line-height: 1.52; }
.reg-who { color: #A6A6A1; font-size: 11.5px; font-weight: 500; line-height: 1.45; }

/* Phase — greyscale, because permission already owns the blue ramp in
   this table. Navy = live now, fading out as the phase gets further away. */
.ph { font-size: 12.5px; font-weight: 650; font-variant-numeric: tabular-nums; }
.ph-1 { color: var(--navy); }
.ph-2 { color: #9A9A96; }
.ph-3 { color: #C7C7C2; }

.fcheck {
  display: inline-flex; align-items: center; gap: 8px;
  color: #7A7B7E; font-size: 12.5px; font-weight: 500; cursor: pointer;
}
.fcheck input { width: 14px; height: 14px; cursor: pointer; }
.linkish {
  border: 0; background: none; padding: 0; cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 650; color: var(--navy);
}
.linkish:hover { color: var(--orange); }

/* ---------- 14.7 The never list ----------
   The trust-ladder rows and the 3-phase rollout strip lived here until the
   2026-07-29 minimalist pass. Both were cut: the ladder is legible from the
   rail plus the permission tag on every row, and the phasing is one sentence
   in the registry foot. Put these back first if the client asks how a
   capability gets from Read to Act. */
.never { list-style: none; margin: 0; padding: 0; }
.never li {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 11px 0; border-top: 1px solid var(--hair-soft);
  color: var(--ink); font-size: 12.5px; font-weight: 500; line-height: 1.55;
}
.never li:first-child { border-top: 0; padding-top: 4px; }
.never svg.ic { width: 14px; height: 14px; flex: 0 0 14px; margin-top: 2px; color: #D8B4B3; }

/* ---------- 14.10 The launcher + panel ----------
   IRA is a layer over all 23 pages, not a nav destination, so it lives in a
   floating mark bottom-right and a slide-in panel. Three decisions:

   · The mark is the supplied OneStaff PNG, and it IS the button — the artwork
     is already a black disc, so there is no navy plate behind it to fight.
     The gold in the logo is the one place a non-palette hue is allowed: it is
     supplied brand artwork, the same licence `MARKETPLACES` monograms take.
   · Shadows are allowed here. §7's no-shadow rule governs *static surfaces* —
     a floating launcher and an overlay panel are genuinely above the page and
     need to read that way, the same exemption `.toast` already takes.
   · The PNG's disc fills exactly 80% of its canvas (measured: 400px of 500px,
     centred), so `.ira-logo` scales 1.25× inside an `overflow:hidden` circle
     to bring the disc flush to the edge. Replacing the file means re-checking
     that ratio — a different margin will show as a gap or a crop.
   ---------------------------------------------------------------- */
.ira-logo {
  display: block; width: 125%; height: 125%;
  margin: -12.5%; object-fit: contain; pointer-events: none;
}
/* NO `overflow: hidden` here, deliberately. The artwork already contains its
   own circle — at 125% of a 52px button the black disc lands at exactly 52px,
   centred, with only transparent margin spilling past the edge. Clipping the
   button to `border-radius: 50%` additionally cut **56% of the breach dot
   away**, because a dot at the top-right corner sits outside the inscribed
   circle. The background and radius stay purely as a fallback if the PNG
   fails to load; the disc covers them exactly. */
.ira-fab {
  position: fixed; right: 26px; bottom: 26px; z-index: 90;
  width: 52px; height: 52px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: #000;
  box-shadow: 0 2px 5px rgba(19, 25, 33, .18), 0 12px 28px rgba(19, 25, 33, .22);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease);
}
.ira-fab:hover { transform: translateY(-1px); box-shadow: 0 3px 7px rgba(19,25,33,.2), 0 16px 34px rgba(19,25,33,.26); }
.ira-fab:focus-visible { outline: 0; box-shadow: 0 0 0 3px rgba(43,124,216,.34), 0 12px 28px rgba(19,25,33,.22); }
.ira-fab .fab-dot {
  position: absolute; top: 1px; right: 1px; z-index: 1;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--critical); border: 2px solid var(--page);
}
body.ira-open .ira-fab { transform: scale(.9); opacity: 0; pointer-events: none; }

.ira-scrim {
  position: fixed; inset: 0; z-index: 95; border: 0; padding: 0;
  background: rgba(19, 25, 33, .13); cursor: default;
  opacity: 0; visibility: hidden;
  /* visibility gets a 0s change DELAYED to the end, never a duration — see
     the note on .ira-panel below. */
  transition: opacity .2s, visibility 0s linear .2s;
}
body.ira-open .ira-scrim { opacity: 1; visibility: visible; transition: opacity .2s, visibility 0s; }

.ira-panel {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 96;
  width: 404px; max-width: 100vw;
  display: flex; flex-direction: column;
  background: var(--surface); border-left: 1px solid var(--hair);
  box-shadow: -18px 0 44px rgba(19, 25, 33, .13);
  transform: translateX(100%); visibility: hidden;
  /* `visibility` is a DISCRETE property — giving it a duration ("visibility
     .24s") is the classic slide-in bug: the panel stays hidden while the
     transform runs, and on a backgrounded tab the transform can stall at its
     start value entirely, leaving the panel permanently off-screen. Flip it
     instantly on open (0s, no delay) and only after the slide-out on close
     (0s delayed by the duration), so the transform always animates on an
     element that is already visible. */
  transition: transform .24s var(--ease), visibility 0s linear .24s;
}
body.ira-open .ira-panel { transform: none; visibility: visible; transition: transform .24s var(--ease), visibility 0s; }

/* --- head --- */
.ip-head {
  display: flex; align-items: center; gap: 12px;
  padding: 17px 18px 15px; border-bottom: 1px solid var(--hair);
}
.ip-mark {
  display: inline-flex; flex: 0 0 26px; width: 26px; height: 26px;
  border-radius: 50%; overflow: hidden; background: #000;
}
.ip-id { min-width: 0; flex: 1; }
.ip-id b {
  display: block; color: var(--navy);
  font-size: 14px; font-weight: 700; letter-spacing: .4px; line-height: 1.2;
}
/* Borderless so it reads as a status line, not a form control — but it is a
   real select, because the role switch is the proof that IRA is personalised. */
.ip-role {
  margin: 1px 0 0 -4px; max-width: 100%;
  border: 0; background: none; padding: 0 4px; cursor: pointer;
  font: inherit; font-size: 11.5px; font-weight: 500; color: #A6A6A1;
}
.ip-role:hover { color: var(--navy); }
.ip-role:focus-visible { outline: 1px solid var(--blue); border-radius: 4px; }
.ip-close {
  border: 0; background: none; padding: 5px; cursor: pointer;
  display: inline-flex; color: #B4B4AF; border-radius: 7px;
}
.ip-close:hover { color: var(--navy); background: var(--hair-soft); }
.ip-close svg.ic { width: 16px; height: 16px; }

/* --- body --- */
.ip-body { flex: 1; overflow-y: auto; overscroll-behavior: contain; }
.ip-eyebrow {
  display: flex; align-items: baseline; gap: 10px;
  margin: 0; padding: 15px 18px 4px; color: #A6A6A1;
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.15px; text-transform: uppercase;
}
.ip-eyebrow span { margin-left: auto; letter-spacing: .4px; text-transform: none; font-weight: 500; font-size: 11px; }
.ira-panel .nudge { padding: 13px 18px 14px; }
.ira-panel .lane-empty { padding: 14px 18px 18px; }

/* The answer is the same component as everywhere else, folded to one column —
   404px cannot carry the 168px label gutter the wide card uses. */
.ira-panel .ans { margin: 4px 18px 18px; padding-top: 16px; }
.ira-panel .ans-ev li { grid-template-columns: 1fr; gap: 3px; padding: 8px 0; }
.ira-panel .e-a { justify-self: start; }
.ira-panel .ans-verdict { font-size: 13px; }
.ira-panel .ans-act { gap: 10px; }
.ira-panel .ans-act .spacer { display: none; }

/* --- composer --- */
.ip-foot { border-top: 1px solid var(--hair); padding: 12px 18px 14px; background: var(--surface); }
.ip-foot .ask-chips { margin: 0 0 11px; gap: 6px; max-height: 96px; overflow-y: auto; }
.ip-foot .ask-chips .chip { font-size: 11.5px; padding: 5px 11px; }
.ip-foot .ask { gap: 8px; }
.ip-foot .ask-field { min-height: 40px; padding: 0 15px; }
.ip-foot .ask-field input { font-size: 13px; }
.ip-foot .btn.primary {
  min-height: 40px; width: 40px; padding: 0; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 40px;
}
.ip-foot .btn.primary svg.ic { width: 15px; height: 15px; }
.ip-link {
  display: block; margin-top: 11px; text-align: center;
  color: #A6A6A1; font-size: 11.5px; font-weight: 600;
}
.ip-link:hover { color: var(--orange); }

@media (max-width: 520px) {
  .ira-panel { width: 100vw; border-left: 0; }
  .ira-fab { right: 18px; bottom: 18px; }
}

/* ---------- 14.9 Folds ---------- */
@media (max-width: 820px) {
  .ask { flex-wrap: wrap; }
  .ask-field { flex: 1 1 100%; }
  .ask .btn.primary { width: 100%; justify-content: center; }
  .ans-ev li { grid-template-columns: 1fr; gap: 4px; }
  .e-a { justify-self: start; }
}

/* ============================================================
   15. Orders page — the dashboard's restraint, 2026-07-29
   ------------------------------------------------------------
   Gaurav: the dashboard reads minimal and elegant, make orders
   match — but "i want that flag and decor, thats what makes the
   site worth it". So NOTHING decorative is removed here. The
   flags, the marketplace monograms and the source chips all stay
   exactly as they were.

   The diagnosis was that they were competing, not that there
   were too many. One orders row was spending its attention
   budget on things that are not decor at all: four separate
   600-weights (order ID, marketplace, item, deadline), a cluster
   of six boxed filter controls, 68px rows with no air, and a
   purchase-window rail written in a different component language
   than the dashboard's tiles. Quiet all of that and the flags
   become the only colour in the row — which is what they were
   for. Subtraction everywhere except the decoration.

   Scoped to body[data-page="orders"] on purpose: .otable, .dl,
   .w-* and .window-rail are shared with purchase, tracking, qc,
   ira and the §13 pages, whose column budgets were measured to
   the pixel. A global change here silently re-cuts all of them.
   ============================================================ */

/* ---------- 15.1 Purchase window as the dashboard's tile strip ---------- */
/* Was flat divider columns inside a .card — a second language for the same
   "here are five counts" job the dashboard does with raised tiles, and a box
   sitting inside a box. Now the page opens on the dashboard's own rhythm:
   toolbar → tiles → the working surface. The sequential blue ramp on the
   bars is untouched; it is still the only thing separating the buckets. */
/* .sec-head is retained for any page that wants a card-less section heading,
   but orders.html no longer uses one — see 15.6. */
body[data-page="orders"] .sec-head {
  display: flex; align-items: baseline; gap: 9px;
  padding: 0 2px 14px;
}
body[data-page="orders"] .sec-head h2 {
  margin: 0; font-size: 14px; font-weight: 650; letter-spacing: -.05px; color: var(--navy);
}
body[data-page="orders"] .sec-head .sub {
  font-size: 12.5px; font-weight: 500; color: #A6A6A1;
}
body[data-page="orders"] .sec-head .sub::before { content: "·"; margin-right: 8px; color: #CFCFCA; }
body[data-page="orders"] .sec-head .spacer { flex: 1; }
body[data-page="orders"] .sec-head a:not(.btn) { font-size: 12.5px; font-weight: 600; color: #7A7B7E; }
body[data-page="orders"] .sec-head a:not(.btn):hover { color: var(--orange); }

body[data-page="orders"] .window-rail {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 16px;
}
/* the §7.4 tile recipe verbatim — contact + ambient + cast shadow, inner
   top highlight, darker bottom edge — so the two strips read as one system */
body[data-page="orders"] .wcell {
  display: flex; flex-direction: column;
  min-height: 126px; padding: 17px 18px 18px;
  border: 1px solid var(--hair); border-bottom-color: #E3E3DF;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), border-color .18s;
}
body[data-page="orders"] .wcell:hover {
  transform: translateY(-2px); border-color: #DCDCD7;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 4px 8px rgba(19, 25, 33, .05),
    0 14px 28px rgba(19, 25, 33, .08),
    inset 0 1px 0 rgba(255, 255, 255, .9);
}
body[data-page="orders"] .wcell:active { transform: translateY(0); }
/* the active filter keeps its orange — §8 already allowed it here, the same
   treatment the tabs use. A ring rather than an underline, because the tile
   is rounded now and an inset bar clips against the radius. */
body[data-page="orders"] .wcell.active {
  border-color: transparent;
  box-shadow:
    inset 0 0 0 1.5px var(--orange),
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05);
}
/* figure pushed to the bottom of the tile like .kpi .figure, so five tiles
   with different sub-line lengths still align on their numbers */
body[data-page="orders"] .w-val {
  margin-top: auto; padding-top: 14px;
  font-size: 30px; font-weight: 600; letter-spacing: -1.1px;
}
body[data-page="orders"] .w-sub { margin-top: 7px; }
body[data-page="orders"] .rail-note { margin: 14px 2px 0; }

/* ---------- 15.2 Filter row — chrome down, not controls out ---------- */
/* Six pill-outlined controls in a row was the heaviest cluster in the deck;
   the dashboard's only cluster is a three-button segment. The controls all
   stay — they just stop drawing their boxes until you reach for them. */
body[data-page="orders"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-page="orders"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-page="orders"] .filters select:hover {
  border-color: var(--hair); background-color: var(--surface);
}
body[data-page="orders"] .filters select:focus {
  border-color: var(--blue); background-color: #fff;
}
body[data-page="orders"] .fsearch { background: transparent; border-color: var(--hair-soft); }
body[data-page="orders"] .fsearch:hover { border-color: var(--hair); }
body[data-page="orders"] .fsearch:focus-within { background: var(--surface); }

/* ---------- 15.3 Row air ---------- */
/* Vertical only. The 1296px horizontal budget from §8 is untouched — these
   nine columns still have to fit the card at 1600px before the wrap scrolls. */
body[data-page="orders"] table.data.otable th,
body[data-page="orders"] table.data.otable td { padding: 15px 13px; }
body[data-page="orders"] table.data.otable th { padding-top: 13px; padding-bottom: 11px; }

/* ---------- 15.4 One bold per row ---------- */
/* Order ID, marketplace name, item name and deadline value were all 600–650,
   so nothing was primary and the eye had no entry point. §7's rule is that
   size and colour carry hierarchy, not weight — the ID stays 600 as the
   thing you actually click, everything else steps back to 500 and keeps its
   ink colour. Net effect: the flag is the brightest mark in the cell. */
body[data-page="orders"] .o-mp-name b,
body[data-page="orders"] .o-item b { font-weight: 500; }
body[data-page="orders"] .dl-v { font-weight: 600; }
body[data-page="orders"] .dl.breach .dl-v { font-weight: 650; }

/* ---------- 15.5 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="orders"] .window-rail { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-page="orders"] .window-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  body[data-page="orders"] .sec-head { flex-wrap: wrap; }
  body[data-page="orders"] .sec-head .sub::before { content: none; }
}

/* ============================================================
   16. Order detail — A-tier visual pass (2026-07-29)
   ------------------------------------------------------------
   The page loaded the v3 system but used almost none of its
   vocabulary: measured against index.html it carried 0 flags,
   0 marketplace marks, 0 rings, 1 meter and 6 painted hues
   (the dashboard: 9 / 7 / 3 / 17 / 20), and its two largest
   elements were an order ID and a day count while the money —
   report 13's gross contribution — sat at 13px.

   Everything here is scoped to body[data-view="order-detail"].
   .flag, .mk, .kpi and the §8 od-* anatomy are shared with the
   orders / purchase / tracking / IRA pages whose column budgets
   were measured to the pixel; a global edit re-cuts all of them.
   ============================================================ */

/* ---------- 16.1 Fact strip → raised tiles ---------- */
/* Was a flat 88px divider row inside the hero with 13px values: a second
   component language for the job §7.4 already does, and the same "box inside
   a box" §15.1 removed from the orders window rail. Same fix, same recipe —
   contact + ambient + cast shadow, inner top highlight, darker bottom edge. */
/* minmax(0, …) on every track, not bare `fr`: an `fr` track carries an
   automatic min-content floor, so these tiles refused to shrink and the row
   ran ~99px past its own container between 1241 and ~1340px — the uppercase
   labels ("PROJECTED GROSS CONTRIBUTION") set the floor. Same failure family
   as the `min-width: auto` grid-item note in §2; house style is minmax(0,…). */
body[data-view="order-detail"] .od-facts {
  display: grid;
  grid-template-columns:
    minmax(0, 1.15fr) minmax(0, .92fr) minmax(0, .86fr) minmax(0, .86fr) minmax(0, 1.2fr);
  gap: 16px;
}
body[data-view="order-detail"] .od-fact { min-width: 0; }
body[data-view="order-detail"] .od-fact {
  display: flex;
  flex-direction: column;
  min-height: 108px;
  padding: 15px 17px 16px;
  border: 1px solid var(--hair);
  border-bottom-color: #E3E3DF;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05),
    inset 0 1px 0 rgba(255, 255, 255, .9);
}
body[data-view="order-detail"] .od-fact > span {
  display: block;
  color: var(--navy);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 1.15px;
  text-transform: uppercase;
}
/* the figure row sits on the baseline of the tile, so five tiles with
   different label lengths still line their numbers up */
body[data-view="order-detail"] .od-figure {
  display: flex;
  align-items: center;
  gap: 11px;
  margin-top: auto;
  padding-top: 13px;
  min-width: 0;
}
body[data-view="order-detail"] .od-figure > div { min-width: 0; }
body[data-view="order-detail"] .od-fact strong {
  display: block;
  overflow: hidden;
  color: var(--navy);
  font-size: 21px;
  font-weight: 620;
  letter-spacing: -.5px;
  line-height: 1.1;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}
body[data-view="order-detail"] .od-fact small {
  display: block;
  margin-top: 5px;
  color: #A6A6A1;
  font-size: 10.5px;
}
/* the money tile is the page's headline figure — report 13 */
body[data-view="order-detail"] .od-fact.is-money strong { font-size: 25px; letter-spacing: -.9px; }
body[data-view="order-detail"] .od-fact.is-money small b { color: #56575A; font-weight: 650; }

/* the tile's subject, in the same recessed square the KPI tiles use */
body[data-view="order-detail"] .od-fact-ic {
  margin-left: auto;
  flex: 0 0 32px;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 10px;
  color: #8E8F92;
  background: linear-gradient(180deg, #F7F8F9, #F1F2F3);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(19, 25, 33, .045);
}
body[data-view="order-detail"] .od-fact-ic svg.ic { display: block; width: 17px; height: 17px; stroke-width: 1.7; }

/* the marketplace tile carries its own identity mark instead of a line icon,
   exactly as an orders.html row does — the mark IS the subject there */
body[data-view="order-detail"] .od-fact .mk { margin-left: auto; }
body[data-view="order-detail"] .od-fact strong.is-name { font-size: 16px; letter-spacing: -.2px; }

/* entity route: two flags, because this tile's whole content is a corridor */
body[data-view="order-detail"] .od-route-flags {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  color: #C2C2BD;
  font-size: 12px;
}
body[data-view="order-detail"] .od-route-flags .flag { width: 22px; height: 22px; flex: 0 0 22px; }

/* ---------- 16.2 Product cover ---------- */
/* Was a 38px grey square holding a generic line icon — smaller than the icon
   squares in the tiles beside it, so the one concrete thing on the page read
   as an afterthought. A cover makes the record a thing rather than a row. */
body[data-view="order-detail"] .od-product { align-items: flex-start; gap: 16px; }
body[data-view="order-detail"] .od-cover {
  flex: 0 0 62px;
  width: 62px;
  height: 78px;
  border-radius: 4px 7px 7px 4px;
  overflow: hidden;
  box-shadow:
    0 1px 2px rgba(19, 25, 33, .10),
    0 6px 14px rgba(19, 25, 33, .10);
}
body[data-view="order-detail"] .od-cover svg { display: block; width: 100%; height: 100%; }
body[data-view="order-detail"] .od-product > div { padding-top: 6px; }
body[data-view="order-detail"] .od-product strong { font-size: 15px; }
body[data-view="order-detail"] .od-product-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 9px;
  color: #A6A6A1;
  font-size: 11.5px;
}
body[data-view="order-detail"] .od-product-meta .flag { width: 17px; height: 17px; flex: 0 0 17px; }
body[data-view="order-detail"] .od-product-meta i {
  width: 1px; height: 11px; background: var(--hair); font-style: normal;
}

/* ---------- 16.3 Journey rail earns its height ---------- */
/* The card was 172px carrying 74px of content: the band above the nodes was
   empty. On index.html the identical rail puts a figure there. Here the
   figure is the timestamp — so the rail reads as a chronology, and "when did
   this order actually move" is answerable without opening the audit trail. */
/* Scaled up 2026-07-29 (Gaurav: "make this section visible and bold and
   increase the font size and icon size slightly"). The rail is the spine of
   the page and it was reading as the quietest thing on it — 11.5px labels
   under 10.5px subs, all in mid-grey. Type is up one step of the §19 scale
   (11.5 → 13.5 body, 10.5 → 11.5 sub, 12 → 13.5 date), nodes 33 → 38px with
   17px icons, and the three states now separate on colour rather than only
   on a ring: done = navy, current = blue, still-to-come stays grey.
   Weights stop at 650 — §7's cap. */
body[data-view="order-detail"] .od-steps { padding-top: 18px; }
body[data-view="order-detail"] .od-step-when {
  display: block;
  height: 19px;
  color: #A6A6A1;
  font-size: 13.5px;
  font-weight: 650;
  line-height: 19px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
body[data-view="order-detail"] .od-steps li.done .od-step-when { color: #56575A; }
body[data-view="order-detail"] .od-steps li.current .od-step-when { color: var(--blue-deep); }

/* bigger node, and the icon grows with it so the glyph keeps its optical
   weight inside the circle rather than swimming in it */
body[data-view="order-detail"] .od-step-node { width: 38px; height: 38px; }
body[data-view="order-detail"] .od-step-node svg.ic { width: 17px; height: 17px; stroke-width: 1.9; }
body[data-view="order-detail"] .od-steps li.done .od-step-node { color: #56575A; border-color: #CFCFC9; }
body[data-view="order-detail"] .od-steps li.current .od-step-node { box-shadow: 0 0 0 5px rgba(43, 124, 216, .09); }

body[data-view="order-detail"] .od-step-copy strong { font-size: 13.5px; font-weight: 650; }
body[data-view="order-detail"] .od-step-copy small { margin-top: 5px; font-size: 11.5px; }
body[data-view="order-detail"] .od-steps li.done .od-step-copy strong { color: var(--navy); }
body[data-view="order-detail"] .od-steps li.done .od-step-copy small { color: #A6A6A1; }

/* Rows must stay packed at the top. `.od-steps li` has three auto rows and
   the parent grid stretches every li to the tallest one — with the default
   align-content:stretch the spare height is shared between the rows, so a
   single two-line label in one column pushed that column's node ~5px down
   and off the connector. Only visible once labels started wrapping. */
body[data-view="order-detail"] .od-steps li { align-content: start; }

/* the connector carries structure now that the nodes are heavier; at --hair
   it disappeared between them */
body[data-view="order-detail"] .od-steps::before { background: #E3E3DF; }
/* node centre = 18 pad + 19 when-line + 10 grid gap + 19 half-node */
body[data-view="order-detail"] .od-steps::before { top: 66px; }

/* ---------- 16.3b The vertical route (§8's ≤840px rail) ---------- */
/* §8 turns the rail into a vertical route below 840px with a TWO-column li
   (33px node | copy). The date line is a third child, so in source order it
   took col 1 / row 1 and shoved the node into col 2 — and the node is 38px
   now, which a 33px column cannot hold. Re-place all three explicitly.
   The ::before overrides are not optional: these scoped selectors out-weigh
   §8's rules *inside its own media query* (media queries add no specificity),
   so without them the vertical line inherits top:66px / left:38px. */
@media (max-width: 840px) {
  /* padding restated deliberately: §16.7's horizontal-rail inset is fenced to
     ≥841px so it cannot reach here, but this rule is equally scoped and would
     silently win if that fence were ever removed. Keeping the value explicit
     means the vertical route cannot drift off its line again. */
  body[data-view="order-detail"] .od-steps li {
    grid-template-columns: 38px minmax(0, 1fr);
    padding: 8px 0;
  }
  body[data-view="order-detail"] .od-step-node { grid-column: 1; grid-row: 1 / span 2; align-self: start; }
  body[data-view="order-detail"] .od-step-when {
    grid-column: 2; grid-row: 1;
    height: auto; line-height: 1.35;
  }
  body[data-view="order-detail"] .od-step-copy { grid-column: 2; grid-row: 2; margin-top: 2px; }
  body[data-view="order-detail"] .od-steps::before {
    top: 20px; bottom: 35px;
    left: 41px; /* 22px padding + half of the 38px node */
    right: auto;
  }
}

/* the route label is a corridor — flag it, the same way a tracking row does */
body[data-view="order-detail"] .od-route-label {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
body[data-view="order-detail"] .od-route-label .flag { width: 17px; height: 17px; flex: 0 0 17px; }
body[data-view="order-detail"] .od-route-label em { font-style: normal; color: #C2C2BD; }

/* ---------- 16.4 Planned movement, flagged ---------- */
body[data-view="order-detail"] .od-route-map > div { position: relative; }
body[data-view="order-detail"] .od-route-map .flag {
  position: absolute;
  left: 15px;
  top: 13px;
  width: 15px;
  height: 15px;
  flex: 0 0 15px;
  box-shadow: 0 0 0 2px var(--surface);
}

/* ---------- 16.5 Purchase attempts: closed vs live ---------- */
/* Both attempts carried equal weight although one failed and is closed and
   one is the live record. Hierarchy comes from state, not decoration: a
   hairline state edge, and the closed attempt steps back rather than hiding.
   Exception 4 requires every PO to stay visible — this recedes, never folds. */
body[data-view="order-detail"] .od-attempt { position: relative; padding-left: 4px; }
body[data-view="order-detail"] .od-attempt::before {
  content: "";
  position: absolute;
  left: -6px;
  top: 20px;
  bottom: 20px;
  width: 2px;
  border-radius: 2px;
  background: transparent;
}
body[data-view="order-detail"] .od-attempt.current::before { background: var(--series); }
body[data-view="order-detail"] .od-attempt.failed::before { background: #EDC7C6; }
body[data-view="order-detail"] .od-attempt.failed .od-attempt-grid strong { color: #7A7B7E; font-weight: 600; }
body[data-view="order-detail"] .od-attempt.failed .od-po { color: #56575A; }
body[data-view="order-detail"] .od-attempt-grid strong { font-variant-numeric: tabular-nums; }
body[data-view="order-detail"] .od-attempt-closed {
  margin-left: 8px;
  color: #B4B4AF;
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: .5px;
  text-transform: uppercase;
}

/* ---------- 16.6 Economics waterfall ---------- */
/* The order's money story was five rows of 12.5px text. As a waterfall it
   also makes the footnote visible: the running balance genuinely dips to
   −250 before the vendor refund lands, which is precisely the downside the
   note describes in words. One hue plus grey — the bars are ordered stages
   of one running total, not categories, so §7's one-data-hue rule holds. */
body[data-view="order-detail"] .od-wf { position: relative; padding: 4px 22px 2px; }
/* the zero line, drawn once behind every track */
body[data-view="order-detail"] .od-wf::before {
  content: "";
  position: absolute;
  top: 8px;
  bottom: 10px;
  left: calc(22px + var(--zero) * (100% - 44px));
  width: 1px;
  /* a shade darker than --hair: this is an axis, not a divider, and at
     --hair it was invisible against the bars it exists to give meaning to */
  background: #DCDCD8;
}
body[data-view="order-detail"] .od-wf-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 3px 10px;
  padding: 9px 0;
  border-top: 1px solid var(--hair-soft);
}
body[data-view="order-detail"] .od-wf-row:first-child { border-top: 0; }
body[data-view="order-detail"] .od-wf-label {
  min-width: 0;
  overflow: hidden;
  color: #56575A;
  font-size: 11.5px;
  white-space: nowrap;
  text-overflow: ellipsis;
}
body[data-view="order-detail"] .od-wf-label em { font-style: normal; color: #A6A6A1; }
body[data-view="order-detail"] .od-wf-amt {
  color: #56575A;
  font-size: 11.5px;
  font-weight: 620;
  font-variant-numeric: tabular-nums;
}
body[data-view="order-detail"] .od-wf-track {
  position: relative;
  grid-column: 1 / -1;
  height: 9px;
  margin-top: 3px;
}
body[data-view="order-detail"] .od-wf-track i {
  position: absolute;
  top: 0;
  height: 9px;
  border-radius: 2px;
  background: #D2D2CD;
}
body[data-view="order-detail"] .od-wf-row.is-in i { background: var(--series); }
/* money that is not yet real reads as an outline, never a fill — the same
   convention the pending refund takes in the ledger below it */
body[data-view="order-detail"] .od-wf-row.is-pending i {
  background: transparent;
  border: 1px dashed #C8C8C3;
}
body[data-view="order-detail"] .od-wf-row.is-pending .od-wf-label,
body[data-view="order-detail"] .od-wf-row.is-pending .od-wf-amt { color: #A6A6A1; }
body[data-view="order-detail"] .od-wf-row.is-total {
  margin-top: 2px;
  padding-top: 12px;
  border-top: 1px solid var(--hair);
}
body[data-view="order-detail"] .od-wf-row.is-total .od-wf-label { color: var(--navy); font-weight: 620; font-size: 12px; }
body[data-view="order-detail"] .od-wf-row.is-total .od-wf-amt { color: var(--navy); font-size: 16px; font-weight: 650; }
/* the deepest step of the one blue ramp, not black — the total is the sum of
   the story the bars above tell, so it stays inside the data hue */
body[data-view="order-detail"] .od-wf-row.is-total i { background: var(--blue-deep); }
body[data-view="order-detail"] .od-wf-row.is-total.is-short .od-wf-amt { color: var(--critical); }
body[data-view="order-detail"] .od-wf-row.is-total.is-short i { background: var(--critical); }
/* the floor marker: where the balance sits if the refund is declined */
body[data-view="order-detail"] .od-wf-floor {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin: 10px 22px 0;
  padding-top: 10px;
  border-top: 1px dashed var(--hair);
  color: #A6A6A1;
  font-size: 10.5px;
  line-height: 1.5;
}
body[data-view="order-detail"] .od-wf-floor b { color: var(--critical); font-weight: 650; }

/* ---------- 16.7 Folds ---------- */
/* §8 folded .od-layout at 1120 while the fact strip folds at 1240, so between
   those two widths the left column kept its 1.6fr share and the Details card's
   three groups were crushed to ~260px each — "Amazon UAE SG (S-Amazon)" broke
   over four lines. The two folds now happen together. Scoped, so §8's shared
   thresholds are untouched for anything else that uses them. */
/* Five tiles stop being comfortable well before the layout folds, so the
   strip drops to three of its own accord at 1360 rather than being squeezed
   down to 1240. The layout fold stays at 1240 — it is there for the Details
   card, not for the tiles, and the two no longer need to agree. */
@media (max-width: 1360px) {
  body[data-view="order-detail"] .od-facts { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* five tiles into three columns leaves a hole on row 2; the money tile —
     the one that earns extra width anyway — closes it */
  body[data-view="order-detail"] .od-fact.is-money { grid-column: span 2; }
}
/* min-width guards the horizontal rail only: below 841px §8 turns the rail
   vertical, and this 5px inset would otherwise beat §8's own `padding: 8px 0`
   (it is scoped, so it wins on specificity) and push every node off the line. */
/* 1400, not 1300: the scaled-up labels start colliding around 1360, so the
   wrap has to be armed above where the collision begins. Measured — 1370 is
   clear, 1360 is not. */
@media (min-width: 841px) and (max-width: 1400px) {
  /* seven nowrap sub-labels collide before the layout folds: "stock checked ·
     PO-IN-88437" ran straight through "Marol · inscanned". Wrapping is the
     fix — the rail stays horizontal, the labels just take two lines. */
  body[data-view="order-detail"] .od-step-copy strong,
  body[data-view="order-detail"] .od-step-copy small { white-space: normal; }
  /* the date line stays nowrap on purpose: it sits above the nodes and its
     height is what positions the connector (::before top: 66px). Let it wrap
     to two lines and the rail detaches from the circles. The strings are
     short enough ("EDD 18 Aug" is the longest) that it never needs to. */
  body[data-view="order-detail"] .od-steps li { padding: 0 5px; }
}
@media (max-width: 1240px) {
  body[data-view="order-detail"] .od-layout { grid-template-columns: minmax(0, 1fr); }
  body[data-view="order-detail"] .od-secondary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  body[data-view="order-detail"] .od-activity { grid-column: 1 / -1; }
}
@media (max-width: 820px) {
  body[data-view="order-detail"] .od-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  body[data-view="order-detail"] .od-cover { flex-basis: 52px; width: 52px; height: 66px; }
}

/* the floor note's icon, scoped like every other per-context icon size */
body[data-view="order-detail"] .od-wf-floor svg.ic {
  width: 13px; height: 13px; stroke-width: 1.7; color: #C2C2BD;
}
body[data-view="order-detail"] .od-wf-floor > span:first-child { flex: 0 0 13px; line-height: 1; }

/* ---------- 15.6 Icons, 2026-07-29 ---------- */
/* Gaurav: "make it visually more appealing and add icons", and remove both the
   "Purchase window" heading block and the toolbar's date + "12 orders need a
   decision now" line. Those two removals are why the tile icons matter: with
   the heading gone the strip has to name itself, so each bucket carries a mark
   in the dashboard's own recessed square (§7.4 .kpi-ic, same geometry). The
   icons read as a time progression — breach, clock, one day, a range, archive.
   Feather stroke paths only; no emoji anywhere in this deck (see §19). */
body[data-page="orders"] .w-figure {
  display: flex; align-items: center; gap: 12px;
  margin-top: auto; padding-top: 14px;
}
body[data-page="orders"] .w-figure .w-val { margin-top: 0; padding-top: 0; }
body[data-page="orders"] .w-ic {
  margin-left: auto; flex: 0 0 34px;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 11px; color: #8E8F92;
  background: linear-gradient(180deg, #F7F8F9, #F1F2F3);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(19, 25, 33, .045);
  transition: color .18s, background .18s;
}
body[data-page="orders"] .w-ic svg.ic { display: block; width: 18px; height: 18px; stroke-width: 1.7; }
/* only a genuine breach recolours the square — same rule the KPI tiles follow */
body[data-page="orders"] .wcell:first-child .w-ic {
  color: var(--critical);
  background: linear-gradient(180deg, #FDF3F3, #FBEBEB);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(197, 34, 31, .09);
}
body[data-page="orders"] .wcell:hover .w-ic { color: var(--navy); }
body[data-page="orders"] .wcell:first-child:hover .w-ic { color: var(--critical); }

/* toolbar is actions-only now, so it needs a left anchor — the link the
   removed heading used to carry, at link weight rather than button weight.
   Left UNSCOPED: purchase.html reuses both of these (§16), and duplicating
   them per page is how the pre-v3 hand-written counts drifted. Checked
   against every inline <style> block in the deck before taking the names —
   see the `.chip` incident in §14. */
.tool-link {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 600; color: #7A7B7E;
}
.tool-link:hover { color: var(--orange); }
.tool-link svg.ic { width: 14px; height: 14px; }

/* leading affordances for the filter / sort control clusters */
.f-ic { display: grid; place-items: center; color: #C2C2BD; }
.f-ic svg.ic { width: 14px; height: 14px; }
.f-ic:first-child { margin-left: 6px; margin-right: 2px; }

/* the §9.5 rule, now the only prose on the page — icon and text align on the
   first line rather than the icon centring against a two-line wrap */
body[data-page="orders"] .rail-note {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 16px 2px 0;
}
body[data-page="orders"] .rail-note svg.ic {
  width: 14px; height: 14px; flex: 0 0 14px; margin-top: 2px; color: #C2C2BD;
}

/* ============================================================
   16. Purchase page — §15 applied, 2026-07-29
   ------------------------------------------------------------
   Gaurav: "now do the same for the purchase page". Same brief as
   §15 and the same constraint — the flags, monograms and source
   tags all stay. Measured, this page was the denser of the two:
   57 elements per row against orders' 43, and TEN elements at
   weight >= 600.

   The weight census is what drove the edit. Three of those bolds
   are small-caps label chips (.o-mod 9.5px, .tag 11px, .dl-k
   9.5px uppercase) and one is the monogram letter — those read
   as labels and decor, not emphasis, so they stay. What was
   actually competing were the four body-size 600/650 runs, which
   meant the row had no entry point.

   The KPI strip needed nothing: it already uses the global .kpi,
   so it inherited the dashboard tiles when §7.4 landed.
   ============================================================ */

/* ---------- 16.1 The trailing-unit bug (global, not scoped) ---------- */
/* .kpi .value .unit was written for a LEADING unit — the dashboard's
   "AED 48.3k" — so it carries margin-right and no margin-left. purchase.html
   uses TRAILING units ("85%", "4h 06m"), which left the unit jammed against
   the digits (made worse by the value's -1.1px tracking) and a stray 5px gap
   hanging off the end.

   This needs an explicit modifier, NOT a positional selector. The first
   attempt was `.unit:not(:first-child)` and it only fixed the "m" of
   "4h 06m": :first-child counts ELEMENT children, and the digits ("85", "4")
   are text nodes — so the "%" and the "h" both still matched :first-child.
   No structural selector can see the difference, because the thing that
   distinguishes leading from trailing is a text node. Hence `.unit.post`,
   which also documents itself at the call site. */
.kpi .value .unit.post { margin-right: 0; margin-left: 2.5px; }

/* ---------- 16.2 Row air ---------- */
/* Vertical only — §9's 1296px budget needed three squeezes to land and the
   11px horizontal gutters are load-bearing. Do not widen these. */
body[data-page="purchase"] table.data.otable th,
body[data-page="purchase"] table.data.otable td { padding-top: 15px; padding-bottom: 15px; }
body[data-page="purchase"] table.data.otable th { padding-top: 13px; padding-bottom: 11px; }

/* ---------- 16.3 One bold per row ---------- */
/* The order ID keeps 600 as the thing you click. The marketplace name and the
   offer seller step back to 500 keeping their ink colour; the margin figure
   and the deadline drop 650 -> 600, since colour already carries both (green
   / red margin, red on an actual breach). Net effect is the same as §15.4:
   the flag becomes the brightest mark in the row. */
body[data-page="purchase"] .o-mp-name b,
body[data-page="purchase"] .p-offer-t b { font-weight: 500; }
body[data-page="purchase"] .econ b,
body[data-page="purchase"] .dl-v { font-weight: 600; }
body[data-page="purchase"] .dl.breach .dl-v { font-weight: 650; }

/* ---------- 16.4 Filter row — chrome down, controls kept ---------- */
body[data-page="purchase"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-page="purchase"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-page="purchase"] .filters select:hover {
  border-color: var(--hair); background-color: var(--surface);
}
body[data-page="purchase"] .filters select:focus {
  border-color: var(--blue); background-color: #fff;
}
body[data-page="purchase"] .fsearch { background: transparent; border-color: var(--hair-soft); }
body[data-page="purchase"] .fsearch:hover { border-color: var(--hair); }
body[data-page="purchase"] .fsearch:focus-within { background: var(--surface); }

/* ---------- 16.5 Engine line ---------- */
/* Was a bare text run floating under the meter; it now sits on a hairline so
   the card ends on a rule rather than trailing off. Deliberately gets NO
   icon — .engine::before is already a green status dot and §7 defines status
   as a dot + text, so an icon here would be a second mark for one signal. */
body[data-page="purchase"] .engine {
  display: flex; align-items: center; gap: 8px;
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--hair-soft);
}

/* ============================================================
   17. QC / Inscan — visual pass (2026-07-29)
   ------------------------------------------------------------
   Same diagnosis as §16 on order-detail, different symptoms.
   The KPI strip was already the §7.4 raised recipe, and both
   grids were already perfectly balanced (0px), so the work here
   is the other two findings: the QC clock rail was flat divider
   columns inside a .card — a box inside a box, directly below a
   strip of raised tiles doing the same "five counts" job — and
   the page carried ZERO flags while naming eleven countries in
   plain text across its two analytics cards.

   Everything is scoped to body[data-page="qc"]. .wcell and
   .window-rail are shared with tracking / purchase / IRA, whose
   flat treatment and column budgets were measured to the pixel.
   ============================================================ */

/* ---------- 17.1 QC clock as a raised tile strip ---------- */
/* §15.1's recipe, applied to this page's five buckets. The sequential blue
   ramp per bucket is untouched — it is still what separates them. */
body[data-page="qc"] .sec-head {
  display: flex; align-items: baseline; gap: 9px;
  padding: 0 2px 14px;
}
body[data-page="qc"] .sec-head h2 {
  margin: 0; font-size: 14px; font-weight: 650; letter-spacing: -.05px; color: var(--navy);
}
body[data-page="qc"] .sec-head .sub { font-size: 12.5px; font-weight: 500; color: #A6A6A1; }
body[data-page="qc"] .sec-head .sub::before { content: "·"; margin-right: 8px; color: #CFCFCA; }
body[data-page="qc"] .sec-head .spacer { flex: 1; }
body[data-page="qc"] .sec-head a:not(.btn) { font-size: 12.5px; font-weight: 600; color: #7A7B7E; }
body[data-page="qc"] .sec-head a:not(.btn):hover { color: var(--orange); }

body[data-page="qc"] .window-rail {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 16px;
}
body[data-page="qc"] .wcell {
  display: flex; flex-direction: column;
  min-height: 126px; padding: 17px 18px 18px;
  border: 1px solid var(--hair); border-bottom-color: #E3E3DF;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), border-color .18s;
}
body[data-page="qc"] .wcell:hover {
  transform: translateY(-2px); border-color: #DCDCD7;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 4px 8px rgba(19, 25, 33, .05),
    0 14px 28px rgba(19, 25, 33, .08),
    inset 0 1px 0 rgba(255, 255, 255, .9);
}
body[data-page="qc"] .wcell:active { transform: translateY(0); }
/* an inset ring, not an underline — an inset bar clips against the radius */
body[data-page="qc"] .wcell.active {
  border-color: transparent;
  box-shadow:
    inset 0 0 0 1.5px var(--orange),
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05);
}
/* figure pushed to the bottom so five tiles with different sub-line lengths
   still align their numbers */
body[data-page="qc"] .w-val {
  margin-top: auto; padding-top: 14px;
  font-size: 30px; font-weight: 600; letter-spacing: -1.1px;
}
body[data-page="qc"] .w-sub { margin-top: 7px; }

/* ---------- 17.2 Flags on the geography ---------- */
/* Eleven country names were set as plain text. .meters .m-name .flag already
   sizes them (§10, added for the tracking carrier scorecard) — the meters
   were built to take flags, this page simply never passed any. */
body[data-page="qc"] .meters .m-name { display: inline-flex; align-items: center; gap: 8px; }

/* queue Source cell: flag outside .o-loc, since .o-loc blocks its children */
body[data-page="qc"] .q-src { display: flex; align-items: flex-start; gap: 9px; }
body[data-page="qc"] .q-src .flag { width: 17px; height: 17px; flex: 0 0 17px; margin-top: 1px; }

/* the warehouse scope in the toolbar */
body[data-page="qc"] .qc-scope-flag { width: 19px; height: 19px; flex: 0 0 19px; margin-right: -3px; }

/* ---------- 17.3 The bench ---------- */
/* The bench is this page's spine — the thing an inspector actually works in.
   The expected item now shows a cover, because QC is a visual comparison and
   "expected contents" that you cannot see is a weaker instruction. */
/* fixed layout so the declared colgroup is honoured; cells wrap rather than
   pushing the verdict buttons out of reach */
body[data-page="qc"] .bench-table { table-layout: fixed; }
/* 13px gutters (§8's table convention) rather than the default 20px. At 20px
   the Mark cell had 285px of inner width for four verdict chips needing 290 —
   "Short" wrapped to its own line by five pixels. Narrowing the gutters gives
   back 14px per cell without shrinking a single control. */
body[data-page="qc"] .bench-table td,
body[data-page="qc"] .bench-table th {
  padding-left: 13px; padding-right: 13px;
  overflow-wrap: break-word;
}
/* headers wrap instead of truncating — at several widths the fixed columns
   clipped "Expected" / "Received" to "EXPECTE" / "RECEIVE" */
body[data-page="qc"] .bench-table th { white-space: normal; }
/* last-resort safety: if the Mark column is ever squeezed further (a narrow
   card once the grid folds), the four verdicts stack instead of overflowing */
body[data-page="qc"] .qmark { flex-wrap: wrap; }

body[data-page="qc"] .q-expected { display: flex; align-items: center; gap: 12px; }
body[data-page="qc"] .q-cover {
  flex: 0 0 38px; width: 38px; height: 48px;
  border-radius: 3px 5px 5px 3px; overflow: hidden;
  box-shadow: 0 1px 2px rgba(19, 25, 33, .10), 0 4px 10px rgba(19, 25, 33, .09);
}
body[data-page="qc"] .q-cover svg { display: block; width: 100%; height: 100%; }
body[data-page="qc"] .q-expected .o-item b { font-size: 13.5px; }

/* the over-SLA clock is the most time-critical fact on the page */
body[data-page="qc"] .bench-due { font-size: 12.5px; }
body[data-page="qc"] .bench-due b { font-size: 13px; }

/* ---------- 17.4 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="qc"] .window-rail { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-page="qc"] .window-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  body[data-page="qc"] .sec-head { flex-wrap: wrap; }
  body[data-page="qc"] .sec-head .sub::before { content: none; }
  body[data-page="qc"] .q-cover { flex-basis: 34px; width: 34px; height: 43px; }
}

/* ============================================================
   18. Dispatch — visual pass (2026-07-29)
   ------------------------------------------------------------
   Same diagnosis again, and this page was the furthest behind:
   it still carried the pre-v3 breadcrumb head, KPI tiles with
   sub-lines and no icon square, five orange filled buttons (four
   of them inside rows and cards), and zero flags on a page whose
   entire subject is where a parcel is going.

   Scoped to body[data-page="dispatch"]. .kpi / .kpis / .toolbar
   are shared with every v3 page.
   ============================================================ */

/* ---------- 18.1 Five tiles, not six ---------- */
/* the inline style="grid-template-columns:repeat(5,1fr)" is gone from the
   markup — bare `fr` has a min-content floor, the same trap §16.1 hit */
body[data-page="dispatch"] .kpis {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

/* ---------- 18.2 Destination as a flagged cell ---------- */
/* This page's subject is where a parcel goes, and every destination was set
   as plain text. Riyadh / Dubai / Sydney / Mexico City now read as places. */
body[data-page="dispatch"] .d-dest {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  min-width: 0;
}
body[data-page="dispatch"] .d-dest > .flag {
  width: 18px; height: 18px; flex: 0 0 18px;
  margin-top: 1px;
}
body[data-page="dispatch"] .d-dest > span { min-width: 0; }
body[data-page="dispatch"] .d-dest .sub {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 3px;
  color: #ADADA8;
  font-size: 11px;
  font-weight: 500;
}
/* the marketplace panel's own flag, inside the sub-line — smaller than the
   destination flag so the two never read as equals, but not below 15px:
   at 13px the JP flag (a red disc on white) reads as a §7 status dot. */
body[data-page="dispatch"] .d-panel.flag {
  width: 15px; height: 15px; flex: 0 0 15px;
}

/* the Break Bulk lane on each builder card */
body[data-page="dispatch"] .d-lane {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
body[data-page="dispatch"] .d-lane .flag { width: 16px; height: 16px; flex: 0 0 16px; }

/* ---------- 18.3 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="dispatch"] .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-page="dispatch"] .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}


/* ============================================================
   19. Inventory — §15 applied, 2026-07-29
   ------------------------------------------------------------
   Gaurav: "look at orders.html, make inventory the same way —
   minimalist and elegant."

   Measured first, as on every one of these passes, and this
   page came back with its own shortfall rather than orders'.
   It was still pre-v3 at the top — a breadcrumb .page-head, KPI
   tiles carrying sub-lines and no icon square — and it named
   SIX warehouses and eleven locations in plain text while
   carrying zero flags. Same diagnosis as dispatch (§18): a page
   whose entire subject is WHERE stock sits, set as prose.

   It also had no rail, which every other working page has, and
   its Ageing tab opened with four flat .kpi tiles that said
   exactly what a rail would say — so the rail is not an
   addition here, it is those four tiles moved to the top of
   the page and given a job (see the app.js note on INV_AGE).

   Nothing decorative is removed. Scoped to
   body[data-page="inventory"] throughout: .kpi, .wcell,
   .window-rail, .filters and the §13 column budget are shared
   with orders / purchase / tracking / qc / ira / dispatch,
   whose tables were measured to the pixel.
   ============================================================ */

/* ---------- 19.1 Ageing as the dashboard's tile strip ---------- */
/* §15.1's recipe verbatim — contact + ambient + cast shadow, inner top
   highlight, darker bottom edge — so the rail and the KPI strip above it
   read as one system rather than two component languages. Four buckets
   here, not five: ageing is 0–30 / 31–60 / 61–90 / 90+ and inventing a
   fifth to match the orders grid would be decoration standing in for data. */
body[data-page="inventory"] .window-rail {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}
body[data-page="inventory"] .wcell {
  display: flex; flex-direction: column;
  min-height: 126px; padding: 17px 18px 18px;
  border: 1px solid var(--hair); border-bottom-color: #E3E3DF;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), border-color .18s;
}
body[data-page="inventory"] .wcell:hover {
  transform: translateY(-2px); border-color: #DCDCD7;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 4px 8px rgba(19, 25, 33, .05),
    0 14px 28px rgba(19, 25, 33, .08),
    inset 0 1px 0 rgba(255, 255, 255, .9);
}
body[data-page="inventory"] .wcell:active { transform: translateY(0); }
/* an inset ring, not §8's inset underline — a bar clips against the radius */
body[data-page="inventory"] .wcell.active {
  border-color: transparent;
  box-shadow:
    inset 0 0 0 1.5px var(--orange),
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05);
}
body[data-page="inventory"] .w-figure {
  display: flex; align-items: center; gap: 12px;
  margin-top: auto; padding-top: 14px;
}
body[data-page="inventory"] .w-val {
  margin-top: 0; padding-top: 0;
  font-size: 30px; font-weight: 600; letter-spacing: -1.1px;
}
body[data-page="inventory"] .w-sub { margin-top: 7px; }

/* §15.6's recessed square, same geometry as .kpi-ic. The icons read as the
   ageing progression itself — still turning, watch it, slowing, dead. */
body[data-page="inventory"] .w-ic {
  margin-left: auto; flex: 0 0 34px;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 11px; color: #8E8F92;
  background: linear-gradient(180deg, #F7F8F9, #F1F2F3);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(19, 25, 33, .045);
  transition: color .18s, background .18s;
}
body[data-page="inventory"] .w-ic svg.ic { display: block; width: 18px; height: 18px; stroke-width: 1.7; }
/* scoped to .is-dead, NOT :first-child as on orders — here the breach is the
   LAST bucket, because ageing runs the other way round from a purchase window */
body[data-page="inventory"] .wcell.is-dead .w-ic {
  color: var(--critical);
  background: linear-gradient(180deg, #FDF3F3, #FBEBEB);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(197, 34, 31, .09);
}
body[data-page="inventory"] .wcell:hover .w-ic { color: var(--navy); }
body[data-page="inventory"] .wcell.is-dead:hover .w-ic { color: var(--critical); }

/* the rule under the rail, §15.6's rail-note treatment */
body[data-page="inventory"] .rail-note {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 16px 2px 0;
}
body[data-page="inventory"] .rail-note svg.ic {
  width: 14px; height: 14px; flex: 0 0 14px; margin-top: 2px; color: #C2C2BD;
}

/* ---------- 19.2 Five tiles ---------- */
/* was six with a DEAD STOCK tile — the 90+ bucket in the rail carries that
   figure with an ageing window attached, so the tile was the duplication
   §15 exists to remove. bare `fr` avoided: min-content floor (§16.1). */
body[data-page="inventory"] .kpis {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

/* ---------- 19.3 Warehouse as a flagged cell ---------- */
/* Eleven place names set as plain text on the one page that is entirely
   about place. Same fix as §18.2 on dispatch. This is decor doing work:
   Marol / UAE / KSA / Amazon US FBA are now distinguishable at a glance
   down the column, which is how anyone actually reads a stock table. */
/* 16px + a 7px gap, not §18.2's 18 + 9. That is 4px, and 4px is the whole
   argument: "Marol godown" needs 92px and the cell leaves 89 at 18 + 9, so
   the most common warehouse in the deck wrapped onto two lines in every
   table. 16px still reads as a flag at this type size — dispatch already
   runs a 15px one — and nothing here is a status dot it could be confused
   with, since §7 dots are 6px. */
body[data-page="inventory"] .inv-loc {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  min-width: 0;
}
body[data-page="inventory"] .inv-loc > .flag {
  width: 16px; height: 16px; flex: 0 0 16px;
  margin-top: 1px;
}
/* .o-loc-style stacking is NOT used here — a flag inside a container whose
   children are all display:block drops onto its own row (the qSource() trap
   from §17). The text wrapper is the block, the flag sits outside it. */
/* flex: 1 1 auto, not the default 0 1 auto — as a max-content flex item the
   text span sized itself to 76px inside a 90px track and wrapped "Marol
   godown" onto two lines with 14px of the cell sitting empty beside it.
   Letting it take the remaining space puts every short name on one line and
   still wraps the genuinely long ones ("Amazon US IGECOM FBA"). */
body[data-page="inventory"] .inv-loc > span { flex: 1 1 auto; min-width: 0; }
body[data-page="inventory"] .inv-loc .sub { display: block; margin-top: 3px; }

/* ---------- 19.4 Filter row — chrome down, not controls out ---------- */
body[data-page="inventory"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-page="inventory"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-page="inventory"] .filters select:hover {
  border-color: var(--hair); background-color: var(--surface);
}
body[data-page="inventory"] .filters select:focus {
  border-color: var(--blue); background-color: #fff;
}
body[data-page="inventory"] .filters input:not([type="checkbox"]) {
  border-color: var(--hair-soft); background: transparent;
}
body[data-page="inventory"] .filters input:not([type="checkbox"]):hover { border-color: var(--hair); }
body[data-page="inventory"] .filters input:not([type="checkbox"]):focus { background: var(--surface); }

/* ---------- 19.5 Row air ---------- */
/* Vertical only. §13 fixed this page's column budget to the pixel with a
   declared <colgroup> per table; touching the horizontal gutters re-cuts it. */
body[data-page="inventory"] table.data th,
body[data-page="inventory"] table.data td { padding-top: 15px; padding-bottom: 15px; }
body[data-page="inventory"] table.data th { padding-top: 13px; padding-bottom: 11px; }

/* ---------- 19.6 One bold per row ---------- */
/* The Master SKU is the thing you click; it keeps its weight. The identifier
   columns beside it (source PO, dates, quantities) were all set in the same
   600-weight .num, so the row had five equal entry points and no first one.
   §7: size and colour carry hierarchy, weight does not stack on top. */
body[data-page="inventory"] table.data td.num { font-weight: 600; color: var(--navy); }
body[data-page="inventory"] table.data td.num.soft { font-weight: 500; color: #7A7B7E; }
body[data-page="inventory"] table.data td.right.num { font-weight: 550; }
body[data-page="inventory"] table.data td.right.num b { font-weight: 650; }

/* the footer line under the ageing table — honest about what a mock loads */
body[data-page="inventory"] .inv-foot {
  padding: 13px 20px 15px; border-top: 1px solid var(--hair-soft);
  color: #A6A6A1; font-size: 11.5px; font-weight: 500;
}

/* ---------- 19.7 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="inventory"] .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  body[data-page="inventory"] .window-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-page="inventory"] .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  body[data-page="inventory"] .window-rail { gap: 12px; }
}

/* ============================================================
   19. Reconciliation — §15 applied, 2026-07-29
   ------------------------------------------------------------
   Gaurav: "look at orders.html — make recon minimalist and
   elegant like it." Measured against orders/index at 1600px the
   shortfall was a different one again, which is why every page
   gets diagnosed rather than have components copied onto it:

     · 0 flags and 0 marketplace marks, on a page that names four
       warehouses and six selling accounts in plain text — the
       same finding as §16 (order detail) and §17 (QC).
     · a .page-head breadcrumb, when the sidebar already lights
       the active nav item and the topbar already prints the
       page title: three statements of "you are here".
     · six KPI tiles of which FOUR restate a tab count exactly
       (1,412 / 3 / 5 / 1). That is the precise flaw §8 removed
       from the pre-v3 orders page. The two that did NOT restate
       a tab — unexplained gaps and Amazon-lost — are already
       terms in the equation below them.
     · an equation strip of bordered boxes with an ORANGE-washed
       total and a green-washed gap, inside a card: a box inside
       a box, plus two §7 breaks in one component (orange is
       reserved for the active nav item and the primary button;
       nothing gets a fill behind text on a static surface).
     · 58px rows and 65 inline style attributes hand-painting
       tone that classes already carry.

   Scoped to body[data-page="recon"] throughout. .wcell,
   .window-rail, .kpi and table.data are shared with orders,
   purchase, tracking, qc, inventory and IRA, whose column
   budgets and flat/raised treatments were measured to the pixel.
   ============================================================ */

/* ---------- 19.1 Reconciliation state as the tile strip ---------- */
/* The KPI strip is gone and this replaces it, so the page opens on the
   dashboard's rhythm — toolbar → tiles → the working surface — with one
   strip instead of two. Unlike the old KPIs these buckets PARTITION the
   1,412 POs and scope the list below, which is what makes the orders rail
   work: the tile is a filter, not a restated count. §15.1's recipe verbatim. */
body[data-page="recon"] .window-rail {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 16px;
}
body[data-page="recon"] .wcell {
  display: flex; flex-direction: column;
  min-height: 126px; padding: 17px 18px 18px;
  border: 1px solid var(--hair); border-bottom-color: #E3E3DF;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), border-color .18s;
}
body[data-page="recon"] .wcell:hover {
  transform: translateY(-2px); border-color: #DCDCD7;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 4px 8px rgba(19, 25, 33, .05),
    0 14px 28px rgba(19, 25, 33, .08),
    inset 0 1px 0 rgba(255, 255, 255, .9);
}
body[data-page="recon"] .wcell:active { transform: translateY(0); }
/* an inset ring, not an underline — an inset bar clips against the radius */
body[data-page="recon"] .wcell.active {
  border-color: transparent;
  box-shadow:
    inset 0 0 0 1.5px var(--orange),
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05);
}
body[data-page="recon"] .w-val {
  margin-top: auto; padding-top: 14px;
  font-size: 30px; font-weight: 600; letter-spacing: -1.1px;
}
body[data-page="recon"] .w-sub { margin-top: 7px; }
/* §15.6's figure row + recessed icon square. The icons name the buckets, so
   no heading block sits above the strip — same trade orders made. */
body[data-page="recon"] .w-figure {
  display: flex; align-items: center; gap: 12px;
  margin-top: auto; padding-top: 14px;
}
body[data-page="recon"] .w-figure .w-val { margin-top: 0; padding-top: 0; }
body[data-page="recon"] .w-ic {
  margin-left: auto; flex: 0 0 34px;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 11px; color: #8E8F92;
  background: linear-gradient(180deg, #F7F8F9, #F1F2F3);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(19, 25, 33, .045);
  transition: color .18s, background .18s;
}
body[data-page="recon"] .w-ic svg.ic { display: block; width: 18px; height: 18px; stroke-width: 1.7; }
/* only the genuine breach recolours its square — the KPI tiles' own rule */
body[data-page="recon"] .wcell:first-child .w-ic {
  color: var(--critical);
  background: linear-gradient(180deg, #FDF3F3, #FBEBEB);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(197, 34, 31, .09);
}
body[data-page="recon"] .wcell:hover .w-ic { color: var(--navy); }
body[data-page="recon"] .wcell:first-child:hover .w-ic { color: var(--critical); }
/* Every bar here is a share of the SAME 1,412, which is the honest scale and
   also an awkward one: 1,396 POs balance, so the four exception buckets are
   0.1–0.4% and would paint sub-pixel. A floor keeps a non-zero bucket from
   rendering as an empty track — an exception that looks like nothing is the
   one thing this page must not do. Anything at exactly zero still shows
   nothing, because that difference is the whole point of the strip. */
body[data-page="recon"] .w-track i { min-width: 3px; }

/* ---------- 19.2 The equation ---------- */
/* Annexure A's core rule, and the reason the page exists. It was eight
   bordered boxes; boxes say "these are eight separate things" when the whole
   claim is that they are ONE equation that has to balance. So the terms are
   divider-separated columns (§7's KPI rule) with the operators standing in
   for the dividers — which is what an equation looks like written down, and
   the same argument that keeps the customs duty ladder from being a bar. */
body[data-page="recon"] .equation {
  display: flex; align-items: stretch; flex-wrap: wrap;
  padding: 4px 0 2px;
}
body[data-page="recon"] .eq-term {
  flex: 1 1 96px; min-width: 0;
  display: flex; flex-direction: column;
  padding: 0 14px;
}
body[data-page="recon"] .eq-k {
  font-size: 10.5px; font-weight: 600; letter-spacing: .55px;
  text-transform: uppercase; color: #A6A6A1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body[data-page="recon"] .eq-v {
  margin-top: auto; padding-top: 12px;
  font-size: 25px; font-weight: 600; letter-spacing: -.9px; color: var(--navy);
}
/* the total leads on size and ink, not on an orange wash */
body[data-page="recon"] .eq-term.total { flex-basis: 128px; padding-left: 0; }
body[data-page="recon"] .eq-term.total .eq-k { color: var(--ink-2); }
body[data-page="recon"] .eq-term.total .eq-v { font-size: 31px; letter-spacing: -1.2px; }
/* the component's share of the total — one hue, §7 */
body[data-page="recon"] .eq-share {
  display: block; height: 3px; margin-top: 11px;
  border-radius: 99px; background: var(--track); overflow: hidden;
}
body[data-page="recon"] .eq-share i {
  display: block; height: 100%; border-radius: 99px; background: var(--blue);
}
/* a zero component keeps its track and paints nothing — "Lost (Amazon) 0" is
   a result, and blanking the row would hide it */
body[data-page="recon"] .eq-term.is-zero .eq-v { color: #A6A6A1; }
body[data-page="recon"] .eq-op {
  display: grid; place-items: end center; padding: 0 0 26px;
  font-size: 15px; font-weight: 500; color: #C2C2BD;
}
/* the verdict. A dot + label, never a wash — §7 */
body[data-page="recon"] .eq-term.gap { flex-basis: 132px; padding-right: 0; }
body[data-page="recon"] .eq-gap {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: auto; padding-top: 12px;
  font-size: 25px; font-weight: 600; letter-spacing: -.9px; color: var(--good);
}
body[data-page="recon"] .eq-gap::before {
  content: ""; flex: 0 0 8px; width: 8px; height: 8px;
  border-radius: 50%; background: currentColor;
}
body[data-page="recon"] .eq-gap.is-open { color: var(--critical); }
body[data-page="recon"] .eq-note { margin-top: 18px; }

/* ---------- 19.3 Filter row — chrome down, not controls out ---------- */
body[data-page="recon"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-page="recon"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-page="recon"] .filters select:hover { border-color: var(--hair); background-color: var(--surface); }
body[data-page="recon"] .filters select:focus { border-color: var(--blue); background-color: #fff; }
body[data-page="recon"] .filters input[type="search"],
body[data-page="recon"] .filters input:not([type]) {
  border-color: var(--hair-soft); background: transparent;
}
body[data-page="recon"] .filters input:hover { border-color: var(--hair); }

/* ---------- 19.4 Row air ---------- */
/* Vertical air is §15.3's move. The horizontal change is the one §17.3 made
   for the QC bench: table.data's default 20px gutters left the SKU column
   115px of inner width for a 14-character Master SKU, so "INZ_B0BOOK7719"
   broke mid-token. Dropping to §8's 13px table convention returns 14px per
   cell and fixes it WITHOUT re-cutting a single §13 column width — the five
   tables still land at exactly 1292px inside a 1292px wrap. */
body[data-page="recon"] table.data th,
body[data-page="recon"] table.data td {
  padding: 15px 13px;
}
body[data-page="recon"] table.data th { padding-top: 13px; padding-bottom: 11px; }

/* the Annexure A rule — this page's equivalent of the §9.5 note under the
   orders rail, and the only prose above the working surface */
body[data-page="recon"] .rail-note {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 16px 2px 0;
}
body[data-page="recon"] .rail-note svg.ic {
  width: 14px; height: 14px; flex: 0 0 14px; margin-top: 2px; color: #C2C2BD;
}

/* ---------- 19.5 Flags and marks on the geography ---------- */
/* Four warehouses, seven purchase flows and six selling accounts were all
   plain text. renderMarks() hydrates data-flag / data-mk from the existing
   FLAGS / MARKETPLACES tables, so a static page carries them without pasting
   flag SVG into the markup (§16). */
body[data-page="recon"] .r-geo { display: flex; align-items: flex-start; gap: 9px; min-width: 0; }
body[data-page="recon"] .r-geo > .flag { width: 17px; height: 17px; flex: 0 0 17px; margin-top: 1px; }
body[data-page="recon"] .r-geo > span { min-width: 0; }
body[data-page="recon"] .r-geo b { display: block; font-weight: 500; color: var(--ink); }
body[data-page="recon"] .r-geo .sub { display: block; margin-top: 3px; }
/* the flow ordinal — a label, so it stays small-caps and never competes */
body[data-page="recon"] .r-ord {
  font-size: 10.5px; font-weight: 600; color: #B4B4AF; letter-spacing: .3px;
}
/* marketplace monogram + country badge, the .mk anatomy §7 already defines */
body[data-page="recon"] .r-acct { display: flex; align-items: center; gap: 9px; min-width: 0; }
body[data-page="recon"] .r-acct .mk { flex: 0 0 auto; }
body[data-page="recon"] .r-acct > span:last-child { min-width: 0; font-weight: 500; }

/* ---------- 19.6 One bold per row ---------- */
/* Every identifier, count and status was 600+, so nothing was primary. The
   PO is what you click, so it keeps its weight; the rest step back to 500
   and keep their ink colour (§15.4). Numbers lean on alignment and colour. */
body[data-page="recon"] table.data td.num { font-weight: 500; }
body[data-page="recon"] table.data td.po,
body[data-page="recon"] table.data td.po a { font-weight: 600; color: var(--navy); }
body[data-page="recon"] table.data td.po a:hover { color: var(--orange); }
/* a variance reads as a signed number, not as a bold slab: the sign and the
   colour already say it. Replaces 14 inline style="color:var(--…)" spans. */
body[data-page="recon"] .r-neg { color: var(--critical); font-weight: 600; }
body[data-page="recon"] .r-warn { color: var(--warn); font-weight: 600; }
body[data-page="recon"] .r-pos { color: var(--good); font-weight: 600; }

/* ---------- 19.7 Scope bar ---------- */
body[data-page="recon"] .scope-bar {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 20px; border-bottom: 1px solid var(--hair);
  background: var(--hair-soft);
  font-size: 12.5px; font-weight: 500; color: var(--ink-2);
}
body[data-page="recon"] .scope-bar b { font-weight: 650; color: var(--navy); }
body[data-page="recon"] .scope-bar .btn { margin-left: auto; }
/* [hidden] is a UA rule at the lowest specificity, so the display:flex above
   beat it and the empty bar painted as a grey strip under the tabs whenever
   nothing was scoped. Any class that sets display on an element the markup
   toggles with [hidden] has to say so. */
body[data-page="recon"] .scope-bar[hidden] { display: none; }

/* ---------- 19.8 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="recon"] .window-rail { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 1100px) {
  /* the equation wraps rather than crushing eight terms into 90px each; the
     operators stay with the term they precede because they are flex items in
     the same row, so a wrapped line still reads as "+ good + bad + transit" */
  body[data-page="recon"] .eq-term { flex-basis: 118px; }
  body[data-page="recon"] .eq-v { font-size: 22px; }
}
@media (max-width: 820px) {
  body[data-page="recon"] .window-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  body[data-page="recon"] .eq-term { flex: 1 1 104px; padding: 0 10px; }
  body[data-page="recon"] .eq-term.total { flex-basis: 100%; padding: 0 0 14px; }
  body[data-page="recon"] .eq-term.total + .eq-op { display: none; }
}


/* ============================================================
   20. Customs & duty — §15 applied, 2026-07-29
   ------------------------------------------------------------
   Gaurav: "look at orders.html, make customs the same minimalist
   and elegant way." Measured against orders at 1600px, this page
   was still pre-v3 in four separate ways and — the finding that
   matters — carried ZERO flags while being the one page in the
   deck whose entire subject is a border being crossed. Every
   corridor on it ("India → Saudi Arabia", "Skull Shaver · China")
   was set as plain text. Same shortfall §17 found on qc and §18
   on dispatch, and the same fix: the geography was already in the
   copy, it just was not being drawn.

     · .page-head breadcrumb → the v3 .toolbar
     · KPI tiles: .delta sub-lines and inline colour → the §7.4
       label + figure + icon-square recipe
     · four .alert washes of standing prose → quiet notes
     · one orange .btn.primary per pane → ghost + plain

   The decor is ADDED here, never removed — the same constraint
   §15 was built under ("i want that flag and decor, thats what
   makes the site worth it").

   Scoped to body[data-view="customs"] throughout, deliberately.
   .kpi, .filters, .f-ic, table.data and the §12.2 column budgets
   are shared with pages measured to the pixel; §12 stays the
   owner of the ladder and the nil treatment.
   ============================================================ */

/* ---------- 20.1 Standing prose is not an alert ---------- */
/* Four .alert blocks (three info, one serious) held three-line
   explanations of what the tab is for. §7 rules out fills behind text on
   static surfaces, and none of these is a live condition — the actual red
   on this page is the toolbar's .live and the rows' own pills. Same
   treatment orders.html gives the §9.5 formula: an info icon and grey. */
body[data-view="customs"] .c-note {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 16px 20px 16px;
  border-bottom: 1px solid var(--hair-soft);
  color: #8A8B8E; font-size: 12.5px; font-weight: 500; line-height: 1.65;
}
body[data-view="customs"] .c-note > div { flex: 1; min-width: 0; }
body[data-view="customs"] .c-note b { color: var(--navy); font-weight: 650; }
body[data-view="customs"] .c-note a { color: #7A7B7E; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
body[data-view="customs"] .c-note a:hover { color: var(--orange); }
body[data-view="customs"] .c-note > span:first-child { flex: 0 0 auto; color: #C2C2BD; margin-top: 1px; }
body[data-view="customs"] .c-note > span:first-child svg.ic { display: block; width: 15px; height: 15px; }
/* the rate table's "+ Add HS code" used to sit outside the alert in a flex
   card-body; it rides the note now, centred against three lines of prose */
body[data-view="customs"] .c-note > .btn { flex: 0 0 auto; align-self: center; margin-left: 4px; }

/* ---------- 20.2 A corridor, drawn as one ---------- */
/* Flags sit OUTSIDE the text block, never inside it — .c-geo-t makes its
   children block-level to stack the sub-line, so a flag placed within it
   drops onto its own row. That is the §17 qSource() trap, same shape. */
body[data-view="customs"] .c-geo { display: flex; align-items: flex-start; gap: 9px; min-width: 0; }
body[data-view="customs"] .c-geo .c-flags { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; margin-top: 1px; }
body[data-view="customs"] .c-geo-t { display: block; min-width: 0; }
body[data-view="customs"] .c-flags .flag { width: 17px; height: 17px; flex: 0 0 17px; }

/* the duty build-up's own header line — the consignment's corridor */
body[data-view="customs"] .c-lane {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 14px; color: #B4B4AF; font-size: 12px; font-weight: 500;
}
body[data-view="customs"] .c-lane .c-flags { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; }

/* ---------- 20.3 Filter row — chrome down, not controls out ---------- */
/* §15.2 verbatim. Every control stays; they stop drawing their boxes until
   you reach for them, so the heaviest cluster on the page goes quiet. */
body[data-view="customs"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-view="customs"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-view="customs"] .filters select:hover { border-color: var(--hair); background-color: var(--surface); }
body[data-view="customs"] .filters select:focus { border-color: var(--blue); background-color: #fff; }
body[data-view="customs"] .filters input {
  background: transparent; border-color: var(--hair-soft);
}
body[data-view="customs"] .filters input:hover { border-color: var(--hair); }
body[data-view="customs"] .filters input:focus { background: #fff; border-color: var(--blue); }

/* ---------- 20.4 Row air ---------- */
/* Vertical only. §12.2's 12px gutters are load-bearing — eleven columns on
   the import register only fit the card because of them. */
body[data-view="customs"] table.data td { padding-top: 15px; padding-bottom: 15px; }
body[data-view="customs"] table.data th { padding-top: 13px; padding-bottom: 11px; }

/* ---------- 20.5 Headers wrap ---------- */
/* §5 keeps headers on one line, which is fine under an auto layout but
   clips under §12.2's fixed one — "Weight — packed vs charged" and
   "Declared / invoice value" were both cut off mid-word. Same fix §17
   landed on the QC bench: let the header wrap and it costs height once,
   at the top of the table, instead of clipping at every width. It also
   frees the budget below, since a wrapped header no longer sets a
   column's minimum — "Declared / invoice value" was demanding 147px for
   cells that need 96. */
body[data-view="customs"] table.data th { white-space: normal; }

/* ---------- 20.6 Column budget, re-cut for the flags ---------- */
/* Measured, not guessed: the widest rendered line per column plus the
   flag group (47px for a pair, 26px for one) plus §12.2's 24px of gutter.
   Export totals 1265 of the 1296 available, so every cell holds its line.
   Route buys its flags from fob/decl/act, all three of which measured
   26–51px wider than their content ever needs. */
#pane-export col.x-ship { width: 14.4%; } #pane-export col.x-route { width: 22.5%; }
#pane-export col.x-inv  { width: 15.7%; } #pane-export col.x-fob   { width: 8.6%;  }
#pane-export col.x-decl { width: 7.4%;  } #pane-export col.x-hs    { width: 10.7%; }
#pane-export col.x-wt   { width: 14.7%; } #pane-export col.x-act   { width: 6%;    }

/* Charged: the expected/charged columns hold "104,220" at most — 80px of
   content in a 130px track. Two points off each buy the action column a
   single-line "Chase broker" and give Impact its sentence back. */
#pane-charged col.c-cons { width: 17%; } #pane-charged col.c-what { width: 19%; }
#pane-charged col.c-exp  { width: 8%;  } #pane-charged col.c-chg  { width: 8%;  }
#pane-charged col.c-imp  { width: 19%; } #pane-charged col.c-act  { width: 10%; }

/* ---------- 20.7 Below the reference width, scroll rather than clip ---------- */
/* §12.2's fixed layout distributes by percentage, so as the card narrows every
   track narrows with it and a header made of one long word ("Assessable",
   "Cmpnstry", "Declared") clips instead of wrapping — 20.5's white-space fix
   cannot help a single word. The deck's answer is already established: give
   the table a floor and let .table-wrap scroll, which is what §8 does on
   orders (min-width: 1060px). The action column then sits off-screen until
   scrolled, which the 2026-07-29 drift audit records as by design.
   Import carries eleven columns, so its floor is higher. */
body[data-view="customs"] table.data { min-width: 1180px; }
body[data-view="customs"] #pane-import table.data { min-width: 1290px; }

/* §7 made .pill a dot + label rather than a filled chip, so its global
   white-space: nowrap now paints sentence-length statuses over the next
   column instead of clipping them. Letting them wrap is the correct
   behaviour and the same fix §13 applied across the slice 2–5 pages. */
body[data-view="customs"] .pill { white-space: normal; }

/* ---------- 20.8 Folds ---------- */
@media (max-width: 1240px) {
  body[data-view="customs"] .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-view="customs"] .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  body[data-view="customs"] .c-note { padding: 14px 16px; flex-wrap: wrap; }
  body[data-view="customs"] .c-note > .btn { margin-left: 26px; }
}

/* ============================================================
   22. Returns & Refunds — §15 applied, 2026-07-29
   ------------------------------------------------------------
   Gaurav: make returns read like the orders page. Ran the §16
   diagnosis first; this page came back with the pre-v3 profile
   in full — a breadcrumb head, six KPI tiles with delta
   sub-lines, five tinted .alert blocks inside the panes, tinted
   row-warn / row-critical stripes, and ZERO flags and ZERO
   marketplace marks on a page that names eight marketplaces and
   six countries in plain text.

   So the same two moves as §15: quiet the competing chrome, and
   put the decor back where the geography already was. Nothing
   decorative is removed — this page had none to remove.

   The structural change is that the KPI strip is gone and the
   refund clock rail takes its place. Four of the six tiles
   restated a tab count, which is the exact duplication §15
   removed from orders; the two that did not are carried into
   the rail's composition line.

   Scoped to body[data-page="returns"] throughout. .wcell,
   .window-rail, .w-*, .o-mp, .o-loc, .dl and .pane-context are
   shared with orders / purchase / tracking / qc / inventory /
   IRA, whose flat treatment and column budgets were measured to
   the pixel. A global edit here silently re-cuts all of them.
   ============================================================ */

/* ---------- 22.1 The refund clock as the dashboard's tile strip ---------- */
/* §15.1's recipe verbatim — the two strips have to read as one system. */
body[data-page="returns"] .window-rail {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 16px;
}
body[data-page="returns"] .wcell {
  display: flex; flex-direction: column;
  min-height: 126px; padding: 17px 18px 18px;
  border: 1px solid var(--hair); border-bottom-color: #E3E3DF;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), border-color .18s;
}
body[data-page="returns"] .wcell:hover {
  transform: translateY(-2px); border-color: #DCDCD7;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 4px 8px rgba(19, 25, 33, .05),
    0 14px 28px rgba(19, 25, 33, .08),
    inset 0 1px 0 rgba(255, 255, 255, .9);
}
body[data-page="returns"] .wcell:active { transform: translateY(0); }
/* an inset ring, not an underline — an inset bar clips against the radius */
body[data-page="returns"] .wcell.active {
  border-color: transparent;
  box-shadow:
    inset 0 0 0 1.5px var(--orange),
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05);
}
body[data-page="returns"] .w-figure {
  display: flex; align-items: center; gap: 12px;
  margin-top: auto; padding-top: 14px;
}
body[data-page="returns"] .w-val {
  margin-top: auto; padding-top: 14px;
  font-size: 30px; font-weight: 600; letter-spacing: -1.1px;
}
body[data-page="returns"] .w-figure .w-val { margin-top: 0; padding-top: 0; }
body[data-page="returns"] .w-sub { margin-top: 7px; }
body[data-page="returns"] .w-ic {
  margin-left: auto; flex: 0 0 34px;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 11px; color: #8E8F92;
  background: linear-gradient(180deg, #F7F8F9, #F1F2F3);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(19, 25, 33, .045);
  transition: color .18s, background .18s;
}
body[data-page="returns"] .w-ic svg.ic { display: block; width: 18px; height: 18px; stroke-width: 1.7; }
/* only the breached bucket recolours its square — the KPI tiles' own rule */
body[data-page="returns"] .wcell:first-child .w-ic {
  color: var(--critical);
  background: linear-gradient(180deg, #FDF3F3, #FBEBEB);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(197, 34, 31, .09);
}
body[data-page="returns"] .wcell:hover .w-ic { color: var(--navy); }
body[data-page="returns"] .wcell:first-child:hover .w-ic { color: var(--critical); }

/* the 96-hr rule — the one place in the deck that states the refund clock */
body[data-page="returns"] .rail-note {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 16px 2px 0;
}
body[data-page="returns"] .rail-note svg.ic {
  width: 14px; height: 14px; flex: 0 0 14px; margin-top: 2px; color: #C2C2BD;
}

/* ---------- 22.2 Filter row — chrome down, not controls out ---------- */
body[data-page="returns"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-page="returns"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-page="returns"] .filters select:hover {
  border-color: var(--hair); background-color: var(--surface);
}
body[data-page="returns"] .filters select:focus {
  border-color: var(--blue); background-color: #fff;
}

/* ---------- 22.3 Row air ---------- */
/* Vertical only. §13's fixed layout and the declared colgroups own the
   horizontal budget; narrowing the gutters from table.data's 20px to §8's
   13px is what buys the room the flags and monograms need — the same trade
   §17.3 made on the QC bench, and it shrinks no control. */
body[data-page="returns"] table.data th,
body[data-page="returns"] table.data td { padding: 15px 13px; }
body[data-page="returns"] table.data th { padding-top: 13px; padding-bottom: 11px; }
body[data-page="returns"] table.data td.actions { padding-left: 8px; padding-right: 12px; }

/* ---------- 22.4 One bold per row ---------- */
/* The order ID is the entry point; the marketplace name, the item line and
   the ASIN columns all stepped back to 500 so the flag is the brightest mark
   in the row. §7's rule — size and colour carry hierarchy, not weight. */
body[data-page="returns"] .o-mp-name b,
body[data-page="returns"] .o-item b { font-weight: 500; }
/* the mismatched ASIN is the one figure on the QC tab that must shout */
body[data-page="returns"] .r-mismatch { color: var(--critical); font-weight: 650; }

/* ---------- 22.5 Flags where the geography already was ---------- */
/* Destination / receiving warehouse. The flag sits OUTSIDE .o-loc because
   .o-loc makes every child span a block — that is how it stacks its
   sub-line — so a flag placed inside drops onto its own row (§17.2). */
body[data-page="returns"] .r-loc { display: flex; align-items: flex-start; gap: 9px; }
body[data-page="returns"] .r-loc > [data-flag] { flex: 0 0 17px; width: 17px; height: 17px; margin-top: 1px; }
body[data-page="returns"] .r-loc > .o-loc { min-width: 0; }
/* renderMarks() hydrates [data-mk] into a .mk, so the monogram sits one
   level deeper than on the JS-rendered pages; give the wrapper the size */
body[data-page="returns"] .o-mp > [data-mk] { display: block; flex: 0 0 26px; }
body[data-page="returns"] .o-src > [data-flag] { flex: 0 0 17px; width: 17px; height: 17px; }

/* ---------- 22.6 Scope empty state ---------- */
/* A table whose every row is hidden reads as a broken grid, so the whole
   wrap is swapped for a line saying which bucket found nothing here. */
body[data-page="returns"] .scope-empty {
  margin: 0; padding: 34px 20px;
  color: #A6A6A1; font-size: 12.5px; font-weight: 500;
}

/* ---------- 22.7 Below the fold, scroll rather than compress ---------- */
/* §8 gives .otable a min-width so the columns stop shrinking once the card
   gets narrow and the .table-wrap scrolls instead. The §13 pages never took
   that rule, so below ~1240px their percentage columns keep compressing and
   short status labels ("In window", "Out of window") start printing over the
   next cell — measured 9 here, 22 on cs, 17 on inventory. Adopting the orders
   floor clears this page's in one line, and it is the behaviour the client
   already sees on orders, purchase and tracking. */
body[data-page="returns"] .table-wrap table.data { min-width: 1060px; }

/* ---------- 22.8 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="returns"] .window-rail { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-page="returns"] .window-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}


/* ============================================================
   21. JIT Inventory — §15 applied, 2026-07-29
   ------------------------------------------------------------
   Same brief as orders ("minimal and elegant"), same constraint
   ("i want that flag and decor"). Measured first, as §16 and
   §17 were, and this page came back with the widest shortfall
   of any so far: against orders.html's 46 flags / 25 marketplace
   marks / 84 SVGs, jit.html carried 0 / 0 / 0 — while naming
   India, UAE and KSA on nearly every row and naming marketplaces
   in plain text. It was also the last page still on the pre-v3
   `.page-head`, and its 6-tile KPI strip restated four tab
   counts verbatim (1,842 / 96 / 12 / 38), which is the exact
   duplication §15 removed from orders.

   So nothing decorative was removed here either — there was
   none to remove. The work was to put the deck's own vocabulary
   onto a page whose entire subject is geography, and to give
   the counts one home instead of two.

   Scoped to body[data-page="jit"] throughout. .wcell, .w-*,
   .dl, .o-loc, .o-item and .peek are shared with orders,
   purchase, tracking, qc, ira and the §13 pages, whose column
   budgets are measured to the pixel — a global edit here
   silently re-cuts all of them.
   ============================================================ */

/* ---------- 21.1 The corridor as the dashboard's tile strip ---------- */
/* §15.1's recipe verbatim, so the two pages read as one system. What is
   page-specific is the ordering: the tiles run India → UAE → KSA → moving,
   which is the direction JIT stock is allowed to travel, and the blue ramp
   runs deep to light along it. Ordered dimension, so one hue with a ramp
   is legal under §7 for the same reason the purchase-window rail is. */
body[data-page="jit"] .window-rail {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 16px;
}
body[data-page="jit"] .wcell {
  display: flex; flex-direction: column;
  min-height: 126px; padding: 17px 18px 18px;
  border: 1px solid var(--hair); border-bottom-color: #E3E3DF;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), border-color .18s;
}
body[data-page="jit"] .wcell:hover {
  transform: translateY(-2px); border-color: #DCDCD7;
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 4px 8px rgba(19, 25, 33, .05),
    0 14px 28px rgba(19, 25, 33, .08),
    inset 0 1px 0 rgba(255, 255, 255, .9);
}
body[data-page="jit"] .wcell:active { transform: translateY(0); }
body[data-page="jit"] .wcell.active {
  border-color: transparent;
  box-shadow:
    inset 0 0 0 1.5px var(--orange),
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05);
}
body[data-page="jit"] .w-figure {
  display: flex; align-items: center; gap: 12px;
  margin-top: auto; padding-top: 14px;
}
body[data-page="jit"] .w-val {
  margin-top: 0; font-size: 30px; font-weight: 600; letter-spacing: -1.1px;
}
body[data-page="jit"] .w-sub { margin-top: 7px; }
/* The icon square holds a FLAG for a place and a line icon for a movement.
   That is the whole idea of the strip: three of these tiles are countries,
   and a country is a thing this deck already knows how to draw. */
body[data-page="jit"] .w-ic {
  margin-left: auto; flex: 0 0 34px;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 11px; color: #8E8F92;
  background: linear-gradient(180deg, #F7F8F9, #F1F2F3);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(19, 25, 33, .045);
  transition: color .18s, background .18s;
}
body[data-page="jit"] .w-ic .flag { width: 19px; height: 19px; }
body[data-page="jit"] .rail-note {
  display: flex; align-items: flex-start; gap: 9px;
  margin: 14px 2px 0;
}
body[data-page="jit"] .rail-note svg.ic {
  flex: 0 0 15px; width: 15px; height: 15px; margin-top: 2px; color: #C2C2BD;
}

/* ---------- 21.2 Filter row — chrome down, not controls out ---------- */
body[data-page="jit"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-page="jit"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-page="jit"] .filters select:hover { border-color: var(--hair); background-color: var(--surface); }
body[data-page="jit"] .filters select:focus { border-color: var(--blue); background-color: #fff; }
body[data-page="jit"] .fsearch { background: transparent; border-color: var(--hair-soft); }
body[data-page="jit"] .fsearch:hover { border-color: var(--hair); }
body[data-page="jit"] .fsearch:focus-within { background: var(--surface); }

/* ---------- 21.3 Row air and the column budget ---------- */
/* Vertical air only, as §15.3. Gutters go to §8's 13px rather than the
   17px `table.data` default: these views run to eight columns and the
   cells are genuinely two-line, so the width has to come from somewhere
   that is not the controls. */
body[data-page="jit"] table.data.jtable th,
body[data-page="jit"] table.data.jtable td { padding: 15px 13px; }
body[data-page="jit"] table.data.jtable th { padding-top: 13px; padding-bottom: 11px; }
body[data-page="jit"] table.data.jtable td.actions { padding-left: 8px; padding-right: 12px; }
/* .dl carries min-width:148px for the orders table, which is wider than the
   13–14% these views can give it under table-layout:fixed. The colgroup is
   the budget here, so the floor has to come off or the cell overflows. */
body[data-page="jit"] .dl { min-width: 0; }

/* The colgroup is PERCENTAGES, so it keeps dividing however narrow the card
   gets: a 9% Source column at 1024px leaves 41px of content for a 17px flag
   plus a 39px source tag, and the tag printed ~10px into the Stock column.
   §8 solves this on the orders table with a min-width and a scrolling wrap —
   REJECTED here, and the reason is worth keeping. jit is a §13 page, and
   §13's pages wrap rather than scroll; a 1040px floor put 27 action controls
   off-screen at 1240px, which is an ordinary laptop width once the 270px
   sidebar is taken off. Trading a 10px overlap for unreachable buttons is
   the wrong way round. .o-src simply wraps instead — the tag drops under
   the flag in the two or three widths where it cannot sit beside it. */
body[data-page="jit"] .o-src { flex-wrap: wrap; row-gap: 4px; }

/* ---------- 21.4 One bold per row ---------- */
/* Product name, Master SKU, warehouse and status were all 600+, so the row
   had no entry point. §7's rule is size and colour, not weight — the
   product name keeps 600 as the thing you read first, the rest steps back
   and the flag becomes the brightest mark in the row. */
body[data-page="jit"] .o-item b { font-weight: 600; }
body[data-page="jit"] .jm-top b { font-weight: 600; }
body[data-page="jit"] .dl-v { font-weight: 600; }
body[data-page="jit"] .dl.breach .dl-v { font-weight: 650; }

/* ---------- 21.5 Cells ---------- */
/* Warehouse: flag outside .o-loc — inside it, .o-loc's block children rule
   drops the flag onto its own line (§17 learned this the hard way). */
body[data-page="jit"] .j-wh { display: flex; align-items: center; gap: 9px; }
body[data-page="jit"] .j-wh .flag { flex: 0 0 17px; width: 17px; height: 17px; }

/* Route: both ends of the corridor, so the forward-only rule is legible
   as a picture and not only as a sentence in the alert above. */
body[data-page="jit"] .j-route { display: flex; align-items: center; gap: 9px; }
body[data-page="jit"] .j-route-flags { display: inline-flex; flex: 0 0 auto; }
body[data-page="jit"] .j-route-flags .flag { width: 17px; height: 17px; }
body[data-page="jit"] .j-route-flags .flag + .flag { margin-left: -5px; box-shadow: 0 0 0 1.5px #fff; }

/* PO scope: a request can cover several marketplaces, so the marks overlap
   the way a stacked avatar group does and the names sit under the label. */
body[data-page="jit"] .j-scope { display: flex; align-items: center; gap: 10px; }
body[data-page="jit"] .j-scope-marks { display: inline-flex; flex: 0 0 auto; }
body[data-page="jit"] .j-scope-marks .mk + .mk { margin-left: -7px; }

/* Stock: available over on-hand, with the reserved share filled. Replaces
   three numeric columns with one cell that answers "can I sell this". */
body[data-page="jit"] .jm { display: block; min-width: 0; }
body[data-page="jit"] .jm-top { display: flex; align-items: baseline; gap: 5px; }
body[data-page="jit"] .jm-top b {
  color: var(--navy); font-size: 15px; letter-spacing: -.3px;
  font-variant-numeric: tabular-nums;
}
body[data-page="jit"] .jm-top span { color: #A6A6A1; font-size: 11.5px; font-weight: 500; }
body[data-page="jit"] .jm-track {
  display: block; height: 3px; margin-top: 8px;
  border-radius: 99px; background: var(--track); overflow: hidden;
}
body[data-page="jit"] .jm-track i { display: block; height: 100%; border-radius: 99px; background: var(--series); }
body[data-page="jit"] .jm-note { display: block; margin-top: 6px; color: #A6A6A1; font-size: 11px; font-weight: 500; }

/* Price pair — curated leads because it is the number §4 says is captured
   at PO time and kept forever; cost is the supporting line. */
body[data-page="jit"] .j-price { display: block; }
body[data-page="jit"] .j-price b {
  display: block; color: var(--navy); font-size: 13px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
body[data-page="jit"] .j-price span { display: block; margin-top: 3px; color: #A6A6A1; font-size: 11px; font-weight: 500; }
/* "No expiry" is a fact, not a gap — grey text, no dash, no pill. */
body[data-page="jit"] .j-noexp { color: #B4B4AF; font-size: 12px; font-weight: 500; }

/* Peek ledger — same two-column li as §8's .od-activity: <time> plus ONE
   wrapper. A third child falls into row 2 column 1 and renders squeezed
   under the timestamp. */
body[data-page="jit"] .jledger { list-style: none; margin: 0; padding: 0; }
body[data-page="jit"] .jledger li {
  display: grid; grid-template-columns: 78px 1fr; gap: 12px;
  padding: 9px 0; border-bottom: 1px solid var(--hair-soft);
}
body[data-page="jit"] .jledger li:last-child { border-bottom: 0; }
body[data-page="jit"] .jledger time { color: #A6A6A1; font-size: 11.5px; font-weight: 600; }
body[data-page="jit"] .jledger strong { display: block; color: var(--ink); font-size: 12.5px; font-weight: 600; }
body[data-page="jit"] .jledger span { display: block; margin-top: 3px; color: #8E8F92; font-size: 11.5px; font-weight: 500; line-height: 1.5; }

/* ---------- 21.6 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="jit"] .window-rail { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-page="jit"] .window-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}


/* ============================================================
   23. Products & SKUs — §15 applied, 2026-07-29
   ------------------------------------------------------------
   Gaurav: "lets do similarly for catalog.html." Ran the §16
   diagnosis. This page came back with the pre-v3 profile in
   full — the most of any page left in the deck:

     · .page-head breadcrumb ("Operations / Products & SKUs")
       while the topbar already says Products & SKUs
     · six KPI tiles carrying .delta sub-lines AND inline
       style="color:var(--critical-text)" / --warning-text
     · four .alert washes holding standing prose
     · FOUR orange .btn.primary outside the toolbar — two
       "Map now", one "Link alternate ASIN", one "+ Add tag
       rule". §8 settled that orange is the toolbar's: seven
       orange buttons in a column turn the reserved accent into
       decoration and fight the red breach signals.
     · Listing health was the one table with NO colgroup, so it
       sized by content while its three siblings were budgeted
       to the pixel.

   And the finding that matters, the same one §17 hit on qc,
   §18 on dispatch and §20 on customs: **0 flags and 0
   marketplace marks** on a page that names five marketplaces
   and three source countries in plain text, and whose entire
   subject is which country a SKU belongs to. The single-source
   ASIN rule IS a geography rule. It was set as text.

   The decor is ADDED here, never removed — the constraint §15
   was built under ("i want that flag and decor, thats what
   makes the site worth it").

   Scoped to body[data-page="catalog"] throughout. .kpi, .flag,
   .mk, .filters, .f-ic, .tool-link and table.data are shared
   with pages measured to the pixel; §11 stays the owner of
   .chain, .mono and the catalog column budgets.
   ============================================================ */

/* ---------- 23.1 Standing prose is not an alert ---------- */
/* Four .alert blocks held three-line explanations of what a tab is for.
   §7 rules out fills behind text on static surfaces, and none of these is
   a live condition — the live things on this page are the row pills and
   the two red tiles. Deliberately NOT reusing customs' .c-note: that is
   scoped to body[data-view="customs"] and its measurements are its own.
   Same recipe, own name — the .chip incident in §14 is why. */
body[data-page="catalog"] .k-note {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--hair-soft);
  color: #8A8B8E; font-size: 12.5px; font-weight: 500; line-height: 1.65;
}
body[data-page="catalog"] .k-note > div { flex: 1; min-width: 0; }
body[data-page="catalog"] .k-note b { color: var(--navy); font-weight: 650; }
body[data-page="catalog"] .k-note .mono { font-weight: 650; }
body[data-page="catalog"] .k-note a { color: #7A7B7E; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
body[data-page="catalog"] .k-note a:hover { color: var(--orange); }
body[data-page="catalog"] .k-note > span:first-child { flex: 0 0 auto; color: #C2C2BD; margin-top: 1px; }
body[data-page="catalog"] .k-note > span:first-child svg.ic { display: block; width: 15px; height: 15px; }
/* "+ Add tag rule" rides the note, centred against three lines of prose */
body[data-page="catalog"] .k-note > .btn { flex: 0 0 auto; align-self: center; margin-left: 4px; }

/* ---------- 23.2 Source and marketplace, drawn ---------- */
/* Flags sit OUTSIDE the text block, never inside it — .k-src-t stacks its
   sub-line by letting .sub be block, so a flag placed within it drops onto
   its own row. That is the §17 qSource() / §20 .c-geo trap, third time. */
body[data-page="catalog"] .k-src { display: flex; align-items: flex-start; gap: 9px; min-width: 0; }
body[data-page="catalog"] .k-src .k-flags { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; margin-top: 1px; }
body[data-page="catalog"] .k-flags .flag { width: 17px; height: 17px; flex: 0 0 17px; }
body[data-page="catalog"] .k-src-t { display: block; min-width: 0; }

/* The conflict row carries TWO flags — the single-source-ASIN breach is
   literally two countries claiming one ASIN, so the cell says so. */
body[data-page="catalog"] .k-src-t .pill { margin-bottom: 2px; }

/* Marketplace cell: the §1 name is Selling Account + Country + Entity +
   Account Name, so the account rides the sub-line and the monogram carries
   the brand while its badge carries the country. */
body[data-page="catalog"] .k-mp { display: flex; align-items: center; gap: 10px; min-width: 0; }
body[data-page="catalog"] .k-mp .mk { flex: 0 0 26px; width: 26px; height: 26px; }
body[data-page="catalog"] .k-mp-t { display: block; min-width: 0; font-weight: 500; }

/* ---------- 23.3 Filter row — chrome down, not controls out ---------- */
/* §15.2 verbatim. Every control stays; they stop drawing their boxes until
   you reach for them. Three filter rows on this page were the heaviest
   chrome cluster on it. */
body[data-page="catalog"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-page="catalog"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-page="catalog"] .filters select:hover { border-color: var(--hair); background-color: var(--surface); }
body[data-page="catalog"] .filters select:focus { border-color: var(--blue); background-color: #fff; }
body[data-page="catalog"] .filters input { background: transparent; border-color: var(--hair-soft); }
body[data-page="catalog"] .filters input:hover { border-color: var(--hair); }
body[data-page="catalog"] .filters input:focus { background: #fff; border-color: var(--blue); }

/* ---------- 23.4 Row air ---------- */
/* Vertical only — §11's catalog gutters are load-bearing, eight columns on
   the product master only fit the card because of them. */
body[data-page="catalog"] table.data td { padding-top: 15px; padding-bottom: 15px; }
body[data-page="catalog"] table.data th { padding-top: 13px; padding-bottom: 11px; }

/* ---------- 23.5 Headers wrap ---------- */
/* §5's th { white-space: nowrap } clips under a fixed layout. Same fix §17
   landed on the QC bench and §20 on customs: a wrapped header costs height
   once, at the top, instead of clipping at every width — and it stops
   setting a column's minimum, which gives the budget back. */
body[data-page="catalog"] table.data th { white-space: normal; }

/* ---------- 23.6 Listing health column budget ---------- */
/* The pane had no colgroup at all. .chain is the widest component on the
   page and was taking whatever it wanted. Cut so the chain gets the room it
   genuinely needs (it stays VERTICAL — §19 records that laying it out
   horizontally wrapped unpredictably inside a table cell) and the action
   column clears its widest control, "Link alternate ASIN". */
body[data-page="catalog"] #pane-listings table.data { table-layout: fixed; }
#pane-listings col.l-sku   { width: 18%; }
#pane-listings col.l-iss   { width: 14%; }
#pane-listings col.l-chain { width: 25%; }
#pane-listings col.l-det   { width: 11%; }
#pane-listings col.l-eff   { width: 18%; }
#pane-listings col.l-act   { width: 14%; }

/* ---------- 23.6b Product master: the action column was 9px short ---------- */
/* Pre-existing, not caused by the flags — §11 cut p-act at 7%, which is 91px
   allocated and 65px inside the 13px gutters. Measured need is 100px: "Link
   ASIN" wrapped onto two lines (39px tall) and "Resolve" at 74px was already
   painting past its own cell. §13's floor for an action column is 12% for
   exactly this reason, and the deck's rule is that a control never shrinks to
   fit a budget.

   The 3 points come from Product. Measuring each line separately against its
   own font (§20's method — a nowrap clone flattens the stacked main and sub
   into one line and lies), Product needs 225px and every other column is
   within 8px of its content, so it is the only column with anything to give.
   What overflows there is a product TITLE, which wraps cleanly and already
   sits above a sub-line — as against p-ids, where the longest line is
   "ISBN 978-93-8812345-1" and a wrapped identifier is a defect.

   p-src stays at 13% and wraps on the single conflict row: two flags plus a
   Conflict pill plus "also mapped to AEZ" is the widest cell on the page, and
   it is one row of six. */
/* p-prod pays for BOTH the action column here and the 4px Master SKU needs in
   23.6d — 18% → 14%. It is the only column on this table with anything to
   give, and what overflows it is a product title. */
#pane-products col.p-prod { width: 14%; }
#pane-products col.p-act  { width: 10%; }

/* ---------- 23.6c SKU mapping: same deficit, and real slack to pay for it -- */
/* "Map now" wrapped in an 8% action column (78px inside the gutters against a
   109px need) and Mapping SLA was 14px short of "escalated to Sales
   supervisor". Both are paid for out of measured slack rather than out of
   another column's content: Marketplace had 93px spare and Orders held 50px.

   Marketplace could give it because the §1 name was split — the monogram now
   carries the brand and its badge the country, so "Amazon UAE SG (S-Amazon)"
   became a 26px mark plus a name over an account sub-line. Orders held is a
   single digit in a 91px track.

   Source drops to a wrapped second line on the two unmapped rows only, where
   the cell holds the muted "— derived from Master SKU". That is prose
   explaining an absence, not an identifier, so wrapping is correct. */
/* m-held is 6%, not 5%: at the 1120px floor 5% left 56px against the 65px its
   own HEADER word needs, so "ORDERS" clipped even with 23.5's wrapping (a
   wrapped header still cannot break a single word — the §20 lesson). Budget a
   column against the wider of its content and its heading. */
#pane-mapping col.m-mkt  { width: 12%; }
#pane-mapping col.m-held { width: 6%;  }
#pane-mapping col.m-src  { width: 13%; }
#pane-mapping col.m-sla  { width: 17%; }
#pane-mapping col.m-act  { width: 10%; }

/* ---------- 23.6d The last two columns, found at the min-width floor ------- */
/* Only visible at ≤1240px, where the table sits on 23.7's 1120px floor and
   every percentage track is at its narrowest. Both were pre-existing §11 cuts.

   Handling tags' action column was 8% — 90px at the floor against "Edit rule"
   needing 104px, so the button painted 2px into the next cell. Below §13's 12%
   floor for an action column, which exists for exactly this. The 3 points come
   from "What it changes downstream", which is a wrapping sentence.

   Product master's Master SKU was 4px short of "AEZ_B0PERF3321_JIT" — the
   longest identifier on the page, and an identifier is the one thing that must
   not wrap. Paid for by Product, whose overflow is a title. */
#pane-tags col.t-eff { width: 26%; }
#pane-tags col.t-act { width: 11%; }
#pane-products col.p-sku  { width: 16%; }

/* ---------- 23.7 Below the reference width, scroll rather than clip ---------- */
/* Established answer (§8 on orders at 1060px, §20 on customs at 1180px): a
   fixed layout distributes by percentage, so as the card narrows a header
   made of one long word clips and 23.5 cannot help it. Give the table a
   floor and let .table-wrap scroll. */
body[data-page="catalog"] table.data { min-width: 1120px; }

/* §7 made .pill a dot + label rather than a filled chip, so its global
   white-space: nowrap paints sentence-length statuses over the next column
   instead of clipping. "None — 1 order bought on the next listing" and
   "1 order blocked — past purchase window" are both sentences. */
body[data-page="catalog"] .pill { white-space: normal; }

/* ---------- 23.8 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="catalog"] .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-page="catalog"] .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  body[data-page="catalog"] .k-note { padding: 14px 16px; flex-wrap: wrap; }
  body[data-page="catalog"] .k-note > .btn { margin-left: 26px; }
}


/* ============================================================
   24. Approvals — §15 applied, 2026-07-29
   ------------------------------------------------------------
   Gaurav: "now similarly do for approvals page." Ran the §16
   diagnosis, and this page's shortfall is genuinely different
   from the last three — which is the whole argument for
   measuring each page instead of copying components onto it.

   qc / dispatch / customs / catalog were all diagnosed as
   "names its geography in plain text and never draws it".
   Approvals is NOT that page. It is about thresholds, money and
   clocks; three requester lines name a place and those now
   carry a flag, but there is no corridor here and inventing one
   would be decoration for its own sake, which is exactly what
   §7 forbids. Its two real defects were:

     · EIGHT orange .btn.primary, SIX of them a column of
       "Approve" buttons in the rows. §8 settled this — orange
       is the toolbar's; a column of orange row-actions turns
       the reserved accent into decoration and, here, competed
       directly with the red SLA-breach pills two cells away.
       Approve is now a plain .btn.sm against a .danger Reject,
       so the pair still reads as a decision without either
       shouting.
     · NOT ONE of the four tables had a colgroup — the only
       page in the deck where every table sized by content.

   Plus the usual pre-v3 set: .page-head breadcrumb, six KPI
   tiles with .delta sub-lines and inline colour, four .alert
   washes of standing prose.

   Scoped to body[data-page="approvals"] THROUGHOUT, including
   the #pane-… rules: #pane-mine is ALSO used by tickets.html,
   so an unscoped budget here would silently re-cut that page.
   The other three IDs are unique but are scoped anyway, so the
   whole section is safe to read as page-local.
   ============================================================ */

/* ---------- 24.1 Standing prose is not an alert ---------- */
/* Four .alert blocks held explanations of what a tab is for. §7 rules out
   fills behind text on static surfaces, and none is a live condition — the
   live things here are the SLA pills and the one red tile. Own class name,
   not §20's .c-note or §23's .k-note: each is scoped to its own page and
   measured there (the .chip incident in §14 is why). */
body[data-page="approvals"] .a-note {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--hair-soft);
  color: #8A8B8E; font-size: 12.5px; font-weight: 500; line-height: 1.65;
}
body[data-page="approvals"] .a-note > div { flex: 1; min-width: 0; }
body[data-page="approvals"] .a-note b { color: var(--navy); font-weight: 650; }
body[data-page="approvals"] .a-note > span:first-child { flex: 0 0 auto; color: #C2C2BD; margin-top: 1px; }
body[data-page="approvals"] .a-note > span:first-child svg.ic { display: block; width: 15px; height: 15px; }

/* ---------- 24.2 The three lines that do name a place ---------- */
/* A requester sub-line, so the flag is 14px rather than the 17px a route cell
   uses — it is identifying a person's location, not drawing a corridor. Flex
   rather than inline because .sub is a block. */
body[data-page="approvals"] .a-who { display: flex; align-items: center; gap: 6px; }
body[data-page="approvals"] .a-who .flag { width: 14px; height: 14px; flex: 0 0 14px; }

/* ---------- 24.3 Filter row — chrome down, not controls out ---------- */
/* §15.2 verbatim. Entity moved up to the toolbar as a page-level scope, so
   this row is Type + Sort + search — the three that genuinely re-scope a tab. */
body[data-page="approvals"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-page="approvals"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-page="approvals"] .filters select:hover { border-color: var(--hair); background-color: var(--surface); }
body[data-page="approvals"] .filters select:focus { border-color: var(--blue); background-color: #fff; }
body[data-page="approvals"] .filters input { background: transparent; border-color: var(--hair-soft); }
body[data-page="approvals"] .filters input:hover { border-color: var(--hair); }
body[data-page="approvals"] .filters input:focus { background: #fff; border-color: var(--blue); }

/* ---------- 24.4 Row air ---------- */
/* Vertical only — §11 already sets 13px gutters on this page and eleven of
   these cells are two-line, so the horizontal figure is load-bearing. */
body[data-page="approvals"] table.data td { padding-top: 15px; padding-bottom: 15px; }
body[data-page="approvals"] table.data th { padding-top: 13px; padding-bottom: 11px; }

/* The global table.data td is `white-space: nowrap` (line ~357), which is fine
   under an auto layout but not under 24.6's fixed one: a cell can no longer
   widen to fit, so a long label paints straight over the next column instead.
   §11 had given this page `height: auto` but never the wrap, and it did not
   show while the tables sized by content.

   Caught only below the 1600px reference — "Master data — vendor / carrier /
   marketplace" ran 43px into the next cell at 1240px, "30% max purchase-price
   rule" 31px. Both are labels that should wrap, and neither is an identifier.
   customs (§20) and dispatch already override this page-wide; approvals now
   does too, with .sub given the same line-height those two use. */
body[data-page="approvals"] table.data td { white-space: normal; }
body[data-page="approvals"] table.data td .sub { white-space: normal; line-height: 1.45; }
/* but a control still never breaks mid-label */
body[data-page="approvals"] table.data td.actions .btn { white-space: nowrap; }

/* ---------- 24.5 Headers wrap ---------- */
/* §5's nowrap clips under a fixed layout; "Time to decide", "Approver group"
   and "Trigger & threshold" all needed it. Costs height once at the top
   instead of clipping at every width, and frees the budget below because a
   wrapped header stops setting its column's minimum (§17 / §20 / §23). */
body[data-page="approvals"] table.data th { white-space: normal; }

/* ---------- 24.6 Column budgets, four tables that had none ---------- */
/* Action columns sit at or above §13's 12% floor in every pane. My queue
   needs the most of any action column in the deck, because it is the only
   one carrying a PAIR — Approve + Reject — and .row-actions wraps them onto
   two lines rather than clipping if it is starved. */
body[data-page="approvals"] table.data { table-layout: fixed; }

body[data-page="approvals"] #pane-mine col.q-req  { width: 22%; }
body[data-page="approvals"] #pane-mine col.q-unb  { width: 24%; }
body[data-page="approvals"] #pane-mine col.q-val  { width: 10%; }
body[data-page="approvals"] #pane-mine col.q-rule { width: 15%; }
body[data-page="approvals"] #pane-mine col.q-sla  { width: 15%; }
body[data-page="approvals"] #pane-mine col.q-act  { width: 14%; }

body[data-page="approvals"] #pane-pending col.p-type { width: 26%; }
body[data-page="approvals"] #pane-pending col.p-pend { width: 8%;  }
body[data-page="approvals"] #pane-pending col.p-late { width: 9%;  }
body[data-page="approvals"] #pane-pending col.p-val  { width: 12%; }
body[data-page="approvals"] #pane-pending col.p-grp  { width: 17%; }
body[data-page="approvals"] #pane-pending col.p-old  { width: 15%; }
body[data-page="approvals"] #pane-pending col.p-act  { width: 13%; }

body[data-page="approvals"] #pane-decided col.d-when { width: 11%; }
body[data-page="approvals"] #pane-decided col.d-req  { width: 17%; }
body[data-page="approvals"] #pane-decided col.d-rec  { width: 16%; }
body[data-page="approvals"] #pane-decided col.d-dec  { width: 11%; }
body[data-page="approvals"] #pane-decided col.d-appr { width: 15%; }
body[data-page="approvals"] #pane-decided col.d-why  { width: 21%; }
body[data-page="approvals"] #pane-decided col.d-ttd  { width: 9%;  }

body[data-page="approvals"] #pane-rules col.r-rule { width: 17%; }
body[data-page="approvals"] #pane-rules col.r-trig { width: 24%; }
body[data-page="approvals"] #pane-rules col.r-grp  { width: 16%; }
body[data-page="approvals"] #pane-rules col.r-sla  { width: 7%;  }
body[data-page="approvals"] #pane-rules col.r-brch { width: 16%; }
body[data-page="approvals"] #pane-rules col.r-stat { width: 8%;  }
body[data-page="approvals"] #pane-rules col.r-act  { width: 12%; }

/* ---------- 24.7 Below the reference width, scroll rather than clip ------- */
/* The established answer (§8 orders 1060, §20 customs 1180, §23 catalog 1120):
   a fixed layout distributes by percentage, so as the card narrows a header
   made of one long word clips and 24.5 cannot save it. Give the table a floor
   and let .table-wrap scroll. */
body[data-page="approvals"] table.data { min-width: 1100px; }

/* §7 made .pill a dot + label rather than a filled chip, so its global
   white-space: nowrap paints "Breached 6h 20m" and "On — notify" over the
   next column instead of clipping. Wrapping is the correct behaviour. */
body[data-page="approvals"] .pill { white-space: normal; }

/* ---------- 24.8 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="approvals"] .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-page="approvals"] .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  body[data-page="approvals"] .a-note { padding: 14px 16px; }
}


/* =========================================================================
   25. Reports — analytics workspace, 2026-07-29
   -------------------------------------------------------------------------
   reports.html was the last purely descriptive page in the deck: 31 cards
   naming a report, a dead "Run" button on each, and no figure anywhere. It
   also carried every pre-v3 defect the earlier passes removed one at a time
   — a .page-head breadcrumb, 31 orange row buttons (§8 settled that orange
   belongs to the toolbar), a bespoke .report component in an inline <style>,
   zero flags on a page naming eleven countries, and no rail.

   It is now a workspace: a delivery-state rail → an analytical library where
   every card carries its live headline and sparkline → a viewer that RENDERS
   the selected report (KPIs with variance, a chart, the output table) →
   a delivery manager and a self-service builder.

   Everything is scoped to body[data-page="reports"] deliberately. .wcell,
   .window-rail, .kpi, .meters, .o-mp and .data are shared with orders,
   purchase, tracking, qc, inventory, recon and IRA, whose column budgets are
   measured to the pixel. A global edit here silently re-cuts all of them.
   ========================================================================= */

/* ---------- 25.1 The rail — delivery state, as raised tiles ----------
   §15.1's recipe verbatim. Reports are governed by freshness rather than by
   volume, so the five buckets partition all 31 by delivery state and sum to
   31 by construction — the figures are computed from REPORTS, not written. */
body[data-page="reports"] .window-rail {
  gap: 14px; margin-bottom: 18px;
}
body[data-page="reports"] .wcell {
  display: flex; flex-direction: column;
  min-height: 126px; padding: 17px 18px 18px;
  border: 1px solid var(--hair); border-bottom-color: #E3E3DF;
  border-radius: 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FCFCFB 100%);
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), border-color .18s;
}
body[data-page="reports"] .wcell:first-child,
body[data-page="reports"] .wcell:nth-child(odd),
body[data-page="reports"] .wcell:nth-child(3n + 1) { border-left: 1px solid var(--hair); }
body[data-page="reports"] .wcell:nth-child(n + 3),
body[data-page="reports"] .wcell:nth-child(n + 4) { border-top: 1px solid var(--hair); }
body[data-page="reports"] .wcell:hover {
  transform: translateY(-2px); border-color: #DCDCD7;
  box-shadow:
    0 1px 1px rgba(19, 25, 33, .04),
    0 4px 8px rgba(19, 25, 33, .05),
    0 14px 28px rgba(19, 25, 33, .08),
    inset 0 1px 0 rgba(255, 255, 255, .9);
}
body[data-page="reports"] .wcell:active { transform: translateY(0); }
body[data-page="reports"] .wcell.active {
  border-color: transparent;
  box-shadow:
    inset 0 0 0 1.5px var(--orange),
    0 1px 1px rgba(19, 25, 33, .04),
    0 2px 4px rgba(19, 25, 33, .035),
    0 8px 18px rgba(19, 25, 33, .05);
}
body[data-page="reports"] .w-figure {
  display: flex; align-items: center; gap: 12px;
  margin-top: auto; padding-top: 14px;
}
body[data-page="reports"] .w-figure .w-val {
  margin-top: 0; padding-top: 0;
  font-size: 30px; font-weight: 600; letter-spacing: -1.1px;
}
body[data-page="reports"] .w-sub { margin-top: 7px; }
body[data-page="reports"] .w-ic {
  margin-left: auto; flex: 0 0 34px;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 11px; color: #8E8F92;
  background: linear-gradient(180deg, #F7F8F9, #F1F2F3);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(19, 25, 33, .045);
  transition: color .18s, background .18s;
}
body[data-page="reports"] .w-ic svg.ic { display: block; width: 18px; height: 18px; stroke-width: 1.7; }
/* .is-breach, not :first-child — the breach bucket happens to lead here, but
   naming it means a reordered rail cannot quietly redden the wrong tile
   (the lesson §19 learned when ageing runs the other way round). */
body[data-page="reports"] .wcell.is-breach .w-ic {
  color: var(--critical);
  background: linear-gradient(180deg, #FDF3F3, #FBEBEB);
  box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(197, 34, 31, .09);
}
body[data-page="reports"] .wcell:hover .w-ic { color: var(--navy); }
body[data-page="reports"] .rail-note { margin: 0 2px 18px; }

/* ---------- 25.2 Filter row ---------- */
/* §15.2 — chrome down, not controls out. */
body[data-page="reports"] .filters { gap: 5px; padding: 14px 20px 13px; flex-wrap: wrap; }
body[data-page="reports"] .filters select {
  border-color: transparent; background-color: transparent;
  transition: border-color .15s, background-color .15s;
}
body[data-page="reports"] .filters select:hover,
body[data-page="reports"] .filters select:focus { border-color: var(--line); background-color: #fff; }

/* `.rgchip`, not `.gchip` — users.html defines its own .gchip in an inline
   <style> block that loads AFTER this stylesheet, so taking that name would
   have leaked across pages. Same class of collision as the §14 .chip incident;
   grep the inline blocks, not only styles.css, before taking a generic name. */
body[data-page="reports"] .rgchip {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; font-size: 12px; font-weight: 500; color: #7A7B7E;
  padding: 5px 11px; border: 1px solid transparent; border-radius: 99px;
  background: none; cursor: pointer;
  transition: color .15s, background .15s, border-color .15s;
}
body[data-page="reports"] .rgchip:hover { color: var(--navy); background: #F7F7F4; }
body[data-page="reports"] .rgchip.on {
  color: var(--navy); font-weight: 600;
  background: #fff; border-color: var(--orange);
  box-shadow: inset 0 0 0 .5px var(--orange);
}
body[data-page="reports"] .rgchip .gn {
  font-size: 11px; font-weight: 600; color: #B4B4AF;
  font-variant-numeric: tabular-nums;
}
body[data-page="reports"] .rgchip.on .gn { color: var(--orange); }

/* ---------- 25.3 The library ---------- */
/* Two columns, not three. The descriptions are the client's own requirement
   text and get read line by line at sign-off — at three columns they clamp to
   an unreadable stub, which is the one thing this page must not do. */
body[data-page="reports"] .rp-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px; padding: 4px 20px 18px;
}
body[data-page="reports"] .rp-card {
  display: grid; gap: 9px; align-content: start; text-align: left;
  padding: 17px 19px 15px; min-width: 0;
  font: inherit; color: inherit; cursor: pointer;
  border: 1px solid var(--hair); border-radius: 14px; background: #fff;
  transition: transform .16s var(--ease), border-color .16s, box-shadow .16s var(--ease);
}
/* the lift is a hover state only — §7's no-shadow rule governs the surface at
   rest, and at rest these are flat white cards like every other card here */
body[data-page="reports"] .rp-card:hover {
  transform: translateY(-1px); border-color: #DCDCD7;
  box-shadow: 0 2px 5px rgba(19, 25, 33, .045), 0 10px 22px rgba(19, 25, 33, .055);
}
body[data-page="reports"] .rp-card:active { transform: translateY(0); }
body[data-page="reports"] .rp-card:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }

body[data-page="reports"] .rp-top { display: flex; align-items: center; gap: 10px; min-width: 0; }
body[data-page="reports"] .rp-num {
  flex: 0 0 auto; display: grid; place-items: center;
  min-width: 24px; height: 22px; padding: 0 6px;
  border-radius: 7px; background: #F4F4F1; color: #8E8F92;
  font-size: 11.5px; font-weight: 650; font-variant-numeric: tabular-nums;
}
body[data-page="reports"] .rp-name {
  flex: 1 1 auto; min-width: 0;
  font-size: 14px; font-weight: 650; color: var(--navy); line-height: 1.35;
}
body[data-page="reports"] .rp-state { flex: 0 0 auto; font-size: 11.5px; }

body[data-page="reports"] .rp-fig {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  margin-top: 3px;
}
body[data-page="reports"] .rp-figv {
  font-size: 28px; font-weight: 600; line-height: 1;
  letter-spacing: -1.1px; color: var(--navy);
}
body[data-page="reports"] .rp-figv i {
  font-style: normal; font-size: 13px; font-weight: 600;
  color: #A6A6A1; letter-spacing: 0; margin-left: 5px;
}
body[data-page="reports"] .rp-basis { font-size: 11px; font-weight: 500; color: #B4B4AF; }
body[data-page="reports"] .rp-sparkwrap { margin-left: auto; display: block; flex: 0 0 auto; }
body[data-page="reports"] .rp-spark { display: block; width: 104px; height: 28px; }
body[data-page="reports"] .rp-headlbl { font-size: 11.5px; font-weight: 500; color: #A6A6A1; }
body[data-page="reports"] .rp-desc {
  font-size: 12.5px; line-height: 1.6; color: var(--ink-2);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
body[data-page="reports"] .rp-foot {
  display: flex; align-items: center; gap: 12px;
  margin-top: 3px; padding-top: 11px; border-top: 1px solid var(--hair-soft);
}
body[data-page="reports"] .rp-meta {
  flex: 1 1 auto; min-width: 0;
  font-size: 11.5px; font-weight: 500; color: #B4B4AF;
}
body[data-page="reports"] .rp-open {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; color: #7A7B7E;
  transition: color .15s, gap .15s;
}
body[data-page="reports"] .rp-open i { font-style: normal; font-size: 13px; }
body[data-page="reports"] .rp-card:hover .rp-open { color: var(--orange); gap: 9px; }

body[data-page="reports"] .rp-delta {
  display: inline-flex; align-items: center;
  font-size: 12.5px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
body[data-page="reports"] .rp-delta.up   { color: var(--good); }
body[data-page="reports"] .rp-delta.down { color: var(--critical); }
body[data-page="reports"] .rp-delta.flat { color: #A6A6A1; }
body[data-page="reports"] .rp-empty {
  grid-column: 1 / -1; display: flex; align-items: center; gap: 12px;
  padding: 26px 4px; color: #A6A6A1; font-size: 13px;
}

/* ---------- 25.4 The viewer ---------- */
body[data-page="reports"] .rv-head {
  display: flex; align-items: center; gap: 8px;
  min-height: 31px; margin-bottom: 18px; flex-wrap: wrap;
}
body[data-page="reports"] .rv-back {
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit; font-size: 12.5px; font-weight: 600; color: #7A7B7E;
  padding: 0; border: 0; background: none; cursor: pointer;
  transition: color .15s;
}
/* a text glyph, not an ICONS slot — ICONS.chevron is the row-peek DOWN
   chevron and points the wrong way here (the §16 order-detail lesson) */
body[data-page="reports"] .rv-back span { font-size: 17px; line-height: 1; }
body[data-page="reports"] .rv-back:hover { color: var(--orange); }

body[data-page="reports"] .rv-title { margin-bottom: 18px; }
body[data-page="reports"] .rv-title-main { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
body[data-page="reports"] .rv-num {
  display: grid; place-items: center; min-width: 30px; height: 26px; padding: 0 8px;
  border-radius: 8px; background: var(--navy); color: #fff;
  font-size: 12px; font-weight: 650; letter-spacing: .3px;
}
body[data-page="reports"] .rv-title h2 {
  margin: 0; font-size: 22px; font-weight: 650;
  letter-spacing: -.5px; color: var(--navy);
}
/* The requirement text, in full. The library card clamps it to three lines
   to keep 31 cards scannable; the viewer is where it has to be complete,
   because this paragraph IS what the client signs off against. */
body[data-page="reports"] .rv-desc {
  margin: 11px 0 0; max-width: 96ch;
  font-size: 13.5px; line-height: 1.65; color: var(--ink-2);
}
/* Why the report exists, set apart by a hairline rather than a wash (§7). */
body[data-page="reports"] .rv-why {
  margin: 13px 0 0; max-width: 88ch;
  padding-left: 13px; border-left: 2px solid var(--hair);
  font-size: 13px; line-height: 1.6; color: #7A7B7E;
}
body[data-page="reports"] .rv-why b {
  display: block; margin-bottom: 3px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.1px;
  text-transform: uppercase; color: var(--navy);
}

/* A bare <select> has no styling outside .filters, so the comparison-basis
   control rendered as a raw native box next to ghost buttons. It is a real
   control and keeps its border — it just matches .btn.sm's metrics. */
body[data-page="reports"] .rv-head select,
body[data-page="reports"] .rb-filters select {
  font: inherit; font-size: 12px; font-weight: 500;
  min-height: 27px; padding: 4px 10px;
  border: 1px solid var(--hair); border-radius: 99px;
  background: var(--surface); color: var(--ink-2); cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}
body[data-page="reports"] .rv-head select:hover,
body[data-page="reports"] .rb-filters select:hover { border-color: #D9D9D4; }
body[data-page="reports"] .rv-head select:focus,
body[data-page="reports"] .rb-filters select:focus {
  outline: 0; border-color: var(--blue); background: #fff; box-shadow: var(--shadow-focus);
}
body[data-page="reports"] .rb-filters select { min-height: 31px; font-size: 12.5px; padding: 6px 12px; }
body[data-page="reports"] .rv-scope {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 11px; font-size: 11.5px; font-weight: 500; color: #A6A6A1;
}
body[data-page="reports"] .rv-scope-ic { display: grid; place-items: center; color: #C2C2BD; }
body[data-page="reports"] .rv-scope-ic svg.ic { width: 13px; height: 13px; }
body[data-page="reports"] .rv-sep { color: #D6D6D1; }
body[data-page="reports"] .rv-fail { margin-top: 13px; border-radius: 10px; border: 1px solid #F0D9D8; border-left-width: 2px; border-left-color: var(--critical); }
body[data-page="reports"] .rv-fail .context-ic { color: var(--critical); border-color: #F0D9D8; }

/* KPI tiles inherit §7.4's raised recipe from the global .kpi — the deltas
   are the only addition, and they state the basis on every tile so a figure
   is never a bare percentage with no comparison attached. */
body[data-page="reports"] .rv-kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: 18px; }
body[data-page="reports"] .rv-kpi { min-height: 128px; }
body[data-page="reports"] .rv-kpi .figure { padding-top: 12px; }
body[data-page="reports"] .rv-kpi .value { font-size: 27px; }
body[data-page="reports"] .rv-kpi-d {
  display: block; margin-top: 8px;
  font-size: 11.5px; font-weight: 500; color: #A6A6A1;
}
body[data-page="reports"] .rv-kpi-d i { font-style: normal; color: #C2C2BD; }
body[data-page="reports"] .rv-kpi-w {
  display: block; margin-top: 5px;
  font-size: 11px; font-weight: 500; color: #B4B4AF;
}
body[data-page="reports"] .rv-kpi.bad .value { color: var(--critical); }
body[data-page="reports"] .rv-card { margin-bottom: 18px; }
body[data-page="reports"] .rv-card:last-child { margin-bottom: 0; }

/* The variance note is the "comparison & variance" capability made visible —
   a stated reading of the movement, not just a delta the reader has to
   interpret. A hairline and an icon, never a wash (§7). */
body[data-page="reports"] .rv-variance {
  display: flex; gap: 12px; align-items: flex-start;
  margin-top: 16px; padding-top: 15px; border-top: 1px solid var(--hair);
}
body[data-page="reports"] .rv-var-ic {
  flex: 0 0 26px; display: grid; place-items: center; width: 26px; height: 26px;
  border: 1px solid var(--hair); border-radius: 8px; color: #8E8F92; background: #fff;
}
body[data-page="reports"] .rv-var-ic svg.ic { width: 14px; height: 14px; }
body[data-page="reports"] .rv-variance b {
  display: block; font-size: 11px; font-weight: 700;
  letter-spacing: 1.1px; text-transform: uppercase; color: var(--navy);
}
body[data-page="reports"] .rv-variance p {
  margin: 6px 0 0; max-width: 92ch;
  font-size: 13px; line-height: 1.65; color: var(--ink-2);
}
body[data-page="reports"] .rv-variance p b { display: inline; font-size: inherit; letter-spacing: 0; text-transform: none; font-weight: 650; color: var(--navy); }

/* ---------- 25.5 Chart primitives ---------- */
body[data-page="reports"] .rv-chart { position: relative; }
body[data-page="reports"] .rv-chart svg { display: block; width: 100%; height: auto; }

body[data-page="reports"] .rv-bars { display: grid; gap: 15px; }
body[data-page="reports"] .rv-bar { min-width: 0; }
body[data-page="reports"] .rv-bar-head { display: flex; align-items: baseline; gap: 10px; font-size: 13.5px; }
body[data-page="reports"] .rv-bar-name {
  display: inline-flex; align-items: center; gap: 8px; min-width: 0;
  font-weight: 500; color: var(--ink);
}
body[data-page="reports"] .rv-bar-name .flag { width: 16px; height: 16px; flex: 0 0 16px; }
body[data-page="reports"] .rv-bar-val {
  margin-left: auto; font-weight: 650; color: var(--navy);
  font-variant-numeric: tabular-nums;
}
body[data-page="reports"] .rv-bar-track {
  height: 6px; margin-top: 9px; border-radius: 99px;
  background: var(--track); overflow: hidden;
}
body[data-page="reports"] .rv-bar-track i {
  display: block; height: 100%; border-radius: 99px;
  background: var(--series);
}
body[data-page="reports"] .rv-bar.tone-warn .rv-bar-track i { background: var(--series-dim); }
body[data-page="reports"] .rv-bar.tone-bad .rv-bar-track i { background: var(--critical); }
body[data-page="reports"] .rv-bar.tone-bad .rv-bar-val { color: var(--critical); }
body[data-page="reports"] .rv-bar-sub { margin-top: 8px; color: #A6A6A1; font-size: 11.5px; font-weight: 500; }
body[data-page="reports"] .rv-bar-sub b { color: #7A7B7E; font-weight: 600; }

body[data-page="reports"] .rv-meters { gap: 18px; }
body[data-page="reports"] .rv-axis {
  display: flex; align-items: center; gap: 12px;
  margin-top: 17px; padding-top: 12px; border-top: 1px solid var(--hair-soft);
  font-size: 11px; font-weight: 500; color: #B4B4AF;
}
body[data-page="reports"] .rv-axis span:nth-child(2) { margin: 0 auto; }

/* Composition: one bar in a sequential blue ramp. Legal under §7's one-hue
   rule because every use of it here is an ORDERED dimension (ageing, SLA
   distance, resolution state) — the same exemption the purchase-window rail
   takes. A categorical set with no order goes to .rv-bars instead, which is
   why there are two shapes and not one. */
body[data-page="reports"] .rv-compo-bar {
  display: flex; height: 34px; border-radius: 8px; overflow: hidden;
  background: var(--track);
}
body[data-page="reports"] .rv-compo-bar i { display: block; height: 100%; }
body[data-page="reports"] .rv-compo-bar i + i { box-shadow: inset 1px 0 0 rgba(255, 255, 255, .55); }
body[data-page="reports"] .rv-compo-legend {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 3px 26px; margin-top: 18px;
}
body[data-page="reports"] .rv-seg {
  display: grid; grid-template-columns: 9px 1fr auto auto;
  align-items: baseline; gap: 4px 9px;
  padding: 9px 0; border-bottom: 1px solid var(--hair-soft);
}
body[data-page="reports"] .rv-seg-sw { width: 9px; height: 9px; border-radius: 3px; }
body[data-page="reports"] .rv-seg-n { font-size: 13px; font-weight: 500; color: var(--ink); min-width: 0; }
body[data-page="reports"] .rv-seg-v { font-size: 13.5px; font-weight: 650; color: var(--navy); font-variant-numeric: tabular-nums; }
body[data-page="reports"] .rv-seg-v.bad { color: var(--critical); }
body[data-page="reports"] .rv-seg-p { font-size: 11.5px; font-weight: 500; color: #B4B4AF; font-variant-numeric: tabular-nums; min-width: 42px; text-align: right; }
body[data-page="reports"] .rv-seg-s {
  grid-column: 2 / -1; font-size: 11.5px; font-weight: 500; color: #A6A6A1;
}

/* ---------- 25.6 Tables ---------- */
/* §8's table convention: 13px gutters, fixed layout against a declared
   colgroup, wrapping cells. `break-word` and not `anywhere` — the latter
   drives min-content sizing and splits an identifier that would have fit
   (the §13 lesson). An action or identifier column never shrinks to fit. */
body[data-page="reports"] .rv-table,
body[data-page="reports"] .rs-table,
body[data-page="reports"] .rb-table { table-layout: fixed; width: 100%; }
body[data-page="reports"] .rv-table th, body[data-page="reports"] .rv-table td,
body[data-page="reports"] .rs-table th, body[data-page="reports"] .rs-table td,
body[data-page="reports"] .rb-table th, body[data-page="reports"] .rb-table td {
  padding-left: 13px; padding-right: 13px;
  white-space: normal; overflow-wrap: break-word;
}
body[data-page="reports"] .rv-table td, body[data-page="reports"] .rs-table td { vertical-align: middle; }
body[data-page="reports"] .rv-twin { width: 100%; }
/* below ~1240px the percentage tracks compress past their content, so the
   wrap scrolls rather than letting short labels print over the next cell */
body[data-page="reports"] .table-wrap table.data { min-width: 1040px; }
body[data-page="reports"] .rv-twin { min-width: 0; }

/* .pill still carries a global white-space: nowrap from before §7 made it a
   dot + label; letting it wrap is what stops sentence-length statuses
   painting into the neighbouring column. */
body[data-page="reports"] .pill { white-space: normal; }
body[data-page="reports"] .r-pos { color: var(--good); font-weight: 600; }
body[data-page="reports"] .r-neg { color: var(--critical); font-weight: 600; }
body[data-page="reports"] .mono { font-size: 12.5px; color: var(--ink-2); }

/* renderMarks() replaces the slot's innerHTML, so the .mk sits one level
   deeper than on the JS-rendered pages and the wrapper needs its own basis
   (§22.5). Flags go OUTSIDE a text block, never inside one — .o-loc and its
   relatives make every child span a block, so a flag placed within drops onto
   its own row. That trap has now been hit on qc, customs and catalog. */
body[data-page="reports"] .o-mp .mk-slot { flex: 0 0 26px; display: block; }
body[data-page="reports"] .o-mp > span:last-child {
  min-width: 0; font-size: 12.5px; font-weight: 500; color: var(--ink);
}
body[data-page="reports"] .rv-geo { display: flex; align-items: center; gap: 8px; min-width: 0; }
body[data-page="reports"] .rv-geo .flag { width: 18px; height: 18px; flex: 0 0 18px; }
body[data-page="reports"] .rv-geo > span { min-width: 0; }
body[data-page="reports"] .rs-bad td { color: var(--ink); }

/* ---------- 25.7 Scheduled delivery ---------- */
body[data-page="reports"] #rep-sched .pane-context { border-top: 0; }

/* ---------- 25.8 The builder ---------- */
body[data-page="reports"] .rb-grid {
  display: grid; grid-template-columns: minmax(0, 330px) minmax(0, 1fr);
  gap: 0; align-items: start;
}
body[data-page="reports"] .rb-picker {
  padding: 18px 20px 20px; border-right: 1px solid var(--hair);
  min-height: 420px;
}
body[data-page="reports"] .rb-picker h3 {
  margin: 0 0 10px; font-size: 10.5px; font-weight: 700;
  letter-spacing: 1.15px; text-transform: uppercase; color: var(--navy);
}
body[data-page="reports"] .rb-picker h3 small {
  font-size: 10.5px; font-weight: 500; letter-spacing: .4px;
  text-transform: none; color: #B4B4AF; margin-left: 6px;
}
body[data-page="reports"] .rb-picker h3 + .rb-chips { margin-bottom: 20px; }
body[data-page="reports"] .rb-chips { display: flex; flex-wrap: wrap; gap: 5px; }
body[data-page="reports"] .rb-filters { display: grid; gap: 7px; margin-bottom: 16px; }
body[data-page="reports"] .rb-filters select { width: 100%; }
body[data-page="reports"] .rb-note {
  margin: 0; padding-top: 14px; border-top: 1px solid var(--hair-soft);
  font-size: 11.5px; line-height: 1.6; color: #A6A6A1;
}
body[data-page="reports"] .rb-preview { min-width: 0; }
body[data-page="reports"] .rb-preview .card-head { border-bottom: 1px solid var(--hair); }
body[data-page="reports"] .rb-preview .table-wrap table.data { min-width: 0; }
body[data-page="reports"] .rb-total td {
  border-top: 1px solid var(--line-strong);
  font-weight: 650; color: var(--navy); background: #FCFCFB;
}

/* ---------- 25.9 Folds ---------- */
@media (max-width: 1400px) {
  body[data-page="reports"] .rv-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1240px) {
  body[data-page="reports"] .rp-grid { grid-template-columns: minmax(0, 1fr); }
  body[data-page="reports"] .rv-compo-legend { grid-template-columns: minmax(0, 1fr); }
  body[data-page="reports"] .rb-grid { grid-template-columns: minmax(0, 1fr); }
  body[data-page="reports"] .rb-picker { border-right: 0; border-bottom: 1px solid var(--hair); min-height: 0; }
}
@media (max-width: 980px) {
  body[data-page="reports"] .rv-title h2 { font-size: 19px; }
  body[data-page="reports"] .rp-figv { font-size: 25px; }
}
@media (max-width: 760px) {
  body[data-page="reports"] .rv-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 11px; }
  body[data-page="reports"] .rp-sparkwrap { display: none; }
  body[data-page="reports"] .rp-grid { padding: 4px 14px 16px; }
}

/* ---------- 25.10 Scope bar ---------- */
body[data-page="reports"] .scope-bar {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 20px; border-bottom: 1px solid var(--hair);
  background: var(--hair-soft);
  font-size: 12.5px; font-weight: 500; color: var(--ink-2);
}
body[data-page="reports"] .scope-bar b { font-weight: 650; color: var(--navy); }
body[data-page="reports"] .scope-bar .btn { margin-left: auto; }
/* [hidden] is a UA rule at the lowest specificity, so the display:flex above
   beats it and an empty bar paints a grey strip under the tabs. §19.6. */
body[data-page="reports"] .scope-bar[hidden] { display: none; }


/* ============================================================
   26. Ticketing — §15 applied, 2026-07-29
   ------------------------------------------------------------
   Gaurav: "now similarly do for tickets page." Ran the §16
   diagnosis. Like §24 on approvals, the shortfall here is NOT
   missing geography — a ticket routes between TEAMS ("QC
   (S. Patil) → Cataloging (P. Iyer)"), not between countries,
   and the only place named anywhere on the page is one rack
   label. Forcing flags on would have been decoration for its
   own sake, which §7 forbids. What it had instead:

     · SIX orange .btn.primary in the rows — four "Open", two
       "Respond". §8: orange is the toolbar's. Same violation
       §24 found on approvals, and on the same shape of page.
     · the .page-head breadcrumb, five KPI tiles with .delta
       sub-lines and inline colour, and an inline
       grid-template-columns on .kpis
     · 31 inline style= attributes, 27 of them <col width>
     · and the finding that makes this page distinct: it was
       the LEAST self-explanatory page in the deck — ZERO pane
       context notes and ZERO footers on any of four tabs. Four
       loaded rows read as "19 open tickets" with nothing
       saying otherwise, and the two PRD facts this page exists
       to demonstrate (any-member-to-any-member, email intake,
       configurable SLA) lived in a floating .mock-note in the
       breadcrumb that the v3 toolbar removes.

   So the work here is mostly RESTORING what the page asserts,
   not restyling what it draws.

   Scoped to body[data-page="tickets"] throughout — #pane-mine
   is ALSO approvals', so an unscoped budget would re-cut §24.
   §13 already owns this page's white-space / height / gutters
   and its table-layout: fixed; this section does not restate
   them.
   ============================================================ */

/* ---------- 26.1 Five tiles ---------- */
/* Was an inline grid-template-columns on .kpis. Five is a layout decision and
   belongs with the folds below, not in the markup. */
body[data-page="tickets"] .kpis { grid-template-columns: repeat(5, minmax(0, 1fr)); }

/* ---------- 26.2 The page says what it is ---------- */
/* Four panes, no context of any kind. Same recipe as §20 .c-note / §23
   .k-note / §24 .a-note, own name and own scope — each is measured on its own
   page (the .chip incident in §14 is why these never share a class). */
body[data-page="tickets"] .t-note {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--hair-soft);
  color: #8A8B8E; font-size: 12.5px; font-weight: 500; line-height: 1.65;
}
body[data-page="tickets"] .t-note > div { flex: 1; min-width: 0; }
body[data-page="tickets"] .t-note b { color: var(--navy); font-weight: 650; }
body[data-page="tickets"] .t-note i { font-style: italic; }
body[data-page="tickets"] .t-note a { color: #7A7B7E; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
body[data-page="tickets"] .t-note a:hover { color: var(--orange); }
body[data-page="tickets"] .t-note > span:first-child { flex: 0 0 auto; color: #C2C2BD; margin-top: 1px; }
body[data-page="tickets"] .t-note > span:first-child svg.ic { display: block; width: 15px; height: 15px; }

/* a breached SLA date, replacing inline style="color:var(--critical-text)" */
body[data-page="tickets"] table.data td.t-late,
body[data-page="tickets"] table.data td.t-late b { color: var(--critical-text); }

/* ---------- 26.3 Filter row — chrome down, not controls out ---------- */
body[data-page="tickets"] .filters { gap: 4px; padding: 15px 20px 14px; }
body[data-page="tickets"] .filters select {
  border-color: transparent; background-color: transparent;
  color: #7A7B7E; font-weight: 600;
}
body[data-page="tickets"] .filters select:hover { border-color: var(--hair); background-color: var(--surface); }
body[data-page="tickets"] .filters select:focus { border-color: var(--blue); background-color: #fff; }
body[data-page="tickets"] .filters input { background: transparent; border-color: var(--hair-soft); }
body[data-page="tickets"] .filters input:hover { border-color: var(--hair); }
body[data-page="tickets"] .filters input:focus { background: #fff; border-color: var(--blue); }

/* ---------- 26.4 Row air ---------- */
/* Vertical only; §13 owns this page's horizontal gutters. */
body[data-page="tickets"] table.data td { padding-top: 15px; padding-bottom: 15px; }
body[data-page="tickets"] table.data th { padding-top: 13px; padding-bottom: 11px; }

/* ---------- 26.5 Headers wrap ---------- */
body[data-page="tickets"] table.data th { white-space: normal; }
/* but a control never breaks mid-label */
body[data-page="tickets"] table.data td.actions .btn { white-space: nowrap; }

/* ---------- 26.6 Column budgets, off inline style= and onto classes ------- */
/* Same percentages §13 measured and landed — this is a move, not a re-cut, so
   the four tables stay at the 1296px they were verified at. Named cols mean
   the budget can be audited in one place instead of read out of the markup. */
/* All-open re-cut so the two IDENTIFIER columns hold one line. §13's original
   figures were measured while the table sized by content; under a fixed layout
   they left "TKT-2026-0341" breaking at a hyphen (113px of text in 77px) and
   "403-9312876-7712345" over three lines (144px in 77px). §23's rule applies —
   a wrapped identifier is a defect, a wrapped title is not — so the width comes
   out of Subject and From → To, both of which are prose that already sit above
   a sub-line. Measured per line against its own font (§20's method); gutters
   here are §13's 20px, not the 13px the newer pages use. */
body[data-page="tickets"] #pane-open col.tk-tkt   { width: 13%; }
body[data-page="tickets"] #pane-open col.tk-subj  { width: 13%; }
body[data-page="tickets"] #pane-open col.tk-route { width: 11%; }
body[data-page="tickets"] #pane-open col.tk-link  { width: 16%; }
body[data-page="tickets"] #pane-open col.tk-rsd   { width: 10%; }
body[data-page="tickets"] #pane-open col.tk-sla   { width: 10%; }
body[data-page="tickets"] #pane-open col.tk-pri   { width: 8%;  }
body[data-page="tickets"] #pane-open col.tk-st    { width: 9%;  }
body[data-page="tickets"] #pane-open col.tk-act   { width: 10%; }

body[data-page="tickets"] #pane-mine col.tk-tkt  { width: 13%; }
body[data-page="tickets"] #pane-mine col.tk-subj { width: 23%; }
body[data-page="tickets"] #pane-mine col.tk-from { width: 16%; }
body[data-page="tickets"] #pane-mine col.tk-sla  { width: 14%; }
body[data-page="tickets"] #pane-mine col.tk-pri  { width: 10%; }
body[data-page="tickets"] #pane-mine col.tk-st   { width: 12%; }
body[data-page="tickets"] #pane-mine col.tk-act  { width: 12%; }

body[data-page="tickets"] #pane-raised col.tk-tkt  { width: 13%; }
body[data-page="tickets"] #pane-raised col.tk-subj { width: 29%; }
body[data-page="tickets"] #pane-raised col.tk-to   { width: 18%; }
body[data-page="tickets"] #pane-raised col.tk-rsd  { width: 13%; }
body[data-page="tickets"] #pane-raised col.tk-st   { width: 15%; }
body[data-page="tickets"] #pane-raised col.tk-act  { width: 12%; }

body[data-page="tickets"] #pane-closed col.tk-tkt   { width: 13%; }
body[data-page="tickets"] #pane-closed col.tk-subj  { width: 28%; }
body[data-page="tickets"] #pane-closed col.tk-route { width: 20%; }
body[data-page="tickets"] #pane-closed col.tk-res   { width: 13%; }
body[data-page="tickets"] #pane-closed col.tk-ttr   { width: 14%; }
body[data-page="tickets"] #pane-closed col.tk-out   { width: 12%; }

/* ---------- 26.7 Below the reference width, scroll rather than clip ------- */
/* tickets is a §13 page and §13's pages WRAP rather than scroll, which is
   correct while a table sizes by content. Under §13's own table-layout: fixed
   it is not: every percentage track narrows with the card, so below ~1240px
   short labels printed over the next cell and three headers clipped mid-word
   (measured 8 element spills, 7 text spills, 3 truncated headers at 980px).
   That is exactly the symptom §22 fixed on returns by adopting the orders
   floor, and the note there records that the remaining §13 pages still had
   theirs. This is tickets'.

   The §21 JIT objection — a floor putting action controls off-screen — was
   checked and does not apply: clipped controls stay at 0 across the sweep,
   because .table-wrap scrolls and every button remains reachable. 1180px is
   the All-open tab, which carries nine columns. */
body[data-page="tickets"] table.data { min-width: 1240px; }

/* ---------- 26.8 Folds ---------- */
@media (max-width: 1240px) {
  body[data-page="tickets"] .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  body[data-page="tickets"] .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  body[data-page="tickets"] .t-note { padding: 14px 16px; }
}
