/* ── Carrier Procurement Styles ──────────────────────────────
   Module UI for Phase 6 (Carrier Procurement). Uses the shared
   --arl-* design tokens; global .btn/.modal/.badge come from
   styles.css. All classes are cp-* scoped. Modeled on quote-tracker.css. */

/* ── Page header + count ─────────────────────────────────────── */
.cp-page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}
.cp-page-header h2 { font-size: 22px; }
.cp-count {
  font-family: var(--arl-font-accent);
  font-size: 12px;
  font-weight: 600;
  color: var(--arl-text-muted);
  letter-spacing: 0.3px;
}
.cp-header-actions { display: flex; gap: 8px; align-items: center; }

/* ── Toolbar (search / status / mine) ────────────────────────── */
.cp-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 14px;
}
.cp-search {
  flex: 1 1 260px;
  max-width: 360px;
  padding: 8px 12px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  font-family: var(--arl-font-body);
  font-size: 14px;
  color: var(--arl-text);
  background: var(--arl-white);
}
.cp-search:focus, .cp-select:focus {
  outline: none;
  border-color: var(--arl-primary);
  box-shadow: 0 0 0 3px rgba(0, 96, 175, 0.12);
}
.cp-select {
  padding: 8px 10px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  font-family: var(--arl-font-body);
  font-size: 14px;
  color: var(--arl-text);
  background: var(--arl-white);
  cursor: pointer;
}
.cp-mine-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--arl-font-accent);
  font-size: 12px;
  font-weight: 600;
  color: var(--arl-text-secondary);
  cursor: pointer;
  user-select: none;
}
.cp-mine-toggle input { cursor: pointer; }

/* ── Table ───────────────────────────────────────────────────── */
.cp-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--arl-white);
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  overflow: hidden;
  font-size: 14px;
}
.cp-table thead th {
  text-align: left;
  padding: 10px 12px;
  font-family: var(--arl-font-accent);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--arl-text-secondary);
  background: var(--arl-surface-light);
  border-bottom: 1px solid var(--arl-border);
  white-space: nowrap;
}
.cp-table tbody td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--arl-border);
  color: var(--arl-text);
  vertical-align: middle;
}
.cp-table tbody tr:last-child td { border-bottom: none; }
.cp-table tbody tr.cp-row { cursor: pointer; transition: background 0.12s; }
.cp-table tbody tr.cp-row:hover { background: rgba(0, 96, 175, 0.04); }
.cp-num { text-align: right; font-variant-numeric: tabular-nums; }
.cp-carrier-name { font-weight: 600; color: var(--arl-primary); }
.cp-carrier-sub { font-size: 12px; color: var(--arl-text-muted); }
.cp-muted { color: var(--arl-text-muted); }

/* ── Carrier Directory: a collapsed carrier and its per-office children ───────────
 * ⚠️ UNSCOPED, and reading ONLY --arl-* tokens. `#cp-carriers-view` has no class at all,
 * so a `.cp-qm`-scoped rule would not match here and every --qm-* would resolve to
 * nothing — which voids the entire declaration it appears in. That is exactly how
 * `.cp-ltab` lost its bottom border, and how the Vet chip came out unstyled on this very
 * screen. --arl-* is declared at `:root` in styles.css, so it IS in scope; literal
 * fallbacks are kept anyway so a renamed token degrades to a visible control rather than
 * an invisible one. */
.cp-dircaret {
  display: inline-block;
  width: 14px;
  margin-right: 4px;
  color: var(--arl-text-muted, #71717a);
  transition: transform 0.12s;
  font-size: 11px;
}
.cp-dircaret-open { transform: rotate(90deg); color: var(--arl-primary, #0060af); }
/* Keeps single-office names aligned with expandable ones. Without it the two kinds of row
 * start at different x positions and the column reads as ragged. */
.cp-dircaret-spacer { display: inline-block; width: 14px; margin-right: 4px; }
/* "3 offices" — a sentence-case grey tag on the DOT · MC line under the name (2026-10-08). */
.cp-dirbadge {
  display: inline-block;
  margin-left: 6px;
  font-size: 11px;
  font-weight: 600;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--arl-surface, #EEEEEE);
  color: var(--arl-text-secondary, #666666);
  white-space: nowrap;
}
.cp-table tbody tr.cp-row-open { background: rgba(0, 96, 175, 0.06); }
.cp-table tbody tr.cp-dirchild { background: rgba(0, 96, 175, 0.03); }
.cp-table tbody tr.cp-dirchild:hover { background: rgba(0, 96, 175, 0.07); }
/* The indent sits on the first cell so it survives the row's own background. */
.cp-table tbody tr.cp-dirchild td:first-child { padding-left: 34px; }
.cp-dirchild-org { font-weight: 600; color: var(--arl-text, #18181b); font-size: 13px; }
/* "history only" — the load figures on this row cannot be confirmed against the ledger.
 * Amber rather than red on purpose: the carrier is real and callable, it is the NUMBER that
 * is unverifiable. Red would read as a safety verdict and collide with the PASS/REVIEW/NOT
 * PASS labels sitting on the same row. Unscoped and --arl-* tokens or literals only, for the same
 * reason as the rules above: #cp-carriers-view carries no class. */
.cp-dirstale {
  display: inline-block;
  margin-left: 6px;
  font-size: 11px;
  font-weight: 600;
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid #f5d0a9;
  background: #fdf6ec;
  color: #92600e;
  white-space: nowrap;
}

/* ── Carrier Directory restyle (2026-10-08) ─────────────────────────────────────
 * The "new UI style" of the Projects list and the PM carrier list: ONE card with a readable
 * heading, names in text colour, people with initials circles (carriers never — they are
 * companies), tags that always carry their word, figures written plainly, "—" for unknown.
 * Same discipline as the block above: #cp-carriers-view has no class, so --arl-* only, every
 * var() with a literal fallback, and no --qm-*. */
/* The card IS the frame, so the table inside it drops its own border, radius and clip.
 * The card itself only clips (its rounded corners over the head band); the sideways scroll
 * lives on .cp-dircard-scroll, the box around the TABLE alone, so on a phone the "Directory"
 * heading and the count stay put while the columns slide under them. That box is safe to
 * scroll (unlike the PM carrier card): only the tbody is ever repainted, so the box and its
 * sideways scroll position survive a search keystroke. */
.cp-dircard {
  background: var(--arl-white, #FFFFFF);
  border: 1px solid var(--arl-border, #E0E0E0);
  border-radius: var(--arl-radius-lg, 8px);
  overflow: hidden;
}
.cp-dircard-scroll { overflow-x: auto; }
.cp-dircard-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  padding: 10px 14px;
  background: var(--arl-surface-alt, #FAF9F9);
  border-bottom: 1px solid var(--arl-border, #E0E0E0);
}
/* The BODY font, said outright: styles.css gives every h3 the accent font, and this is an h3. */
.cp-dircard-title {
  margin: 0;
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--arl-text, #333333);
}
/* The count line moved in from the page header: the body font and sentence case of the title
 * beside it. */
.cp-dircard-head .cp-count {
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--arl-text-secondary, #666666);
}
.cp-dircard-scroll > .cp-table { border: 0; border-radius: 0; overflow: visible; min-width: 860px; }
.cp-dircard-scroll > .cp-table thead th {
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-size: 12px;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  background: transparent;
}
.cp-dircard-scroll > .cp-table tbody td { vertical-align: top; }

/* The carrier: name in TEXT colour (not link blue), verdict + Vet beside it, DOT · MC under. */
.cp-dirname-line { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.cp-dirname { font-weight: 600; color: var(--arl-text, #333333); }
.cp-table tbody tr.cp-row:hover .cp-dirname { text-decoration: underline; }
/* Lines the DOT · MC line up under the name: past the caret (14px), its margin (4px) and the
 * name line's flex gap (4px). */
.cp-dirindent { padding-left: 22px; }
.cp-dirline { line-height: 1.45; }
.cp-dirsub { font-size: 12px; line-height: 1.5; color: var(--arl-text-secondary, #666666); }
.cp-dirn { font-weight: 600; color: var(--arl-text, #333333); }
/* Two classes, because it always rides with .cp-pm-person, whose `display: flex` sits later
 * in this file: a lone .cp-dirperson ties on specificity and LOSES, a dead rule. */
.cp-pm-person.cp-dirperson { display: inline-flex; }

/* Status — always WITH its word (Fabio, 2026-10-08): Active BLUE, Inactive grey, Do not use
 * red. Active is not green because green already means PASS two cells along; Do not use
 * keeps red because it means what NOT PASS means — don't dispatch. */
.cp-dirstat {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.cp-dirstat--active { background: #E6F1FB; color: #0C447C; }
.cp-dirstat--inactive,
.cp-dirstat--other { background: var(--arl-surface, #EEEEEE); color: var(--arl-text-secondary, #666666); }
.cp-dirstat--do-not-use { background: var(--arl-error-light, #FEE2E2); color: var(--arl-accent-dark, #BD0E0E); }

/* The profile page's matching touches: readable card headings, the reliability figures
 * written as one line. */
.cp-dirprof-h {
  margin: 0 0 10px;
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--arl-text, #333333);
}
.cp-dirprof-figs { font-size: 14px; line-height: 1.6; color: var(--arl-text-secondary, #666666); }
.cp-dirprof-fig { white-space: nowrap; }
.cp-dirprof-last { margin-top: 6px; }
/* 640px, not the 600px the OS glance uses: os-glance-client.test.js reads the FIRST
 * `@media (max-width: 600px)` block in this file as its own. */
@media (max-width: 640px) {
  .cp-dirprof-head { flex-direction: column; gap: 10px; }
  .cp-dirprof-head .cp-detail-actions { flex-wrap: wrap; }
}

/* ── Status pills ────────────────────────────────────────────── */
/* Soft and rounded, in the page's font and normal case, on every CP page. This is the look
   Fabio gave most pages on 2026-10-21, moved here from his rule for those pages so that
   Coverage, Offers and Bids have it too. Each status keeps its colours. */
.cp-status {
  display: inline-block;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  padding: 2px 9px;
  border-radius: 999px;
  white-space: nowrap;
}
.cp-status-active { background: var(--arl-success-light); color: #15803D; }
.cp-status-inactive { background: var(--arl-surface); color: var(--arl-text-secondary); }
.cp-status-do_not_use { background: var(--arl-error-light); color: var(--arl-accent-dark); }
/* Bid / offer lifecycle pills reuse the same shape */
.cp-status-draft { background: var(--arl-surface); color: var(--arl-text-secondary); }
.cp-status-sent { background: rgba(0,96,175,0.12); color: var(--arl-primary-dark); }
.cp-status-failed { background: var(--arl-error-light); color: var(--arl-accent-dark); }
.cp-status-cancelled { background: var(--arl-surface); color: var(--arl-text-muted); }
.cp-status-received { background: rgba(0,96,175,0.12); color: var(--arl-primary-dark); }
.cp-status-awarded { background: var(--arl-success-light); color: #15803D; }
.cp-status-declined { background: var(--arl-error-light); color: var(--arl-accent-dark); }
.cp-status-expired { background: var(--arl-surface); color: var(--arl-text-muted); }

/* On-time chips */
.cp-ontime-good { color: #15803D; font-weight: 600; }
.cp-ontime-mid { color: var(--arl-warning); font-weight: 600; }
.cp-ontime-low { color: var(--arl-accent); font-weight: 600; }

/* ── Empty / loading state ───────────────────────────────────── */
.cp-empty {
  padding: 32px 16px;
  text-align: center;
  color: var(--arl-text-muted);
  font-size: 14px;
}

/* ── Back button ─────────────────────────────────────────────── */
.cp-back {
  background: none;
  border: none;
  color: var(--arl-primary);
  font-family: var(--arl-font-accent);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 0;
  margin-bottom: 12px;
}
.cp-back:hover { text-decoration: underline; }

/* ── Detail view ─────────────────────────────────────────────── */
.cp-detail-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}
.cp-detail-title { font-size: 22px; margin-bottom: 4px; }
.cp-detail-meta { font-size: 13px; color: var(--arl-text-secondary); }
.cp-detail-actions { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }

.cp-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px;
  margin-bottom: 18px;
}
.cp-card {
  background: var(--arl-white);
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius-lg);
  padding: 16px;
}
.cp-card-title {
  font-family: var(--arl-font-accent);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--arl-text-muted);
  margin-bottom: 12px;
}

/* Reliability stat tiles */
.cp-stats { display: flex; gap: 20px; flex-wrap: wrap; }
.cp-stat-value {
  font-family: var(--arl-font-heading);
  font-size: 26px;
  font-weight: 700;
  color: var(--arl-primary);
  line-height: 1.1;
}
.cp-stat-label {
  font-size: 11px;
  color: var(--arl-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Field grid (profile display + edit) */
.cp-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 20px; }
.cp-field { display: flex; flex-direction: column; gap: 3px; }
.cp-field-full { grid-column: 1 / -1; }
.cp-field-label {
  font-family: var(--arl-font-accent);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--arl-text-muted);
}
.cp-field-value { font-size: 14px; color: var(--arl-text); }
.cp-field input, .cp-field select, .cp-field textarea {
  padding: 7px 10px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  font-family: var(--arl-font-body);
  font-size: 14px;
  color: var(--arl-text);
  background: var(--arl-white);
  width: 100%;
}
.cp-field input:focus, .cp-field select:focus, .cp-field textarea:focus {
  outline: none;
  border-color: var(--arl-primary);
  box-shadow: 0 0 0 3px rgba(0, 96, 175, 0.12);
}
.cp-field textarea { resize: vertical; min-height: 60px; }

/* Mini list (recent offers / bids on a carrier) */
.cp-mini-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.cp-mini-table th {
  text-align: left;
  padding: 6px 8px;
  font-family: var(--arl-font-accent);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--arl-text-muted);
  border-bottom: 1px solid var(--arl-border);
}
.cp-mini-table td {
  padding: 6px 8px;
  border-bottom: 1px solid var(--arl-border);
  color: var(--arl-text);
}
.cp-mini-table tr:last-child td { border-bottom: none; }
.cp-mini-empty { padding: 12px 8px; color: var(--arl-text-muted); font-size: 13px; }

/* Equipment chips */
.cp-equip-chip {
  display: inline-block;
  background: var(--arl-surface-light);
  border: 1px solid var(--arl-border);
  border-radius: 10px;
  padding: 1px 7px;
  font-size: 11px;
  color: var(--arl-text-secondary);
  margin: 0 3px 3px 0;
}

/* Modal body form spacing (create carrier) reuses global .modal* */
.cp-modal-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 16px; }
.cp-modal-fields .cp-field-full { grid-column: 1 / -1; }

@media (max-width: 640px) {
  .cp-fields, .cp-modal-fields { grid-template-columns: 1fr; }
}

/* ── Phase 2: shared pieces (the Find Capacity and Outreach tabs were removed 2026-09-29) ── */

/* Clickable carrier-name link (SPA-navigated) */
.cp-link { color: var(--arl-primary); font-weight: 600; cursor: pointer; }
.cp-link:hover { text-decoration: underline; }

/* Match form */
.cp-match-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  padding: 14px 16px;
  background: var(--arl-white);
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius-lg);
  margin-bottom: 16px;
}
.cp-match-form .cp-field { min-width: 120px; }
.cp-match-form input {
  padding: 7px 10px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  font-family: var(--arl-font-body);
  font-size: 14px;
  background: var(--arl-white);
  color: var(--arl-text);
}
.cp-match-form input:focus { outline: none; border-color: var(--arl-primary); box-shadow: 0 0 0 3px rgba(0,96,175,0.12); }

/* The Find Capacity result cards and the "Draft outreach" compose modal's extras
   (.cp-match-count/-card/-head/-headright/-stats/-reasons/-actions, .cp-dat-warn,
   .cp-source-badge) went with the tab on 2026-09-29. `.cp-match-form` above stays:
   the Vetting page's lookup form wears it. */

/* Offer detail body + banners + status message */
.cp-body-pre {
  white-space: pre-wrap;
  word-break: break-word;
  font-family: var(--arl-font-body);
  font-size: 14px;
  color: var(--arl-text);
  background: var(--arl-surface-light);
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  padding: 12px;
  margin: 0;
}
.cp-banner {
  padding: 10px 14px;
  border-radius: var(--arl-radius);
  font-size: 13px;
  margin-bottom: 14px;
}
.cp-banner-error { background: var(--arl-error-light); border: 1px solid #FCA5A5; color: var(--arl-accent-dark); }
.cp-banner-info { background: rgba(0,96,175,0.08); border: 1px solid rgba(0,96,175,0.25); color: var(--arl-primary-dark); }
.cp-banner-info code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }

/* ── Vetting (Highway) ──────────────────────────────────────── */
/* Failed / not-verified rule columns inside the verdict card. */
.cp-vet-rules { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px 32px; margin-top: 12px; }
.cp-vet-rules-h { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 4px; }
.cp-vet-rules ul { margin: 0; padding-left: 18px; font-size: 13px; }
.cp-vet-rules li { margin: 2px 0; }
/* Field value tones (shared with the profile/safety cards). */
.cp-tone-red   { color: var(--arl-error); font-weight: 600; }
.cp-tone-green { color: #15803D; font-weight: 600; }
.cp-tone-amber { color: var(--arl-warning); font-weight: 600; }

/* ── Vetting page restyle (2026-10-08) ───────────────────────────────────────────
 * The Carriers Directory's frame reused as-is: section.cp-dircard + .cp-dircard-head +
 * h3.cp-dircard-title. Only the page's own classes live here, all prefixed cp-vetpg-, so
 * nothing else on the site moves. Every var() names a token styles.css declares, with a
 * literal fallback. #cp-vet-view carries .cp-qm, so the .cp-qm table rules reach inside and
 * are reset below at a higher specificity. Every colour sits beside its word: the verdict
 * tag, its edge and the alert tag are never the only sign. */
.cp-vetpg-card { margin-bottom: 16px; min-width: 0; }
.cp-vetpg-body { padding: 14px; }
.cp-vetpg-src {
  margin-left: auto;
  font-size: 12px;
  color: var(--arl-text-secondary, #666666);
  white-space: nowrap;
}

/* The carrier name in text colour and the body font (styles.css gives every h2 the heading
 * font, the brand blue and capitals). */
.cp-vetpg-head { margin: 4px 0 12px; }
.cp-vetpg-name {
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0;
  color: var(--arl-text, #333333);
}

/* The verdict card: a 4px edge in the tone of Highway's word, beside that word in its tag. */
.cp-vetpg-verdict { border-left-width: 4px; }
.cp-vetpg--pass { border-left-color: var(--arl-success, #16A34A); }
.cp-vetpg--review { border-left-color: #F59E0B; }
.cp-vetpg--notpass { border-left-color: var(--arl-error, #E11A22); }
/* Grey: no verdict exists — the slot is off, or the lookup failed / found nothing (unknown). */
.cp-vetpg--off,
.cp-vetpg--unknown { border-left-color: var(--arl-border, #E0E0E0); }
.cp-vetpg-verdictline { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.cp-vetpg-says { font-size: 15px; font-weight: 600; color: var(--arl-text, #333333); }
/* FORGE's full check, when it differs from Highway's word: its own line, its own tag. */
.cp-vetpg-full {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  margin-top: 10px;
  padding: 8px 10px;
  border-radius: var(--arl-radius, 6px);
  background: var(--arl-surface-alt, #FAF9F9);
  border: 1px solid var(--arl-border, #E0E0E0);
  font-size: 14px;
}
.cp-vetpg-full-l { font-weight: 600; color: var(--arl-text, #333333); }
.cp-vetpg-full-why { color: var(--arl-text, #333333); }
.cp-vetpg-full-src { flex-basis: 100%; font-size: 12px; color: var(--arl-text-secondary, #666666); }
.cp-vetpg-sub { margin: 6px 0 0; font-size: 13px; color: var(--arl-text-secondary, #666666); }
.cp-vetpg-lead { margin: 0 0 10px; }
.cp-vetpg-clear { margin: 10px 0 0; font-size: 13px; color: #15803D; }
.cp-vetpg-notes { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.cp-vetpg-body .cp-vet-rules-h { text-transform: none; letter-spacing: 0; font-size: 13px; font-weight: 600; }
.cp-vetpg-sub code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }

/* Tags: the word always inside the colour. PASS green, REVIEW amber, NOT PASS red, nothing to
 * say grey, and a BASIC alert AMBER (Fabio, 2026-10-08: an alert does not change the verdict,
 * so it does not wear NOT PASS's red). */
.cp-vetpg-tag {
  display: inline-block;
  padding: 3px 12px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.cp-vetpg-tag--sm { padding: 2px 10px; font-size: 12px; font-weight: 600; letter-spacing: 0; }
.cp-vetpg-tag--xs { padding: 0 7px; font-size: 11px; font-weight: 600; letter-spacing: 0; vertical-align: 1px; }
.cp-vetpg-tag--pass { background: var(--arl-success-light, #DCFCE7); color: #15803D; }
.cp-vetpg-tag--review,
.cp-vetpg-tag--alert { background: var(--arl-warning-light, #FEF3C7); color: #92400E; }
.cp-vetpg-tag--notpass { background: var(--arl-error-light, #FEE2E2); color: var(--arl-accent-dark, #BD0E0E); }
.cp-vetpg-tag--off,
.cp-vetpg-tag--unknown { background: var(--arl-surface, #EEEEEE); color: var(--arl-text-secondary, #666666); }

/* Two cards side by side, one column on a phone. */
.cp-vetpg-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 0 16px; align-items: start; }

/* Labelled groups of label and value rows, read left to right like a sentence. */
.cp-vetpg-group + .cp-vetpg-group { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--arl-border, #E0E0E0); }
.cp-vetpg-gh {
  margin: 0 0 8px;
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--arl-text-secondary, #666666);
}
.cp-vetpg-rows {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(110px, 44%) minmax(0, 1fr);
  gap: 6px 14px;
  font-size: 14px;
}
.cp-vetpg-rows > dt { color: var(--arl-text-secondary, #666666); }
.cp-vetpg-rows > dd { margin: 0; color: var(--arl-text, #333333); overflow-wrap: anywhere; }
.cp-vetpg-rows > dd.cp-tone-red { color: var(--arl-error, #E11A22); }
.cp-vetpg-rows > dd.cp-tone-green { color: #15803D; }
.cp-vetpg-rows > dd.cp-tone-amber { color: var(--arl-warning, #D97706); }

/* The head band's written figures (the history counts). */
.cp-vetpg-figs { font-size: 13px; color: var(--arl-text-secondary, #666666); }
.cp-vetpg-n { font-weight: 600; color: var(--arl-text, #333333); }

/* Tables inside a card: the card is the frame (the Directory's rule), headings in the body
 * font and sentence case. (0,3,0) beats the .cp-qm .cp-mini-table rules (0,2,0). */
.cp-qm .cp-vetpg-card .cp-mini-table { border: 0; border-radius: 0; box-shadow: none; }
/* Only ARL's history tables (five and six columns, full width) keep a 560px floor and slide in
 * their scroll box on a phone. The Associated carriers table is three columns in a HALF-width
 * card: a 560px floor cut its "Why" column off at 1400px (539px of box), so it wraps instead. */
#cp-vet-history .cp-vetpg-card .cp-mini-table { min-width: 560px; }
.cp-qm .cp-vetpg-card .cp-mini-table thead th {
  padding: 8px 10px;
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-size: 12px;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  background: transparent;
}
.cp-qm .cp-vetpg-card .cp-mini-table th.cp-num { text-align: right; }
.cp-qm .cp-vetpg-card .cp-mini-table tbody td { padding: 8px 10px; }

/* The lookup form and the page subtitle: body font, sentence case. CSS only, index.html's
 * markup is untouched (the Carriers precedent). */
#cp-vet-view .cp-page-header .cp-count {
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--arl-text-secondary, #666666);
}
#cp-vet-form .cp-field-label {
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-size: 12px;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  color: var(--arl-text-secondary, #666666);
}
/* 640px, not 600px: os-glance-client.test.js reads the FIRST 600px block in this file. */
@media (max-width: 640px) {
  .cp-vetpg-grid { grid-template-columns: minmax(0, 1fr); }
  .cp-vetpg-rows { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .cp-vetpg-rows > dd { margin-bottom: 8px; }
  .cp-vetpg-src { margin-left: 0; }
}

/* ── Loads board ────────────────────────────────────────────── */
.cp-check { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--arl-text-secondary); white-space: nowrap; }
.cp-check input[type="number"] { padding: 4px 6px; border: 1px solid var(--arl-border); border-radius: 6px; }
/* The pickup date range (2026-10-13): "Pickup [from] to [to]" and three quick picks, one
   markup on Coverage's toolbar and Coverage - OS's tools (cpPickupRangeHTML). The quick
   picks are a segmented group pressed like the OS page's Your team / Every OC switch. */
.cp-range { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.cp-range-date {
  padding: 4px 6px;
  border: 1px solid var(--arl-border);
  border-radius: 6px;
  font-family: var(--arl-font-body);
  font-size: 13px;
  color: var(--arl-text);
  background: var(--arl-white);
}
.cp-range-date:focus { outline: none; border-color: var(--arl-primary); }
/* Since 2026-11-05 the quick picks are the kit's filter buttons (cpPickupRangeHTML): the
   pressed one carries `is-set`, the kit's blue. */
.cp-range-quick { display: inline-flex; gap: 6px; }
.cp-qbadge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 24px; padding: 1px 8px; border-radius: 999px;
  border: 1px solid var(--arl-border); color: var(--arl-text-muted); font-size: 12px;
}
.cp-qbadge-has { border-color: var(--arl-primary-dark); background: rgba(0,96,175,0.08); color: var(--arl-primary-dark); font-weight: 600; }

/* ── "vs posted": what the load finally cost against what we posted it for ────
   Only `under`/`at`/`over` are outcomes. `provisional` is deliberately the QUIETEST
   of the four — the load is still moving, so its rate can still change, and a
   number that will revise itself must not look like a result. Uses `--arl-*`
   (root-scoped), never `--qm-*` (declared on `.cp-qm`): an undefined var voids the
   whole shorthand, which is how the Sourcing tab strip silently lost its border. */
.cp-under { font-size: 11px; font-weight: 600; white-space: nowrap; }
.cp-under-under { color: #15803D; }
.cp-under-over { color: var(--arl-accent-dark); }
.cp-under-at { color: var(--arl-text-secondary); }
.cp-under-provisional { color: var(--arl-text-muted); font-weight: 400; font-style: italic; }
.cp-under-unknown { color: var(--arl-text-muted); font-weight: 400; }

/* ── Quote History ──────────────────────────────────────────── */
.cp-qstats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; margin-bottom: 16px; }
.cp-qstat { border: 1px solid var(--arl-border); border-radius: var(--arl-radius); padding: 12px 14px; background: var(--arl-surface-light); }
.cp-qstat-v { font-size: 22px; font-weight: 700; color: var(--arl-text); }
.cp-qstat-l { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--arl-text-muted); margin-top: 2px; }
/* Cards are all-time and span every lane; the table is one searched lane. Explain
   the gap rather than leave two correct-but-different numbers on screen. */
.cp-qtrunc { font-size: 12px; margin: -6px 0 14px; }
/* `.cp-oon-badge` (added by the core PR for Parade's "[Out of Network Carrier]"
   subject marker) is deliberately NOT carried here: this branch renders that signal
   through cpQuoteFlags as `qm-chip qm-chip-warn`, next to Lowest and At/under
   offer, so keeping the standalone badge would leave a dead selector and risk two
   markers on one row. */
.cp-qchips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.cp-qchip { border: 1px solid var(--arl-border); background: transparent; color: var(--arl-text-secondary); border-radius: 999px; padding: 4px 12px; font-size: 12px; font-weight: 500; cursor: pointer; }
.cp-qchip:hover { background: var(--arl-surface); }
.cp-qchip-on { background: var(--arl-text); color: #fff; border-color: var(--arl-text); }
/* Decision pills (share cp-status base). */
.cp-status-won { background: var(--arl-success-light); color: #15803D; }
.cp-status-lost { background: var(--arl-error-light); color: var(--arl-accent-dark); }
/* 🔴 cpStatusPill emits the RAW decision value as the class, and .cp-status carries
   no colour of its own — so a state with no rule here renders as bare uppercase text
   with no chip, and nothing errors. Renamed with the state (was .cp-status-countered)
   rather than added alongside it: a rule for a value the schema can no longer hold is
   dead style that still reads as coverage. */
.cp-status-negotiating { background: rgba(0,96,175,0.08); color: var(--arl-primary-dark); }
.cp-status-pending { background: var(--arl-surface); color: var(--arl-text-secondary); }

.cp-offer-msg { padding: 10px 14px; border-radius: var(--arl-radius); font-size: 13px; }
.cp-offer-msg-ok { background: var(--arl-success-light); border: 1px solid #86EFAC; color: #15803D; }
.cp-offer-msg-info { background: rgba(0,96,175,0.08); border: 1px solid rgba(0,96,175,0.25); color: var(--arl-primary-dark); }
.cp-offer-msg-error { background: var(--arl-error-light); border: 1px solid #FCA5A5; color: var(--arl-accent-dark); }

/* ══════════════════════════════════════════════════════════════════
   QM-styled tabs (Loads · Load detail · Vetting · Quote History)
   ------------------------------------------------------------------
   Ports the visual language of the standalone Carrier Quote Manager
   (Tailwind + zinc scale) into FORGE's light theme, at Fabio's request.

   EVERYTHING here is scoped under `.cp-qm`, which sits only on the four
   view containers this port adds. Keith's Carriers / Find Capacity /
   Outreach / Bids tabs share the same cp-* classes and must NOT shift,
   so no bare `.cp-table` / `.cp-card` selector may appear below.

   QM's brand tokens already match arl-theme, so this is card treatment,
   type scale and interaction feedback — not colour.
   ══════════════════════════════════════════════════════════════════ */

.cp-qm {
  /* zinc scale, the one QM leans on for everything non-brand */
  --qm-50:  #fafafa;
  --qm-100: #f4f4f5;
  --qm-200: #e4e4e7;
  --qm-300: #d4d4d8;
  --qm-400: #a1a1aa;
  --qm-500: #71717a;
  --qm-700: #3f3f46;
  --qm-900: #18181b;
  --qm-shadow:       0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --qm-shadow-hover: 0 4px 6px -1px rgba(0, 0, 0, 0.10), 0 2px 4px -2px rgba(0, 0, 0, 0.10);
  font-size: 14.5px;
}

/* ── Cards: white, lifted, and they respond to the cursor ───────── */
.cp-qm .cp-card,
.cp-qm .cp-qstat {
  background: #fff;
  border: 1px solid var(--qm-200);
  border-radius: 8px;
  box-shadow: var(--qm-shadow);
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
.cp-qm .cp-card:hover,
.cp-qm .cp-qstat:hover { box-shadow: var(--qm-shadow-hover); }

.cp-qm .cp-card-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.045em;
  color: var(--qm-500);
}
.cp-qm .cp-card-title .qm-i { width: 15px; height: 15px; color: var(--qm-400); flex: 0 0 auto; }

/* ── Stat tiles: QM's 2-up → 5-up responsive grid ───────────────── */
.cp-qm .cp-qstats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}
@media (min-width: 720px) {
  .cp-qm .cp-qstats { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
.cp-qm .cp-qstat { padding: 14px 16px; }
.cp-qm .cp-qstat-v { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; color: var(--qm-900); }
.cp-qm .cp-qstat-l {
  margin-top: 2px;
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--qm-500);
}

/* ── Tables: lighter header, real row hover ─────────────────────── */
.cp-qm .cp-table,
.cp-qm .cp-mini-table {
  background: #fff;
  border: 1px solid var(--qm-200);
  border-radius: 8px;
  box-shadow: var(--qm-shadow);
  overflow: hidden;
  font-size: 14px;
}
.cp-qm .cp-table thead th,
.cp-qm .cp-mini-table thead th {
  padding: 10px 14px;
  /* QM uses a medium weight here — the 700 reads heavy next to its cards */
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.05em;
  color: var(--qm-500);
  background: var(--qm-50);
  border-bottom: 1px solid var(--qm-200);
}
.cp-qm .cp-table tbody td,
.cp-qm .cp-mini-table tbody td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--qm-100);
}
.cp-qm .cp-table tbody tr,
.cp-qm .cp-mini-table tbody tr { transition: background-color 0.15s ease; }
.cp-qm .cp-table tbody tr:hover,
.cp-qm .cp-mini-table tbody tr:hover { background: var(--qm-50); }
.cp-qm .cp-table tbody tr.cp-row:hover { background: var(--qm-50); }

/* Identifiers read as data, not prose — QM sets every load ref in mono. */
.cp-qm .qm-mono {
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  font-weight: 600;
}

/* ── Inputs: rounded with a brand focus ring ────────────────────── */
.cp-qm input[type="text"],
.cp-qm input[type="number"],
.cp-qm .cp-select {
  border: 1px solid var(--qm-200);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 14px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.cp-qm input[type="text"]:focus,
.cp-qm input[type="number"]:focus,
.cp-qm .cp-select:focus {
  outline: none;
  border-color: var(--arl-primary);
  box-shadow: 0 0 0 3px rgba(0, 96, 175, 0.30);
}

/* ── Empty state: dashed frame + icon disc, not a bare sentence ─── */
.cp-qm .qm-empty {
  border: 1px dashed var(--qm-300);
  border-radius: 12px;
  background: #fff;
  padding: 48px 24px;
  text-align: center;
}
.cp-qm .qm-empty-icon {
  width: 56px; height: 56px;
  margin: 0 auto 14px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--qm-100);
  color: var(--qm-500);
}
.cp-qm .qm-empty-icon svg { width: 24px; height: 24px; }
.cp-qm .qm-empty-title { font-weight: 600; color: var(--qm-700); margin-bottom: 4px; }
.cp-qm .qm-empty-sub { font-size: 13px; color: var(--qm-500); }
/* The control an empty state offers, when describing the situation isn't enough. Inside
   .qm-empty so it inherits the block's centring rather than sitting under its padding. */
.cp-qm .qm-empty-action { margin-top: 12px; }

/* A real <button> wearing .qm-ext's link styling.
   Two things have to be undone or it reads as broken: the browser's button chrome
   (border, grey background, its own font) on top of link-coloured text, and .qm-ext's
   ` ↗` — that glyph promises an external destination, and these navigate inside the
   app or not at all.
   ⚠️ `.cp-oc-revert` below carries an identical reset for the same reason. Deliberately
   NOT consolidated here: exercising the revert button needs a load that has actually
   been reassigned, so folding it in would mean changing a control this change cannot
   look at. */
.cp-qm .cp-linkbtn {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
}
.cp-qm .cp-linkbtn::after { content: none; }

/* ── Skeletons: QM shows the shape of the data while it loads ───── */
.cp-qm .qm-skeleton {
  background: var(--qm-100);
  border-radius: 8px;
  animation: qm-pulse 1.6s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.cp-qm .qm-skeleton-row { height: 44px; margin-bottom: 8px; }
.cp-qm .qm-skeleton-tile { height: 74px; }
@keyframes qm-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

/* QM fades content in on mount; keeps a tab switch from feeling abrupt. */
.cp-qm .qm-fade { animation: qm-fade-up 0.35s ease; }
@keyframes qm-fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .cp-qm .qm-fade { animation: none; }
  .cp-qm .qm-skeleton { animation: none; }
}

/* ── Expandable load rows + backhaul panel (QM parity) ──────────── */
/* Read to a screen reader, never drawn. UNSCOPED since the slim board (2026-11-10), when the
   board's OC cell started hiding the name behind the initials: a scoped rule draws the text on
   any host without a .cp-qm ancestor (#170 shipped a control unstyled that way). */
.cp-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;
}
.cp-qm .qm-caret-cell { width: 34px; padding-right: 0 !important; }
.cp-qm .qm-caret {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--qm-400);
  transition: transform 0.18s ease, color 0.18s ease;
}
.cp-qm .qm-caret-i { width: 15px; height: 15px; }
.cp-qm .qm-caret-open { transform: rotate(90deg); color: var(--arl-primary); }
.cp-qm tr.cp-row-open { background: var(--qm-50); }
.cp-qm tr.cp-row-open td { border-bottom-color: transparent; }

.cp-qm tr.qm-expand > td {
  background: var(--qm-50);
  padding: 4px 16px 18px 48px;
  border-bottom: 1px solid var(--qm-200);
}
.cp-qm .qm-expand-inner { display: flex; flex-direction: column; gap: 16px; }
.cp-qm .qm-expand .cp-mini-table { box-shadow: none; }

/* ── The side panel: one opened load, ON TOP of the board (2026-11-10) ─────────────────
   Fabio replaced the dropdown that opened under a row with a panel on the right — "I want
   it to open on top of the main screen without compressing it". So it is fixed and floats:
   the board keeps its full width and every column, and the rows left of the panel stay
   clickable (a click there moves the panel to that load). Same layer as the email drawer
   (50): over the board and its sticky bars, under the vet and buy peeks (60), the sidebar
   on a phone (89/90) and every dialog (200+). The header, facts, tabs and links stay put;
   only the tab's body scrolls (.cp-lp-scroll).
   ⚠️ `display: flex` would beat the `hidden` attribute's own display, so [hidden] says none
   again — the panel is hidden, not removed, between loads. */
.cp-lp {
  position: fixed;
  top: var(--app-content-top);
  right: 0;
  bottom: 0;
  z-index: 50;
  width: clamp(460px, 40vw, 640px);
  display: flex;
  flex-direction: column;
  background: var(--fk-surface);
  border-left: 1px solid var(--fk-line);
  box-shadow: var(--fk-shadow-lg);
  font-family: var(--fk-font-ui);
}
.cp-lp[hidden] { display: none; }
.cp-lp-head { display: flex; align-items: flex-start; gap: 12px; padding: 16px 20px 0; }
.cp-lp-titles { flex: 1; min-width: 0; }
.cp-lp .cp-lp-title {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin: 0; font-family: var(--fk-font-ui); font-size: var(--fk-type-xl); font-weight: 700;
  line-height: 1.25; letter-spacing: 0; text-transform: none; color: var(--fk-ink);
}
.cp-lp-lane { margin-top: 2px; font-size: var(--fk-type-lg); color: var(--fk-ink); }
.cp-lp-sub { margin-top: 2px; font-size: var(--fk-type-sm); color: var(--fk-ink-3); }
.cp-lp-nav { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.cp-lp-pos { margin-right: 4px; font-size: var(--fk-type-xs); color: var(--fk-ink-3); white-space: nowrap; }
.cp-lp-iconbtn {
  width: 32px; height: 32px; padding: 0;
  border: 1px solid var(--fk-line); border-radius: var(--fk-radius-sm);
  background: var(--fk-surface); color: var(--fk-ink);
  font-size: var(--fk-type-lg); line-height: 1; cursor: pointer;
}
.cp-lp-iconbtn:hover:not(:disabled) { background: var(--fk-canvas); }
.cp-lp-iconbtn:focus-visible { outline: none; box-shadow: var(--fk-focus-ring); }
.cp-lp-iconbtn:disabled { opacity: 0.35; cursor: default; }
.cp-lp-facts { display: flex; flex-wrap: wrap; gap: 10px 22px; margin: 0; padding: 12px 20px; }
.cp-lp-facts > div { min-width: 0; }
.cp-lp-facts dt { font-size: var(--fk-type-xs); color: var(--fk-ink-3); }
.cp-lp-facts dd { margin: 0; font-size: var(--fk-type-sm); font-weight: 600; color: var(--fk-ink); }
.cp-lp-facts .cp-stop-note { font-weight: 400; }
.cp-lp .cp-ltabs { flex-shrink: 0; margin: 0; padding: 0 20px; overflow-x: auto; overflow-y: hidden; }
.cp-lp-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 14px 20px 20px; }
.cp-lp-foot { flex-shrink: 0; flex-wrap: wrap; padding: 10px 20px; border-top: 1px solid var(--fk-line); }
.cp-lp .cp-lp-title .qm-mono { font-size: inherit; }

/* The carrier rows in the panel — Carriers to call AND TFX's results, which draw the same
   `.qm-carrier-row` (checked on dev 2026-11-10). Their grid needs ~900px, so in the ~600px panel
   the DOT column wrapped a letter to a line, and TFX's phone and place broke apart. Stacked here,
   as narrow screens stack them below: the name (and TFX's tick box) on top, the MC/DOT beside the
   lane history or place, the contact, then the verdict, the rating and Create quote on ONE line.
   Two template rules because two grids compete: `.cp-lp.cp-qm .qm-carrier-row` (0,3,0) beats the
   board's `.cp-qm .qm-carrier-row` (0,2,0), and the call row's own (0,3,0) template needs
   `.cp-lp.cp-qm … .cp-call-row` (0,4,0), or order alone would decide — the #345 trap. */
.cp-lp.cp-qm .qm-carrier-row,
.cp-lp.cp-qm .qm-carrier-row.cp-call-row {
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  column-gap: 12px; row-gap: 4px; align-items: center;
}
.cp-lp.cp-qm .qm-carrier-row > .qm-carrier-main { grid-column: 1 / -1; }
.cp-lp.cp-qm .qm-carrier-row > .qm-carrier-id { grid-column: 1; }
.cp-lp.cp-qm .qm-carrier-row > .qm-carrier-hist { grid-column: 2 / -1; }
.cp-lp.cp-qm .qm-carrier-row > .qm-carrier-contact { grid-column: 1 / -1; }
.cp-lp.cp-qm .qm-carrier-row > .qm-carrier-vet { grid-column: 1 / 3; margin-top: 0; }
.cp-lp.cp-qm .qm-carrier-row > .cp-num { grid-column: 3; }
.cp-lp.cp-qm .qm-carrier-row > .qm-carrier-act { grid-column: 4; justify-self: end; margin-top: 0; }
/* TFX's rows in the panel: THREE lines a carrier (Fabio, 2026-11-10: "uses the space more
   efficiently" — they stood ~7 lines tall): the tick box, name and tags with the verdict and Vet at
   the right; MC/DOT beside the place, history and insights; the phone and email side by side.
   `.cp-tfx-row` (0,5,0 with its children) outranks the stacking rules above, which Carriers to
   call keeps. Outside the panel (the load page) the row keeps the board's columns. */
.cp-lp.cp-qm .qm-carrier-row.cp-tfx-row {
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas: "main main vet" "id hist hist" "contact contact contact";
  column-gap: 12px; row-gap: 2px; align-items: center;
}
.cp-lp.cp-qm .qm-carrier-row.cp-tfx-row > .qm-carrier-main { grid-area: main; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.cp-lp.cp-qm .qm-carrier-row.cp-tfx-row > .qm-carrier-main > .qm-carrier-why { margin: 0; }
.cp-lp.cp-qm .qm-carrier-row.cp-tfx-row > .qm-carrier-id { grid-area: id; }
.cp-lp.cp-qm .qm-carrier-row.cp-tfx-row > .qm-carrier-hist { grid-area: hist; }
.cp-lp.cp-qm .qm-carrier-row.cp-tfx-row > .qm-carrier-contact { grid-area: contact; }
.cp-lp.cp-qm .qm-carrier-row.cp-tfx-row > .qm-carrier-vet { grid-area: vet; justify-self: end; margin: 0; }
.cp-lp.cp-qm .qm-carrier-row.cp-tfx-row > .cp-num { display: none; }
/* The phone and the email on ONE line: the shared contact cell stacks them with a <br>. */
.cp-lp.cp-qm .cp-tfx-row .cp-contact-cell { display: flex; flex-wrap: wrap; gap: 0 14px; }
.cp-lp.cp-qm .cp-tfx-row .cp-contact-cell > br { display: none; }
/* "How TFX picks carriers": the kit's fold, tight above the list. */
.cp-lp .cp-tfx-how { margin: 0 0 8px; }

/* The Quotes table in the panel: its seven columns fold into a card per carrier — the name and
   its checks beside the price, the contact beside where and when the price came, then Book…,
   Passed and Reply… (the mock Fabio approved). The MARKUP is the board's own, so every button,
   handler and tour lookup is unchanged; only the layout folds. The header row stays for screen
   readers. A carrier's earlier prices (tr.qm-expand) open under its card; `.hidden` (styles.css,
   !important) still closes them. */
.cp-lp .cp-qtable, .cp-lp .cp-qtable > tbody { display: block; width: 100%; }
.cp-lp .cp-qtable > thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.cp-lp .cp-qtable > tbody > tr:not(.qm-expand) {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) auto;
  grid-template-areas: "caret carrier price" ". contact source" ". contact received" ". decide decide";
  /* Room on the right (Fabio, 2026-11-10: "there is not space with the border"): the price, the
     source and the date are right-aligned, and ran into the card's border. */
  column-gap: 12px; row-gap: 4px; padding: 12px 16px 12px 0;
  border-bottom: 1px solid var(--fk-line);
}
.cp-lp .cp-qtable > tbody > tr > td { display: block; padding: 0; border: 0; }
.cp-lp .cp-qtable > tbody > tr > td:nth-child(1) { grid-area: caret; width: auto; }
.cp-lp .cp-qtable > tbody > tr > td:nth-child(2) { grid-area: carrier; }
.cp-lp .cp-qtable > tbody > tr > td:nth-child(3) { grid-area: contact; }
.cp-lp .cp-qtable > tbody > tr > td:nth-child(4) { grid-area: price; font-size: var(--fk-type-lg); font-weight: 700; color: var(--fk-ink); }
.cp-lp .cp-qtable > tbody > tr > td:nth-child(5) { grid-area: source; text-align: right; }
.cp-lp .cp-qtable > tbody > tr > td:nth-child(6) { grid-area: received; text-align: right; color: var(--fk-ink-3); }
.cp-lp .cp-qtable > tbody > tr > td:nth-child(7) { grid-area: decide; }
.cp-lp .cp-qtable > tbody > tr.qm-expand { display: block; }
.cp-lp .cp-qtable > tbody > tr.qm-expand > td { display: block; padding: 0 16px 12px 34px; }

/* A HOT load is the whole row, tinted, with a red edge (Fabio, 2026-11-10: "replace the HOT icon
   for a color coded highlight of the whole row"). The edge is a SHAPE as well as a colour, for
   anyone who cannot tell the tint; who marked it rides on the row's title. Before the open-row
   rules below, so the row the panel shows still reads as the open one. */
.cp-table tbody tr.cp-row.cp-row-hot > td { background: var(--fk-broken-bg); }
.cp-table tbody tr.cp-row.cp-row-hot > td:first-child { box-shadow: inset 4px 0 0 var(--fk-red-600); }
/* Pickup: the date, then the countdown on the same line. */
.cp-sp-pickup { white-space: nowrap; }
.cp-sp-pickup .cp-risk-slot:not(:empty) { margin-left: 6px; }
/* The row whose load the panel shows: a blue edge, on both boards. */
.cp-table tbody tr.cp-row.cp-row-open > td { background: var(--fk-moving-bg); }
.cp-table tbody tr.cp-row.cp-row-open > td:first-child { box-shadow: inset 4px 0 0 var(--fk-blue-600); }
/* A phone: the panel is the whole screen, and Esc or × goes back to the board. */
@media (max-width: 800px) {
  .cp-lp { width: 100vw; border-left: 0; }
}

/* ── A collapsed carrier's own quotes, inside the Active-quotes panel ──────────
   The Active-quotes rows collapse to one per carrier at their LOWEST price
   (Fabio, 2026-09-15). This is the disclosure that keeps the individual messages
   reachable — which matters because several REPS at one carrier quote separately,
   so the collapsed row's contact is only one of the people who wrote in.
   ⚠️ `.cp-qx-detail` relies on styles.css's `.hidden { display: none !important }`
   to stay closed; the handler toggles that class rather than repainting. Do not
   add a competing `display` here — a rule that merely PARSES and matches can still
   lose on specificity, which is how a panel once clipped 107 of 112 carriers. */
.cp-qm .cp-qx-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 0; padding: 0; cursor: pointer;
}
.cp-qm .cp-qx-inner { margin: 2px 0 0; background: transparent; }
.cp-qm .cp-qx-inner th {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--qm-500); padding-top: 0;
}
.cp-qm .cp-qx-inner td { padding-top: 4px; padding-bottom: 4px; }
.cp-qm tr.cp-qx-detail > td { padding: 4px 16px 14px 48px; }

/* ── Per-load detail tabs (inside an expanded row) ─────────────────────────────
   Each tab answers a different question about the load, so only one shows at a
   time instead of three stacked sections. Underline-style rather than the pill
   treatment used by the Quote History decision chips (.cp-qchip) — these switch a
   panel within a row, and reusing the pill look would suggest they filter. */
.cp-qm .cp-ltabs,
.cp-sourcing .cp-stabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--qm-200);
  margin-bottom: -6px;
}
.cp-qm .cp-ltab,
.cp-sourcing .cp-ltab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: none;
  background: transparent;
  padding: 7px 12px;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  font-family: var(--arl-font-accent);
  font-size: 12px;
  font-weight: 600;
  color: var(--qm-500);
  cursor: pointer;
  white-space: nowrap;
}
.cp-qm .cp-ltab:hover,
.cp-sourcing .cp-ltab:hover { color: var(--arl-text); background: var(--arl-surface-light); }
.cp-qm .cp-ltab:focus-visible,
.cp-sourcing .cp-ltab:focus-visible { outline: 2px solid var(--arl-primary); outline-offset: -2px; }
.cp-qm .cp-ltab-on,
.cp-sourcing .cp-ltab-on {
  color: var(--arl-primary-dark);
  border-bottom-color: var(--arl-primary);
  background: transparent;
}
/* Count badge in the label, so what's behind a tab is visible without opening it. */
.cp-qm .cp-ltab-n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--qm-100, var(--arl-surface));
  color: var(--qm-500);
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.cp-qm .cp-ltab-on .cp-ltab-n { background: rgba(0, 96, 175, 0.12); color: var(--arl-primary-dark); }
.cp-qm .cp-ltab-panel { display: flex; flex-direction: column; gap: 10px; }
.cp-qm .cp-ltab-sub { font-size: 12px; color: var(--qm-500); }
.cp-qm .qm-inline-empty {
  margin: 0;
  border: 1px dashed var(--qm-200);
  border-radius: 8px;
  background: #fff;
  padding: 12px 16px;
  font-size: 13px;
  color: var(--qm-500);
}
.cp-qm .qm-expand-link {
  align-self: flex-start;
  font-size: 12px; font-weight: 600;
  color: var(--qm-500); text-decoration: none;
}
.cp-qm .qm-expand-link:hover { color: var(--arl-primary); text-decoration: underline; }

.cp-qm .qm-bh-list {
  border: 1px solid var(--qm-200);
  border-radius: 8px;
  background: #fff;
  overflow: hidden;
}
.cp-qm .qm-bh-row {
  display: grid;
  grid-template-columns: 118px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--qm-100);
}
.cp-qm .qm-bh-row:last-child { border-bottom: none; }
.cp-qm .qm-bh-dist { margin-top: 2px; font-size: 11px; color: var(--qm-500); }
.cp-qm .qm-bh-lane { font-size: 14px; font-weight: 500; }
.cp-qm .qm-bh-meta { margin-top: 2px; font-size: 12px; color: var(--qm-500); }
@media (max-width: 720px) {
  .cp-qm .qm-bh-row { grid-template-columns: 1fr; gap: 4px; }
  .cp-qm tr.qm-expand > td { padding-left: 16px; }
}

/* ── Sortable headers, signal chips, external links ─────────────── */
.cp-qm th.qm-sortable { cursor: pointer; user-select: none; }
.cp-qm th.qm-sortable:hover { color: var(--qm-700); }
.cp-qm .qm-sort-i { font-size: 9px; color: var(--arl-primary); }

.cp-qm .qm-chip {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  vertical-align: middle;
  white-space: nowrap;
}
.cp-qm .qm-chip-good { background: var(--arl-success-light, #DCFCE7); color: #15803D; }
.cp-qm .qm-chip-warn { background: #FEF3C7; color: #92400E; }

.cp-qm .qm-ext {
  font-size: 12px;
  font-weight: 500;
  color: var(--arl-primary);
  text-decoration: none;
  white-space: nowrap;
}
.cp-qm .qm-ext:hover { text-decoration: underline; }
.cp-qm .qm-ext::after { content: ' ↗'; font-size: 10px; }
.cp-qm .qm-expand-links { display: flex; align-items: center; gap: 16px; }

/* ── OC coverage cell ─────────────────────────────────────────────
   The select sits inline in a dense table row, so it is sized down to the row's
   type scale rather than the browser default (which is tall enough to stretch
   every row on the board). max-width keeps a long display name from widening the
   column past its share of the table.                                        */
.cp-qm .cp-oc-cell { white-space: normal; }
.cp-qm .cp-oc-select {
  font-family: inherit;
  font-size: 12px;
  padding: 3px 6px;
  max-width: 150px;
  border: 1px solid var(--arl-border, #E4E4E7);
  border-radius: 5px;
  background: #fff;
  color: inherit;
}
.cp-qm .cp-oc-select:hover { border-color: var(--arl-primary); }
.cp-qm .cp-oc-select:focus-visible { outline: 2px solid var(--arl-primary); outline-offset: 1px; }
/* Reuses .qm-ext's link styling but is a real <button>, so the external-link ↗ that
   .qm-ext appends would be a lie — this navigates nowhere. */
.cp-qm .cp-oc-revert {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
}
.cp-qm .cp-oc-revert::after { content: none; }
/* (The select and Revert render on Coverage - OS only since 2026-09-23; the Coverage
   board draws the OC as text. The 🔒 "supervisor-only" marker went with that change.) */

/* ── Lane search + rate suggestion (QM's Quote History model) ───── */
.cp-qm .qm-lane-bar {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px;
  padding: 14px 16px; margin-bottom: 12px;
  background: #fff; border: 1px solid var(--qm-200); border-radius: 8px;
  box-shadow: var(--qm-shadow);
}
.cp-qm .qm-lane-f { display: flex; flex-direction: column; gap: 4px; }
.cp-qm .qm-lane-f > span {
  font-size: 10.5px; font-weight: 500; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--qm-500);
}
.cp-qm .qm-lane-f input, .cp-qm .qm-lane-f select { min-width: 190px; }
.cp-qm .qm-lane-narrow input { min-width: 80px; width: 80px; }

.cp-qm .qm-recent { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 14px; }
.cp-qm .qm-recent:empty { margin-bottom: 0; }
.cp-qm .qm-recent-label {
  font-size: 10.5px; font-weight: 500; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--qm-500);
}
.cp-qm .qm-recent-chip {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 4px 10px; border-radius: 999px; cursor: pointer;
  background: #fff; border: 1px solid var(--qm-200);
  font-size: 12.5px; color: var(--qm-700);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.cp-qm .qm-recent-chip:hover { border-color: var(--arl-primary); background: var(--qm-50); }
.cp-qm .qm-recent-meta { font-size: 10.5px; color: var(--qm-400); }

.cp-qm .qm-suggest {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px;
  padding: 16px 18px; margin: 0 0 16px;
  background: #fff; border: 1px solid var(--qm-200);
  border-left: 3px solid var(--arl-primary);
  border-radius: 8px; box-shadow: var(--qm-shadow);
}
.cp-qm .qm-suggest-l {
  font-size: 10.5px; font-weight: 500; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--qm-500);
}
.cp-qm .qm-suggest-v {
  font-size: 30px; font-weight: 700; letter-spacing: -0.02em;
  color: var(--arl-primary-dark, #00437a); line-height: 1.1;
}
.cp-qm .qm-suggest-range { font-size: 12.5px; color: var(--qm-500); }
.cp-qm .qm-suggest-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 12px; }
.cp-qm .qm-chip-neutral { background: var(--qm-100); color: var(--qm-700); }
.cp-qm .qm-conf-high { background: #DCFCE7; color: #15803D; }
.cp-qm .qm-conf-medium { background: #FEF3C7; color: #92400E; }
.cp-qm .qm-conf-low { background: var(--qm-100); color: var(--qm-500); }

/* ── Inline vet chip + quote age ──────────────────────────────────
   ⚠️ The chip is deliberately NOT scoped to `.cp-qm`, and the verdict label below is
   the precedent. It renders on four surfaces and only two of them are inside that
   class: `#cp-coverage-view` and `#cp-quotes-view` carry it, while
   `#cp-carriers-view` has no class at all and the Tracking board's host is
   `.cp-tracking` (built at runtime). Scoped, the rule simply did not match there —
   so the Vet control was a pill on two screens and a bare blue link on the other
   two, on the affordance that leads to the dispatch decision.
   Fixed by de-scoping rather than by adding `.cp-qm` to those hosts: that class
   carries ~130 rules and would restyle both tables wholesale. `--qm-200` is declared
   on `.cp-qm` and `.cp-sourcing` (`.cp-tracking` too until 2026-10-09) but not at `:root`, so it takes a
   literal fallback for the hosts that declare nothing — a `var()` that resolves to
   nothing voids the whole `border` shorthand, which is how the tab strip lost its
   bottom rule once already. Safe to widen: `qm-vet-chip` appears in no file outside
   this module's own CSS and JS. */
.qm-vet-chip {
  display: inline-block; margin-left: 6px; padding: 1px 8px;
  border: 1px solid var(--qm-200, #e4e4e7); border-radius: 999px;
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.02em;
  color: var(--arl-primary); text-decoration: none; vertical-align: middle;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.qm-vet-chip:hover { background: rgba(0, 96, 175, 0.08); border-color: var(--arl-primary); }
.cp-qm .qm-age {
  display: inline-block; margin-left: 6px;
  font-size: 10.5px; font-weight: 600; color: var(--qm-400); vertical-align: middle;
}
.cp-qm .qm-age-stale { color: #B45309; }

/* ── Load page: the Stops card (2026-10-19) ─────────────────────────
   One block per TAI stop, in order. Instructions and notes keep TAI's line breaks. */
.cp-ldstops { display: flex; flex-direction: column; gap: 12px; }
.cp-ldstop { border: 1px solid var(--arl-border); border-radius: var(--arl-radius); padding: 10px 12px; }
.cp-ldstop-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; font-size: 14px; }
.cp-ldstop-num {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; border-radius: 10px;
  background: var(--arl-border); font-size: 11px; font-weight: 700;
}
.cp-ldstop-type { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--arl-text-muted); }
.cp-ldstop-grid { display: grid; grid-template-columns: 1.3fr 1fr 1.3fr; gap: 8px 16px; font-size: 13px; }
.cp-ldstop-text { margin-top: 8px; font-size: 13px; }
.cp-ldstop-text > div { white-space: pre-line; overflow-wrap: anywhere; }
@media (max-width: 760px) { .cp-ldstop-grid { grid-template-columns: 1fr; } }

/* ── Load page: References and Freight cards (2026-10-20) ─────────── */
.cp-ldrefs { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 16px; font-size: 13px; }
.cp-ldref { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cp-ldref .qm-mono { overflow-wrap: anywhere; }
.cp-ldfreights { display: flex; flex-direction: column; gap: 10px; font-size: 13px; }
.cp-ldfreight > div:first-child { overflow-wrap: anywhere; }
.cp-ldhazmat {
  display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 4px;
  background: var(--arl-error-light, #FEE2E2); color: var(--arl-accent-dark, #BD0E0E); border: 1px solid #FCA5A5;
  font-size: 11px; font-weight: 700; letter-spacing: 0.02em; white-space: nowrap;
}

/* ── Stop times on the board (Appt / FCFS) ──────────────────────────
   The time sits under the date as a second line so the Pickup and Delivery
   columns stay narrow enough to keep the lane and customer visible. */
.cp-qm .cp-stop-note {
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--arl-text-muted);
  white-space: nowrap;
}
/* Appt reads as a commitment, FCFS as informational — deliberately NOT green/red:
   neither is good or bad news, they're different instructions to the driver, and
   colouring them as outcomes would compete with the Lowest / Out-of-network chips
   that DO carry a judgement. */
.cp-qm .qm-chip-appt { background: #E0E7FF; color: #3730A3; }
.cp-qm .qm-chip-fcfs { background: var(--qm-100, #F4F4F5); color: var(--qm-700, #3F3F46); }

/* Turned-down prices: present but visibly secondary. */
.cp-qbadge-rejected {
  border-color: var(--arl-border);
  background: transparent;
  color: var(--arl-text-muted);
  text-decoration: line-through;
}
.cp-qm .cp-row-rejected { opacity: 0.62; }

/* ── Highway verdict label ────────────────────────────────────────
   PASS / REVIEW / NOT PASS beside the Vet control, on every surface that lists a
   carrier. Deliberately louder than the neighbouring chips: this is the one signal a
   rep must not misread at a glance, and it is the difference between dispatching a
   carrier and not. Tones borrow the existing semantic tokens so it matches the vet
   page's own colouring rather than inventing a third palette. */
.cp-vetv {
  display: inline-block;
  font-family: var(--arl-font-accent);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 2px 7px;
  border-radius: 10px;
  white-space: nowrap;
  vertical-align: middle;
}
.cp-vetv-pass { background: var(--arl-success-light); color: #15803D; }
.cp-vetv-warn { background: var(--arl-warning-light, #FEF3C7); color: #92400E; }
.cp-vetv-fail { background: var(--arl-error-light); color: var(--arl-accent-dark); }
/* Unknown and in-flight are visually QUIET — neither reassuring nor alarming. An
   absent verdict must not read as a clear one, and must not cry wolf either. */
.cp-vetv-unknown { background: var(--arl-surface); color: var(--arl-text-secondary); }
.cp-vetv-checking { background: transparent; color: var(--arl-text-muted); font-weight: 600; text-transform: none; letter-spacing: 0; }
.cp-vetv-none { background: transparent; color: var(--arl-text-muted); font-weight: 400; }

/* ── The "Carriers to call" summary bar ──────────────────────────────────────
   One line above the shortlist: are they clear to dispatch, and can we reach them.
   ⚠️ These read `--qm-*` variables, which are declared on `.cp-qm` rather than on
   `:root` — the same trap that voided the Sourcing tab strip's border, where an
   invalid colour silently killed the whole shorthand and a structural test passed
   throughout. Everything here uses `--arl-*`, which IS root-scoped, so the bar
   renders wherever the panel is mounted. */
.cp-call-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  align-items: baseline;
  margin: 0 0 8px;
  font-size: 11px;
}
.cp-call-safety { font-weight: 700; }
/* Quiet while in flight: a pending count must not look like a finding. */
.cp-call-safety-pending { color: var(--arl-text-muted); font-weight: 600; }
.cp-call-safety-clear { color: #15803D; }
.cp-call-safety-warn { color: #92400E; }
.cp-call-safety-bad { color: var(--arl-accent-dark); }
.cp-call-reach { color: var(--arl-text-secondary); }

/* ── The full lane list, scrolled rather than truncated (2026-09-09) ──────────
   The panel used to show five carriers and a line saying how many more existed.
   It now lists every carrier who has RUN the lane, which is 128 on the busiest
   open lane, so the rows need their own scroll rather than pushing the tab strip
   and the load rows below off screen.

   ⚠️ `--arl-*` only. `--qm-*` is declared on `.cp-qm`/`.cp-sourcing`, NOT on
   `:root`, and a var() that resolves to nothing voids its whole declaration —
   which is how the Sourcing tab strip lost its border while a structural test
   stayed green. A literal fallback is given anyway, so the border survives even
   where the token is out of scope. */
/* 🔴 THE SELECTOR IS COMPOUND ON PURPOSE, and a single class does NOT work here.
   `.cp-qm .qm-bh-list` sets `overflow: hidden` and has TWO-class specificity (0,2,0);
   a bare `.cp-call-scroll` is (0,1,0) and loses however late it is declared. Measured
   in a real browser: the rule parsed, sat in cssRules, and computed `overflow-y:
   hidden` — so the box clipped 107 of 112 carriers with no way to reach them, which is
   worse than the five-row list this replaced. `.qm-bh-list.cp-call-scroll` is also
   (0,2,0) and wins on order, and it does not depend on a `.cp-qm` ancestor — which
   matters because two of this module's four hosts do not have one.
   ⚠️ The structural test asserting the rule EXISTED passed the entire time. */
.qm-bh-list.cp-call-scroll {
  max-height: 420px;
  overflow-y: auto;
  /* Contains the scroll to this panel: without it a trackpad gesture that reaches
     the end of the list keeps going and scrolls the whole board out from under a
     rep who is reading the rows. */
  overscroll-behavior: contain;
  /* A scrolled box needs an edge, or its last visible row reads as the last row. */
  border-bottom: 1px solid var(--arl-border, #e4e4e7);
}
.cp-call-count {
  margin: 0 0 6px;
  font-size: 11px;
  color: var(--arl-text-secondary, #52525b);
}

/* The verdict + Vet button travel together, label first (left), so the eye hits the
   answer before the control — the order asked for. */
.qm-carrier-vet { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }

/* Outreach replies — the pre-posting channel, in its own slot beside the posting's
   Active count so the two phases don't read as one number. Dashed rather than solid:
   distinguishable from Active at a glance without competing with it for attention,
   since it will read 0 on every row until outreach send is configured. */
.cp-qbadge-outreach {
  border-style: dashed;
  border-color: var(--arl-border);
  background: transparent;
  color: var(--arl-text-muted);
}

.cp-qm .cp-contact-cell { font-size: 12px; line-height: 1.5; }
.cp-qm .cp-contact-link { color: var(--arl-primary-dark); text-decoration: none; }
.cp-qm .cp-contact-link:hover { text-decoration: underline; }

/* ── Vet hover snapshot ─────────────────────────────────────────────
   Appended to <body> rather than nested in the row, because the expansion and the
   table both establish overflow/stacking contexts that would clip it. */
.cp-vet-peek {
  position: absolute;
  z-index: 60;
  width: 290px;
  padding: 10px 12px;
  border: 1px solid var(--arl-border);
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 8px 24px rgba(0,0,0,0.14);
  font-size: 12px;
  line-height: 1.45;
  /* Purely informational, and it follows the pointer — never a click target, so it
     must not swallow the mouseout that closes it. */
  pointer-events: none;
}
.cp-vet-peek[hidden] { display: none; }
.cp-vet-peek-head { font-weight: 700; font-size: 12.5px; margin-bottom: 2px; }
.cp-vet-peek-row { margin-top: 3px; }
.cp-vet-peek-sub { font-size: 11px; color: var(--arl-text-muted); word-break: break-all; }
.cp-vet-peek-div { height: 1px; background: var(--arl-border); margin: 8px 0 6px; }
.cp-vet-peek-foot { margin-top: 8px; font-size: 10.5px; }

/* ── Buy-rate peek (Coverage → Target cell) ──────────────────────────────────
   Shares .cp-vet-peek for position, shadow and pointer-events; these are only the
   lines specific to the buy comparison.

   ⚠️ COLOUR IS REINFORCEMENT, NEVER THE MESSAGE. Every verdict states its direction
   in words ("BELOW what we normally pay"), because this module has already shipped a
   bug where meaning lived in CSS — a separator drawn in ::before made a 4.7 rating
   read as "4.76" once the rule was dropped. A reader with the stylesheet stripped,
   or colour-blind, must lose nothing here. */
.cp-buy-peek { width: 300px; }

/* The Target figure, made hoverable, focusable and — since 2026-09-29 — clickable:
   a click opens the rate pop-up. A dotted underline is the only hint that it holds
   something — deliberately quiet, because every row has one. The pointer cursor is
   what says "click me" now that it does something; `help` promised only a tooltip. */
.cp-buypeek-trigger {
  border-bottom: 1px dotted var(--arl-text-muted);
  cursor: pointer;
}
.cp-buypeek-trigger:focus-visible {
  outline: 2px solid var(--arl-primary);
  outline-offset: 2px;
  border-radius: 2px;
}

.cp-buypeek-plan { margin-top: 2px; }
.cp-buypeek-usual { font-size: 13px; }
.cp-buypeek-verdict { margin-top: 6px; font-weight: 600; }
.cp-buypeek-light  { color: var(--arl-warning); }  /* plan under the going rate */
.cp-buypeek-rich   { color: var(--arl-success); }  /* room to negotiate down */
.cp-buypeek-inline { color: var(--arl-text-secondary); }
.cp-buypeek-none   { color: var(--arl-text-muted); font-weight: 400; }
.cp-buypeek-thin   { color: var(--arl-warning); }

/* ── Rate pop-up (click the Buy Rate) ─────────────────────────────────────────
   The panel itself borrows Quote Tracker's lane-panel classes (qt-lane-*, qt-org-*,
   qt-loads-*) from quote-tracker.css, so it reads like the screen it copies; a test
   pins that each one still exists there. These rules are only the pop-up's own frame
   and the lines the Quote Tracker panel does not have.

   ⚠️ `.cp-paidpop .modal-content` (two classes) beats the base `.modal-content`
   (one) on specificity, not on source order — carrier-procurement.css loads after
   styles.css today, but the width must not depend on that staying true. */
.cp-paidpop .modal-content { width: 94%; max-width: 980px; }
/* The dialog box takes focus on open and on a click inside (tabindex="-1"), so it is
   not a control — its controls keep their own focus rings. */
.cp-paidpop .modal-content:focus { outline: none; }

/* ── Load pop-out (a load number on Coverage or Coverage - OS, 2026-10-29) ─────────
   The load page, drawn in a dialog over the board (cpOpenLoadPop). It wears the page's
   look because #cp-loadpop stands beside #cp-load-detail-view in the "One FORGE look"
   lists below, and its body carries .cp-qm as the page's view does.
   `#cp-loadpop .modal-content` (an id) beats the base `.modal-content` 700px width on
   specificity, as the rate pop-up's rule does. */
#cp-loadpop .modal-content { width: 94%; max-width: 1100px; }
#cp-loadpop .modal-content:focus { outline: none; }
/* A load runs long (stops, quotes, replies): the body scrolls and the title bar and the
   footer stay put, so × and Close are always on screen. */
#cp-loadpop .modal-content { display: flex; flex-direction: column; overflow: hidden; }
#cp-loadpop .modal-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* The page's grey behind the cards, so they read as cards here too. */
#cp-loadpop .modal-body { background: var(--arl-surface-light); }
/* Smaller than the page's 26px title. Two classes after the id: the look list's
   `:is(#cp-load-detail-view, #cp-loadpop, …) h2.cp-detail-title` weighs one id, one class
   and one element too, and comes later in this file, so an equal weight would lose. */
#cp-loadpop .modal-body h2.cp-detail-title { font-size: 22px; }
/* "Open as a full page" on the left, Close on the right. */
#cp-loadpop .modal-footer { justify-content: space-between; align-items: center; }
.cp-paidpop-sub { margin: -6px 0 12px; font-size: 12.5px; color: var(--arl-text-muted); }
.cp-paidpop-plan { margin: 0 0 14px; font-size: 14px; }
.cp-paidpop-plan .cp-buypeek-verdict { margin-top: 4px; font-size: 13px; }
.cp-paidpop-plan .cp-buypeek-thin { margin-top: 4px; font-size: 12px; }
.cp-paidpop-tier-note { padding: 8px 12px 10px; font-size: 12px; color: var(--arl-text-muted); }
.cp-paidpop-loads-btn { margin: 4px 12px 10px; }
/* The clickable count in a tier header ("7 loads ▸"). Its size, weight and colour come
   from Quote Tracker's .qt-lane-count / .qt-lane-count-link; this only strips the
   button chrome. No `font` shorthand: it would reset those borrowed sizes. */
.cp-paidpop .cp-paidpop-count { background: none; border: 0; padding: 0; font-family: inherit; }
.cp-paidpop .cp-paidpop-count:focus-visible { outline: 2px solid var(--arl-primary); outline-offset: 2px; border-radius: 2px; }
/* Quote Tracker's load table never wraps — it has its own full-screen dialog. In a
   980px pop-up the lane, customer and carrier columns wrap instead of pushing $/mi
   off the right edge; the figures stay on one line (0,3,0 beats 0,2,2 below). */
.cp-paidpop .qt-loads-table tbody td { white-space: normal; }
.cp-paidpop .qt-loads-table .cp-num { text-align: right; white-space: nowrap; }
.cp-paidpop-map { margin-top: 14px; }
/* The market-rate cards (Triumph, DAT) under the plan line — 2026-10-08, "Both now". The
   cards themselves are Quote Tracker's (.qt-gs-market / .qt-dat-market from
   quote-tracker.css); these rules only space them and draw the Pull row under each.
   ⚠️ Compact on purpose: both cards sit ABOVE "We normally pay", which must stay above
   the fold at 1366×900 (measured by gen-paid-popup-harness). */
.cp-mktpull { margin: 0 0 12px; }
.cp-mktpull:empty { display: none; }
.cp-mktpull-card { margin-bottom: 6px; }
.cp-mktpull .cp-mktpull-card .qt-dat-market,
.cp-mktpull .cp-mktpull-card .qt-gs-market { margin-bottom: 3px; }
/* The Pull button: INSIDE its card on the right, filled red like Quote Tracker's Pull — its
   own rule (Quote Tracker's .qt-rate-refresh is Keith's, and the board's click wiring keys
   on its own class). Tokens only. */
.cp-mktpull-btn.btn {
  flex: none; margin-left: auto; padding: 2px 10px; font-weight: 700;
  color: var(--arl-white); background: var(--arl-error); border: 1px solid var(--arl-error);
}
.cp-mktpull-btn.btn:hover:not(:disabled) { background: var(--arl-accent-dark); border-color: var(--arl-accent-dark); }
.cp-mktpull-btn.btn:disabled { opacity: 0.6; cursor: default; }
/* The note under each card: full text colour (it carries the cost of a click). */
.cp-mktpull-note { padding: 0 2px; font-size: 12px; color: var(--arl-text); }
.cp-mktpull-note:empty { display: none; }
.cp-mktpull-note--warn { color: var(--arl-error); }
.cp-mktpull-note--stale { color: var(--arl-warning); font-weight: 600; }
/* A stale pull is marked on the card itself, even collapsed — Quote Tracker's red edge. */
.cp-mktpull-card--stale .qt-dat-market,
.cp-mktpull-card--stale .qt-gs-market { border-left-color: var(--arl-error); }
/* Only when Quote Tracker's script is missing or threw: the figure on one plain line. */
.cp-mktpull-plain {
  padding: 8px 12px; font-size: 13px; color: var(--arl-text);
  background: var(--arl-surface-light); border: 1px solid var(--arl-border); border-radius: var(--arl-radius);
}
.cp-vet-pass { color: #15803D; }
.cp-vet-fail { color: #B91C1C; }
.cp-vet-warn { color: #92400E; }

/* ── Carrier rows (Historical carriers) ─────────────────────────────
   These used to borrow `.qm-bh-row`, whose first column is a fixed 118px because a
   backhaul row starts with a load number. A carrier NAME wrapped to three lines in
   that width while its whole identity/rate/reliability string crushed into the next
   column and the rest of the row sat empty. Four real columns instead: who they are,
   their identity, their history with us, how to reach them, and the score.

   minmax(0, …) on every flexible track lets the long strings shrink instead of
   forcing an overflow, and the name column gets the largest share because it holds
   the two-line name + reason. */
.cp-qm .qm-carrier-row {
  display: grid;
  grid-template-columns:
    minmax(190px, 2.2fr)   /* name + why it matched */
    minmax(0, 1.2fr)       /* MC / DOT */
    minmax(0, 1.6fr)       /* lane history, avg buy, on-time */
    minmax(0, 1.3fr)       /* phone / email */
    auto                   /* Highway verdict + Vet button */
    auto;                  /* score */
  align-items: start;
  column-gap: 18px;
  row-gap: 2px;
  padding: 11px 16px;
  border-bottom: 1px solid var(--qm-100);
}
.cp-qm .qm-carrier-row:last-child { border-bottom: none; }
.cp-qm .qm-carrier-main { min-width: 0; }
.cp-qm .qm-carrier-why { margin-top: 2px; font-size: 11.5px; color: var(--qm-500); }
.cp-qm .qm-carrier-id,
.cp-qm .qm-carrier-hist,
.cp-qm .qm-carrier-contact {
  min-width: 0;
  font-size: 12px;
  color: var(--qm-500);
  /* Long values wrap inside their own cell rather than widening the grid. */
  overflow-wrap: anywhere;
}
.cp-qm .qm-carrier-row .cp-carrier-name { font-weight: 600; }
/* The TFX tab's outreach email (2026-11-03): a tick box before the name, the connection status
   under the dispatch contact, and the selection bar above the rows. Spacing only. */
.cp-qm .qm-carrier-row .cp-tfx-pick { margin: 0 6px 0 0; vertical-align: middle; }
/* .cp-tfx-conn is a tag beside the name since 2026-11-10 (a .qm-chip), no longer a line under the contact. */
.cp-qm .cp-tfx-bar { margin: 4px 0 8px; flex-wrap: wrap; }

/* ── The call list's row action ──────────────────────────────────────────────
   Fabio, 2026-09-10: *"This create quote button, we could make it smaller and move
   it to the right. It looks cramped up with the ph#."* It lived inside
   `.qm-carrier-contact` — a `minmax(0, 1.3fr)` cell — so a full-width button sat
   stacked under the phone number, in the one cell a rep reads to place the call.
   An ACTION and a piece of DATA were sharing a column.

   🔴 THE SEVENTH TRACK IS FIXED, AND SCOPED TO THIS LIST. Both halves were found by
   measuring, and each is a bug the obvious version has:

   • `auto` SHEARS THE LIST. A row that renders no action — `cpCanWrite()` false, or
     a carrier with no `id` — leaves the cell empty, an auto track collapses to zero,
     and that row's flexible columns absorb the freed width. Measured: the verdict
     and rating cells sat **103px further right** on such a row than on its
     neighbours, in the same list. A fixed track reserves the space either way, so
     every row lines up whether or not it can be acted on.
   • SCOPED, or the OTHER TWO renderers pay for it. `.qm-carrier-row` is shared with
     the TFX lane-search rows (six cells) and the per-rating rows (four), neither of
     which has an action — an unscoped seventh track would reserve 104px of dead
     space on both. They keep the six-column grid.

   🔴 112px, AND THE FIRST FIGURE WAS MEASURED IN THE WRONG PLACE. It was 104px, taken
   off the harness page, where the button renders 103px wide. The LIVE app resolves
   `600 10.5px Montserrat` with `text-transform: uppercase` and `letter-spacing:
   0.21px`; the harness has no network, so Montserrat never loads and it measures a
   fallback face. Live, the button needs **108px** — so the reservation was 4px short
   and the button spilled left into the 18px column gap. No collision, no overflow,
   which is exactly why only a measurement on the deployed page found it.

   ⚠️ A HARNESS CANNOT SIZE A WEBFONT. Take any figure that reserves space for text
   from the real app, never from `tools/harness/`. The harness is still the right
   place to check structure, cascade and wrapping — just not absolute text metrics.

   The 6px `margin-left` `.btn` carries is zeroed below, so the track holds the button
   and nothing else: 108 needed + 4 headroom against a different fallback face. A
   longer label would overflow rather than widening one row, which is why the label is
   pinned by a test. */
.cp-qm .qm-carrier-row.cp-call-row {
  grid-template-columns:
    minmax(190px, 2.2fr)   /* name + why it matched */
    minmax(0, 1.2fr)       /* MC / DOT */
    minmax(0, 1.6fr)       /* lane history, avg buy, on-time */
    minmax(0, 1.3fr)       /* phone / email */
    auto                   /* Highway verdict + Vet button */
    auto                   /* score */
    112px;                 /* row action — reserved even when empty */
}
/* `justify-self: end` rather than `text-align: right`: the button is the grid item,
   and the track is wider than it by design, so the pin has to be on the item. */
.cp-qm .cp-call-row .qm-carrier-act {
  justify-self: end;
  min-width: 0;
}
/* Smaller than a general-purpose `.btn-sm`, because this one repeats on every row of
   a list that runs to 39 carriers and is secondary to the name, the verdict and the
   rating. `!important` matches `.btn-sm`'s own trick in styles.css (:3229) — without
   it that rule wins on source order and the button keeps its 11px / 4px-10px sizing.
   `white-space: nowrap` because the label is two words in a fixed track: allowed to
   wrap, it would render a two-line button on a one-line row. */
.cp-qm .cp-call-row .cp-mq-from {
  font-size: 10.5px !important;
  padding: 3px 9px !important;
  white-space: nowrap;
  letter-spacing: 0.02em;
  /* `.btn` carries `margin-left: 6px` for buttons that sit in a row beside siblings.
     This one is alone in its own cell, so that margin is 6px of the reserved track
     spent on nothing — and it is what made the rendered cell 113px against a 104px
     track. Zeroed so the track holds the button and only the button. */
  margin-left: 0;
}

/* Stack to a single column on narrow viewports, with the labels the columns lose. */
@media (max-width: 900px) {
  .cp-qm .qm-carrier-row {
    grid-template-columns: 1fr auto;
    column-gap: 12px;
  }
  /* 🔴 THE CALL ROW NEEDS ITS OWN LINE HERE, and leaving it out is not a cosmetic
     miss — it is the #345 defect exactly. `.cp-qm .qm-carrier-row.cp-call-row` is
     (0,3,0) and the rule above is (0,2,0), so the seven-column template would PARSE,
     sit in cssRules, match the element and WIN inside this media query: the stacked
     layout would silently never apply to the one list that has an action column.
     Same selector shape, so it wins on order instead. */
  .cp-qm .qm-carrier-row.cp-call-row {
    grid-template-columns: 1fr auto;
  }
  .cp-qm .qm-carrier-main { grid-column: 1 / -1; }
  .cp-qm .qm-carrier-contact { grid-column: 1 / -1; }
  /* The verdict keeps its own full-width line rather than being squeezed beside the
     score — it is the thing being read, and truncating it would defeat the point. */
  .cp-qm .qm-carrier-vet { grid-column: 1 / -1; margin-top: 4px; }
  /* Stacked, "to the right" stops meaning anything and an end-pinned button sits
     alone against the edge with the row's whole width empty beside it. It takes its
     own line and starts where every other stacked cell starts. */
  .cp-qm .cp-call-row .qm-carrier-act { grid-column: 1 / -1; justify-self: start; margin-top: 6px; }
}

/* A zero rejected count is the normal case — present so the column keeps three
   stable slots, but faded so it doesn't read as a number worth acting on. */
.cp-qbadge-zero { opacity: 0.45; text-decoration: none; }

/* ── The envelope: carriers waiting for our answer (2026-10-14) ───────────────
   Under the load reference (and under a carrier's name in an opened load), NOT in
   the four-slot badge column, and drawn only when there is something to see — see
   cpEnvelopeHTML for the three states and why opening an email does not clear it.

   `.cp-env-line` is its OWN LINE inside the same cell: a block, so the envelope sits
   under the number and adds no width to the column (Fabio: "under the load #").

   ⚠️ Appearance is the ONLY thing these rules carry. The envelope and the
   number are real text in the markup, so dropping them leaves a legible "✉3", not a
   blank. This module shipped a rating separator that lived in `::before` and made
   4.7/6 read as "4.76"; a stylesheet must never be the only place a value exists.

   Deliberately NOT `pointer-events: none`. The pill is a SIBLING of the load link,
   not a child, so a click here cannot navigate by accident — it falls through to the
   row and expands the load, where the quotes and Reply… are. Suppressing pointer
   events would also kill the `title`, and the tooltip is what explains a bare number. */
.cp-env-line { display: block; margin-top: 3px; line-height: 1; }
/* On the board (Fabio, 2026-11-10: "move the envelop to where I indicate without moving the
   rest"): in the Load # cell, at its RIGHT edge on the number's line, beside the lane — so it adds
   no line to the row and moves neither the number nor the lane. */
.cp-sp-load .cp-env-line { float: right; margin: 0 0 0 8px; line-height: inherit; }
/* …and the column a FIXED width, or the table's auto layout hands each column its share of the
   spare width by its content, and one envelope on the board widened Load # by 66px and pushed
   every lane right (measured on dev, 2026-11-10). 150px holds a load number and a two-digit
   envelope on one line (62 + 8 + 41, inside 12px padding); with it the lane did not move for 0,
   2, 12 or 99 waiting, and sat within 6px of where it was before. */
.cp-sp-load { width: 150px; }
.cp-env {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 1px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 700; line-height: 1.6;
  vertical-align: middle; white-space: nowrap;
}
/* Waiting: a filled orange pill, white text. #C2410C and not --arl-warning (#D97706):
   white on #D97706 is 3.2:1 and fails WCAG AA for 11px bold text; on #C2410C it is
   5.2:1. Declared here once — no other rule in the module uses it. */
.cp-env-waiting { background: #C2410C; color: #fff; }
/* Answered: a grey outline and no number. The glyph takes the secondary text grey
   (5.7:1), not the lighter muted one (2.8:1), so the envelope still reads as a mark
   rather than a smudge — it is quiet, not invisible. */
.cp-env-answered {
  padding: 0 6px; font-weight: 400; line-height: 1.5;
  border: 1px solid #C8C8C8; color: var(--arl-text-secondary, #666);
}

/* ── Outreach & outcome (carrier profile) ─────────────────────────────────────
   One full-width card rather than the auto-fit grid: this table carries six
   columns and reads as a history, so squeezing it beside a sibling card was what
   made the old two-card split unreadable in the first place. */
.cp-cards-wide { grid-template-columns: 1fr; }

.cp-card-sub {
  font-size: 12px;
  color: var(--arl-text-secondary);
  margin: -6px 0 12px;
}

/* offered → asked → paid, given room to breathe above the row detail */
.cp-outcome-stats { margin-bottom: 4px; }

.cp-outcome-gap {
  font-size: 13px;
  color: var(--arl-text-secondary);
  padding: 8px 0 4px;
  border-bottom: 1px solid var(--arl-border);
  margin-bottom: 8px;
}
.cp-outcome-gap strong { color: var(--arl-text); }

/* Money columns right-align so the three rate columns compare down the column
   rather than needing to be read across. */
.cp-outcome-table th:nth-child(3), .cp-outcome-table td:nth-child(3),
.cp-outcome-table th:nth-child(4), .cp-outcome-table td:nth-child(4),
.cp-outcome-table th:nth-child(6), .cp-outcome-table td:nth-child(6) {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Which of the three row types this is. Muted by design — the rates are the
   subject of the table, and the tag is only there so a rep can tell an
   unanswered offer from an unprompted bid at a glance. */
.cp-oc-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: var(--arl-radius);
  font-family: var(--arl-font-accent);
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  vertical-align: middle;
  white-space: nowrap;
}
.cp-oc-answered    { background: var(--arl-success-light); color: var(--arl-text); }
.cp-oc-noreply     { background: var(--arl-warning-light); color: var(--arl-text); }
.cp-oc-unsolicited { background: var(--arl-surface-light); color: var(--arl-text-secondary); }
/* Never sent — draft/cancelled/failed. Deliberately quieter than `noreply`: it is
   our own unfinished work, not a carrier who owes us an answer. */
.cp-oc-notsent     { background: var(--arl-surface-light); color: var(--arl-text-muted); border: 1px dashed var(--arl-border); }

/* ── Lane preferences (carrier profile) ───────────────────────────────────────
   Stated wants/avoids per dimension. Sits directly above "Lanes they run" so a
   rep can compare what a carrier SAYS against what they actually haul. */
.cp-pref-row {
  padding: 10px 0;
  border-bottom: 1px solid var(--arl-border);
}
.cp-pref-row:last-child { border-bottom: none; }

.cp-pref-dim { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.cp-pref-dim-label {
  font-family: var(--arl-font-accent);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--arl-text-secondary);
}
.cp-pref-add {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font-size: 11px;
  font-weight: 600;
  color: var(--arl-primary);
}
.cp-pref-add:hover { text-decoration: underline; }

/* Wants and avoids stack on narrow screens rather than crushing the chips. */
.cp-pref-stances { display: flex; flex-wrap: wrap; gap: 6px 24px; }
.cp-pref-stance { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 220px; }
.cp-pref-stance-label {
  font-size: 11px;
  color: var(--arl-text-muted);
  min-width: 46px;
}
.cp-pref-none { font-size: 13px; }

.cp-pref-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: var(--arl-radius);
  font-size: 12px;
  font-weight: 600;
  color: var(--arl-text);
}
/* Want vs avoid is carried by colour AND by the "Wants"/"Avoids" label beside it,
   so the distinction does not rest on colour alone. */
.cp-pref-want  { background: var(--arl-success-light); }
.cp-pref-avoid { background: var(--arl-warning-light); }
.cp-pref-dir { font-weight: 400; font-size: 11px; color: var(--arl-text-secondary); }

.cp-pref-x {
  background: none;
  border: none;
  padding: 0 0 0 2px;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  color: var(--arl-text-muted);
}
.cp-pref-x:hover { color: var(--arl-error); }

.cp-pref-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  padding: 10px;
  background: var(--arl-surface-light);
  border-radius: var(--arl-radius);
}
.cp-pref-input, .cp-pref-select {
  padding: 5px 8px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  font-family: var(--arl-font-body);
  font-size: 13px;
  background: var(--arl-white);
}
.cp-pref-input { width: 150px; }
.cp-pref-note { flex: 1 1 160px; min-width: 120px; }

.cp-pref-error {
  margin-bottom: 10px;
  padding: 8px 10px;
  border-radius: var(--arl-radius);
  background: var(--arl-error-light);
  color: var(--arl-text);
  font-size: 13px;
}

/* ── Sourcing: the four-in-one screen ─────────────────────────────────────────
   The tab strip reuses .cp-ltab wholesale (selectors extended above) so Sourcing
   and the load-expansion strip look like one system rather than two tab designs.
   Only the container-level rules are new.

   ⚠ The panels are the ORIGINAL view divs, moved here by cpSourcingBuild. One of
   them (#cp-quotes-view) carries .cp-qm, which ~130 rules are scoped to — moving
   the node carries the class with it, which is exactly why they are relocated
   rather than rebuilt. */
/* ⚠ The .cp-ltab rules resolve --qm-* custom properties, and those are declared
   ON .cp-qm — not at :root. Extending the SELECTORS to .cp-sourcing therefore was
   not enough: outside .cp-qm every var() resolved to nothing, which silently
   dropped the strip's bottom rule entirely (an invalid colour voids the whole
   `border-bottom` shorthand) and left inactive tabs inheriting body text instead
   of the muted grey. It looked correct in the diff and was only visible in a
   browser — the structural test asserting the selector exists passed throughout.
   Re-declaring just the three the strip actually reads, with the same values. */
.cp-sourcing {
  display: flex;
  flex-direction: column;
  gap: 14px;
  --qm-100: #f4f4f5;
  --qm-200: #e4e4e7;
  --qm-500: #71717a;
}
.cp-sourcing .cp-stabs { margin-bottom: 0; }
.cp-spanel { display: flex; flex-direction: column; gap: 14px; }
/* The relocated panels each shipped their own <h2> as a standalone page. Inside a
   tab the strip already names the screen, so the duplicate headers are collapsed —
   today that is Quote History's, inside the Quotes tab. (The Outreach pane's rule
   went with its tab on 2026-09-29.) */
.cp-sourcing > .cp-spanel > .cp-page-header { display: none; }

/* ── Carriers: Directory / Awaiting rating tab strip ─────────────────────────
   The calm look of the Project Management status tabs (2026-10-08): body font, text
   colour, and the selected tab says so THREE ways — a 2px blue underline, blue text and
   weight — so colour is never the only signal.
   🐛 FIXED HERE: this strip used to read --qm-200 / --qm-500, and the comment above it
   claimed they were re-declared on the strip. They were not (the declaration sat on
   .cp-tracking, then the next rule down), and #cp-carriers-view has no .cp-qm ancestor, so
   both resolved to nothing: the strip's bottom rule computed to 0px none and the
   unselected tabs fell back to the body colour. --arl-* only now — declared at :root in
   styles.css — each with a literal fallback. */
.cp-carriers-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  border-bottom: 1px solid var(--arl-border, #E0E0E0);
  margin: 4px 0 14px;
}
.cp-carriers-tabs .cp-ltab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: none;
  border-radius: 0;
  background: transparent;
  padding: 6px 12px 7px;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  font-family: var(--arl-font-body, 'Source Sans Pro', sans-serif);
  font-size: 13px;
  font-weight: 400;
  color: var(--arl-text, #333333);
  cursor: pointer;
  white-space: nowrap;
}
.cp-carriers-tabs .cp-ltab:hover { border-bottom-color: var(--arl-text-muted, #999999); }
.cp-carriers-tabs .cp-ltab:focus-visible { outline: 2px solid var(--arl-primary, #0060AF); outline-offset: -2px; }
.cp-carriers-tabs .cp-ltab-on,
.cp-carriers-tabs .cp-ltab-on:hover {
  color: var(--arl-primary-dark, #00437A);
  border-bottom-color: var(--arl-primary, #0060AF);
  font-weight: 600;
  background: transparent;
}

/* ── Tracking board (restyled 2026-10-09) ────────────────────────────────────
   One card (the Directory's .cp-dircard frame) with the Project Management status tabs reused
   as its filter; only the rules below are Tracking's own. Moved OUT of the Carriers tab-strip
   run above, where a missing brace once wiped the whole board (#155), and without the zinc
   scale it used to declare: nothing on the board reads one any more. Every custom property is
   an --arl-* token declared at :root in styles.css, each with a literal fallback.
   Reused as-is, never re-ruled here: .cp-dircard / -head / -title / -scroll, .cp-dirline,
   .cp-dirsub, .cp-dirname-line, .cp-dirname, .cp-pm-person (via cpDirPerson), .cp-pm-fig,
   .cp-pm-n, .cp-pm-buckets / .cp-pm-bucket, and the head band's source line (via cpVetPgSrc). */
.cp-tracking { display: block; }
/* The two figures that are not tabs, under the page title. */
.cp-trk-figs { margin-top: 2px; font-size: 13px; line-height: 1.5; color: var(--arl-text-secondary, #666666); }

/* How long silent, as a tag that always carries the duration. 🔑 No green, amber or red: two
   cells along the same row they mean PASS, REVIEW and NOT PASS (Fabio, 2026-10-09). 24h or
   more is BLUE, the colour he chose for a signal that is not a verdict (the carrier list's
   "New replies", Carriers' Active). 6–24h is a grey OUTLINE: the filled grey is the unknown
   verdict's (Vetting off / Not vetted / Check failed / No record). Under 6h is plain text. The
   same 24h tag carries the "Silent 24h or more" tab's count, today's one coloured figure. */
.cp-trk-silent { display: inline-block; padding: 0 8px; border: 1px solid transparent; border-radius: 999px; font-size: 12px; font-weight: 600; line-height: 18px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cp-trk-silent--late { color: #0C447C; background: #E6F1FB; border-color: #B5D4F4; }
.cp-trk-silent--aging, .cp-trk-silent--other { background: transparent; border-color: var(--arl-text-muted, #999999); color: var(--arl-text, #333333); }
.cp-trk-silent--fresh { padding: 0; border: 0; background: transparent; color: var(--arl-text, #333333); font-weight: 400; }

/* An OC with no directory match shows their raw address. The shipped .cp-pm-personname breaks
   it ANYWHERE, so it cannot widen a card with no scroll box; this card has one
   (.cp-dircard-scroll), so here the address stays whole and the column widens instead. */
.cp-trk-oc .cp-pm-personname { overflow-wrap: normal; }

/* TAI's alerts in TAI's words: the light OUTLINED amber of "History only", which Fabio approved
   beside a verdict on Carriers — not the filled amber of REVIEW. */
.cp-trk-alerts { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; }
.cp-trk-alerttag { display: inline-block; padding: 0 8px; border: 1px solid #F5D0A9; border-radius: 999px; background: #FDF6EC; color: #92600E; font-size: 11px; font-weight: 600; line-height: 18px; white-space: nowrap; }

/* "8 days past" delivery: bold words, no colour. */
.cp-trk-past { font-weight: 600; color: var(--arl-text, #333333); white-space: nowrap; }
.cp-trk-when { white-space: nowrap; }

/* ── Service rating stars (Carriers → Awaiting rating) ────────────────────────
   Five buttons, not a select. At ~131 ratings per OC per month a rating has to be
   one click from the list, so the control is sized to be hit accurately at a
   glance and to show its state without a repaint.

   ⚠️ Declared on the BARE classes, not scoped under .cp-qm. #cp-carriers-view
   carries no class at all — that is exactly how .qm-vet-chip ended up rendering
   as an unstyled link on two screens. Every custom property below therefore also
   takes a literal fallback: --qm-* live on .cp-qm / .cp-sourcing, NOT on :root,
   and a var() that resolves to nothing voids the whole shorthand it sits in.     */
.cp-stars { display: inline-flex; gap: 1px; white-space: nowrap; }
.cp-star {
  border: 0;
  background: none;
  padding: 0 1px;
  font-size: 17px;
  line-height: 1;
  color: var(--qm-200, #e4e4e7);          /* unfilled */
  transition: color 90ms linear, transform 90ms linear;
}
/* ⚠️ Pointer only on the BUTTON form. The same class is reused as a display-only
   <span> on the carrier profile, and a hand cursor over something that cannot be
   clicked is a promise the page does not keep. */
button.cp-star { cursor: pointer; }
button.cp-star:hover:not([disabled]),
.cp-star:focus-visible:not([disabled]) { color: #facc15; transform: scale(1.12); }
.cp-star:focus-visible { outline: 2px solid var(--arl-primary, #134ca8); outline-offset: 1px; border-radius: 2px; }
/* Filled state for an already-recorded rating. Yellow (#eab308), not the amber
   #f5a524 this started as — on screen that read as orange rather than a star.
   Hover/focus is the LIGHTER #facc15 so previewing a rating still lifts visibly
   against the stars already filled. Literal hex rather than a token, for the
   var()-out-of-scope reason in the block comment above. */
.cp-star-on { color: #eab308; }
.cp-star[disabled] { cursor: default; opacity: 0.55; }
/* Mid-save: dim the group and refuse pointer events, so the in-flight latch is
   visible rather than only enforced in JS. */
.cp-stars-saving { opacity: 0.45; pointer-events: none; }

/* ── Fill-through preview (hover / keyboard focus) ────────────────────────────
   Pointing at the 4th star colours 1–4. While a group is being previewed the
   COMMITTED fill steps aside, so a row already rated 5 that is hovered at 2 reads
   as two stars rather than two-plus-three-already-gold.

   ⚠️ SPECIFICITY IS THE WHOLE TRICK HERE. Both selectors below score the same
   (class + attribute + class), so the hot rule can only win by coming SECOND. A
   bare `.cp-star-hot { }` would score lower than the reset above it and lose —
   the preview would silently do nothing but grey the row out. */
.cp-stars[data-cp-hover] .cp-star { color: var(--qm-200, #e4e4e7); }
.cp-stars[data-cp-hover] .cp-star-hot { color: #facc15; }

/* ── Bulk rating bar (Carriers → Awaiting rating) ─────────────────────────────
   Shown only while something is selected, so the queue is unchanged for the
   one-click-per-row pass that stays the common case.

   Relies on styles.css's `.hidden { display: none !important }` to beat this
   `display: flex` — that rule is !important, so no specificity juggling is needed
   here, but this one is not safe to change to a plain `display: none` there. */
.cp-rbulk {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 10px;
  padding: 8px 10px;
  border: 1px solid var(--qm-200, #e4e4e7);
  border-radius: 6px;
  background: var(--qm-100, #f4f4f5);
  font-size: 13px;
}
.cp-rbulk-count strong { font-size: 15px; }
.cp-rbulk-label,
.cp-rbulk-msg { color: var(--qm-500, #71717a); }
/* The checkbox column carries no header text, so it must not claim a text column's
   width and push the lane out of the row. */
.cp-rsel-cell { width: 28px; text-align: center; }
.cp-rsel { cursor: pointer; }
.cp-rsel[disabled] { cursor: default; }

/* ── Sample-data banner (TFX preview) ────────────────────────────────────────
   Deliberately loud. This sits above rows that look exactly like real carrier
   results inside the tool OCs use to decide who to phone, so the banner has to
   survive a glance, a screenshot and a scroll-back — amber, a left bar, and it
   stays in the panel rather than being a toast that disappears.

   Literal colour fallbacks, not bare var()s: --qm-* live on .cp-qm / .cp-sourcing
   and NOT on :root, so a var() with no fallback voids the whole declaration here. */
.cp-sample-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 10px;
  padding: 8px 12px;
  font-size: 12px;
  line-height: 1.45;
  color: #7c4a03;
  background: var(--arl-warning-light, #fef7e6);
  border: 1px solid #f0c471;
  border-left: 4px solid #d98a00;
  border-radius: 6px;
}
.cp-sample-banner strong { color: #6b3f02; }
/* Push the dismiss button to the end without it stretching on a narrow panel. */
.cp-sample-banner .btn { margin-left: auto; flex: 0 0 auto; }

/* ── Suggestion tiers on "Carriers to call" ───────────────────────────────────
   Headings only render when the list actually spans more than one tier (see
   cpMatchedCarriersHTML), so these are never decoration over a uniform list.

   ⚠️ Bare classes with literal fallbacks on every var(), for the reason recorded
   at .qm-vet-chip: --qm-* live on .cp-qm / .cp-sourcing and NOT on :root, and a
   var() that resolves to nothing voids the whole declaration it sits in.        */
.cp-tier-head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 10px 0 4px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--qm-500, #71717a);
}
.cp-tier-head:first-child { margin-top: 0; }
.cp-tier-n {
  font-weight: 600;
  font-size: 10.5px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--qm-100, #f4f4f5);
  color: var(--qm-500, #71717a);
}
/* A left rule carries the tier's colour down past the heading, so the rows under
   it read as a group without tinting every row's background. */
.cp-tier-good   { color: #15803d; border-left: 3px solid #15803d; padding-left: 7px; }
.cp-tier-neutral{ border-left: 3px solid var(--qm-200, #e4e4e7); padding-left: 7px; }
.cp-tier-bad    { color: #b91c1c; border-left: 3px solid #b91c1c; padding-left: 7px; }

/* ── Service ratings card (carrier profile) ───────────────────────────────────
   The average is the summary; the rows below it are the evidence. Bare classes
   with literal var() fallbacks, per the .qm-vet-chip note above.                */
.cp-rating-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.cp-rating-head strong { font-size: 18px; line-height: 1; }
/* The per-rating rows reuse .qm-carrier-row's grid, which has six cells; these
   rows fill four, so the trailing columns collapse. Narrower first column than a
   carrier row, because it starts with stars and a load number rather than a name. */
.cp-rating-row { font-size: 12px; }
.cp-rating-row .cp-star { font-size: 13px; }

/* ── Service rating badge on "Carriers to call" ───────────────────────────────
   Replaces the match-score circle. A pill rather than a circle because it holds a
   glyph and a figure side by side, and a circle crops the second one.

   ⚠️ This comment said the pill carries "three things — the star, the average and the
   sample size" and that "the count is not optional here". Both went false within the
   hour, when Fabio decided the count belongs in the title instead. Corrected rather
   than deleted, because the reason the profile card DOES print its count still stands
   and a reader should know the two surfaces differ on purpose — see cpCarrierRatingBadge.

   ⚠️ Bare classes with a literal fallback on every var(), for the reason recorded
   at .qm-vet-chip: --qm-* live on .cp-qm / .cp-sourcing and NOT on :root, so a
   var() that resolves to nothing voids the whole declaration it sits in.        */
.cp-rbadge {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--qm-200, #e4e4e7);
  font-size: 12px;
  line-height: 18px;
  white-space: nowrap;
  color: var(--qm-500, #71717a);
}
.cp-rbadge strong { font-size: 13px; font-weight: 600; }
/* Tone follows the tier thresholds in match-carriers.js (>=4 good, <=2 bad), so the
   badge cannot disagree with the tier heading the row sits under. */
.cp-rbadge-good { color: #15803d; border-color: #bbf7d0; background: #f0fdf4; }
.cp-rbadge-good strong { color: #15803d; }
.cp-rbadge-mid  { color: #a16207; border-color: #fde68a; background: #fffbeb; }
.cp-rbadge-bad  { color: #b91c1c; border-color: #fecaca; background: #fef2f2; }
.cp-rbadge-bad strong { color: #b91c1c; }
/* Unrated: no fill and no colour. This is most of the column today, and a tinted
   pill on every row would read as a verdict where there is no data. */
.cp-rbadge-none { border-style: dashed; opacity: 0.7; }
/* ── The Carrier Directory's fuller form (Fabio, 2026-09-02) ──────────────────
   *"I need to see an average of the reviews and see how many reviews each carrier
   has."* On this screen comparing carriers IS the job, so the sample size goes back
   beside the figure — the opposite of the compact call-list rule three rules up.
   Both are his calls and they are per-screen; see cpCarrierRatingBadge.

   ⚠️ REAL TEXT IN A SPAN, never ::before/::after content. A separator that lived in
   a pseudo-element once made a rating read as "4.76" — CSS must not carry meaning,
   because a copy, a screen reader or a stylesheet that fails to load loses it.
   Smaller and muted so the average stays what the eye lands on and "(1)" reads as a
   caveat on the number rather than part of it. */
.cp-rbadge-n { font-size: 11px; font-weight: 500; opacity: 0.75; }
/* Inside a toned pill the count inherits the tone, or a grey "(12)" on a green pill
   reads as a second, disagreeing signal. */
.cp-rbadge-good .cp-rbadge-n,
.cp-rbadge-mid .cp-rbadge-n,
.cp-rbadge-bad .cp-rbadge-n { color: inherit; }
/* "Not rated" instead of "0.0" — Directory only. It keeps .cp-rbadge-none's dashed,
   untinted treatment, so it can never read as a verdict; this only stops a word
   sitting at the same weight as the figures in the rated rows above and below it. */
.cp-rbadge-unrated { font-size: 11px; }
.cp-rbadge-warn {
  font-weight: 700;
  color: #b91c1c;
  margin-left: 3px;   /* 1px let it crowd the figure and read as "1.8!" */
}
/* Sample mode: a dashed outline plus the banner above the list. The row itself has
   to carry a visual tell, because a screenshot of one row loses the banner. */
.cp-rbadge-sample { border-style: dashed; border-color: #d98a00; }

/* The sample-ratings opt-in, in the panel header beside the reach/safety counts.
   Quiet on purpose: it is a developer/reviewer affordance sitting on a working
   screen, so it must not compete with the counts a rep actually reads. */
.cp-rsample-btn { font-size: 11.5px; margin-left: 2px; }

/* ── Quote actions: the Message / Book dialogs ────────────────────────────
   The dialogs reparent to <body> (the create-modal pattern), so nothing here may
   rely on a .cp-qm ancestor — that scoping is exactly what leaves the Vet chip
   unstyled on hosts outside it. .cp-vetv is globally scoped, so badges work. */
.cp-qact-carrier { font-weight: 600; font-size: 15px; margin-bottom: 2px; }
.cp-qact-sub { color: var(--arl-text-secondary); font-size: 13px; margin-bottom: 8px; }
.cp-qact-note { color: var(--arl-text-secondary); font-size: 12px; margin: 8px 0; }
.cp-qact-label { display: block; font-size: 12px; font-weight: 600; margin: 10px 0 4px; }
.cp-qact-section { font-size: 13px; font-weight: 600; margin-top: 14px; }
.cp-qact-text {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--arl-border);
  border-radius: 6px;
  font: inherit;
  font-size: 13px;
  resize: vertical;
}
.cp-qact-text:disabled { opacity: 0.6; }
/* The counter dialog's rate field. Shares every property with .cp-qact-text so
   the two controls in that dialog cannot drift apart visually; only the width
   differs, because a rate is a short number and a full-width box invites a
   sentence. `resize` is not inherited here — an <input> has none to give.
   ⚠️ `--arl-border` is declared at :root in styles.css (unlike `--qm-*`, which
   lives on .cp-qm), so it resolves in a dialog reparented to <body>. The literal
   fallback is belt-and-braces: a var() that resolves to nothing voids the whole
   border shorthand, which is how .cp-ltab silently lost its rule. */
.cp-qact-rate {
  width: 140px;
  padding: 8px 10px;
  border: 1px solid var(--arl-border, #e4e4e7);
  border-radius: 6px;
  font: inherit;
  font-size: 13px;
}
.cp-qact-rate:disabled { opacity: 0.6; }
/* The Book dialog's list of the OTHER carriers whose prices booking marks Passed
   (2026-10-07). A plain list now — no tick boxes and no "offer another load" picker,
   because Book emails none of them. Scrolls so a load with many quoters cannot push
   the Book button off a short screen. */
.cp-cover-list {
  margin: 4px 0 10px;
  padding-left: 18px;
  font-size: 13px;
  max-height: 160px;
  overflow-y: auto;
}
/* ── The conversation log inside the Reply dialog (2026-09-16) ─────────────────
   Emails with one carrier, oldest first, above the compose box.

   ⚠️ UNSCOPED bare classes, and every token is an `--arl-*` declared at :root in
   styles.css — the same choice the `.cp-qact-*` rules above make, and for the
   reason recorded at `.qm-vet-chip`: a `.cp-qm`-scoped rule leaves the control
   unstyled on hosts outside that class. A `--qm-*` token here would resolve to
   nothing and VOID the whole declaration it sits in.

   ⚠️ These rules style only properties nothing else sets on these elements — the
   #345 lesson. A rule can parse, sit in `cssRules`, match the element and still
   LOSE on specificity; `overflow-y: auto` computed as `hidden` that way and
   clipped 107 of 112 carriers while its test stayed green. The scroller is a
   bare class on an element no other rule targets, so there is nothing to lose to. */
.cp-qlog { margin: 10px 0 4px; }
.cp-qlog-head {
  font-size: 12px; font-weight: 600; margin-bottom: 6px;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px;
}
.cp-qlog-only { font-weight: 400; font-size: 11px; color: var(--arl-text-secondary, #666666); }
/* The height cap is what makes a long negotiation readable without pushing the
   compose box off screen. `auto`, not `scroll` — a permanent gutter on a
   two-message thread reads as a broken panel. */
.cp-qlog-scroll {
  max-height: 260px; overflow-y: auto;
  border: 1px solid var(--arl-border, #E0E0E0); border-radius: 6px;
  /* White behind the bubbles (2026-11-05): the carrier's grey bubble needs a ground it stands out from. */
  padding: 8px; background: var(--arl-white, #FFFFFF);
  display: flex; flex-direction: column; gap: 8px;
}
/* ── The conversation card ──────────────────────────────────────────────────
   One box per message, our side and theirs told apart, a run by one sender under
   a single header. Fabio, 2026-09-21: the emails back and forth "look messy".

   🔴 EVERY SELECTOR HERE IS A BARE CLASS, AND THAT IS LOAD-BEARING. The Reply
   dialog is appended to `<body>`, so `.cp-qm` is NOT an ancestor of anything it
   draws — the shape that shipped the Vet chip as a plain blue link on two of four
   surfaces (#170). A `.cp-qm`-scoped rule here would not match at all, and every
   `--qm-*` inside it would resolve to nothing and void its whole declaration.

   🔴 EVERY `var()` CARRIES A LITERAL FALLBACK. `--arl-surface-2` is declared in NO
   stylesheet under `apps/server/public` — checked, 0 declarations — and the
   feedback module's own comment card survives only because it wrote
   `var(--arl-surface-2, #F9FAFB)`. The PM note row wrote
   `var(--arl-surface-2, transparent)` and computes a transparent background to
   this day. Tokens used below (`--arl-border`, `--arl-surface-alt`, `--arl-text`,
   `--arl-text-secondary`, `--arl-text-muted`) are each declared once at `:root`
   in styles.css; the fallbacks are their measured values, so a rule cannot be
   voided by a token that moves.

   ⚠️ These rules style properties nothing else sets on these elements — the #345
   lesson: a rule can parse, sit in `cssRules`, MATCH and still LOSE on
   specificity. `.cp-msg*` appears in no other rule in this file or in styles.css,
   so there is nothing to lose to; the harness page proves it with a control. */
/* 🔑 THE TEXT-MESSAGE LOOK (Fabio, 2026-11-05: "mimic what text messages would look like.
   Meaning OC's responses should be color coded differently", a phone's chat as the picture).
   Ours on the RIGHT in ARL blue, the carrier's on the LEFT in grey with their initials beside
   the first message of a run; who and when sit above each bubble, outside it.
   ⚠️ This REPLACES the #415 layout (2026-09-21): one column, a tint and a left rule, "without
   the chat-bubble alignment a negotiation log does not want". That was this module's own
   reasoning, not Fabio's call; he has now asked for the bubbles. */
.cp-msg {
  display: flex; flex-direction: column; align-items: flex-start;
  font-size: 13px;
}
.cp-msg-us { align-items: flex-end; }
.cp-msg-us > .cp-msg-head { justify-content: flex-end; }
/* The carrier's side is a two-column grid: the round, then the header, the bubble and any
   note, each placed in column 2 so a continuation (no round) lines up under the first. */
.cp-msg-them {
  display: grid; grid-template-columns: 26px minmax(0, 1fr); column-gap: 8px;
  justify-items: start;
}
.cp-msg-them > :not(.cp-msg-avatar) { grid-column: 2; }
/* A continuation is tucked under its predecessor — the run reads as one turn in
   the conversation rather than as N separate events. Measured: the busiest real
   thread runs four inbound messages together. */
.cp-msg-cont { margin-top: -4px; }
.cp-msg-bubble {
  max-width: 82%;
  padding: 7px 11px;
  border-radius: 16px;
  background: var(--arl-surface, #EEEEEE);
  color: var(--arl-text, #333333);
}
/* The corner nearest the speaker is squared off, as a phone draws the tail. */
.cp-msg-us > .cp-msg-bubble {
  background: var(--arl-primary, #0060AF);
  color: var(--arl-white, #FFFFFF);
  border-bottom-right-radius: 4px;
}
.cp-msg-them > .cp-msg-bubble { border-bottom-left-radius: 4px; }
/* The carrier's initials, level with the bottom of their bubble. Decorative (aria-hidden): the
   name is in the header above. */
.cp-msg-avatar {
  grid-column: 1; grid-row: 2; align-self: end;
  width: 26px; height: 26px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--arl-text-muted, #999999); color: var(--arl-white, #FFFFFF);
  font-size: 11px; font-weight: 700;
}
/* Inside OUR blue bubble the module's grey secondary text would sit on blue at about 1.5:1.
   Each takes the bubble's own white instead, with the quote and the notes quietened by opacity,
   never by a second colour. */
.cp-msg-us .cp-msg-blank,
.cp-msg-us .cp-msg-quote,
.cp-msg-us .cp-msg-files { color: inherit; opacity: 0.85; }
.cp-msg-us .cp-msg-quote { border-left-color: currentColor; }
.cp-msg-us .cp-msg-sig,
.cp-msg-us .cp-msg-sig > summary,
.cp-msg-us .cp-msg-more > summary { color: inherit; text-decoration: underline; }
.cp-msg-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 5px;
  font-size: 11px; color: var(--arl-text-secondary, #666666); margin-bottom: 3px;
}
.cp-msg-who { font-weight: 600; color: var(--arl-text, #333333); }
.cp-msg-sub { color: var(--arl-text-muted, #999999); }
.cp-msg-tag { font-style: italic; color: var(--arl-text-muted, #999999); }
.cp-msg-dot { color: var(--arl-text-muted, #999999); }
/* `pre-wrap` keeps the carrier's own line breaks — a quote laid out over four
   lines collapses into an unreadable run otherwise. `break-word` because a long
   unbroken reference number would widen the dialog. */
.cp-msg-body { white-space: pre-wrap; overflow-wrap: break-word; }
.cp-msg-blank { color: var(--arl-text-muted, #999999); font-style: italic; }
.cp-msg-note { font-size: 11px; color: var(--arl-text-secondary, #666666); font-style: italic; margin-top: 3px; }
/* The reveal. `<details>` rather than a class toggle so that an unstyled or
   out-specified page still OPENS — a reveal that loses the cascade hides text
   unreachably, which is exactly what #345 shipped. Only 3 of 150 measured
   messages are long enough to clamp, so this is rarely on screen; the worst is
   2,702 characters, which is why it exists at all. */
.cp-msg-more { margin-top: 4px; }
.cp-msg-more > summary {
  cursor: pointer; font-size: 11px; color: var(--arl-primary, #0060AF);
  font-style: italic; list-style: none;
}
.cp-msg-more > summary::-webkit-details-marker { display: none; }
/* "Show signature" (2026-09-29). QUIETER than "Show the rest": the rest is the message,
   this is a phone number and a logo. Same `<details>` for the same reason — an
   out-specified page must still be able to OPEN it. */
.cp-msg-sig { margin-top: 4px; font-size: 12px; color: var(--arl-text-muted, #999999); }
.cp-msg-sig > summary {
  cursor: pointer; font-size: 11px; color: var(--arl-text-muted, #999999);
  font-style: italic; list-style: none;
}
.cp-msg-sig > summary::-webkit-details-marker { display: none; }
/* #340: the email a carrier answered, when theirs opened with the quote. A quote's own
   look — a rule down the left and quieter text — so it can never read as the carrier's
   words. `pre-wrap` for the same reason as the body: answers typed into it are lines. */
.cp-msg-quote {
  margin: 2px 0 4px; padding: 2px 0 2px 8px;
  border-left: 2px solid var(--arl-border, #E0E0E0);
  color: var(--arl-text-secondary, #666666);
  white-space: pre-wrap; overflow-wrap: break-word;
}
/* #340: "Attached: pod.pdf" — a carrier who sends only a file has no other line. */
.cp-msg-files { margin-top: 4px; font-size: 11px; color: var(--arl-text-secondary, #666666); }
.cp-qlog-skel,
.cp-qlog-empty { font-size: 12px; color: var(--arl-text-secondary, #666666); padding: 6px 0; }
/* 🔴 `--arl-danger` is NOT declared at :root — checked, 0 declarations in
   styles.css — so this fallback is LOAD-BEARING, not decoration. Without it the
   `var()` resolves to nothing and voids the whole `color` declaration, leaving a
   failure notice in ordinary body text. #E11A22 is the red the rest of this
   module's error tone already computes to. */
.cp-qlog-warn { font-size: 12px; color: var(--arl-danger, #E11A22); padding: 4px 0; }

.cp-qact-result { margin-top: 10px; font-size: 13px; display: flex; flex-direction: column; gap: 4px; }
.cp-qact-result ul { margin: 2px 0 0 18px; }
.cp-qact-ok { color: #15803d; font-weight: 600; }
.cp-qact-warn { color: var(--arl-accent-dark); }

/* ── Project Management, tab 1 ───────────────────────────────────────────────
   Deliberately plain: a table and four numbers. Every var() carries a literal
   fallback, and .cp-pm re-declares the --qm-* it reads because those live on
   .cp-qm rather than :root — a var() resolving to nothing voids the WHOLE
   declaration, with a 200 on the stylesheet and no console error. */
.cp-pm {
  display: flex;
  flex-direction: column;
  gap: 18px;
  --qm-100: #f4f4f5;
  --qm-200: #e4e4e7;
  --qm-500: #71717a;
}
/* The P-number beside a project's name — Fabio, 2026-09-17.
   A BARE class, deliberately. `.cp-sub`, the line it sits in, has no rule anywhere in
   either stylesheet (checked), so nothing competes with this and nothing can out-specify
   it — and a `.cp-qm`-scoped version would not match, because the Project Management
   panel is one of the hosts that does not carry that class (the #170 trap, which shipped
   the Vet chip unstyled on two of four surfaces).
   Weight only. No colour, no border, no background: this is an identifier, not a status,
   and a tinted pill here would read as a verdict beside the vetting labels this module
   renders four cells away. */
.cp-pm-code { font-weight: 600; }

/* "2 new" on a carrier who has written back, and the project's own tally beside the
   heading — Fabio, 2026-09-22.

   BARE classes, and WEIGHT ONLY: no colour, no border, no background, no `--qm-*`. The
   count and the state are in the TEXT, so the cell still says everything it means if
   these rules never arrive — which is the #170 failure (a control shipped unstyled on a
   host with no `.cp-qm` ancestor) made harmless rather than merely guarded against.
   Colour here would also collide with the PASS / REVIEW / NOT PASS verdicts four cells
   along, where a tint IS the meaning. */
.cp-pm-replied { font-weight: 600; }

/* The tally beside the carrier list's heading, as a TAG since 2026-09-29 (Fabio: "Now do
   the carrier list"). 🔑 BLUE, BY HIS CALL, not the Projects list's red: on this page red
   already means NOT PASS four cells along, and green means PASS, so the tag takes the one
   hue the verdicts do not use. The WORDS still carry it (cpPmRepliedWords, shared with the
   Projects list), so the heading says everything if this rule never arrives. The row's own
   "2 new" above stays WEIGHT ONLY in the text; its button takes the same blue (below). */
.cp-pm-repliedsum {
  display: inline-block;
  margin-left: 10px;
  padding: 2px 10px;
  border-radius: 999px;
  background: #E6F1FB;
  color: #0C447C;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
}

/* ── The Projects list's look — Fabio, 2026-09-29 ("do the Projects list first", after
   seeing another team's Pulse). BARE classes, for the reason the rules above give. Every
   colour here sits beside the word it stands for — the tag says "Active", the bar's
   figures are written under it, a person's name is beside their circle — so the list
   still says everything if these rules never arrive. Unlike the carrier list, nothing on
   this screen is a PASS / NOT PASS verdict for a tint to be confused with. */
/* `overflow-x: auto`, NOT `hidden`: hidden clipped the Outreach and Status columns clean off
   at a 1,100px window (measured — the table ran 165px past the card). Auto still rounds the
   table's corners into the card, and on a screen too narrow for it the table scrolls
   sideways instead of silently losing columns. */
.cp-pm-group {
  background: var(--arl-white, #FFFFFF);
  border: 1px solid var(--arl-border, #E0E0E0);
  border-radius: 10px;
  margin: 0 0 14px;
  overflow-x: auto;
}
.cp-pm-grouphead {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  cursor: pointer;
  list-style: none;
  background: var(--arl-surface-alt, #FAF9F9);
  font-size: 14px;
  font-weight: 600;
  color: var(--arl-text, #333333);
}
.cp-pm-grouphead::-webkit-details-marker { display: none; }
/* The keyboard ring INSIDE the header: the browser's default ring is drawn outside the
   summary's box, and the group's own overflow clips it away — a keyboard user could not
   see which section they were on (2026-09-29 review). Same inset ring the tabs use. */
.cp-pm-grouphead:focus-visible { outline: 2px solid var(--arl-primary, #0060AF); outline-offset: -2px; }
/* A real heading (the detail page's sections are headings too), reset to the header's look. */
.cp-pm-grouptitle { margin: 0; font: inherit; color: inherit; }
.cp-pm-group[open] > .cp-pm-grouphead { border-bottom: 1px solid var(--arl-border, #E0E0E0); }
/* The fold arrow, drawn with borders so no glyph is announced — `<details>` already tells a
   screen reader whether the section is open. */
.cp-pm-chev {
  margin-left: auto;
  width: 7px;
  height: 7px;
  border-right: 2px solid var(--arl-text-muted, #999999);
  border-bottom: 2px solid var(--arl-text-muted, #999999);
  transform: rotate(45deg);
}
.cp-pm-group[open] > .cp-pm-grouphead .cp-pm-chev { transform: rotate(-135deg); }
/* The card IS the frame. Under `.cp-qm` the table brings its own border, radius, shadow and
   clip (`.cp-qm .cp-table`), which drew a second frame inside the card's. Same specificity,
   later in the file — so this wins; the `.cp-os-oc-body > .cp-table` reset is the precedent. */
.cp-pm-group > .cp-table { border: 0; border-radius: 0; box-shadow: none; overflow: visible; }

.cp-pm-person { display: flex; align-items: center; gap: 8px; }
/* A long address WRAPS rather than widening the column — before the directory loads (or if
   it fails) a person reads as their full email, which pushed the table past its card. */
.cp-pm-personname { min-width: 0; overflow-wrap: anywhere; }
.cp-pm-avatar {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.cp-pm-avatar--0 { background: #E6F1FB; color: #0C447C; }
.cp-pm-avatar--1 { background: #E1F5EE; color: #085041; }
.cp-pm-avatar--2 { background: #EEEDFE; color: #3C3489; }
.cp-pm-avatar--3 { background: #FAECE7; color: #712B13; }
.cp-pm-avatar--4 { background: #FAEEDA; color: #633806; }
.cp-pm-avatar--5 { background: #FBEAF0; color: #72243E; }

.cp-pm-outreach { min-width: 170px; max-width: 360px; }
.cp-pm-bar {
  display: flex;
  height: 6px;
  border-radius: 3px;
  overflow: hidden;
  background: var(--arl-surface, #EEEEEE);
}
/* `flex: none` so a segment is exactly its share — the widths are percentages of the track,
   and a shrinking flex item would draw 40% for a figure that is 50%. */
.cp-pm-seg { flex: none; height: 100%; }
.cp-pm-seg--yes { background: var(--arl-success, #16A34A); }
.cp-pm-seg--no { background: #B4B2A9; }
.cp-pm-seg--emailed { background: #85B7EB; }
.cp-pm-barnums {
  margin-top: 5px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--arl-text-secondary, #666666);
}
/* One figure never breaks across lines — the line breaks BETWEEN figures. */
.cp-pm-fig { white-space: nowrap; }
.cp-pm-n { font-weight: 600; color: var(--arl-text, #333333); }

.cp-pm-statuspill {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.cp-pm-statuspill--active { background: var(--arl-success-light, #DCFCE7); color: #166534; }
.cp-pm-statuspill--done { background: #E6F1FB; color: #0C447C; }
.cp-pm-statuspill--off,
.cp-pm-statuspill--other { background: var(--arl-surface, #EEEEEE); color: var(--arl-text-secondary, #666666); }
/* The bell's red, lightly: a carrier is waiting on this project. The same pill shape as the
   status tag, declared in ONE rule of its own (one class, one component — see the collision
   test in apps/server/src). */
.cp-pm-newreplies {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  margin-top: 6px;
  background: var(--arl-error-light, #FEE2E2);
  color: var(--arl-accent-dark, #BD0E0E);
}

/* The Replied cell as the way into the carrier's emails (stage 3b, 2026-09-28) — the same
   small bordered button the Notes cell beside it is, so the two read as the same kind of
   control. The words inside still carry every state; this only makes it clickable. */
.cp-pm-threadbtn {
  border: 1px solid var(--arl-border);
  border-radius: 6px;
  background: transparent;
  color: var(--arl-text);
  font: inherit;
  font-size: 12px;
  padding: 2px 8px;
  text-align: left;
  cursor: pointer;
}
.cp-pm-threadbtn:hover { border-color: var(--arl-text-muted); }
/* The "3h ago" line. A SPAN, because a <div> inside a <button> is invalid — so it is made
   a line of its own here, where the div used to be one by default. */
.cp-pm-replywhen { display: block; }

/* ── "Suggest carriers from ARL history" dialog (2026-09-29) ──────────────────────────
   Appended to <body> like every CP dialog, so BARE classes and `--arl-*` tokens with
   fallbacks. Wider than the other dialogs: it is a list of up to 100 carriers. No green
   and no red of its own — the Vetting column's PASS / NOT PASS badges are the only
   verdict colours in it, and a status is words, never a tint. */
.cp-pm-sugg-modal > .modal-content { max-width: 1000px; }
.cp-pm-sugg-summary { margin: 0 0 8px; font-size: 13px; color: var(--arl-text-secondary, #666666); }
.cp-pm-sugg-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.cp-pm-sugg-table th,
.cp-pm-sugg-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--arl-border, #E0E0E0);
  text-align: left;
  vertical-align: top;
}
.cp-pm-sugg-table thead th {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--arl-text-muted, #999999);
}
/* The two halves Fabio named, each under its own heading row. */
.cp-pm-sugg-group > th {
  background: var(--arl-surface-alt, #FAF9F9);
  font-size: 12px;
  font-weight: 600;
  color: var(--arl-text, #333333);
}
.cp-pm-sugg-name { font-weight: 600; color: var(--arl-text, #333333); }
.cp-pm-sugg-sub { font-size: 12px; color: var(--arl-text-secondary, #666666); }
.cp-pm-sugg-why {
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
  font-size: 12px;
  color: var(--arl-text-secondary, #666666);
}
/* "On this lane: Interested" — already here, so no box to tick. Words and weight only. */
.cp-pm-sugg-on { font-size: 12px; font-weight: 600; color: var(--arl-text-secondary, #666666); }

/* The thread dialog — appended to <body> like every CP dialog, so BARE classes and only
   `--arl-*` tokens (the #170 rule). A carrier has one thread per LANE; this heads each. */
.cp-pm-threadlane {
  margin: 10px 0 4px;
  font-size: 12px;
  font-weight: 600;
  color: var(--arl-text);
}
/* 🔴 `.cp-qact-label` sets `display: block`, which BEATS the `hidden` attribute (an author
   display outranks the UA's `[hidden] { display: none }`), so without this the "reply on
   which thread" picker would show for a carrier with ONE thread — a choice of one. Same
   repair as `.cp-vet-peek[hidden]`. */
.cp-pm-threadpick[hidden] { display: none; }

/* The outreach preview dialog — Fabio, 2026-09-17.
   BARE classes: the modal is appended to <body>, NOT inside the project panel, so a
   `.cp-qm`-scoped rule would not match it at all (the #170 trap). `--qm-*` tokens live
   on `.cp-qm` for the same reason, so nothing here reads one.
   The body is a <pre> because the email is plain text and its line breaks ARE the
   layout — rendering it as flowed HTML would show a rep something the carrier will
   not receive, which is the one thing a preview may not do. */
.cp-pm-preview-subject {
  font-weight: 600; padding: 6px 0; word-break: break-word;
}
.cp-pm-preview-body {
  white-space: pre-wrap; word-break: break-word; margin: 0;
  font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: #f6f6f7; border: 1px solid #e4e4e7; border-radius: 8px;
  padding: 10px 12px; max-height: 320px; overflow-y: auto;
}
/* The SEND window's draft is editable (#304): the subject as a box, the body as a text
   area in the same type as the read-only preview, so a rep sees the same layout they
   would have read there. */
.cp-pm-input.cp-pm-draft-subject { font-weight: 600; margin-bottom: 8px; }
.cp-pm-input.cp-pm-draft-body {
  font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  resize: vertical; min-height: 220px; margin-bottom: 6px;
}
.cp-pm-draft-subject[aria-invalid="true"],
.cp-pm-draft-body[aria-invalid="true"] { border-color: var(--fk-broken); }
.cp-pm-preview-skipped ul { margin: 4px 0 8px; padding-left: 18px; }
.cp-pm-preview-skipped li { font-size: 12px; color: var(--arl-text-muted, #6B7280); }

.cp-pm-section { display: flex; flex-direction: column; gap: 6px; }
.cp-pm-sectionh {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-family: var(--arl-font-accent, inherit);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--arl-text-secondary, #4B5563);
}

/* The four counters are ordinary numeric columns — no bespoke widget. `.cp-num`
   already gives right-alignment and tabular figures, which is what makes the digits
   line up down a column, and every other CP table counts this way. A custom cell
   here would read as a different app on the same screen. */

/* A numeric HEADER must sit over its numbers.

   `.cp-table thead th` sets text-align:left and out-specifies `.cp-num` (0,1,2 beats
   0,1,0), so a `<th class="cp-num">` renders left-aligned above a right-aligned
   column and the label drifts away from the figure it names. Scoped to .cp-pm rather
   than fixed globally: every other CP table has the same gap, and restyling screens
   this change is not about is not mine to do uninvited. */
.cp-pm .cp-table thead th.cp-num { text-align: right; }

/* Section headings use the accent face and the same uppercase treatment as the
   table headers they sit above, so a section reads as part of the table rather than
   as a page of its own. */
/* ── Project Management: the new-project form and the detail view ─────────────
 *
 * Plain by instruction. The first version of these screens was scrapped — "this is
 * too intricate" — so this is ordinary inputs on a grid and nothing else: no tone
 * system, no chips, no tiles, no colour that carries meaning.
 *
 * Only `--arl-*` tokens are used. Those are declared at :root, so they need no
 * literal fallback — unlike `--qm-*`, which lives on .cp-qm and voids the whole
 * declaration when it resolves to nothing.
 */

.cp-pm-form {
  margin: 0 0 16px;
  padding: 14px 16px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  background: var(--arl-white);
}

.cp-pm-form h3 {
  margin: 0 0 12px;
  font-family: var(--arl-font-accent, inherit);
  font-size: 15px;
}

.cp-pm-formgrid,
.cp-pm-lanegrid {
  display: grid;
  gap: 10px 12px;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}

.cp-pm-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--arl-text-muted);
}

.cp-pm-wide { grid-column: 1 / -1; }

.cp-pm-input,
.cp-pm-select {
  padding: 6px 8px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  font-family: var(--arl-font-body);
  font-size: 13px;
  color: var(--arl-text);
  background: var(--arl-white);
  width: 100%;
  box-sizing: border-box;
}

.cp-pm-input:focus,
.cp-pm-select:focus { outline: 2px solid var(--arl-accent); outline-offset: -1px; }

/* The lane's trailer types (#306): a closed line like the other boxes, opening onto a
   list of tick boxes. Several ticked = one lane each. The field is a div, not a <label>,
   because each type is its own label and labels do not nest; it copies the form label's
   column look so the grid reads the same. */
.cp-pm-equipfield {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--arl-text-muted);
  position: relative;
}
.cp-pm-equipmenu > summary {
  cursor: pointer;
  list-style: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cp-pm-equipmenu > summary::-webkit-details-marker { display: none; }
.cp-pm-equipopts {
  position: absolute;
  z-index: 5;
  left: 0;
  right: 0;
  margin-top: 2px;
  padding: 6px 8px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  background: var(--arl-white);
  box-shadow: var(--arl-shadow);
  max-height: 240px;
  overflow-y: auto;
}
.cp-pm-form .cp-pm-equipopt {
  flex-direction: row;
  align-items: center;
  gap: 6px;
  padding: 3px 0;
  font-size: 13px;
  color: var(--arl-text);
  cursor: pointer;
}

/* A project person who is TYPED TEXT rather than a picked directory account.
   Everything keyed on identity — the "Only mine" filter, assignment, notifications,
   the CC on outbound mail — matches on the address, so a bare name silently misses.
   ⚠️ The words "not a FORGE user" are emitted in the MARKUP by `cpPmPerson`, not
   here: if this rule is dropped or renamed the row still SAYS what is wrong, it just
   stops looking urgent. Never move that text into a ::before — a rating in this same
   module once read as "4.76" because a separator lived in one.
   ⚠️ Literal fallbacks on both vars: these render inside .cp-table and .cp-fields,
   and #cp-projects-view carries no .cp-qm ancestor, so a var() that resolved to
   nothing would void the whole declaration (how .cp-ltab lost its border). */
.cp-pm-noacct { color: var(--arl-text, #1f2933); }
.cp-pm-noacct-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 0 6px;
  border: 1px solid var(--arl-warn-border, #f5c26b);
  border-radius: 999px;
  background: var(--arl-warn-bg, #fff8e6);
  color: var(--arl-warn-text, #8a5a00);
  font-size: 10.5px;
  font-weight: 600;
  white-space: nowrap;
  vertical-align: baseline;
}

/* A 2-char state and a 5-char ZIP do not need a 160px column. */
.cp-pm-st { text-transform: uppercase; }
.cp-pm-form label:has(> .cp-pm-st) { max-width: 70px; }
.cp-pm-form label:has(> .cp-pm-zip) { max-width: 110px; }
.cp-pm-num { text-align: right; font-variant-numeric: tabular-nums; }

.cp-pm-lane {
  margin: 12px 0 0;
  padding: 10px 12px 12px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
}

.cp-pm-lane legend {
  padding: 0 6px;
  font-size: 12px;
  color: var(--arl-text-muted);
}

.cp-pm-lane > button { margin-top: 10px; }

.cp-pm-formactions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
}

.cp-pm-spacer { flex: 1 1 auto; }

/* The form's own error line. Text, not colour alone — a rep who cannot distinguish
 * the background still reads the sentence. */
.cp-pm-formerr {
  margin: 0 0 12px;
  padding: 8px 10px;
  border-radius: var(--arl-radius);
  background: var(--arl-error-light);
  color: var(--arl-text);
  font-size: 13px;
}

/* The partial-save notice: created, but not everything landed. */
.cp-pm-partial {
  margin: 0 0 16px;
  padding: 12px 14px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  background: var(--arl-warning-light);
  font-size: 13px;
}

.cp-pm-partial ul { margin: 8px 0 12px; padding-left: 20px; }
.cp-pm-partial li { margin: 2px 0; }
.cp-pm-partial .btn { margin-right: 8px; }

/* A project's notes on the detail screen. */
.cp-pm-notes {
  margin: 12px 0 16px;
  padding: 10px 12px;
  border-left: 3px solid var(--arl-border);
  color: var(--arl-text);
  font-size: 13px;
  white-space: pre-wrap;
}

/* The dashboard has no page header of its own (the Project Management group above it
   carries the name), so its primary action lives in the toolbar. Pushed to the right
   edge, which is where the rest of FORGE puts one. */
.cp-pm .cp-toolbar #cp-pm-new { margin-left: auto; }

/* The customer picker on the new-project form. Plain: a search box, a hint, and a
   list of buttons. Only --arl-* tokens, which are declared at :root and so need no
   literal fallback. Nothing here carries meaning by colour alone. */
.cp-pm-custhint {
  margin-top: 4px;
  font-size: 11px;
  color: var(--arl-text-muted);
}

.cp-pm-custresults {
  margin-top: 6px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  background: var(--arl-white);
  max-height: 220px;
  overflow-y: auto;
}

.cp-pm-custrow {
  display: block;
  width: 100%;
  padding: 7px 10px;
  border: 0;
  border-bottom: 1px solid var(--arl-border);
  background: none;
  font-family: var(--arl-font-body);
  font-size: 13px;
  color: var(--arl-text);
  text-align: left;
  cursor: pointer;
}

.cp-pm-custrow:last-child { border-bottom: 0; }
.cp-pm-custrow:hover,
.cp-pm-custrow:focus { background: var(--arl-hover, rgba(0, 0, 0, 0.04)); }

/* ── Tab 2: the project carrier list ─────────────────────────────────────────
   Each carrier's status on the lane is a DROPDOWN (2026-09-24; it was four buttons).
   The <select> itself wears .cp-oc-select, the page's existing picker style, so the
   only rules here are the wrapper — which holds a failed save's message beside it —
   and the busy state while a save is in flight. The selected option's own TEXT says
   the status; nothing here builds a class from the stored value. */
.cp-pm-status {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}

.cp-pm-status[aria-busy="true"] { opacity: 0.6; }

/* A failed write, as TEXT on the row. Nothing renders a bare data attribute. */
.cp-pm-statuserr { margin-left: 6px; font-size: 12px; }

/* "Choose a lane…" on a carrier who is on NO lane (2026-09-30). Its wrapper holds, as
   TEXT with the picker (beside it, or under it in a narrow cell — it wraps), a failed
   save — or the answer that the carrier is already on a lane, which takes the picker's
   place because a second pick could only refuse again — and dims while the pick is saved. The status dropdown's rules above, for the same
   reasons; kept apart so the two controls are never mistaken for each other. The words
   carry the meaning; the colour is .cp-vet-warn's, set on the element in the markup. */
.cp-pm-firstlane {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}

.cp-pm-firstlane[aria-busy="true"] { opacity: 0.6; }

.cp-pm-firstlane-said { font-size: 12px; }

.cp-pm-lanepick {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--arl-text-muted);
}

/* ── TFX lane-intelligence import ──────────────────────────────────────────────
 * Presentation ONLY. Every fact the rep needs — what was created, what was filled,
 * what was skipped, that the carriers are NOT vetted — is real text in the report
 * markup, never a colour or a pseudo-element. This module has already shipped a
 * separator that lived in ::before and made a rating read as "4.76", and a missing
 * brace here once made Chrome discard 46 rules with no error anywhere. */
.cp-pm-import {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 12px;
}
.cp-pm-importfile {
  font-size: 12px;
  max-width: 100%;
}
.cp-pm-importhint {
  font-size: 12px;
  color: var(--arl-text-muted);
  flex: 1 1 240px;
}
.cp-pm-importreport {
  margin-bottom: 14px;
  padding: 10px 12px;
  border: 1px solid var(--arl-border);
  border-radius: 6px;
  background: var(--arl-surface-alt, #FAF9F9);
  font-size: 13px;
}
.cp-pm-importdone > :last-child {
  margin-bottom: 0;
}
.cp-pm-importhead {
  margin: 0 0 6px;
}
.cp-pm-importdetail,
.cp-pm-importwarn,
.cp-pm-importskips ul {
  margin: 0 0 6px;
  padding-left: 18px;
}
.cp-pm-importskips summary {
  cursor: pointer;
  font-size: 12px;
  color: var(--arl-text-muted);
}
.cp-pm-importvet {
  margin: 8px 0 0;
  font-size: 12px;
}

/* ── Lanes card + status tabs ─────────────────────────────────────────────────
 * Presentation ONLY. Every fact — which lane, which status, how many, "showing 200 of
 * 514" — is real text in the markup. Nothing here uses content: attr() or ::before to
 * deliver a value: this module shipped a separator that lived in ::before and made a
 * rating read as "4.76", and one missing brace once made Chrome discard 46 rules with
 * no error anywhere.
 *
 * Fabio, feedback #66 (2026-09-30): "Status as tabs, Select lane from the card above,
 * Remove the 'all' label". The lane tab strip is GONE — a row of the Lanes card picks
 * the lane — and the status pills took the strip's underline look. */

/* The Lanes card rows are the lane picker. The selected lane is marked three ways — a
   tint, a bar down its left edge and bold text — so it never depends on colour alone,
   and the "Carriers <lane>" heading below names it in words.
   ⚠️ The tint sits on the CELLS, not the row: `.cp-qm .cp-table tbody tr:hover` (0,3,2)
   paints the ROW, and a cell's background is drawn over its row's, so the selected tint
   holds under the pointer without out-specifying the board's own hover rule. */
.cp-pm-lanerow { cursor: pointer; }
/* Each lane's Edit (2026-11-05): the last column, as narrow as its button, on both pages. */
.cp-pm-laneact { width: 1%; white-space: nowrap; text-align: right; }
/* Why a lane's pickup, delivery and equipment are greyed out in its Edit form. */
.cp-laneedit-locked { margin: 0 0 8px; }
/* …and they LOOK greyed out: a disabled text box is otherwise drawn like an open one (only the
   select changes), so a rep would click into Pickup and wonder why it takes no typing. The kit's
   own disabled look (.fk-input:disabled). */
.cp-laneedit .cp-pm-input:disabled { background: var(--fk-canvas); color: var(--fk-ink-2); cursor: not-allowed; }
/* The "Click a lane to see its carriers" hint beside the card's heading is a sentence, not
   a label: the heading's capitals and tracking would make it read as shouting. */
.cp-pm-lanescard > .cp-pm-sectionh .cp-pm-scope {
  text-transform: none;
  letter-spacing: normal;
  /* The only words saying the rows are clickable — the darker grey, not the muted one
     (#999 on white is 2.8:1; #666 is 5.7:1). */
  color: var(--arl-text-secondary, #666666);
}
.cp-pm-lanerow.is-selected > td {
  background: #E6F1FB;
  color: #0C447C;
  font-weight: 600;
}
.cp-pm-lanerow.is-selected > td:first-child {
  box-shadow: inset 3px 0 0 var(--arl-primary, #0060AF);
}
/* The row's keyboard handle — the lane number, as a real button. */
.cp-pm-lanego {
  min-width: 28px;
  padding: 1px 8px;
  border: 1px solid var(--arl-border, #E0E0E0);
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.cp-pm-lanego[aria-pressed="true"] {
  border-color: var(--arl-primary, #0060AF);
  background: #FFFFFF;
}
.cp-pm-lanego:focus-visible {
  outline: 2px solid var(--arl-primary, #0060AF);
  outline-offset: 1px;
}

/* The status TABS: an underline strip, the look the lane tabs had.
   ⚠️ It WRAPS on a narrow screen, so the rule is drawn by EACH TAB (gap 0, spacing from
   padding), not only by the strip: a strip-only rule ran under the last row alone, and a
   selected tab on an upper row drew its underline in mid-air (2026-09-29 review, on the
   lane strip). The strip's own border finishes the last row to the right edge.
   aria-selected is the source of truth for which tab is showing, so the styling keys off
   it rather than a second class that could disagree with what screen readers hear. */
.cp-pm-buckets {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--arl-border, #E0E0E0);
}
.cp-pm-bucket {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  color: var(--arl-text);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.cp-pm-buckets > .cp-pm-bucket {
  border: 0;
  border-bottom: 1px solid var(--arl-border, #E0E0E0);
  border-radius: 0;
  padding: 6px 10px 8px;
  margin-bottom: -1px;
}
.cp-pm-buckets > .cp-pm-bucket:not([aria-selected="true"]):hover {
  border-bottom-color: var(--arl-text-muted, #666666);
}
/* 2px under the selected status, 1px less padding, so selecting one never shifts the row. */
.cp-pm-buckets > .cp-pm-bucket[aria-selected="true"] {
  background: transparent;
  border-bottom-width: 2px;
  padding-bottom: 7px;
}
/* The selected tab is marked three ways — the blue underline, the blue text and its
 * weight — so it does not depend on colour alone.
 * 🔑 BLUE, NOT RED, SINCE 2026-09-29 (Fabio, "Now do the carrier list"): on this page red
 * means only NOT PASS and "destructive". */
.cp-pm-bucket[aria-selected="true"] {
  border-color: var(--arl-primary, #0060AF);
  color: #0C447C;
  font-weight: 600;
}
/* The count inside the selected tab takes its blue too. `.cp-count` sets its own muted
   grey, which read at 2.5:1 on the old blue fill — the number the tabs exist to show. */
.cp-pm-bucket[aria-selected="true"] .cp-count,
.cp-pm-lanerow.is-selected .cp-count,
.cp-pm-lanerow.is-selected .cp-muted { color: inherit; }
.cp-pm-scope {
  font-weight: 400;
  font-size: 13px;
  color: var(--arl-text-muted);
}

/* ── Tab 2 as ONE CARD — Fabio, 2026-09-29 ("Now do the carrier list"), after the
   Projects list restyle. The same frame as that list's sections, on a class of its own
   (the list's rules are pinned by exact selector). Presentation only: every fact is
   text, and NO green or red is introduced — four cells along, green means PASS and red
   means NOT PASS, so the only tint added here is blue.
   🔴 NO `overflow` HERE — neither `hidden` (it clips the right-hand columns) nor `auto`.
   `auto` was tried first and the review caught two costs: this root is REPLACED by
   outerHTML on every repaint (a lane pick, Select all, Show more), so a sideways scroll
   snapped back to the left each time; and the card's own scrollbar sat under up to 200
   rows. Left visible, a too-wide table scrolls the PAGE, as it did before — the window
   keeps its position across a repaint and its scrollbar is always on screen.
   `min-width: min-content` makes the CARD grow with the table instead, so on a narrow
   window the border still goes round every column rather than the table poking out. */
.cp-pm-carriercard {
  background: var(--arl-white, #FFFFFF);
  border: 1px solid var(--arl-border, #E0E0E0);
  border-radius: 10px;
  padding: 14px 16px 10px;
  gap: 10px;
  min-width: min-content;
}
/* A readable heading: the section headings' small grey capitals, in the card's own words. */
.cp-pm-carriercard > .cp-pm-sectionh {
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--arl-text, #333333);
}
/* The card IS the frame — the table's own border, radius and shadow would draw a second
   one inside it (`.cp-qm .cp-table`, equal specificity, earlier in the file). */
.cp-pm-carriercard > .cp-table { border: 0; border-radius: 0; box-shadow: none; overflow: visible; }
/* The name is not a link and the row is not clickable, so it is not link-blue here. */
.cp-pm-carriercard .cp-carrier-name { color: var(--arl-text, #333333); }
/* DOT/MC and the spread line: `.cp-sub` has no rule anywhere, so they rendered at the
   name's size. Smaller and quieter, the name leads. */
.cp-pm-carriercard .cp-sub { font-size: 12px; color: var(--arl-text-secondary, #666666); }
/* The card's small buttons in sentence case — "Send email", not "SEND EMAIL". The site's
   `.btn` is uppercase with letter-spacing, which on a working list of 500 rows shouts from
   every strip. Scoped to this card; the buttons, their classes and hooks are unchanged. */
.cp-pm-carriercard .btn-sm {
  font-family: inherit;
  letter-spacing: 0;
  text-transform: none;
}
/* Strip 1: the two ways a carrier gets onto a project, side by side when there is room.
   Each keeps its own root and report; an opened add form or a report takes the full row. */
.cp-pm-carriertools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 28px;
}
.cp-pm-carriertools > .cp-pm-import,
.cp-pm-carriertools > .cp-toolbar { flex: 1 1 420px; margin-bottom: 0; }
/* Anything that is NOT one of the two control rows — the opened add form, either report —
   takes a whole row. Said by exclusion rather than by naming them: naming the add receipt
   here gave its selector a second occurrence in this file, which a mutation anchor and a
   "has its own rule" test both read as the receipt's own rule (2026-09-29 review). Keep
   the receipt's class name, with its brace, out of this comment for the same reason. */
.cp-pm-carriertools > :not(.cp-pm-import):not(.cp-toolbar) { flex: 1 1 100%; margin-bottom: 0; }
/* Strip 2, directly over the rows: the safety roll-up beside the selection bar. */
.cp-pm-carrierbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px 18px;
  padding-top: 8px;
  border-top: 1px solid var(--arl-border, #E0E0E0);
}
.cp-pm-carrierbar > .cp-toolbar { margin-bottom: 0; }
/* The lane's search box, first in that strip (2026-10-05). `.cp-search` draws the box; this
   makes it smaller — 31px tall on dev against `.cp-search`'s 36px — so it sits quieter over
   the rows. Later in the file than `.cp-search` and equal in weight, so it wins on order
   (measured on dev against a copy without this class). */
.cp-pm-carriersearch {
  padding: 6px 10px;
  font-size: 13px;
}
/* "3 of the 514 carriers on this tab match" — quiet, like the scope beside the heading. */
.cp-pm-searchnote {
  font-size: 12px;
  color: var(--arl-text-secondary, #666666);
}
/* Replied and Notes read as one pair of controls. A thread with NEW replies wears the
   tag's blue — the "2 new" in it is still the words that say so. */
.cp-pm-carriercard .cp-pm-threadbtn,
.cp-pm-carriercard .cp-pm-notesbtn { min-width: 56px; min-height: 26px; }
.cp-pm-carriercard .cp-pm-threadbtn:has(.cp-pm-replied) {
  background: #E6F1FB;
  border-color: #B5D4F4;
  color: #0C447C;
}
.cp-pm-pagenote {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  font-size: 12px;
  color: var(--arl-text-muted);
}
.cp-pm-sectionerr {
  margin: 0 0 8px;
  font-size: 13px;
}
[data-cp-pm-lane-active][aria-busy="true"] {
  opacity: 0.6;
}

/* ── Carrier notes ────────────────────────────────────────────────────────────
 * Presentation ONLY. Who wrote a note, when, whether it is automatic, and the fact
 * that notes span every lane are all real text in the markup. Nothing here uses
 * content: attr() or a pseudo-element to deliver a value — this module shipped a
 * separator that lived in ::before and made a rating read as "4.76", and one missing
 * brace once made Chrome throw away 46 rules with no error at all. */
/* ── Ask BDR: the questions on a project ─────────────────────────────────────
   ⚠️ EVERY DISTINCTION HERE IS ALREADY IN THE TEXT. "sent to Keith Reeher" and
   "nobody was notified — no requester on the project" are different SENTENCES, not
   one sentence in two colours. This module shipped a rating that read as "4.76"
   because a separator lived in ::before; a reader with the stylesheet stripped, or
   colour-blind, must lose nothing here. Colour is emphasis only.

   Every var() carries a literal fallback. The project view does add .cp-qm (see
   cpPmLoadDetail), so --qm-* is in scope today — but .cp-ltab lost its whole border
   when a var resolved to nothing outside that class, and a missing fallback voids the
   entire declaration rather than degrading it. */
.cp-pm-asks {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cp-pm-ask {
  padding: 8px 12px;
  border-left: 3px solid var(--arl-border, #e0e0e0);
  background: var(--arl-surface-alt, #faf9f9);
  border-radius: 0 6px 6px 0;
}
.cp-pm-ask-head { font-size: 12px; font-weight: 600; }
.cp-pm-ask-body {
  margin-top: 3px;
  font-size: 13px;
  /* The OC typed this. Their line breaks are part of the question. */
  white-space: pre-wrap;
}
.cp-pm-ask-foot { margin-top: 5px; font-size: 11px; }
.cp-pm-ask-to { color: var(--arl-text-muted, #999999); }
.cp-pm-ask-nobody { color: var(--arl-warning, #d97706); }
.cp-pm-ask-warn { color: var(--arl-warning, #d97706); }
/* Pushed to the end of the section heading, which is already a flex row. */
.cp-pm-sectionh [data-cp-pm-ask] { margin-left: auto; }

/* ── The answers under a question, and the BDR's answer box (2026-10-01) ──────────
   Drawn on the OC's page AND on Project Management - BDR, whose host is created at
   runtime — so bare classes, every var() with a literal fallback, as the block above.
   Every distinction is in the TEXT ("No reply in FORGE yet", "Sent — …"); colour is
   emphasis only. */
.cp-pm-ask-replies {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}
.cp-pm-ask-reply {
  padding: 6px 10px;
  border-left: 3px solid var(--arl-primary, #0060AF);
  /* --arl-white, NOT --arl-surface: that token is #EEEEEE, a grey, not a page background. */
  background: var(--arl-white, #ffffff);
  border-radius: 0 6px 6px 0;
}
.cp-pm-ask-replyhead { font-size: 12px; font-weight: 600; }
.cp-pm-ask-replybody {
  margin-top: 2px;
  font-size: 13px;
  /* The BDR typed this; their line breaks are part of the answer. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* --arl-text-secondary (#666, ~5.5:1 here), not --arl-text-muted (#999, under 3:1). */
.cp-pm-ask-noreply { margin-top: 6px; font-size: 11px; color: var(--arl-text-secondary, #666666); }
.cp-pm-ask-replyform { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.cp-pm-ask-replyform textarea {
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  resize: vertical;
  padding: 6px 8px;
  border: 1px solid var(--arl-border, #e0e0e0);
  border-radius: 6px;
  background: var(--arl-white, #ffffff);
  color: inherit;
  font: inherit;
  font-size: 13px;
}
.cp-pm-ask-replyform textarea:focus-visible { outline: 2px solid var(--arl-primary, #0060AF); outline-offset: 1px; }
.cp-pm-ask-replyactions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* `.btn` carries a 6px left margin for a button beside a sibling; this one leads its row. */
.cp-pm-ask-replyactions .btn { margin-left: 0; }
/* Literal 700-weight greens and ambers on purpose: --arl-success and --arl-warning are
   about 3:1 on white, too faint for a 12px sentence that says whether an answer went. */
.cp-pm-ask-replystatus { font-size: 12px; color: var(--arl-text-secondary, #666666); }
.cp-pm-ask-replystatus[data-tone="ok"] { color: #15803d; }
.cp-pm-ask-replystatus[data-tone="warn"] { color: #b45309; }

/* ── Project Management - BDR ────────────────────────────────────────────────────
   ⚠️ `.cp-bdr .cp-bdr-tabs`, two classes: `.cp-qm .cp-ltabs` (0,2,0) pulls the strip up
   with a -6px bottom margin, and a one-class rule would parse, match and LOSE. Equal
   specificity, later in the file, wins. The tabs are LINKS, so the underline goes too. */
.cp-bdr .cp-bdr-tabs { margin: 4px 0 14px; }
.cp-bdr .cp-bdr-tabs .cp-ltab { text-decoration: none; }
.cp-bdr-summary { margin: 0 0 12px; font-size: 13px; }
.cp-bdr-note { margin: 0 0 8px; }
.cp-bdr-group + .cp-bdr-group { margin-top: 12px; }
.cp-bdr-qgroup + .cp-bdr-qgroup { margin-top: 16px; }
.cp-bdr-link { text-decoration: none; }
.cp-bdr-link:hover,
.cp-bdr-link:focus-visible { text-decoration: underline; }
.cp-bdr-waiting { color: #b45309; }
/* The Questions tab names what a link opened it for — a bell's question, or a project's
   questions — and marks it. An OUTLINE, so marking it moves nothing on the page. Two
   classes: the question rows have rules of their own, and a one-class mark must not lose. */
.cp-bdr .cp-bdr-target {
  outline: 2px solid var(--arl-primary, #0060AF);
  outline-offset: 3px;
  border-radius: 8px;
  /* A project's section scrolls to its TOP — keep that below the sticky app header. */
  scroll-margin-top: calc(var(--app-content-top, 56px) + 12px);
}
.cp-bdr-missing { color: #b45309; }
/* Project Management's Questions tab (2026-10-05) — the BDR page's Questions tab, from the
   other side: the same question rows (`.cp-pm-asks`), grouped by project. Its own classes,
   so neither page's rules can restyle the other. */
.cp-pmq-bar { margin-bottom: 10px; }
.cp-pmq-summary { margin: 0 0 12px; font-size: 13px; }
.cp-pmq-note { margin: 0 0 8px; color: #b45309; }
.cp-pmq-group + .cp-pmq-group { margin-top: 16px; }
.cp-pmq-link { text-decoration: none; }
.cp-pmq-link:hover,
.cp-pmq-link:focus-visible { text-decoration: underline; }
/* "Ask a follow-up" at the end of its project's heading, where Ask BDR sits on the project page. */
.cp-pmq-group > .cp-pm-sectionh [data-cp-pmq-ask] { margin-left: auto; }
/* A bell's question, marked. An OUTLINE, so marking it moves nothing; two classes, because
   the question rows have rules of their own and a one-class mark must not lose to them. */
.cp-pmq .cp-pmq-target {
  outline: 2px solid var(--arl-primary, #0060AF);
  outline-offset: 3px;
  border-radius: 8px;
}
/* "+ New project" on the BDR page (release 2). The form is Project Management's own, bare
   classes and all, so only what is the BDR page's is styled here: the sentence that says who
   it is requested by (it sits in the form's grid where Project Management has two people
   pickers), and the note on the project page right after a save. Literal 700-weight green and
   amber on purpose, as on the answer status line: the tokens are about 3:1 on white. */
.cp-bdr-asker { margin: 0; font-size: 13px; color: var(--arl-text-secondary, #666666); }
.cp-bdr-asker strong { color: var(--arl-text, #333333); }
.cp-bdr-saved {
  padding: 8px 12px;
  border-left: 3px solid #15803d;
  border-radius: 4px;
  background: #f0fdf4;
  color: #14532d;
  font-size: 13px;
}
.cp-bdr-saved[data-tone="warn"] { border-left-color: #b45309; background: #fffbeb; color: #78350f; }
/* The BDR lanes card borrows two of Project Management's LOOKS for its own hooks, as rules of
   its own — PM's keep their exact selectors, which PM's tests read:
   · the "Click a lane…" hint reads as a sentence, not in the heading's capitals (PM's rule is
     scoped to `.cp-pm-lanescard`; this card is `.cp-bdr-lanes`) — (0,3,0) beats both
     `.cp-pm-sectionh`'s capitals and `.cp-pm-scope`'s faint grey;
   · an OPEN lane's button looks like PM's picked one, keyed on `aria-expanded` (this button
     opens a panel) where PM's keys on `aria-pressed`. */
.cp-bdr-lanes > .cp-pm-sectionh .cp-pm-scope {
  text-transform: none;
  letter-spacing: normal;
  color: var(--arl-text-secondary, #666666);
}
.cp-pm-lanego[aria-expanded="true"] {
  border-color: var(--arl-primary, #0060AF);
  background: #FFFFFF;
}
/* (Who answered on a lane — the BDR project page's panel — is styled after the carrier
   notes rules below, because its notes ARE those notes and one of its rules has to come
   after theirs.) */

.cp-pm-notesbtn {
  border: 1px solid var(--arl-border);
  border-radius: 6px;
  background: transparent;
  color: var(--arl-text);
  font: inherit;
  font-size: 12px;
  min-width: 34px;
  padding: 2px 8px;
  cursor: pointer;
}
.cp-pm-notesbtn:hover {
  border-color: var(--arl-text-muted);
}
/* Open notes: blue, like the selected tab — not the brand red NOT PASS shares (2026-09-29). */
.cp-pm-notesbtn[aria-expanded="true"] {
  border-color: var(--arl-primary, #0060AF);
  font-weight: 600;
}
/* The carrier note thread. Renamed off `.cp-pm-notes`, which the PROJECT notes card
   also used: two rules, same class, identical specificity (0,1,0). The later one won
   on padding, so the project card lost its 10px/12px, and the thread inherited the
   card's border-left, margins and — the one that actually showed — white-space:
   pre-wrap, which rendered the template's own indentation as visible whitespace. */
.cp-pm-notethread {
  padding: 4px 2px 8px;
}
.cp-pm-notescope {
  margin: 0 0 10px;
  font-size: 12px;
  color: var(--arl-text-muted);
}
.cp-pm-notelist {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 340px;
  overflow-y: auto;
}
/* A typed note is a CARD; an automatic entry is a quiet line in the same list.
   Fabio, 2026-09-21: the thread should read "something like the comments that are shown
   at the bug reports", and FORGE's own status lines should "stay in the same list, just
   quieter".

   🔑 THE TWO TREATMENTS ARE THIS FAR APART BECAUSE OF THE MEASUREMENT. Across both dev
   projects — 1,016 carriers — the threads hold **1 human note and 31 status lines**. A
   card per entry would give 31 boxes to the machine and one to the person. So the card
   is the human's, and an automatic entry keeps only a left rule: present, readable,
   and out of the way.

   ⚠️ NO `content:` AND NO `::before`/`::after` ANYWHERE BELOW `.cp-pm-notesbtn` — the
   existing guard in pm-notes-client.test.js forbids them over exactly that slice, and it
   is right to: this module shipped a separator in a `::before` and a carrier rating read
   as "4.76". Everything a reader needs is in the markup.

   ⚠️ PM's host carries `.cp-qm` (`classList.add('cp-pm', 'cp-qm')`), unlike the Reply
   dialog the conversation card was built for — so a `.cp-qm` descendant rule WOULD
   compete here. Checked: the only `.cp-qm <element>` rules in this file target inputs
   (css:662-675), which none of these elements are. Verified in a browser against a
   control clone in the real `.cp-pm.cp-qm` context rather than assumed. */
.cp-pm-note {
  border: 1px solid var(--arl-border, #E0E0E0);
  border-left: 2px solid var(--arl-border, #E0E0E0);
  border-radius: 8px;
  padding: 8px 10px;
  background: var(--arl-white, #FFFFFF);
}
/* An automatic entry gives up the card — no box, no background — and keeps the left
 * rule so it still reads as part of the thread. It ALSO carries the words "status
 * change" in the markup, so it stays distinguishable with no stylesheet at all: a human
 * note mistaken for an automatic one is how a rep ignores "do not use, insurance
 * lapsed", and that failure must not depend on CSS loading. */
.cp-pm-note-auto {
  border: 0;
  border-left: 2px dotted var(--arl-border, #E0E0E0);
  border-radius: 0;
  padding: 0 0 0 10px;
  background: none;
}
.cp-pm-note-auto .cp-pm-notebody {
  color: var(--arl-text-muted, #999999);
  font-size: 12px;
}
/* How many times a run said the same thing. Measured worst case on dev: nine identical
 * "Status set to interested." lines, 19:17:15 through 19:31:12 — so this is the ordinary
 * shape of a worked carrier, not an edge case. */
.cp-pm-noterepeat {
  font-size: 11px;
  font-weight: 600;
  color: var(--arl-text-secondary, #666666);
}
.cp-pm-notemeta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: baseline;
  font-size: 12px;
  margin-bottom: 2px;
}
.cp-pm-notekind {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--arl-text-muted);
  border: 1px solid var(--arl-border);
  border-radius: 4px;
  padding: 0 4px;
}
/* Which lane a status line is about.
 *
 * 🔑 The lane is CONTENT, not decoration — it is the difference between "this carrier
 * changed their mind eleven times" and "these are two lanes". So it is real text in the
 * markup and this rule only makes it quiet. With the stylesheet gone it still reads.
 * This module shipped a separator that lived in `::before` and made a rating read as
 * "4.76"; nothing here may carry meaning in CSS alone.
 *
 * ⚠️ Deliberately NOT `--arl-surface-2`. That custom property is declared in no
 * stylesheet under apps/server/public — four rules read it with a `transparent`
 * fallback and all four silently did nothing until #416, one of them copied from a
 * neighbour the day before. `--arl-surface-alt` is declared at styles.css:16-18.
 *
 * ⚠️ The host here is `.cp-pm.cp-qm`, so every `.cp-qm` descendant rule in this file is
 * a competitor. This selector is a single class at (0,1,0) and nothing in `.cp-qm`
 * targets `.cp-pm-notelane`; checked rather than assumed, because the conversation
 * card's bare classes exist precisely because ITS host sits outside `.cp-qm`. */
.cp-pm-notelane {
  font-size: 11px;
  font-weight: 600;
  color: var(--arl-text-secondary, #666666);
  background: var(--arl-surface-alt, #f4f4f5);
  border-radius: 4px;
  padding: 0 5px;
}
/* pre-wrap, so a multi-line note keeps its shape without any markup being built from
 * user text. The body is escaped; the line breaks are the stylesheet's job. */
.cp-pm-notebody {
  font-size: 13px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.cp-pm-noteform {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 640px;
}
.cp-pm-noteinput {
  width: 100%;
  font: inherit;
  font-size: 13px;
  padding: 6px 8px;
  border: 1px solid var(--arl-border);
  border-radius: 6px;
  background: transparent;
  color: var(--arl-text);
  resize: vertical;
}
.cp-pm-noteactions {
  display: flex;
  align-items: center;
  gap: 10px;
}
.cp-pm-notecount {
  font-size: 11px;
}
.cp-pm-noteerr {
  margin: 0 0 4px;
  font-size: 12px;
}
[data-cp-pm-noterow] > td {
  background: var(--arl-surface-alt, #FAF9F9);
}

/* ── Project Management - BDR: who answered on a lane (2026-10-02) ───────────────────
   The row the BDR's project page opens right under a clicked lane. The CELL is tinted, as
   on the notes row just above: `.cp-qm .cp-table tbody tr:hover` paints the ROW, and a
   cell is drawn over its row, so the panel keeps its tint under the pointer.
   The carriers' notes are Project Management's own note cards in a `.cp-pm-notelist`.
   ⚠️ `.cp-bdr-notes` comes AFTER `.cp-pm-notelist` on purpose: the two are one class each
   (0,1,0), so the later rule wins — each carrier's notes end where the carrier does (the
   12px between carriers is the list's own gap), and they are shown IN FULL. PM's 340px
   scroll box opens on the newest note (cpPmNoteScrollToNewest); here it would open on the
   oldest and hide the newest, once per carrier, in boxes nested in the page. */
[data-cp-bdr-answers] > td { background: var(--arl-surface-alt, #FAF9F9); }
.cp-bdr-answers { padding: 4px 2px 8px; }
.cp-bdr-answersh { margin: 0 0 6px; font-size: 13px; }
.cp-bdr-answergroup + .cp-bdr-answergroup { margin-top: 14px; }
.cp-bdr-answergrouph { margin: 0 0 8px; font-size: 13px; }
.cp-bdr-answerlist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.cp-bdr-answerhead {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: baseline;
  margin-bottom: 6px;
  font-size: 13px;
}
.cp-bdr-notes {
  margin-bottom: 0;
  max-height: none;
  overflow-y: visible;
}
.cp-bdr-nonotes { margin: 0; font-size: 12px; }

/* What the carrier said WITH the answer (2026-10-02): the price and loads a week on
   Interested, then the Notes or the Reason, each behind a small label — above the other
   notes, which get a heading of their own when both are there. Bare classes: the panel sits
   in the BDR page, which carries no .cp-qm. */
.cp-bdr-price,
.cp-bdr-said {
  margin: 0 0 6px;
  font-size: 13px;
  line-height: 1.45;
}
.cp-bdr-saidlabel {
  display: inline-block;
  margin-right: 8px;
  padding: 0 6px;
  border-radius: var(--arl-radius);
  background: var(--arl-surface-light, #F5F5F5);
  /* --arl-text-secondary, not -muted: #999 on this grey is under 3:1 at 11px. */
  color: var(--arl-text-secondary, #666666);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
/* Typed text keeps its line breaks, as a note card does. */
.cp-bdr-saidbody { white-space: pre-wrap; overflow-wrap: anywhere; }
.cp-bdr-saidwho { font-size: 12px; }
.cp-bdr-nosaid { margin: 0 0 6px; font-size: 12px; }
.cp-bdr-otherh {
  margin: 6px 0 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--arl-text-secondary, #666666);
}

/* ── Quote by phone: the entry form on the Active-quotes panel ──────────────
 *
 * ⚠️ These rules deliberately set NO border, padding or font-size on the inputs
 * themselves. `.cp-qm input[type="text"]` (:657) already owns those at (0,2,1) —
 * one class plus an attribute selector — so a `.cp-mq-field > input` rule at
 * (0,1,1) would PARSE, sit in `cssRules`, MATCH the element and still lose, which
 * is exactly how #345 shipped a scroll box that computed `overflow: hidden` and
 * clipped 107 of 112 carriers while its structural test stayed green. Rather than
 * win that fight with a heavier selector, this styles only properties nothing else
 * sets on these elements — layout — so there is no cascade to lose.
 *
 * Every token used here is declared at `:root` in styles.css (--arl-border,
 * --arl-text-secondary, --arl-error), so no literal fallback is needed. The
 * `--qm-*` scale is deliberately NOT used: it lives on `.cp-qm`, and a var() that
 * resolves to nothing voids its whole declaration — how `.cp-ltab` lost its border
 * and how the Vet chip shipped unstyled.
 */
.cp-mq-wrap {
  margin-top: 10px;
}
.cp-mq-form {
  margin-top: 8px;
  padding: 10px 12px;
  border: 1px solid var(--arl-border);
  border-radius: 8px;
  max-width: 760px;
}
/* The "Quote from <carrier>" line a PREFILLED form carries, with the dispatch
 * verdict and the Vet link beside the name. Only on the prefilled form: an empty
 * one has no carrier to name. `align-items: center` because the badge and the
 * chip are inline-blocks of a different height than the text they sit against. */
.cp-mq-for {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 10px;
  font-size: 13px;
}
.cp-mq-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 8px;
}
/* `min-width: 0` on both the field and the input: a flex item's default
 * `min-width: auto` is the input's intrinsic size, so without it a narrow panel
 * pushes the row wider than the table instead of wrapping. */
.cp-mq-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1 1 140px;
  min-width: 0;
}
.cp-mq-field > span {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--arl-text-secondary);
}
.cp-mq-field > input {
  width: 100%;
  min-width: 0;
}
.cp-mq-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}
.cp-mq-msg {
  font-size: 12px;
  color: var(--arl-text-secondary);
}
/* A failure has to be distinguishable from "Saving…" and from "already on file",
 * which share this element — the message is the only feedback the form gives. */
.cp-mq-msg.cp-mq-bad {
  color: var(--arl-error);
  font-weight: 600;
}
.cp-mq-note {
  font-size: 11px;
  margin-top: 8px;
}


/* The lane tick-list on the hand-add form.
 *
 * 🔴 THE FIGHT IS ON THE LABEL RULE ONLY, and the arithmetic below applies to it alone.
 * The CONTAINER rule `.cp-pm-form .cp-pm-addlanes` (0,2,0) competes with nothing — it is
 * kept scoped for consistency with its sibling, not because it has to win anything. An
 * earlier version of this comment claimed both selectors were fighting the same battle;
 * an adversarial review pointed out that is false for the container, and a comment that
 * over-states a mechanism is the kind this module has had to correct before.
 * `.cp-pm-form label` is (0,1,1) and sets `flex-direction: column`, which stacks a
 * checkbox ABOVE its own text — so a single-class rule here would PARSE, sit in
 * cssRules, MATCH the element and still LOSE, which is exactly how #345 shipped a
 * scroll box computing `overflow: hidden`. Adding `.cp-pm-form` in front wins on
 * specificity rather than on source order.
 *
 * ⚠️ No `--qm-*` token is read here. They live on `.cp-qm`/`.cp-sourcing`, and the
 * Project Management panel is one of the hosts that carries neither — a var() that
 * resolves to nothing voids its whole declaration (#170). `--arl-*` is declared at
 * `:root` and is safe. */
.cp-pm-form .cp-pm-addlanes {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  align-items: center;
}
.cp-pm-form .cp-pm-addlanes label {
  flex-direction: row;
  align-items: center;
  gap: 6px;
  color: var(--arl-text);
  font-size: 13px;
}
/* The hand-add hint, beside the button. Declarations identical to
 * `.cp-pm-importhint` and DELIBERATELY NOT that class: a test asserts the
 * Not-on-a-lane tab renders no `cp-pm-import`, and `cp-pm-importhint` contains
 * that string as a substring — so borrowing it made the import control
 * unassertable. Three shared declarations are not worth making a neighbour
 * impossible to test for. */
.cp-pm-addhint {
  font-size: 12px;
  color: var(--arl-text-muted);
  flex: 1 1 240px;
}
/* The "Suggest carriers from ARL history" hint (2026-09-29). Same look, its OWN class,
 * for the reason above: borrowing the hand-add hint's class made the add-carrier checks
 * read the suggest button's hint as the hand-add form's, and a mutation anchor matched
 * twice. (The class name is left out of this comment on purpose, for the same reason.) */
.cp-pm-suggesthint {
  font-size: 12px;
  color: var(--arl-text-muted, #999999);
  flex: 1 1 240px;
}
.cp-pm-addlanesh {
  flex: 1 1 100%;
  font-size: 12px;
  color: var(--arl-text-muted);
}

/* The hand-add receipt.
 *
 * 🔴 DELIBERATELY NOT `.cp-pm-importreport`, whose declarations these duplicate. That
 * class CONTAINS the substring `cp-pm-import`, and
 * `pm-lane-workspace-client.test.js` asserts the Not-on-a-lane tab renders none of
 * it — so borrowing it made the IMPORT control impossible to assert the absence of.
 * The hint class was already renamed for exactly this reason and the report div was
 * missed; an adversarial review caught it. Four shared declarations are not worth
 * making a neighbouring component untestable. */
.cp-pm-addreport {
  margin-bottom: 14px;
  padding: 10px 12px;
  border: 1px solid var(--arl-border);
  border-radius: 6px;
  background: var(--arl-surface-alt, #FAF9F9);
  font-size: 13px;
}

/* The lanes a receipt names. A <ul>, because a lane label CONTAINS a comma
 * ("Lemont, IL → Baraboo, WI") — joining three of them with ", " produced a run of
 * six place names a rep could not parse into lanes. The boundary is structural. */
.cp-pm-addlanes-said {
  margin: 4px 0 0;
  padding-left: 18px;
}
.cp-pm-addlanes-said li { margin: 0; }

/* "Create quote" (Fabio, 2026-09-25) — the button sits where the "+ another lane…"
 * picker did (that picker and its `.cp-pm-addlane` rule are gone: one lane per carrier),
 * and a carrier's prices on the project's OTHER lanes read under their name.
 *
 * ⚠️ BARE CLASSES, and no `--qm-*` token. The DIALOG is appended to <body>, outside the
 * project host that carries `.cp-qm`, so a `--qm-*` var() in its rules would resolve to
 * nothing and VOID the whole declaration (#170); `--arl-*` is declared at `:root` and is
 * safe anywhere. The row rules sit inside that host and could read `--qm-*`, but use the
 * same `--arl-*` tokens so the two halves of one feature cannot drift apart. */
.cp-pm-quotebtn { margin-top: 6px; }
/* In the carrier card (2026-09-29) a small outline PILL, not a full button in every row.
   Only the shape is set: size and padding come from the site's `.btn-sm`, which declares
   both `!important` (styles.css) — a padding here was measured losing to it and removed
   rather than left looking load-bearing. Sentence case comes from `.cp-pm-carriercard
   .btn-sm`. Kept AFTER the base rule, which tests read as this class's rule. */
.cp-pm-carriercard .cp-pm-quotebtn { border-radius: 999px; }
.cp-pm-otherquotes {
  margin-top: 4px;
  font-size: 12px;
  color: var(--arl-text-muted);
}
.cp-pm-otherquotes strong { color: var(--arl-text); font-weight: 600; }
.cp-pm-quotecell { font-variant-numeric: tabular-nums; }
/* The dialog's form. NOT `.cp-pm-form`: that rule draws a bordered, padded box, which
 * inside a modal reads as a box within a box. Only the label layout is borrowed. */
.cp-pm-quoteform label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--arl-text-muted);
}
.cp-pm-quotewas {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--arl-text-muted);
}

/* The loads a week under a price in the QUOTE column (2026-10-02). */
.cp-pm-quoteloads { white-space: nowrap; }

/* ── The answer pop-up: Interested / Not interested (2026-10-02) ──────────────────────
   Built on Create quote's form (.cp-pm-quoteform, .cp-pm-formgrid, .cp-pm-input), in the
   same <body>-level dialog, so it looks like it. These add the lane line, the
   leaving-Emailed warning, the line saying who will read it, the note box, and the mark
   on the box the rep has to fix. */
.cp-pm-answerlane {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--arl-text);
}
.cp-pm-answerwarn {
  margin: 0 0 12px;
  padding: 8px 10px;
  border-radius: var(--arl-radius);
  background: var(--arl-warning-light, #FEF3C7);
  color: var(--arl-text);
  font-size: 13px;
}
.cp-pm-answerwho {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--arl-text-muted);
}
/* "Who you talked to" (#305): a small heading over the three optional boxes, and the line
   it becomes under the carrier's name in the list. */
.cp-pm-contacthead {
  margin: 4px 0 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--arl-text);
}
.cp-pm-talkedto { margin-top: 2px; }
.cp-pm-talkedto strong { font-weight: 600; color: var(--arl-text); }
.cp-pm-answernote {
  min-height: 72px;
  resize: vertical;
  line-height: 1.4;
}
.cp-pm-answerform [aria-invalid="true"] {
  border-color: var(--arl-error, #E11A22);
}

/* Remove sits at the foot of the notes panel, separated by a rule so it cannot be
 * mistaken for part of the note form above it. */
.cp-pm-noteremove {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--arl-border);
}

/* ⚠️ THE COLOUR IS NOT THE WARNING. The button says "Remove from project" and the
 * hint beside it names what goes, so a rep who cannot distinguish the tint still
 * reads the consequence — this module shipped a rating whose meaning lived in CSS
 * once and will not do it again. */
.cp-pm-removebtn { color: var(--arl-error, #e11a22); }

.cp-pm-removehint {
  font-size: 12px;
  flex: 1 1 260px;
}

.cp-pm-removeerr {
  flex: 1 1 100%;
  margin: 4px 0 0;
  font-size: 12px;
}

/* ── Coverage - OS: the supervisors' page and its team cards (2026-09-23) ─────────
   ⚠️ BARE CLASSES, `--arl-*` TOKENS ONLY. The page's container (#cp-os-view) is
   created by registerModuleView with no `.cp-qm` class, and the team dialog is
   appended to <body> — so a `.cp-qm`-scoped rule would never match, and a `--qm-*`
   token would resolve to nothing and void its whole declaration. That is how the Vet
   chip shipped as a bare link on two of four screens (#170). `--arl-*` is declared
   at :root. */
.cp-os-mine { margin: 0 0 6px; font-size: 14px; color: var(--arl-text); }
.cp-os-next { margin: 0 0 18px; font-size: 12px; }
.cp-os-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 12px;
}
.cp-os-section-head h3 { margin: 0; font-size: 16px; }
/* Full width, as many cards per row as fit (Fabio: "make use of the full width"). */
.cp-os-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
  gap: 16px;
}
.cp-os-card {
  background: var(--arl-white);
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  padding: 16px;
  min-width: 0;
}
.cp-os-card-mine { border-color: var(--arl-primary); box-shadow: inset 0 0 0 1px var(--arl-primary); }
.cp-os-card-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.cp-os-card-title {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}
.cp-os-mine-tag {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--arl-primary);
}
.cp-os-card-actions { display: flex; gap: 6px; flex: 0 0 auto; }
/* `.btn` carries margin-left: 6px for buttons that sit beside siblings; the gap does
   that job here. (0,2,0) beats `.btn` (0,1,0) regardless of order. */
.cp-os-card-actions .btn { margin-left: 0; }
.cp-os-row { display: flex; gap: 12px; align-items: flex-start; padding: 8px 0; }
.cp-os-row + .cp-os-row { border-top: 1px solid var(--arl-border); }
.cp-os-label { flex: 0 0 96px; padding-top: 3px; font-size: 12px; color: var(--arl-text-muted); }
.cp-os-chips { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.cp-os-chip {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  padding: 2px 10px;
  border: 1px solid var(--arl-border);
  border-radius: 999px;
  background: var(--arl-surface-light);
  font-size: 12.5px;
  color: var(--arl-text);
  overflow-wrap: anywhere;
}
.cp-os-chip-warn { border-color: var(--arl-warning); background: var(--arl-warning-light); }
/* Visually hidden, still read aloud — the chip's ⚠ is aria-hidden, this says it in words. */
.cp-os-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
/* The New / Edit dialog. */
.cp-os-field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 14px; font-size: 13px; }
/* Nothing in styles.css dresses a plain text input inside a dialog — measured in the
   harness, it rendered with the browser's 2px inset border and no padding. */
.cp-os-field input {
  padding: 8px 10px;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  font: inherit;
  font-size: 14px;
  color: var(--arl-text);
  background: var(--arl-white);
}
.cp-os-field input:focus { outline: none; border-color: var(--arl-primary); box-shadow: 0 0 0 3px rgba(0, 96, 175, 0.12); }
.cp-os-form-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
@media (max-width: 640px) {
  .cp-os-form-cols { grid-template-columns: minmax(0, 1fr); }
}
.cp-os-pick {
  margin: 0;
  padding: 8px 10px;
  min-width: 0;
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
}
.cp-os-pick legend { padding: 0 4px; font-size: 12px; font-weight: 600; }
.cp-os-pick-item { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; padding: 3px 0; font-size: 13px; }
/* The OC list window's "Find a person" hides rows with `hidden`, which loses to the display
   above unless said again (2026-10-20). */
.cp-os-pick-item[hidden] { display: none; }
/* "OC list" beside "New team" in the Teams head (the head spreads its children apart). */
.cp-os-head-actions { display: inline-flex; gap: 8px; align-items: center; }
.cp-os-pick-warn { color: var(--arl-warning); }
.cp-os-pick-email { flex: 1 1 100%; padding-left: 20px; font-size: 11.5px; color: var(--arl-text-muted); overflow-wrap: anywhere; }
/* Why someone may be missing from the lists — below both, so it never scrolls away. */
.cp-os-form-note { margin-top: 10px; font-size: 12px; line-height: 1.45; color: var(--arl-text-muted); }
.cp-os-form-msg { margin-top: 10px; font-size: 13px; color: var(--arl-error, #e11a22); }
.cp-os-form-msg:empty { display: none; }

/* Coverage - OS part 2: one wide card per OC (2026-09-23). Still bare classes and
   --arl-* tokens only. The one place the board's .cp-qm styles apply is INSIDE a card
   body, which carries that class in its markup — the header stays outside so its
   buttons keep the plain page styling. */
.cp-os-cards { margin-bottom: 28px; }
/* Your team / Every OC: two of the kit's filter buttons; the one on carries `is-set`. The tools
   row itself is the kit's filter bar (`.cp-os-cards-tools`, 2026-11-05). */
.cp-os-switch { display: inline-flex; gap: 6px; }
.cp-os-cards-sum { margin: 0 0 12px; font-size: 13px; color: var(--arl-text-secondary); }
.cp-os-updating { color: var(--arl-text-muted); font-style: italic; }
.cp-os-notice {
  margin: 0 0 10px;
  padding: 8px 12px;
  font-size: 13px;
  color: var(--arl-text);
  background: var(--arl-warning-light);
  border-radius: var(--arl-radius);
}
/* One card per row, full width: the board inside is ten columns wide. */
.cp-os-oc-list { display: flex; flex-direction: column; gap: 14px; }
.cp-os-oc {
  min-width: 0;
  background: var(--arl-white);
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
}
.cp-os-oc-mine { border-color: var(--arl-primary); box-shadow: inset 0 0 0 1px var(--arl-primary); }
.cp-os-oc-none-card { border-left: 4px solid var(--arl-warning); }
.cp-os-oc-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 20px;
  padding: 12px 16px;
}
.cp-os-oc-who { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; min-width: 0; }
.cp-os-oc-name { margin: 0; font-size: 16px; font-weight: 600; color: var(--arl-text); overflow-wrap: anywhere; }
.cp-os-oc-sub { font-size: 12px; color: var(--arl-text-muted); overflow-wrap: anywhere; }
.cp-os-oc-teams { display: inline-flex; flex-wrap: wrap; gap: 4px; }
/* Primary text on the PALE surface: --arl-primary-light is a mid blue (#3388C7), and
   primary text on it measured 1.67:1 — unreadable. On --arl-surface-light it is 5.85:1. */
.cp-os-oc-team {
  padding: 1px 8px;
  font-size: 11px;
  font-weight: 600;
  color: var(--arl-primary);
  background: var(--arl-surface-light);
  border: 1px solid var(--arl-border);
  border-radius: 999px;
}
.cp-os-oc-stats { display: flex; flex-wrap: wrap; gap: 6px 22px; margin: 0; }
.cp-os-stat { display: flex; flex-direction: column; align-items: flex-end; min-width: 56px; }
.cp-os-stat dt { font-size: 11px; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; color: var(--arl-text-muted); }
.cp-os-stat dd { margin: 0; font-size: 20px; font-weight: 600; line-height: 1.2; color: var(--arl-text); font-variant-numeric: tabular-nums; }
.cp-os-stat-hot dd { color: var(--arl-error, #e11a22); }
.cp-os-oc-none { margin: 0; padding: 0 16px 14px; font-size: 13px; color: var(--arl-text-muted); }
/* The board's table scrolls sideways INSIDE its card on a narrow screen, never the
   page: ten columns do not fit a phone, and clipping them would hide the OC picker. */
.cp-os-oc-body { border-top: 1px solid var(--arl-border); overflow-x: auto; }
/* The card is the frame. The board's own table rule adds a border, a radius, a shadow
   and overflow:hidden (it is written for a table standing alone on a page) — a double
   border here, and a clip instead of a scroll on a phone. Child combinator: tables
   nested inside a load's panels keep their own frames. Equal specificity to that rule,
   so it wins by coming later in the file. */
.cp-os-oc-body > .cp-table { border: 0; border-radius: 0; box-shadow: none; overflow: visible; }
@media (max-width: 640px) {
  .cp-os-oc-stats { width: 100%; justify-content: space-between; gap: 6px 12px; }
  .cp-os-stat { align-items: flex-start; }
}

/* ── Coverage - OS part 3: the bulk move (Fabio, 2026-09-23) ─────────────────
   Tick boxes on the rows and a "select all" on each card, then one bar: how many,
   Move to, Move, Clear. Bare classes and --arl-* tokens, like the rest of this page. */
/* The tick box shares the caret cell, so the row keeps the board's ten columns.
   ⚠️ `-tick`, NOT `-pick`: `.cp-os-pick` is part 1's teams-dialog FIELDSET class (above),
   and a checkbox rule under that name restyled those fieldsets (review finding). */
.cp-os-oc-body .qm-caret-cell { width: 52px; white-space: nowrap; }
.cp-os-tick { margin: 0 6px 0 0; vertical-align: middle; cursor: pointer; }
.cp-os-tick-all { margin: 0; align-self: center; cursor: pointer; }
/* The slot exists so ticking can repaint the bar without rebuilding every card. It must
   NOT be a box: a sticky element sticks only within its parent, and the slot is exactly
   the bar's own height, so the bar had nowhere to travel and scrolled away with the page
   (review finding, measured in a browser). As `contents`, the bar's parent is the whole
   OC section, so it stays in reach down every card. An empty slot draws nothing. */
.cp-os-bulk-slot { display: contents; }
/* Sticky, so Move stays in reach while ticking loads far down a long card. The WINDOW
   scrolls here, and the app header is itself sticky at top 0 (z-index 100, 56px), so
   `top: 0` parked the bar behind it — hidden exactly when it was stuck (review finding).
   --app-content-top is the header's own offset, and it grows under the "View as" banner. */
.cp-os-bulk {
  position: sticky;
  top: var(--app-content-top);
  z-index: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin: 0 0 12px;
  padding: 10px 12px;
  background: var(--arl-surface-light);
  border: 1px solid var(--arl-border);
  border-radius: 10px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
}
.cp-os-bulk .btn { margin-left: 0; }
.cp-os-bulk-count { font-size: 14px; color: var(--arl-text); }
.cp-os-bulk-to { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--arl-text-secondary); }
.cp-os-bulk-to select { max-width: min(260px, 100%); padding: 4px 6px; border: 1px solid var(--arl-border); border-radius: 6px; background: #fff; font: inherit; color: var(--arl-text); }
/* Dark text on the pale token: the token colours alone are about 3:1 on white. */
/* The result sticks where the bar was: a move made from the stuck bar, deep in a card,
   must not report what did NOT move (or "let them know yourself") off-screen at the top
   of the section (review finding). The bar and the note never show together — a new
   tick clears the note, and a successful move empties the bar — so they share one spot.
   Both tones below paint an opaque background, which a stuck element needs. */
.cp-os-bulk-note { position: sticky; top: var(--app-content-top); z-index: 3; margin: 0 0 12px; padding: 8px 12px; border-radius: 8px; font-size: 13px; }
.cp-os-bulk-note-ok { background: var(--arl-success-light); color: #166534; }
.cp-os-bulk-note-warn { background: var(--arl-warning-light); color: #92400e; }
.cp-os-bulk-from { margin: 6px 0 10px 18px; padding: 0; font-size: 13px; }
/* ── Loads at risk (Coverage - OS part 4, 2026-09-24) ──────────────────────────────
   BARE classes and --arl-* tokens only, for the reason the part-2 block gives: these
   render inside `.cp-qm` on Coverage and Load Detail, but also in the at-risk strip on
   #cp-os-view, where no `.cp-qm` ancestor exists outside the table wrapper. None of them
   uses `.qm-chip`, whose layout rule is `.cp-qm`-scoped and would not apply there. */
.cp-load-hot {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--arl-error, #E11A22);
  color: #fff;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  line-height: 1.6;
  vertical-align: middle;
  white-space: nowrap;
}
.cp-risk-clock {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--arl-warning-light, #FEF3C7);
  color: #92400E;
  font-size: 10.5px;
  font-weight: 700;
  vertical-align: middle;
  white-space: nowrap;
}
/* Dark text on the pale token, as .cp-status-lost does: the token red alone is ~4:1 on it. */
.cp-risk-clock.cp-risk-past { background: var(--arl-error-light, #FEE2E2); color: var(--arl-accent-dark, #BD0E0E); }
.cp-window-default {
  display: inline-block;
  margin-top: 2px;
  padding: 0 6px;
  border: 1px dashed var(--arl-border);
  border-radius: 999px;
  color: var(--arl-text-secondary);
  font-size: 10.5px;
  font-weight: 600;
  white-space: nowrap;
}
.cp-hot-unknown { margin-left: 8px; font-size: 12px; font-weight: 400; color: var(--arl-text-muted); }
.cp-detail-actions .cp-hot-btn { margin-right: 6px; }
.qm-expand-links .cp-hot-btn { margin-left: auto; }

/* ── Coverage - OS: OCs at a glance (2026-10-07) ─────────────────────────────────
   One small card per OC under the heading; since 2026-11-10 a click shows that OC's loads in
   the OCs section below (the picked card is pressed, .is-shown). Still bare
   classes and --arl-* tokens only. The initials circle is the Projects list's own
   `.cp-pm-avatar` (no copy of its rule); the pills are its word-bearing tags' palette. */
.cp-os-glance { margin: 0 0 18px; }
.cp-os-glance-head { display: flex; align-items: baseline; gap: 12px; margin: 0 0 8px; }
.cp-os-glance-head h3 { margin: 0; font-size: 16px; }
/* min(100%, …): a bare 230px track overflows a 327px phone (the teams grid's lesson).
   Many OCs wrap onto more rows — nothing hidden, no sideways scroll. */
.cp-os-glance-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr));
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cp-os-glance-list > li { min-width: 0; }
.cp-os-glance-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  width: 100%;
  height: 100%;
  min-width: 0;
  margin: 0;
  text-align: left;
  font: inherit;
  color: var(--arl-text);
  background: var(--arl-white);
  border: 1px solid var(--arl-border);
  border-radius: var(--arl-radius);
  padding: 10px 12px;
  cursor: pointer;
}
/* The border says "clickable" too: the paler background alone barely shows on a white page. */
.cp-os-glance-card:hover { background: var(--arl-surface-alt); border-color: var(--arl-primary); }
.cp-os-glance-card:focus-visible { outline: 2px solid var(--arl-primary); outline-offset: 2px; }
/* The OC whose loads show below: the open row's blue, and a thicker edge — a shape as well as
   a colour. */
.cp-os-glance-card.is-shown { background: var(--fk-moving-bg); border-color: var(--fk-blue-600); box-shadow: inset 0 -3px 0 var(--fk-blue-600); }
/* No OC picked yet: what to do, where the loads will be. */
.cp-os-pick-hint { margin: 0; padding: 18px 16px; border: 1px dashed var(--arl-border); border-radius: var(--arl-radius); color: var(--arl-text-secondary); text-align: center; }
/* The No-OC card: the wide No-OC card's own warning edge. */
.cp-os-glance-none { border-left: 4px solid var(--arl-warning); }
.cp-os-glance-who { display: flex; align-items: center; gap: 8px; min-width: 0; max-width: 100%; }
/* A long address WRAPS: before the directory loads a name reads as its email. */
.cp-os-glance-name { min-width: 0; overflow-wrap: anywhere; font-size: 14px; font-weight: 600; }
.cp-os-glance-mine {
  flex: none;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--arl-surface);
  color: var(--arl-primary);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}
.cp-os-glance-figs { font-size: 12px; line-height: 1.5; color: var(--arl-text-secondary); }
/* One figure never breaks between its number and its words. */
.cp-os-glance-fig { white-space: nowrap; }
.cp-os-glance-n { font-weight: 600; color: var(--arl-text); }
.cp-os-glance-risk {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.cp-os-glance-risk--on { background: var(--arl-error-light); color: var(--arl-accent-dark); }
.cp-os-glance-risk--none { background: var(--arl-surface); color: var(--arl-text-secondary); }
/* --arl-text-muted (#999) is 2.8:1 on white; the secondary grey is the lightest that passes. */
.cp-os-glance-risk--unknown { padding-left: 0; background: transparent; color: var(--arl-text-secondary); font-weight: 400; }
.cp-os-glance-note { margin: 8px 0 0; font-size: 12px; color: var(--arl-text-secondary); }
/* The shown OC's card lands below the sticky app header (and the "View as" banner, which
   grows --app-content-top) rather than under it. Focused only by script, so no ring. */
.cp-os-oc { scroll-margin-top: calc(var(--app-content-top, 56px) + 12px); }
.cp-os-oc:focus { outline: none; }
/* While loads are ticked the bulk bar is stuck there too — or the move's result, which sticks
   in its place: land the card's head below it. --cp-os-stuck-h is the bar's MEASURED height,
   set by the glance click (cpOsJumpControl) — one line wide, three on a phone; 52px is one line. */
#cp-os-cards:has(.cp-os-bulk, .cp-os-bulk-note) .cp-os-oc {
  scroll-margin-top: calc(var(--app-content-top, 56px) + var(--cp-os-stuck-h, 52px) + 12px);
}
/* A phone: thirteen cards at full width were 1,400px of page. Compact instead — the tag on the
   name row, right-aligned, and the three figures on one line under it. */
@media (max-width: 600px) {
  .cp-os-glance-list { gap: 8px; }
  .cp-os-glance-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 4px 8px;
    padding: 8px 10px;
  }
  .cp-os-glance-who { grid-column: 1; grid-row: 1; }
  .cp-os-glance-risk { grid-column: 2; grid-row: 1; justify-self: end; }
  .cp-os-glance-figs { grid-column: 1 / -1; }
}

/* ── The Project Management tour guide (cpTour, 2026-10-06) ────────────────────────
   Appended to <body>, outside every .cp-qm scope: it reads only its own --cp-tour-*
   tokens, declared on the root here, and --arl-* tokens declared at :root in styles.css.
   An undeclared var() would render the card transparent with no error anywhere.
   Modifiers are compound selectors on the element that carries them. */
.cp-tour-root {
  --cp-tour-dim: rgba(1, 10, 25, 0.55);
  --cp-tour-ring: color-mix(in srgb, var(--arl-primary) 70%, transparent);
  --cp-tour-primary: var(--arl-primary);
  --cp-tour-primary-hover: var(--arl-primary-dark);
  --cp-tour-surface: var(--arl-white);
  --cp-tour-hover: var(--arl-surface-light);
  --cp-tour-border: var(--arl-border);
  --cp-tour-text: var(--arl-text);
  --cp-tour-text-2: var(--arl-text-secondary);
  --cp-tour-dot: var(--arl-text-muted);
  --cp-tour-dot-past: color-mix(in srgb, var(--arl-primary) 40%, transparent);
  --cp-tour-shadow: var(--arl-shadow-lg);
  --cp-tour-radius: var(--arl-radius-lg);
  --cp-tour-btn-radius: var(--arl-radius);
  --cp-tour-font: var(--arl-font-body);
  --cp-tour-font-ui: var(--arl-font-accent);
  --cp-tour-ease: cubic-bezier(0.22, 1, 0.36, 1);
  position: fixed;
  inset: 0;
  z-index: 100000;            /* above the 429 notice (app.js, 99999) and the feedback modal (10000) */
  opacity: 0;
  transition: opacity 300ms linear;
}
.cp-tour-root.is-in { opacity: 1; }
/* While it fades out only the card stops taking clicks; the shield under it keeps
   catching them until the root is removed, so a double-click never reaches the page. */
.cp-tour-root.is-leaving .cp-tour-cardpos { pointer-events: none; }
.cp-tour-shield { position: absolute; inset: 0; background: transparent; }
/* The hole. Its huge spread shadow IS the dim; it takes no clicks, the shield does. */
.cp-tour-spot {
  position: absolute; left: 0; top: 0; width: 0; height: 0;
  border-radius: 10px;
  box-shadow: 0 0 0 200vmax var(--cp-tour-dim);
  pointer-events: none;
}
.cp-tour-spot.is-lit { outline: 2px solid var(--cp-tour-ring); }
.cp-tour-spot.is-animated {
  transition: transform 320ms var(--cp-tour-ease), width 320ms var(--cp-tour-ease),
    height 320ms var(--cp-tour-ease), border-radius 320ms var(--cp-tour-ease);
}
.cp-tour-cardpos { position: absolute; left: 0; top: 0; opacity: 0; }
/* Until its first placement the card waits, unseen, at the top-left corner, over the logo and
   the sidebar toggle: there it takes no click (an unseen Skip or Next). pointer-events, never
   visibility: the primary button must keep its focus, so the keys work from the first frame. */
.cp-tour-cardpos:not(.is-placed) { pointer-events: none; }
.cp-tour-cardpos.is-placed { opacity: 1; }
.cp-tour-cardpos.is-animated { transition: transform 320ms var(--cp-tour-ease), opacity 150ms linear; }
.cp-tour-card {
  position: relative; box-sizing: border-box;
  width: 352px; max-width: calc(100vw - 24px); padding: 16px;
  background: var(--cp-tour-surface); color: var(--cp-tour-text);
  border: 1px solid var(--cp-tour-border); border-radius: var(--cp-tour-radius);
  box-shadow: var(--cp-tour-shadow);
  font-family: var(--cp-tour-font); text-align: left;
}
.cp-tour-card.is-wide { width: 416px; padding: 20px; }
.cp-tour-card.is-shown { animation: cp-tour-pop 240ms var(--cp-tour-ease) both; }
.cp-tour-caret { position: absolute; width: 12px; height: 12px; background: var(--cp-tour-surface); transform: rotate(45deg); }
.cp-tour-caret.is-top    { top: -6px;    margin-left: -6px; border-left: 1px solid var(--cp-tour-border);  border-top: 1px solid var(--cp-tour-border); }
.cp-tour-caret.is-bottom { bottom: -6px; margin-left: -6px; border-right: 1px solid var(--cp-tour-border); border-bottom: 1px solid var(--cp-tour-border); }
.cp-tour-caret.is-left   { left: -6px;   margin-top: -6px;  border-left: 1px solid var(--cp-tour-border);  border-bottom: 1px solid var(--cp-tour-border); }
.cp-tour-caret.is-right  { right: -6px;  margin-top: -6px;  border-right: 1px solid var(--cp-tour-border); border-top: 1px solid var(--cp-tour-border); }
.cp-tour-head { display: flex; justify-content: flex-end; min-height: 4px; }
/* Two classes, so it beats the global h1, h2 rule (Oswald, UPPERCASE, blue). */
.cp-tour-card .cp-tour-title {
  margin: 0 0 6px;
  font-family: var(--cp-tour-font-ui); font-size: 17px; font-weight: 600; line-height: 1.3;
  letter-spacing: -0.01em; text-transform: none; color: var(--cp-tour-text);
}
.cp-tour-card.is-wide .cp-tour-title { font-size: 20px; }
.cp-tour-card .cp-tour-body { margin: 0; font-family: var(--cp-tour-font); font-size: 14px; line-height: 1.5; color: var(--cp-tour-text-2); }
.cp-tour-card.is-wide .cp-tour-body { font-size: 15px; }
.cp-tour-foot { display: flex; align-items: center; gap: 10px; margin-top: 14px; }
.cp-tour-dots { display: inline-flex; align-items: center; gap: 4px; }
.cp-tour-dots > span { display: block; width: 6px; height: 6px; border-radius: 999px; background: var(--cp-tour-dot);
  transition: width 200ms cubic-bezier(0.45, 0, 0.15, 1), background-color 200ms linear; }
.cp-tour-dots > span.is-current { width: 16px; background: var(--cp-tour-primary); }
.cp-tour-dots > span.is-past { background: var(--cp-tour-dot-past); }
.cp-tour-count { font-family: var(--cp-tour-font-ui); font-size: 12px; font-weight: 600;
  font-variant-numeric: tabular-nums; color: var(--cp-tour-text-2); white-space: nowrap; }
.cp-tour-actions { display: flex; align-items: center; gap: 6px; margin-left: auto; }
/* Its own button class: the global .btn is UPPERCASE, and .btn-sm forces 11px with !important. */
.cp-tour-btn {
  display: inline-flex; align-items: center; justify-content: center;
  margin: 0; padding: 6px 12px; border: 1px solid transparent; border-radius: var(--cp-tour-btn-radius);
  background: transparent; color: var(--cp-tour-primary);
  font-family: var(--cp-tour-font-ui); font-size: 13px; font-weight: 600; line-height: 1.2;
  letter-spacing: 0; text-transform: none; white-space: nowrap; cursor: pointer;
}
.cp-tour-btn.is-primary { background: var(--cp-tour-primary); border-color: var(--cp-tour-primary); color: var(--cp-tour-surface); }
.cp-tour-btn.is-primary:hover { background: var(--cp-tour-primary-hover); border-color: var(--cp-tour-primary-hover); }
.cp-tour-btn.is-ghost { color: var(--cp-tour-text-2); }
.cp-tour-btn.is-ghost:hover { background: var(--cp-tour-hover); color: var(--cp-tour-text); }
.cp-tour-btn:focus-visible { outline: 2px solid var(--cp-tour-primary); outline-offset: 2px; }
.cp-tour-btn.cp-tour-skip { padding: 2px 6px; font-size: 12px; }
.cp-tour-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* The "?" ("How this page works") sits on the page, outside the root, so it reads the --arl-*
   tokens directly. A page's own "?" floats (.cp-tour-fab, below); an opened load's and the
   Active quotes one sit in their rows. */
.cp-tour-help {
  display: inline-flex; align-items: center; justify-content: center; align-self: center;
  flex: 0 0 28px; width: 28px; height: 28px; margin-left: 6px; padding: 0; vertical-align: middle;
  border: 1px solid var(--arl-primary); border-radius: 50%;
  background: var(--arl-white); color: var(--arl-primary);
  font-family: var(--arl-font-accent); font-size: 15px; font-weight: 600; line-height: 1; cursor: pointer;
}
.cp-tour-help:hover { background: var(--arl-primary); color: var(--arl-white); }
.cp-tour-help:focus-visible { outline: 2px solid var(--arl-primary); outline-offset: 2px; }
.cp-tour-help[aria-busy="true"] { opacity: 0.6; cursor: progress; }
/* The Projects list's "?" belongs to the Projects tab: not on Questions or Quotes. */
.cp-sourcing:has(> #cp-pm-panel.hidden) .cp-tour-help { display: none; }
/* An opened load's "?" ends its links row: sized to the row, not to a page header. */
.qm-expand-links > .cp-tour-help { flex-basis: 22px; width: 22px; height: 22px; font-size: 13px; }
/* The Active quotes "?" ends the small line under an opened load's tabs: sized to that line. */
.cp-ltab-sub > .cp-tour-help { width: 20px; height: 20px; font-size: 12px; }
/* A page's own "?" (Fabio, 2026-10-13): small, fixed at the bottom right so it stays in reach
   as the page scrolls, just LEFT of the bug button (feedback.css .fb-floating-btn: fixed, right
   20px, bottom 20px, 48px) with an 8px gap, and centred on it: right 20 + 48 + 8, bottom
   20 + (48 - 32) / 2. Calm, not the bug's red. z-index 45: over the page's own sticky bars,
   under the email drawer (50), the phone drawer (89/90), every dialog (200+) and the tour. */
.cp-tour-help.cp-tour-fab {
  position: fixed; right: 76px; bottom: 28px; z-index: 45;
  flex: none; width: 32px; height: 32px; margin: 0;
  border-color: var(--arl-border); color: var(--arl-text-secondary); box-shadow: var(--arl-shadow);
}
.cp-tour-help.cp-tour-fab:hover { border-color: var(--arl-primary); background: var(--arl-primary); color: var(--arl-white); }
/* No bug button on screen (feedback.css hides it with .hidden; it is never injected on /login):
   the "?" takes the bug's spot, centred where the bug would be. */
body:not(:has(> .fb-floating-btn:not(.hidden))) .cp-tour-help.cp-tour-fab { right: 28px; }
@keyframes cp-tour-pop { from { opacity: 0; transform: translateY(-4px) scale(0.98); } }
@media (prefers-reduced-motion: reduce) {
  .cp-tour-root, .cp-tour-spot.is-animated, .cp-tour-cardpos.is-animated, .cp-tour-dots > span { transition: none; }
  .cp-tour-card.is-shown { animation: none; }
}

/* ── Coverage restyle: the Strategy Pulse look in FORGE's colours (Fabio, 2026-10-20) ─────
   Approved from a mock. Page-level rules are scoped to #cp-coverage-view.cp-sp (an id, so
   they outrank the `.cp-qm .cp-table` rules above); the row's own pieces (lane + customer,
   avatar, equipment tag, Quotes cell) are plain `.cp-sp-*` classes because the Coverage - OS
   cards draw the same row. Type: one family (Segoe UI) at 14px; colours: --arl-* only. */
#cp-coverage-view.cp-sp {
  font-family: "Segoe UI", system-ui, -apple-system, Roboto, var(--arl-font-body), sans-serif;
  font-size: 14px;
  color: #1F1F1F;
}
#cp-coverage-view.cp-sp .cp-page-header { align-items: flex-start; margin-bottom: 20px; }
#cp-coverage-view.cp-sp .cp-page-header h2 {
  font-family: inherit; font-size: 26px; font-weight: 600; line-height: 1.2;
  text-transform: none; letter-spacing: 0; color: #1F1F1F; margin: 0;
}
.cp-sp-desc { margin: 4px 0 0; color: #6B6B6B; font-size: 14px; }
#cp-coverage-view.cp-sp .cp-count {
  display: block; margin-top: 8px; font-family: inherit; font-size: 12px; font-weight: 400;
  letter-spacing: 0; color: #6B6B6B;
}

/* Buttons: one filled primary per page, the rest outlined; normal case. */
.cp-sp-actions { display: flex; align-items: center; gap: 8px; }
.cp-sp-btn {
  display: inline-flex; align-items: center; gap: 6px; height: 36px; padding: 0 12px;
  border: 1px solid var(--arl-border); border-radius: 6px; background: var(--arl-white);
  color: #1F1F1F; font: 500 14px/1 inherit; font-family: inherit; cursor: pointer; white-space: nowrap;
}
.cp-sp-btn:hover { background: #F0F2F5; }
.cp-sp-btn-primary { background: var(--arl-primary); border-color: var(--arl-primary); color: #fff; font-weight: 600; }
.cp-sp-btn-primary:hover { background: var(--arl-primary-dark); }
.cp-sp-btn:focus-visible, .cp-sp-tab:focus-visible { outline: 2px solid var(--arl-primary); outline-offset: 2px; }

/* `hidden` must win over the display this class sets (a button hidden from a reader):
   author CSS otherwise beats the browser's own [hidden] rule. */
.cp-sp-btn[hidden] { display: none; }
.cp-sp-pop-label { font-size: 12px; font-weight: 600; color: #4F4F4F; }

/* ── The filter bar (Fabio, 2026-11-05: "something alike what we have in the Load builder") ──
   Coverage's search and filters, and Coverage - OS's controls, are the FORGE kit's filter bar
   (forge-kit.css `.fk-filterbar`, as on the Review Queue). What is CP's own is below: the bar
   drawn as a card above the tabs, every menu opening to the RIGHT of its button, and room in
   More filters for the dates. Colours are the kit's tokens.
   Rightward because a button's LEFT edge stays put: the kit opens a menu leftward (for a More
   filters at a bar's end), so when More filters' count appeared the button grew and its menu
   jumped ~20px under the cursor — seen on dev, a click meant for Include overdue landed outside
   the menu and shut it. Here no bar has an end element, so rightward fits on a desktop. */
.cp-cov-bar { margin-bottom: 10px; background: var(--fk-surface); border: 1px solid var(--fk-line); border-radius: var(--fk-radius-md); }
.cp-fk-pick > .fk-filter-menu { right: auto; left: 0; width: 300px; gap: 8px; }
.cp-cov-more > .fk-filter-menu { right: auto; left: 0; width: 340px; gap: 8px; }
.cp-cov-more .cp-range { display: flex; flex-wrap: wrap; gap: 6px; }
/* The arrow after OC / Customer: they open a menu, as a dropdown does. */
.cp-fk-caret { width: 12px; height: 12px; flex: none; fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
/* A long customer name in the button: cut, with the whole list in the button's hover. */
.cp-fk-pick [data-cp-pick-value] { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A tick box held by a filter button (Include overdue on Coverage - OS): its own size, not
   the kit's full-height control. */
.cp-os-cards-tools .fk-filter > input[type="checkbox"] { width: auto; height: auto; margin: 0; }
/* The OS bar sits flush with the page's sections, its line under it like the Review Queue's. */
.cp-os-cards-tools { padding-left: 0; padding-right: 0; margin-bottom: 8px; }
@media (max-width: 800px) {
  /* On a phone the bar wraps and a button can start a line: every menu opens rightward and
     is never wider than the screen. */
  .cp-fk-pick > .fk-filter-menu, .cp-cov-more > .fk-filter-menu { right: auto; left: 0; width: min(320px, calc(100vw - 48px)); }
}
/* The OC filter as tick boxes (2026-10-21: several OCs at once). None ticked = every OC. */
.cp-oc-checks { border: 1px solid var(--arl-border, #E0E0E0); border-radius: 6px; background: var(--arl-white, #FFFFFF); }
.cp-oc-checks-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 10px; border-bottom: 1px solid #EEF0F2; font-size: 12px; color: #6B6B6B; }
.cp-oc-checks-clear { border: 0; background: none; padding: 0; color: var(--arl-primary, #0060AF); font: inherit; font-weight: 600; cursor: pointer; }
.cp-oc-checks-clear:hover { text-decoration: underline; }
.cp-oc-checks-list { max-height: 220px; overflow-y: auto; padding: 4px 0; }
.cp-oc-check { display: flex; align-items: center; gap: 8px; padding: 5px 10px; font-size: 14px; color: #1F1F1F; cursor: pointer; }
.cp-oc-check:hover { background: #F0F2F5; }
.cp-oc-check input { margin: 0; }

/* Quick-filter tabs with counts. */
.cp-sp-tabs { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 14px; }
.cp-sp-tabs:empty { display: none; }
.cp-sp-tab {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 12px; border-radius: 999px;
  border: 1px solid var(--arl-border); background: var(--arl-white); color: #4F4F4F;
  font: inherit; font-size: 13px; cursor: pointer;
}
.cp-sp-tab:hover { background: #F0F2F5; }
.cp-sp-tab-n { font-size: 12px; color: #6B6B6B; }
.cp-sp-tab-on, .cp-sp-tab-on:hover { background: var(--arl-primary); border-color: var(--arl-primary); color: #fff; font-weight: 600; }
.cp-sp-tab-on .cp-sp-tab-n { color: #CCE0F1; }
.cp-sp-tabs-sep { width: 1px; height: 20px; margin: 0 4px; background: var(--arl-border); }

/* The grid: grey normal-case header, compact rows, a white card. */
/* `overflow: clip`, not `hidden`, for the rounded corners: `hidden` makes the table a scroll box,
   and a header cell pinned inside one sticks to the TABLE, so it never pins. `clip` cuts the same
   corners and leaves the page as the thing that scrolls. */
#cp-coverage-view.cp-sp .cp-table {
  border-radius: 8px; overflow: clip;
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05), 0 0 1px rgba(16, 24, 40, 0.14);
}
#cp-coverage-view.cp-sp .cp-table thead th {
  font-family: inherit; font-size: 12px; font-weight: 600; text-transform: none; letter-spacing: 0;
  color: #4F4F4F; background: #F8F9FA; padding: 10px 12px;
}
/* The header row stays on screen while the loads scroll (Fabio, 2026-11-10: "leave the headers
   static"), pinned under the app header (and the "View as" banner) as Quote Tracker's is (#123):
   the window scrolls, and the app header is sticky at 0 over everything, so `top: 0` would park
   it behind that. Over the rows (a HOT row's tint, the open row's edge), under the side panel (50)
   and the app header (100). The line under it is a shadow: with collapsed borders a border-bottom
   belongs to the row below and would slide away. */
#cp-coverage-view.cp-sp #cp-loads-table > thead th {
  position: sticky; top: var(--app-content-top); z-index: 3;
  box-shadow: 0 1px 0 var(--fk-line);
}
/* On a phone the table scrolls sideways in its own box (.fk-table-scroll), where there is no page
   to pin to — that offset would push the header down over the first loads — so there it stays put. */
@media (max-width: 800px) {
  #cp-coverage-view.cp-sp .fk-table-scroll #cp-loads-table > thead th { position: static; }
}
#cp-coverage-view.cp-sp .cp-table tbody td { padding: 9px 12px; border-bottom-color: #EEF0F2; font-size: 14px; }
#cp-coverage-view.cp-sp .cp-table tbody tr.cp-row:hover td { background: #F7FAFD; }

/* The row's pieces — on Coverage and in the Coverage - OS cards alike. */
.cp-sp-lane { font-weight: 600; color: #1F1F1F; }
.cp-sp-sub { margin-top: 2px; font-size: 12px; color: #6B6B6B; }
/* The equipment: plain words, no box (Fabio, 2026-11-10: "Remove the borders of the equipment
   type"). No padding either, so it lines up under its column heading like the cells beside it. */
.cp-sp-tag {
  display: inline-block; padding: 0; border: 0;
  color: #4F4F4F; font-size: 12px; white-space: nowrap;
}
.cp-sp-avatar {
  display: inline-grid; place-items: center; width: 24px; height: 24px; margin-right: 8px; border-radius: 50%;
  vertical-align: middle; color: #fff; font-size: 10px; font-weight: 700; letter-spacing: 0;
}
.cp-sp-avatar-0 { background: var(--arl-primary); }
.cp-sp-avatar-1 { background: #00437A; }
.cp-sp-avatar-2 { background: #0F766E; }
.cp-sp-avatar-3 { background: #7C3AED; }
.cp-sp-avatar-4 { background: #B45309; }
.cp-sp-avatar-5 { background: #BE185D; }
.cp-sp-qpill {
  display: inline-flex; align-items: center; height: 22px; padding: 0 9px; border-radius: 999px;
  font-size: 12px; font-weight: 600; white-space: nowrap;
}
.cp-sp-qpill-has { background: rgba(0, 96, 175, 0.10); color: var(--arl-primary-dark); }
.cp-sp-qpill-none { background: var(--arl-warning-light); color: #92400E; }
.cp-sp-qsub { margin-top: 3px; font-size: 12px; color: #6B6B6B; white-space: nowrap; }

/* ── The other Carrier Procurement pages in the same look (Fabio, 2026-10-21) ──────────────
   "Update the visual style for all of the other Carrier Procurement tabs": the Load page,
   Coverage - OS, Project Management (and its BDR twin), Carriers, Vetting and Tracking, all
   in one change, the look only. Nothing here renders anything or moves a control, so every
   page works exactly as before.
   How it is scoped, so it cannot reach outside CP or undo a page's own decisions:
   - Each rule names the page hosts by id. :where(...) adds no weight, for rules that only
     have to beat the shared base rules (styles.css, quote-tracker.css and the top of this
     file); :is(...) carries an id's weight, for the few that must beat a quote-manager-scoped rule.
   - No selector here names the quote-manager scope class and no body uses its tokens (the
     OS guards read to the end of the file), every var() has a literal fallback, and rules
     stay one per line so none repeats a mutation anchor's text.
   - Left alone on purpose: the lane status tabs (underlined, Fabio's feedback #66 "Status as
     tabs", and shared with Tracking), coloured verdict borders, the table frames inside
     cards, and every page's own layout. */
:where(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) { font-family: "Segoe UI", system-ui, -apple-system, Roboto, var(--arl-font-body, 'Source Sans Pro'), sans-serif; font-size: 14px; color: #1F1F1F; }

/* Page title: 26px, semibold, normal case, near-black, with one grey line under it. */
:is(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) .cp-page-header h2,
:is(#cp-load-detail-view, #cp-loadpop, #cp-carrier-detail-view) h2.cp-detail-title { font-family: inherit; font-size: 26px; font-weight: 600; line-height: 1.2; text-transform: none; letter-spacing: 0; color: #1F1F1F; }
:is(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) .cp-page-header > div > .cp-count,
:is(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) .cp-page-header > div > .cp-sub,
:is(#cp-load-detail-view, #cp-loadpop, #cp-carrier-detail-view) .cp-detail-meta { display: block; margin-top: 4px; font-family: inherit; font-size: 14px; font-weight: 400; letter-spacing: 0; color: #6B6B6B; }
:where(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) .cp-count { font-family: inherit; letter-spacing: 0; }
:where(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) .cp-back { font-family: inherit; font-size: 14px; font-weight: 500; }

/* Section and card headings: normal case, near-black, one family. */
:is(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(.cp-card-title, .cp-pm-sectionh, .cp-dircard-title, .cp-dirprof-h) { font-family: inherit; font-size: 15px; font-weight: 600; text-transform: none; letter-spacing: 0; color: #1F1F1F; }
:where(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(h3, h4, h5) { font-family: inherit; color: #1F1F1F; }

/* Labels: normal case and grey instead of small blue capitals. */
:where(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(.cp-field-label, .cp-stat-label, .cp-pref-dim-label) { font-family: inherit; font-size: 12px; font-weight: 600; text-transform: none; letter-spacing: 0; color: #6B6B6B; }
:where(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(.cp-ldstop-type, .cp-os-stat dt) { font-family: inherit; text-transform: none; letter-spacing: 0; }
:is(#cp-sourcing-view) .qm-lane-f > span { font-family: inherit; text-transform: none; letter-spacing: 0; }

/* Buttons: the kit's look comes from the base .btn in styles.css ("One FORGE look" step 3,
   2026-10-27). Here they only keep the page's own font family. Pressed toggles keep their own
   blue rules (the base outline hover skips [aria-pressed="true"]). */
:where(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) .btn { font-family: inherit; }

/* Tab strips (Projects / Questions / Quotes, Directory / Awaiting rating, the BDR tabs). */
:is(#cp-sourcing-view, #cp-bdr-projects-view, #cp-carriers-view) .cp-ltab { font-family: inherit; font-size: 14px; font-weight: 500; text-transform: none; letter-spacing: 0; }
:is(#cp-sourcing-view, #cp-bdr-projects-view, #cp-carriers-view) .cp-ltab.cp-ltab-on { font-weight: 600; }

/* Search boxes, dropdowns and the small toggles beside them. */
:is(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(.cp-search, .cp-select) { height: 36px; padding: 0 12px; border: 1px solid var(--arl-border, #E0E0E0); border-radius: 6px; background: var(--arl-white, #FFFFFF); color: #1F1F1F; font-family: inherit; font-size: 14px; }
:is(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(.cp-search, .cp-select):focus { outline: none; border-color: var(--arl-primary, #0060AF); box-shadow: 0 0 0 2px rgba(0, 96, 175, 0.15); }
:where(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(.cp-mine-toggle, .cp-check) { font-family: inherit; font-size: 13px; font-weight: 500; letter-spacing: 0; }

/* Table headers: grey band, normal case, 12px; cells in the page's size. */
:is(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(.cp-table thead th, .cp-mini-table th) { font-family: inherit; font-size: 12px; font-weight: 600; text-transform: none; letter-spacing: 0; color: #4F4F4F; background: #F8F9FA; }
:is(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(.cp-table tbody td, .cp-mini-table td) { font-size: 14px; border-bottom-color: #EEF0F2; }

/* Cards: rounded and lightly lifted; borders and coloured edges stay each card's own. */
:is(#cp-load-detail-view, #cp-loadpop, #cp-os-view, #cp-sourcing-view, #cp-project-detail-view, #cp-bdr-projects-view, #cp-bdr-project-detail-view, #cp-carriers-view, #cp-carrier-detail-view, #cp-vet-view, #cp-tracking-view) :is(.cp-card, .cp-dircard) { border-radius: 8px; box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05), 0 0 1px rgba(16, 24, 40, 0.14); }
