/* ITAD chain of custody - depot interface
   Visual language taken from chain-of-custody paperwork: docket books, ruled
   manifest columns, carbon-copy stamps. One rule carries the whole system -
   every machine-readable value is monospace, every human label is sans. A
   mis-scan is then visible at a glance, from across the bay. */

:root {
  color-scheme: light;

  --ink:          #16191C;
  --paper:        #FFFFFF;
  --panel:        #FFFFFF;
  --rule:         #D6D3CB;
  --rule-strong:  #9C978B;
  --muted:        #6B6862;

  /* Every surface that was a hardcoded near-white. Named for what it is
     rather than what colour it happens to be, because in the dark theme none
     of them are white and a name like "off-white" would then be a lie. */
  --panel-head:   #FBFAF8;   /* the strip across the top of a panel */
  --row-alt:      #FAF9F6;   /* every other manifest row */
  --row-hover:    #F2F0EA;
  --field:        #FFFFFF;   /* inside an input */
  --chip:         #F1EFE8;   /* the enrolment code, and similar */
  --nav-ink:      #3A3D40;
  --nav-hover:    #F1F6EF;
  --nav-on:       #E9F3E5;
  --on-solid:     #FFFFFF;   /* text on a filled button or stamp */
  --btn-face:     #16191C;   /* a filled button - ink in the light theme */
  --btn-ink:      #FFFFFF;   /* and the writing on it */
  --btn-hover:    #2E3336;
  --checked-rule: #BEDCC8;   /* the rule under a row that has been ticked */

  /* Two roles, and in the dark theme they cannot be one colour: --verified
     is text and borders on a tint, --verified-solid is a filled shape with
     white on top. Light happens to want the same value for both. */
  --verified:     #17703F;
  --verified-solid: #17703F;
  --verified-bg:  #E1F0E6;
  --verified-ink: #0F5730;   /* verified text on a verified background */
  --flag:         #9E2B15;
  --flag-solid:   #9E2B15;
  --flag-bg:      #F8E5E0;
  --flag-hover:   #8A2412;
  --pending:      #8C6009;
  --pending-bg:   #FAEFD6;
  --seal:         #1C4A72;
  --seal-bg:      #E3ECF4;
  --go-hover:     #125C33;

  /* Ecotech IT house colours.
     Deliberately confined to the brand mark and nothing else. Green already
     carries meaning here - --verified is what the screen goes when a scan is
     recorded - and painting the furniture the same colour would spend the one
     signal an operator reads at a glance across a bay. The identity sits in
     the header; the colours that mean something stay rare. */
  --brand:        #1E7A24;
  --brand-light:  #8DC63F;

  --sans: "Segoe UI Variable Text", "Segoe UI", Inter, system-ui, -apple-system, sans-serif;
  --mono: "Cascadia Mono", Consolas, "SF Mono", ui-monospace, "Roboto Mono", monospace;
}

/* ------------------------------------------------------------------- dark
   A bay is often badly lit, and a white screen at six in the morning is the
   thing people complain about first. Nothing structural changes here - every
   value below is a swap of the same named surface, so the two themes cannot
   drift into being two designs.

   What is NOT free to change is meaning. Verified green, flag red, pending
   amber and seal blue are how a mis-scan is spotted from across the floor, so
   each keeps its hue and only its lightness moves - enough to stay legible on
   a dark ground, not so much that green stops reading as green.

   Set on the element rather than by media query alone: the operator's choice
   has to win over the machine's, because one terminal in a dark corner is not
   the same as the whole depot. */
:root[data-theme="dark"] {
  /* Tells the browser to draw the parts it owns and this file cannot reach -
     the date picker, dropdown lists, scrollbars, the caret. Without it those
     stay bright white and are the only glare left on the screen. */
  color-scheme: dark;

  --ink:          #E6E4DF;
  --paper:        #14171A;
  --panel:        #1B1F22;
  --rule:         #333A3E;
  --rule-strong:  #566065;
  --muted:        #9CA2A6;

  --panel-head:   #22272B;
  --row-alt:      #1F2427;
  --row-hover:    #2B3235;
  --field:        #101315;
  --chip:         #22272B;
  --nav-ink:      #C6CBCE;
  --nav-hover:    #1E2A20;
  --nav-on:       #22331F;
  --on-solid:     #FFFFFF;
  /* Inverted: on a dark page the filled button is the light one, so its
     writing has to go the other way too. */
  --btn-face:     #E6E4DF;
  --btn-ink:      #14171A;
  --btn-hover:    #CFCCC5;
  --checked-rule: #2F5C41;

  /* Text on a tint is light; a filled shape with white on it stays deep. */
  --verified:       #6FD79A;
  --verified-solid: #1B7A45;
  --verified-bg:    #14301F;
  --verified-ink:   #8CE3AE;
  --flag:           #FF9077;
  --flag-solid:     #A33018;
  --flag-bg:        #351610;
  --flag-hover:     #B93A1F;
  --pending:        #E8B65A;
  --pending-bg:     #33270E;
  --seal:           #7DB2E0;
  --seal-bg:        #142838;
  --go-hover:       #228F52;

  /* The lighter house green, because the darker one disappears on this. */
  --brand:        #8DC63F;
}

* { box-sizing: border-box; }

/* The browser's own [hidden] rule lives at the lowest priority, so any
   selector here that sets a display value silently beats it and the element
   stays on screen. This has caught us out more than once - most visibly with
   the authorisation dialog, which appeared the moment the bench opened and
   then stole focus back to the scanner because the script still believed it
   was closed. Stated once, loudly, so it cannot happen again. */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
}

.mono, .tag, .seal, .count, td.mono, input.mono {
  font-family: var(--mono);
  font-variant-ligatures: none;
  letter-spacing: -0.01em;
}

/* ------------------------------------------------------------ chrome */

header.top {
  background: var(--panel); color: var(--ink);
  display: flex; align-items: center; gap: 1.5rem;
  padding: 0 1.25rem; height: 52px;
  position: sticky; top: 0; z-index: 50;
  border-bottom: 1px solid var(--rule);
}
header.top .brand {
  font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
  font-size: 0.75rem; padding-right: 1.25rem;
  border-right: 1px solid var(--rule);
  display: flex; align-items: center; gap: 0.6rem;
  color: var(--brand);
}
/* On white the logo needs no plate behind it. Sized to most of the header's
   52px: the mark is wide and carries a tagline, so anything smaller is a green
   smudge rather than a logo. */
header.top .brand img { height: 34px; width: auto; display: block; }

/* The sign-in and enrolment screens stand alone, so the mark can be large
   enough that the tagline under it is actually readable. */
.mark img { height: 76px; width: auto; display: block; margin-bottom: 0.75rem; }
header.top nav { display: flex; gap: 0.25rem; flex: 1; }
header.top nav a {
  color: var(--nav-ink); text-decoration: none; padding: 0.35rem 0.7rem;
  border-radius: 3px; font-size: 0.875rem;
}
header.top nav a:hover { background: var(--nav-hover); color: var(--brand); }
/* The page you are on, in the house green. An accent, and small - the colours
   that mean something on this screen are in the scan band. */
header.top nav a.on { background: var(--nav-on); color: var(--brand); font-weight: 600; }
header.top .who { font-size: 0.8rem; color: var(--muted); }
header.top .who b { color: var(--ink); font-weight: 600; }
header.top .who .role {
  display: inline-block; margin-left: 0.5rem; padding: 0.1rem 0.45rem;
  border: 1px solid var(--rule-strong); border-radius: 2px; font-size: 0.7rem;
  text-transform: uppercase; letter-spacing: 0.06em;
}
header.top .who a { color: var(--muted); margin-left: 0.75rem; }

/* The dark mode switch. Small and quiet: it sits next to the sign-out link
   rather than in the navigation, because it is a property of this terminal
   rather than another place to go. */
.themetoggle {
  display: flex; align-items: center; gap: 0.4rem;
  background: none; border: 0; padding: 0.2rem 0.35rem; cursor: pointer;
  color: var(--muted); font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.08em; font-weight: 600; font-family: var(--sans);
}
.themetoggle:hover { color: var(--ink); }
.themetoggle .track {
  width: 30px; height: 16px; border-radius: 8px; position: relative;
  background: var(--rule); border: 1px solid var(--rule-strong);
  transition: background .12s ease;
}
.themetoggle .knob {
  position: absolute; top: 1px; left: 1px; width: 12px; height: 12px;
  border-radius: 50%; background: var(--panel);
  border: 1px solid var(--rule-strong);
  transition: transform .12s ease;
}
.themetoggle[aria-checked="true"] .track { background: var(--verified-solid); border-color: var(--verified-solid); }
.themetoggle[aria-checked="true"] .knob { transform: translateX(14px); }
@media (prefers-reduced-motion: reduce) {
  .themetoggle .track, .themetoggle .knob { transition: none; }
}
/* The header is tight on a small screen and the word is the first thing that
   can go - the switch still says what it is. */
@media (max-width: 1100px) { .themetoggle .lbl { display: none; } }

/* The mark carries black lettering and a tagline, which vanish on a dark
   header. Rather than recolour the artwork - there is one master and every
   other copy is cut from it - it sits on a small light plate, which keeps the
   brand exactly as drawn. */
:root[data-theme="dark"] header.top .brand img,
:root[data-theme="dark"] .mark img {
  background: #FFFFFF; padding: 3px 6px; border-radius: 3px;
}

main { max-width: 1240px; margin: 0 auto; padding: 1.5rem 1.25rem 4rem; }
main.wide { max-width: none; }

/* Which code this is. Quiet on purpose - it is for the one moment somebody
   asks whether the test server and the live one are the same, and should not
   compete with anything on the page the rest of the time. */
footer.buildstamp {
  max-width: 1240px; margin: 0 auto; padding: 0 1.25rem 1.5rem;
  font-size: 0.72rem; color: var(--muted); text-align: right;
}

/* Headings carry the house green; body text stays black. Green is a signal on
   the scan band, so it is spent sparingly elsewhere - on the words that label
   a screen, not on its surfaces. */
h1 { font-size: 1.35rem; font-weight: 600; margin: 0 0 0.25rem; letter-spacing: -0.01em;
     color: var(--brand); }
h2 { font-size: 1rem; font-weight: 600; margin: 2rem 0 0.6rem; color: var(--brand); }
h2:first-child { margin-top: 0; }
.sub { color: var(--muted); font-size: 0.875rem; margin: 0 0 1.25rem; }

/* Eyebrow labels encode record type, not decoration */
.eyebrow {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted); font-weight: 600; margin-bottom: 0.2rem;
}

/* ------------------------------------------------------------ panels */

.panel {
  background: var(--panel); border: 1px solid var(--rule);
  border-radius: 3px; margin-bottom: 1.25rem;
}
.panel > .hd {
  padding: 0.7rem 1rem; border-bottom: 1px solid var(--rule);
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  background: var(--panel-head);
}
.panel > .hd h2 { margin: 0; font-size: 0.9rem; }
.panel > .bd { padding: 1rem; }
.panel.flag { border-color: var(--flag); }
.panel.flag > .hd { background: var(--flag-bg); border-bottom-color: var(--flag); color: var(--flag); }
/* A flagged panel's heading is red because the panel is flagged. Headings are
   green by default now, and an element rule beats an inherited colour, so it
   has to be said again here or the one panel that means trouble would be
   wearing the house colour. */
.panel.flag > .hd h2 { color: var(--flag); }

.grid { display: grid; gap: 1.25rem; }
.grid.c2 { grid-template-columns: 1fr 1fr; }
.grid.c3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .grid.c2, .grid.c3 { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------ docket tables */

table.docket { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
table.docket th {
  text-align: left; font-size: 0.68rem; text-transform: uppercase;
  letter-spacing: 0.1em; color: var(--muted); font-weight: 600;
  padding: 0.5rem 0.75rem; border-bottom: 1.5px solid var(--rule-strong);
  white-space: nowrap;
}
table.docket td {
  padding: 0.55rem 0.75rem; border-bottom: 1px solid var(--rule);
  vertical-align: middle;
}
table.docket tbody tr:nth-child(even) { background: var(--row-alt); }
table.docket tbody tr:hover { background: var(--row-hover); }
table.docket a { color: var(--seal); text-decoration: none; }
table.docket a:hover { text-decoration: underline; }
/* Header and value centred together, and it has to be both. Only the cell was
   styled here, so a count sat hard right in its column while its heading sat
   hard left, and across a wide table each number appeared under the *next*
   heading - the Received figure read as Missing, which is exactly how it was
   reported. A column of numbers that does not line up under its own name is
   worse than no column. */
table.docket th.num, table.docket td.num { text-align: center; }
table.docket td.num { font-family: var(--mono); }
.empty { padding: 2rem 1rem; text-align: center; color: var(--muted); font-size: 0.9rem; }

/* Left check column - the docket-book mark */
td.mark, th.mark { width: 34px; text-align: center; padding-left: 0.5rem; }
.mark-box {
  display: inline-block; width: 18px; height: 18px; line-height: 16px;
  border: 1.5px solid var(--rule-strong); border-radius: 2px;
  font-size: 0.75rem; color: transparent;
}
tr.is-checked { background: var(--verified-bg) !important; }
tr.is-checked td { border-bottom-color: var(--checked-rule); }
tr.is-checked .mark-box {
  background: var(--verified-solid); border-color: var(--verified-solid); color: var(--on-solid);
}
tr.is-missing { background: var(--flag-bg) !important; }
tr.is-missing .mark-box { border-color: var(--flag); color: var(--flag); }

/* Status stamps - reads like an ink stamp on a docket */
.stamp {
  display: inline-block; font-size: 0.66rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em;
  padding: 0.15rem 0.45rem; border: 1.5px solid; border-radius: 2px;
  white-space: nowrap;
}
.stamp.ok      { color: var(--verified); border-color: var(--verified); background: var(--verified-bg); }
.stamp.bad     { color: var(--flag);     border-color: var(--flag);     background: var(--flag-bg); }
.stamp.wait    { color: var(--pending);  border-color: var(--pending);  background: var(--pending-bg); }
.stamp.neutral { color: var(--seal);     border-color: var(--seal);     background: var(--seal-bg); }
.stamp.quiet   { color: var(--muted);    border-color: var(--rule-strong); background: transparent; }

/* ------------------------------------------------------------ forms */

label.fld { display: block; margin-bottom: 0.85rem; }
label.fld > span {
  display: block; font-size: 0.7rem; text-transform: uppercase;
  letter-spacing: 0.09em; color: var(--muted); font-weight: 600; margin-bottom: 0.25rem;
}
input[type=text], input[type=password], input[type=number], select, textarea {
  width: 100%; padding: 0.5rem 0.65rem; font-size: 0.95rem;
  border: 1px solid var(--rule-strong); border-radius: 3px;
  background: var(--field); color: var(--ink); font-family: var(--sans);
}
input.mono { font-family: var(--mono); }
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--seal); outline-offset: 1px; border-color: var(--seal);
}
.row { display: flex; gap: 0.75rem; align-items: flex-end; flex-wrap: wrap; }
.row > * { flex: 1; min-width: 140px; }
.row > .shrink { flex: 0 0 auto; min-width: 0; }

button, .btn {
  display: inline-block; padding: 0.5rem 1rem; font-size: 0.875rem;
  font-family: var(--sans); font-weight: 500; cursor: pointer;
  border: 1px solid var(--btn-face); background: var(--btn-face); color: var(--btn-ink);
  border-radius: 3px; text-decoration: none; line-height: 1.4;
}
button:hover, .btn:hover { background: var(--btn-hover); }
button.ghost, .btn.ghost { background: var(--panel); color: var(--ink); border-color: var(--rule-strong); }
button.ghost:hover, .btn.ghost:hover { background: var(--row-hover); }
button.danger, .btn.danger { background: var(--flag-solid); border-color: var(--flag-solid); }
button.danger:hover { background: var(--flag-hover); }
button.go, .btn.go { background: var(--verified-solid); border-color: var(--verified-solid); }
button.go:hover { background: var(--go-hover); }
button.sm, .btn.sm { padding: 0.3rem 0.6rem; font-size: 0.8rem; }
button:focus-visible, .btn:focus-visible, a:focus-visible {
  outline: 2px solid var(--seal); outline-offset: 2px;
}

.flash { padding: 0.7rem 1rem; border-radius: 3px; margin-bottom: 1rem; font-size: 0.9rem;
         border: 1px solid; }
.flash.ok    { background: var(--verified-bg); border-color: var(--verified); color: var(--verified-ink); }
.flash.error { background: var(--flag-bg);     border-color: var(--flag);     color: var(--flag); }

/* ------------------------------------------------------------ scan band
   The signature element. Floods with colour on every scan and shows the
   value in very large mono so it reads from across the goods-in bay. */

.scanband {
  border: 2px solid var(--rule-strong); border-radius: 3px;
  background: var(--panel); margin-bottom: 1.25rem;
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  min-height: 118px; overflow: hidden;
  transition: background-color .12s ease, border-color .12s ease;
}
.scanband .val {
  padding: 0.9rem 1.25rem;
}
.scanband .verdict {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.14em;
  font-weight: 700; color: var(--muted); margin-bottom: 0.15rem;
}
.scanband .big {
  font-family: var(--mono); font-size: 2.6rem; font-weight: 600;
  line-height: 1.05; letter-spacing: -0.02em; word-break: break-all;
}
.scanband .msg { font-size: 0.9rem; color: var(--muted); margin-top: 0.2rem; }
.scanband .tally {
  text-align: right; padding: 0.9rem 1.5rem; border-left: 2px solid var(--rule-strong);
  align-self: stretch; display: flex; flex-direction: column; justify-content: center;
}
.scanband .tally .count {
  font-size: 2.6rem; font-weight: 600; line-height: 1; letter-spacing: -0.03em;
}
.scanband .tally .count small { font-size: 1.4rem; color: var(--muted); font-weight: 400; }
.scanband .tally .lbl {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted); font-weight: 600; margin-top: 0.2rem;
}

.scanband.accepted { background: var(--verified-bg); border-color: var(--verified); }
.scanband.accepted .verdict, .scanband.accepted .big { color: var(--verified); }
.scanband.duplicate, .scanband.surplus { background: var(--pending-bg); border-color: var(--pending); }
.scanband.duplicate .verdict, .scanband.duplicate .big,
.scanband.surplus .verdict, .scanband.surplus .big { color: var(--pending); }
.scanband.unknown, .scanband.error, .scanband.seal {
  background: var(--flag-bg); border-color: var(--flag);
}
.scanband.unknown .verdict, .scanband.unknown .big,
.scanband.error .verdict, .scanband.error .big,
.scanband.seal .verdict, .scanband.seal .big { color: var(--flag); }

@media (prefers-reduced-motion: no-preference) {
  .scanband.pulse { animation: pulse .28s ease-out; }
  @keyframes pulse { 0% { transform: scale(1); } 40% { transform: scale(1.008); } 100% { transform: scale(1); } }
}

/* Scanner capture field - kept visible so the operator can see focus state */
.capture {
  display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1.25rem;
  padding: 0.6rem 0.9rem; border: 1px dashed var(--rule-strong); border-radius: 3px;
  background: var(--panel-head);
}
.capture input {
  font-family: var(--mono); font-size: 1.1rem; border: none; background: transparent;
  padding: 0.15rem 0; flex: 1;
}
.capture input:focus { outline: none; }
.capture .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--rule-strong); flex: 0 0 auto; }
.capture.live { border-color: var(--verified); border-style: solid; background: var(--field); }
.capture.live .dot { background: var(--verified); }
.capture .hint { font-size: 0.78rem; color: var(--muted); flex: 0 0 auto; }

/* ------------------------------------------------------------ meta list */

dl.meta { display: grid; grid-template-columns: max-content 1fr; gap: 0.35rem 1.25rem;
          margin: 0; font-size: 0.875rem; }
dl.meta dt { color: var(--muted); font-size: 0.7rem; text-transform: uppercase;
             letter-spacing: 0.09em; font-weight: 600; padding-top: 0.15rem; }
dl.meta dd { margin: 0; }

/* ------------------------------------------------------------ provenance */

ol.chain { list-style: none; margin: 0; padding: 0; }
ol.chain li {
  position: relative; padding: 0 0 1.1rem 1.6rem;
  border-left: 2px solid var(--rule); margin-left: 5px;
}
ol.chain li:last-child { border-left-color: transparent; padding-bottom: 0; }
ol.chain li::before {
  content: ""; position: absolute; left: -6px; top: 4px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--panel); border: 2px solid var(--rule-strong);
}
ol.chain li.key::before { background: var(--seal); border-color: var(--seal); }
ol.chain li.bad::before { background: var(--flag); border-color: var(--flag); }
ol.chain li.voided { opacity: 0.45; }
ol.chain li.voided .what { text-decoration: line-through; }
ol.chain .what { font-weight: 500; }
ol.chain .when { font-family: var(--mono); font-size: 0.78rem; color: var(--muted); }
ol.chain .by { font-size: 0.82rem; color: var(--muted); }

.hashline { font-family: var(--mono); font-size: 0.68rem; color: var(--muted);
            word-break: break-all; }

/* ------------------------------------------------------------ login */

.loginwrap { max-width: 360px; margin: 8vh auto; }
.loginwrap .mark {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 0.5rem;
}
.loginwrap h1 { font-size: 1.15rem; margin-bottom: 1.25rem; }
.loginwrap button[type=submit] { width: 100%; padding: 0.6rem; }

@media (max-width: 700px) {
  .scanband { grid-template-columns: 1fr; }
  .scanband .tally { border-left: none; border-top: 2px solid var(--rule-strong); text-align: left; }
  .scanband .big { font-size: 1.9rem; }
  header.top { gap: 0.75rem; overflow-x: auto; }
}

/* Password entry: masked by default with a deliberate, momentary reveal.
   The note below the fields carries the live match state - it is the only
   place the form talks back, so it does the job alone rather than competing
   with icons or coloured borders.

   Specificity note: `label.fld > span` above styles field labels and would
   otherwise win over a bare `.pw`, blocking the flex layout. The selector is
   qualified to match it rather than relying on source order. */
label.fld > span.pw,
.pw {
  display: flex; gap: 0.4rem; align-items: stretch;
  margin-bottom: 0; text-transform: none; letter-spacing: normal;
  font-size: inherit; font-weight: normal; color: inherit;
}
/* The input must always keep usable width, and the toggle must always size to
   its own text - whatever width rules a surrounding layout applies. */
.pw > input { flex: 1 1 auto; min-width: 6rem; width: auto; }
.pw > button { flex: 0 0 auto; width: auto; white-space: nowrap; padding: 0.5rem 0.75rem; }

.pwnote {
  font-size: 0.82rem; color: var(--muted); margin: 0 0 0.9rem;
  padding-left: 0.9rem; border-left: 3px solid var(--rule-strong);
}
.pwnote.good { color: var(--verified); border-left-color: var(--verified); }
.pwnote.warn { color: var(--pending);  border-left-color: var(--pending); }
.pwnote.bad  { color: var(--flag);     border-left-color: var(--flag); }

button:disabled, .btn:disabled {
  opacity: 0.45; cursor: not-allowed; background: var(--rule-strong);
  border-color: var(--rule-strong);
}

/* ------------------------------------------------------------ bench mode
   A working screen for someone holding a scanner, not a mouse. Everything is
   larger than the admin pages and there is nothing to click. */

.benchbar {
  display: flex; align-items: center; gap: 2rem;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 3px;
  padding: 0.75rem 1.25rem; margin-bottom: 1rem;
}
.benchbar .benchval { font-size: 1.5rem; font-weight: 600; line-height: 1.1; }
.benchbar .benchcount { margin-left: auto; text-align: right; }
.benchbar .benchcount small { font-size: 1rem; color: var(--muted); font-weight: 400; }
.benchbar .shrink { flex: 0 0 auto; }

/* The note prompt reuses the scan field, so it has to look different when it
   wants typing rather than scanning. */
.capture.typing { border-style: solid; border-color: var(--pending); background: var(--pending-bg); }
.capture.typing .dot { background: var(--pending); }
.capture.typing .hint { color: var(--pending); font-weight: 600; }

.scanband.info { background: var(--seal-bg); border-color: var(--seal); }
.scanband.info .verdict, .scanband.info .big { color: var(--seal); }
.scanband.idle { background: var(--panel); border-color: var(--rule-strong); }

/* Enrolment QR. Centred and given room - a code squeezed against surrounding
   text is harder for a phone to lock on to. */
.qr { display: flex; justify-content: center; margin: 1.25rem 0; }
/* Rendered at its natural size on purpose. Constraining the width would make
   the browser rescale it to a fractional number of pixels per module, which
   is exactly the blurring the crispEdges setting exists to avoid. */
.qr svg { width: auto; height: auto; max-width: none; image-rendering: pixelated; }

.manualkey { margin-top: 0.5rem; }
.manualkey summary { cursor: pointer; font-size: 0.85rem; color: var(--seal); }
.keyblock {
  font-size: 1.1rem; letter-spacing: 0.06em; background: var(--chip);
  padding: 0.75rem; border-radius: 3px; word-break: break-all; margin: 0.5rem 0;
}

/* A rule that is turned off is still listed - keeping an old tag format
   alongside a new one is normal during a changeover. */
table.docket tr.is-off td { opacity: 0.5; }

/* Editable grid on the test data page. Inputs sit flush inside the cells so
   the table reads as a spreadsheet rather than a stack of form fields. */
table.docket td input[type=text],
table.docket td select { padding: 0.3rem 0.4rem; font-size: 0.85rem; }
table.docket td { padding: 0.3rem 0.4rem; }
textarea { width: 100%; padding: 0.5rem 0.65rem; font-family: var(--mono);
           font-size: 0.85rem; border: 1px solid var(--rule-strong); border-radius: 3px; }

/* Held items are a queue somebody owes an answer on, so the count rides in
   the navigation rather than waiting to be discovered. */
header.top nav .badge {
  display: inline-block; min-width: 17px; padding: 0 5px; margin-left: 3px;
  background: var(--flag-solid); color: var(--on-solid); border-radius: 9px;
  font-family: var(--mono); font-size: 0.7rem; text-align: center;
}
.scanband.quarantined { background: var(--pending-bg); border-color: var(--pending); }
.scanband.quarantined .verdict, .scanband.quarantined .big { color: var(--pending); }

/* Re-tagging a duplicate, inline on the exceptions row. Small and quiet: it is
   an action on one row of a report, not a form in its own right, and the new
   tag is normally scanned rather than typed. */
/* Filling in a job's descriptive detail. Folded away when the job already has
   a client, open when it does not - a job that arrived with nothing but its
   number is the case this exists for, so it should not need finding. */
details.jobdetails { margin: 0 0 1rem; }
details.jobdetails > summary {
  cursor: pointer; font-size: 0.85rem; color: var(--muted);
  padding: 0.2rem 0; width: fit-content;
}
details.jobdetails > summary:hover { color: var(--brand); }
details.jobdetails > summary:focus-visible { outline: 2px solid var(--verified); }
details.jobdetails[open] > summary { color: var(--ink); font-weight: 600; }

/* ------------------------------------------- make and model, at the bench
   Offered after an item is checked off and gone by the next scan. Quiet by
   design: it sits between the scan band and the manifest, takes no focus until
   it is clicked, and an operator who never uses it should barely notice it. */
.details { max-width: 1240px; margin: 0 auto .9rem; padding: 0 1.25rem; }
.details form { display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
                margin-top: 4px; }
.details input { padding: .35rem .5rem; font-size: .85rem; }
.details input#det-make  { width: 11rem; }
.details input#det-model { width: 13rem; }
.details .hint { font-size: .75rem; color: var(--muted); }

.retag { display: flex; gap: 4px; margin-top: 4px; flex-wrap: wrap; }
.retag input { padding: 0.25rem 0.4rem; font-size: 0.78rem; }
.retag input[name=new_tag] { width: 8.5rem; }
.retag input[name=reason] { width: 11rem; }
.retag button { padding: 0.25rem 0.5rem; font-size: 0.75rem; }

/* Closing off a seal investigation. Its own row spanning the table rather than
   a cell, because the finding is a sentence somebody will read back in a
   year - given the seal column it came out as a strip a few characters wide,
   which reads as a styling fault and is really a measurement one.

   Tinted with the flag colour so it stays visibly attached to the breach above
   it, and so nobody mistakes it for an ordinary row of the report. */
.signoff > td { background: var(--flag-bg); padding-top: 0.4rem; padding-bottom: 0.5rem; }
.sealoff { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.sealoff .lbl { font-size: 0.78rem; color: var(--flag); font-weight: 600; }
.sealoff input { padding: 0.3rem 0.45rem; font-size: 0.8rem; }
/* The finding takes whatever is left - it is the field with something to say. */
.sealoff input[name=finding] { flex: 1 1 20rem; min-width: 14rem; }
.sealoff input[name=password] { width: 10rem; }
.sealoff input[name=code] { width: 5rem; }
.sealoff button { padding: 0.3rem 0.6rem; font-size: 0.78rem; }

/* ------------------------------------------------------------- job complete
   The opposite of the authorisation modal below: that one interrupts on
   purpose, this one must not. It sits over the screen where an operator
   looking up will see it, but takes no focus and no clicks - pointer-events
   is what keeps the scanner working underneath it - and it leaves on its own
   after five seconds or on the next scan, whichever comes first. z-index is
   below the modal so a supervisor dialog is never buried by good news. */

.jobdone {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: center; justify-content: center;
  padding: 1.5rem; pointer-events: none;
  /* The scan band behind this has already gone pale green for the accepted
     scan, so a pale green box on top of it is one green among two. The scrim
     separates them and makes this the only thing on the screen. */
  background: rgba(22, 25, 28, 0.34);
}
.jobdone-box {
  /* Solid rather than tinted, for the same reason. Still the verified green -
     the signal an operator already reads as "recorded" - turned up rather than
     replaced with a colour that would have to be learnt. */
  background: var(--verified-solid); border: 2px solid var(--verified-solid);
  border-radius: 3px; color: var(--on-solid);
  padding: 2rem 3.5rem; text-align: center;
  box-shadow: 0 10px 40px rgba(22, 25, 28, 0.35);
  animation: jobdone-in .18s ease-out;
}
.jobdone-box .eyebrow { color: var(--on-solid); opacity: .75; margin-bottom: .5rem; }
.jobdone-line { font-size: 2.1rem; font-weight: 600; line-height: 1.2; }
.jobdone-line .mono { font-size: 2.6rem; letter-spacing: .01em; }
.jobdone-sub { font-size: .95rem; opacity: .85; margin-top: .6rem; }

@keyframes jobdone-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .jobdone-box { animation: none; }
}

/* ------------------------------------------------------- authorisation modal
   A supervisor signing off one action at the bench. Deliberately heavy: it
   interrupts a scanning rhythm on purpose, because what it authorises is
   permanent. The scanner gives up focus while it is open and takes it back
   when it closes. */

.modalwrap {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(22, 25, 28, 0.55);
  display: flex; align-items: center; justify-content: center;
  padding: 1.5rem;
}
.modal {
  background: var(--panel); border: 2px solid var(--ink); border-radius: 3px;
  width: 100%; max-width: 460px; max-height: 92vh; overflow: auto;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.28);
}
.modal-hd {
  padding: 1rem 1.25rem; border-bottom: 1px solid var(--rule); background: var(--panel-head);
}
.modal-hd h2 { margin: 0; font-size: 1.1rem; }
.modal-bd { padding: 1.25rem; }
.modal-bd .fld { margin-bottom: 0.9rem; }

/* ------------------------------------------------------------------ paper

   Paper is white whatever the screen is set to. A dark theme sent to a
   printer is unreadable, empties a toner cartridge, and would quietly ruin the
   one thing on this system that has to be scannable off a page - the command
   cards. The light values are restated rather than unset, because a custom
   property that is merely absent falls back to nothing at all. */

@media print {
  :root[data-theme="dark"] {
    /* This one first, and it is not optional. color-scheme controls the canvas
       the browser paints itself, which in print is the margin around the page -
       and that is outside anything the variables below can reach. Left dark, a
       card comes out of the printer with a black border round it. */
    color-scheme: light;

    --ink:          #16191C;
    --paper:        #FFFFFF;
    --panel:        #FFFFFF;
    --rule:         #D6D3CB;
    --rule-strong:  #9C978B;
    --muted:        #6B6862;

    --panel-head:   #FBFAF8;
    --row-alt:      #FAF9F6;
    --row-hover:    #FFFFFF;
    --field:        #FFFFFF;
    --chip:         #F1EFE8;
    --nav-ink:      #3A3D40;
    --nav-hover:    #F1F6EF;
    --nav-on:       #E9F3E5;
    --on-solid:     #FFFFFF;
    --btn-face:     #16191C;
    --btn-ink:      #FFFFFF;
    --btn-hover:    #2E3336;
    --checked-rule: #BEDCC8;

    --verified:       #17703F;
    --verified-solid: #17703F;
    --verified-bg:    #E1F0E6;
    --verified-ink:   #0F5730;
    --flag:           #9E2B15;
    --flag-solid:     #9E2B15;
    --flag-bg:        #F8E5E0;
    --flag-hover:     #8A2412;
    --pending:        #8C6009;
    --pending-bg:     #FAEFD6;
    --seal:           #1C4A72;
    --seal-bg:        #E3ECF4;
    --go-hover:       #125C33;
    --brand:          #1E7A24;
  }
  /* The plate behind the logo is only there to rescue it from a dark header,
     and on paper the header is white already. */
  :root[data-theme="dark"] header.top .brand img,
  :root[data-theme="dark"] .mark img { background: none; padding: 0; }

  /* Neither of these is any use on paper. */
  .themetoggle, header.top nav { display: none; }
}
