/* ==========================================================================
   Versatile Production Tracking - shared stylesheet
   Single source of truth for tokens, shell and components across all screens.

   Conventions:
   - Radius is 2px everywhere (industrial: cut, not rounded). Never pill.
   - 8-pt spacing grid.
   - Minimum text size is 12px anywhere, badges and micro-labels included.
   - Colour values are defined HERE and nowhere else. data.js hands back
     var(--token) references, never hexes, so no markup carries a literal
     colour. Stage colour reaches a component via the --stage custom property.
     See the stage palette below and VPT.stageColor() in data.js.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Typeface
   -------------------------------------------------------------------------- */
@font-face{font-family:'Acronym';src:url('../fonts/Acronym-Regular.otf') format('opentype');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Acronym';src:url('../fonts/Acronym-RegularItalic.otf') format('opentype');font-weight:400;font-style:italic;font-display:swap}
@font-face{font-family:'Acronym';src:url('../fonts/Acronym-Bold.otf') format('opentype');font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:'Acronym';src:url('../fonts/Acronym-Black.otf') format('opentype');font-weight:900;font-style:normal;font-display:swap}

/* --------------------------------------------------------------------------
   2. Design tokens
   -------------------------------------------------------------------------- */
:root{
  /* Brand */
  --deep-blue:#051732;
  --aqua:#014C8D;
  --grey:#465564;
  --sandstone:#F8F8F8;
  --yellow:#FBCF20;
  --white:#FFFFFF;

  /* Supporting surfaces */
  --page-bg:#E9EBEF;
  --field-fill:#F2F4F7;
  --hairline:#E2E6EB;
  --input-border:#C8CFD8;
  --body-ink:#3A475A;

  /* Status */
  --green:#1E8F5B;          /* fills and dots only, never behind white text */
  --green-dark:#17734A;     /* required behind WHITE text: white on #1E8F5B is 4.09:1 */
  --green-ink:#1B6B47;      /* green ink on a white surface */
  --danger:#A8322A;
  --danger-ink:#8E2C24;
  --danger-ink-deep:#7F241E;
  --danger-tint:#FDF6F5;
  --danger-border:#E8C9C4;
  --danger-border-strong:#C8A19B;
  --priority-tint:#EDF3F9;
  --due-soon-fill:#FFF8E1;
  --due-soon-ink:#8A5B00;
  --today-fill:#FFFBEA;

  /* Stage palette.
     THE single definition of stage colour. data.js references these by name
     (VPT.STAGE_COLORS / VPT.stageBadge) and never emits a hex, so changing a
     stage colour here moves the board columns, the KPI accents, the scan-feed
     dots and the month chips together. */
  --stage-available:var(--grey);
  --stage-cnc:var(--aqua);
  --stage-staged-for-eb:var(--aqua);
  --stage-edge-banding:var(--aqua);
  --stage-qa-qc:var(--yellow);
  --stage-staging:var(--deep-blue);
  --stage-complete:var(--green);
  --stage-complete-badge:var(--green-dark);   /* white text needs the darker green */

  /* Structure */
  --radius:2px;
  --card-shadow:0 12px 32px rgba(5,23,50,.14);
  --panel-border:1px solid rgba(5,23,50,.1);
  --focus-ring:0 0 0 3px rgba(1,76,141,.18);

  --font:'Acronym',system-ui,sans-serif;
}

/* --------------------------------------------------------------------------
   3. Base
   -------------------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}

/* The [hidden] attribute is applied by the UA stylesheet at a specificity any
   class rule beats - so a component with its own `display` (.board-layout is
   `display:grid`) would stay visible when hidden. Enforce it once, globally. */
[hidden]{display:none !important}

body{
  margin:0;
  background:var(--page-bg);
  font-family:var(--font);
  color:var(--deep-blue);
  -webkit-font-smoothing:antialiased;
}

a{color:var(--aqua)}
a:hover{color:var(--deep-blue)}
select,input,button,textarea{font-family:var(--font)}
img{display:block}

/* Skip link. Off-screen until focused, then a real, visible target at the top
   left - not a 1px box that "receives focus" invisibly. It lands on <main>,
   which carries tabindex="-1" so focus actually moves rather than only the
   scroll position. WCAG 2.4.1. */
.skip-link{
  position:absolute;left:-9999px;top:0;z-index:10;
  padding:12px 18px;min-height:44px;display:inline-flex;align-items:center;
  font-weight:900;font-size:12px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--deep-blue);background:var(--yellow);text-decoration:none;
  border-radius:0 0 var(--radius) 0;
}
.skip-link:focus{left:0}
.skip-link:focus-visible{outline:2px solid var(--deep-blue);outline-offset:-4px;box-shadow:none}
/* The target must not draw a ring of its own when focus is moved to it
   programmatically - the page scrolling to the content is the feedback. */
main:focus{outline:none}

/* Visually hidden, still exposed to assistive technology. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}

/* Focus.
   The handoff ring is an #014C8D border plus a 3px rgba(1,76,141,.18) halo.
   That reads clearly on a white input, but an 18% halo alone is not
   perceivable against a filled button, so buttons additionally carry a solid
   2px outline. The halo from the handoff is retained in both cases. */
:focus{outline:none}
/* .search-input belongs in this list. It was previously omitted, which left the
   dashboard Search box with no focus indicator at all once :focus removed the
   UA outline - only the caret moved. WCAG 2.1 AA 2.4.7. */
.input:focus-visible,.select:focus-visible,.date-input:focus-visible,
.search-input:focus-visible,.textarea:focus-visible{
  border-color:var(--aqua);
  box-shadow:var(--focus-ring);
}
button:focus-visible,a:focus-visible,[tabindex]:focus-visible{
  outline:2px solid var(--aqua);
  outline-offset:2px;
  box-shadow:var(--focus-ring);
}
/* Buttons with a dark fill: an aqua outline on an aqua button is invisible, so
   these get a two-tone ring instead - white inside to separate it from the
   fill, deep blue outside to separate it from the page. */
.btn--primary:focus-visible,.btn--action:focus-visible,
.chip[aria-pressed="true"]:focus-visible,.seg__btn[aria-pressed="true"]:focus-visible,
.result-btn.is-selected:focus-visible{
  outline:none;
  box-shadow:0 0 0 2px var(--white), 0 0 0 5px var(--deep-blue);
}
.textarea:focus-visible{border-color:var(--danger);box-shadow:0 0 0 3px rgba(168,50,42,.16)}

/* Motion: hover transitions on buttons only, under 150ms. */
button,.launch-card{transition:background-color 120ms ease-out,color 120ms ease-out,border-color 120ms ease-out}
@media (prefers-reduced-motion:reduce){
  *{transition-duration:0ms !important;animation-duration:0ms !important}
}

/* --------------------------------------------------------------------------
   4. App header (shared by every screen; markup from VPT.headerHTML)
   -------------------------------------------------------------------------- */
.app-header{
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  flex-wrap:wrap;padding:14px 20px;background:var(--deep-blue);
}
.app-header--wide{padding:14px 24px}
.app-header__brand{display:flex;align-items:center;gap:18px;min-width:0}
.app-header__logo{height:26px;width:auto}
.app-header__divider{width:1px;height:22px;background:rgba(255,255,255,.22);display:block}
.app-header__title{
  font-weight:900;font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:var(--yellow);
  margin:0;   /* it may render as an <h1> - see VPT.headerHTML asH1 */
}
.app-header__meta{
  display:flex;align-items:center;gap:12px;
  font-weight:700;font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:rgba(255,255,255,.82);
}
/* Header nav between the board, the Available queue and the two forms. */
.app-nav{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-left:6px}
.app-nav__link{
  /* 44px like every other target. It was 34, and it is the control an operator
     taps most - naming .notice-dismiss as "the" exception while this sat here
     was not a true account of the build. See the target-size note in the
     README: 44px is this project's house standard for gloved hands, NOT a
     WCAG 2.1 AA requirement (there isn't one; 2.5.5 is AAA and 2.2 AA's 2.5.8
     asks 24x24). */
  display:inline-flex;align-items:center;padding:7px 10px;min-height:44px;
  font-weight:900;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(255,255,255,.82);text-decoration:none;border-radius:var(--radius);
  border:1px solid transparent;
}
.app-nav__link:hover{color:var(--white);background:rgba(255,255,255,.1)}
.app-nav__link.is-current{
  color:var(--deep-blue);background:var(--yellow);border-color:var(--yellow);
}
.app-nav__link:focus-visible{
  outline:2px solid var(--yellow);outline-offset:2px;box-shadow:none;
}

.status-dot{width:7px;height:7px;border-radius:999px;background:var(--green);display:block;flex:none}
.app-header__clock{
  font-weight:700;font-size:12px;letter-spacing:.06em;text-transform:none;color:var(--white);
  font-variant-numeric:tabular-nums;
}

/* --------------------------------------------------------------------------
   5. Form screens (Job Tracker, QA/QC): fluid column capped at 560px
   -------------------------------------------------------------------------- */
.form-page{min-height:100vh;padding:40px 24px;display:flex;justify-content:center;align-items:flex-start}
.form-wrap{width:100%;max-width:560px}

.card{
  background:var(--white);border:var(--panel-border);border-radius:var(--radius);
  box-shadow:var(--card-shadow);overflow:hidden;
}

.titleblock{padding:24px 24px 0}
.eyebrow{
  font-weight:700;font-size:12px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--aqua);margin-bottom:6px;
}
.screen-title{
  font-weight:900;font-size:30px;line-height:1.1;letter-spacing:.025em;
  text-transform:uppercase;color:var(--deep-blue);margin:0;
}
.subhead{
  font-style:italic;font-weight:400;font-size:14px;line-height:1.4;letter-spacing:.02em;
  color:var(--grey);margin-top:7px;
}

.form-body{padding:22px 24px 0;display:flex;flex-direction:column;gap:18px}

.field__label{
  display:block;font-weight:700;font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--deep-blue);margin-bottom:7px;
}

/* SO number row -------------------------------------------------------- */
.so-row{display:flex;gap:10px}
.input-wrap{position:relative;flex:1;min-width:0}
.input-icon{
  position:absolute;left:14px;top:50%;transform:translateY(-50%);
  display:flex;pointer-events:none;color:var(--grey);
}
.input{
  width:100%;padding:15px 14px;font-weight:700;font-size:16px;letter-spacing:.03em;
  color:var(--deep-blue);background:var(--white);border:1px solid var(--input-border);
  border-radius:var(--radius);min-height:54px;
}
.input--so{padding-left:44px;font-size:19px;letter-spacing:.06em}
.input::placeholder{font-weight:400;letter-spacing:.02em;color:var(--grey)}

.scan-btn{
  flex:none;padding:0 18px;min-height:54px;
  font-weight:900;font-size:12px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--deep-blue);background:var(--field-fill);
  border:1px solid var(--input-border);border-radius:var(--radius);cursor:pointer;
}
.scan-btn:hover{background:var(--yellow);border-color:var(--yellow)}

/* "No job found" note under the SO field. */
.so-note{
  display:flex;align-items:center;gap:7px;margin-top:8px;
  font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--danger-ink);
}

/* Customer strip ------------------------------------------------------- */
.customer-strip{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:13px 16px;background:var(--sandstone);
  border:1px solid var(--hairline);border-left:3px solid var(--aqua);border-radius:var(--radius);
}
.customer-strip__label{
  font-weight:700;font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--grey);margin-bottom:3px;
}
.customer-strip__name{font-weight:700;font-size:15px;letter-spacing:.02em;color:var(--deep-blue)}
.customer-strip__note{
  font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey);text-align:right;flex:none;
}

/* Read-only sheets / parts --------------------------------------------- */
.ro-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.ro-box{
  display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px;
  background:var(--field-fill);border:1px dashed var(--input-border);border-radius:var(--radius);
}
.ro-box__value{font-weight:700;font-size:18px;letter-spacing:.04em;color:var(--body-ink)}
.ro-tag{
  font-weight:700;font-size:12px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--grey);white-space:nowrap;
}
.ro-tag--boxed{
  padding:4px 8px;background:var(--white);border:1px solid var(--hairline);border-radius:var(--radius);
}
/* Full width inside the two-column read-only grid. The material is a label,
   not a number: "0.5mm White" in a half-width box wraps at the widths these
   forms are actually used at, and sitting beside "8" it reads as a count. */
.ro-wide{grid-column:1/-1}
/* Text, so it does not take the 18px figure size the counts use - a material
   name at that size wraps where a two-digit number never would. */
.ro-box__value--text{font-size:15px;letter-spacing:.03em}
.source-note{
  grid-column:1/-1;display:flex;align-items:center;gap:8px;
  font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey);margin-top:-4px;
}
.source-note svg{color:var(--aqua);flex:none}

/* Select --------------------------------------------------------------- */
.select-wrap{position:relative}
.select{
  width:100%;appearance:none;-webkit-appearance:none;
  padding:15px 44px 15px 14px;min-height:54px;
  font-weight:700;font-size:16px;letter-spacing:.03em;color:var(--deep-blue);
  background:var(--white);border:1px solid var(--input-border);border-radius:var(--radius);cursor:pointer;
}
.select-chevron{
  position:absolute;right:15px;top:50%;transform:translateY(-50%);
  pointer-events:none;display:flex;color:var(--deep-blue);
}

/* Timestamp ------------------------------------------------------------ */
.stamp-row{
  display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px;
  background:var(--field-fill);border:1px dashed var(--input-border);border-radius:var(--radius);
}
.stamp-row__inner{display:flex;align-items:center;gap:11px;min-width:0}
.stamp-row__inner svg{color:var(--grey);flex:none}
.stamp-row__value{
  font-weight:700;font-size:15px;letter-spacing:.03em;color:var(--body-ink);
  font-variant-numeric:tabular-nums;
}

/* Actions -------------------------------------------------------------- */
.actions{
  padding:22px 24px 24px;margin-top:20px;display:flex;align-items:center;gap:14px;
  border-top:1px solid var(--hairline);
}
.btn{
  font-weight:900;letter-spacing:.12em;text-transform:uppercase;
  border-radius:var(--radius);cursor:pointer;min-height:56px;
}
.btn--primary{
  flex:1;font-size:14px;color:var(--white);background:var(--aqua);border:0;
}
.btn--primary:hover:not(:disabled){background:var(--deep-blue)}
.btn--primary:disabled{background:var(--hairline);color:var(--grey);cursor:not-allowed}
.btn--ghost{
  flex:none;padding:0 20px;font-size:12px;color:var(--grey);
  background:transparent;border:1px solid var(--input-border);
}
.btn--ghost:hover{color:var(--deep-blue);background:var(--field-fill);border-color:var(--deep-blue)}

/* Confirmation bar: inline at the card bottom edge, never a toast ------- */
.confirm{
  display:flex;align-items:center;gap:11px;padding:13px 24px;
  background:var(--deep-blue);color:var(--white);
}
.confirm--fail{background:var(--danger)}
.confirm svg{color:var(--yellow);flex:none}
.confirm--fail svg{color:var(--white)}
.confirm__text{font-weight:700;font-size:12.5px;letter-spacing:.06em}

/* --------------------------------------------------------------------------
   6. QA/QC additions
   -------------------------------------------------------------------------- */
.result-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.result-btn{
  display:flex;align-items:center;justify-content:center;gap:10px;min-height:64px;
  font-weight:900;font-size:16px;letter-spacing:.1em;text-transform:uppercase;
  background:var(--white);border:2px solid var(--input-border);border-radius:var(--radius);cursor:pointer;
}
.result-btn--pass{color:var(--green-ink)}
.result-btn--fail{color:var(--danger-ink)}
/* Selected Pass uses --green-dark, not --green: white on #1E8F5B measures
   4.09:1 and fails AA for 16px bold. See README "Divergences from the spec". */
.result-btn--pass.is-selected{background:var(--green-dark);border-color:var(--green-dark);color:var(--white)}
.result-btn--fail.is-selected{background:var(--danger);border-color:var(--danger);color:var(--white)}

.fail-panel{
  padding:18px;background:var(--danger-tint);
  border:1px solid var(--danger-border);border-left:3px solid var(--danger);border-radius:var(--radius);
}
.fail-panel__label{
  display:block;font-weight:700;font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--danger-ink-deep);margin-bottom:7px;
}
.fail-panel .select{border-color:var(--danger-border-strong)}
.fail-hint{margin-top:10px;font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--danger-ink-deep)}
.notes-block{margin-top:16px}
.textarea{
  width:100%;resize:vertical;padding:13px 14px;
  font-weight:400;font-size:14px;line-height:1.5;letter-spacing:.02em;
  color:var(--deep-blue);background:var(--white);
  border:1px solid var(--danger-border-strong);border-radius:var(--radius);
}
.textarea::placeholder{color:var(--grey)}

/* Quiet link back to the launcher, sat under the card. */
.back-link{
  margin:18px 0 0;text-align:center;
  font-weight:700;font-size:12px;letter-spacing:.12em;text-transform:uppercase;
}
.back-link a{color:var(--aqua);text-decoration:none;padding:6px 8px;display:inline-block}
.back-link a:hover{color:var(--deep-blue);text-decoration:underline}

/* --------------------------------------------------------------------------
   7. Dashboard shell
   -------------------------------------------------------------------------- */
.dash-page{min-height:100vh;background:var(--page-bg)}
.dash-body{padding:24px;display:flex;flex-direction:column;gap:20px}

/* Filter toolbar ------------------------------------------------------- */
.toolbar{
  display:flex;align-items:flex-end;gap:16px;flex-wrap:wrap;padding:16px 18px;
  background:var(--white);border:var(--panel-border);border-radius:var(--radius);
}
.toolbar__label{
  display:block;font-weight:700;font-size:12px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--grey);margin-bottom:7px;
}
.toolbar__search{flex:1;min-width:240px}
.search-input{
  width:100%;padding:12px 14px 12px 40px;min-height:44px;
  font-weight:700;font-size:15px;letter-spacing:.03em;color:var(--deep-blue);
  background:var(--white);border:1px solid var(--input-border);border-radius:var(--radius);
}
.search-input::placeholder{font-weight:400;color:var(--grey)}
.search-icon{
  position:absolute;left:13px;top:50%;transform:translateY(-50%);
  display:flex;pointer-events:none;color:var(--grey);
}
.date-input{
  padding:12px;min-height:44px;
  font-weight:700;font-size:14px;letter-spacing:.02em;color:var(--deep-blue);
  background:var(--white);border:1px solid var(--input-border);border-radius:var(--radius);
}

.chip-row{display:flex;gap:8px;flex-wrap:wrap}
.chip{
  padding:11px 13px;min-height:44px;
  font-weight:900;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--grey);background:var(--white);
  border:1px solid var(--input-border);border-radius:var(--radius);cursor:pointer;
}
.chip:hover{border-color:var(--deep-blue);color:var(--deep-blue)}
.chip[aria-pressed="true"]{background:var(--deep-blue);color:var(--white);border-color:var(--deep-blue)}

.toolbar__right{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-left:auto;padding-bottom:2px}
.seg{display:flex}
.seg__btn{
  padding:11px 15px;min-height:44px;
  font-weight:900;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--grey);background:var(--white);border:1px solid var(--input-border);cursor:pointer;
}
.seg__btn:first-child{border-right:0;border-radius:var(--radius) 0 0 var(--radius)}
.seg__btn:last-child{border-radius:0 var(--radius) var(--radius) 0}
.seg__btn[aria-pressed="true"]{background:var(--deep-blue);color:var(--white);border-color:var(--deep-blue)}
.seg__btn[aria-pressed="true"]:first-child{border-right:0}
.result-count{font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey)}
.btn--clear{
  padding:11px 14px;min-height:44px;
  font-weight:900;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--aqua);background:transparent;border:1px solid var(--input-border);
  border-radius:var(--radius);cursor:pointer;
}
.btn--clear:hover{color:var(--deep-blue);background:var(--field-fill);border-color:var(--deep-blue)}

/* KPI row -------------------------------------------------------------- */
/* 150px rather than 170: six tiles then fit one row from ~1000px up, where
   170 wrapped them 5+1 and left a dead band beside the orphan. Seven tiles
   (the Available queue) still wrap 6+1 below ~1130px - unavoidable without
   dropping a tile or the 12px text floor, and the wrapped tile stretches. */
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(145px,1fr));gap:14px}

/* Layout-shift placeholders. Same box, same grid, no content - so the row
   occupies its final height on first paint instead of growing under the
   board. Replaced wholesale by the first render. */
.kpi--skeleton{min-height:171px;background:var(--white);opacity:.55}

/* What the tiles are counting, in words. The calendar's counter says this
   for itself; the tiles had nothing, so range-scoped numbers sat above a
   range-ignoring month view unexplained. */
.kpi-scope{
  margin:-8px 0 0;font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey);
}
.kpi{
  padding:16px 18px;background:var(--white);
  border:var(--panel-border);border-top:3px solid var(--stage,var(--grey));border-radius:var(--radius);
}
/* The label reserves two lines whether it needs them or not.

   Without it, "QA holds" (one line) sat beside "Available for production"
   (two), and the two 34px numbers underneath started at different heights -
   visible at 768 and 900, where more labels wrap. A row of KPI numbers that
   does not share a baseline reads as a rendering fault. Two lines is the
   observed maximum for the labels in use; a third would push the value down
   again, so keep labels short. */
.kpi__label{
  font-weight:700;font-size:12px;line-height:1.25;letter-spacing:.15em;text-transform:uppercase;
  color:var(--grey);margin-bottom:8px;min-height:30px;
}
.kpi__value{
  font-weight:900;font-size:34px;line-height:1;letter-spacing:.03em;color:var(--deep-blue);
  font-variant-numeric:tabular-nums;
}
/* Two lines reserved, like the label above it. Without it a tile's height
   depended on whether its note wrapped, so the row - and the placeholder
   height that has to match it - changed with the viewport. */
.kpi__note{
  font-weight:400;font-size:12px;line-height:1.25;letter-spacing:.02em;
  color:var(--grey);margin-top:7px;min-height:30px;
}

/* A KPI tile that is also a route to another page. */
.kpi--link{display:block;text-decoration:none}
.kpi--link:hover{background:var(--sandstone)}
.kpi--link:hover .kpi__cue{color:var(--deep-blue)}
.kpi__cue{
  display:inline-flex;align-items:center;gap:6px;margin-top:10px;
  font-weight:900;font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--aqua);
}

/* Available queue: a single ordered list, not stage columns. */
.queue-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));
  gap:12px;padding:14px 16px;list-style:none;margin:0;
}
/* The empty-state message spans the grid rather than sitting in one column
   of it, where it read as a stray card. */
.queue-grid__empty{grid-column:1/-1}
.queue-note{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:12px 16px;border-bottom:1px solid var(--hairline);
  font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey);
}
.queue-note strong{
  font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--deep-blue);
}

/* --------------------------------------------------------------------------
   8. Board view
   -------------------------------------------------------------------------- */
.board-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,340px);gap:20px;align-items:start}
.board{display:flex;flex-direction:column;gap:14px;min-width:0}
.board-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap}
.board-head__title{
  font-weight:900;font-size:15px;letter-spacing:.1em;text-transform:uppercase;color:var(--deep-blue);margin:0;
}
.board-head__note{font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey)}

/* Six columns, one row, at desktop widths.

   `auto-fit` with a 200px floor could never do it: the board track is about
   1,017px at 1440 and 976px at 1024, which fits FOUR - so Staging and
   Complete / Shipped wrapped onto a second row starting ~670px down and left
   a ~640x1000px white void beside them. A stage board that does not show the
   whole pipeline in one row is not a board.

   Below 1000px the columns would be too narrow to read, so the fluid rule
   takes back over there - 834 and 768 (iPad Pro 11" and iPad portrait, the
   widths that actually matter on the floor) land on three columns.

   A stray-stage column is a 7th item and wraps to a second row deliberately:
   it is an anomaly, and it should look like one. */
.stage-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px;align-items:start}
@media (min-width:1000px){
  .stage-grid{grid-template-columns:repeat(6,minmax(0,1fr))}
}
.stage-col{
  background:var(--white);border:var(--panel-border);border-top:3px solid var(--stage,var(--grey));
  border-radius:var(--radius);display:flex;flex-direction:column;min-width:0;
}
.stage-col__head{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:12px 14px;border-bottom:1px solid var(--hairline);
}
.stage-col__name{
  font-weight:900;font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--deep-blue);margin:0;
}
/* A column for a stage outside the canonical seven. Uppercasing would erase a
   case difference and normal white-space handling would collapse padding
   spaces, so "cnc", " CNC " and "CNC" would all look like the real column.
   Keep the raw value verbatim and colour it as the warning it is. */
.stage-col__name--stray,.stage-pill--stray{
  text-transform:none;white-space:pre-wrap;word-break:break-word;color:var(--danger-ink);
}
.stage-pill--stray{background:var(--danger-tint);border:1px solid var(--danger);color:var(--danger-ink)}
.stage-col__count{
  font-weight:900;font-size:12px;letter-spacing:.04em;
  color:var(--badge-ink,#fff);background:var(--badge-bg,var(--grey));
  padding:3px 8px;border-radius:var(--radius);
}
/* A <ul> when it holds cards, a <div> when it holds the empty placeholder.
   The list gives each card a boundary and the column an item count for
   assistive tech; the reset stops it looking like a bulleted list. */
.stage-col__body{padding:12px;display:flex;flex-direction:column;gap:10px;list-style:none;margin:0}

.empty{
  padding:16px 10px;border:1px dashed var(--input-border);border-radius:var(--radius);
  text-align:center;font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey);
}

/* Job card ------------------------------------------------------------- */
.job-card{
  padding:11px 12px;background:var(--sandstone);
  border:1px solid var(--hairline);border-left:3px solid var(--stage,var(--grey));
  border-radius:var(--radius);
}
.job-card--held{background:var(--danger-tint);border-color:var(--danger-border)}
/* Band material on a job card. Its own row under the counts, and only drawn
   when the job has one - see jobCardHTML. The label is a prefix rather than a
   column so the row costs one line whatever the material is called. */
.material-row{
  display:flex;align-items:baseline;gap:7px;margin-top:6px;
  font-weight:700;font-size:12px;letter-spacing:.03em;color:var(--body-ink);
  overflow-wrap:anywhere;
}
.material-row__label{
  font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--grey);flex:none;
}
/* Wraps rather than colliding: six columns at 1024 leave ~150px of card, and
   "SO-48198" beside "7:12 AM" does not fit that on one line. */
.job-card__top{display:flex;align-items:baseline;justify-content:space-between;gap:8px;flex-wrap:wrap}
.job-card__so{font-weight:900;font-size:14px;letter-spacing:.04em;color:var(--deep-blue)}
.job-card__time{font-weight:700;font-size:12px;letter-spacing:.03em;color:var(--grey);white-space:nowrap}
.job-card__customer{font-weight:400;font-size:12.5px;line-height:1.35;letter-spacing:.02em;color:var(--body-ink);margin-top:4px}
.job-card__dates{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:6px}
.job-date{font-weight:700;font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:var(--grey)}

.due-chip{
  padding:2px 7px;border-radius:var(--radius);
  font-weight:700;font-size:12px;letter-spacing:.04em;
  background:var(--field-fill);border:1px solid var(--hairline);color:var(--grey);
}
.due-chip--soon{background:var(--due-soon-fill);border-color:var(--yellow);color:var(--due-soon-ink)}
.due-chip--late{background:var(--danger-tint);border-color:var(--danger);color:var(--danger-ink)}

.micro-stats{
  display:flex;align-items:center;gap:10px;margin-top:8px;flex-wrap:wrap;
  font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--grey);
}
.micro-rule{width:1px;height:10px;background:var(--input-border);display:block;flex:none}

/* Order value. Deep blue rather than grey because it is the figure the floor
   schedules against - the source sheet's day capacity is a dollar figure, not
   a sheet count. Tabular numerals so a column of cards lines up. A missing
   total drops to grey and lighter weight: "No total" is the absence of a
   number, and should not read with the authority of one. */
.money-row{
  margin-top:8px;
  font-weight:900;font-size:13px;letter-spacing:.04em;color:var(--deep-blue);
  font-variant-numeric:tabular-nums;
}
.money-row--none{font-weight:700;font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:var(--grey)}
.money-row + .micro-stats{margin-top:5px}
.micro-money{color:var(--deep-blue);font-variant-numeric:tabular-nums;letter-spacing:.04em}
.micro-money--none{color:var(--grey)}

/* Flags sit on their own wrapping row so two never collide in a narrow column. */
.flag-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:6px}
.flag-row:empty{display:none}
.flag{
  display:inline-flex;align-items:center;gap:4px;padding:2px 7px;border-radius:var(--radius);
  font-weight:900;font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--white);
}
.flag--priority{background:var(--aqua)}
.flag--rush{background:var(--danger)}
.flag svg{flex:none}

.qa-bar{
  margin-top:9px;padding:6px 8px;background:var(--danger);border-radius:var(--radius);
  font-weight:700;font-size:12px;letter-spacing:.06em;color:var(--white);
}

/* Sidebar -------------------------------------------------------------- */
.sidebar{display:flex;flex-direction:column;gap:20px;min-width:0}
.panel{background:var(--white);border:var(--panel-border);border-radius:var(--radius)}
.panel__head{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:13px 16px;border-bottom:1px solid var(--hairline);
}
.panel__head--holds{background:var(--danger);border-bottom:0}
.panel__head--scans{border-top:3px solid var(--aqua)}
.panel__title{font-weight:900;font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--deep-blue);margin:0}
.panel__head--holds .panel__title{color:var(--white)}
.panel__count{
  font-weight:900;font-size:12px;letter-spacing:.04em;
  color:var(--danger);background:var(--white);padding:3px 8px;border-radius:var(--radius);
}
.panel__body{padding:14px 16px;display:flex;flex-direction:column;gap:12px}

.hold-row{display:flex;flex-direction:column;gap:4px;padding-bottom:12px;border-bottom:1px solid var(--hairline)}
.hold-row:last-child{border-bottom:0;padding-bottom:0}
.hold-row__top{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
.hold-row__so{font-weight:900;font-size:14px;letter-spacing:.04em;color:var(--deep-blue)}
.hold-row__time{font-weight:700;font-size:12px;letter-spacing:.03em;color:var(--grey)}
.hold-row__customer{font-weight:400;font-size:12.5px;letter-spacing:.02em;color:var(--body-ink)}
.hold-row__reason{font-weight:700;font-size:12px;letter-spacing:.03em;color:var(--danger-ink)}

.feed-body{gap:13px}
.feed-row{display:grid;grid-template-columns:auto 1fr auto;gap:11px;align-items:baseline}
.feed-dot{width:9px;height:9px;border-radius:999px;display:block;background:var(--dot,var(--aqua));flex:none}
.feed-row__main{min-width:0}
.feed-row__title{font-weight:700;font-size:13px;letter-spacing:.03em;color:var(--deep-blue)}
.feed-row__who{font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey);margin-top:2px}
.feed-row__right{text-align:right}
.feed-row__time{font-weight:700;font-size:12px;letter-spacing:.03em;color:var(--grey)}
.feed-row__date{font-weight:700;font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--grey);margin-top:2px}

/* --------------------------------------------------------------------------
   9. Month view
   -------------------------------------------------------------------------- */
.month-panel{background:var(--white);border:var(--panel-border);border-top:3px solid var(--aqua);border-radius:var(--radius)}
.month-head{
  display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  padding:14px 18px;border-bottom:1px solid var(--hairline);
}
.month-nav{display:flex;align-items:center;gap:12px}
.stepper{
  width:44px;height:44px;display:flex;align-items:center;justify-content:center;
  background:var(--white);border:1px solid var(--input-border);border-radius:var(--radius);
  cursor:pointer;color:var(--deep-blue);
}
.stepper:hover{background:var(--field-fill);border-color:var(--deep-blue)}
.month-label{
  font-weight:900;font-size:16px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--deep-blue);min-width:190px;text-align:center;margin:0;
}
.month-meta{
  display:flex;align-items:center;gap:16px;flex-wrap:wrap;
  font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--grey);
}
.legend-item{display:inline-flex;align-items:center;gap:6px}
.legend-swatch{width:10px;height:10px;display:block;border-radius:1px}
.legend-swatch--priority{background:var(--aqua)}
.legend-swatch--rush{background:var(--danger)}
/* The letter the chips carry, repeated in the legend so the mapping is
   learnable from the page rather than inferred. The swatch stays: colour is a
   fine ADDITIONAL cue, it just cannot be the only one (1.4.1). */
.legend-mark{font-weight:900;letter-spacing:.06em;margin-right:4px;color:var(--deep-blue)}
.month-total{font-weight:400;font-size:12px;letter-spacing:.02em;text-transform:none;color:var(--grey)}

.month-grid-wrap{padding:14px 18px 18px}
.weekday-row{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:8px;margin-bottom:8px}
.weekday{
  font-weight:900;font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--grey);text-align:center;padding:4px 0;
}
.weeks{display:flex;flex-direction:column;gap:8px}
.week{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:8px}

.day-cell{
  min-height:116px;padding:8px;text-align:left;font-family:var(--font);
  background:var(--white);border:1px solid var(--hairline);border-radius:var(--radius);
  display:flex;flex-direction:column;gap:6px;cursor:pointer;width:100%;
}
.day-cell--blank{background:transparent;border-color:transparent;cursor:default}
.day-cell--weekend{background:var(--field-fill)}
.day-cell--today{background:var(--today-fill);border-color:var(--yellow)}
.day-cell--selected{background:var(--priority-tint);border-color:var(--aqua)}
.day-cell--empty{cursor:default}
.day-cell__top{display:flex;align-items:center;justify-content:space-between;gap:6px;min-height:18px}
.day-num{font-weight:900;font-size:13px;letter-spacing:.03em;color:var(--deep-blue)}
.day-count{
  font-weight:900;font-size:12px;letter-spacing:.06em;color:var(--white);
  background:var(--deep-blue);padding:2px 6px;border-radius:var(--radius);
}
.day-chip{
  padding:2px 7px;border-radius:var(--radius);border-left:2px solid var(--edge,var(--input-border));
  background:var(--chip-bg,var(--field-fill));color:var(--chip-ink,var(--body-ink));
  font-weight:700;font-size:12px;letter-spacing:.02em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* The 1.4.1 marker on a calendar chip: P for priority, R for rush or QA hold.
   Bold, inherits the chip's ink, and sits on the 12px floor like everything
   else - the fill alone carried this before, and the legend was itself a
   colour swatch. */
.day-chip__mark{font-weight:900;letter-spacing:.06em;margin-right:4px}
.day-more{font-weight:700;font-size:12px;letter-spacing:.06em;color:var(--grey)}
/* The day's order value, pinned to the bottom of the cell so it sits on one
   line across a week however many chips each day carries. */
/* The day's money sits at the bottom of the cell. It may truncate - it is a
   figure, and a truncated figure still reads as one. */
.day-money{
  margin-top:auto;padding-top:4px;
  font-weight:900;font-size:12px;letter-spacing:.02em;color:var(--deep-blue);
  font-variant-numeric:tabular-nums;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* The caveat must not. It is short enough to survive at every width, it gets
   its own line under the figure, and it is coloured as the warning it is -
   "+1 no total" clipped to "+1 n…" reads as part of a number. */
.day-money__gap{
  display:block;
  font-weight:700;font-size:12px;letter-spacing:.02em;color:var(--danger-ink);
  white-space:nowrap;
}
.day-money + .day-money__gap{margin-top:1px}

.month-empty{margin:14px 0 0}

/* Shown when stored data was unreadable and had to be discarded. */
.data-notice{
  display:flex;align-items:center;gap:10px;padding:12px 16px;
  background:var(--danger-tint);border:1px solid var(--danger-border);
  border-left:3px solid var(--danger);border-radius:var(--radius);
  font-weight:700;font-size:12.5px;letter-spacing:.02em;color:var(--danger-ink-deep);
}
/* The informational variant. The red treatment is for loss; retiring an old
   store and carrying the work across is news, not damage, and colouring it as
   damage would be its own small lie. */
.data-notice--info{
  background:var(--priority-tint);border-color:var(--input-border);
  border-left-color:var(--aqua);color:var(--deep-blue);
}
/* Two classes, so this beats `.data-notice svg` below it on specificity rather
   than on source order - which it lost, leaving a blue panel with a red danger
   icon. The comment above says colouring this as damage would be its own small
   lie; the icon was still telling it. */
.data-notice.data-notice--info svg{color:var(--aqua)}
/* The dismiss control sits at the end of the notice row and only ever appears
   on the informational variant - see the markup comment. */
.notice-dismiss{margin-left:auto;flex:none;padding:8px 14px;min-height:44px;font-size:12px}
.data-notice svg{color:var(--danger);flex:none}

/* Day detail ----------------------------------------------------------- */
.day-detail{margin-top:18px;border:1px solid var(--input-border);border-top:3px solid var(--aqua);border-radius:var(--radius)}
.day-detail__head{
  display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;
  padding:14px 16px;background:var(--sandstone);border-bottom:1px solid var(--hairline);
}
.day-detail__title{font-weight:900;font-size:15px;letter-spacing:.06em;text-transform:uppercase;color:var(--deep-blue);margin:0}
.day-detail__count{font-weight:400;font-size:12.5px;letter-spacing:.02em;color:var(--grey);margin-top:3px}
.day-detail__actions{display:flex;gap:10px}
.btn--action{
  padding:11px 15px;min-height:44px;
  font-weight:900;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--white);background:var(--aqua);border:0;border-radius:var(--radius);cursor:pointer;
}
.btn--action:hover{background:var(--deep-blue)}
.btn--quiet{
  padding:11px 15px;min-height:44px;
  font-weight:900;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--grey);background:var(--white);
  border:1px solid var(--input-border);border-radius:var(--radius);cursor:pointer;
}
.btn--quiet:hover{color:var(--deep-blue);background:var(--field-fill);border-color:var(--deep-blue)}

.day-detail__body{
  padding:14px 16px;display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));
  gap:12px;list-style:none;margin:0;
}
.detail-card{padding:12px 14px;background:var(--white);border:1px solid var(--hairline);border-radius:var(--radius)}
.detail-card__top{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.detail-card__so{font-weight:900;font-size:14px;letter-spacing:.04em;color:var(--deep-blue)}
/* Four meta values never fit one line in a 250px card, and a wrapping flex row
   orphaned a separator rule at the end of the line. A fixed two-column grid
   removes the separators entirely and always aligns. */
.stage-pill{
  font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--badge-ink,#fff);background:var(--badge-bg,var(--grey));
  padding:3px 7px;border-radius:var(--radius);white-space:nowrap;
}
.detail-card__customer{font-weight:400;font-size:12.5px;line-height:1.35;letter-spacing:.02em;color:var(--body-ink);margin-top:5px}
.detail-card__meta{
  display:grid;grid-template-columns:auto auto;gap:4px 16px;justify-content:start;
  margin-top:8px;
  font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--grey);
}
.hold-tag{
  padding:2px 7px;background:var(--danger-tint);border:1px solid var(--danger);
  border-radius:var(--radius);font-weight:700;font-size:12px;letter-spacing:.04em;color:var(--danger-ink);
}

/* --------------------------------------------------------------------------
   10. Launcher (index.html)
   -------------------------------------------------------------------------- */
.launcher{padding:40px 24px;max-width:1100px;margin:0 auto}
.launcher__intro{margin-bottom:28px}
.launch-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px}
.launch-card{
  display:block;text-decoration:none;padding:24px;background:var(--white);
  border:var(--panel-border);border-top:3px solid var(--stage,var(--aqua));
  border-radius:var(--radius);box-shadow:var(--card-shadow);
}
.launch-card:hover{background:var(--sandstone)}
.launch-card__icon{color:var(--aqua);margin-bottom:14px}
.launch-card__title{
  font-weight:900;font-size:20px;letter-spacing:.04em;text-transform:uppercase;
  color:var(--deep-blue);margin:0 0 8px;
}
.launch-card__desc{font-weight:400;font-size:13px;line-height:1.5;letter-spacing:.02em;color:var(--body-ink);margin:0}
.launch-card__cue{
  display:inline-flex;align-items:center;gap:6px;margin-top:14px;
  font-weight:900;font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--aqua);
}
.launcher__footer{
  margin-top:32px;padding-top:18px;border-top:1px solid var(--input-border);
  display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey);
}
.btn--reset{
  padding:10px 14px;min-height:44px;
  font-weight:900;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--grey);background:transparent;
  border:1px solid var(--input-border);border-radius:var(--radius);cursor:pointer;
}
.btn--reset:hover{color:var(--deep-blue);background:var(--white);border-color:var(--deep-blue)}

/* --------------------------------------------------------------------------
   11. Line 1 order table

   A transcription of the Line# 1 Production sheet, NOT a view of the app's
   own job records - so it deliberately looks like a spreadsheet rather than
   like the queue cards above it. Thirteen columns of free text cannot reflow
   to a card at 320px and must not be made to: the value of this table is that
   a planner can read a row against the workbook it came from, column for
   column. So it scrolls sideways inside its own box (the same rule the month
   grid follows) and the PAGE never does.
   -------------------------------------------------------------------------- */
/* It follows the queue or the calendar, whichever is showing, so it carries
   its own separation rather than relying on a gap that only exists in one of
   the two layouts. */
.l1-panel{margin-top:16px}
.l1-note{
  display:flex;flex-direction:column;gap:4px;
  padding:12px 16px;border-bottom:1px solid var(--hairline);
  font-weight:400;font-size:12px;letter-spacing:.02em;color:var(--grey);
}
.l1-note strong{
  font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--deep-blue);
}
.l1-scroll{overflow-x:auto;padding:0}
.l1-table{border-collapse:collapse;width:100%;min-width:1700px;font-size:12px;letter-spacing:.02em}
.l1-table caption{
  text-align:left;padding:10px 16px;font-size:12px;color:var(--grey);
}
/* The block date repeats on every row rather than being a spanned heading
   row: a spanned row breaks the moment the table is sorted or copied out into
   another sheet, which is the first thing anyone will do with this. */
.l1-table th,.l1-table td{
  padding:7px 10px;border-bottom:1px solid var(--hairline);
  text-align:left;vertical-align:top;white-space:nowrap;
}
.l1-table thead th{
  position:sticky;top:0;z-index:1;
  background:var(--deep-blue);color:var(--white);
  font-weight:700;font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  border-bottom:0;white-space:normal;
}
/* Column letter under the sheet's own header text, so a value can be traced
   back to the cell it came from without counting columns in Excel. */
.l1-table thead .l1-col{display:block;font-weight:400;color:var(--yellow);letter-spacing:.1em}
.l1-table tbody tr:nth-child(even){background:var(--sandstone)}
.l1-table tbody tr:hover{background:var(--priority-tint)}
.l1-row-no{color:var(--grey);font-variant-numeric:tabular-nums}
.l1-so{font-weight:900;font-size:13px;color:var(--deep-blue)}
.l1-total{text-align:right;font-variant-numeric:tabular-nums}
/* Free text - descriptions run to 90 characters and comments to 60. These are
   the only two columns allowed to wrap, and they are capped so a single long
   cell cannot push Order Total off the far edge of the scroll box. */
.l1-wrap{white-space:normal;min-width:240px;max-width:340px}
.l1-wrap--narrow{white-space:normal;min-width:150px;max-width:220px}
/* An empty cell is empty in the sheet. Saying so beats a blank that reads as
   a rendering failure. */
.l1-empty{color:var(--input-border)}
/* A row the sheet carries with no order number in column C. It is on the
   list, so it is in the table; it is flagged because it cannot be looked up. */
.l1-table tbody tr.l1-row--noso{background:var(--danger-tint)}
.l1-table tbody tr.l1-row--noso:hover{background:var(--danger-tint)}
.l1-flag{
  font-weight:700;font-size:11px;letter-spacing:.04em;color:var(--danger-ink-deep);
  text-transform:uppercase;
}
.l1-foot{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap;
  padding:12px 16px;border-top:1px solid var(--hairline);
  font-weight:700;font-size:12px;letter-spacing:.03em;color:var(--deep-blue);
}
.l1-foot span{font-weight:400;color:var(--grey)}

/* --------------------------------------------------------------------------
   12. R72 scan test rig (qr-test.html)

   A bench page, not a floor screen, so it borrows the panel shell and adds
   only what it needs: a definition list for the fixture's fields and a card
   for each QR code. The codes are SVG files on disk - the app carries no QR
   encoder, see tools/make-r72-qr.py.
   -------------------------------------------------------------------------- */
/* The bench row on the launcher. One card, left at a readable width rather
   than stretched across the four-column grid the screens use. */
.launch-grid--bench{grid-template-columns:minmax(0,1fr);max-width:640px;margin-top:-6px}
.launch-card--bench{border-style:dashed}
.launch-card__tag{
  display:inline-block;margin-left:8px;padding:2px 7px;vertical-align:middle;
  background:var(--grey);color:var(--white);border-radius:var(--radius);
  font-weight:700;font-size:12px;letter-spacing:.08em;text-transform:uppercase;
}

.r72-facts{
  display:grid;grid-template-columns:auto 1fr;gap:6px 16px;margin:0;
  font-size:12.5px;letter-spacing:.02em;
}
.r72-facts dt{
  font-weight:700;font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--grey);padding-top:1px;
}
.r72-facts dd{margin:0;color:var(--body-ink)}
.r72-facts--wide{grid-template-columns:minmax(120px,160px) 1fr;gap:10px 16px}
.r72-actions,.r72-links{display:flex;gap:10px;flex-wrap:wrap;margin:0}
.r72-said{margin:0;font-size:12.5px;letter-spacing:.02em;color:var(--grey)}

.qr-grid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
  gap:16px;padding:14px 16px;
}
.qr-card{
  margin:0;padding:14px;background:var(--sandstone);
  border:1px solid var(--hairline);border-radius:var(--radius);
  display:flex;flex-direction:column;gap:12px;align-items:flex-start;
}
/* The quiet zone is baked into the SVG (border=2 modules). A white plate
   under it as well, because the card sits on sandstone and a scanner wants
   white, not #F8F8F8, around the symbol. */
.qr-img{
  display:block;width:100%;max-width:248px;height:auto;
  background:var(--white);border:1px solid var(--hairline);border-radius:var(--radius);
}
.qr-card__title{
  font-weight:900;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--deep-blue);margin:0;
}
.qr-card__desc{margin:6px 0 0;font-size:12.5px;letter-spacing:.02em;color:var(--body-ink)}
/* The encoded string, shown so nobody has to trust the caption. It wraps
   anywhere because a URL has no spaces and must not push the card wide. */
.qr-payload{
  display:block;margin:10px 0 0;padding:7px 9px;
  background:var(--white);border:1px solid var(--input-border);border-radius:var(--radius);
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:12px;color:var(--deep-blue);overflow-wrap:anywhere;
}
.qr-card__note{margin:8px 0 0;font-size:12px;letter-spacing:.02em;color:var(--grey)}
.qr-card__note--warn{color:var(--danger-ink)}
.qr-card figcaption{min-width:0}

/* --------------------------------------------------------------------------
   13. Responsive

   The widths below are the breakpoints the layout is BUILT around: 1440 and
   1024 desktop, 834 and 768 (iPad Pro 11" and iPad portrait) on the floor, and
   320 as the WCAG 1.4.10 reflow floor. Which of those have actually been
   looked at in a rendered browser, and by whom, belongs in the README - a
   comment claiming verification is not evidence of it, and the previous one
   here claimed 1440 and 1024 were verified while the board was silently
   wrapping to two rows at both.
   -------------------------------------------------------------------------- */
@media (max-width:1100px){
  /* Sidebar drops below the board rather than squeezing the stage columns. */
  .board-layout{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:820px){
  .dash-body{padding:16px;gap:16px}
  .month-grid-wrap{padding:12px}
  .toolbar__right{margin-left:0;width:100%}
  .day-cell{min-height:92px}
  .month-label{min-width:150px;font-size:14px}
}

/* Seven calendar columns leave roughly 60-80px of usable chip width on a
   tablet, which truncated SO numbers to "SO-480...". The "SO-" prefix carries
   no information, so it is dropped and the number - what an operator actually
   reads - stays legible at the 12px floor.

   The breakpoint is set from real device widths, not from where text stopped
   fitting on a dev machine. Portrait CSS widths: iPad mini 744, iPad (9th gen)
   768, iPad 10.2" 810, iPad Air 820, iPad Pro 11" 834. 900px clears the whole
   range with headroom rather than cutting through the middle of it. */
@media (max-width:900px){
  .day-chip__prefix{display:none}
  .day-cell{padding:6px;gap:4px}
  .day-count{padding:2px 4px}
}

@media (max-width:620px){
  .form-page{padding:24px 12px}
  .titleblock,.form-body,.actions{padding-left:18px;padding-right:18px}
  .confirm{padding-left:18px;padding-right:18px}
  .ro-grid{grid-template-columns:1fr}
  .weekday{font-size:12px;letter-spacing:.04em}
  .day-cell{min-height:88px;padding:5px}
  .detail-card__meta{grid-template-columns:auto}

  /* WCAG 1.4.10 Reflow. Seven calendar columns cannot fit 320px without
     dropping below the 12px text floor, and a month grid is two-dimensional
     data - the criterion permits it to scroll in one direction. What it does
     NOT permit is the PAGE scrolling, so the grid gets its own scroll box and
     everything around it reflows to one column. */
  .month-scroll{overflow-x:auto;padding-bottom:4px}
  /* Wide enough that the day's dollar figure and the SO chips read in full.
     430px fitted the grid in fewer swipes but ellipsised "$15,190" to "$15,…",
     which is the one number on the cell the floor plans against. */
  .month-scroll .weekday-row,.month-scroll .week{min-width:620px}
}

/* --------------------------------------------------------------------------
   320px - the reflow floor (WCAG 2.1 AA, 1.4.10)

   Two failures lived here: both dashboard pages scrolled horizontally, and the
   header nav was pushed entirely off-screen by the brand block, so the only
   route between the board and the queue was unreachable. Nothing is hidden to
   fix it - the nav wraps onto its own full-width row and stays operable.
   -------------------------------------------------------------------------- */
@media (max-width:480px){
  .dash-body{padding:12px;gap:12px}
  .app-header,.app-header--wide{padding:12px;gap:12px}
  /* The brand block stops being a single unbreakable row: the logo and title
     share line one, the nav takes line two rather than overflowing the page. */
  .app-header__brand{flex-wrap:wrap;gap:10px 12px}
  .app-header__divider{display:none}
  .app-nav{margin-left:0;width:100%;gap:6px}
  .app-header__meta{gap:8px;letter-spacing:.08em}

  .toolbar{padding:12px;gap:12px}
  .toolbar__search{min-width:0;flex:1 1 100%}
  .toolbar__right{gap:10px}
  .date-input{width:100%}
  .kpi-grid{grid-template-columns:1fr;gap:10px}
  .kpi__label{min-height:0}          /* one column: nothing to align against */

  .queue-grid,.day-detail__body{grid-template-columns:1fr;padding:12px}
  .launcher{padding:24px 12px}
  .launch-grid{grid-template-columns:1fr;gap:14px}
  .launch-card{padding:18px}

  .month-head{padding:12px;gap:10px}
  .month-grid-wrap{padding:10px}
  .day-detail__head{padding:12px}
  .day-detail__actions{width:100%}
  .day-detail__actions .btn--action,.day-detail__actions .btn--quiet{flex:1}

  .board-head{gap:4px}
  .form-page{padding:16px 10px}
}
