/* Emonics Consultant Onboarding -- design tokens shared with the portal
   family (navy/orange/bg/border palette, same spacing scale). Brand mark
   is CSS/text-only in this candidate -- the real logo asset is never
   typeset here (pre-candidate checklist). */

:root {
  --navy: #1E2A5E;
  --navy-dark: #141b40;
  --navy-mid: #2c3a72;
  --navy-tint: rgba(30, 42, 94, 0.06);
  --navy-tint-2: rgba(30, 42, 94, 0.11);
  --orange: #E65F3C;
  --orange-dark: #c94d2d;
  --orange-tint: rgba(230, 95, 60, 0.12);
  --icon-bg: #FDF0EC;
  --ink: #1a1f36;
  --ink-soft: #3d4560;
  --muted: #6b7280;
  --muted-light: #98a0b0;
  --bg: #F4F5F9;
  --card: #ffffff;
  --border: #E5E8F0;
  --border-soft: #EEF0F6;
  --error: #b91c1c;
  --error-bg: #fef2f2;
  --amber: #b45309;
  --amber-bg: #fef3c7;
  --success: #15803d;
  --success-bg: #f0fdf4;
  --green: #15803d;
  --green-bg: #dcfce7;

  /* Phase accents. Colour is an ACCENT per stage tile, never a grouping
     container -- phases interleave in the C2C and Training ladders
     (paperwork -> screening -> paperwork), so grouping them into contiguous
     blocks would misrepresent the order. Accenting each tile conveys the
     same phase information without touching sequence. */
  --phase-close: #1E2A5E;
  --phase-close-bg: rgba(30, 42, 94, 0.08);
  --phase-paperwork: #4338ca;
  --phase-paperwork-bg: rgba(67, 56, 202, 0.09);
  --phase-screening: #E65F3C;
  --phase-screening-bg: rgba(230, 95, 60, 0.11);
  --phase-prep: #0e7490;
  --phase-prep-bg: rgba(14, 116, 144, 0.10);
  /* RE-MARKETING gets its own accent and NOT a shade of marketing green
     (Art's ruling, 2026-07-30): it is a parallel entry queue into marketing,
     and 271 of these cards were split out of "Location assigned" precisely
     because their label was claiming progress they had not made. A green
     variant would say the same thing again in colour.
     Violet rather than amber or red: amber and red are already spoken for by
     the dwell states (.dwell-warn / .dwell-over), and a column whose every
     card is tinted "late" would drown the SLA signal on the cards that
     genuinely are. Violet sits far from teal (prep) and green (marketing) --
     its two neighbours on the board -- which is where the confusion would
     actually happen; indigo (paperwork) is five columns away. */
  --phase-remarketing: #7c3aed;
  --phase-remarketing-bg: rgba(124, 58, 237, 0.10);
  --phase-marketing: #15803d;
  --phase-marketing-bg: rgba(21, 128, 61, 0.10);

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;
  --radius-xl: 18px;

  --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.04);
  --shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 4px 14px rgba(16, 24, 40, 0.05);

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: "SFMono-Regular", Consolas, Menlo, monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
}

a { color: var(--navy); }
button { font-family: var(--font); cursor: pointer; }

.brand-logo { display: block; height: 28px; width: auto; }
.login-card .brand-logo { height: 40px; margin: 0 auto var(--space-5); }

/* ==================== login page ==================== */

.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: var(--space-6); }

.login-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-top: 3px solid var(--orange);
  border-radius: 16px;
  width: 100%;
  max-width: 380px;
  padding: var(--space-6) var(--space-6) var(--space-5);
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 8px 24px rgba(16, 24, 40, 0.06);
}

.login-card h1 { font-size: 22px; font-weight: 700; color: var(--navy); text-align: center; margin: 0 0 var(--space-1); }
.login-card .sub { text-align: center; color: var(--muted); margin: 0 0 var(--space-5); font-size: 13px; }

.login-card label { display: block; font-size: 12px; font-weight: 600; color: var(--navy); margin: 0 0 var(--space-2); letter-spacing: 0.02em; }

.login-card input[type="email"],
.login-card input[type="text"] {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 14px;
  margin-bottom: var(--space-4);
}

.login-card button {
  width: 100%;
  background: var(--navy);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 11px;
  font-weight: 600;
  font-size: 14px;
}
.login-card button:hover { background: var(--navy-dark); }

.login-msg { text-align: center; font-size: 13px; color: var(--muted); min-height: 18px; }
.login-footer { text-align: center; color: var(--muted); font-size: 12px; margin-top: var(--space-4); }

/* ==================== app shell ==================== */

.app-header {
  background: var(--navy);
  color: #fff;
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding: 0 var(--space-5);
  height: 56px;
}
.app-nav { display: flex; gap: var(--space-4); flex: 1; }
.app-nav a { color: rgba(255,255,255,0.75); text-decoration: none; font-size: 14px; font-weight: 600; padding: 8px 0; }
.app-nav a.active, .app-nav a:hover { color: #fff; border-bottom: 2px solid var(--orange); }
.app-account { display: flex; align-items: center; gap: var(--space-3); font-size: 13px; }
.btn-ghost { background: transparent; border: 1px solid rgba(255,255,255,0.3); color: #fff; border-radius: 6px; padding: 6px 10px; font-size: 12px; }
.btn-ghost:hover { background: rgba(255,255,255,0.1); }

/* The pipeline is a wide instrument -- the shell takes the viewport minus
   sane margins rather than a centred reading column, so stage cards can be
   large enough to hold consultants instead of shrinking to chips. */
.app-main { padding: var(--space-5) var(--space-6) var(--space-7); max-width: 1800px; margin: 0 auto; }
.view { display: none; }
.view.active { display: block; }
.page-title { font-size: 25px; font-weight: 700; color: var(--navy); letter-spacing: -0.015em; margin: 0 0 var(--space-1); }
.page-sub { color: var(--muted); font-size: 13.5px; margin: 0; max-width: 70ch; }
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-5); flex-wrap: wrap; margin-bottom: var(--space-5); }

/* ==================== board ==================== */

/* Division switch as a proper segmented control (same component language as
   org-hierarchy's), with each division's live headcount in its label. */
.division-tabs {
  display: inline-flex; background: #e9ecf3; border-radius: 9px; padding: 3px; gap: 2px;
  margin-bottom: var(--space-5);
}
.division-tab {
  background: none; border: none; color: var(--muted);
  font-family: inherit; font-size: 13px; font-weight: 600;
  padding: 7px 15px; border-radius: 6px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
  transition: background .14s ease, color .14s ease, box-shadow .14s ease;
}
.division-tab:hover:not(.active) { color: var(--ink); }
.division-tab.active { background: #fff; color: var(--navy); box-shadow: var(--shadow-sm); }
.division-tab .tab-count {
  min-width: 19px; height: 19px; padding: 0 6px; border-radius: 999px;
  background: var(--navy-tint-2); color: var(--navy);
  font-size: 11px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  font-variant-numeric: tabular-nums;
}
.division-tab.active .tab-count { background: var(--navy); color: #fff; }
.division-tab.is-zero .tab-count { background: transparent; color: var(--muted-light); border: 1px solid var(--border); }

/* Phase legend -- explains the accent colours without grouping stages. */
.phase-legend { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-4); }
.phase-key { display: inline-flex; align-items: center; gap: 7px; font-size: 11.5px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.phase-dot { width: 9px; height: 9px; border-radius: 3px; flex: none; }

/* Stage cards WRAP into a responsive grid instead of one horizontal strip --
   a 10-to-14-stage ladder forced sideways scrolling. Cards are deliberately
   LARGE (min 260px, min-height 196px): the board is the instrument an exec
   opens, and each card must hold 2-3 consultants without expanding. At
   1440px this lays out 5 per row, so the 14-stage FT ladder is 3 full rows
   filling the width and most of the height.

   Cards stretch to a uniform height per row. Letting populated cards grow
   past their row-mates instead left ragged gaps under every short card,
   which read as patchy rather than composed -- and stretching costs
   populated stages nothing, since the row grows to fit its tallest card.
   Because the ladder wraps, each card carries its step number --
   left-to-right alone no longer conveys sequence. */
.board {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  align-items: stretch;
  gap: var(--space-4);
  padding-bottom: var(--space-4);
}

.board-col {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  min-width: 0;
  min-height: 196px;
  display: flex;
  flex-direction: column;
  /* The phase accent rides the top edge of every card -- the journey reads
     as a coloured progression across the ladder, not 14 identical boxes.
     --phase-* are set per card by the renderer. */
  border-top: 3px solid var(--phase, var(--navy));
  transition: box-shadow .16s ease, border-color .12s ease;
}
.board-col:hover { box-shadow: var(--shadow); }

.board-col-header {
  padding: var(--space-4) var(--space-4) var(--space-3);
  display: flex; align-items: flex-start; gap: var(--space-3);
}
/* Step marker styled as a waypoint on the path, tinted to its phase. */
.stage-num {
  flex: none; width: 26px; height: 26px; border-radius: 8px;
  background: var(--phase-bg, var(--navy-tint));
  color: var(--phase, var(--navy));
  font-size: 12px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  font-variant-numeric: tabular-nums;
}
.stage-heading { flex: 1; min-width: 0; }
.stage-name {
  display: block;
  font-size: 12.5px; font-weight: 700; color: var(--navy);
  text-transform: uppercase; letter-spacing: 0.05em;
  line-height: 1.35; overflow-wrap: break-word;
}
.stage-phase { display: block; font-size: 10.5px; font-weight: 600; color: var(--muted-light); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 3px; }
/* Count as a big numeral, not a chip -- it is the number an exec scans for. */
.stage-count {
  flex: none; font-size: 26px; font-weight: 700; line-height: 1;
  color: var(--navy); font-variant-numeric: tabular-nums;
}
.board-col.is-empty .stage-count { color: var(--muted-light); font-weight: 600; }

.board-col-body {
  padding: 0 var(--space-3) var(--space-3);
  display: flex; flex-direction: column; gap: 7px;
  flex: 1;
}

/* ---- empty stage, designed rather than blank ----
   In the all-zero board an empty stage stays FULL SIZE: at zero the board
   must still look like a substantial instrument, not a collapsed accordion.
   A faint dashed well carries the stage's phase tint so the ladder reads as
   the map of the process even with nobody in it. */
.stage-well {
  flex: 1; border: 1px dashed var(--border); border-radius: var(--radius);
  background: linear-gradient(180deg, var(--phase-bg, var(--navy-tint)) 0%, rgba(255,255,255,0) 70%);
  display: flex; align-items: center; justify-content: center;
  min-height: 92px;
}
.stage-well span { font-size: 11.5px; font-weight: 600; color: var(--muted-light); letter-spacing: 0.04em; }

/* ...but once OTHER stages are populated, an empty stage recedes: it keeps
   its row's height so rows stay uniform, and drops the "Empty" well so five
   placeholders don't shout over the consultants who are actually there. */
.board.has-population .board-col.is-empty { box-shadow: none; background: #fbfcfe; }
.board.has-population .board-col.is-empty .stage-well { display: none; }

/* ---- full-board empty state ---- */
.board-empty-banner {
  display: flex; align-items: center; gap: var(--space-4);
  background: var(--card); border: 1px solid var(--border);
  border-left: 4px solid var(--orange);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-4);
  box-shadow: var(--shadow-sm);
}
.board-empty-banner .beb-icon {
  flex: none; width: 38px; height: 38px; border-radius: 10px;
  background: var(--icon-bg); color: var(--orange);
  display: flex; align-items: center; justify-content: center;
}
.board-empty-banner .beb-title { font-size: 14.5px; font-weight: 700; color: var(--navy); margin: 0 0 2px; }
.board-empty-banner .beb-sub { font-size: 12.5px; color: var(--muted); margin: 0; }

/* Consultant entry: a person with presence -- initials, name, dwell chip,
   and a dwell warning that escalates amber -> red rather than one flat
   "over SLA" flag. */
.card {
  background: #fff;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 9px 10px;
  cursor: pointer;
  display: flex; align-items: center; gap: 9px;
  transition: border-color .12s ease, background .12s ease, box-shadow .12s ease;
}
.card:hover { border-color: var(--navy); box-shadow: var(--shadow-sm); }
.card .avatar {
  flex: none; width: 28px; height: 28px; border-radius: 50%;
  background: var(--navy-tint-2); color: var(--navy);
  border: 1px solid rgba(30, 42, 94, 0.09);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em;
}
.card .card-identity { min-width: 0; flex: 1; }
.card .name {
  font-weight: 600; font-size: 13px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.card .meta { display: flex; align-items: center; gap: 6px; margin-top: 2px; }
.dwell {
  font-size: 11px; font-weight: 600; color: var(--muted);
  background: #f4f6fa; border-radius: 999px; padding: 2px 7px;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.card.dwell-warn { border-color: #f3ddb0; background: #fffdf6; }
.card.dwell-warn .dwell { background: var(--amber-bg); color: var(--amber); }
.card.dwell-over { border-color: #f3c6c6; background: var(--error-bg); }
.card.dwell-over .dwell { background: #fde2e2; color: var(--error); }
.card .lane-tag, .card .hold-tag {
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 2px 6px; border-radius: 4px; white-space: nowrap;
}
.card .lane-tag { background: var(--orange-tint); color: var(--orange-dark); }
.card .hold-tag { background: var(--amber-bg); color: var(--amber); }
/* "spine: dropped" is a statement of fact from another system, not an alarm
   this board raises -- grey, so it reads as provenance next to the amber grade
   chip rather than competing with the SLA colours for attention. */
.card .hold-tag.spine-dropped { background: rgba(107, 114, 128, 0.12); color: #4b5563; }
/* A TELL, NOT AN ALARM. The card is workable and the badge must not read
   like a blocker — same amber family as the other holds, no red. */
.card .hold-tag.no-trm-notes { background: rgba(107, 114, 128, 0.12); color: #4b5563; }
/* Mission B. Distinct from spine-dropped on purpose: one is a closed
   consultant, the other is one who is ALREADY BEING MARKETED and whose card
   intake simply cannot advance. Reading them as the same colour would merge a
   loss with a success. */
.card .hold-tag.spine-marketing { background: rgba(16, 185, 129, 0.14); color: #047857; }

/* --- Onboarding document lane ------------------------------------------
   The board indicator uses the SAME muted default as every other card tag:
   a consultant progressing normally is not news. Only `doc-attention` --
   set server-side when a send actually failed -- earns the error treatment,
   so a red tag on the board always means somebody may be waiting. */
.card .doc-tag {
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 2px 6px; border-radius: 4px; white-space: nowrap;
  background: var(--navy-tint-2); color: var(--navy);
}
.card .doc-tag.doc-flow_complete,
.card .doc-tag.doc-hr_verified { background: var(--green-bg); color: var(--green); }
.card .doc-tag.doc-none { background: #f2f4f8; color: var(--muted); }
/* Fenced is DELIBERATE, not broken -- amber (a held action), never red. It is
   visually distinct from doc-none so "we haven't got there yet" and "we tried
   and the fence held it" can never read as the same thing on a board. */
.card .doc-tag.doc-fenced { background: var(--amber-bg); color: var(--amber); }
.card .doc-tag.doc-attention { background: var(--error-bg); color: var(--error); }

/* Why nothing was sent, stated rather than left as an empty panel. */
.lane-note {
  font-size: 12.5px; color: var(--muted); line-height: 1.5;
  background: #f7f9fc; border-left: 3px solid var(--border);
  padding: 8px 10px; border-radius: var(--radius-sm); margin: 8px 0 0;
}

.resend-check {
  display: block; font-size: 12px; color: var(--ink-soft); line-height: 1.45;
  margin: 0 0 8px; font-weight: 500;
}
.resend-check input { margin-right: 6px; }

/* The lane's event trail. Suppressed and failed rows are visually distinct
   from ok ones -- scanning this list must make a non-delivery obvious. */
.engine-events { list-style: none; margin: 0; padding: 0; }
.engine-event {
  display: grid; grid-template-columns: 105px 110px 78px 1fr; gap: 6px;
  align-items: baseline; font-size: 11.5px; padding: 6px 8px;
  border-left: 3px solid var(--border-soft); margin-bottom: 3px;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0; background: #fbfcfe;
}
.engine-event .engine-when { color: var(--muted-light); font-variant-numeric: tabular-nums; }
.engine-event .engine-what { font-weight: 600; color: var(--ink); }
.engine-event .engine-outcome { font-weight: 700; text-transform: uppercase; font-size: 9.5px; letter-spacing: 0.05em; }
.engine-event .engine-reason { color: var(--ink-soft); font-weight: 600; }
.engine-event .engine-detail { grid-column: 4; color: var(--muted); }
.engine-event.engine-ok { border-left-color: var(--green); }
.engine-event.engine-ok .engine-outcome { color: var(--green); }
.engine-event.engine-suppressed { border-left-color: var(--amber); background: var(--amber-bg); }
.engine-event.engine-suppressed .engine-outcome { color: var(--amber); }
.engine-event.engine-failed { border-left-color: var(--error); background: var(--error-bg); }
.engine-event.engine-failed .engine-outcome { color: var(--error); }
.engine-event.engine-skipped .engine-outcome { color: var(--muted); }

@media (max-width: 720px) {
  .engine-event { grid-template-columns: 1fr; gap: 2px; }
  .engine-event .engine-detail { grid-column: 1; }
}

/* "+N more" when a stage holds more than the card shows at rest. */
.card-more {
  text-align: center; font-size: 11.5px; font-weight: 600; color: var(--muted);
  padding: 5px; border-radius: var(--radius-sm); background: #f7f9fc; cursor: pointer;
}
.card-more:hover { background: #eef2f8; color: var(--navy); }
.badge { display: inline-block; border-radius: 999px; padding: 2px 8px; font-size: 11px; font-weight: 600; background: var(--bg); color: var(--muted); }
.badge.division-FT { background: var(--orange-tint); color: var(--orange-dark); }
.badge.division-C2C { background: #EEF2FF; color: #3730A3; }
.badge.division-Hybrid { background: #ECFDF5; color: #065F46; }
.badge.division-Training { background: #FEF3C7; color: #92400E; }
.badge.over-sla { background: var(--error-bg); color: var(--error); }
/* THE PROVENANCE CHIP (Art, 2026-08-19). Amber rather than the C2C indigo, and
   deliberately NOT a division colour: it says something is OUTSTANDING — the
   terms are not set — and a chip that wore the division's own colour would read
   as a label rather than as the caution it is. Same family as `over-sla`, one
   step quieter, because this is a state to notice and not a breach. */
.badge.badge-provenance { background: #FEF3C7; color: #92400E; }

/* ==================== detail ==================== */

.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5); }
.detail-panel { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: var(--space-4); }
.detail-panel h2 { font-size: 14px; color: var(--navy); margin: 0 0 var(--space-3); }
.kv-row { display: flex; justify-content: space-between; padding: 6px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
.kv-row .k { color: var(--muted); }
.event-row, .mail-row { padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 12px; }
.event-row .dir-forward { color: var(--success); }
.event-row .dir-backward { color: var(--error); }
.event-row .dir-mint { color: var(--navy); }

.stage-advance { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-top: var(--space-4); }
.stage-advance select, .stage-advance input, .stage-advance button { padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; }
.stage-advance button { background: var(--navy); color: #fff; border: none; font-weight: 600; }
.stage-advance button:hover { background: var(--navy-dark); }

/* ==================== payments ==================== */

.payment-form { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-top: var(--space-4); align-items: center; }
.payment-form select, .payment-form input, .payment-form button { padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; }
.payment-form input[type="number"] { width: 120px; }
.payment-form input[type="file"] { border: none; padding: 0; }
.payment-form button { background: var(--orange); color: #fff; border: none; font-weight: 600; }
.payment-form button:hover { background: var(--orange-dark); }

/* ==================== pending assignments list ==================== */

.pending-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: var(--space-3);
  margin-bottom: var(--space-2);
}
.pending-row.over-sla { border-left: 3px solid var(--error); background: var(--error-bg); }
.pending-row .main { flex: 1; cursor: pointer; }
.pending-row .name { font-weight: 600; }
.pending-row .meta { color: var(--muted); font-size: 12px; }
.pending-row button { padding: 8px 14px; border: none; border-radius: 6px; font-weight: 600; font-size: 13px; background: var(--navy); color: #fff; }
.pending-row button:hover { background: var(--navy-dark); }
.pending-row .state-label { font-size: 12px; color: var(--muted); font-weight: 600; }

/* ==================== modal ==================== */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(16, 24, 40, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}
.modal-overlay[hidden] { display: none; }
.modal-box {
  background: var(--card);
  border-radius: 12px;
  padding: var(--space-5);
  min-width: 360px;
  max-width: 90vw;
  box-shadow: 0 8px 32px rgba(16, 24, 40, 0.2);
}
.modal-box h2 { margin: 0 0 var(--space-4); color: var(--navy); font-size: 16px; }
.modal-box .row { margin-bottom: var(--space-3); position: relative; }
.modal-box label { display: block; font-size: 12px; font-weight: 600; color: var(--navy); margin-bottom: var(--space-2); }
.modal-box input, .modal-box select { width: 100%; padding: 9px 11px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; }
.modal-box .actions { display: flex; gap: var(--space-2); justify-content: flex-end; margin-top: var(--space-4); }
.modal-box .actions button { padding: 9px 16px; border-radius: 6px; font-weight: 600; font-size: 13px; border: none; }
.modal-box .btn-primary { background: var(--orange); color: #fff; }
.modal-box .btn-primary:hover { background: var(--orange-dark); }
.modal-box .btn-cancel { background: var(--bg); color: var(--ink); }

/* ==================== employee picker ==================== */

.picker-row { position: relative; }
.picker-results {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 10;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  max-height: 220px;
  overflow-y: auto;
  box-shadow: 0 4px 12px rgba(16, 24, 40, 0.1);
}
.picker-option { padding: 8px 12px; font-size: 13px; cursor: pointer; }
.picker-option:hover { background: var(--bg); }
.picker-option.muted { color: var(--muted); cursor: default; }

/* ==================== new enrollment form ==================== */

.form-card { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: var(--space-5); max-width: 560px; }
.form-card .row { margin-bottom: var(--space-4); }
.form-card label { display: block; font-size: 12px; font-weight: 600; color: var(--navy); margin-bottom: var(--space-2); }
.form-card input, .form-card select { width: 100%; padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; font-size: 14px; }
.form-card button { background: var(--orange); color: #fff; border: none; border-radius: 8px; padding: 11px 18px; font-weight: 600; }
.form-card button:hover { background: var(--orange-dark); }

.msg { font-size: 13px; padding: 8px 10px; border-radius: 6px; margin-top: var(--space-3); }
.msg.error { background: var(--error-bg); color: var(--error); }
.msg.success { background: var(--success-bg); color: var(--success); }

/* ---- candidate profile (exec daily-review substance) ---- */
.profile-panel {
  border: 1px solid var(--border); border-left: 3px solid var(--orange);
  border-radius: var(--radius); background: #fcfdff;
  padding: var(--space-3) var(--space-4); margin: var(--space-3) 0;
}
.profile-panel-title {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.07em; color: var(--orange-dark); margin-bottom: var(--space-2);
}
.profile-panel .kv-row { padding: 5px 0; }
.profile-notes { margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--border-soft); }
.profile-notes .k { font-size: 12px; color: var(--muted); font-weight: 600; }
.profile-notes p { margin: 3px 0 0; font-size: 13px; color: var(--ink); }

/* compact profile line on a board card */
/* One line for a blocker ("waiting on: SDP signature, 3d") -- it is a fixed
   phrase and truncating it loses nothing. THREE for everything longer, because
   the Re-marketing line is not filler: "assignment lapsed 2026-04-18 · last
   marketer Twinkle Patel" IS the card, and clipping it at "assignment lapsed
   2026-..." throws away both the date and the name the queue is worked by.
   Three rather than two so the honest-uncertainty phrasing survives whole:
   "date not reliably known (recorded at mirror repair)" cut after "not
   reliably known" loses the reason, and the reason is the half that stops
   somebody going to look for what happened on the 28th. */
.card-profile {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  margin-top: 3px; font-size: 11px; color: var(--muted);
  overflow: hidden; overflow-wrap: anywhere; line-height: 1.4;
}

/* Dropped: visible on the board by ruling, but visually retired -- a
   neutral grey accent so it never competes with live pipeline stages. */
:root { --phase-dropped: #6b7280; --phase-dropped-bg: rgba(107, 114, 128, 0.10); }
.board-col.is-dropped { background: #fbfbfc; }

/* ==========================================================================
   INTAKE ADDITIONS
   --------------------------------------------------------------------------
   Everything above this line is the enrollment pipeline's stylesheet, copied
   verbatim. Nothing of intake's previous board CSS survives.

   Below is only what intake has and the enrollment console does not: a board
   that is dragged on, a multi-select facet row, an append-only note stream,
   and a footer. Each reuses the tokens and component language above rather
   than introducing a second vocabulary.
   ========================================================================== */

/* The `hidden` attribute is only display:none in the UA stylesheet, so ANY
   author rule that sets display beats it. .login-wrap sets display:flex, which
   meant the login card stayed on screen after sign-in with the board rendered
   below it. This bit once before and came back the moment the stylesheet was
   replaced — the engine's CSS carries no global [hidden] rule because nothing
   there toggles a flex container that way. */
[hidden] { display: none !important; }

/* Drop targets. The enrollment board is read-only; ours is dragged on. */
/* Uncapped columns scroll rather than growing without limit — the board must
   stay one screen even when a queue holds 277. */
.board-col-body { max-height: 420px; overflow-y: auto; }
.card-more.window-note { cursor: default; font-weight: 500; }
.card-more.window-note a { color: var(--orange-dark); font-weight: 700; text-decoration: none; }

.board-col.dragover { border-color: var(--orange); box-shadow: 0 0 0 2px var(--orange-tint); }

/* A LOCKED COLUMN, REACHED FOR. Deliberately NOT the orange .dragover language:
   orange means "release here and it lands", and this column is refusing. The
   muted dashed border is the same vocabulary .loc-bucket.is-locked uses for the
   same meaning — the target is present, counted and readable, and not aimable.
   No hover lift, for the reason recorded there: a target that rises to meet the
   cursor is the promise being withdrawn. */
.board-col.drop-locked { border-style: dashed; border-color: var(--muted); box-shadow: none; }
.drop-locked-note {
  margin: 0 0 var(--space-2);
  padding: var(--space-2);
  border-radius: 6px;
  background: var(--bg);
  color: var(--muted);
  font-size: .8rem; font-style: italic; line-height: 1.35;
}
.card[draggable="true"] { cursor: grab; }
.card.dragging { opacity: .4; }

/* FACET PILLS — the engine's segmented control (.division-tabs), reused.
   Its tabs are single-select; ours are multi-select, so a selected pill gets
   the same white/elevated treatment and the row simply allows several. */
.filters { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-5); }
.facet { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.facet-label {
  font-size: 11px; font-weight: 700; color: var(--muted-light);
  text-transform: uppercase; letter-spacing: 0.06em; min-width: 104px;
}
.facet-pills { display: inline-flex; background: #e9ecf3; border-radius: 9px; padding: 3px; gap: 2px; flex-wrap: wrap; }
.pill-btn {
  background: none; border: none; color: var(--muted);
  font-family: inherit; font-size: 13px; font-weight: 600;
  padding: 7px 15px; border-radius: 6px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
  transition: background .14s ease, color .14s ease, box-shadow .14s ease;
}
.pill-btn:hover:not(.on) { color: var(--ink); }
.pill-btn.on { background: #fff; color: var(--navy); box-shadow: var(--shadow-sm); }
.pill-btn .n {
  min-width: 19px; height: 19px; padding: 0 6px; border-radius: 999px;
  background: var(--navy-tint-2); color: var(--navy);
  font-size: 11px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  font-variant-numeric: tabular-nums;
}
.pill-btn.on .n { background: var(--navy); color: #fff; }
.pill-clear { background: none; border: none; color: var(--muted); font-size: 12px;
              text-decoration: underline; padding: 4px 6px; }

/* Toolbar — the two entry points, in the engine's button language. */
.toolbar { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
.btn-primary-solid {
  background: var(--orange); color: #fff; border: none; border-radius: 8px;
  padding: 10px 16px; font-weight: 600; font-size: 13.5px;
}
.btn-primary-solid:hover { background: var(--orange-dark); }
.btn-secondary {
  background: var(--card); color: var(--navy); border: 1px solid var(--border);
  border-radius: 8px; padding: 10px 16px; font-weight: 600; font-size: 13.5px;
}
.btn-secondary:hover { border-color: var(--navy); }
.toolbar-summary { color: var(--muted); font-size: 13px; }

/* Dialogs. Native <dialog> kept for its focus trap and Esc handling, dressed
   as the engine's .modal-box so the language matches without swapping the
   element for a div and losing both. */
dialog {
  border: 0; border-radius: 12px; padding: var(--space-5);
  min-width: 380px; max-width: 92vw;
  box-shadow: 0 8px 32px rgba(16, 24, 40, 0.2);
  font-family: var(--font); color: var(--ink);
}
dialog::backdrop { background: rgba(16, 24, 40, 0.45); }
dialog h3 { margin: 0 0 var(--space-2); color: var(--navy); font-size: 16px; }
dialog label { display: block; font-size: 12px; font-weight: 600; color: var(--navy);
               margin: var(--space-3) 0 var(--space-2); }
dialog input, dialog select, dialog textarea {
  width: 100%; padding: 10px 12px; border: 1px solid var(--border);
  border-radius: 8px; font-size: 14px; font-family: inherit;
}
dialog menu { display: flex; gap: var(--space-2); justify-content: flex-end;
              margin: var(--space-4) 0 0; padding: 0; }
dialog menu button { padding: 9px 16px; border-radius: 6px; font-weight: 600;
                     font-size: 13px; border: none; background: var(--bg); color: var(--ink); }
dialog menu button.primary { background: var(--orange); color: #fff; }
dialog menu button.primary:hover { background: var(--orange-dark); }
dialog menu button:disabled { opacity: .45; cursor: not-allowed; }
.hint { font-size: 12px; color: var(--muted); background: #f7f9fc;
        border-left: 3px solid var(--border); padding: 8px 10px;
        border-radius: var(--radius-sm); margin-top: var(--space-2); }

/* WHETHER A FIELD IS REQUIRED, ON THE LABEL. A close form whose fields are all
   mandatory except two unmarked ones teaches the rule by refusal — which is how
   a C2C dialer spent three attempts learning that the deposit reference was not
   wanted. Weight and colour differ so the two read apart at a glance; neither
   relies on colour alone to carry the meaning, because the word is the signal
   and the colour only reinforces it. */
.field-required, .field-optional {
    font-size: 11px; font-weight: 600; text-transform: uppercase;
    letter-spacing: .04em; margin-left: 6px; vertical-align: middle;
    padding: 1px 6px; border-radius: 999px; }
.field-required { color: var(--orange-dark); background: #fdf1e7; }
.field-optional { color: var(--muted); background: var(--bg);
                  border: 1px solid var(--border); font-weight: 500; }
.grades { display: flex; gap: var(--space-4); }
.grades label { display: inline-flex; align-items: center; gap: 6px; margin: 0; }
.grades input { width: auto; }
#c-lead summary { font-size: 12.5px; color: var(--muted); cursor: pointer;
                  margin-top: var(--space-3); }

/* Detail dialog: the engine's panel/kv language. */
.dtabs { display: flex; gap: 2px; background: #e9ecf3; border-radius: 9px;
         padding: 3px; margin: var(--space-4) 0 var(--space-3); }
.dtab { background: none; border: none; color: var(--muted); font-family: inherit;
        font-size: 13px; font-weight: 600; padding: 7px 15px; border-radius: 6px; }
.dtab.active { background: #fff; color: var(--navy); box-shadow: var(--shadow-sm); }
.dpanel { max-height: 420px; overflow-y: auto; }
.note, .hevent {
  border: 1px solid var(--border-soft); border-left: 3px solid var(--border);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: #fbfcfe; padding: 8px 10px; margin-bottom: 7px; font-size: 13px;
}
.hevent.system { border-left-color: var(--navy); }
.hevent.backward { border-left-color: var(--amber); background: var(--amber-bg); }
.note .who, .hevent .who { font-size: 11px; color: var(--muted-light); margin-bottom: 3px; }
.note .body { white-space: pre-wrap; }

/* Conversion lane + chase + seed: the engine's row/panel language, not tables. */
.row-card {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); background: var(--card); border: 1px solid var(--border);
  border-radius: 8px; padding: var(--space-3); margin-bottom: var(--space-2);
}
.row-card .main { flex: 1; min-width: 0; }
.row-card .name { font-weight: 600; font-size: 13.5px; }
.row-card .meta { color: var(--muted); font-size: 12px; margin-top: 2px; }
.reqs { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-top: 6px; }
.req { font-size: 11px; font-weight: 600; border-radius: 4px; padding: 3px 8px;
       background: var(--error-bg); color: var(--error); }
.req.ok { background: var(--green-bg); color: var(--green); }
.alarm { background: var(--error); color: #fff; padding: 10px var(--space-6);
         font-size: 13px; font-weight: 600; }
/* THREE noises, and the gaps between them are a PLATFORM STANDARD, not this
   module's taste (Art, 2026-07-31):

     .alarm        red   — PERSON-LEVEL ACTION REQUIRED. Reserved platform-wide
                           for that and nothing else. On this board: the parent
                           invariant broken, i.e. "do not trust these numbers".
     .alarm-amber  amber — a CONFIGURATION FAULT. Somebody must act, but it is
                           a wiring problem, not a person's queue. Loud enough
                           that it is never scrolled past; not red, because a
                           config fault is never person-level action.
     .alarm-grey   grey  — an OUTAGE. Transient, nobody's fault, self-resolving.

   NOT_WIRED is AMBER. It was red for one day and that was drift: receivables
   already shipped the same state as amber with a build guard, and two modules
   rendering one state in two colours is exactly the disagreement a design
   system exists to prevent. The colour changed; the ERROR log, the stable
   TRAINING_BATCH_READ_NOT_WIRED marker and the SQLSTATE classification did
   not — loudness lives in the log and the copy, not only in the hue.

   A missing grant must still NEVER render grey. Grey is the colour people
   scroll past, and a configuration fault nobody investigates lives forever. */
.alarm-amber { background: var(--amber-bg); color: #7c4a03;
               border-left: 4px solid var(--amber); }
.alarm-grey { background: #f1f3f7; color: var(--muted);
              border-left: 3px solid var(--muted-light); font-weight: 500; }
.alarm code, .alarm-amber code, .alarm-grey code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }

/* An UNKNOWN count is not a small count. It is rendered as an em dash at the
   weight of a number so the column still reads as a column, but nobody can
   mistake it for zero -- "In training: 0" and "In training: unknown" are
   opposite claims and they were one pixel apart before this. */
.stage-count.is-unknown { color: var(--muted-light); font-weight: 500; }

/* The count rides the tab so the lane's headline number is visible without
   opening it. */
.tab-pill { display: inline-block; min-width: 18px; margin-left: 5px; padding: 1px 6px;
            border-radius: 9px; background: rgba(255,255,255,0.18); color: #fff;
            font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; }

/* READ-ONLY cards and columns. No drag affordance, and no hover lift either —
   the cursor should never suggest these can be picked up, because the spine
   forbids intake writing them at all (see app/training.py). */
.board-col.read-only .stage-phase { color: var(--muted-light); font-style: italic; }
.card.read-only { cursor: default; }
.card.read-only:hover { box-shadow: none; transform: none; }
.sitefoot { text-align: center; color: var(--muted); font-size: 12px;
            padding: var(--space-6) 0 var(--space-5); }
.brand-word { font-weight: 600; font-size: 15px; color: #fff;
              padding-left: var(--space-3); border-left: 1px solid rgba(255,255,255,.28); }

/* ---- THE TERMINAL ZONE (EOS-0371) ----
   Styled as an END rather than as a column that happens to be empty. The
   dashed inset and the arrow say "things arrive here and stop"; the .stage-well
   used by an empty column says "nobody is standing here YET", which would send
   somebody looking for cards that are deliberately not fetched. It still takes
   a drop, so it keeps the full column chrome and the .dragover highlight. */
.board-col.terminal-zone { background: #fbfbfc; }
.board-col.terminal-zone .stage-count { color: var(--muted); }
.board-col.terminal-zone .stage-phase { font-style: italic; }
.terminal-note {
  flex: 1; display: flex; align-items: center; gap: var(--space-3);
  border: 1px dashed var(--border); border-radius: var(--radius);
  background: var(--phase-dropped-bg);
  padding: var(--space-3); min-height: 92px;
  font-size: 11px; line-height: 1.5; color: var(--muted);
}
.terminal-mark { font-size: 20px; color: var(--phase-dropped); line-height: 1; }
/* An empty terminal zone must NOT recede the way an empty column does — it is
   the drag target for dropping somebody, and a receded target is a lost one. */
.board.has-population .board-col.terminal-zone { box-shadow: var(--shadow-sm); }

/* ---- HOTLIST, AS TWO SECTIONS (EOS-0365) ----
   Below the strip, stacked: C2C then Hybrid. Deliberately NOT a grid — these
   are two independent spine reads and side-by-side placement invites reading
   them as halves of one number. Nothing here renders a total. */
.hotlist { display: flex; flex-direction: column; gap: var(--space-4);
           margin-top: var(--space-5); }
.hotlist-section {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  border-top: 3px solid var(--phase-marketing, var(--navy));
  padding: var(--space-4);
}
.hotlist-section.read-only { border-top-color: var(--muted-light); background: #fbfcfe; }
.hotlist-section.dragover { border-color: var(--orange); box-shadow: 0 0 0 2px var(--orange-tint); }
.hotlist-head { display: flex; align-items: baseline; gap: var(--space-3);
                margin-bottom: var(--space-3); flex-wrap: wrap; }
.hotlist-title { margin: 0; font-size: 12.5px; font-weight: 700; color: var(--navy);
                 text-transform: uppercase; letter-spacing: 0.05em; }
.hotlist-count { margin-left: 6px; font-variant-numeric: tabular-nums;
                 font-size: 15px; color: var(--navy); }
.hotlist-source { font-size: 10.5px; font-weight: 600; color: var(--muted-light);
                  text-transform: uppercase; letter-spacing: 0.06em; }
.hotlist-body { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
                gap: 7px; max-height: 420px; overflow-y: auto; }
/* >>> PROVENANCE, WHICH REPLACED "pre-funnel" (Art, 2026-08-19). <<<
   The old tag was tinted like the seeded chip — a muted grey that read as
   "incomplete" — beside a "start in pipeline" button. Badge and colour agreed
   with each other and were both wrong about the same live consultant.

   ALL THREE ARE THE SAME WEIGHT AND THE SAME FAMILY, because the ruling is
   that they are all equally live and the badge says only WHERE THEY CAME FROM.
   They are tinted apart enough to be told at a glance and NOT ranked: nothing
   here is greyer, smaller or quieter than its neighbours, because a reader who
   inferred an ordering would be inferring the thing this replaced. */
.provenance-tag { font-weight: 600; }
.provenance-era { background: rgba(99, 102, 241, 0.14); color: #3730A3; }
.provenance-funnel_graduated { background: rgba(16, 185, 129, 0.14); color: #047857; }
.provenance-converted { background: #FEF3C7; color: #92400E; }
/* Handed off: intake HOLDS a case and somebody is marketing them, so the funnel
   no longer draws a card. Deliberately the `spine-marketing` green and NOT the
   pre-funnel tint — these two tags make opposite claims about whether a case
   exists, and reading them as the same colour is how the false one survived. */
.handed-off-tag { background: rgba(16, 185, 129, 0.14); color: #047857; }

/* The exception queue is ROWS, not a column — a board column is a pipeline
   category and these consultants belong to none (ruling D2). */
.exception-row { border-left: 3px solid var(--amber); }
/* The chip styles were scoped to `.card` and this queue is rows, so the tags
   rendered as bare text and the name line read as one run-on sentence
   ("Lapsed And Spine Dropped C2C spine: dropped"). Extend the selector rather
   than duplicate the rule -- one chip vocabulary, two containers. */
.row-card .lane-tag, .row-card .hold-tag {
  display: inline-block; margin-left: 7px; padding: 2px 7px;
  border-radius: 5px; font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; vertical-align: 1px;
}
.row-card .lane-tag { background: var(--orange-tint); color: var(--orange-dark); }
.row-card .hold-tag.spine-dropped { background: rgba(107,114,128,0.12); color: #4b5563; }
.row-card .hold-tag.spine-marketing { background: rgba(16,185,129,0.14); color: #047857; }
/* Capped at a reading measure. The refusal is a PARAGRAPH somebody has to
   actually read before acting on a person; run across 1400px it is a banner
   they skim. */
.exception-row .drop-reason {
  display: block; margin-top: 5px; font-size: 12.5px; color: #7c4a03;
  line-height: 1.5; max-width: 92ch;
}
.exception-row .meta { display: block; margin-top: 4px; }
/* The 271 -> 204 note, on the column that lost the cards. Amber because it is
   a state somebody must act on, quiet because it is not an alarm. */
.card-more.refused-note {
  cursor: default; font-weight: 600; color: var(--amber);
  background: var(--amber-bg); border-radius: var(--radius);
  padding: 6px 8px; margin-top: 6px; font-size: 11px;
}
.card-more.refused-note a { color: #7c4a03; }
.tab-pill-warn { background: var(--amber); color: #fff; }

/* ---- D4: the filtered-view banner -------------------------------------
   Sits directly above the pills and directly below the count it explains.
   Amber-tinted because it is a STATE the viewer is in, not an alarm: the
   numbers underneath are correct, they are just narrower than the board. */
.filter-banner {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  background: var(--amber-bg); border-left: 4px solid var(--amber);
  border-radius: var(--radius); padding: 9px var(--space-4);
  margin-bottom: var(--space-4); font-size: 13px; color: #7c4a03;
}
.filter-banner-label { font-weight: 800; text-transform: uppercase;
                       letter-spacing: 0.06em; font-size: 11px; }
.filter-banner-count { margin-left: auto; }
.filter-banner-count strong { font-variant-numeric: tabular-nums; }
.filter-chip {
  background: #fff; border: 1px solid rgba(180,83,9,0.35); color: #7c4a03;
  border-radius: 999px; padding: 3px 10px; font-size: 12px; font-weight: 600;
}
.filter-chip:hover { background: #fff7e6; border-color: var(--amber); }
.filter-clear-all {
  background: var(--amber); border: none; color: #fff; border-radius: 6px;
  padding: 5px 11px; font-size: 12px; font-weight: 700;
}

/* ---- D1: the lane strip on the board ----------------------------------
   Training and the exception queue are part of the answer to "where is
   everybody". Behind a nav tab they read as absent, which is how the Training
   lane was reported missing when it was present and working. */
.board-lanes { display: flex; gap: var(--space-3); flex-wrap: wrap;
               margin-bottom: var(--space-4); }
.lane-chip {
  display: flex; align-items: baseline; gap: 9px; text-decoration: none;
  background: var(--card); border: 1px solid var(--border);
  border-left: 4px solid var(--phase-prep);
  border-radius: var(--radius); padding: 10px var(--space-4);
  box-shadow: var(--shadow-sm); min-width: 240px;
}
.lane-chip:hover { box-shadow: var(--shadow); border-left-color: var(--navy); }
.lane-chip-warn { border-left-color: var(--amber); }
.lane-chip-n { font-size: 21px; font-weight: 700; color: var(--navy);
               font-variant-numeric: tabular-nums; }
.lane-chip-label { font-size: 13px; font-weight: 700; color: var(--navy); }
.lane-chip-sub { font-size: 11px; color: var(--muted); margin-left: auto;
                 text-align: right; max-width: 22ch; line-height: 1.35; }

/* ---- D1: the nav can never push a tab out of reach --------------------
   Two lanes were added to a nav that had no shrink or wrap behaviour. Tabs
   are the only route to two of this board's populations, so the nav wraps
   rather than overflowing, and the account block never wins the fight. */
.app-header { flex-wrap: wrap; height: auto; min-height: 56px; padding-top: 6px;
              padding-bottom: 6px; }
.app-nav { flex-wrap: wrap; row-gap: 2px; min-width: 0; }
.app-account { flex: none; }

.scope-note {
  font-size: 13px; color: #7c4a03; background: var(--amber-bg);
  border-left: 4px solid var(--amber); border-radius: var(--radius);
  padding: 8px var(--space-4); margin: 0 0 var(--space-4);
}

/* ---- D5: global search, in the header ---------------------------------- */
.app-search { position: relative; flex: none; width: 260px; }
.app-search input {
  width: 100%; padding: 7px 11px; border-radius: 8px; font-size: 13px;
  border: 1px solid rgba(255,255,255,0.25); background: rgba(255,255,255,0.12);
  color: #fff;
}
.app-search input::placeholder { color: rgba(255,255,255,0.6); }
.app-search input:focus { outline: none; background: #fff; color: var(--ink);
                          border-color: var(--orange); }
.search-results {
  position: absolute; top: calc(100% + 6px); right: 0; width: 460px; z-index: 60;
  background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 8px 28px rgba(16,24,40,0.16); overflow: hidden; max-height: 60vh;
  overflow-y: auto;
}
.search-row {
  display: grid; grid-template-columns: 1fr auto; gap: 2px var(--space-3);
  width: 100%; text-align: left; background: none; border: none;
  border-bottom: 1px solid var(--border-soft); padding: 9px var(--space-4);
}
.search-row:hover { background: var(--navy-tint); }
.search-name { font-size: 13.5px; font-weight: 700; color: var(--navy); }
.search-div  { font-size: 11px; font-weight: 700; color: var(--orange-dark);
               text-transform: uppercase; letter-spacing: 0.04em; }
/* The disposition is what makes two people with one name distinguishable
   BEFORE the click -- it is the point of the row, not decoration. */
.search-disp { font-size: 11.5px; color: var(--muted); grid-column: 1; }
.search-route { font-size: 11px; font-weight: 600; color: var(--navy);
                grid-column: 2; align-self: end; }
.search-msg { padding: 12px var(--space-4); font-size: 12.5px; color: var(--muted); }

/* The card the search landed on. Brief, then gone -- a permanent highlight
   becomes another thing to explain. */
.card-found { box-shadow: 0 0 0 3px var(--orange); border-color: var(--orange); }

.record-card {
  background: var(--card); border: 1px solid var(--border);
  border-left: 4px solid var(--navy); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5); max-width: 640px;
  box-shadow: var(--shadow-sm);
}
.record-card .kv-row {
  display: flex; justify-content: space-between; gap: var(--space-5);
  padding: 7px 0; border-bottom: 1px solid var(--border-soft); font-size: 13px;
}
.record-card .kv-row:last-child { border-bottom: none; }
.record-card .k { color: var(--muted); font-weight: 600; }
.record-card .v { color: var(--ink); font-weight: 600; text-align: right; }

/* ---- D6: referral badge and state -------------------------------------- */
.card .ref-tag {
  display: inline-block; margin-left: 6px; padding: 2px 7px; border-radius: 5px;
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.04em;
}
.card .ref-tag.ref-pending { background: rgba(124,58,237,0.12); color: #6d28d9; }
.card .ref-tag.ref-resolved { background: var(--green-bg); color: var(--green); }
.referral-state {
  font-size: 12.5px; color: #6d28d9; background: rgba(124,58,237,0.08);
  border-left: 3px solid #7c3aed; border-radius: var(--radius);
  padding: 8px var(--space-3); margin: var(--space-3) 0 0;
}
#refer-dialog select, #refer-dialog textarea {
  width: 100%; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: 8px; font-size: 13px; font-family: inherit;
  margin-bottom: var(--space-3);
}

/* ---- the dialer front door: "My closes" --------------------------------- */
/* A dialer has no board, so this list IS their screen. Wider rows than a card,
   because there is no column to fit into and the two things that matter —
   which stage the close reached, and whether the deposit copy is attached —
   should be readable without opening anything. */
body.dialer-only .app-header { justify-content: space-between; }

.close-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-5); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5); margin-bottom: var(--space-3);
  box-shadow: var(--shadow-sm);
}
.close-row .close-name { margin: 0; font-size: 15px; font-weight: 700; color: var(--ink); }
.close-row .close-meta { margin: 4px 0 0; font-size: 12.5px; color: var(--muted); }
.close-row .close-side {
  display: flex; align-items: center; gap: var(--space-3); flex-shrink: 0;
}
.close-row .stage-chip {
  padding: 3px 9px; border-radius: 5px; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em;
  background: rgba(15,23,42,0.06); color: var(--ink);
}
/* The missing-copy state is amber rather than red on purpose: a close with no
   deposit copy yet is normal for the first few minutes, not an error. */
.close-row .evidence-chip {
  padding: 3px 9px; border-radius: 5px; font-size: 11px; font-weight: 700;
}
.close-row .evidence-chip.ok { background: var(--green-bg); color: var(--green); }
.close-row .evidence-chip.missing { background: rgba(217,119,6,0.12); color: #b45309; }

#my-closes-list .empty {
  background: var(--surface); border: 1px dashed var(--border);
  border-radius: var(--radius-lg); padding: var(--space-5);
  color: var(--muted); font-size: 13.5px; max-width: 640px;
}
#deposit-dialog input[type="file"] {
  width: 100%; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: 8px; font-size: 13px; margin-bottom: var(--space-2);
}
#deposit-existing { margin: var(--space-2) 0 0; }
#deposit-existing a { color: var(--navy); font-weight: 600; }

/* ---- close front door v2: picker, schedule, reconcile ------------------- */
/* THE CONSULTANT DROPDOWN — anchored to the field, opaque, above the form.
 *
 * Two faults produced one symptom (results painting over "Payment received
 * now", see-through, drifting):
 *
 *   1. `.picker-results` was ALREADY defined further up this file, by the
 *      legacy employee picker, as `position: absolute; top: 100%` — meant to
 *      sit inside its own `.picker-row { position: relative }` wrapper. The
 *      consultant dropdown reused the class name but had no positioned
 *      ancestor, so `top: 100%` resolved against the <dialog> and landed at the
 *      BOTTOM of the modal. Fixed by `.picker-anchor` in index.html; addressed
 *      here by ID so the legacy picker keeps its own behaviour untouched.
 *   2. `background: var(--surface)` — THERE IS NO `--surface` IN THIS FILE. An
 *      undefined custom property makes the declaration invalid, so the
 *      background fell back to transparent and the form showed through the
 *      results. It is `--card` (#ffffff), which is defined.
 *
 * NOTE: `--surface` is also used by `.close-row` and `#my-closes-list .empty`
 * below, which are therefore transparent too. Those read acceptably against the
 * page background and are OUT OF SCOPE for this fix — recorded so the next
 * person does not have to rediscover it. */
.picker-anchor { position: relative; }

#c-picker-results {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 30;                /* above every field in the form */
  margin: 0;
  background: var(--card);    /* OPAQUE. Never an undefined variable. */
  border: 1px solid var(--border);
  border-radius: 8px;
  max-height: 240px;
  overflow-y: auto;           /* long result sets scroll INSIDE the dropdown */
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.18);
}

.picker-results {
  border: 1px solid var(--border); border-radius: 8px; max-height: 240px;
  overflow-y: auto; margin: 4px 0 var(--space-2); background: var(--card);
}
.picker-row {
  display: block; width: 100%; text-align: left; border: 0; background: none;
  padding: 8px 10px; cursor: pointer; border-bottom: 1px solid var(--border-soft);
}
.picker-row:last-child { border-bottom: none; }
.picker-row:hover { background: rgba(15,23,42,0.04); }
.picker-row .picker-name { display: block; font-weight: 700; font-size: 13px; }
.picker-row .picker-meta { display: block; font-size: 11.5px; color: var(--muted); }
.picker-row .picker-flag {
  display: inline-block; margin-top: 3px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; color: #b45309;
}
.picker-new .picker-name { color: var(--navy); }

.picked-chip {
  margin: 4px 0 var(--space-2); padding: 7px 10px; border-radius: 6px;
  background: var(--green-bg); color: var(--green); font-size: 12.5px;
  font-weight: 600;
}
/* A foreign record is shown, not hidden — the dialer needs to know the person
   exists — but it reads as a stop, because the write will 403. */
.picked-chip.picked-foreign {
  background: rgba(220,38,38,0.10); color: #b91c1c;
}

.form-section {
  margin: var(--space-4) 0 var(--space-2); font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted);
  border-top: 1px solid var(--border-soft); padding-top: var(--space-3);
}
.schedule-line {
  display: grid; grid-template-columns: 1fr 150px 32px; gap: 6px;
  margin-bottom: 6px; align-items: center;
}
.schedule-line input {
  padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px;
  font-size: 13px; font-family: inherit; margin: 0;
}
.schedule-line .line-remove { padding: 4px 8px; font-size: 16px; line-height: 1; }

.reconcile { margin: 6px 0 0; font-size: 12.5px; font-weight: 700; min-height: 1em; }
.reconcile.ok { color: var(--green); }
.reconcile.bad { color: #b91c1c; }

.msg.warn {
  background: rgba(217,119,6,0.10); color: #92400e; border-radius: 6px;
  padding: 8px 10px; font-size: 12.5px;
}
#c-ft-block input[type="file"] {
  width: 100%; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: 8px; font-size: 13px;
}

/* ---- shared-services lanes: dispatch + my work ------------------------- */
.queue-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-5); background: var(--card);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5); margin-bottom: var(--space-3);
  box-shadow: var(--shadow-sm);
}
.queue-row .queue-name { margin: 0; font-size: 15px; font-weight: 700; color: var(--ink); }
.queue-row .queue-meta { margin: 4px 0 0; font-size: 12.5px; color: var(--muted); }
.queue-row .queue-side { display: flex; align-items: center; gap: var(--space-3); flex-shrink: 0; }
/* Days waiting is the number the queue exists to surface. Amber past three
   days: a pileup is measured in days, not in row counts. */
.queue-row .wait-chip {
  padding: 3px 9px; border-radius: 5px; font-size: 11px; font-weight: 700;
  background: rgba(15,23,42,0.06); color: var(--ink);
}
.queue-row .wait-chip.stale { background: rgba(217,119,6,0.12); color: #b45309; }
#dispatch-unassigned .empty, #dispatch-assigned .empty, #mywork-list .empty {
  background: var(--card); border: 1px dashed var(--border);
  border-radius: var(--radius-lg); padding: var(--space-5);
  color: var(--muted); font-size: 13.5px; max-width: 640px;
}
#dispatch-lane { padding: 8px 10px; border: 1px solid var(--border);
                 border-radius: 8px; font-size: 13px; }
#assign-dialog select { width: 100%; padding: 9px 11px; border: 1px solid var(--border);
                        border-radius: 8px; font-size: 13px; }

/* Where a consultant actually is. Off-board (in_training, hold, marketing) is
   normal, not an error — it reads as context, not as a warning. */
.where-chip {
  display: inline-block; padding: 1px 6px; border-radius: 4px;
  font-size: 11px; font-weight: 700; background: rgba(15,23,42,0.06);
  color: var(--ink); text-transform: capitalize;
}
.where-chip.offboard { background: rgba(99,102,241,0.12); color: #4338ca; }
#lane-search { width: 100%; padding: 9px 11px; border: 1px solid var(--border);
               border-radius: 8px; font-size: 13px; }
#lane-search-results { position: static; max-height: 280px; box-shadow: none; }
.picker-failed { font-size: 12.5px; color: #b45309;
                 background: rgba(217,119,6,0.10); border-radius: 6px;
                 padding: 8px 10px; margin: 0; }

/* Sample-agreement trail. `pending` is deliberately NOT red: the engine has not
   shipped its half yet, which is a state of the world rather than a fault the
   operator caused or can fix. */
.sample-trail {
  font-size: 12.5px; border-radius: var(--radius); padding: 8px 10px;
  margin: var(--space-3) 0 0;
}
.sample-trail.ok { background: var(--green-bg); color: var(--green); }
.sample-trail.pending { background: rgba(100,116,139,0.12); color: #475569; }
.sample-trail.bad { background: rgba(220,38,38,0.10); color: #b91c1c; }

/* Lane ownership on the card. The unassigned-at-stage state is RED because it
   is a claim the board is making and cannot back up — not a warning about
   something slow, an assertion that is currently false. */
.lane-row {
  font-size: 12.5px; border-radius: var(--radius); padding: 9px 11px;
  margin: var(--space-2) 0 0;
}
.lane-row.ok { background: var(--green-bg); color: var(--green); }
.lane-row.bad { background: rgba(220,38,38,0.10); color: #b91c1c; }
.lane-row .lane-note { color: var(--muted); font-weight: 500; }
.lane-row.bad .lane-note { color: #b91c1c; opacity: .85; }
.lane-pick { display: flex; gap: var(--space-2); margin-top: 7px; }
.lane-pick select {
  flex: 1; padding: 7px 9px; border: 1px solid var(--border);
  border-radius: 6px; font-size: 12.5px;
}
.lane-pick button { padding: 7px 14px; font-size: 12.5px; }
/* `hidden` on a flex container loses to display:flex — the folded relocate form
   would render open. Stated here rather than relied on. */
.lane-pick[hidden] { display: none; }
/* "change location" is an ACTION and must be reachable by keyboard, so it is a
   real button wearing a link's clothes rather than an <a href="#"> that goes
   nowhere or a <span> with a click handler and no focus. */
.link-button {
  background: none; border: 0; padding: 0; font: inherit; color: inherit;
  text-decoration: underline; cursor: pointer;
}

/* ---- card v2: the engine's document panel -------------------------------- */
.doc-panel {
  font-size: 12.5px; border: 1px solid var(--border); border-radius: var(--radius);
  padding: 10px 12px; margin: var(--space-2) 0 0;
}
.doc-panel.bad { background: rgba(220,38,38,0.10); color: #b91c1c; border-color: #f3b4b4; }
/* THE SEND LINE (v5.9/05). Drawn as a STATED FACT and not as a success toast:
   it is the standing answer to "has anything been sent", re-derived from the
   engine on every render, so it must read the same on the tenth open as on the
   first. Green enough to be found, quiet enough not to read as a fresh event. */
.doc-sent {
  font-size: 12.5px; margin: var(--space-2) 0 0; padding: 8px 10px;
  border: 1px solid #b7dfc4; border-left-width: 3px; border-radius: var(--radius);
  background: rgba(22,163,74,0.08);
}
.doc-sent strong { display: block; }
.doc-sent .lane-note { display: block; }
.doc-head { display: flex; gap: var(--space-2); align-items: baseline; flex-wrap: wrap; }
.doc-list { list-style: none; margin: 7px 0 0; padding: 0; }
.doc-list li { display: flex; gap: var(--space-2); align-items: baseline; padding: 3px 0; }
.doc-key { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
/* Signed reads GREEN, everything else reads PENDING-amber. Deliberately not red:
   an unsigned document is work outstanding, not a fault — same reasoning as the
   platform NOT_WIRED standard (D4). */
.doc-state { font-weight: 600; text-transform: lowercase; }
.doc-state.ok { color: var(--green); }
.doc-state.pending { color: #b45309; }
.doc-actions { display: flex; gap: var(--space-2); align-items: center;
               flex-wrap: wrap; margin-top: var(--space-2); }
.doc-terms { display: grid; gap: var(--space-2); margin-top: var(--space-2); }
.doc-terms label { display: grid; gap: 4px; font-size: 12.5px; }
.doc-terms input { padding: 7px 9px; border: 1px solid var(--border);
                   border-radius: 6px; font-size: 12.5px; }

/* Contact on the consultant card. Directly under the name; the missing state is
   dimmed but PRESENT, because "no phone on file" is a fact worth reading and a
   blank is indistinguishable from a broken render. */
.card-contact { margin: 2px 0 10px; font-size: 13px; }
.card-contact a { color: var(--orange-dark); text-decoration: none; font-weight: 600; }
.card-contact a:hover { text-decoration: underline; }
.card-contact .missing { color: var(--muted); font-style: italic; }
.card-contact .sep { color: var(--muted); }

/* "All tools" — the named way back, beside the brand word. Quiet: it is
   navigation, not an action, and it must not compete with the tab row. */
.all-tools {
  font-size: 12px; font-weight: 600; color: var(--muted);
  text-decoration: none; padding: 3px 8px; border-radius: 999px;
  border: 1px solid var(--border); white-space: nowrap;
}
.all-tools:hover { color: var(--orange-dark); border-color: var(--orange-dark); }

/* The division switch (v2.8). Two funnels, one page, separate renders. */
.division-switch { display: flex; gap: 4px; margin: 0 0 var(--space-3); }
.div-tab {
  padding: 7px 16px; font-size: 13px; font-weight: 600; cursor: pointer;
  border: 1px solid var(--border); background: var(--bg); color: var(--muted);
  border-radius: 999px;
}
.div-tab.active { background: var(--orange-tint); color: var(--orange-dark);
                  border-color: var(--orange-dark); }

/* The logo is a link now. It must not pick up the underline or colour every
   other anchor gets — the mark is the affordance. */
.brand-home { display: inline-flex; align-items: center; text-decoration: none; }
.brand-home:hover { opacity: .85; }

/* The resume lane on the card face. `needs writer` is a STATEMENT that the
   stage is lying — nobody holds work the board says is underway — so it is
   tinted like a hold rather than styled as neutral metadata. */
.needs-writer { color: var(--amber-dark, #92400e); font-weight: 600; }
.assign-link {
  background: none; border: none; padding: 0; margin-left: 4px;
  font: inherit; font-size: 11px; font-weight: 700;
  color: var(--orange-dark); cursor: pointer; text-decoration: none;
}
.assign-link:hover { text-decoration: underline; }

/* THE EXEC OVERRIDE'S SECOND STEP. Tinted as a warning and NOT as a form step:
   it must never read as the next thing you do, only as the thing you chose. */
.override-warn {
  border-left: 3px solid var(--orange); background: var(--orange-tint);
  padding: var(--space-3); border-radius: var(--radius); font-size: 12.5px;
}
.override-label { display: block; margin: var(--space-3) 0 3px;
                  font-size: 11px; font-weight: 700; color: var(--muted); }
.override-warn input { width: 100%; margin-bottom: var(--space-3); }
/* An override on the card is LOUD by design — never a quiet footnote. */
.override-badge {
  display: inline-block; margin-left: 6px; padding: 2px 7px; border-radius: 9px;
  background: var(--orange-tint); color: var(--orange-dark);
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* ==========================================================================
   PAPER STATE — the engine's answer, on the card face and in the card panel.
   --------------------------------------------------------------------------
   READ-ONLY BY CONSTRUCTION: no cursor, no hover affordance, nothing that
   invites a click. A chip that looked pressable would promise a chase action
   this build deliberately does not have.

   THE UNAVAILABLE CHIP IS THE LOUD ONE. `issued_unsigned` and `signed` are
   facts about a person and sit quietly in the card's muted register; "could
   not ask" is a fact about THIS SYSTEM and is tinted amber so it is never
   mistaken for either an answer or an absence. */
.paper-chip {
  display: inline-block; margin-top: 4px; margin-right: 5px;
  padding: 2px 7px; border-radius: 9px; font-size: 10.5px; font-weight: 600;
  background: var(--navy-tint); color: var(--ink-soft);
}
.paper-chip.paper-signed { background: var(--success-bg); color: var(--success); }
.paper-chip.paper-unavailable {
  background: var(--amber-bg); color: var(--amber); font-style: italic;
}
.paper-panel { display: block; }

/* ---- v3.5: resumes on the card ------------------------------------------
   Two blocks, one per artifact. The LATEST version is the prominent row and
   the priors sit behind a <details> — collapsed rather than hidden, because
   "never overwritten" is only credible if the old ones are visibly still
   there. Borrows the doc-panel scale so the two document sections of one card
   read as one surface rather than two designs. */
.section-head {
  font-size: 13px; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted); margin: var(--space-3) 0 var(--space-2);
}
.resume-block {
  font-size: 12.5px; border: 1px solid var(--border); border-radius: var(--radius);
  padding: 10px 12px; margin: 0 0 var(--space-2);
}
.resume-block h4 { margin: 0 0 6px; font-size: 13px; }
.resume-row { display: flex; gap: var(--space-2); align-items: baseline;
              flex-wrap: wrap; padding: 3px 0; }
.resume-row.prominent { font-weight: 600; }
.resume-meta { color: var(--muted); font-weight: 400; font-size: 12px; }
.resume-prior { margin-top: 6px; }
.resume-prior summary { color: var(--muted); cursor: pointer; font-size: 12px; }
.resume-upload { display: block; margin-top: 8px; }
.resume-upload input { font-size: 12px; }
/* Empty until something fails, like every other .msg-shaped host on this card. */
.resume-error:not(:empty) {
  margin: 6px 0 0; font-size: 12.5px; padding: 6px 8px; border-radius: 6px;
  background: rgba(220,38,38,0.10); color: #b91c1c;
}

/* ---- the FT location buckets ----------------------------------------------
   ONE STATE, FOUR VIEWS. The unlocated pool is the column body above these;
   the strip is where a card is dragged to acquire a location. They sit below
   the cards, inside the Ready for Marketing column, so the drag stays short.

   >>> v3.7 GATE 2: THESE ARE DROP ZONES, AND THEY ARE SIZED LIKE IT (Art,
   2026-08-08). <<< v3.6 shipped them as a 6px-gap strip of 5px-padded pills
   with 12px text — roughly 20px tall. Art's finding: they were the SMALLEST
   elements on a screen whose primary action is dragging into them, which is
   the affordance exactly inverted.

   THE v3.6 INSTINCT IS KEPT AND RE-EXPRESSED. That note said these must not
   read as three more columns, and they still must not — they are not stages,
   nothing moves when a card lands here, and no stage event is written. What
   distinguishes them from columns now is SHAPE rather than SIZE: dashed
   bounds, a "drop to assign" cue, and their own tinted tray under the column
   body. Being quiet and being small were conflated; only the first was right.

   NO NEW COLOURS. Resting bounds are --navy-tint-2 over --card, the tray is
   the column's own --phase-bg, and the drag-over state is the SAME
   orange/orange-tint language .board-col.dragover and .hotlist-section.dragover
   already speak — so "this will take your drop" looks identical everywhere on
   the surface. The zones previously used --phase for that, which made the one
   drop target people actually use the only one with its own dialect. */
/* THE ROW SITS BELOW THE FIVE FUNNEL COLUMNS, FULL WIDTH. It is a sibling of
   `.board`, not a child of a column — see the note in app.js for why nesting
   them in Ready for Marketing was the defect rather than their size. */
.loc-row { margin-top: var(--space-4); }
.loc-row-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.loc-hint {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--ink-soft);
}
.loc-sub { font-size: 12px; color: var(--muted); }
/* THREE ACROSS, MATCHING THE FUNNEL'S OWN GRID so the row reads as part of the
   board rather than a footer stuck under it. `.board` uses
   repeat(auto-fill, minmax(260px, 1fr)); this uses auto-FIT with the same
   minimum, so the three zones share the full width instead of leaving a gap
   where a fourth column would be. Below ~820px they wrap and then stack, which
   only makes each target larger. */
.loc-zones {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-3);
}
/* >>> NO DASHED BORDER (Art, rv5: "the hash design is shit"). <<< A dashed
   outline says EMPTY PLACEHOLDER, and these are populated containers that also
   accept drops — the people standing in them are the point, and a hashed box
   around a list of real consultants reads as a slot waiting to be filled.

   SO THEY ARE REAL CARDS, matching the funnel column exactly: same radius,
   same 1px border, same --card background, same --shadow-sm. Drop-affordance
   is carried entirely by the HOVER and DRAG-OVER states below, which is where
   affordance belongs — it is a response to what the operator is doing, not a
   permanent decoration that has to shout while nothing is happening.

   THE TARGET AREA IS UNCONSTRAINED BY COLUMN WIDTH. At a 1400px board these
   run ~450px wide against ~240px nested and ~78px in v3.6. */
.loc-bucket {
  display: flex; flex-direction: column;
  gap: var(--space-2);
  min-height: 128px;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  /* THE COLUMN'S OWN TOKEN, not a hand-picked 12px that happens to look near
     enough. Same radius, same border, same background, same shadow — asserted
     against the column's computed style in flow31e. */
  border-radius: var(--radius-lg);
  background: var(--card);
  box-shadow: var(--shadow-sm);
  transition: border-color .12s ease, background .12s ease,
              box-shadow .12s ease, transform .12s ease;
}
.loc-bucket:hover { border-color: var(--navy); box-shadow: var(--shadow); }
/* SHUT, AND SAYING SO. A viewer without the marketing lane keeps the zone and
   its COUNTS — those are the read this whole window widened — and loses the
   invitation. Muted rather than hidden: Art's ruling on the C2C drop column
   applies here too, that removing a surface removes the thing it was counting.
   The hover lift is cancelled specifically, because a target that rises to meet
   the cursor is the promise being withdrawn. */
.loc-bucket.is-locked {
  background: var(--bg);
  border-style: dashed;
  box-shadow: none;
}
.loc-bucket.is-locked:hover {
  border-color: var(--border);
  box-shadow: none;
  transform: none;
}
.loc-bucket.is-locked .loc-name,
.loc-bucket.is-locked .loc-count { opacity: .65; }
.loc-bucket.is-locked .loc-cue { font-style: italic; opacity: .8; }
.loc-bucket-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border-soft);
}
/* THE LIST SCROLLS; IT NEVER TRUNCATES. ~4 rows visible, the rest reachable —
   a person you cannot see is a person you cannot ring about. */
.loc-people {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
  max-height: 148px; overflow-y: auto;
}
/* THE WHOLE ROW IS THE TARGET, not the text (Art, rv6). Negative margin with
   matching padding so the hover fill spans the zone's full width — a hit area
   that stops at the end of a short name is the same "looks clickable, mostly
   isn't" problem as a name that is not clickable at all. */
.loc-person {
  display: flex; align-items: baseline; gap: var(--space-2);
  font-size: 13px; min-width: 0;
  cursor: pointer;
  padding: 3px var(--space-2);
  margin: 0 calc(var(--space-2) * -1);
  border-radius: var(--radius-sm);
  transition: background .12s ease;
}
.loc-person:hover,
.loc-person:focus-visible { background: var(--navy-tint); outline: none; }
.loc-person:focus-visible { box-shadow: 0 0 0 2px var(--navy-tint-2); }
.loc-person:hover .loc-person-name { color: var(--navy); }
/* SAME FADE THE CARD USES WHILE IN FLIGHT (.card.dragging), so a row being
   dragged between zones reads the same as a card being dragged out of Ready. */
.loc-person.dragging { opacity: .4; }
.loc-person[draggable="true"] { cursor: grab; }
.loc-person[draggable="true"]:active { cursor: grabbing; }
.loc-person-name {
  font-weight: 600; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.loc-name {
  font-weight: 700; font-size: 16px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* THE CUE IS THE EMPTY STATE NOW. A populated zone shows its people instead —
   the names ARE the explanation of what the container is, and a "drop to
   assign" line under a list of four consultants is noise. */
.loc-cue {
  margin: 0; font-size: 12px; letter-spacing: 0.03em;
  color: var(--muted-light); transition: color .12s ease;
}
.loc-count {
  font-size: 28px; font-weight: 700; line-height: 1;
  color: var(--ink-soft); font-variant-numeric: tabular-nums;
}
/* AFFORDANCE LIVES HERE, not in a permanent dashed outline. Same
   --orange/--orange-tint language .board-col.dragover already speaks. */
.loc-bucket.dragover {
  border-color: var(--orange);
  background: var(--icon-bg);
  box-shadow: 0 0 0 3px var(--orange-tint), var(--shadow);
  transform: translateY(-1px);
}
.loc-bucket.dragover .loc-cue { color: var(--orange-dark); font-weight: 600; }
.loc-bucket.dragover .loc-count { color: var(--orange-dark); }

/* ---- owed paper: one queue, one click per row ----------------------------
   Rows rather than cards: this is a worklist read top-to-bottom against a
   clock, not a board scanned spatially. Same card material as the funnel
   columns so it reads as part of the surface. */
.owed-list { display: flex; flex-direction: column; gap: var(--space-2); }
.owed-row {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "who action" "why action";
  gap: 2px var(--space-4);
  align-items: center;
  padding: var(--space-3) var(--space-4);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.owed-row:hover { border-color: var(--navy); }
.owed-who {
  grid-area: who;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2);
}
.owed-name { font-weight: 700; font-size: 15px; color: var(--ink); }
.owed-why { grid-area: why; font-size: 12.5px; color: var(--muted); }
/* THE ACTION IS ALWAYS IN THE SAME PLACE, whatever it says. "Resend" and
   "Link expired — mint a new one and send" are very different lengths, and a
   button that moves between rows is one that gets mis-clicked. */
.owed-do {
  grid-area: action; justify-self: end; white-space: nowrap;
  max-width: 260px;
}
.owed-do:disabled { opacity: .55; cursor: default; }
/* A control that looks like a link because it sits in prose, but is a button
   because it acts rather than navigates (D3: an anchor no handler owns is a
   dead click). */
.linklike {
  background: none; border: 0; padding: 0; font: inherit;
  color: var(--navy); text-decoration: underline; cursor: pointer;
}

/* ---- v3.9: marketing credentials on the card ----------------------------
   Borrows the doc-panel / resume-block scale so the credential section reads
   as another block of the same card rather than a third design. */
.mc-password { font-size: 12.5px; margin: 6px 0 0;
               display: flex; align-items: baseline; gap: var(--space-2);
               flex-wrap: wrap; }
/* THE REVEALED PASSWORD IS MONOSPACE AND SELECTABLE. It is going to be copied
   into a mail client, and a proportional font makes l/1/I and O/0 a guess —
   which in a password is not a cosmetic problem. `user-select: all` makes one
   click select the whole value, so nobody copies it half-way. */
.mc-shown {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px; background: #f7f9fc; border: 1px solid var(--border);
  border-radius: 6px; padding: 2px 8px; user-select: all;
}
.mc-shown.missing { font-family: inherit; user-select: auto; background: none;
                    border: 0; padding: 0; }
.mc-form { margin-top: var(--space-2); padding: 10px 12px;
           border: 1px solid var(--border); border-radius: var(--radius); }
.mc-form label { display: block; font-size: 12px; color: var(--muted);
                 margin: var(--space-2) 0 2px; }
.mc-form input {
  width: 100%; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: 8px; font-size: 13px;
}
.mc-form button[data-mc-save] { margin-top: var(--space-3); }

/* ==========================================================================
   MONEY IN (v4.1) — the payment trail and the recording dialog.

   Borrows the doc-panel / resume-block scale deliberately: the payment section
   is another block of the same card, not a third design language on it.
   ========================================================================== */
.pay-list { list-style: none; margin: var(--space-2) 0; padding: 0;
            display: flex; flex-direction: column; gap: var(--space-2); }
.pay-claim { border: 1px solid var(--border); border-radius: var(--radius);
             padding: 8px 10px; font-size: 13px; }
/* A SUPERSEDED CLAIM IS DIMMED, NOT HIDDEN. It has left the verification queue,
   which is the point of correcting it; it has not left the record, because a
   correction only makes sense next to the thing it corrected. */
.pay-claim.superseded { opacity: 0.62; }
.pay-head { display: flex; align-items: baseline; gap: var(--space-2);
            flex-wrap: wrap; }
.pay-kind { font-size: 12px; color: var(--muted); }
.pay-legs { margin: 4px 0; font-size: 12.5px; }
.pay-leg { display: inline-block; }
/* THE STORED METHOD KEY, beside its label. Monospace and quiet: it is the
   value Jose reconciles against, and it must be legible as a literal rather
   than read as prose. */
.method-key { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
              font-size: 11px; color: var(--muted); background: #f7f9fc;
              border: 1px solid var(--border); border-radius: 4px;
              padding: 0 4px; margin-left: 4px; }
/* THE ENTRY-SIDE CAPTURE, ON THE SURFACE FINANCE VERIFIES AGAINST. Labelled
   rows rather than a chip, because Jose reads these two against a bank line and
   a run-on "ref X · paid by Y" makes him parse a sentence to find a number. The
   value is the thing being matched, so it carries the weight; the label is
   quiet, the same way every other .kv-row on the card reads. */
/* THE MUTUALLY EXCLUSIVE FEE MODE, on the close form. A fieldset rather than a
   select because all three answers should be READABLE AT ONCE — "flat dollar
   amount" carries an exception warning, and an option nobody can see until they
   open a dropdown is an exception nobody weighs. */
.fee-modes { border: 1px solid var(--border); border-radius: var(--radius);
             padding: 8px 10px; margin: var(--space-3) 0; }
.fee-modes legend { font-size: 12px; color: var(--muted); padding: 0 4px; }

/* >>> QUALIFIED WITH `dialog` ON PURPOSE — THIS IS A SPECIFICITY FIX, NOT A
   STYLE PREFERENCE. <<< (2026-08-15, the reported mis-selection risk.)
   `dialog label` is (0,0,1,1) and set `display: block`; a bare `.radio-row` is
   (0,0,1,0) and LOST, whatever the source order — so every label rendered as a
   block and the radio broke onto its own line. Three labels stacked left,
   three controls stacked apart from them, and on a form that sets commercial
   terms a closer could not tell which control belonged to which option.

   CONTROL THEN LABEL, ONE ROW, like every other control on this form. The whole
   row is the hit target because it is a <label for=...>, so the text is
   clickable and not just the 13px circle.

   The `<span>` wrapper in the markup is what makes `gap` mean "between the
   radio and its text" rather than between every inline word. */
dialog .radio-row { display: flex; align-items: center; gap: var(--space-2);
                    font-size: 13px; font-weight: 400; margin: 0;
                    padding: 5px 2px; cursor: pointer; }
dialog .radio-row + .radio-row { border-top: 1px solid var(--border); }
dialog .radio-row input[type="radio"] {
  width: 15px; height: 15px; min-width: 15px; margin: 0; padding: 0;
  flex: none; accent-color: var(--orange); border-radius: 50%; }
dialog .radio-row span { flex: 1; }

/* THE AGREEMENT FIGURES, on the card finance reads. The unit rides beside the
   number and is deliberately quiet — the FIGURE is what gets matched, the unit
   is what stops it being misread. */
.close-terms { margin: 6px 0; }
.close-terms .kv-row { padding: 5px 0; font-size: 13px; gap: var(--space-3); }
.close-terms .kv-row:last-child { border-bottom: none; }
.close-terms .v { text-align: right; font-variant-numeric: tabular-nums; }
.close-terms .missing { color: var(--muted); font-style: italic; }
.fee-unit { font-size: 11px; color: var(--muted); margin-left: var(--space-2); }

/* THE TWO NARRATIVES ARE VISUALLY DISTINCT, because they are different
   instruments. The verbatim read-back is the record that gets defended; the
   explanation is a working note beside it and must never read as the terms. */
.close-prose .k { font-size: 12px; color: var(--muted);
                  margin: var(--space-3) 0 2px; }
.terms-verbatim, .terms-explained {
  white-space: pre-wrap; word-break: break-word; font-size: 12.5px;
  border-radius: 6px; padding: 8px 10px; margin: 0; font-family: inherit; }
.terms-verbatim { background: #f7f9fc; border: 1px solid var(--border); }
.terms-explained { background: transparent; border: 1px dashed var(--border);
                   color: var(--muted); }

/* >>> THE REJECTION, GIVEN THE WEIGHT OF THE THING IT IS. <<< (Art, 2026-08-19.)
   This is the sentence the person who filed the claim came to the card to read,
   and it sits directly above the button that answers it. A tinted panel rather
   than another grey line: the surrounding rows are a payment trail, and finance
   refusing money is not one more entry in it. */
.pay-rejected {
  display: block; margin: 8px 0; padding: 8px 10px;
  border-left: 3px solid var(--error);
  background: var(--error-bg); border-radius: 6px; font-size: 12.5px;
}
.pay-rejected strong { display: block; color: var(--error); margin-bottom: 2px; }

/* JOSE'S OWN WORDS. Bigger than everything around them, and never italic —
   italics read as an aside and this is the point of the block. */
.pay-rejected-note { display: block; font-size: 13.5px; font-weight: 600;
  line-height: 1.4; }

/* THE ABSENCE, STATED. Muted, because it is an account of the RECORD rather
   than something anybody said — but present and legible, because an empty slot
   here would read as "Jose said nothing", which is false for every rejection
   currently on file. */
.pay-rejected-nonote { display: block; color: var(--muted); font-style: normal; }

.pay-rejected-code { display: block; margin-top: 4px; color: var(--muted);
  font-size: 11.5px; }
.pay-rejected-code code { font-size: 11px; }
.pay-rejected-who { display: block; margin-top: 2px; color: var(--muted);
  font-size: 11.5px; }

/* THE PARENT'S RULING on a resubmission. Quieter than a live rejection — this
   claim is not the one that was refused — but the words are the same size,
   because they are the reason this row exists. */
.pay-rejected-parent { border-left-color: var(--muted); background: var(--bg); }
.pay-rejected-parent strong { color: var(--muted); }

/* >>> OUTSTANDING WORK, RENDERED AS WORK. <<< (Art, 2026-08-19.)
   Amber, matching the provenance chip, because both say the same kind of thing:
   something here is not finished. Deliberately NOT the error red — nothing has
   gone wrong, there is simply work left, and colouring it as a fault would
   teach the floor to dismiss it. */
/* THE INSTRUMENT/DIVISION SPLIT NOTE. Informational, not a fault: both facts
   are true and the panel is reconciling them, so it is the calm blue of a
   statement rather than the amber of outstanding work or the red of a refusal.
   A split rendered as a warning would train people to "fix" a correct state. */
.doc-division-note {
  border-left: 3px solid #3730A3; background: #EEF2FF;
  color: #312E81; font-size: 12.5px;
}
.doc-division-note strong { display: block; margin-bottom: 2px; }

.pending-block {
  display: block; margin: 8px 0; padding: 8px 10px;
  border-left: 3px solid #D97706; background: #FFFBEB;
  border-radius: 6px; font-size: 12.5px;
}
.pending-block > strong { display: block; color: #92400E; margin-bottom: 4px; }
.pending-count { float: right; font-weight: 600; font-size: 11.5px; }

.pending-list { list-style: none; margin: 0; padding: 0; }
.pending-item { display: block; padding: 2px 0; line-height: 1.4; }
.pending-mark { display: inline-block; width: 1.1em; font-weight: 700; }

/* DONE ITEMS STAY ON THE LIST, quiet and struck through. A list showing only
   what is left cannot be read as progress: "2 outstanding" means something
   different when you can see it was 6. */
.pending-item.done { color: var(--muted); }
.pending-item.done .pending-label { text-decoration: line-through; }
.pending-item.todo .pending-label { font-weight: 600; }
.pending-detail { display: block; margin-left: 1.1em; color: var(--muted);
  font-size: 11.5px; }

/* NOTHING OUTSTANDING IS STILL STATED, never left blank: an empty region where
   a checklist was is indistinguishable from a checklist that failed to load. */
.pending-settled { border-left-color: var(--ok, #059669); background: #ECFDF5; }
.pending-settled > strong { color: #065F46; }
.pending-none { color: #065F46; }

.pay-capture { margin: 6px 0; }
.pay-capture .kv-row { padding: 4px 0; font-size: 12.5px; gap: var(--space-3); }
.pay-capture .kv-row:last-child { border-bottom: none; }
.pay-capture .v { text-align: right; word-break: break-word; }
.pay-capture .missing { color: var(--muted); font-style: italic; }
/* THE SEAL IS THE ONLY THING ON THIS CARD THAT SAYS WHETHER MONEY IS REAL, so
   it is the one badge that carries colour. `pending` is the ordinary state and
   is deliberately quiet — most claims are waiting, and a wall of amber would
   make the two that are rejected invisible. */
.pay-seal { font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
            border-radius: 999px; padding: 1px 8px; border: 1px solid var(--border); }
.seal-pending { color: var(--muted); }
.seal-verified { color: #0f7b46; border-color: #a7dcc0; background: #eefaf3; }
.seal-rejected { color: #9a2b2b; border-color: #eab6b6; background: #fdf1f1; }
.seal-unreadable, .seal-superseded { color: var(--muted); font-style: italic; }

/* ONE ROW PER INSTRUMENT. Grid rather than flex so the method, the amount and
   the file input line up down the column however many rows are added — a
   ragged left edge on a money form is how a leg gets typed into the wrong row. */
.pay-line { display: grid; gap: var(--space-2); align-items: center;
            grid-template-columns: minmax(120px, 1fr) minmax(90px, 120px) 2fr auto;
            margin: var(--space-2) 0; }
.pay-line input, .pay-line select {
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px;
  font-size: 13px; width: 100%;
}
.pay-drop { padding: 4px 10px; line-height: 1; }
@media (max-width: 640px) {
  .pay-line { grid-template-columns: 1fr; }
}
/* THE RUNNING TOTAL. Green when the lines reconcile, amber when they do not —
   the same sentence the server would refuse with, shown early enough that the
   refusal never has to happen. */
.hint.ok { color: #0f7b46; }
.hint.warn { color: #9a6b00; }

/* THE PAYMENT DOOR ON A SEARCH ROW (v4.1 rv2). The suggestion stays the whole
   clickable width it always was; the door sits beside it, quiet until hovered.
   It must not compete with the row for the eye — most searches are somebody
   looking a consultant up, not recording money — but it must be there on EVERY
   row, because the rows this board cannot open are exactly the ones whose
   payments had nowhere to go. */
.search-row-wrap { display: flex; align-items: stretch; gap: 0; }
.search-row-wrap .search-row { flex: 1 1 auto; }
.search-pay {
  flex: 0 0 auto; align-self: center; margin-right: 8px;
  font-size: 11px; padding: 3px 8px; white-space: nowrap;
  border: 1px solid var(--border); border-radius: 999px;
  background: none; color: var(--muted); cursor: pointer;
}
.search-row-wrap:hover .search-pay { color: inherit; border-color: currentColor; }
/* Rows that carry a door alongside other actions keep it from crowding them. */
.bench-row .pay-door, .exception-row .pay-door, .card.read-only .pay-door {
  font-size: 11px; padding: 3px 8px; white-space: nowrap; align-self: center;
}

/* WHO PAID YOU — the board's payment picker (v4.1 rv3).
   Rows are identity and nothing else, so they are laid out as name-then-
   disambiguator and carry no badges: a stage pill here would be pipeline detail
   in a dialog that has no business showing any. */
.paypick-results { max-height: 300px; overflow-y: auto; margin: var(--space-2) 0; }
.paypick-row {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--space-3); width: 100%; text-align: left; cursor: pointer;
  padding: 8px 10px; border: 0; border-bottom: 1px solid var(--border);
  background: none; font-size: 13px;
}
.paypick-row:hover, .paypick-row:focus-visible { background: #f4f7fb; }
.paypick-name { font-weight: 600; }
.paypick-id { color: var(--muted); font-size: 12px; white-space: nowrap; }
#paypick-input {
  width: 100%; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: 8px; font-size: 13px;
}
/* A PINNED KIND LOOKS PINNED. Disabled rather than hidden, so the dialog still
   says what it is recording — the recruiter should see "Slot payment", not a
   missing field. */
#payment-kind:disabled { background: #f4f7fb; color: var(--muted); cursor: default; }
