/* ==========================================================================
   DFW Logistics - MB016
   Built to be read at arm's length, outdoors, on a cracked phone screen.
   Light-primary on purpose: job sites are bright, and dark UI loses to Texas
   sun. Dark mode exists for night shift.
   ========================================================================== */

:root {
  /* Surfaces: poured concrete and a clipboard form */
  --concrete:   #E9EAEC;
  --concrete-2: #DFE1E4;
  --slab:       #FFFFFF;
  --ink:        #12151A;
  --ink-2:      #4A525E;
  --ink-3:      #79828F;
  --rule:       #CFD3D8;
  --rule-soft:  #E4E6E9;

  /* Structure: blueprint ink and equipment enamel */
  --blueprint:  #17416E;
  --blueprint-2:#255C96;
  --blueprint-w:#E8EEF5;

  /* Signals: site safety vernacular */
  --hazard:     #D6252B;   /* OUT / NEEDS SERVICE / LATE */
  --hazard-w:   #FCEBEB;
  --amber:      #F2B300;   /* LOW / pending / in transit */
  --amber-w:    #FDF4DC;
  --amber-ink:  #7A5A00;
  --go:         #1B7F4E;   /* OK / RETURNED / delivered */
  --go-w:       #E7F4ED;
  --flag:       #E2650C;   /* stored value disagrees with derived */
  --flag-w:     #FDF0E4;

  /* Dispatch flow. A separate axis from the signal colours above, because
     those already mean severity and a load being in transit is not a problem.
     Reads as a journey: concrete, blueprint, steel, amber, green.

     Every ink here is darkened until it clears 4.5:1 against its own wash,
     measured rather than eyeballed. This is the primary theme and it is read
     outdoors in Texas sun, so the first pass (#0A7EA4 transit at 3.98,
     #A8730A staging at 3.62) was not good enough even though it looked fine
     on a desk monitor. */
  --f-queued:   #5A6470;   --f-queued-w:   #E6E8EB;   /* 4.90 */
  --f-pulling:  #17416E;   --f-pulling-w:  #E4ECF5;   /* 8.73 */
  --f-transit:  #0A6A8A;   --f-transit-w:  #DFF1F7;   /* 5.25 */
  --f-staging:  #8F6207;   --f-staging-w:  #FBF0D5;   /* 4.73 */
  --f-delivered:#166B41;   --f-delivered-w:#E4F3EB;   /* 5.70 */
  --f-cancelled:#626A73;   --f-cancelled-w:#EDEEF0;   /* 4.72 */

  /* Type roles.
     Display is Bahnschrift where available: it is Microsoft's DIN, the same
     industrial face used on equipment plates and container markings. It ships
     with Windows, so no webfont and no CDN. */
  --f-display: "Bahnschrift", "DIN Alternate", "Roboto Condensed", "Arial Narrow", system-ui, sans-serif;
  --f-body: system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --f-mono: "Cascadia Mono", ui-monospace, "SF Mono", Consolas, "Roboto Mono", monospace;

  --spine: 6px;
  --radius: 3px;
  --shadow: 0 1px 2px rgba(18, 21, 26, .09), 0 4px 12px -6px rgba(18, 21, 26, .14);
  --maxw: 1560px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --concrete:   #14171B;
    --concrete-2: #1B1F25;
    --slab:       #1E232A;
    --ink:        #EDEFF2;
    --ink-2:      #A8B2BE;
    --ink-3:      #78828E;
    --rule:       #333A44;
    --rule-soft:  #272D35;
    --blueprint:  #7FB0E4;
    --blueprint-2:#A6CBF2;
    --blueprint-w:#1B2C3E;
    --hazard:     #FF6B6B;
    --hazard-w:   #3A1D1F;
    --amber:      #F5C33B;
    --amber-w:    #372D12;
    --amber-ink:  #F5C33B;
    --go:         #4FBF85;
    --go-w:       #16302483;
    --flag:       #FF9448;
    --flag-w:     #3A2515;

    /* Same ramp, lifted for a dark surface. The washes stay dark and the ink
       goes bright, so a chip is legible without becoming a light rectangle. */
    --f-queued:   #A3ACB8;   --f-queued-w:   #262B32;
    --f-pulling:  #7FB0E4;   --f-pulling-w:  #16283C;
    --f-transit:  #4FC3E0;   --f-transit-w:  #10303A;
    --f-staging:  #F5C33B;   --f-staging-w:  #372D12;
    --f-delivered:#4FBF85;   --f-delivered-w:#16302A;
    --f-cancelled:#8B939C;   --f-cancelled-w:#23272C;   /* 4.83, was 3.23 */

    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 4px 14px -6px rgba(0,0,0,.6);
  }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--concrete);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: 1.2; }

a { color: var(--blueprint); }

.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--blueprint); color: #fff; padding: .6rem 1rem; font-weight: 600;
}
.skip:focus { left: 0; }

:focus-visible {
  outline: 3px solid var(--blueprint);
  outline-offset: 2px;
}

/* ---------- Top bar ------------------------------------------------------ */

.topbar {
  position: sticky; top: 0; z-index: 40;
  background: var(--blueprint);
  color: #fff;
}

.topbar-in {
  max-width: var(--maxw); margin: 0 auto;
  display: flex; align-items: center; gap: 1.5rem;
  padding: .55rem 1rem;
}

.brand { display: flex; align-items: center; gap: .65rem; flex: 0 0 auto; }

/* Three bars: the stencil stripe on a container door */
.brand-mark { display: flex; flex-direction: column; gap: 3px; }
.brand-bar { display: block; width: 22px; height: 4px; background: var(--amber); }
.brand-bar:nth-child(2) { width: 15px; }
.brand-bar:nth-child(3) { width: 19px; }

.brand-text { display: flex; flex-direction: column; line-height: 1.1; }
.brand-text b {
  font-family: var(--f-display); font-size: 1.06rem; font-weight: 700;
  letter-spacing: .06em;
}
.brand-text em {
  font-style: normal; font-size: .68rem; color: #A9C4DF;
  letter-spacing: .06em; margin-top: 2px;
}

.groupnav { display: flex; gap: .15rem; flex-wrap: wrap; flex: 1 1 auto; }

.groupnav a {
  font-family: var(--f-display);
  font-size: .93rem; letter-spacing: .045em;
  color: #C6D9EC; text-decoration: none;
  padding: .42rem .78rem; border-radius: var(--radius);
  white-space: nowrap;
}
.groupnav a:hover { background: rgba(255,255,255,.1); color: #fff; }
.groupnav a[aria-current="true"] { background: var(--slab); color: var(--blueprint); font-weight: 700; }
@media (prefers-color-scheme: dark) {
  .topbar { background: #0E1F31; }
  .groupnav a[aria-current="true"] { background: var(--blueprint); color: #0E1F31; }
}

.navtoggle {
  display: none;
  font: inherit; font-weight: 600;
  background: rgba(255,255,255,.12); color: #fff;
  border: 0; border-radius: var(--radius); padding: .42rem .8rem; cursor: pointer;
}

.subnav {
  background: var(--slab);
  border-bottom: 1px solid var(--rule);
  display: flex; gap: .1rem; overflow-x: auto;
  padding: 0 1rem;
  scrollbar-width: thin;
}
.subnav-in { max-width: var(--maxw); margin: 0 auto; display: flex; gap: .1rem; }
.subnav a {
  font-size: .84rem; color: var(--ink-2); text-decoration: none;
  padding: .55rem .7rem; white-space: nowrap;
  border-bottom: 3px solid transparent;
}
.subnav a:hover { color: var(--ink); }
.subnav a[aria-current="true"] {
  color: var(--blueprint); font-weight: 600;
  border-bottom-color: var(--amber);
}
.subnav:empty { display: none; }

/* ---------- Scaffold notice ---------------------------------------------- */

.scaffold-note {
  background: var(--amber-w); color: var(--amber-ink);
  border-bottom: 1px solid var(--amber);
  font-size: .84rem; padding: .5rem 1rem;
  display: flex; align-items: center; gap: .5rem; justify-content: center;
}
.scaffold-note strong { color: inherit; }
.scaffold-note button {
  background: none; border: 0; color: inherit; font-size: 1.2rem;
  line-height: 1; cursor: pointer; padding: 0 .3rem; margin-left: .4rem;
}
.scaffold-note[hidden] { display: none; }

/* ---------- Layout ------------------------------------------------------- */

main {
  max-width: var(--maxw); margin: 0 auto;
  padding: 1.4rem 1rem 3rem;
  outline: none;
}

.viewhead { margin-bottom: 1.15rem; }

/* The eyebrow names the sheet tab this view replaces. That is real
   information during a migration, not decoration. */
.eyebrow {
  font-family: var(--f-mono); font-size: .7rem; letter-spacing: .04em;
  color: var(--ink-3); text-transform: none;
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin-bottom: .3rem;
}
.eyebrow .tag {
  background: var(--concrete-2); color: var(--ink-2);
  padding: .1rem .4rem; border-radius: 2px;
}
.eyebrow .derived {
  background: var(--blueprint-w); color: var(--blueprint);
  padding: .1rem .4rem; border-radius: 2px; font-weight: 600;
}

.viewhead h1 {
  font-family: var(--f-display); font-size: 1.85rem;
  letter-spacing: .01em; font-weight: 700;
}
.viewhead p {
  margin: .35rem 0 0; color: var(--ink-2); max-width: 68ch; font-size: .92rem;
}

.toolbar {
  display: flex; gap: .5rem; flex-wrap: wrap; align-items: center;
  margin: 1rem 0;
}
.toolbar .grow { flex: 1 1 auto; }

/* ---------- Panels ------------------------------------------------------- */

.panel {
  background: var(--slab);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin-bottom: 1.25rem;
  overflow: hidden;
}
.panel-head {
  display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap;
  padding: .7rem .9rem;
  border-bottom: 1px solid var(--rule-soft);
}
.panel-head h2 {
  font-family: var(--f-display); font-size: 1.02rem; letter-spacing: .03em;
}
.panel-head .sub { color: var(--ink-3); font-size: .8rem; }
.panel-body { padding: .9rem; }
.panel-body > :first-child { margin-top: 0; }
.panel-body > :last-child { margin-bottom: 0; }

/* ---------- Buttons ------------------------------------------------------ */

.btn {
  font: inherit; font-size: .88rem; font-weight: 600;
  background: var(--slab); color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: .45rem .85rem; cursor: pointer;
  display: inline-flex; align-items: center; gap: .4rem;
}
.btn:hover { border-color: var(--ink-3); }
.btn-primary {
  background: var(--blueprint); border-color: var(--blueprint); color: #fff;
}
.btn-primary:hover { background: var(--blueprint-2); border-color: var(--blueprint-2); }
.btn-sm { font-size: .78rem; padding: .25rem .55rem; }
.btn[disabled] { opacity: .45; cursor: not-allowed; }
@media (prefers-color-scheme: dark) {
  .btn-primary { color: #0E1F31; }
}

/* ---------- Inputs ------------------------------------------------------- */

input, select, textarea {
  font: inherit; font-size: .9rem;
  background: var(--slab); color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: .42rem .55rem; width: 100%;
}
textarea { min-height: 4.5rem; resize: vertical; }
input[type="search"] { max-width: 22rem; }

/* The rule above sets width:100% because every field in a form grid wants it.
   A checkbox does not: it made the vendor picker's boxes 513px wide, with the
   company name stranded on the far side of the row. No other checkbox exists in
   the app today, so this is fixed at the source rather than patched per
   component and left to catch the next one. */
input[type="checkbox"], input[type="radio"] {
  width: auto; flex: 0 0 auto; padding: 0; margin: 0;
}

.field { margin-bottom: .8rem; }
.field label {
  display: block; font-size: .78rem; font-weight: 600;
  color: var(--ink-2); margin-bottom: .22rem;
  letter-spacing: .02em;
}
.field .hint { font-size: .74rem; color: var(--ink-3); margin-top: .22rem; }
.field .req { color: var(--hazard); }

.formgrid {
  display: grid; gap: 0 1rem;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.formgrid .wide { grid-column: 1 / -1; }

/* ---------- Tables ------------------------------------------------------- */

.tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table.data {
  width: 100%; border-collapse: collapse; font-size: .85rem;
}
table.data th {
  font-family: var(--f-display); font-weight: 700;
  font-size: .78rem; letter-spacing: .05em;
  text-align: left; color: var(--ink-2);
  background: var(--concrete);
  padding: .5rem .6rem; white-space: nowrap;
  border-bottom: 1px solid var(--rule);
  position: sticky; top: 0; z-index: 1;
}
table.data td {
  padding: .48rem .6rem;
  border-bottom: 1px solid var(--rule-soft);
  vertical-align: top;
}
table.data tbody tr:hover td { background: var(--concrete); }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data td.mono { font-family: var(--f-mono); font-size: .8rem; }
table.data td.wrap { min-width: 16rem; white-space: normal; }
table.data .muted { color: var(--ink-3); }

/* SIGNATURE: the status spine.
   A colour bar on the leading edge of every row, so a screen's health reads
   as a stripe pattern before you read a single word. */
table.data td:first-child,
table.data th:first-child { border-left: var(--spine) solid transparent; padding-left: .6rem; }
tr[data-state="bad"]  td:first-child { border-left-color: var(--hazard); }
tr[data-state="warn"] td:first-child { border-left-color: var(--amber); }
tr[data-state="good"] td:first-child { border-left-color: var(--go); }
tr[data-state="flag"] td:first-child { border-left-color: var(--flag); }
tr[data-state="idle"] td:first-child { border-left-color: var(--rule); }

/* A data-integrity problem is not a site condition, so it gets a texture,
   not just a hue: hazard tape across the row. */
tr[data-state="flag"] td { background: var(--flag-w); }
tr[data-state="flag"] td:first-child {
  background-image: repeating-linear-gradient(
    45deg, var(--flag) 0 5px, transparent 5px 10px);
  background-size: var(--spine) 100%;
  background-repeat: no-repeat;
  background-position: left top;
}

.empty {
  padding: 2rem 1rem; text-align: center; color: var(--ink-3); font-size: .9rem;
}
.rowcount { font-size: .78rem; color: var(--ink-3); font-family: var(--f-mono); }

/* ---------- Status chips ------------------------------------------------- */

.chip {
  display: inline-block;
  font-family: var(--f-display); font-size: .74rem; font-weight: 700;
  letter-spacing: .06em;
  padding: .12rem .45rem; border-radius: 2px;
  border: 1px solid; white-space: nowrap;
}
.chip-bad  { background: var(--hazard-w); border-color: var(--hazard); color: var(--hazard); }
.chip-warn { background: var(--amber-w);  border-color: var(--amber);  color: var(--amber-ink); }
.chip-good { background: var(--go-w);     border-color: var(--go);     color: var(--go); }
.chip-flag { background: var(--flag-w);   border-color: var(--flag);   color: var(--flag); }
.chip-idle { background: var(--concrete-2); border-color: var(--rule); color: var(--ink-2); }

/* Dispatch flow chips. Distinct hues so PULLING, IN TRANSIT and STAGING can be
   told apart at a glance, which they could not when all three were amber. */
.chip-queued    { background: var(--f-queued-w);    border-color: var(--f-queued);    color: var(--f-queued); }
.chip-pulling   { background: var(--f-pulling-w);   border-color: var(--f-pulling);   color: var(--f-pulling); }
.chip-transit   { background: var(--f-transit-w);   border-color: var(--f-transit);   color: var(--f-transit); }
.chip-staging   { background: var(--f-staging-w);   border-color: var(--f-staging);   color: var(--f-staging); }
.chip-delivered { background: var(--f-delivered-w); border-color: var(--f-delivered); color: var(--f-delivered); }

/* Cancelled reads as struck out rather than as another colour. A dead load
   should not compete for attention with a live one. */
.chip-cancelled {
  background: var(--f-cancelled-w); border-color: var(--f-cancelled);
  color: var(--f-cancelled); border-style: dashed;
  text-decoration: line-through; opacity: .85;
}

/* ---------- Stat tiles --------------------------------------------------- */

.tiles {
  display: grid; gap: .8rem;
  grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  margin-bottom: 1.25rem;
}
.tile {
  background: var(--slab); border: 1px solid var(--rule);
  border-left: var(--spine) solid var(--rule);
  border-radius: var(--radius); padding: .7rem .8rem;
  box-shadow: var(--shadow);
  text-decoration: none; color: inherit; display: block;
}
a.tile:hover { border-color: var(--ink-3); }
.tile[data-state="bad"]  { border-left-color: var(--hazard); }
.tile[data-state="warn"] { border-left-color: var(--amber); }
.tile[data-state="good"] { border-left-color: var(--go); }
.tile .k {
  font-size: .7rem; letter-spacing: .06em; color: var(--ink-3);
  font-family: var(--f-display); font-weight: 600;
}
.tile .v {
  font-family: var(--f-display); font-size: 2.1rem; font-weight: 700;
  line-height: 1.05; font-variant-numeric: tabular-nums; margin-top: .1rem;
}
.tile[data-state="bad"] .v { color: var(--hazard); }
.tile[data-state="warn"] .v { color: var(--amber-ink); }
.tile .note { font-size: .74rem; color: var(--ink-3); }

/* ---------- Load board (dashboard signature) ----------------------------- */

.board {
  display: grid; gap: .8rem;
  grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
}
.load {
  background: var(--slab); border: 1px solid var(--rule);
  border-left: var(--spine) solid var(--rule);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: .75rem .85rem;
}
.load[data-state="bad"]  { border-left-color: var(--hazard); }
.load[data-state="warn"] { border-left-color: var(--amber); }
.load[data-state="good"] { border-left-color: var(--go); }

/* The spine carries the flow stage, so a card matches the chip inside it and
   a board can be read by colour alone from across the room. An overdue load
   still overrides to hazard red below: running late outranks the stage. */
.load[data-flow="queued"]    { border-left-color: var(--f-queued); }
.load[data-flow="pulling"]   { border-left-color: var(--f-pulling); }
.load[data-flow="transit"]   { border-left-color: var(--f-transit); }
.load[data-flow="staging"]   { border-left-color: var(--f-staging); }
.load[data-flow="delivered"] { border-left-color: var(--f-delivered); }
.load[data-flow="cancelled"] {
  border-left-color: var(--f-cancelled);
  opacity: .62;
}
.load[data-state="bad"][data-flow] { border-left-color: var(--hazard); }
.load-top {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: .5rem; margin-bottom: .4rem;
}
.load-zone {
  font-family: var(--f-display); font-size: 1.3rem; font-weight: 700;
  letter-spacing: .02em;
}
.load-mat { font-size: .88rem; margin-bottom: .5rem; }
.load-meta {
  font-size: .76rem; color: var(--ink-2);
  display: flex; flex-wrap: wrap; gap: .15rem .7rem;
}
.load-meta b { font-weight: 600; color: var(--ink); }
.elapsed {
  font-family: var(--f-mono); font-size: .82rem;
  font-variant-numeric: tabular-nums;
}

/* ---------- Daily report: trend and compliance --------------------------- */

/* Six workday bars. The count is printed above each one rather than shown on
   hover, because this page gets printed and a tooltip does not survive paper. */
.trend {
  display: flex; align-items: flex-end; gap: .5rem;
  height: 150px; padding-top: .2rem;
}
.trend-col {
  flex: 1 1 0; display: flex; flex-direction: column;
  align-items: center; height: 100%; min-width: 0;
}
.trend-n {
  font-family: var(--f-display); font-size: .95rem; font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
.trend-bar { flex: 1 1 auto; width: 100%; display: flex; align-items: flex-end; }
.trend-fill {
  width: 100%; background: var(--blueprint);
  border-radius: 2px 2px 0 0; min-height: 2px;
}
.trend-d {
  font-size: .72rem; color: var(--ink-2); margin-top: .3rem;
  letter-spacing: .04em; text-transform: uppercase;
}

/* Ranked compliance. The raw counts sit under every name on purpose: a bare
   percentage with no denominator cannot be checked by whoever reads it. */
.complist { display: flex; flex-direction: column; gap: .55rem; }
.comprow {
  display: flex; align-items: center; gap: .7rem;
  padding: .45rem .1rem; border-bottom: 1px solid var(--rule-soft);
}
.comprow:last-child { border-bottom: 0; }
.comp-rank {
  font-family: var(--f-display); font-size: .95rem; font-weight: 700;
  color: var(--ink-3); width: 1.2rem; text-align: right; flex: 0 0 auto;
}
.comp-main { flex: 1 1 auto; min-width: 0; }
.comp-name {
  font-weight: 600; font-size: .92rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.comp-sub { font-size: .76rem; color: var(--ink-2); margin: .05rem 0 .28rem; }
.comp-bar {
  height: 6px; background: var(--concrete-2);
  border-radius: 3px; overflow: hidden;
}
.comp-fill { height: 100%; background: var(--ink-3); border-radius: 3px; }
.comprow[data-state="good"] .comp-fill { background: var(--go); }
.comprow[data-state="warn"] .comp-fill { background: var(--amber); }
.comprow[data-state="bad"]  .comp-fill { background: var(--hazard); }
.comp-pct {
  font-family: var(--f-display); font-size: 1.25rem; font-weight: 700;
  font-variant-numeric: tabular-nums; flex: 0 0 auto; min-width: 3rem;
  text-align: right;
}
.comprow[data-state="bad"] .comp-pct { color: var(--hazard); }
.comprow[data-state="warn"] .comp-pct { color: var(--amber-ink); }

.twoup {
  display: grid; gap: 0 1rem;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

/* Status picker inside a table row. Sized to stay on one line next to the
   Label link without stretching the actions column. */
.rowstatus {
  min-width: 8.5rem; font-size: .8rem;
  padding: .25rem .4rem;
}

/* ---------- Toolbar filter and sort controls ----------------------------- */

.ctl { display: flex; align-items: center; gap: .35rem; }
.ctl > span {
  font-size: .74rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3); white-space: nowrap;
}
.ctl select { min-width: 9rem; }

/* ---------- Generated filename preview ----------------------------------- */

.fname {
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  background: var(--concrete); border: 1px dashed var(--rule);
  border-radius: var(--radius); padding: .55rem .7rem; margin-bottom: .8rem;
}
.fname code {
  font-family: var(--f-mono); font-size: .82rem; color: var(--ink);
  overflow-wrap: anywhere;
}

/* ---------- Cleanup workbench -------------------------------------------- */

.fix-head {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  margin-bottom: .4rem;
}
.fix-owner {
  font-size: .8rem; font-weight: 600; color: var(--ink-2);
}
.fix-blurb {
  margin: 0 0 .9rem; font-size: .87rem; color: var(--ink-2);
  max-width: 84ch;
}

/* One action. The severity spine is the only colour, so a wall of these still
   reads as a list rather than as an alarm. */
.fix {
  border: 1px solid var(--rule); border-left: var(--spine) solid var(--rule);
  border-radius: var(--radius); background: var(--slab);
  padding: .7rem .85rem; margin-bottom: .6rem;
}
.fix[data-sev="1"] { border-left-color: var(--hazard); }
.fix[data-sev="2"] { border-left-color: var(--amber); }
.fix[data-sev="3"] { border-left-color: var(--rule); }

.fix-what { font-weight: 600; font-size: .92rem; line-height: 1.35; }
.fix-detail {
  font-size: .84rem; color: var(--ink-2); margin-top: .18rem;
  overflow-wrap: anywhere;
}
.fix-action {
  margin-top: .5rem; font-size: .87rem; line-height: 1.45;
  max-width: 92ch;
}
.fix-k {
  display: inline-block; font-family: var(--f-display); font-size: .68rem;
  font-weight: 700; letter-spacing: .1em; color: var(--blueprint);
  background: var(--blueprint-w); border-radius: 2px;
  padding: .05rem .3rem; margin-right: .4rem; vertical-align: 1px;
}
.fix-rows {
  margin: .55rem 0 0; padding: .5rem 0 0 0; list-style: none;
  border-top: 1px dashed var(--rule-soft);
  font-size: .8rem; color: var(--ink-2);
}
.fix-rows li { padding: .1rem 0; overflow-wrap: anywhere; }
.fix-rows code {
  font-family: var(--f-mono); font-size: .76rem;
  background: var(--concrete-2); border-radius: 2px; padding: .02rem .25rem;
  color: var(--ink);
}
.fix-rows li.muted { color: var(--ink-3); font-style: italic; }

/* ---------- Big ID readout (equipment / item detail) --------------------- */

.idplate {
  font-family: var(--f-display); font-weight: 700;
  font-size: 1.5rem; letter-spacing: .02em;
}
.idsmall { font-family: var(--f-mono); font-size: .8rem; color: var(--ink-2); }

/* Reference list inside a panel body (the request category legend). Layout
   only: it introduces no colour, so there is no new contrast pair to measure. */
.plainlist { margin: 0 0 .6rem; padding-left: 1.1rem; }
.plainlist li { margin: .2rem 0; line-height: 1.45; }

/* ---------- Requests: decision screens -----------------------------------
   Everything below reuses the measured tokens above rather than introducing
   new inks. The one genuinely new pair is .btn-danger, which follows the
   .btn-primary pattern exactly: white on --hazard in light (5.05:1), and dark
   text in dark mode because --hazard lifts to #FF6B6B there and white on it
   is 2.77:1. Both read back from the DOM in the verification pass.          */

/* Pager. The range and the total are always visible: a table that quietly
   shows a slice reads as "that is all of it". */
.pager {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin-top: .75rem; padding-top: .65rem; border-top: 1px solid var(--rule-soft);
}
.pager-at { font-size: .78rem; color: var(--ink-2); font-family: var(--f-mono); }
.btn[disabled] { pointer-events: none; }

/* Fold a panel away behind its own heading. The heading keeps its row count,
   so a collapsed section still says how much is inside it. */
.panel-toggle {
  font: inherit; font-size: .74rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase;
  background: none; border: 1px solid var(--rule); border-radius: var(--radius);
  color: var(--ink-2); padding: .2rem .5rem; cursor: pointer; align-self: center;
}
.panel-toggle:hover { border-color: var(--ink-3); color: var(--ink); }
.panel.is-collapsed .panel-head { border-bottom: 0; }

/* The panel carrying the thing that most needs doing. */
.panel-primary { border-color: var(--blueprint); border-left: var(--spine) solid var(--blueprint); }

/* A panel nested inside another panel, stripped of its own frame so it reads as
   part of the card. Used for the raise-the-order form, which has to sit inside
   the request card rather than below it. */
.panel-plain { border: 0; box-shadow: none; margin: 0; background: none; overflow: visible; }
.panel-plain > .panel-head { padding: 0 0 .5rem; border-bottom: 0; }
.panel-plain > .panel-body { padding: 0; }

.backbar { margin: 0 0 .9rem; }
.hint { font-size: .74rem; color: var(--ink-3); }

/* Stage tabs. The app's first in-page tab strip: .subnav is the router's own
   second row and no view touches it. This borrows that treatment on purpose -
   underline, blueprint ink, amber rule under the current one - so "pick one of
   these" reads the same everywhere instead of gaining a third look.

   The count started on --ink-3 and MEASURED 3.23:1, which fails. That is the
   identical mistake .fact-k already carries a comment about 200 lines below
   ("--ink-2, not --ink-3: measured at 3.89:1 on the slab"), made again by
   assuming a small number next to a label is decoration. It is not: the count
   is the whole reason to look at the tab. --ink-2 is 7.90:1 on the slab. */
.stagetabs {
  display: flex; flex-wrap: wrap; gap: .1rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 1.1rem;
}
.stagetab {
  display: flex; align-items: baseline; gap: .4rem;
  font-size: .84rem; color: var(--ink-2); text-decoration: none;
  padding: .5rem .7rem; white-space: nowrap;
  border-bottom: 3px solid transparent; margin-bottom: -1px;
}
.stagetab:hover { color: var(--ink); }
.stagetab-n {
  font-family: var(--f-mono); font-size: .78rem; font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
.stagetab.is-on {
  color: var(--blueprint); font-weight: 600;
  border-bottom-color: var(--amber);
}
.stagetab.is-on .stagetab-n { color: var(--blueprint); }
/* Empty stages stay on the strip. It is a map of the process, so it must not
   change shape as work moves through it, and "none right now" has to look
   different from "this stage does not exist" - the same reason .ladder-step
   gained an explicit .is-todo instead of being styled by a missing class.

   The dim is .9 and it was MEASURED, not picked. Opacity composites the ink
   over the backdrop, so getComputedStyle's colour is not what anybody reads:
   the first value here was .55, which computes to a legible-looking 6.56:1 and
   is actually 2.46:1 light / 3.4:1 dark. Swept every step - .8 is 4.13 light
   and still fails, .85 is 4.62 and only just passes, .9 is 5.18 light / 6.99
   dark and clears the project floor with room. The count reading 0 is the real
   signal; this is only weight.

   Same trap sits unfixed on .ladder-step.is-todo (opacity .5), which predates
   this and is logged rather than changed here. */
.stagetab.is-empty { opacity: .9; }
.stagetab.is-empty.is-on { opacity: 1; }

/* A tile row that repeats what the strip above it already says. On a narrow
   screen the two together push the first actionable control off the bottom,
   measured at 390px: 405px below the fold with both, 54px with the tiles gone.
   The strip both counts AND navigates, so the tiles are the redundant half.
   The residual panel still renders further down, so nothing is lost - only the
   duplicate counter is. */
@media (max-width: 760px) {
  .tiles-secondary { display: none; }
}

/* Requested -> Approved -> Priced -> Ordered -> Delivered. Answers "what
   happens next" on the page instead of in a document nobody opens. The words
   and the mapping live in D.REQUEST_STAGES, not here and not in the view.
   (This comment listed four steps for two days after Priced was added.)

   These are TABS as well as a progress bar. They were read-only while the page
   below them rendered every step at once - the quote form and the eight-field
   order form both open on a request whose only job was to ask a vendor a price.
   The chips already knew where the request was; now they act on it, and the
   page shows one step. Each carries a second line saying done / now / stopped,
   because colour alone is what was already there and was still confusing. */
.ladder { display: flex; flex-wrap: wrap; gap: .3rem; margin-bottom: .9rem; }
.ladder-step {
  display: flex; flex-direction: column; gap: .1rem;
  font-family: var(--f-display); font-size: .76rem; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase;
  padding: .22rem .6rem; border-radius: 2px;
  border: 1px solid var(--rule); background: var(--concrete); color: var(--ink-3);
  text-decoration: none;
}
/* NO opacity here, though it was the obvious way to make this line secondary to
   the label above it. At .85 the done chip's word MEASURED 4.20:1 light, under
   the 4.5 floor, because the chip inks are already mid-tone washes with nothing
   spare. It inherits the chip's colour at full strength and takes its hierarchy
   from being smaller, lighter-weight and lowercase instead. */
.ladder-state {
  font-family: var(--f-mono); font-size: .62rem; font-weight: 400;
  letter-spacing: .02em; text-transform: lowercase;
  min-height: .8em;   /* holds the row height when a step has no state word */
}
/* The flow-delivered pair, not --go on --go-w: that measured 4.43:1, just
   under. This pair was already darkened to 5.70 for exactly this reason. */
.ladder-step.is-done {
  background: var(--f-delivered-w); border-color: var(--f-delivered); color: var(--f-delivered);
}
.ladder-step.is-now { background: var(--amber-w); border-color: var(--amber-ink); color: var(--amber-ink); }
/* --ink-2 on the red wash, not --hazard on it: that MEASURED 4.38:1 light,
   under the floor. Pre-existing and marginal enough to have gone unnoticed
   while it was a static <span>; it is a link now, so it is a control nobody
   can read. Only the ink changes - the hazard wash and the hazard border stay,
   so the chip still reads as a refusal rather than going neutral grey.
   (--ink-2 here: 6.85 light / 7.11 dark.) */
.ladder-step.is-dead { background: var(--hazard-w); border-color: var(--hazard); color: var(--ink-2); }
/* Behind us, but it never happened: an order raised without a quote goes ROUND
   Priced rather than through it. Drawing that as done was a claim the section
   underneath immediately contradicted ("no vendor has come back with a price
   yet"). Dashed border, flat background - visibly not a green tick. */
.ladder-step.is-skipped {
  background: var(--concrete); border-style: dashed; border-color: var(--ink-3); color: var(--ink-2);
}
/* Steps not reached yet used to be styled by the ABSENCE of a class, which made
   "not yet" and "does not apply" look identical. Now it is stated.

   The dim was `opacity: .5`, the last unfixed instance of the trap .stagetab
   .is-empty carries a comment about: opacity composites the ink over the
   backdrop, so getComputedStyle's colour is not what anybody reads.

   MEASURED on a real is-todo chip, so the backdrop is --concrete rather than
   the slab, both themes, composited:

     --ink-3   @.5  1.69 light / 2.09 dark   <- what shipped
               @.7  2.16 / 2.90
               @.9  2.81 / 3.97
               @1   3.23 / 4.61              <- fails light even undimmed
     --ink-2   @.8  4.13 / 5.78              <- still fails light
               @.9  5.18 / 6.99
               @1   6.56 / 8.37              <- this

   The whole alpha sweep is academic: --ink-3 fails at FULL opacity (3.23, the
   identical number this file already records for .stagetab-n), so no dim of it
   could ever have passed. The fix is the token, not the alpha. These are links
   now, so an unreadable one was an unusable control, not just a faint label.
   "Not yet" still reads, from the flat background and the empty state line
   under it rather than from being faded out. */
.ladder-step.is-todo { color: var(--ink-2); }

/* It is a link now, so it has to behave like one. */
.ladder-step:hover { border-color: var(--blueprint); }
.ladder-step:focus-visible { outline: 2px solid var(--blueprint); outline-offset: 2px; }
/* The step being VIEWED, which is usually but not always the step the request
   is AT: a later step stays reachable because raising an order without a quote
   is a path this app supports on purpose. Underline rather than colour, so it
   composes with all four state colours above instead of fighting them. */
.ladder-step.is-on { box-shadow: inset 0 -3px 0 0 var(--amber); }

.ladderwrap { margin-bottom: .9rem; }
.ladderwrap .ladder { margin-bottom: .35rem; }
/* Where it has got to is only half the question. This line is the other half:
   what happens next, and whose move it is. */
.ladder-next { font-size: .82rem; color: var(--ink-2); }

/* A one-line statement of the job under a heading that states the count. */
.panel-lead { font-size: .86rem; color: var(--ink-2); margin: 0 0 .7rem; max-width: 62ch; }

/* Request facts, as label/value rows rather than a one-row table. */
.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: .35rem .9rem; }
.fact { display: flex; gap: .5rem; align-items: baseline; padding: .18rem 0; }
/* --ink-2, not --ink-3: measured at 3.89:1 on the slab, which fails. These are
   labels carrying meaning rather than decoration, so they clear 4.5. (7.90:1) */
.fact-k {
  font-size: .72rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-2); min-width: 7.5rem; flex: 0 0 auto;
}
.fact-v { color: var(--ink); font-size: .9rem; }

/* A request needing a human, as a card. A dense 11-column table is the wrong
   shape for a handful of items that each need one decision, and that is what
   made the queue read as confusing. */
.actcards { display: flex; flex-direction: column; gap: .6rem; }
.actcard {
  display: flex; gap: .9rem; align-items: center; flex-wrap: wrap;
  border: 1px solid var(--rule); border-left: var(--spine) solid var(--rule);
  border-radius: var(--radius); background: var(--slab); padding: .7rem .85rem;
}
.actcard[data-state="warn"] { border-left-color: var(--amber); background: var(--amber-w); }
.actcard[data-state="bad"]  { border-left-color: var(--hazard); background: var(--hazard-w); }
.actcard[data-state="flag"] { border-left-color: var(--flag); background: var(--flag-w); }
.actcard[data-state="good"] { border-left-color: var(--go); background: var(--go-w); }
.actcard-main { flex: 1 1 22rem; min-width: 0; }
.actcard-top { display: flex; gap: .6rem; align-items: baseline; flex-wrap: wrap; }
.actcard-id { font-family: var(--f-mono); font-size: .82rem; font-weight: 700; color: var(--ink); }
.actcard-who { font-size: .78rem; color: var(--ink-2); }
.actcard-what {
  font-family: var(--f-display); font-size: 1.05rem; letter-spacing: .01em;
  color: var(--ink); margin: .15rem 0;
}
.actcard-meta { font-size: .78rem; color: var(--ink-2); font-family: var(--f-mono); }
.actcard-why { font-size: .8rem; color: var(--ink-2); margin-top: .3rem; }
.actcard-act { flex: 0 0 auto; }

/* What is being decided, in one line, above the controls. */
.headline { margin-bottom: .8rem; }
.headline-what {
  font-family: var(--f-display); font-size: 1.35rem; letter-spacing: .01em; color: var(--ink);
}
.headline-meta { font-family: var(--f-mono); font-size: .8rem; color: var(--ink-2); margin-top: .2rem; }

/* The decision, inside the same card as the request it decides, and ABOVE the
   supporting facts: the controls have to be reachable without scrolling. */
.decide { padding-top: .85rem; border-top: 1px solid var(--rule); margin-bottom: 1rem; }
.decide-fields { display: flex; gap: .6rem; flex-wrap: wrap; margin-bottom: .7rem; }
.decide-fields .ctl { flex: 0 1 auto; }
.decide-fields .ctl.grow { flex: 1 1 18rem; }
.decide-fields .ctl.grow input { width: 100%; }
.decide-acts { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: .6rem; }
.decide .note { margin-top: .7rem; margin-bottom: 0; }

/* Picking who to ask for a price. Vendors without an address are not listed
   here at all - an unusable checkbox is worse than an honest count elsewhere. */
.vendorpick {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: .15rem .9rem; margin: .6rem 0 .9rem;
  max-height: 15rem; overflow-y: auto;
}
.vendorpick-item {
  display: flex; align-items: baseline; gap: .45rem;
  padding: .22rem .3rem; border-radius: var(--radius); cursor: pointer;
}
.vendorpick-item:hover { background: var(--concrete); }
.vendorpick-name { font-weight: 600; color: var(--ink); font-size: .86rem; }
.vendorpick-mail { font-family: var(--f-mono); font-size: .74rem; color: var(--ink-2); }
.vendorpick-n { font-size: .72rem; color: var(--ink-2); margin-left: auto; white-space: nowrap; }

/* One draft button per vendor: no vendor sees who else was asked. */
.draftlist { display: flex; flex-wrap: wrap; gap: .45rem; margin: .3rem 0 .6rem; }

/* ---- Batch quote requests ------------------------------------------------ */

/* Ticking which approved items go on one ask. */
.pickrows { display: flex; flex-direction: column; gap: .1rem; margin: .5rem 0; }
.pickrow {
  display: grid; grid-template-columns: auto 6.5rem 1fr auto 9rem;
  align-items: baseline; gap: .6rem;
  padding: .3rem .35rem; border-radius: var(--radius); cursor: pointer;
  border-bottom: 1px solid var(--rule);
}
.pickrow:hover { background: var(--concrete); }
.pickrow-id { font-family: var(--f-mono); font-size: .78rem; color: var(--ink-2); }
.pickrow-what { font-weight: 600; color: var(--ink); font-size: .88rem; }
.pickrow-qty { font-family: var(--f-mono); font-size: .8rem; white-space: nowrap; }
.pickrow-who { font-size: .76rem; color: var(--ink-2); text-align: right; }

/* Chosen vendors, each removable. Replaces a 40-item checkbox wall that could
   not grow past its cap and read as a wall of text on a phone. */
.chips { display: flex; flex-wrap: wrap; gap: .4rem; margin: .1rem 0 .7rem; }
.chipsel {
  display: inline-flex; align-items: baseline; gap: .45rem;
  padding: .28rem .3rem .28rem .6rem; border-radius: 999px;
  background: var(--concrete); border: 1px solid var(--rule);
  font-size: .84rem; font-weight: 600; color: var(--ink);
}
.chipsel.is-warn { border-color: var(--f-staging); background: var(--wash-warn, var(--concrete)); }
.chipsel-mail { font-family: var(--f-mono); font-size: .72rem; font-weight: 400; color: var(--ink-2); }
.chipsel-x {
  border: 0; background: none; cursor: pointer; font-size: 1rem; line-height: 1;
  padding: 0 .35rem; color: var(--ink-2); border-radius: 999px;
}
.chipsel-x:hover { background: var(--rule); color: var(--ink); }

/* One row per vendor: name, address, its RFQ number, and its OWN measured
   character budget. The budget is per vendor because the body differs per
   vendor - each carries its own reference. */
.draftrow {
  border: 1px solid var(--rule); border-left: 3px solid var(--ink-3);
  border-radius: var(--radius); padding: .6rem .75rem; margin: .5rem 0;
}
.draftrow[data-state="good"] { border-left-color: var(--f-delivered); }
.draftrow[data-state="warn"] { border-left-color: var(--f-staging); }
.draftrow[data-state="bad"]  { border-left-color: var(--hazard); }
.draftrow-top {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem .9rem;
  margin-bottom: .5rem;
}
.draftrow-name { font-weight: 700; color: var(--ink); }
.draftrow-mail { font-family: var(--f-mono); font-size: .76rem; color: var(--ink-2); }
.draftrow-no { font-family: var(--f-mono); font-size: .76rem; color: var(--ink-2); }
.draftrow-budget { font-size: .76rem; color: var(--ink-2); margin-left: auto; white-space: nowrap; }
.draftrow-acts { display: flex; flex-wrap: wrap; gap: .45rem; }

.rfqpreview {
  font-family: var(--f-mono); font-size: .8rem; color: var(--ink);
  background: var(--concrete); border: 1px dashed var(--rule);
  border-radius: var(--radius); padding: .7rem .8rem; margin: 0;
  white-space: pre-wrap; word-break: break-word;
}

.btn-lg { font-size: 1rem; padding: .6rem 1.4rem; }
.btn-danger { background: var(--hazard); border-color: var(--hazard); color: #fff; }
.btn-danger:hover { filter: brightness(.92); border-color: var(--hazard); }

@media (prefers-color-scheme: dark) {
  /* --hazard lifts to #FF6B6B on a dark surface, where white text is 2.77:1.
     Dark ink on it is 6.59:1. Same inversion .btn-primary already makes. */
  .btn-danger { color: #12151A; }
}

/* ---------- Misc --------------------------------------------------------- */

.note {
  background: var(--blueprint-w); border-left: var(--spine) solid var(--blueprint);
  padding: .65rem .8rem; font-size: .85rem; border-radius: var(--radius);
  margin-bottom: 1rem;
}
.note strong { font-weight: 700; }
.note.warn { background: var(--flag-w); border-left-color: var(--flag); }

/* ---------- Upload ------------------------------------------------------- */

.dropzone {
  border: 2px dashed var(--rule);
  border-radius: var(--radius);
  padding: 1.6rem 1rem;
  text-align: center;
  background: var(--concrete);
  transition: border-color .15s ease, background .15s ease;
}
.dropzone.over {
  border-color: var(--blueprint);
  background: var(--blueprint-w);
}
.dropzone strong {
  display: block;
  font-family: var(--f-display); font-size: 1.1rem; letter-spacing: .02em;
}
.dropzone p {
  margin: .35rem auto .8rem; max-width: 46ch;
  font-size: .85rem; color: var(--ink-2);
}
.dropzone .rowcount { display: block; margin-top: .6rem; }

.legend-k {
  font-size: .7rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: .35rem;
}
.legend { display: flex; flex-wrap: wrap; gap: .5rem 1.1rem; font-size: .8rem; }
.legend span { display: flex; align-items: center; gap: .38rem; }
.legend i { width: 14px; height: 14px; border-radius: 2px; display: block; }

.foot {
  max-width: var(--maxw); margin: 0 auto; padding: 1.2rem 1rem 2rem;
  color: var(--ink-3); font-size: .78rem;
  display: flex; gap: .6rem; flex-wrap: wrap;
  border-top: 1px solid var(--rule);
}

.toast {
  position: fixed; left: 50%; bottom: 1.3rem; transform: translate(-50%, 2rem);
  background: var(--ink); color: var(--concrete);
  padding: .6rem 1rem; border-radius: var(--radius);
  font-size: .87rem; font-weight: 600; box-shadow: var(--shadow);
  opacity: 0; pointer-events: none; z-index: 60;
  transition: opacity .18s ease, transform .18s ease;
  max-width: calc(100vw - 2rem);
}
.toast.on { opacity: 1; transform: translate(-50%, 0); }

/* A write just landed here. Confirms the submit without a modal. */
@keyframes landed {
  from { background: var(--amber-w); }
  to { background: transparent; }
}
tr.landed td { animation: landed 1.5s ease-out; }
/* Same confirmation on a card. Raising a request drops you on the Tracker at
   the step it entered, and the flash is what says "that one, there" - the
   answer to raising something and not being able to find it again. The border
   stays after the flash ends, because an animation is over in 1.5s and reading
   the page is not. */
.actcard.is-landed { animation: landed 1.5s ease-out; border-left-color: var(--amber); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}

/* ---------- Responsive --------------------------------------------------- */

@media (max-width: 860px) {
  .topbar-in { flex-wrap: wrap; gap: .6rem; }
  .navtoggle { display: block; margin-left: auto; }
  .groupnav {
    flex: 1 0 100%; flex-direction: column; gap: 0;
    display: none;
  }
  .groupnav.open { display: flex; }
  .groupnav a { padding: .6rem .5rem; border-radius: 0; }
  .viewhead h1 { font-size: 1.5rem; }
  .tile .v { font-size: 1.8rem; }
}

/* ==========================================================================
   LABEL SHEETS
   Sized in inches on screen as well as on paper, so what you see before
   printing is what comes out of the printer. A preview that does not match
   the sheet is worse than no preview: you find out at the laminator.
   ========================================================================== */

/* Widths are exact multiples of the label size, and the frame is an outline
   rather than a border so it cannot eat into the content box and push the
   last column onto its own row. 7.7in is also the printable width of US
   letter at 0.4in margins, so the screen grid and the paper grid agree. */
.labelsheet {
  display: flex; flex-wrap: wrap;
  background: #fff; color: #000;
  max-width: 100%;
  outline: 1px solid var(--rule);
}
.sheet-mb002 { width: 7.2in; }   /* 3 across at 2.4in  */
.sheet-mb006 { width: 7.7in; }   /* 2 across at 3.85in */

.sheet-mb002 .label {
  width: 2.4in; height: 2.35in;
  padding: .08in;
  display: flex; flex-direction: column; align-items: center;
  justify-content: flex-start; text-align: center;
  border: 1px dashed #bbb;
  page-break-inside: avoid; break-inside: avoid;
}
.sheet-mb002 .label svg { width: 1.5in; height: 1.5in; }
.sheet-mb002 .label .lname {
  font-family: var(--f-body); font-size: 9pt; font-weight: 700;
  line-height: 1.12; margin-top: .05in;
  overflow: hidden; max-height: .42in;
}
.sheet-mb002 .label .lid { font-family: var(--f-mono); font-size: 7pt; margin-top: .02in; }
.sheet-mb002 .label .lcat { font-size: 6.5pt; color: #444; }

.sheet-mb006 .tag {
  width: 3.85in; height: 3.4in;
  padding: .1in;
  display: flex; flex-direction: column; align-items: center; text-align: center;
  border: 1px dashed #bbb;
  page-break-inside: avoid; break-inside: avoid;
}
.sheet-mb006 .tag .thead {
  font-family: var(--f-display); font-size: 13pt; font-weight: 700;
  letter-spacing: .01em; margin-bottom: .04in;
}
.sheet-mb006 .tag svg { width: 2.1in; height: 2.1in; }
.sheet-mb006 .tag .tid {
  font-family: var(--f-display); font-size: 22pt; font-weight: 700;
  line-height: 1; margin-top: .05in;
}
.sheet-mb006 .tag .ttype { font-size: 9pt; margin-top: .02in; }

/* The delivery label. Sized in inches on screen too, so the preview is the
   sheet. The foreman's name is the largest thing on it by a wide margin: a box
   in a laydown yard is read from ten feet away by somebody deciding whether it
   is theirs, and that decision is made on a name, not on a zone letter. */
.deliverylabel {
  border: 2pt solid #000; padding: .28in;
  background: #fff; color: #000;
  width: 7.7in; max-width: 100%;
  page-break-inside: avoid; break-inside: avoid;
  margin-bottom: .3in;
}
.deliverylabel .dl-head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-family: var(--f-display); font-size: 9pt; font-weight: 700;
  letter-spacing: .12em; border-bottom: 1.5pt solid #000;
  padding-bottom: .06in; margin-bottom: .16in;
}
.deliverylabel .dl-body { display: flex; gap: .3in; align-items: flex-start; }
.deliverylabel .dl-main { flex: 1 1 auto; min-width: 0; }
.deliverylabel .dl-to {
  font-family: var(--f-display); font-size: 38pt; font-weight: 700;
  line-height: 1.02; letter-spacing: -.01em; overflow-wrap: break-word;
}
.deliverylabel .dl-phone { font-family: var(--f-mono); font-size: 13pt; margin-top: .04in; }
.deliverylabel .dl-k {
  font-size: 7.5pt; letter-spacing: .09em; color: #333; text-transform: uppercase;
}
.deliverylabel .dl-v { font-family: var(--f-display); font-size: 17pt; font-weight: 700; line-height: 1.1; }
.deliverylabel .dl-v.mono { font-family: var(--f-mono); font-size: 14pt; }
.deliverylabel .dl-facts {
  display: flex; gap: .32in; flex-wrap: wrap; margin-top: .18in;
  border-top: .75pt solid #999; padding-top: .12in;
}
.deliverylabel .dl-mat { margin-top: .14in; }
.deliverylabel .dl-mat-v { font-size: 12.5pt; line-height: 1.25; }

/* The scan block is the point of the label, so it is boxed rather than tucked
   in a corner. */
.deliverylabel .dl-scan {
  flex: 0 0 auto; width: 2.1in; text-align: center;
  border: 1.5pt solid #000; padding: .1in .06in;
}
.deliverylabel .dl-scan svg { width: 1.85in; height: 1.85in; display: block; margin: 0 auto; }
.deliverylabel .dl-scan-k {
  font-family: var(--f-display); font-size: 10pt; font-weight: 700;
  letter-spacing: .04em; margin-top: .06in; line-height: 1.15;
}
.deliverylabel .dl-scan-sub { font-size: 7.5pt; color: #333; margin-top: .03in; line-height: 1.2; }
.deliverylabel .dl-noscan {
  display: flex; flex-direction: column; justify-content: center;
  height: 1.85in; border: 1.5pt dashed #999;
}

@media (max-width: 900px) {
  .labelsheet { width: 100%; }
  .deliverylabel { width: 100%; }
  .deliverylabel .dl-body { flex-direction: column; align-items: stretch; }
  .deliverylabel .dl-scan { width: auto; }
}

/* ==========================================================================
   PRINT
   Label sheets are the reason this app can replace the Apps Script doc
   generator. Print at 100% scale, never "fit to page".
   ========================================================================== */

@media print {
  .topbar, .subnav, .foot, .toolbar, .scaffold-note, .toast, .skip,
  .noprint { display: none !important; }

  body { background: #fff; color: #000; font-size: 11pt; }
  main { padding: 0; max-width: none; }
  .panel { border: 0; box-shadow: none; margin: 0 0 .18in; }
  /* Only label sheets lose their heading on paper. A printed daily report
     needs its section titles, and hiding every panel head took them too. */
  .panel.sheet .panel-head { display: none; }
  .panel-head { border: 0; padding: 0 0 .04in; background: none; }
  .panel-head h2 { font-size: 12pt; }
  .panel-body { padding: 0; }

  @page { size: letter portrait; margin: 0.4in; }

  /* Layout is shared with the screen preview above. Only the paper-specific
     bits change here: no outer frame, and one delivery label per page. The
     last label does not force a break, or every print run ends on a blank
     sheet. */
  .labelsheet { max-width: none; outline: 0; }
  .deliverylabel { page-break-after: always; margin-bottom: 0; }
  .deliverylabel:last-child { page-break-after: auto; }

  /* Bars are backgrounds, and browsers drop those by default. Without this the
     trend chart and every compliance bar print as empty outlines. */
  .trend-fill, .comp-fill, .comp-bar {
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .panel { page-break-inside: avoid; break-inside: avoid; }
  .twoup { display: block; }

  table.data { font-size: 9pt; }
  table.data th { background: #eee !important; position: static; }
  table.data td:first-child, table.data th:first-child { border-left: 0; padding-left: .6rem; }
  tr[data-state="flag"] td { background: #fff !important; }
}
