/* CGH Fulfillment Dashboard — standalone styles.
   Light, modern, generous whitespace. Mobile-responsive: the manager uses
   this on a phone/tablet on the floor. No framework — vanilla CSS. */

:root {
  --bg: #fafaf7;
  --surface: #ffffff;
  --ink: #1f2421;
  --ink-soft: #4b5249;
  --ink-faint: #5e6660;  /* was #828b80 — bumped 2026-05-22 for WCAG AA contrast (~5.5:1 on #fff vs ~3:1 before). Used across .count-sub, .empty, .del-subfilters-label, .row-edit, .ro-dash, .exc-stage, .ro-hint, status group labels — all of which Lighthouse flagged as failing AA. */
  --line: #e4e6e0;
  --green: #14532d;
  --green-soft: #e8f0ea;
  --aging-green: #eefaef;
  --aging-green-bd: #bfe3c6;
  --aging-yellow: #fdf6e3;
  --aging-yellow-bd: #ecd9a3;
  --aging-red: #fdeceb;
  --aging-red-bd: #f0bdb8;
  --flag: #b45309;
  --stall: #b91c1c;
  --radius: 10px;
  --shadow: 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--ink);
  -webkit-text-size-adjust: 100%;
  /* Belt-and-suspenders: prevents any abspos child (tooltip, popover,
     dropdown) that extends past the viewport from making the page
     pinch-zoomable into empty whitespace on mobile Safari. `clip`
     (not `hidden`) keeps abspos descendants visible but excludes them
     from scroll/zoom calc. */
  overflow-x: clip;
}

.dash { max-width: 1280px; margin: 0 auto; padding: 0 0 3rem; }

/* ---- Header ---- */
.dash-head {
  background: var(--green);
  color: #fff;
  /* env(safe-area-inset-top) ensures iOS Safari's floating URL bar
     doesn't eat the top row of header content. Falls back to 0 on
     non-notched browsers. Chris 2026-05-25 — caught real iPhone screenshot
     showing "Back to dashboard" partially obscured by Safari chrome. */
  padding: calc(.85rem + env(safe-area-inset-top)) 1rem .85rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;
  /* Chris 2026-05-25 P1-amendment: don't wrap — fit wordmark + location +
     refresh + roster all on one line on iPhone. Roster goes gear-only,
     wordmark allowed to truncate if needed. */
  flex-wrap: nowrap;
  position: sticky;
  top: 0;
  z-index: 10;
}
.brand { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; flex: 1 1 auto; }
.wordmark {
  font-size: 1.05rem; font-weight: 700; letter-spacing: .02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.brand-sub { font-size: .78rem; opacity: .8; }
.head-controls { flex: 0 0 auto; }
/* Mobile: tighten wordmark + gear-only Roster + hide username so we
   fit four things on the header row: wordmark, location, refresh,
   roster. */
@media (max-width: 480px) {
  .wordmark { font-size: .85rem; letter-spacing: 0; }
  .roster-btn-label { display: none; }
  .head-controls { gap: .5rem; }
  /* Hide the plain text name on mobile (no room). The Mine button still
     shows — but compacted to a bare star (name span hidden below). */
  .head-controls > .who-am-i:not(.who-am-i-mine) { display: none; }
  .head-controls > button.who-am-i-mine .who-mine-name { display: none; }
  .head-controls > button.who-am-i-mine { padding: .3rem .45rem; }
}
.head-controls { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.loc-pick { display: flex; align-items: center; gap: .4rem; }
.loc-label { font-size: .78rem; opacity: .85; }
#cgh-location {
  font: inherit; font-size: .9rem; padding: .3rem .5rem;
  border-radius: 6px; border: 1px solid rgba(255,255,255,.3);
  background: rgba(255,255,255,.12); color: #fff;
}
#cgh-location option { color: #1f2421; }
.refresh { display: flex; align-items: center; gap: .5rem; }
.last-refresh { font-size: .78rem; opacity: .85; min-width: 7.5rem; text-align: right; }
.refresh-btn {
  position: relative; width: 2rem; height: 2rem; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.3); background: rgba(255,255,255,.12);
  color: #fff; cursor: pointer; font-size: 1rem; line-height: 1;
  /* Chris 2026-05-25 P21: subtle hover-lift for tactile feel on desktop;
     mobile taps ignore :hover so this is desktop-only enrichment. */
  transition: background .12s, transform .08s, box-shadow .12s;
}
.refresh-btn:hover { background: rgba(255,255,255,.22); transform: translateY(-1px); box-shadow: 0 2px 6px rgba(0,0,0,.18); }
.refresh-btn:active { transform: translateY(0); box-shadow: none; }
.refresh-icon { display: inline-block; }
.spinner {
  display: none; position: absolute; inset: 0; margin: auto;
  width: 1rem; height: 1rem; border: 2px solid rgba(255,255,255,.35);
  border-top-color: #fff; border-radius: 50%; animation: spin .7s linear infinite;
}
.dash.is-loading .spinner { display: block; }
.dash.is-loading .refresh-icon { visibility: hidden; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Top-of-viewport progress bar — shows during any snapshot poll or
   filter-driven refetch. Always visible because the dash-header isn't
   sticky on mobile, so the small spinner-in-header is easy to miss.

   Implementation: a fixed 40%-width bar that slides left→right via
   `transform: translateX(...)`. translate is GPU-composited, so the
   animation doesn't trigger layout/repaint each frame — keeps page
   CLS at ~0. Prior version animated `background-position-x`, a
   non-composited property; that caused CLS ≈ 0.12. */
.dash::before {
  content: '';
  position: fixed; top: 0; left: 0;
  width: 40%;
  height: 3px; z-index: 200;
  background: linear-gradient(90deg, transparent 0%, var(--green) 50%, transparent 100%);
  transform: translateX(-100%);
  opacity: 0;
  transition: opacity .15s ease;
  pointer-events: none;
  will-change: transform;
}
.dash.is-loading::before {
  opacity: 1;
  animation: cgh-loadbar 1.1s linear infinite;
}
@keyframes cgh-loadbar {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(250%); }
}
.who-am-i { font-size: .82rem; opacity: .9; }

/* Identity-as-Mine-toggle (Chris 2026-05-26). On desktop it reads as
   "★ Chris" — the name doubles as the tap target. On mobile only the
   star shows, sitting compactly in head-controls between the gear and
   the right edge. Active = gold star + green pill background. */
button.who-am-i-mine {
  display: inline-flex; align-items: center; gap: .35rem;
  font: inherit; font-size: .82rem;
  background: rgba(255,255,255,.10);
  border: 1px solid rgba(255,255,255,.25);
  color: #fff;
  padding: .3rem .55rem;
  border-radius: 999px;
  cursor: pointer;
  opacity: .9;
  transition: background .12s, opacity .12s;
}
button.who-am-i-mine:hover { background: rgba(255,255,255,.18); opacity: 1; }
button.who-am-i-mine .who-mine-star { font-size: 1rem; line-height: 1; }
button.who-am-i-mine.is-on,
button.who-am-i-mine[aria-pressed="true"] {
  background: rgba(251,191,36,.22);                /* gold wash */
  border-color: rgba(251,191,36,.55);
  opacity: 1;
}
button.who-am-i-mine.is-on .who-mine-star,
button.who-am-i-mine[aria-pressed="true"] .who-mine-star {
  color: #fbbf24;                                  /* filled gold */
  /* Render the filled glyph via content-replace so the OFF state is an
     outline star (☆ 9734) and ON is a solid star (★ 9733). */
}
button.who-am-i-mine.is-on .who-mine-star::before,
button.who-am-i-mine[aria-pressed="true"] .who-mine-star::before {
  content: "\2605";  /* ★ */
}
button.who-am-i-mine.is-on .who-mine-star,
button.who-am-i-mine[aria-pressed="true"] .who-mine-star {
  /* Hide the original outline char when replaced */
  font-size: 0;
}
button.who-am-i-mine.is-on .who-mine-star::before,
button.who-am-i-mine[aria-pressed="true"] .who-mine-star::before {
  font-size: 1rem; line-height: 1;
}

/* ---- Funnel ---- */
.funnel {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: .6rem;
  padding: 1.25rem;
}
.tile {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: .5rem .4rem; text-align: center; cursor: pointer;
  font: inherit; display: flex; flex-direction: column; gap: .05rem;
  transition: border-color .12s, transform .04s;
}
.tile[data-stage] { cursor: pointer; }
.tile:not([data-stage]) { cursor: default; opacity: .92; }
.tile:hover[data-stage] { border-color: var(--green); }
.tile:active[data-stage] { transform: translateY(1px); }
.tile.is-active { border-color: var(--green); background: var(--green-soft); }
.tile-count { font-size: 1.6rem; font-weight: 700; color: var(--green); line-height: 1; }
.tile-label { font-size: .74rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .03em; }
/* Chris 2026-05-25: zero-count tiles fade so the eye skips them while
   still preserving the grid (manager wants confirmation that the stage
   is checked, not just absence of a tile). */
.tile.is-zero { opacity: .42; }
.tile.is-zero .tile-count { color: var(--ink-faint); font-weight: 600; }
/* Stage-color tinting on the count number — same palette as the dt-pill
   colors elsewhere so the eye learns the language. Received/Counted use
   muted in-progress tones; Confirmed/Ready use the brand green. */
.tile[data-stage="received"]    .tile-count { color: #1d4e7a; }  /* blue */
.tile[data-stage="counted"]     .tile-count { color: #6b21a8; }  /* purple */
.tile[data-stage="confirmed"]   .tile-count { color: var(--green); }
.tile[data-stage="preparation"] .tile-count { color: #b45309; }  /* amber */
.tile[data-stage="ready"]       .tile-count { color: var(--green); }

/* ---- Panels ---- */
.panel { margin: 0 1.25rem 1.25rem; }
.panel h2 {
  font-size: .95rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-soft); margin: 0 0 .6rem; display: flex; align-items: center; gap: .5rem;
}
.count-pill {
  background: var(--green-soft); color: var(--green); font-size: .8rem;
  font-weight: 700; padding: .1rem .5rem; border-radius: 999px;
}
.count-sub { font-size: .78rem; color: var(--ink-faint); text-transform: none; letter-spacing: 0; font-weight: 400; }
.panel-scroll { overflow-x: auto; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.empty { color: var(--ink-faint); padding: 1rem 1.1rem; margin: 0; font-size: .9rem; }

/* ---- Order tables ---- */
table.orders { width: 100%; border-collapse: collapse; font-size: .88rem; }
table.orders th {
  text-align: left; font-size: .72rem; text-transform: uppercase; letter-spacing: .03em;
  color: var(--ink-faint); padding: .6rem .7rem; border-bottom: 1px solid var(--line); white-space: nowrap;
}
table.orders td { padding: .55rem .7rem; border-bottom: 1px solid var(--line); white-space: nowrap; }
table.orders tr:last-child td { border-bottom: none; }
table.orders .num { text-align: right; }
table.orders .mono { font-variant-numeric: tabular-nums; }
table.orders tbody tr.is-dim { opacity: .28; }

.fill-badge {
  font-size: .72rem; font-weight: 700; color: var(--flag);
  background: #fdf0e0; padding: .05rem .35rem; border-radius: 4px;
}

/* aging — Today panel only */
tr.aging-green  td { background: var(--aging-green); }
tr.aging-yellow td { background: var(--aging-yellow); box-shadow: inset 3px 0 0 var(--aging-yellow-bd); }
tr.aging-red    td { background: var(--aging-red);    box-shadow: inset 3px 0 0 var(--stall); }

/* payment terms badges */
.terms { font-size: .74rem; padding: .1rem .4rem; border-radius: 4px; background: #eef0ec; color: var(--ink-soft); }
.terms-cash  { background: var(--green-soft); color: var(--green); }
.terms-ar    { background: #fdf0e0; color: var(--flag); }
.terms-check { background: #e7eef5; color: #1d4e7a; }
.terms-none  { background: transparent; color: var(--ink-faint); }

/* No-show exception card — inline Reschedule action */
.exc-card .exc-actions { margin-top: .45rem; }
.exc-reschedule-btn {
  font: inherit; font-size: .78rem; font-weight: 600;
  padding: .28rem .65rem; border-radius: 5px;
  border: 1px solid var(--stall); color: var(--stall);
  background: #fff; cursor: pointer;
}
.exc-reschedule-btn:hover { background: var(--stall); color: #fff; }
.exc-reschedule-picker {
  display: flex; flex-direction: column; gap: .35rem; margin-top: .35rem;
}
.exc-reschedule-picker .picker-row {
  display: flex; gap: .4rem; align-items: center; flex-wrap: wrap;
}
.exc-reschedule-picker label {
  display: flex; flex-direction: column; gap: .15rem;
  font-size: .68rem; color: var(--ink-soft); text-transform: uppercase;
  letter-spacing: .03em; flex: 1; min-width: 7rem;
}
.exc-reschedule-picker input[type="date"],
.exc-reschedule-picker select {
  padding: .35rem .5rem; font: inherit; font-size: .85rem;
  border: 1px solid var(--green); border-radius: 4px; background: #fff;
  color: var(--ink); text-transform: none; letter-spacing: 0;
  font-weight: 400;
}
.exc-reschedule-picker .resched-save {
  font: inherit; font-size: .8rem; font-weight: 600;
  padding: .35rem .8rem; border-radius: 5px;
  border: 1px solid var(--green); background: var(--green); color: #fff;
  cursor: pointer;
}
.exc-reschedule-picker .resched-save:hover { background: #103f24; }
.exc-reschedule-picker .exc-cancel {
  font: inherit; font-size: .8rem; padding: .35rem .65rem;
  border-radius: 5px; border: 1px solid var(--line);
  background: #fff; cursor: pointer; color: var(--ink-soft);
}
.exc-card.is-saving { opacity: .6; }

/* ---- Exceptions strip ---- */
/* Chris 2026-05-25: bare all-caps red heading looked like a server
   error label. Wrap in a soft amber band with the ⚠ icon so it reads
   as intentional warning, not "the page is broken." */
.panel-exceptions h2 {
  display: inline-flex; align-items: center; gap: .4rem;
  color: #92400e; background: #fef3c7;
  border: 1px solid #fcd34d; border-radius: 6px;
  font-size: .85rem; text-transform: uppercase; letter-spacing: .06em;
  padding: .3rem .65rem; margin: 0 0 .55rem;
}
.exc-h-icon { font-size: .9rem; line-height: 1; }
/* Shown only while the overdue-banner tap has narrowed the strip to
   late/past-due cards; clears state.excFilter back to the full mix. */
.exc-filter-chip {
  border: 1px solid #fcd34d; background: #fff; color: #92400e;
  border-radius: 4px; font-size: .72rem; text-transform: none;
  letter-spacing: normal; padding: .15rem .5rem; cursor: pointer;
  margin-left: .25rem;
}
.exc-filter-chip:hover { background: #fef3c7; }
.exc-filter-chip[hidden] { display: none; }
/* Applied by applyExcRowFilter() in dashboard.js while the overdue-banner
   filter is active — hides non-past-due rows/sections in the main list
   (not the Exceptions strip, which re-renders instead of hiding). */
.is-hidden-by-excfilter { display: none; }
.exc-strip {
  display: flex; gap: .6rem; overflow-x: auto; padding: .25rem;
  background: var(--surface); border: 1px solid var(--aging-red-bd);
  border-left: 4px solid var(--stall); border-radius: var(--radius); box-shadow: var(--shadow);
}
.exc-card {
  flex: 0 0 auto; min-width: 11rem; background: var(--aging-red);
  border: 1px solid var(--aging-red-bd); border-radius: 8px; padding: .55rem .65rem;
}
/* Chris 2026-05-23 — exception cards leaned out:
   row 1 = [order#] [primary reason tag] [Reschedule btn], all inline
   row 2 = customer name (1 line) */
.exc-top {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: .35rem; margin-bottom: .25rem;
}
.exc-order { font-weight: 700; font-size: .85rem; font-variant-numeric: tabular-nums; text-decoration: none; }
.exc-cust { font-size: .8rem; color: var(--ink-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-decoration: none; display: block; }
.exc-order:hover, .exc-cust:hover { text-decoration: underline; }
.exc-top .exc-actions {
  margin-left: auto;       /* pin the button to the right of the top row */
  margin-top: 0;           /* override the default .exc-card .exc-actions { margin-top: .45rem } */
}
/* When the picker is open it needs the full width — let it wrap to a
   new visual row inside .exc-top so the date input + window select fit. */
.exc-top .exc-actions:has(.exc-reschedule-picker) {
  margin-left: 0; flex-basis: 100%;
}
.exc-top .exc-reschedule-btn,
.exc-top .exc-bumpdate-btn {
  /* Override the touch-target 44px min-height set elsewhere — exception
     cards are dense and the button can be smaller in this context. */
  min-height: 32px; padding: .35rem .6rem; font-size: .78rem;
}
.exc-stage {
  font-size: .72rem; color: var(--ink-faint); padding: .08rem .4rem;
  border: 1px solid var(--line); border-radius: 999px; background: #fff;
}
/* Exception tags — distinct color per reason so the strip is scannable.
   flag = amber (warning), stall = indigo (SLA breach), late = red (alarm),
   noshow = violet (different category: customer didn't show), restock =
   green (matches the RS badge shown beside the order in the list — same
   meaning, just surfaced as its own exception card). */
.tag { font-size: .68rem; font-weight: 700; padding: .12rem .45rem; border-radius: 999px;
       letter-spacing: .02em; text-transform: uppercase; white-space: nowrap; }
.tag-flag    { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
.tag-stall   { background: #e0e7ff; color: #3730a3; border: 1px solid #a5b4fc; }
.tag-late    { background: #fee2e2; color: #991b1b; border: 1px solid #fca5a5; }
.tag-noshow  { background: #ede9fe; color: #5b21b6; border: 1px solid #c4b5fd; }
.tag-restock { background: #dcfce7; color: #16a34a; border: 1px solid #86efac; }
.exc-strip .empty { white-space: normal; }

/* ---- Collapsible (Beyond) ---- */
.collapse-toggle {
  font: inherit; background: none; border: none; cursor: pointer; padding: 0;
  display: flex; align-items: center; gap: .5rem; color: inherit;
  text-transform: uppercase; letter-spacing: .04em; font-size: .95rem; font-weight: 700;
}
.chevron { transition: transform .15s; font-size: .8rem; color: var(--ink-faint); }
.panel-collapsible.collapsed .panel-scroll { display: none; }
.panel-collapsible:not(.collapsed) .chevron { transform: rotate(90deg); }

/* ---- Team activity ---- */
.team-cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: .8rem; }
.team-col {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: .8rem .9rem;
}
.team-col h3 {
  margin: 0 0 .5rem; font-size: .76rem; text-transform: uppercase;
  letter-spacing: .04em; color: var(--ink-faint);
}
.team-col ul { list-style: none; margin: 0; padding: 0; }
.team-col li { display: flex; justify-content: space-between; padding: .25rem 0; border-bottom: 1px solid var(--line); }
.team-col li:last-child { border-bottom: none; }
.team-col li.empty { color: var(--ink-faint); border: none; padding: .25rem 0; font-size: .85rem; }
.team-col .who { color: var(--ink); }
.team-col .cnt { font-weight: 700; color: var(--green); font-variant-numeric: tabular-nums; }

/* ---- Footer ----
   Chris 2026-05-25 P6: tuck the dev-shaped stall/past-due/refresh info
   behind a small "(i)" hover/tap. Floor manager doesn't need to see it
   on every page load; tap reveals via :hover (desktop) or :focus
   (mobile click on the trigger). */
.dash-foot {
  display: flex; align-items: center; gap: .75rem;
  padding: .35rem 1.25rem 1rem;
  color: var(--ink-faint); font-size: .78rem;
}
.dash-foot-info {
  position: relative; cursor: help;
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); border-radius: 999px;
  font-size: .7rem; font-weight: 700; color: var(--ink-soft);
  background: #fff;
}
.dash-foot-info-body {
  display: none; position: absolute; bottom: 100%; left: 0;
  background: #fff; border: 1px solid var(--line); border-radius: 6px;
  padding: .5rem .75rem; box-shadow: 0 4px 12px rgba(0,0,0,.08);
  white-space: nowrap; margin-bottom: .35rem; z-index: 5;
  font-size: .75rem; color: var(--ink-soft);
}
.dash-foot-info:hover .dash-foot-info-body,
.dash-foot-info:focus-within .dash-foot-info-body,
.dash-foot-info.is-open .dash-foot-info-body { display: block; }
.dash-foot-info-body span { display: block; line-height: 1.5; }
.team-empty {
  padding: .75rem 1.25rem; color: var(--ink-faint);
  font-size: .85rem; font-style: italic;
}

/* ---- Filter bar (v2 — restructured for clarity) ----
   Rows are stacked top-to-bottom: segment → view+date → group. Each row is
   its own flex line. Compact on mobile. */
.filter-bar {
  display: flex; flex-direction: column; gap: .5rem; align-items: stretch;
  padding: .6rem 1.25rem; border-bottom: 1px solid var(--line); background: #fff;
  position: sticky; top: 3.4rem; z-index: 9;
}
.filter-row {
  display: flex; flex-wrap: wrap; gap: .75rem; align-items: center;
}
.filter-row-view-date {
  justify-content: space-between;
}

/* Filter-bar redesign (2026-05-23 v2) — Chris: pull List+View+Group into
   one horizontal row at the top, Filters on its own row below. Section
   width matches the funnel cards (same horizontal padding). */
.filter-bar {
  display: flex;
  flex-direction: column;
  gap: .55rem;
  padding: .7rem 1rem;  /* matches .funnel mobile padding */
}
.filter-bar-top {
  display: grid;
  /* Chris 2026-05-25: 4 columns — List + View + Group + Date all on one line.
     Group column slightly wider so "By Status" doesn't truncate to "By Sta".
     Date column gets explicit fit-content so it doesn't squeeze view toggle. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1.2fr) auto;
  gap: .4rem;
  align-items: end;
}
/* Keep date chip on one line and the view toggle full-width (List | Map). */
.filter-bar-top .chip-date { white-space: nowrap; }
.filter-bar-top .view-toggle { width: max-content; }
/* Chris 2026-05-25 P17: in Map mode, List + Group dropdowns are
   redundant (map is implicitly delivery-only with no list grouping).
   Hide them; keep View toggle (so user can switch back) + Date filter. */
.dash[data-view="map"] .filter-pair:nth-child(1),
.dash[data-view="map"] .filter-pair:nth-child(3) { display: none; }
.dash[data-view="map"] .filter-bar-top { grid-template-columns: 1fr 1fr; }
/* Tighter dropdown padding on narrow phones so labels read cleanly.
   Caret column shrinks too — the SVG arrow only needs ~14px. */
@media (max-width: 480px) {
  .filter-bar-top .list-select,
  .filter-bar-top .group-select { padding: 0 1.15rem 0 .45rem; font-size: .8rem; background-position: right .35rem center; }
  /* Tighten View toggle + Date chip so dropdowns don't truncate. */
  .filter-bar-top .view-btn { padding: .25rem .5rem; font-size: .8rem; }
  .filter-bar-top .chip-date { padding: .45rem .55rem; font-size: .8rem; gap: .3rem; }
  .filter-bar-top .chip-icon { font-size: .8rem; }
}
/* Hide the sub-filter row entirely when none of its conditional chips
   are visible (all data-segment-only mismatched current segment). */
.dash:not([data-segment="shipping"]):not([data-segment="delivery"]) .filter-sub { display: none; }
.filter-pair {
  display: flex; flex-direction: column; gap: .25rem; min-width: 0;
}
.filter-pair .filter-row-label { font-size: .68rem; }
.filter-row { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.filter-row-label {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-soft); font-weight: 700; white-space: nowrap;
}
/* Chris 2026-05-25: visually hide LIST: / VIEW: / GROUP: / FILTERS:
   labels — they were eating ~40px of vertical space on mobile to label
   controls that already self-identify (segmented + dropdowns). Keep
   the text for screen readers (a11y). */
@media (max-width: 720px) {
  .filter-row-label, .filter-pair .filter-row-label {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
  }
}
.list-select, .group-select, .driver-filter-select {
  font: inherit; font-size: .9rem; font-weight: 600;
  /* Explicit height instead of min-height — iOS Safari ignores min-height
     on native <select> and forces its own intrinsic height, which made
     the dropdowns taller than the View toggle (Chris flagged this). */
  height: 44px; box-sizing: border-box;
  padding: 0 1.85rem 0 .65rem;   /* room for our own caret on the right */
  border: 1px solid var(--line); border-radius: 6px;
  color: var(--ink); cursor: pointer;
  /* Strip iOS Safari's chrome (rounded background, padding overrides,
     native caret) so our height + padding actually apply. */
  -webkit-appearance: none; appearance: none;
  background: #fff url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' stroke='%235e6660' stroke-width='1.5' fill='none' stroke-linecap='round'/></svg>") no-repeat right .7rem center;
  width: 100%; min-width: 0;
}
.driver-filter-select { font-size: .85rem; font-weight: 500; padding: .45rem .55rem; }
.view-toggle { display: flex; gap: .35rem; flex-shrink: 0; }
/* Match the .list-select / .group-select height (44px) inside the filter-
   bar-top grid. The .view-toggle's default 2px inner padding + 1px border
   + 44px inner button = 50px, which made it 6px taller than the selects
   and threw off the row alignment. Tighten here without losing the pill
   group's visual identity. */
.filter-bar-top .view-toggle { padding: 0; border: none; background: transparent; height: 44px; }
.filter-bar-top .view-btn { min-height: 44px; height: 44px; padding: .25rem .75rem; border: 1px solid var(--line); border-radius: 6px; }
.filter-bar-top .view-btn.is-active { border-color: var(--green); }
.filters-row { gap: .4rem; }
/* Hide segment-only chips/options when not in their segment.
   For <option> elements inside a <select> we need to hide via JS, not CSS,
   because option visibility is browser-quirky. But chip buttons in filters
   row still use the data-segment-only attribute hide rule. */
/* "All" segment is a quieter fallback — visually smaller than the three
   primary types so the eye lands on Will Call / Delivery / Shipping first. */
.team-btn-all {
  font-size: .72rem; opacity: .75;
}
.team-btn-all.is-active { opacity: 1; }
/* Date chip — gains a clear (×) button when a date is set. */
.chip-date { display: inline-flex; align-items: center; gap: .35rem; }
.chip-mine { display: inline-flex; align-items: center; gap: .3rem; }
.chip-mine.is-on { background: var(--green); color: #fff; border-color: var(--green); }
.chip-mine.is-on .chip-icon { color: #fbbf24; /* gold star on green */ }

/* "Mine" lives on its own slim row, right-aligned so it sits below the
   top filter bar without crowding it. Hides itself when Mine isn't in
   the DOM (i.e. counter/confirmer/closer — no edit_own_orders cap). */
.filter-row-personal {
  display: flex; justify-content: flex-end;
  padding: .15rem .9rem .35rem;
  margin: 0;
}
.filter-row-personal:empty { display: none; }
@media (max-width: 720px) {
  .filter-row-personal { padding: .1rem .65rem .35rem; }
}
.chip-date-clear {
  border: none; background: transparent; cursor: pointer;
  color: var(--ink-faint); font-size: 1.1rem; line-height: 1;
  /* Chris 2026-05-26: 44×44 min-* was correct for iOS HIG but inflated
     the chip width to ~120px and overflowed its grid column on shipping
     view. Compromise: visual is small (~28×28), the chip's own padding
     gives it a generous tap area, and the X sits inside it. Touch zone
     is still well above the 30px common-sense minimum. */
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  position: relative; z-index: 2;
  border-radius: 4px;
}
.chip-date-clear:hover { background: rgba(0,0,0,.05); color: var(--ink); }
/* Chris 2026-05-25: in route-planning modes (Map view OR By Driver
   group) the date filter is MANDATORY — without it, users were
   accidentally routing orders from different days into one truck.
   Hide the X clear button (user can still CHANGE the date, just not
   nullify it). */
.dash[data-view="map"] .chip-date-clear,
.dash[data-by-driver="1"] .chip-date-clear { display: none; }
/* Chris 2026-05-25: when grouping By Date, the per-date filter is
   redundant (each order is already bucketed by its date). Hide the
   whole chip — JS clears state.date_filter BEFORE this CSS hides it
   so the snapshot fetch doesn't keep filtering on a stale value. */
.dash[data-by-date="1"] .chip-date { display: none; }
/* Chris 2026-05-25: on segment=All the date filter is also moot — All
   is browse/find mode across mixed types where the per-day cut doesn't
   carry consistent meaning (Will Call day ≠ Delivery day ≠ Ship day).
   Hidden in this mode so search becomes the primary navigation aid. */
.dash[data-segment="all"] .chip-date { display: none; }

/* iOS Safari auto-zooms on focus when an input's font-size is <16px.
   Standard fix: force ≥16px (1rem) on every text-like input on mobile.
   Covers .order-search-input, .roster-search, all inline editors,
   roster Add/Edit form, etc. — single rule prevents future regressions.
   Chris 2026-05-25: don't zoom on search focus. */
@media (max-width: 720px) {
  input[type="text"], input[type="search"], input[type="email"],
  input[type="tel"],  input[type="number"], input[type="url"],
  input[type="password"], input[type="date"], input[type="datetime-local"],
  input[type="time"], input[type="month"], input[type="week"],
  textarea, select {
    font-size: 16px;
  }
}

/* Client-side search bar above the status groups. Only visible on
   segment=All — that's the browse/find context (Chris 2026-05-25).
   Other segments already scope down via status/group/date controls. */
.order-search-bar { display: none; }
.dash[data-segment="all"] .order-search-bar {
  display: flex; align-items: center; gap: .5rem;
  margin: 0 1rem .75rem;
  padding: .55rem .75rem;
  background: #fff; border: 1px solid var(--line); border-radius: 8px;
  box-shadow: var(--shadow);
}
.order-search-input {
  flex: 1; font: inherit; font-size: 1rem;  /* 16px — iOS zoom-on-focus threshold */
  padding: .35rem .5rem;
  border: none; background: transparent;
}
.order-search-input:focus { outline: none; }
.order-search-count {
  font-size: .75rem; color: var(--ink-soft); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.order-search-clear {
  background: transparent; border: none; cursor: pointer;
  font-size: 1.1rem; line-height: 1; color: var(--ink-faint);
  min-width: 32px; min-height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 6px;
}
.order-search-clear:hover { background: rgba(0,0,0,.05); color: var(--ink); }
/* Hide matched-out rows in the status groups when a filter is active. */
.dash[data-search-active] .status-group tbody tr.is-search-hidden { display: none; }
.dash[data-search-active] .status-group.is-search-empty { display: none; }
@media (max-width: 480px) {
  .order-search-bar { margin: 0 .75rem .65rem; padding: .45rem .55rem; }
  /* Keep input at 16px — anything smaller triggers iOS zoom-on-focus. */
}
.chip-date-clear:hover { color: var(--stall); }
/* On mobile the dash-header wraps to ~2 rows, so its real height exceeds
   3.4rem and the sticky filter-bar locks under it. Drop sticky for small
   screens — content scrolls cleanly past both bars. */
@media (max-width: 720px) {
  .dash-header { position: static; }
  .filter-bar  { position: static; top: auto; padding: .55rem .9rem; gap: .45rem; }
  .team-bar    { gap: .3rem; }
}
.segmented {
  display: inline-flex; background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden; padding: 2px;
}
.seg {
  font: inherit; font-size: .82rem; padding: .35rem .75rem;
  background: transparent; border: none; cursor: pointer; color: var(--ink-soft);
  border-radius: 7px; display: inline-flex; align-items: center; gap: .4rem;
}
.seg:hover { color: var(--ink); }
.seg.is-active { background: var(--green); color: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.08); }
.seg-count {
  font-size: .7rem; padding: .04rem .35rem; border-radius: 999px;
  background: rgba(0,0,0,.06);
}
.seg.is-active .seg-count { background: rgba(255,255,255,.22); }

.chips { display: inline-flex; gap: .4rem; }
.chip {
  font: inherit; font-size: .78rem; padding: .3rem .65rem;
  background: var(--bg); border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer; color: var(--ink-soft); display: inline-flex; align-items: center; gap: .35rem;
}
.chip:hover { border-color: var(--green); color: var(--ink); }
.chip.is-on { background: var(--green-soft); border-color: var(--green); color: var(--green); }
.chip-dot { width: .55rem; height: .55rem; border-radius: 50%; background: #2563eb; display: inline-block; }
/* Blue Tag chip — bold blue when on, so the "selected" state is unmistakable
   on the floor. Was a subtle #e7eef5 wash; Chris flagged it as too soft. */
.chip[data-chip="blue_tag"].is-on { background: #1d4e7a; border-color: #1d4e7a; color: #fff; }
.chip[data-chip="blue_tag"].is-on .chip-dot { background: #fff; }

.grouping {
  display: inline-flex; align-items: center; gap: .35rem;
  margin-left: auto;
}
.grouping[hidden] { display: none; }
.grouping-label { font-size: .78rem; color: var(--ink-faint); }
.grp {
  font: inherit; font-size: .78rem; padding: .3rem .55rem;
  background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer; color: var(--ink-soft);
}
.grp:hover { border-color: var(--green); }
.grp.is-on { background: var(--green); color: #fff; border-color: var(--green); }

/* ---- v2: View toggle (List | Map) ---- */
.view-toggle {
  display: inline-flex; background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden; padding: 2px;
}
.view-btn {
  font: inherit; font-size: .82rem; padding: .35rem .75rem;
  background: transparent; border: none; cursor: pointer; color: var(--ink-soft);
  border-radius: 7px; display: inline-flex; align-items: center; gap: .4rem;
}
.view-btn:hover:not([disabled]):not(.is-active) { color: var(--ink); }
.view-btn.is-active { background: var(--green); color: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.08); }
.view-btn[disabled] { opacity: .5; cursor: not-allowed; }
/* Map view is delivery-only — routes/geocoded stops are meaningless for
   Will Call (in-store pickup) or Shipping (carrier). Hide the toggle for
   anything except the Delivery segment. */
.dash:not([data-segment="delivery"]) .view-btn[data-delivery-only="1"] { display: none; }

/* ---- v2: Team bar ---- */
.team-bar { display: inline-flex; flex-wrap: wrap; gap: .35rem; }
.team-bar[hidden] { display: none !important; }
/* Any element with the `hidden` attribute should be invisible regardless of
   per-class display overrides. */
[hidden] { display: none !important; }
.team-btn {
  font: inherit; font-size: .82rem; padding: .35rem .7rem;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  cursor: pointer; color: var(--ink-soft);
  display: inline-flex; align-items: center; gap: .4rem;
}
.team-btn:hover { border-color: var(--green); color: var(--ink); }
.team-btn.is-active { background: var(--green); color: #fff; border-color: var(--green); }
.team-count {
  font-size: .7rem; padding: .04rem .35rem; border-radius: 999px;
  background: rgba(0,0,0,.06); font-variant-numeric: tabular-nums;
}
.team-btn.is-active .team-count { background: rgba(255,255,255,.22); }
.team-btn[data-team="blue_tags"].is-active { background: #1d4e7a; border-color: #1d4e7a; }
.team-btn[data-team="loading"].is-active { background: #b45309; border-color: #b45309; }

/* ---- v2: View targets (visibility driven by .dash[data-view] + .dash[data-team]) ---- */
[data-view-target] { display: none; }
.dash[data-view="list"] [data-view-target="list"],
.dash[data-view="map"]  [data-view-target="map"] { display: block; }
.dash [data-view-target] .empty {
  padding: 2rem 1.25rem; color: var(--ink-faint); text-align: center;
}

/* Within the list view, the active grouping mode picks which sub-view
   renders. data-mode is set on .dash and updated by JS on any chip toggle.
   modes: status (default) | driver | county | window. */
.dash[data-view="list"] .status-view,
.dash[data-view="list"] .driver-view,
.dash[data-view="list"] .county-view,
.dash[data-view="list"] .window-view,
.dash[data-view="list"] .shipper-view,
.dash[data-view="list"] .date-view { display: none; }
.dash[data-view="list"][data-mode="status"]  .status-view  { display: block; }
.dash[data-view="list"][data-mode="driver"]  .driver-view  { display: block; }
.dash[data-view="list"][data-mode="county"]  .county-view  { display: block; }
.dash[data-view="list"][data-mode="window"]  .window-view  { display: block; }
.dash[data-view="list"][data-mode="shipper"] .shipper-view { display: block; }
.dash[data-view="list"][data-mode="date"]    .date-view    { display: block; }
/* Segment-only group-by chips — hide for non-matching segments so the chip
   row collapses to only what's actionable for the active type. */
.dash:not([data-segment="delivery"]) [data-segment-only="delivery"] { display: none; }
.dash:not([data-segment="willcall"]) [data-segment-only="willcall"] { display: none; }
.dash:not([data-segment="shipping"]) [data-segment-only="shipping"] { display: none; }
/* Date-group: past-due dates get a subtle red accent so they read as urgent. */
.date-group.date-group-past > .driver-group-head { background: var(--aging-red); }
.date-group.date-group-past .driver-group-label { color: var(--stall); font-weight: 700; }

/* ---- v2: Driver-grouped (Driver view) — assignment surface for routes ---- */
.driver-view { padding: 0 1.25rem 1rem; }
.driver-group {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); margin: 0 0 .75rem; overflow: hidden;
}
.driver-group-unassigned { border-color: var(--aging-yellow-bd); }
.driver-group-unassigned .driver-group-head { background: var(--aging-yellow); }
.driver-group-head {
  display: flex; align-items: center; gap: .5rem;
  padding: 0; background: var(--bg); border-bottom: 1px solid var(--line);
  flex-wrap: wrap;  /* lets the bulk-editor row drop below the toggle when open */
}
/* F9 — bulk-edit affordance + editor for By Driver group headers. */
.driver-group-bulk-btn {
  font: inherit; font-size: 1rem; line-height: 1;
  padding: .35rem .6rem; min-height: 44px; min-width: 44px;
  margin-right: .35rem;
  border: 1px solid var(--line); background: #fff; color: var(--ink-soft);
  border-radius: 6px; cursor: pointer;
}
.driver-group-bulk-btn:hover { border-color: var(--green); color: var(--green); }
.driver-group-bulk-editor {
  flex: 1 1 100%;
  padding: .55rem .85rem; background: #fff; border-top: 1px dashed var(--line);
}
.bulk-editor-body {
  display: flex; flex-wrap: wrap; align-items: center; gap: .55rem;
}
.bulk-editor-field {
  display: inline-flex; align-items: center; gap: .35rem;
  font-size: .82rem; color: var(--ink-soft);
}
.bulk-editor-field select {
  font: inherit; font-size: .9rem;
  padding: .45rem .6rem; min-height: 44px;
  border: 1px solid var(--line); border-radius: 5px; background: #fff;
}
.bulk-editor-apply, .bulk-editor-cancel {
  font: inherit; font-size: .85rem; font-weight: 600;
  padding: .55rem .9rem; min-height: 44px;
  border-radius: 5px; cursor: pointer;
}
.bulk-editor-apply {
  background: var(--green); color: #fff; border: 1px solid var(--green);
}
.bulk-editor-apply:hover { filter: brightness(0.92); }
.bulk-editor-apply:disabled { opacity: .55; cursor: wait; }
.bulk-editor-cancel {
  background: #fff; color: var(--ink-soft); border: 1px solid var(--line);
}
.bulk-editor-status {
  font-size: .82rem; color: var(--ink-soft); margin-left: .25rem;
}
.driver-group-toggle {
  flex: 1; display: flex; align-items: center; gap: .55rem;
  font: inherit; padding: .6rem .85rem; background: transparent;
  border: none; cursor: pointer; text-align: left; color: var(--ink);
}
.driver-group-toggle:hover { background: rgba(0,0,0,.02); }
.driver-group-toggle .chevron {
  display: inline-block; font-size: .8rem; color: var(--ink-faint);
  transition: transform .15s ease;
}
.driver-group.is-collapsed .driver-group-toggle .chevron { transform: rotate(-90deg); }
.driver-group.is-collapsed .driver-group-body { display: none; }
.driver-group-label { font-weight: 700; font-size: .92rem; }
.driver-group-count {
  margin-left: auto; font-size: .78rem; font-variant-numeric: tabular-nums;
  padding: .08rem .45rem; border-radius: 999px;
  background: var(--green-soft); color: var(--green);
}
.driver-group-unassigned .driver-group-count {
  background: rgba(180,83,9,.18); color: var(--flag);
}
.orders-driver { table-layout: fixed; width: 100%; }
.orders-driver td.post-no, .orders-driver th.post-no {
  width: 4rem; text-align: right;
}
.orders-driver .post-no-num {
  font-weight: 700; font-size: 1rem; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.orders-driver td, .orders-driver th {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.orders-driver td.num, .orders-driver th.num { width: 4rem; }

/* Status table — also fixed layout so segment-aware columns align across
   each status group's separate <table> element. */
.orders-compact { table-layout: fixed; width: 100%; }
.orders-compact td, .orders-compact th {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.orders-compact td.num, .orders-compact th.num { width: 5.5rem; }
.orders-compact td.post-col, .orders-compact th.post-col { width: 5rem; text-align: center; }
/* Explicit widths on the short/predictable columns so customer (the only
   genuinely variable-length field) absorbs the remaining width instead of
   table-layout:fixed splitting it evenly and leaving big gaps around Due/Post/Type.
   Order needs the extra room for the BT/RS/fill-% badges that can trail the
   order number. */
.orders-compact td.order-col, .orders-compact th.order-col { width: 13rem; }
.orders-compact td.due-col, .orders-compact th.due-col { width: 6rem; }
.orders-compact td.type-col, .orders-compact th.type-col { width: 9rem; }
/* Line-items card has only 3 columns — give Total more room so values like $1,234.50 don't clip */
.card[data-card="items"] .orders-compact td.num,
.card[data-card="items"] .orders-compact th.num { width: 7rem; }

/* Inline row-edit affordance */
.row-edit.is-editable {
  cursor: pointer; position: relative;
}
.row-edit.is-editable:hover {
  background: rgba(20,83,45,.06);
  outline: 1px dashed rgba(20,83,45,.3);
}
.row-edit.is-editing { background: #fff; }
.row-edit.is-editing .cell-input {
  display: inline-block; vertical-align: middle; margin-right: .25rem;
  min-width: 0; max-width: 100%;
}
.row-edit .cell-saving {
  display: inline-block; width: .8rem; height: .8rem;
  border: 2px solid rgba(20,83,45,.25); border-top-color: var(--green);
  border-radius: 50%; vertical-align: middle;
  animation: spin .7s linear infinite;
}

/* Inline companion-field picker — appears when user changes Ship via to
   Shipping/Will Call but the required carrier/window isn't set yet. The
   picker holds the new type + the companion field together, so save is one
   atomic POST. */
.companion-prompt {
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem;
  padding: .35rem .5rem; border: 1px solid var(--green);
  border-radius: 6px; background: var(--green-soft);
  font-size: .85rem;
}
.companion-prompt-type {
  font-weight: 700; color: var(--green); padding: .1rem .45rem;
  background: #fff; border-radius: 4px;
}
.companion-prompt-label {
  display: inline-flex; align-items: center; gap: .25rem;
  font-size: .82rem; color: var(--ink-soft);
}
.companion-prompt-select, .companion-prompt-input {
  font: inherit; font-size: .85rem; padding: .25rem .4rem;
  border: 1px solid var(--line); border-radius: 4px;
}
.companion-prompt-input { width: 7rem; }
.companion-prompt-save {
  font: inherit; font-size: .78rem; padding: .25rem .65rem;
  background: var(--green); color: #fff; border: none; border-radius: 4px;
  cursor: pointer; font-weight: 600;
}
.companion-prompt-cancel {
  font: inherit; font-size: .78rem; padding: .25rem .55rem;
  background: #fff; border: 1px solid var(--line); border-radius: 4px;
  cursor: pointer; color: var(--ink-soft);
}
.companion-prompt-hint {
  flex-basis: 100%; font-size: .72rem; color: var(--ink-faint);
}
.row-edit.cell-saved-ok { background: rgba(20,83,45,.12); transition: background .25s; }
.row-edit.cell-saved-err { background: rgba(185,28,28,.12); }

/* ---- v2: Status-grouped list ---- */
.status-view { padding: 0 1.25rem 1rem; }
.status-group {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); margin: 0 0 .75rem; overflow: hidden;
}
.status-group.is-empty { opacity: .72; }  /* was .55 — bumped 2026-05-22; .55 dropped the section-label below WCAG AA (3.7:1). At .72 stays visually deemphasized but text stays readable (~4.7:1). */
.status-group.is-empty .status-group-head { padding: .5rem .85rem; }
.status-group-head {
  display: flex; align-items: center; gap: .5rem;
  padding: 0; background: var(--bg); border-bottom: 1px solid var(--line);
}
.status-group.is-empty .status-group-head { border-bottom: none; background: transparent; }
.status-group-toggle {
  flex: 1; display: flex; align-items: center; gap: .55rem;
  font: inherit; padding: .6rem .85rem; background: transparent;
  border: none; cursor: pointer; text-align: left; color: var(--ink);
}
.status-group-toggle:hover { background: rgba(0,0,0,.02); }
.status-group-toggle .chevron {
  display: inline-block; font-size: .8rem; color: var(--ink-faint);
  transition: transform .15s ease;
}
.status-group.is-collapsed .status-group-toggle .chevron { transform: rotate(-90deg); }
.status-group.is-collapsed .status-group-body { display: none; }
.status-group-label { font-weight: 700; font-size: .92rem; }
.status-group-count {
  margin-left: auto; font-size: .78rem; font-variant-numeric: tabular-nums;
  padding: .08rem .45rem; border-radius: 999px;
  background: var(--green-soft); color: var(--green);
}
.status-group.is-empty .status-group-count {
  background: rgba(0,0,0,.04); color: var(--ink-faint);
}
/* Chris 2026-05-25: stage-color tint on the group count chip, same
   palette as the status tiles above. Helps the eye anchor when
   scrolling through long Received → Counted → Confirmed sections. */
.status-group[data-status-group="received"]    .status-group-count { background: #e6eef5; color: #1d4e7a; }
.status-group[data-status-group="counted"]     .status-group-count { background: #f1e8f8; color: #6b21a8; }
.status-group[data-status-group="preparation"] .status-group-count { background: #fdf0e0; color: #b45309; }
/* confirmed + ready keep the brand-green default; completed uses muted */
.status-group[data-status-group="completed"]   .status-group-count { background: rgba(0,0,0,.04); color: var(--ink-faint); }

/* compact orders table inside a status group */
.orders-compact { width: 100%; border-collapse: collapse; font-size: .88rem; }
.orders-compact thead th {
  text-align: left; font-size: .72rem; text-transform: uppercase;
  letter-spacing: .04em; color: var(--ink-faint); font-weight: 600;
  padding: .45rem .85rem; border-bottom: 1px solid var(--line); background: #fff;
}
.orders-compact thead th.num { text-align: right; }
.orders-compact tbody td {
  padding: .5rem .85rem; border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.orders-compact tbody tr:last-child td { border-bottom: none; }
.orders-compact tbody tr:hover td { background: var(--bg); }
.orders-compact td.mono { font-variant-numeric: tabular-nums; }
.orders-compact td.num { text-align: right; font-variant-numeric: tabular-nums; }
.orders-compact td a { color: var(--green); text-decoration: none; font-weight: 600; }
.orders-compact td a:hover { text-decoration: underline; }
.orders-compact .fill-badge {
  display: inline-block; font-size: .68rem; padding: .04rem .3rem;
  border-radius: 999px; background: rgba(180,83,9,.12); color: var(--flag);
  margin-left: .35rem; font-weight: 600;
}
.orders-compact .blue-tag,
.orders-compact .restock-tag {
  display: inline-block; font-size: .65rem; padding: .04rem .3rem;
  border-radius: 999px; color: #fff;
  margin-left: .25rem; font-weight: 700; letter-spacing: .03em;
}
.orders-compact .blue-tag    { background: #1d4e7a; }
.orders-compact .restock-tag { background: #16a34a; }
.orders-compact .dt-pill {
  display: inline-flex; align-items: center; gap: .25rem;
  font-size: .7rem; padding: .08rem .5rem;
  border-radius: 999px;
}
/* Chris 2026-05-25: on mobile compress to colored-dot + 1-letter code
   (D / S / W) — saves row width and the color carries the meaning
   anyway. aria-label preserves "Delivery" etc for screen readers. */
@media (max-width: 720px) {
  .orders-compact .dt-pill {
    font-size: 0;  /* hide the long text */
    padding: .15rem .35rem;
  }
  .orders-compact .dt-pill[data-short]::before {
    content: attr(data-short);
    font-size: .68rem; font-weight: 700;
    letter-spacing: .02em;
  }
}
/* Chris 2026-05-25: per-type colors scoped to .orders-compact were
   inverted vs the global .dt-pill rules (list said delivery=amber while
   detail said delivery=green). Drop the list overrides so all surfaces
   share the same color per type — green=delivery, blue=willcall,
   amber=shipping. Defined globally below. */

@media (max-width: 720px) {
  /* ---- Mobile: shared status table (Order / Customer / Due / Type|Driver|Window|Shipper / Total) ----
     Two-column dense card. Order # + total on row 1; customer on row 2;
     LEAN layout (Chris 2026-05-23): two lines per row.
       Row 1: [order#] [due] [type/window/shipper] [route?]   [$total]
       Row 2: customer name (full width, ellipsis on overflow)
     Uses flex with `order:` to place cells regardless of segment-specific
     column count (5 cells for willcall/all/shipping, 6 for delivery). */
  .orders-compact thead { display: none; }
  .orders-compact tbody tr {
    display: flex; flex-wrap: wrap; align-items: baseline;
    column-gap: .5rem; row-gap: .15rem;
    padding: .5rem .85rem;
    border-bottom: 1px solid var(--line);
  }
  .orders-compact tbody tr:last-child { border-bottom: none; }
  .orders-compact tbody td {
    padding: 0; border: none; white-space: normal;
    overflow: visible; text-overflow: clip;
  }
  /* col1 order# — `display: contents` so the anchor + fill-badge + blue-tag
     become direct flex items of the row instead of being trapped in one cell
     (which bloated the cell width and pushed $total to wrap onto a 1.5 row).
     Anchor stays on row 1 left; badges (fill % + BT) sit absolute-right on
     row 2 next to customer. Keeps row 1 uniformly: [#order] [date] [type] [$total]. */
  .orders-compact tbody tr { position: relative; }
  /* Columns are targeted by data-col (set in dashboard.js renderStatusRow)
     rather than nth-child position — segments have different column counts
     (willcall/all/shipping vs delivery, plus the post column), so position
     indexes drift; name-based selectors don't. */
  .orders-compact tbody td[data-col="order"] { display: contents; }
  .orders-compact tbody td[data-col="order"] a {
    order: 1; font-weight: 600; font-size: .95rem;
  }
  .orders-compact tbody td[data-col="order"] .fill-badge,
  .orders-compact tbody td[data-col="order"] .blue-tag,
  .orders-compact tbody td[data-col="order"] .restock-tag {
    /* Absolutely position to the bottom-right of the row so they don't
       affect the flex flow of row 1 (date/type/total alignment). */
    position: absolute; bottom: .5rem; font-size: .68rem;
    margin: 0;
  }
  .orders-compact tbody td[data-col="order"] .restock-tag { right: .85rem; }
  .orders-compact tbody td[data-col="order"] .blue-tag    { right: 2.6rem; }
  .orders-compact tbody td[data-col="order"] .fill-badge  { right: 4.35rem; }
  /* Pad the customer cell on the right so its text doesn't run under the
     absolute-positioned badges. */
  .orders-compact tbody td[data-col="customer"] { padding-right: 4rem; }
  /* due (date) */
  .orders-compact tbody td[data-col="due"] { order: 2; font-size: .78rem; color: var(--ink-soft); }
  /* post — warehouse post/location number; hidden entirely when blank or 'A' (see dashboard.js) */
  .orders-compact tbody td[data-col="post"] { order: 3; font-size: .76rem; color: var(--ink-faint); }
  .orders-compact tbody td[data-col="post"]:empty { display: none; }
  /* type/driver/window/shipper */
  .orders-compact tbody td[data-col="type"],
  .orders-compact tbody td[data-col="driver"],
  .orders-compact tbody td[data-col="window"],
  .orders-compact tbody td[data-col="shipper"] { order: 4; font-size: .76rem; color: var(--ink-faint); }
  /* route — delivery segment only */
  .orders-compact tbody td[data-col="route"] { order: 5; font-size: .76rem; color: var(--ink-faint); }
  /* Total = last cell — pinned to right */
  .orders-compact tbody td:last-child {
    order: 6; margin-left: auto;
    font-weight: 600; font-size: .9rem; font-variant-numeric: tabular-nums;
  }
  /* customer — full-width second row */
  .orders-compact tbody td[data-col="customer"] {
    order: 7; flex: 0 0 100%;
    font-size: .82rem; color: var(--ink-soft);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    min-width: 0;
  }
  /* city — Delivery segment only (Chris 2026-05-23). Sits on its own row
     under customer in faint type so it doesn't fight row 1's editable cluster
     (date / driver / route / $total). Empty cells are hidden so the row
     collapses to 2 lines instead of leaving an em-dash gap. */
  .orders-compact tbody td.city-cell {
    order: 8; flex: 0 0 100%;
    font-size: .76rem; color: var(--ink-faint);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    min-width: 0;
  }
  .orders-compact tbody td.city-cell:has(.ro-dash) { display: none; }

  /* ---- Mobile: Driver-grouped table (Post# / Order / Customer / City / Route / Qty) ----
     Scoped via :has(td.post-no) so it only fires on the actual driver table
     — county uses the same row shape, so it shares. Window/Shipper tables
     reuse .orders-driver but have DIFFERENT column counts; the generic
     .orders-compact block above handles them safely. */
  /* Legacy orders-driver layout removed 2026-05-23 — superseded by the
     spreadsheet-feel rule at the bottom of this @media block. */

  /* ---- Mobile: Line-items table (Item / Qty / Total) ----
     3-col layout — the generic .orders-compact rules above were designed for
     the 5-6 col list tables and end up stacking Qty + Total in column 1.
     Override so Item takes the whole left col, Qty + Total stack on the right. */
  .card[data-card="items"] .orders-compact tbody tr {
    grid-template-columns: 1fr auto;
    gap: .1rem .75rem;
    padding: .6rem .85rem;
  }
  .card[data-card="items"] .orders-compact tbody td:nth-child(1) {
    grid-column: 1; grid-row: 1 / span 2;
    color: var(--ink); font-weight: inherit; font-size: inherit;
  }
  .card[data-card="items"] .orders-compact tbody td:nth-child(2) {
    grid-column: 2; grid-row: 1; text-align: right;
    font-weight: 600; color: var(--ink); font-size: .9rem;
    font-variant-numeric: tabular-nums;
  }
  .card[data-card="items"] .orders-compact tbody td:nth-child(2)::after {
    content: ' qty'; font-size: .68rem; color: var(--ink-faint); opacity: .8; font-weight: 400;
  }
  .card[data-card="items"] .orders-compact tbody td:nth-child(3) {
    grid-column: 2; grid-row: 2; text-align: right;
    font-weight: 600; color: var(--ink); font-size: .9rem;
    font-variant-numeric: tabular-nums;
  }
}

/* ---- Past-due band ---- */
.late-band {
  margin: 0 1.25rem 1.25rem; background: var(--aging-red);
  border: 1px solid var(--aging-red-bd); border-left: 4px solid var(--stall);
  border-radius: var(--radius); padding: .65rem .85rem;
}
.late-band-head {
  display: flex; align-items: baseline; gap: .55rem;
  margin-bottom: .55rem; color: var(--stall);
}
.late-band-head strong { font-size: 1rem; }
.late-icon { font-size: 1.1rem; }
.late-band-sub { color: var(--ink-soft); font-size: .8rem; }
.late-strip { display: flex; gap: .55rem; overflow-x: auto; }
.late-card {
  flex: 0 0 auto; min-width: 12rem; background: #fff;
  border: 1px solid var(--aging-red-bd); border-radius: 8px;
  padding: .5rem .65rem;
}
.late-top { display: flex; flex-direction: column; gap: .1rem; margin-bottom: .35rem; }
.late-order { font-weight: 700; font-size: .85rem; font-variant-numeric: tabular-nums; }
.late-cust { font-size: .78rem; color: var(--ink-soft); }
.late-meta { display: flex; align-items: center; gap: .4rem; font-size: .72rem; }
.late-stage { color: var(--ink-faint); }

/* ---- Group headers (per-panel grouping toggle) ---- */
.group { border-bottom: 1px solid var(--line); }
.group:last-child { border-bottom: none; }
.group-head {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: .55rem .85rem; background: var(--bg);
  border-bottom: 1px solid var(--line); color: var(--ink-soft);
}
.group-key { font-weight: 700; font-size: .9rem; color: var(--ink); }
.group-stats { font-size: .78rem; }
.group .orders { border-radius: 0; box-shadow: none; }

/* ---- Print button (per-panel manifest) ---- */
.print-btn {
  margin-left: auto; font: inherit; font-size: .72rem;
  background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
  padding: .2rem .55rem; cursor: pointer; color: var(--ink-soft);
}
.print-btn:hover { border-color: var(--green); color: var(--green); }
.panel h2 { flex-wrap: wrap; }

/* ---- Delivery-type pills + Blue-tag badge ---- */
.dt-pill {
  font-size: .68rem; font-weight: 700; padding: .05rem .4rem;
  border-radius: 4px; text-transform: uppercase; letter-spacing: .03em;
  vertical-align: middle; margin-left: .35rem;
}
.dt-willcall        { background: #e7eef5; color: #1d4e7a; }
.dt-shipping        { background: #fdf0e0; color: var(--flag); }
.dt-delivery        { background: var(--green-soft); color: var(--green); }
.dt-add_to_existing { background: #f0eaf8; color: #6b35a8; }

.blue-tag {
  display: inline-block; font-size: .65rem; font-weight: 700;
  background: #1d4e7a; color: #fff; padding: .05rem .35rem; border-radius: 3px;
  letter-spacing: .04em; margin-left: .3rem; vertical-align: middle;
}
tr.has-blue-tag .blue-tag { box-shadow: 0 0 0 1px rgba(29,78,122,.4); }
.restock-tag {
  display: inline-block; font-size: .65rem; font-weight: 700;
  background: #16a34a; color: #fff; padding: .05rem .35rem; border-radius: 3px;
  letter-spacing: .04em; margin-left: .3rem; vertical-align: middle;
}

/* ---- Exception card backgrounds — primary-reason tint on the strip card ---- */
.exc-card.exc-flag   { background: #fef3c7; border-color: #fcd34d; }
.exc-card.exc-flag   .exc-order { color: #92400e; }
.exc-card.exc-stall  { background: #e0e7ff; border-color: #a5b4fc; }
.exc-card.exc-stall  .exc-order { color: #3730a3; }
.exc-card.exc-late   { background: #fee2e2; border-color: #fca5a5; }
.exc-card.exc-late   .exc-order { color: #991b1b; }
.exc-card.exc-noshow { background: #ede9fe; border-color: #c4b5fd; }
.exc-card.exc-noshow .exc-order { color: #5b21b6; }
.exc-card.exc-restock { background: #dcfce7; border-color: #86efac; }
.exc-card.exc-restock .exc-order { color: #16a34a; }

/* ---- Staleness escalation for overdue exception cards. Late cards
   already get the red wash; these classes layer a left-border
   indicator that gets thicker + redder as the order sits unresolved. */
.exc-card.late-staleness-fresh { box-shadow: inset 4px 0 0 0 #fbbf24; }    /* today, yellow */
.exc-card.late-staleness-warm  { box-shadow: inset 4px 0 0 0 #f97316; }    /* 1-2 days, orange */
.exc-card.late-staleness-cold  { box-shadow: inset 4px 0 0 0 #b91c1c;
                                  animation: cgh-overdue-pulse 2.4s ease-in-out infinite; }  /* >2 days */
@keyframes cgh-overdue-pulse {
  0%,100% { box-shadow: inset 4px 0 0 0 #b91c1c, 0 0 0 0 rgba(185,28,28,0); }
  50%     { box-shadow: inset 4px 0 0 0 #b91c1c, 0 0 0 6px rgba(185,28,28,.22); }
}
@media (prefers-reduced-motion: reduce) {
  .exc-card.late-staleness-cold { animation: none; }
}

/* ---- Sticky overdue banner — appears under the header when the
   viewer has past-due orders they own. Click → scrolls to exceptions
   panel. JS toggles [hidden] + writes the count into [data-overdue-banner-text]. */
.overdue-banner {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex; align-items: center; gap: .55rem;
  margin: 0 0 .8rem;
  padding: .65rem .9rem;
  background: linear-gradient(180deg, #fee2e2 0%, #fecaca 100%);
  border: 1px solid #f87171;
  border-radius: 0 0 8px 8px;
  color: #7f1d1d;
  font-weight: 600;
  font-size: .92rem;
  cursor: pointer;
  box-shadow: 0 2px 6px rgba(127,29,29,.18);
  /* Subtle pulse so it doesn't blend into the page. Only animates on
     first appearance — JS removes the class after the user has seen it. */
  animation: cgh-overdue-banner-pulse 1.2s ease-in-out 2;
}
.overdue-banner[hidden] { display: none; }
.overdue-banner-icon { font-size: 1.1rem; line-height: 1; }
.overdue-banner-text { flex: 1; }
.overdue-banner-cta { font-weight: 500; opacity: .8; }
@keyframes cgh-overdue-banner-pulse {
  0%,100% { background: linear-gradient(180deg, #fee2e2 0%, #fecaca 100%); }
  50%     { background: linear-gradient(180deg, #fecaca 0%, #fca5a5 100%); }
}
@media (prefers-reduced-motion: reduce) {
  .overdue-banner { animation: none; }
}

/* Count badge on the Exceptions heading — bright red pill that won't dim. */
.exc-count-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; height: 1.5rem;
  padding: 0 .45rem; margin-left: .5rem;
  background: #b91c1c; color: #fff;
  border-radius: 999px;
  font: 600 .8rem/1 ui-sans-serif, system-ui, sans-serif;
  vertical-align: middle;
}
.exc-count-badge[hidden] { display: none; }

/* ---- Per-segment sub-filter rows (grouping toggles) ---- */
.del-subfilters,
.wc-subfilters {
  display: flex; flex-wrap: wrap; gap: .4rem; align-items: center;
  width: 100%; padding-top: .55rem; margin-top: .55rem;
  border-top: 1px dashed var(--line);
}
.del-subfilters[hidden],
.wc-subfilters[hidden] { display: none; }
.del-subfilters-label {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-faint); font-weight: 600; margin-right: .25rem;
}
.chip-by-status.is-on,
.chip-by-driver.is-on,
.chip-by-county.is-on,
.chip-by-window.is-on,
.chip-by-shipper.is-on,
.chip-by-date.is-on { background: var(--green); color: #fff; border-color: var(--green); }
.county-view, .window-view, .shipper-view { padding: 0 1.25rem 1rem; }
.map-view { padding: 0 1.25rem 1rem; }
.map-shell {
  display: grid; grid-template-columns: 1fr 240px; gap: .75rem;
  align-items: stretch;
}
#cgh-fdash-map { height: 50vh; min-height: 380px; max-height: 620px; border-radius: 10px; overflow: hidden; }
.map-shell.lasso-mode #cgh-fdash-map { cursor: crosshair; }
/* View-only roles: hide all routing-mutation controls but keep the map
   itself visible for situational awareness. */
.map-shell[data-cap-routing="0"] .palette-tool,
.map-shell[data-cap-routing="0"] .palette-clear-all,
.map-shell[data-cap-routing="0"] .palette-route,
.map-shell[data-cap-routing="0"] .palette-selection,
.map-shell[data-cap-routing="0"] .map-hint { display: none !important; }
.map-shell[data-cap-routing="0"] .palette-row { cursor: default; }
@media (max-width: 720px) {
  .map-shell { grid-template-columns: 1fr; }
}

/* Custom divIcon pin styling — replaces the default Leaflet circleMarker
   so we get draggable + selection ring + custom drag image hooks. */
.cgh-pin { background: transparent !important; border: none !important; }
.cgh-pin .cgh-pin-dot {
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0,0,0,.35);
  cursor: grab;
}
.cgh-pin .cgh-pin-dot.cgh-pin-num {
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; font-size: 11px; line-height: 1;
  text-shadow: 0 1px 2px rgba(0,0,0,.6);
}
.cgh-pin.is-selected .cgh-pin-dot {
  box-shadow: 0 0 0 4px rgba(20,83,45,.5), 0 1px 3px rgba(0,0,0,.35);
  transform: scale(1.15);
  transition: transform .12s ease;
}
.leaflet-container.lasso-mode { cursor: crosshair !important; }

/* Driver palette — drop targets + bulk-assign click targets */
.map-palette {
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  padding: .75rem; display: flex; flex-direction: column;
  min-height: 380px;
}
.palette-head { display: flex; align-items: center; gap: .5rem; }
.palette-head h3 { margin: 0; font-size: .85rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-soft); flex: 1; }
.palette-tool {
  font: inherit; font-size: .72rem; padding: .25rem .55rem;
  border: 1px solid var(--line); border-radius: 5px; background: var(--bg);
  cursor: pointer; color: var(--ink-soft);
}
.palette-tool:hover { border-color: var(--green); color: var(--ink); }
.palette-tool.is-active { background: var(--green); color: #fff; border-color: var(--green); }
.palette-clear-all { color: var(--stall); border-color: rgba(185,28,28,.35); }
.palette-clear-all:hover { background: var(--aging-red); border-color: var(--stall); color: var(--stall); }
/* Lasso (Alt+drag) is a desktop-only gesture — hide on mobile since touch
   can't hold a modifier key while dragging. Pin tap + driver row click
   still works for bulk reassign without the lasso. */
@media (max-width: 720px) {
  #cgh-lasso-btn { display: none !important; }
}
.palette-status { margin-left: auto; font-size: .7rem; color: var(--green); }
.palette-selection {
  margin-top: .55rem; padding: .35rem .5rem; border-radius: 6px;
  background: var(--green-soft); color: var(--green); font-size: .78rem;
  display: flex; align-items: center; gap: .5rem;
}
.sel-count { font-weight: 700; font-variant-numeric: tabular-nums; }
.sel-clear {
  margin-left: auto; font: inherit; font-size: .7rem; padding: .15rem .45rem;
  border: 1px solid var(--green); background: #fff; color: var(--green);
  border-radius: 4px; cursor: pointer;
}
.palette-list {
  list-style: none; margin: .55rem 0 0; padding: 0; overflow-y: auto;
  flex: 1;
}
.palette-row {
  display: flex; align-items: center; gap: .5rem;
  padding: .45rem .55rem; margin: 0 -.25rem; border-radius: 6px;
  cursor: pointer; transition: background .12s;
}
.palette-row:hover { background: var(--bg); }
.palette-row.is-drop-target {
  background: var(--green-soft); outline: 2px dashed var(--green); outline-offset: -2px;
}
.palette-dot {
  width: 12px; height: 12px; border-radius: 50%; flex: 0 0 12px;
  border: 1.5px solid #fff; box-shadow: 0 0 0 1px var(--line);
}
.palette-name { flex: 1; font-size: .9rem; color: var(--ink); }
.palette-count {
  font-size: .75rem; font-variant-numeric: tabular-nums;
  padding: .04rem .4rem; border-radius: 999px;
  background: var(--bg); color: var(--ink-soft);
}
/* Amber when some orders are missing a geocode — flag the gap so the user
   knows the map is showing N of M, not the full set. */
.palette-count-partial {
  background: #fef3c7; color: #92400e; font-weight: 600;
}
.palette-count-total {
  opacity: .65; font-weight: 400; margin-left: .05rem;
}
.palette-route {
  font: inherit; font-size: .68rem; padding: .15rem .45rem;
  border: 1px solid var(--green); background: #fff; color: var(--green);
  border-radius: 4px; cursor: pointer; margin-left: .35rem;
}
.palette-route:hover { background: var(--green-soft); }
.palette-route.is-loading { opacity: .6; }
.palette-hint { margin: .55rem 0 0; font-size: .68rem; color: var(--ink-faint); line-height: 1.4; }

/* Date picker chip — sits beside Today / Tomorrow. Native date input
   without browser chrome distractions. */
.chip-date {
  display: inline-flex; align-items: center; gap: .4rem;
  cursor: pointer; padding: .55rem .85rem; position: relative;
}
.chip-icon { font-size: .95rem; line-height: 1; }
.chip-date-display { font-size: .85rem; font-weight: 600; line-height: 1; }
/* Hide the native iOS date-edit UI (Month / Day / Year spinbuttons + the
   default picker icon). The whole <label> remains tappable; tap fires the
   underlying input's picker. Our own .chip-date-display shows the value. */
.chip-date-input {
  position: absolute; inset: 0;
  font: inherit; border: none; background: transparent; color: transparent;
  opacity: 0; cursor: pointer;
  appearance: none; -webkit-appearance: none;
}
.chip-date-input::-webkit-datetime-edit,
.chip-date-input::-webkit-datetime-edit-fields-wrapper,
.chip-date-input::-webkit-datetime-edit-text,
.chip-date-input::-webkit-datetime-edit-month-field,
.chip-date-input::-webkit-datetime-edit-day-field,
.chip-date-input::-webkit-datetime-edit-year-field { display: none !important; }
.chip-date-input::-webkit-calendar-picker-indicator { opacity: 0; pointer-events: none; }
.chip-date.is-on { background: var(--green-soft); border-color: var(--green); color: var(--green); }

/* Map popup — editable Driver + Route inputs */
.map-popup { font: 13px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; min-width: 220px; }
.map-popup-head { display: flex; align-items: baseline; gap: .45rem; flex-wrap: wrap; }
.map-popup-num { font-weight: 700; font-size: 14px; color: var(--green); text-decoration: none; font-variant-numeric: tabular-nums; }
.map-popup-cust { font-weight: 600; color: var(--ink); }
.map-popup-meta { color: var(--ink-faint); font-size: 12px; margin: 4px 0 8px; }
.map-popup-edit { display: flex; flex-direction: column; gap: .35rem; padding-top: .35rem; border-top: 1px dashed var(--line); }
.map-popup-field { display: flex; align-items: center; gap: .5rem; }
.map-popup-field span { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-faint); width: 4rem; flex: 0 0 4rem; }
.map-popup-field input {
  flex: 1; min-width: 0; padding: .25rem .4rem; font: inherit;
  border: 1px solid var(--line); border-radius: 4px; background: #fff;
}
.map-popup-field input:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 2px rgba(20,83,45,.18); }
.map-popup-status { font-size: 11px; min-height: 14px; color: var(--ink-faint); }
.map-popup-status.ok  { color: var(--green); }
.map-popup-status.err { color: var(--stall); }

/* Roster manager — admin-only panel for renaming / removing drivers + routes */
.roster-btn {
  font: inherit; font-size: .8rem; background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.3); color: #fff; text-decoration: none;
  padding: .3rem .65rem; border-radius: 6px; cursor: pointer;
  transition: background .12s, transform .08s, box-shadow .12s;
}
.roster-btn:hover { background: rgba(255,255,255,.22); transform: translateY(-1px); box-shadow: 0 2px 6px rgba(0,0,0,.18); }
.roster-btn:active { transform: translateY(0); box-shadow: none; }

/* Admin menu (gear + dropdown). Replaces standalone Roster pill — now
   one entry point for Roster + Settings + Audit log. */
/* Header action button — shared by `+ New Order` and any future
   one-tap shortcuts. Same chrome as .admin-menu-btn so the row stays
   visually consistent. */
.head-btn {
  font: inherit; font-size: .8rem;
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.3);
  color: #fff; padding: .3rem .6rem; border-radius: 6px;
  display: inline-flex; align-items: center; gap: .25rem;
  text-decoration: none; cursor: pointer;
  transition: background .12s, transform .08s;
}
.head-btn:hover  { background: rgba(255,255,255,.22); transform: translateY(-1px); }
.head-btn:active { transform: translateY(0); }
.head-btn-qo span[aria-hidden] { font-weight: 700; font-size: .95rem; line-height: 1; }
@media (max-width: 720px) {
  /* Hide the label on phones — `+` glyph alone is the affordance. */
  .head-btn-label { display: none; }
  .head-btn { padding: .3rem .5rem; }
}

.admin-menu { position: relative; }
.admin-menu-btn {
  font: inherit; font-size: .8rem;
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.3);
  color: #fff; padding: .3rem .55rem; border-radius: 6px; cursor: pointer;
  display: inline-flex; align-items: center; gap: .25rem;
  transition: background .12s, transform .08s;
}
.admin-menu-btn:hover { background: rgba(255,255,255,.22); transform: translateY(-1px); }
.admin-menu-btn:active { transform: translateY(0); }
.admin-menu-caret { font-size: .65rem; opacity: .8; }
.admin-menu-pop {
  position: absolute; top: calc(100% + .4rem); right: 0;
  background: #fff; border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0,0,0,.18);
  min-width: 11rem; padding: .35rem; z-index: 100;
}
.admin-menu-pop[hidden] { display: none; }
.admin-menu-item {
  display: block; padding: .55rem .75rem; border-radius: 6px;
  color: var(--ink); text-decoration: none; font-size: .9rem;
  white-space: nowrap;
}
.admin-menu-item:hover { background: var(--green-soft); color: var(--green); }
.admin-menu-item:active { background: rgba(20,83,45,.18); }
/* Menu items support <button> too — strip default button chrome */
button.admin-menu-item {
  background: none; border: 0; width: 100%; text-align: left;
  font: inherit; cursor: pointer;
}
button.admin-menu-item:disabled { opacity: .5; cursor: not-allowed; }
.admin-menu-item-danger { color: var(--err, #b91c1c); }
.admin-menu-item-danger:hover { background: rgba(185,28,28,.08); color: var(--err, #b91c1c); }

/* Generic form row/label/control — used inside modals (status override
   etc). Kept minimal because each surface picks its own layout. */
.form-row { display: flex; flex-direction: column; gap: .3rem; }
.form-label { font-size: .78rem; font-weight: 600; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .03em; }
.form-control {
  font: inherit; font-size: 16px;  /* 16px avoids iOS auto-zoom */
  padding: .55rem .65rem;
  border: 1px solid var(--line); border-radius: 6px;
  background: #fff; color: var(--ink);
}
.form-control:focus { outline: 2px solid var(--green-soft); outline-offset: 1px; }
textarea.form-control { resize: vertical; min-height: 3.2rem; }

/* Accessible label hidden visually but read by screen readers */
.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;
}

/* Audit log list — used on /dashboard/audit/ AND inline on order detail */
.audit-filter-bar { margin-bottom: 1rem; }
.audit-filter-label { font-size: .85rem; color: var(--ink-soft); display: inline-flex; align-items: center; gap: .5rem; }
.audit-filter-type { font: inherit; padding: .35rem .6rem; border: 1px solid var(--line); border-radius: 6px; background: #fff; }
.audit-list { list-style: none; padding: 0; margin: 0; }
.audit-row {
  padding: .65rem .75rem; border-bottom: 1px solid var(--line);
  font-size: .85rem;
}
.audit-row:last-child { border-bottom: none; }
.audit-row-head {
  display: flex; align-items: baseline; gap: .55rem; flex-wrap: wrap;
}
.audit-when { font-size: .75rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.audit-target { color: var(--ink); font-weight: 600; }
.audit-target a { color: var(--green); text-decoration: none; }
.audit-target a:hover { text-decoration: underline; }
.audit-action {
  font-size: .68rem; text-transform: uppercase; letter-spacing: .04em;
  background: var(--green-soft); color: var(--green);
  padding: .1rem .45rem; border-radius: 999px;
}
.audit-row-body { margin-top: .2rem; color: var(--ink-soft); }
.audit-actor { font-weight: 600; color: var(--ink); margin-right: .35rem; }
.audit-summary { font-size: .82rem; }
/* ---- Roster landing page (/dashboard/roster) ---- */
.dash-roster { background: #fafaf7; min-height: 100vh; }
.roster-back-btn {
  font: inherit; font-size: .8rem; background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.3); color: #fff; text-decoration: none;
  padding: .3rem .65rem; border-radius: 6px;
}
.roster-back-btn:hover { background: rgba(255,255,255,.22); }
/* On mobile the in-body .roster-back-link is sticky and covers the same
   navigation. Hide the header-side btn so we don't have two competing
   back affordances stacked (Chris 2026-05-25 — the header one rendered
   half-visible / washed-out behind the sticky overlay). */
@media (max-width: 720px) {
  .roster-back-btn { display: none; }
}
/* In-body back link — sticks to top while scrolling the roster so the user
   can leave the page from anywhere, not just the start. dash-header is
   non-sticky on mobile (it wraps too tall), so this is the only persistent
   nav-out affordance once the user scrolls. */
.roster-back-link {
  margin: 0 -.85rem .85rem; font-size: .9rem;
  position: sticky; top: 0; z-index: 20;
  padding: .55rem .85rem;
  background: rgba(250,250,247,.95);
  backdrop-filter: blur(4px);
  border-bottom: 1px solid var(--line);
}
.roster-back-link a {
  color: var(--green); text-decoration: none; font-weight: 600;
  padding: .35rem .65rem; border-radius: 6px;
  background: var(--green-soft);
  display: inline-block;
}
.roster-back-link a:hover { background: rgba(20,83,45,.18); }
.roster-page {
  max-width: 880px; margin: 0 auto; padding: 1.25rem 1.25rem 4rem;
}
.roster-page-toolbar {
  display: flex; align-items: center; gap: .65rem; flex-wrap: wrap;
  margin-bottom: 1rem;
}
.roster-add-btn {
  font: inherit; font-size: .85rem; padding: .45rem .9rem;
  background: var(--green); color: #fff; border: none; border-radius: 6px;
  cursor: pointer; font-weight: 600;
  transition: background .12s, transform .08s, box-shadow .12s;
}
.roster-add-btn:hover { background: var(--green-dark, #0f3a23); transform: translateY(-1px); box-shadow: 0 3px 8px rgba(20,83,45,.25); }
.roster-add-btn:active { transform: translateY(0); box-shadow: none; }
.roster-search {
  font: inherit; font-size: .9rem; padding: .45rem .7rem; flex: 1; min-width: 12rem;
  border: 1px solid var(--line); border-radius: 6px; background: #fff;
}
.roster-store-select {
  font: inherit; font-size: .9rem; padding: .45rem .55rem;
  border: 1px solid var(--line); border-radius: 6px; background: #fff;
}
.roster-page-body { display: flex; flex-direction: column; gap: .5rem; }
.roster-section {
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
  background: #fff;
}
.roster-section-head {
  display: flex; align-items: center; gap: .6rem;
  padding: .6rem .85rem; cursor: pointer; user-select: none;
  background: var(--bg);
}
.roster-section-head:hover { background: rgba(0,0,0,.03); }
.roster-section-head .chevron {
  color: var(--ink-faint); font-size: .8rem; width: 1rem;
  transition: transform .15s ease;
  transform: rotate(-90deg);
}
.roster-section.is-open .roster-section-head .chevron { transform: rotate(0deg); }
.roster-section-label { flex: 1; font-weight: 600; color: var(--ink); font-size: .95rem; }
.roster-section-count {
  font-size: .75rem; padding: .1rem .55rem; border-radius: 999px;
  background: var(--green-soft); color: var(--green); font-weight: 600;
}
.roster-list { list-style: none; margin: 0; padding: 0; }
.roster-section:not(.is-open) .roster-list,
.roster-section:not(.is-open) .roster-empty { display: none; }
.roster-row { border-top: 1px solid var(--line); }
.roster-row.is-editing { background: rgba(20,83,45,.04); }
.roster-row-toggle {
  width: 100%; display: grid; grid-template-columns: 1fr auto auto;
  align-items: center; gap: .75rem;
  padding: .65rem .85rem;
  background: transparent; border: none; cursor: pointer;
  text-align: left; font: inherit;
}
.roster-row-toggle:hover { background: rgba(0,0,0,.02); }
.roster-name {
  font-weight: 600; color: var(--ink); font-size: .92rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.roster-row-meta { display: flex; gap: .55rem; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.roster-status { font-size: .65rem; padding: .05rem .4rem; border-radius: 999px; text-transform: uppercase; letter-spacing: .04em; font-weight: 600; }
.roster-status.is-active  { background: var(--green-soft); color: var(--green); }
.roster-status.is-pending { background: rgba(180,83,9,.18); color: var(--flag); }
/* Chris 2026-05-25 P15: demote PIN dots + store to quieter weight so
   the ACTIVE/PENDING pill is the visual anchor on each row. */
.roster-pin { font-size: .68rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; letter-spacing: .04em; }
.roster-pin.is-empty { color: var(--ink-faint); font-style: italic; }
.roster-store { font-size: .68rem; color: var(--ink-faint); }
/* Chris 2026-05-25 P14: "Roster" subtitle as a pill chip — chip styling
   makes it read as an intentional page label rather than tentative
   small text. */
.roster-chip {
  display: inline-block; padding: .1rem .55rem; border-radius: 999px;
  background: var(--green-soft); color: var(--green);
  font-size: .68rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; opacity: 1;
  margin-top: .15rem; align-self: flex-start;
}
.roster-driver-badge {
  font-size: .62rem; font-weight: 700; padding: .08rem .38rem;
  border-radius: 4px; background: var(--green); color: #fff;
  margin-left: .35rem; vertical-align: middle;
}
.roster-row-caret {
  font-size: .8rem; color: var(--ink-faint);
  transition: transform .15s ease;
}
.roster-row.is-editing .roster-row-caret { transform: rotate(180deg); }
.roster-row-editor { padding: .85rem 1rem 1rem; border-top: 1px dashed var(--line); }
.roster-row-editor[hidden] { display: none; }

/* Inline editor (also used by Add) */
.roster-editor-form .ed-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: .55rem .7rem;
}
.roster-editor-form .ed-full { grid-column: 1 / -1; }
.roster-editor-form .ed-driver {
  grid-column: 1 / -1; flex-direction: row; align-items: center;
  gap: .4rem; font-size: .85rem; color: var(--ink); cursor: pointer;
}
.roster-editor-form .ed-flags {
  display: flex; gap: 1rem; flex-wrap: wrap;
  padding-top: .25rem;
}
.roster-editor-form .ed-flag {
  flex-direction: row; align-items: center; gap: .35rem;
  font-size: .85rem; color: var(--ink); text-transform: none; letter-spacing: 0;
  cursor: pointer;
}
.roster-editor-form .ed-flag input { margin: 0; }
.roster-editor-form .ed-flag-lead.is-hidden { display: none; }
.roster-editor-form label {
  display: flex; flex-direction: column; gap: .2rem;
  font-size: .72rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .04em;
}
.roster-editor-form input[type="text"],
.roster-editor-form input[type="email"],
.roster-editor-form select {
  font: inherit; font-size: .92rem; padding: .4rem .55rem;
  border: 1px solid var(--line); border-radius: 6px; background: #fff;
  color: var(--ink); text-transform: none; letter-spacing: 0;
}
.roster-editor-form .ed-actions {
  display: flex; justify-content: space-between; gap: .5rem; margin-top: .85rem;
  flex-wrap: wrap;
}
.roster-editor-form .ed-actions-left,
.roster-editor-form .ed-actions-right {
  display: flex; gap: .5rem; flex-wrap: wrap;
}
.ed-remove-role, .ed-deactivate {
  font: inherit; font-size: .8rem; padding: .42rem .8rem;
  background: #fff; border: 1px solid rgba(185,28,28,.35); border-radius: 6px;
  cursor: pointer; color: var(--stall);
}
.ed-remove-role:hover, .ed-deactivate:hover {
  background: var(--aging-red); border-color: var(--stall);
}
.ed-cancel, .ed-reset-pin {
  font: inherit; font-size: .82rem; padding: .42rem .85rem;
  background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer; color: var(--ink-soft);
}
.ed-cancel:hover, .ed-reset-pin:hover { color: var(--ink); border-color: var(--green); }
.ed-save {
  font: inherit; font-size: .82rem; padding: .42rem .9rem;
  background: var(--green); color: #fff; border: none; border-radius: 6px;
  cursor: pointer; font-weight: 600;
}
.ed-save:disabled { opacity: .6; cursor: progress; }
.roster-add-editor {
  border: 1px solid var(--green); border-radius: 10px; background: #fff;
  padding: 1rem 1.1rem; margin-bottom: 1rem;
}
.roster-empty { color: var(--ink-faint); font-size: .85rem; padding: .65rem .85rem; margin: 0; }

/* Toast (used for save status) */
.roster-toast {
  position: fixed; bottom: 1.5rem; left: 50%;
  transform: translate(-50%, 1rem); opacity: 0;
  background: var(--ink, #1f2421); color: #fff;
  padding: .55rem 1rem; border-radius: 8px; font-size: .85rem;
  box-shadow: 0 6px 18px rgba(0,0,0,.25); z-index: 200;
  transition: transform .2s ease, opacity .2s ease;
  max-width: calc(100vw - 2rem);
}
.roster-toast.is-on { opacity: 1; transform: translate(-50%, 0); }
.roster-toast.is-err { background: var(--stall, #b91c1c); }

@media (max-width: 720px) {
  .roster-page { padding: 1rem .85rem 4rem; }
  .roster-row-toggle { grid-template-columns: 1fr auto; }
  .roster-row-caret { display: none; }
  .roster-row-meta { grid-column: 1 / -1; justify-content: flex-start; }
  .roster-editor-form .ed-grid { grid-template-columns: 1fr; }
}

/* ---- Shipping sub-filter row (carriers + blue tag) ---- */
.ship-subfilters {
  display: flex; flex-wrap: wrap; gap: .4rem; align-items: center;
  width: 100%; padding-top: .55rem; margin-top: .55rem;
  border-top: 1px dashed var(--line);
}
.ship-subfilters[hidden] { display: none; }
.ship-subfilters-label {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-faint); font-weight: 600; margin-right: .25rem;
}
.ship-subfilters-sep {
  color: var(--ink-faint); padding: 0 .35rem; font-size: 1.1rem; line-height: 1;
}
.carrier-chip { font-variant-numeric: tabular-nums; }
.carrier-chip.is-on { background: #1d4e7a; color: #fff; border-color: #1d4e7a; }
.carrier-chip.is-on .team-count { background: rgba(255,255,255,.22); color: #fff; }
.chip-blue-tag.is-on {
  background: #1d4e7a; color: #fff; border-color: #1d4e7a;
}
.chip-blue-tag.is-on .chip-dot { background: #fff; }
.chip-blue-tag .chip-dot { background: #1d4e7a; }

/* ---- Print manifest ---- */
@media print {
  .dash-head, .filter-bar, .funnel, .late-band, .panel-exceptions,
  .panel-team, .dash-foot, .print-btn, .collapse-toggle .chevron,
  .refresh, .who-am-i, .loc-pick { display: none !important; }
  body, .dash { background: #fff; max-width: none; padding: 0; }
  .panel { margin: 0 0 1rem; page-break-inside: avoid; }
  .panel h2 { font-size: 1rem; color: #000; border-bottom: 1px solid #000; padding-bottom: .25rem; }
  .panel-scroll { overflow: visible; box-shadow: none; border: none; }
  table.orders { font-size: 10pt; }
  table.orders th { background: #eee; }
  /* When body has cgh-print-only-<panel>, hide every other panel */
  body.print-only-today    .panel:not([data-print-target="today"]),
  body.print-only-tomorrow .panel:not([data-print-target="tomorrow"]),
  body.print-only-beyond   .panel:not([data-print-target="beyond"]),
  body.print-only-shipped  .panel:not([data-print-target="shipped"]) { display: none !important; }
  /* expand collapsed panels for print */
  .panel-collapsible.collapsed .panel-scroll { display: block !important; }
}

/* ---- Will Call header strip (visible only when segment=willcall) ---- */
.wc-header { display: none; padding: 0 1.25rem; }
.dash[data-segment="willcall"] .wc-header { display: block; margin-top: 1rem; }
.wc-strip {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: .6rem;
}
.wc-tile {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: .8rem .6rem; text-align: center;
  display: flex; flex-direction: column; gap: .15rem;
}
.wc-tile .wc-count { font-size: 1.5rem; font-weight: 700; color: var(--green); line-height: 1; }
.wc-tile .wc-lbl   { font-size: .72rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .03em; }
.wc-tile-alert { border-color: var(--stall); background: var(--aging-red); }
.wc-tile-alert .wc-count { color: var(--stall); }
.wc-tile-next .wc-count { color: var(--ink); }

/* Inline-edit cells: pickup window (WC segment) + delivery date (All segment).
   Edit icon is ALWAYS visible (low opacity) so touch users see editability
   without hover. Brightens on hover/focus for desktop. */
.cell-window, .cell-date { cursor: pointer; position: relative; padding-right: 1.4rem; }
.cell-window::after, .cell-date::after {
  content: '✎';
  position: absolute; right: .55rem; top: 50%; transform: translateY(-50%);
  font-size: .8rem; color: var(--ink-faint); opacity: .45;
  transition: opacity .12s;
  pointer-events: none;
}
.cell-window:hover, .cell-date:hover { background: rgba(20, 83, 45, .04); }
.cell-window:hover::after, .cell-date:hover::after { opacity: 1; }
.cell-window.editing, .cell-date.editing { padding: 0; }
.cell-window.editing::after, .cell-date.editing::after { display: none; }
.cell-window-select, .cell-date-input {
  width: 100%; height: 100%; min-height: 2rem;
  padding: .35rem .5rem; font: inherit; font-size: .85rem;
  border: 1px solid var(--green); border-radius: 4px;
  background: #fff;
}
.cell-window.saving, .cell-date.saving { background: #fff7e0; }
.cell-window.saved-flash, .cell-date.saved-flash { animation: cgh-flash-save .9s ease-out 1; }
@keyframes cgh-flash-save {
  0%   { background: var(--green-soft); }
  100% { background: transparent; }
}

/* Toast — bottom-right transient notice */
.cgh-toast {
  position: fixed; right: 1.25rem; bottom: 1.25rem;
  background: var(--ink); color: #fff;
  padding: .6rem .9rem; border-radius: 6px;
  font-size: .88rem; box-shadow: 0 4px 12px rgba(0,0,0,.18);
  opacity: 0; transform: translateY(8px);
  transition: opacity .2s, transform .2s;
  z-index: 50; max-width: 22rem;
}
.cgh-toast.is-visible { opacity: 1; transform: translateY(0); }
.cgh-toast.is-error { background: var(--stall); }

/* Will-Call no-show row treatment — shown in any panel */
tr.has-no-show td:first-child { box-shadow: inset 3px 0 0 var(--stall); }
tr.has-no-show td { color: var(--ink-soft); }
tr.has-no-show td.mono::after {
  content: 'no-show'; margin-left: .5rem;
  font-size: .68rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--stall);
  background: #fbe0e0; padding: .08rem .35rem; border-radius: 4px;
}

@media (max-width: 720px) {
  .wc-strip { grid-template-columns: repeat(2, 1fr); }
}

/* ---- Order detail (/dashboard/order/{id}) ---- */
/* Header treatment for the order page: replaces generic "California
   Greenhouses / Fulfillment Dashboard" wordmark with order context
   (#order + customer + stage pill). Back link is a chevron button on
   the left. Chris 2026-05-25 — saves a "where am I?" cognitive ping. */
.dash-head-order {
  flex-wrap: nowrap; gap: .6rem;
  padding: calc(.7rem + env(safe-area-inset-top)) 1rem .7rem;
}
.dash-head-order .back-link {
  color: #fff; text-decoration: none; font-size: 1.25rem; font-weight: 600;
  width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 6px; background: rgba(255,255,255,.12);
  flex: 0 0 auto;
}
.dash-head-order .back-link:hover { background: rgba(255,255,255,.22); }
.order-head-title {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; line-height: 1.2;
  overflow: hidden;
}
.order-head-num {
  font-size: 1rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.order-head-cust {
  font-size: .85rem; font-weight: 500; opacity: .9;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.stage-pill.stage-pill-head {
  flex: 0 0 auto; font-size: .7rem; padding: .2rem .55rem;
  /* Header is on dark green — use lighter chip tones so pill stays visible */
  background: rgba(255,255,255,.18); color: #fff; border-color: rgba(255,255,255,.3);
}
/* Merge button on order header. Sits between title and stage pill on the
   right side. Icon-only on narrow screens — same pattern as Roster. */
.order-head-merge {
  flex: 0 0 auto;
  font: inherit; font-size: .8rem; color: #fff; cursor: pointer;
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.3);
  padding: .3rem .55rem; border-radius: 6px;
  transition: background .12s, transform .08s;
}
.order-head-merge:hover { background: rgba(255,255,255,.22); transform: translateY(-1px); }
.order-head-merge:active { transform: translateY(0); }
@media (max-width: 480px) {
  .order-head-merge-label { display: none; }
  .order-head-merge { padding: .3rem .45rem; font-size: .9rem; }
}

/* ---- Merge modal ----------------------------------------------------- */
.merge-modal[hidden] { display: none; }
.merge-modal {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: flex-end; justify-content: center;
}
.merge-modal-backdrop {
  position: absolute; inset: 0; background: rgba(0,0,0,.45);
}
.merge-modal-panel {
  position: relative; background: #fff; width: 100%; max-width: 480px;
  border-radius: 14px 14px 0 0;
  display: flex; flex-direction: column; max-height: 85vh;
  box-shadow: 0 -8px 24px rgba(0,0,0,.2);
  animation: merge-slide-up .18s ease-out;
}
@keyframes merge-slide-up {
  from { transform: translateY(20px); opacity: .6; }
  to   { transform: translateY(0);    opacity: 1; }
}
@media (min-width: 720px) {
  .merge-modal { align-items: center; }
  .merge-modal-panel { border-radius: 14px; }
}
.merge-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.25rem .65rem;
  border-bottom: 1px solid var(--line);
}
.merge-modal-head h2 { margin: 0; font-size: 1.05rem; font-weight: 700; }
.merge-modal-x {
  background: transparent; border: none; font-size: 1.4rem; line-height: 1;
  cursor: pointer; color: var(--ink-faint); padding: 0 .25rem;
  min-width: 44px; min-height: 44px;
}
.merge-modal-body {
  flex: 1; overflow-y: auto;
  padding: 1rem 1.25rem;
  font-size: .9rem; color: var(--ink);
}
.merge-modal-note {
  margin: 0 0 1rem; font-size: .8rem; color: var(--ink-soft); line-height: 1.5;
  background: var(--green-soft); padding: .65rem .8rem; border-radius: 8px;
}
.merge-modal-loading, .merge-modal-empty {
  margin: 1rem 0; text-align: center; color: var(--ink-faint);
}
.merge-modal-error { color: var(--stall); padding: .8rem; background: #fef2f2; border-radius: 6px; }
.merge-cand-list { display: flex; flex-direction: column; gap: .5rem; }
.merge-cand {
  display: flex; gap: .65rem; align-items: flex-start;
  padding: .65rem .75rem; border: 1px solid var(--line); border-radius: 8px;
  cursor: pointer; transition: background .1s, border-color .1s;
}
.merge-cand:hover { background: #fafaf7; }
.merge-cand.is-disabled { opacity: .6; cursor: not-allowed; background: #fafafa; }
.merge-cand input[type=checkbox] {
  width: 20px; height: 20px; flex: 0 0 auto; margin-top: .15rem; cursor: inherit;
}
.cand-main { flex: 1; min-width: 0; }
.cand-top { display: flex; gap: .45rem; align-items: center; }
.cand-num { font-weight: 700; font-variant-numeric: tabular-nums; }
.cand-meta { font-size: .78rem; color: var(--ink-soft); margin-top: .15rem; }
.cand-due { font-weight: 600; }
.cand-hint {
  margin-top: .35rem; font-size: .72rem; color: var(--stall);
  font-style: italic;
}
.merge-modal-foot {
  display: flex; align-items: center; gap: .65rem;
  padding: .75rem 1.25rem 1rem;
  padding-bottom: calc(1rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
.merge-modal-status { flex: 1; font-size: .8rem; color: var(--ink-soft); }
.merge-modal-cancel {
  font: inherit; font-size: .85rem; padding: .55rem 1rem;
  background: #fff; border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer; color: var(--ink);
}
.merge-modal-go {
  font: inherit; font-size: .9rem; font-weight: 600;
  padding: .55rem 1.1rem; background: var(--green); color: #fff;
  border: none; border-radius: 6px; cursor: pointer;
  transition: background .12s, transform .08s, box-shadow .12s;
}
.merge-modal-go:hover:not(:disabled) {
  background: var(--green-dark, #0f3a23);
  transform: translateY(-1px); box-shadow: 0 3px 8px rgba(20,83,45,.25);
}
.merge-modal-go:disabled { background: #c4c8c2; cursor: not-allowed; }
.dash-order .back-link {
  color: #fff; text-decoration: none; font-size: .85rem;
  padding: .35rem .7rem; border-radius: 6px;
  border: 1px solid rgba(255,255,255,.3); background: rgba(255,255,255,.12);
}
.dash-order .back-link:hover { background: rgba(255,255,255,.22); }
.order-summary { padding: .85rem 1.25rem 0; }
.order-meta-row {
  margin-top: .65rem; display: flex; flex-wrap: wrap; gap: .55rem; align-items: center;
}
.order-meta-row .ro-meta { font-size: .8rem; color: var(--ink-faint); }
.stage-pill {
  display: inline-block; padding: .15rem .55rem; border-radius: 999px;
  font-size: .78rem; font-weight: 600; letter-spacing: .02em;
  background: var(--green-soft); color: var(--green); border: 1px solid #cfe1d3;
}
.stage-pill.stage-received   { background: #eef0ee; color: #4b5249; border-color: #d4d8d3; }
.stage-pill.stage-counted    { background: #fdf6e3; color: #8a6d1d; border-color: #ecd9a3; }
.stage-pill.stage-confirmed  { background: #fdeceb; color: #b91c1c; border-color: #f0bdb8; }
.stage-pill.stage-preparation{ background: #fde6d3; color: #b45309; border-color: #f0c389; }
.stage-pill.stage-ready      { background: #d6f0e9; color: #0f766e; border-color: #9cd6c9; }
.stage-pill.stage-completed  { background: var(--green-soft); color: var(--green); border-color: #b7d7c2; }

.order-grid {
  display: grid; gap: 1rem; padding: 1.25rem;
  grid-template-columns: repeat(2, 1fr);
}
.card {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 1rem 1.1rem;
}
/* Chris 2026-05-25: smaller uppercase tracking gives the cards a
   "panel section header" feel instead of plain heading text. */
.card h2 {
  margin: 0 0 .65rem;
  font-size: .78rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-soft);
}
.card .card-sub { font-weight: 400; color: var(--ink-faint); font-size: .82rem; margin-left: .35rem; }
.card .card-subh { margin: 1rem 0 .35rem; font-size: .82rem; font-weight: 700; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .04em; }
.card-wide { grid-column: 1 / -1; }
.card .hint { margin: .65rem 0 0; font-size: .75rem; color: var(--ink-faint); }
.card .hint code { background: var(--bg); padding: 0 .25rem; border-radius: 3px; }

.kv {
  display: grid; grid-template-columns: max-content 1fr; gap: .35rem .85rem;
  margin: 0; font-size: .9rem;
}
.kv dt { color: var(--ink-faint); font-size: .78rem; text-transform: uppercase; letter-spacing: .03em; align-self: center; }
.kv dd { margin: 0; color: var(--ink); }
.kv.kv-grid { grid-template-columns: repeat(2, max-content 1fr); }
.ro-dash { color: var(--ink-faint); font-style: italic; }
.ro-hint { color: var(--ink-faint); font-size: 11px; font-style: italic; margin-left: .35rem; }
.ro-empty { color: var(--ink-faint); font-size: .85rem; margin: .25rem 0 0; }

.doc-links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .25rem; }
.doc-links a { color: var(--green); text-decoration: none; font-weight: 600; font-size: .9rem; }
.doc-links a:hover { text-decoration: underline; }

.notes-body { font-size: .9rem; color: var(--ink); }
.notes-body p { margin: 0 0 .5rem; }

.transitions { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .35rem; }
.transitions li { display: grid; grid-template-columns: 7rem 1fr auto; gap: .65rem; align-items: baseline; font-size: .85rem; }
.transitions .t-stage { font-weight: 700; color: var(--ink); }
.transitions .t-by { color: var(--ink-soft); }
.transitions .t-when { color: var(--ink-faint); font-variant-numeric: tabular-nums; }

.item-cell { display: flex; align-items: center; gap: .65rem; }
.item-thumb-slot {
  flex: 0 0 36px; width: 36px; height: 36px;
  background: var(--bg); border-radius: 4px;
}
.item-thumb { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 4px; }
.item-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.item-name { color: var(--ink); }
.item-sku { font-size: .72rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }

/* Metrics strip — horizontal row across the top of the order detail page.
   "What gets measured gets managed." 4 tiles, equal width on desktop, stack on mobile. */
.order-metrics-strip {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: .75rem;
  padding: 1rem 1.25rem 0;
}
@media (max-width: 720px) {
  .order-metrics-strip { grid-template-columns: repeat(2, 1fr); padding: .85rem .85rem 0; }
}
.order-metrics-strip .metric {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: .85rem 1rem;
}
.metric {
  background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
  padding: .65rem .75rem;
}
.metric-num-small { font-size: 1.05rem; }
.metric-num {
  font-size: 1.55rem; font-weight: 700; line-height: 1.1;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.metric-unit { font-size: .85rem; font-weight: 600; color: var(--ink-faint); margin-left: .1rem; }
.metric-label {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-soft); margin-top: .15rem; font-weight: 600;
}
.metric-sub { font-size: .72rem; color: var(--ink-faint); margin-top: .15rem; }
/* Generic metric color states — usable on any .metric tile. */
.metric.metric-good { background: var(--green-soft); border-color: #b7d7c2; }
.metric.metric-good .metric-num { color: var(--green); }
.metric.metric-warn { background: #fdf6e3; border-color: var(--aging-yellow-bd); }
.metric.metric-warn .metric-num { color: var(--flag); }
.metric.metric-bad  { background: var(--aging-red); border-color: var(--aging-red-bd); }
.metric.metric-bad  .metric-num { color: var(--stall); }
.metric-completed-at {
  margin: .65rem 0 0; font-size: .78rem; color: var(--ink-faint);
  text-align: right;
}

/* Transition row: now has a delta column too */
.transitions li { grid-template-columns: 7rem 1fr auto auto; }
.transitions .t-delta {
  color: var(--ink-soft); font-size: .78rem; font-variant-numeric: tabular-nums;
  margin-left: .75rem;
}

/* Inline-edit affordance on the order detail page */
[data-edit-field].is-editable {
  cursor: pointer; position: relative; border-radius: 4px;
  padding: .2rem .35rem; margin: -.2rem -.35rem;
  transition: background .12s ease;
}
[data-edit-field].is-editable:hover { background: rgba(20,83,45,.06); }
[data-edit-field].is-editable:focus-visible {
  outline: 2px solid var(--green); outline-offset: 2px;
}
[data-edit-field].is-editable:not(.is-editing):hover::after {
  content: '✎'; position: absolute; right: .3rem; top: 50%;
  transform: translateY(-50%); font-size: .8rem; color: var(--green-soft);
  color: rgba(20,83,45,.5); pointer-events: none;
}
[data-edit-field].is-editing { background: #fff; }
.cell-input, .notes-input {
  font: inherit; width: 100%; min-height: 2rem; padding: .35rem .5rem;
  border: 1px solid var(--green); border-radius: 4px; background: #fff;
  color: var(--ink); outline: none;
}
.cell-input:focus, .notes-input:focus { box-shadow: 0 0 0 3px rgba(20,83,45,.18); }
.notes-input { min-height: 5rem; resize: vertical; }
.cell-saving {
  display: inline-block; width: .8rem; height: .8rem; margin-left: .4rem;
  border: 2px solid rgba(20,83,45,.25); border-top-color: var(--green);
  border-radius: 50%; vertical-align: middle;
  animation: spin .7s linear infinite;
}
/* Edit-cell visual state machine. The user needs to read these at a
   glance on a phone: editing → in-flight → saved-ok (then settled),
   or editing → saved-err (then settled). Background tints + left
   border accents are both used so the cell shows state with or
   without color perception. */
[data-edit-field].is-saving {
  /* "Save in flight" — committed, awaiting server. Subtle amber left
     border + faint tint. No spinner (that's what felt laggy). */
  background: rgba(180,120,0,.07) !important;
  box-shadow: inset 3px 0 0 0 rgba(180,120,0,.55) !important;
  transition: background .12s, box-shadow .12s;
}
[data-edit-field].cell-saved-ok {
  /* Success — bright green left border + tint. 1.5s lets the user
     actually register it on a phone (vs the prior 0.9s subtle flash). */
  background: rgba(20,83,45,.16) !important;
  box-shadow: inset 4px 0 0 0 var(--green) !important;
  transition: background .25s, box-shadow .25s;
}
[data-edit-field].cell-saved-err {
  background: rgba(185,28,28,.16) !important;
  box-shadow: inset 4px 0 0 0 var(--err, #b91c1c) !important;
  transition: background .25s, box-shadow .25s;
}
.notes-status { font-size: .75rem; color: var(--ink-faint); margin-left: .55rem; }

/* Mobile tap targets — 44px iOS guideline */
@media (max-width: 720px) {
  [data-edit-field].is-editable { min-height: 2.5rem; display: flex; align-items: center; }
  .cell-input { min-height: 2.75rem; font-size: 1rem; } /* prevent iOS zoom */
  .notes-input { min-height: 6rem; font-size: 1rem; }
}

.order-error { padding: 3rem 1.25rem; text-align: center; }
.order-error h1 { font-size: 1.4rem; margin: 0 0 .5rem; }
.order-error a { color: var(--green); }

@media (max-width: 720px) {
  .order-grid { grid-template-columns: 1fr; padding: .85rem; }
  .kv.kv-grid { grid-template-columns: max-content 1fr; }
  .transitions li { grid-template-columns: 1fr auto; }
  .transitions .t-by { grid-column: 1 / -1; font-size: .78rem; }
}

/* ---- Banner alerts (above filter bar) ---- */
[data-banner] { margin: 0 1.25rem; }
[data-banner]:not(:empty) { padding: .75rem 0 .25rem; }
.alert-banner {
  display: flex; align-items: center; gap: .6rem;
  padding: .7rem 1rem; border-radius: var(--radius);
  margin: 0 0 .5rem; box-shadow: var(--shadow);
  border: 1px solid transparent; transition: opacity .15s;
}
.alert-banner.is-dismissed { display: none; }
.alert-banner .alert-icon {
  flex: 0 0 1.4rem; height: 1.4rem; width: 1.4rem;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; font-weight: 700; font-size: .9rem;
}
.alert-banner .alert-text { flex: 1; line-height: 1.35; font-size: .92rem; }
.alert-banner .alert-text strong { font-weight: 700; }
.alert-banner .alert-controls { display: flex; align-items: center; gap: .4rem; flex-shrink: 0; }
.alert-action {
  font: inherit; font-size: .82rem; font-weight: 600;
  padding: .3rem .7rem; border-radius: 6px; cursor: pointer;
  border: 1px solid currentColor; background: transparent; color: inherit;
}
.alert-action:hover { background: rgba(0,0,0,.06); }
.alert-dismiss {
  font: inherit; font-size: 1.1rem; line-height: 1;
  width: 1.7rem; height: 1.7rem; border-radius: 50%; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: inherit; opacity: .65;
}
.alert-dismiss:hover { opacity: 1; background: rgba(0,0,0,.06); }

/* severities */
.alert-urgent  { background: #fdeceb; border-color: var(--stall);            color: #7f1d1d; }
.alert-urgent  .alert-icon { background: var(--stall);          color: #fff; }
.alert-warning { background: #fdf6e3; border-color: var(--aging-yellow-bd);  color: #7a4f00; }
.alert-warning .alert-icon { background: #ecd9a3;               color: #5a3500; }
.alert-info    { background: #eef0ec; border-color: var(--line);             color: var(--ink); }
.alert-info    .alert-icon { background: var(--ink-faint);      color: #fff; }

/* Attention pulse — used when a banner Action button scrolls to its target */
.attention-pulse { animation: cgh-pulse 1.4s ease-out 1; }
@keyframes cgh-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(20, 83, 45, .35); }
  60%  { box-shadow: 0 0 0 8px rgba(20, 83, 45, 0); }
  100% { box-shadow: 0 0 0 0 rgba(20, 83, 45, 0); }
}

/* Locked location display (non-admin users) */
.loc-fixed { display: flex; flex-direction: column; line-height: 1.2; }
.loc-fixed .loc-label { font-size: .72rem; opacity: .8; }
.loc-fixed .loc-name { font-weight: 700; font-size: .95rem; }

/* ---- Responsive ---- */
@media (max-width: 860px) {
  .funnel { grid-template-columns: repeat(3, 1fr); }
  .team-cols { grid-template-columns: 1fr; }
  .dash-head { gap: .6rem; }
  /* Chris 2026-05-25: dropped width: 100% — was forcing head-controls
     to take a full second row, collapsing the wordmark to 0. Keep
     head-controls intrinsic so brand + controls share one row. */
  .head-controls { gap: .6rem; }
  .last-refresh { min-width: auto; }
}
@media (max-width: 480px) {
  /* 3 × 2 funnel layout per Chris — reads left-to-right top-to-bottom
     matching the order pipeline (Received → Counted → Confirmed on top,
     Preparation → Ready → Completed on bottom). */
  .funnel { grid-template-columns: repeat(3, 1fr); padding: 1rem; }
  .panel { margin: 0 1rem 1rem; }
  .tile-count { font-size: 1.35rem; }
  .who-am-i { display: none; }

  /* Driver-group / county-group / etc — "spreadsheet" feel for quick
     route + driver edits. Per-row layout overrides the generic
     .orders-compact stacking with a tighter grid where the editable
     Route + Driver cells sit on the top line alongside the order #
     so taps land naturally. (Chris 2026-05-23 "as close to a
     spreadsheet as possible".) Columns in renderDriverRow:
       1=post#, 2=order, 3=customer, 4=city, 5=route, 6=driver, 7=qty */
  /* Spreadsheet feel for By Driver / By County views.
     Columns in renderDriverRow:
       1=post#, 2=order#, 3=customer, 4=city, 5=route, 6=driver, 7=total
     Layout (Chris 2026-05-23):
       Row 1: [order#]                [Route▾] [Driver▾]
       Row 2: customer              · Staged 77 · $190
     City hidden on mobile (secondary). */
  .orders-driver tbody tr {
    display: grid;
    grid-template-columns: 1fr auto auto;
    column-gap: .5rem; row-gap: .15rem;
    padding: .5rem .85rem;
    align-items: baseline;
  }
  .orders-driver tbody tr td { display: block; padding: 0; }
  .orders-driver tbody tr td:nth-child(2) {  /* order # */
    grid-column: 1; grid-row: 1;
    font-weight: 600; font-size: .95rem;
  }
  .orders-driver tbody tr td:nth-child(5) {  /* Route — editable */
    grid-column: 2; grid-row: 1;
    min-width: 2.5rem; text-align: center;
    background: rgba(20,83,45,.04); border-radius: 4px; padding: .25rem .5rem;
    font-weight: 600; font-size: .85rem;
  }
  .orders-driver tbody tr td:nth-child(5):not(:has(.ro-dash))::before {
    content: '#'; opacity: .55; font-weight: 500;
  }
  .orders-driver tbody tr td:nth-child(6) {  /* Driver — editable */
    grid-column: 3; grid-row: 1;
    min-width: 4rem; max-width: 7rem;
    background: rgba(20,83,45,.04); border-radius: 4px; padding: .25rem .5rem;
    font-size: .82rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .orders-driver tbody tr td:nth-child(3) {  /* customer */
    grid-column: 1; grid-row: 2;
    font-size: .78rem; color: var(--ink-soft);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .orders-driver tbody tr td:nth-child(1) {  /* Staged (post #) */
    display: block;  /* override .orders-compact tbody td:nth-child(1) { display: contents } */
    grid-column: 2; grid-row: 2; text-align: right;
    font-size: .72rem; color: var(--ink-faint); font-weight: 400;
    white-space: nowrap;
  }
  .orders-driver tbody tr td:nth-child(1) .post-no-num::before {
    content: 'Staged '; opacity: .7;
  }
  /* When staged cell is just an em-dash (no post_no assigned), hide it
     so the grid doesn't reserve empty space next to total. */
  .orders-driver tbody tr td:nth-child(1):has(.ro-dash) { visibility: hidden; }
  .orders-driver tbody tr td:nth-child(7) {  /* total */
    grid-column: 3; grid-row: 2; text-align: right;
    font-size: .82rem; font-weight: 600;
    font-variant-numeric: tabular-nums;
  }
  .orders-driver tbody tr td:nth-child(4) {  /* city — hidden on mobile */
    display: none;
  }
}

/* =====================================================================
   A11y + touch-target enhancements — 2026-05-22
   Eliminates the Lighthouse-flagged WCAG AA contrast fails (124/136)
   and pushes interactive elements to the 44×44 floor for floor-staff
   thumb-tap reliability. CSS-only — no JS or markup changes.
   ===================================================================== */

/* --- Contrast: bump foreground on the 3 dominant patterns Lighthouse
   flagged. --ink-faint (#828b80) vs #fff is ~3.0:1 — fails AA (4.5:1).
   --flag (#b45309) on #fdf0e0 is ~4.2:1 — fails AA. Targeted overrides
   keep the rest of the design untouched. */
/* --ink-faint bump above covers most of the previously-failing patterns
   (del-subfilters-label, row-edit content, exc-stage, count-sub, empty,
   ro-dash, ro-hint, status-group-label). Targeted overrides below stay
   for the badge that needs a custom palette: */
/* .fill-badge appears in two places — a plain one (line ~155) and a more
   specific .orders-compact .fill-badge (line ~594). Match both selectors
   here so the bump wins via later-cascade. */
.orders-compact .fill-badge,
.fill-badge {
  background: #fde9c8; color: #7a3a07;   /* now ≈5.5:1 */
}

/* --- CLS: reserve vertical space for the dashboard bands.
   Without min-height, the empty <section data-band="..."> placeholders
   collapse to 0 height, and when the snapshot JSON arrives ~1s later,
   filling them shoves content down by ~600px — a Cumulative Layout
   Shift of 0.12. Reserving min-height keeps the page geometry stable
   so populating the data doesn't shift anything. */
.dash .funnel,
.dash .status-view,
.dash .driver-view,
.dash .county-view,
.dash .window-view,
.dash .shipper-view,
.dash .date-view { min-height: 60vh; }
.dash .funnel { min-height: 110px; }
.dash .panel-exceptions:not([hidden]) { min-height: 120px; }

/* --- Touch targets: WCAG 2.5.5 / Apple HIG 44×44 floor.
   Hits the worst offenders Lighthouse flagged on the dashboard:
   refresh button (was 32×32), Reschedule buttons in exception cards
   (was 86×21), order-number drill-down links (was 76×17), status-
   group section toggles (was 41px high), team-btn tabs (was 33 high),
   chip-date input (was 21 high). */
.refresh-btn {
  width: 2.75rem; height: 2.75rem;   /* ≈44px @ 16px root */
  font-size: 1.15rem;
}
.exc-reschedule-btn,
.exc-bumpdate-btn {
  min-height: 44px;
  padding: 0.6rem 0.85rem;
  font-size: 0.85rem;
}
.orders-compact a[href^="/dashboard/order/"],
.orders a[href^="/dashboard/order/"] {
  display: inline-block;
  min-height: 44px;
  padding: 0.6rem 0.25rem;       /* vertical padding boosts tap area without widening cell */
  line-height: 1.2;
}
.status-group-toggle { min-height: 44px; padding: 0.75rem 0.85rem; }
.team-btn { min-height: 44px; padding: 0.55rem 0.85rem; }
.view-btn { min-height: 44px; padding: 0.5rem 0.95rem; }
.chip { min-height: 44px; }       /* covers chip-date + group chips */
.chip-date-input { min-height: 32px; padding: 0.4rem 0.25rem; }  /* input inside chip — chip provides outer 44 */

/* iOS Safari double-tap delay — touch-action:manipulation disables the
   built-in 300ms double-tap-to-zoom heuristic on these interactive
   surfaces. Chris reported "sometimes I have to double-tap" on the
   chip-by-driver. Applies to every tap target so single-tap is always
   first-tap. */
.chip,
.team-btn,
.view-btn,
.refresh-btn,
.status-group-toggle,
.exc-reschedule-btn,
.exc-bumpdate-btn,
.orders-compact a[href^="/dashboard/order/"],
.row-edit.is-editable { touch-action: manipulation; }

/* Snap feedback during segment switch — stale content dims while the new
   snapshot is in flight, so the tap feels instantly acknowledged even
   before the fetch lands. Excludes the loading bar + header chrome. */
.dash.is-loading .status-view,
.dash.is-loading .driver-view,
.dash.is-loading .county-view,
.dash.is-loading .window-view,
.dash.is-loading .shipper-view,
.dash.is-loading .date-view,
.dash.is-loading .funnel,
.dash.is-loading .panel-exceptions { opacity: .55; transition: opacity .08s; }

/* ---- Shimmer skeletons (loading placeholders) ---------------------------
   Used wherever the page renders a frame before data is ready. Single
   color-stop gradient that slides across; respects prefers-reduced-motion.
   Apply .skeleton to any element you want to show as a loading bar; use
   .skeleton-block for cards. .skeleton-list-row stamps a "fake row" with
   a tall left + short right block. */
@keyframes cgh-shimmer {
  from { background-position: -200% 0; }
  to   { background-position: 200% 0; }
}
.skeleton {
  display: block;
  background: linear-gradient(90deg,
    rgba(0,0,0,.06) 0%,
    rgba(0,0,0,.12) 50%,
    rgba(0,0,0,.06) 100%);
  background-size: 200% 100%;
  animation: cgh-shimmer 1.4s ease-in-out infinite;
  border-radius: 6px;
  color: transparent !important;  /* hide any fallback text inside */
  user-select: none;
}
.skeleton-row {
  display: grid;
  grid-template-columns: 1fr 6rem;
  gap: 1rem;
  padding: .75rem 0;
  border-bottom: 1px solid var(--line);
}
.skeleton-row .skeleton { height: 1rem; }
.skeleton-row .skeleton:first-child { width: 70%; }
.skeleton-row .skeleton:last-child  { width: 100%; }
.skeleton-stack > * + * { margin-top: .55rem; }

@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; opacity: .25; }
}

/* ---- Inline help (i) — hover on desktop, tap on mobile ------------------
   Tiny circled "i" the user can hover or tap to reveal an explanation.
   The tooltip is rendered as a sibling .help-tip; CSS shows it on hover
   or when [aria-expanded="true"] (toggled via JS for taps). */
.help-i {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px;
  margin-left: .3rem;
  border: 1px solid currentColor;
  border-radius: 50%;
  background: transparent;
  color: inherit;
  font: 600 10px/1 ui-sans-serif, system-ui, sans-serif;
  cursor: help;
  opacity: .55;
  padding: 0;
  vertical-align: middle;
  position: relative;
  transition: opacity .12s;
}
.help-i:hover, .help-i:focus-visible { opacity: 1; outline: none; }
.help-i .help-tip {
  /* display:none when hidden so the box doesn't contribute to body
     scrollWidth — otherwise hidden tips near a viewport edge let users
     pinch-zoom into empty whitespace on mobile. */
  display: none;
  position: absolute;
  bottom: calc(100% + .35rem);
  left: 50%; transform: translateX(-50%);
  background: var(--ink, #1f2937);
  color: #fff;
  font: 400 .75rem/1.35 ui-sans-serif, system-ui, sans-serif;
  padding: .5rem .65rem;
  border-radius: 6px;
  width: max-content; max-width: min(16rem, calc(100vw - 1.5rem));
  text-align: left;
  box-shadow: 0 4px 12px rgba(0,0,0,.18);
  pointer-events: none;
  z-index: 200;
  white-space: normal;
}
.help-i .help-tip::after {
  content: ""; position: absolute;
  top: 100%; left: 50%; transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: var(--ink, #1f2937);
}
/* When the icon sits near the viewport edge, snap the tooltip to that
   edge instead of overflowing. Detect via parent ancestor having a known
   "edge" container class, or just use position-anchored fallback below. */
@media (max-width: 720px) {
  /* On phones, just anchor the left edge of the tip to the icon (not
     centered) — the (i) is usually at the start of the label, so a
     left-aligned tip stays on-screen. */
  .help-i .help-tip {
    left: 0; transform: none;
    max-width: min(18rem, calc(100vw - 1rem));
  }
  .help-i .help-tip::after {
    left: 6px; transform: none;
  }
}
.help-i:hover .help-tip,
.help-i:focus-visible .help-tip,
.help-i[aria-expanded="true"] .help-tip {
  display: block;
}
/* On touch devices, prefer tap-to-toggle over hover (hover triggers on
   touch can stick around awkwardly). aria-expanded does the real work. */
@media (hover: none) {
  .help-i:hover .help-tip { display: none; }
  .help-i[aria-expanded="true"] .help-tip { display: block; }
}
