/* NICOLL CRM — clean, dense, professional. Neutral and unbranded. */

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  font-family: var(--font);
  font-size: var(--fs-md);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* --- Layout --- */
.layout { display: flex; min-height: 100vh; }

.sidebar {
  width: 210px;
  flex: 0 0 210px;
  background: var(--primary);
  color: #fff;
  display: flex;
  flex-direction: column;
  padding: 18px 14px;
}
.wordmark {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  font-size: var(--fs-lg);
  padding: 6px 8px 18px;
  text-decoration: none;
}
/* The mark is a square app-style icon with its own rounded corners and dark
   ground, so it needs no plate behind it on the dark sidebar. */
.wordmark img {
  width: 44px;
  height: 44px;
  flex: 0 0 44px;
  border-radius: 10px;
  display: block;
}
.wordmark span { line-height: 1.15; }
.wordmark:hover { text-decoration: none; }
.nav { display: flex; flex-direction: column; gap: 2px; }
.nav-item {
  color: rgba(255, 255, 255, 0.82);
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  font-weight: 500;
}
.nav-item:hover { background: rgba(255, 255, 255, 0.08); text-decoration: none; }
.nav-item.is-active { background: rgba(255, 255, 255, 0.16); color: #fff; }
.nav-note {
  margin-top: auto;
  font-size: var(--fs-sm);
  color: #ffd7a8;
  background: rgba(183, 121, 31, 0.25);
  border: 1px solid rgba(255, 215, 168, 0.35);
  padding: 8px 10px;
  border-radius: var(--radius-sm);
}

.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 22px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.topbar-title { font-size: var(--fs-xl); font-weight: 600; }
.topbar-actions { display: flex; gap: 8px; align-items: center; }

.content { padding: 22px; flex: 1; min-width: 0; }

/* --- Buttons --- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  line-height: 1;
}
.btn:hover { background: var(--surface-2); text-decoration: none; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { filter: brightness(0.94); background: var(--accent); }
.btn-danger { color: var(--red); border-color: #e6c3bd; }
.btn-sm { padding: 5px 10px; font-size: var(--fs-base); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* --- Cards / panels --- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px;
  margin-bottom: 18px;
}
.card h2 { margin: 0 0 12px; font-size: var(--fs-lg); }
.card h3 { margin: 0 0 10px; font-size: var(--fs-md); color: var(--text-muted); }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.stat-row { display: flex; gap: 18px; flex-wrap: wrap; }
.stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 20px;
  min-width: 140px;
}
.stat .num { font-size: var(--fs-3xl); font-weight: 700; }
.stat .lbl { color: var(--text-muted); font-size: var(--fs-base); margin-top: 4px; }

.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.small { font-size: var(--fs-base); }

/* --- Tables / grid --- */
.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
table.grid { border-collapse: collapse; width: 100%; font-size: var(--fs-base); }
table.grid th, table.grid td {
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
table.grid th {
  background: var(--surface-2);
  font-weight: 600;
  color: var(--text-muted);
  position: sticky;
  top: 0;
}
table.grid tbody tr:hover { background: var(--surface-2); }
table.grid td.wrap, table.grid th.wrap { white-space: normal; }

/* --- Forms --- */
label { display: block; font-weight: 500; margin-bottom: 4px; font-size: var(--fs-base); }
input[type=text], input[type=email], input[type=number], input[type=date],
input[type=password], select, textarea {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font: inherit;
  background: var(--surface);
  color: var(--text);
}
textarea { resize: vertical; min-height: 80px; }
.field { margin-bottom: 14px; }
.field-row { display: flex; gap: 14px; }
.field-row .field { flex: 1; }
.inline { display: flex; gap: 8px; align-items: center; }

/* --- Badges / pills --- */
.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: var(--fs-sm);
  font-weight: 500;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.badge.ok { color: var(--green); border-color: #bfe3cd; background: #eef8f2; }
.badge.warn { color: var(--amber); border-color: #f0dcb8; background: #fdf6e8; }
.badge.err { color: var(--red); border-color: #eecac3; background: #fdeeeb; }
.tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: var(--fs-sm);
  background: #eef2fb;
  color: var(--accent);
  border: 1px solid #d6e1f7;
}

/* --- Empty states --- */
.empty {
  text-align: center;
  color: var(--text-muted);
  padding: 48px 20px;
}
.empty .big { font-size: var(--fs-xl); color: var(--text); margin-bottom: 6px; }

/* --- Health check result --- */
.result { padding: 10px 12px; border-radius: var(--radius-sm); margin-top: 10px; font-size: var(--fs-base); }
.result.ok { background: #eef8f2; color: var(--green); border: 1px solid #bfe3cd; }
.result.err { background: #fdeeeb; color: var(--red); border: 1px solid #eecac3; }

/* --- Toast --- */
.toast {
  position: fixed;
  bottom: 22px;
  right: 22px;
  background: var(--primary);
  color: #fff;
  padding: 12px 16px;
  border-radius: var(--radius);
  font-size: var(--fs-base);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s, transform 0.2s;
  pointer-events: none;
  max-width: 360px;
  z-index: 50;
}
.toast.show { opacity: 1; transform: translateY(0); }
.toast.err { background: var(--red); }

/* --- Misc --- */
.row-actions { display: flex; gap: 6px; }
.spacer { flex: 1; }
.mt { margin-top: 14px; }
.mb { margin-bottom: 14px; }
.section-title { font-size: var(--fs-base); text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-faint); margin: 18px 0 8px; }
hr.sep { border: 0; border-top: 1px solid var(--border); margin: 16px 0; }

/* --- Kanban (used in Phase E) --- */
.board { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 8px; }
.board-col { flex: 0 0 210px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px; }
.board-col h4 { margin: 0 0 8px; font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }
.board-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 9px 10px; margin-bottom: 8px; font-size: var(--fs-base); }
.board-card .name { font-weight: 600; }

/* ==========================================================================
   Dark-theme corrections.
   Everything above resolves through the tokens in theme.css and needed no
   change. What follows is the handful of rules that had light colours baked
   in as literals, plus the extra work dense data tables need to stay readable
   on a dark background.
   ========================================================================== */

/* --- Dense data tables (candidate grid, roles, placements, clients) ------
   On dark, a 1px rgba border at 8% disappears and rows run together, so the
   grid gets a stronger divider, a solid sticky header, and hover/selected
   states that are obvious without shouting. */

.table-wrap {
  border-color: var(--rb-border-strong);
  background: var(--rb-panel);
}

table.grid th {
  background: var(--rb-panel-2);
  color: var(--rb-heading);
  font-weight: 600;
  font-size: var(--fs-sm);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--rb-border-strong);
  box-shadow: inset 0 -1px 0 var(--rb-border-strong);
}

table.grid td {
  border-bottom: 1px solid var(--rb-border-strong);
  color: var(--rb-text);
  padding: 9px 12px;
}

/* Zebra striping: subtle, but enough to track a row across many columns. */
table.grid tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.018); }
table.grid tbody tr:hover { background: var(--rb-accent-soft); }
table.grid tbody tr:hover td { color: var(--rb-heading); }

/* Row selected by its checkbox (bulk actions on the candidate grid). */
table.grid tbody tr:has(input[type=checkbox]:checked) {
  background: rgba(232, 134, 62, 0.10);
  box-shadow: inset 3px 0 0 var(--rb-accent);
}

table.grid a { color: var(--rb-text); text-decoration: none; }
table.grid a:hover { color: var(--rb-accent); text-decoration: underline; }
table.grid td.faint, table.grid .faint { color: var(--rb-muted); }

/* --- Links --------------------------------------------------------------- */
a { color: var(--rb-accent); }
a:hover { color: var(--rb-accent-deep); }

/* --- Headings ------------------------------------------------------------ */
h1, h2, h3, h4 { color: var(--rb-heading); }
.card h3 { color: var(--rb-muted); }

/* --- Forms --------------------------------------------------------------- */
input[type=text], input[type=email], input[type=number], input[type=date],
input[type=password], select, textarea {
  background: var(--rb-bg-alt);
  border-color: var(--rb-border-strong);
  color: var(--rb-text);
}
input::placeholder, textarea::placeholder { color: var(--rb-faint); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--rb-accent);
  box-shadow: 0 0 0 2px var(--rb-accent-soft);
}
label { color: var(--rb-text); }
/* Native date and select pickers render their glyphs dark-on-dark otherwise. */
input[type=date] { color-scheme: dark; }
select { color-scheme: dark; }
input[type=checkbox], input[type=radio] { accent-color: var(--rb-accent); }

/* --- Buttons ------------------------------------------------------------- */
.btn {
  background: var(--rb-panel-2);
  border-color: var(--rb-border-strong);
  color: var(--rb-text);
}
.btn:hover { background: var(--rb-panel); color: var(--rb-heading); }
.btn-primary { background: var(--rb-accent); border-color: var(--rb-accent); color: #17120c; }
.btn-primary:hover { background: var(--rb-accent-deep); border-color: var(--rb-accent-deep); color: #17120c; }
.btn-danger { color: var(--rb-red); border-color: rgba(224, 86, 79, 0.45); background: rgba(224, 86, 79, 0.10); }

/* --- Badges, tags and result banners -------------------------------------
   These carried light pastel literals. Same semantic colours, tinted for dark. */
.badge { background: var(--rb-panel-2); border-color: var(--rb-border-strong); color: var(--rb-muted); }
.badge.ok   { color: var(--rb-green); border-color: rgba(63, 182, 139, 0.40); background: rgba(63, 182, 139, 0.14); }
.badge.warn { color: var(--rb-amber); border-color: rgba(232, 161, 62, 0.40); background: rgba(232, 161, 62, 0.14); }
.badge.err  { color: var(--rb-red);   border-color: rgba(224, 86, 79, 0.40);  background: rgba(224, 86, 79, 0.14); }

.tag {
  background: var(--rb-accent-soft);
  color: var(--rb-accent);
  border-color: rgba(232, 134, 62, 0.35);
}

.result.ok  { background: rgba(63, 182, 139, 0.12); color: var(--rb-green); border-color: rgba(63, 182, 139, 0.40); }
.result.err { background: rgba(224, 86, 79, 0.12);  color: var(--rb-red);   border-color: rgba(224, 86, 79, 0.40); }
.result     { background: var(--rb-panel-2); color: var(--rb-text); border: 1px solid var(--rb-border-strong); }

/* --- Cards, empty states, toast ------------------------------------------ */
.card { background: var(--rb-panel); border: 1px solid var(--rb-border); box-shadow: var(--rb-shadow); }
.stat { background: var(--rb-panel-2); border: 1px solid var(--rb-border); }
.stat .num { color: var(--rb-heading); }
.empty { color: var(--rb-muted); }
.empty .big { color: var(--rb-heading); }
.toast { background: var(--rb-panel-2); color: var(--rb-text); border: 1px solid var(--rb-border-strong); }
.toast.err { background: var(--rb-red); color: #fff; }

/* --- Kanban board -------------------------------------------------------- */
.board-col h4 { color: var(--rb-muted); text-transform: uppercase; font-size: var(--fs-xs); letter-spacing: 0.08em; }
.board-card {
  background: var(--rb-panel);
  border: 1px solid var(--rb-border-strong);
  border-radius: var(--rb-radius-sm);
}
.board-card:hover { border-color: var(--rb-accent); }
.board-card .name a { color: var(--rb-heading); }

/* --- Misc ---------------------------------------------------------------- */
code { background: var(--rb-bg-alt); color: var(--rb-accent); padding: 1px 5px; border-radius: 4px; }
details summary { color: var(--rb-text); }
hr { border: 0; border-top: 1px solid var(--rb-border); }
::selection { background: var(--rb-accent); color: #17120c; }

/* Sticky headers belong to real column headers only. The candidate profile's
   "Details" panel is a key/value table using <th> as a row label in <tbody>,
   and those must not stick to the top of the viewport when scrolling. */
table.grid th { position: static; }
table.grid thead th { position: sticky; top: 0; z-index: 1; }

/* A row-label <th> reads as a quiet label column, not a column header. */
table.grid tbody th {
  background: var(--rb-bg-alt);
  color: var(--rb-muted);
  font-size: var(--fs-xs);
  width: 1%;
  white-space: nowrap;
}

/* Links inside a dense grid: brighter than the surrounding text so they are
   discoverable, amber and underlined on hover. Amber for every link would be
   overwhelming in a table this dense. */
table.grid tbody td a { color: var(--rb-heading); }
table.grid tbody td a:hover { color: var(--rb-accent); text-decoration: underline; }

/* Scrollbars: the default light thumb is invisible on dark, which matters for
   the horizontally scrolling Kanban board and wide data tables. */
* { scrollbar-color: var(--rb-panel-2) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { height: 10px; width: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--rb-panel-2);
  border-radius: 6px;
  border: 2px solid var(--rb-bg);
}
::-webkit-scrollbar-thumb:hover { background: var(--rb-border-strong); }

/* Move-signal dot. Colour is set inline from the band, so the harmonised
   traffic-light values stay in one place (services/move_signal.py). */
.move-dot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 50%;
  margin-right: 7px;
  vertical-align: middle;
}
.move-dot-lg { width: 16px; height: 16px; margin-right: 0; }

/* A soft warning: the save went through, but something is worth checking. */
.result.warn {
  background: rgba(232, 161, 62, 0.12);
  color: var(--rb-amber);
  border-color: rgba(232, 161, 62, 0.40);
}

/* --- "Add candidates to this wave" filter chips ---------------------------
   Role-derived filters are amber and read "from the role"; anything typed
   here is neutral and reads "yours". A relaxed role requirement stays on
   screen, dimmed, so it is obvious the results are wider than the role. */
.find-filters {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: var(--fs-sm);
  border: 1px solid var(--rb-border-strong);
  background: var(--rb-panel-2);
  color: var(--rb-text);
}
.chip .chip-src {
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.75;
}
.chip a { text-decoration: none; font-weight: 700; opacity: 0.8; }
.chip a:hover { opacity: 1; text-decoration: none; }

.chip-role {
  background: var(--rb-accent-soft);
  border-color: rgba(232, 134, 62, 0.45);
  color: var(--rb-accent);
}
.chip-role a { color: var(--rb-accent); }

.chip-yours {
  background: rgba(74, 144, 217, 0.14);
  border-color: rgba(74, 144, 217, 0.45);
  color: #7fb3e8;
}
.chip-yours a { color: #7fb3e8; }

.chip-relaxed {
  background: transparent;
  border-style: dashed;
  color: var(--rb-muted);
  text-decoration: line-through;
}
.chip-relaxed a { color: var(--rb-accent); text-decoration: none; font-weight: 600; }

/* --- Global job progress -------------------------------------------------
   Pinned to the viewport, not the page: position:fixed against the initial
   containing block, so scrolling a long list never takes a running job off
   screen. Nothing in the ancestor chain may use transform, filter or
   will-change, or the fixed positioning would resolve against that element
   instead; the container is a direct child of <body> for exactly that reason.

   One card per running job, because an ingest and a submission can run at
   once and a single bar could not honestly represent both. */
#job-progress {
  position: fixed;
  top: 12px;
  right: 16px;
  z-index: 200;
  width: 288px;
  max-height: calc(100vh - 24px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: auto;
}
#job-progress[hidden] { display: none; }

.job-card {
  background: var(--rb-panel);
  border: 1px solid rgba(232, 134, 62, 0.45);
  border-radius: var(--rb-radius-sm);
  box-shadow: var(--rb-shadow);
  padding: 9px 11px 10px;
  font-size: var(--fs-sm);
  color: var(--rb-text);
}

.job-row { display: flex; align-items: center; gap: 8px; }
.job-label { flex: 1; font-weight: 600; color: var(--rb-heading); line-height: 1.3; }

.job-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--rb-accent);
  flex: 0 0 8px;
}
.job-card.is-running .job-dot { animation: job-pulse 1.4s ease-in-out infinite; }
@keyframes job-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .job-dot { animation: none !important; } }

.job-dismiss {
  background: transparent; border: 0;
  color: var(--rb-muted);
  font-size: var(--fs-lg); line-height: 1; cursor: pointer; padding: 0 2px;
}
.job-dismiss:hover { color: var(--rb-heading); }

.job-track {
  margin-top: 8px; height: 5px; border-radius: 3px;
  background: var(--rb-bg-alt); overflow: hidden;
}
.job-fill {
  height: 100%; width: 0;
  background: var(--rb-accent); border-radius: 3px;
  transition: width 0.35s ease;
}
.job-link {
  display: inline-block;
  margin-top: 8px;
  color: var(--rb-accent);
  font-weight: 700;
  text-decoration: none;
}
.job-link:hover { text-decoration: underline; }

/* Finished cleanly: green, and it clears itself shortly after. */
.job-card.is-done { border-color: rgba(63, 182, 139, 0.45); }
.job-card.is-done .job-fill { background: var(--rb-green); }
.job-card.is-done .job-dot { background: var(--rb-green); }

/* Stopped partway: red, and it stays until dismissed. */
.job-card.is-error { border-color: rgba(224, 86, 79, 0.5); }
.job-card.is-error .job-fill { background: var(--rb-red); }
.job-card.is-error .job-dot { background: var(--rb-red); }

/* --- Summary presentation ------------------------------------------------
   The on-screen and clipboard version. A bold header, generous spacing
   between people and between bullets, so a pack of five reads as five people
   rather than one block of text. */
.summary-rich {
  background: var(--rb-bg-alt);
  border: 1px solid var(--rb-border-strong);
  border-radius: var(--rb-radius-sm);
  padding: 14px 16px;
  font-size: var(--fs-base);
  line-height: 1.55;
}
.summary-block + .summary-block {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--rb-border);
}
.summary-header {
  margin: 0 0 8px;
  color: var(--rb-heading);
  font-size: var(--fs-md);
}
.summary-bullets { margin: 0; padding-left: 18px; }
.summary-bullets li { margin-bottom: 7px; }
.summary-bullets li:last-child { margin-bottom: 0; }

/* A date that cannot be right (after today). Flagged, never silently fixed,
   so it can be recognised and corrected at source. */
.date-flagged { color: var(--rb-red); font-weight: 600; }

/* --- Cascading facets ----------------------------------------------------
   Each facet is a collapsible list of checkboxes. Every option shown returns
   at least one candidate given the other active filters, so there is nothing
   to grey out: an unusable option is simply not rendered. */
.facet-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-start;
}
.facet {
  flex: 1 1 210px;
  min-width: 190px;
  background: var(--rb-bg-alt);
  border: 1px solid var(--rb-border-strong);
  border-radius: var(--rb-radius-sm);
  padding: 8px 10px;
}
.facet > summary {
  cursor: pointer;
  font-weight: 600;
  font-size: var(--fs-base);
  color: var(--rb-heading);
  list-style: none;
}
.facet > summary::-webkit-details-marker { display: none; }
.facet > summary::before { content: "▸ "; color: var(--rb-muted); }
.facet[open] > summary::before { content: "▾ "; }
.facet-note { margin: 6px 0 2px; }

.facet-options { max-height: 230px; overflow-y: auto; margin-top: 6px; }
.facet-heading {
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--rb-accent);
  margin: 8px 0 3px;
}
.facet-option {
  display: flex;
  align-items: center;
  gap: 7px;
  font-weight: 400;
  font-size: var(--fs-base);
  margin: 0;
  padding: 3px 2px;
  border-radius: 4px;
  cursor: pointer;
}
.facet-option:hover { background: rgba(255, 255, 255, 0.04); }
.facet-option input { width: auto; margin: 0; }
.facet-label { flex: 1; }
.facet-count { color: var(--rb-muted); font-size: var(--fs-xs); }
/* A selected value kept visible although the other filters would hide it. */
.facet-option.is-empty .facet-label { color: var(--rb-muted); font-style: italic; }
.facet-option.is-empty .facet-count { color: var(--rb-red); }

.result-count { font-size: var(--fs-base); color: var(--rb-text); }
.result-count strong { color: var(--rb-accent); font-size: var(--fs-xl); }

/* --- Follow-ups ---------------------------------------------------------
   One list style, used by the dashboard panels, the role page, the
   placements page and the full follow-ups page, so a flag looks and behaves
   the same wherever it turns up. */
.fu-list { list-style: none; margin: 0; padding: 0; }
.fu-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 8px 0; border-bottom: 1px solid var(--rb-hairline, rgba(128,128,128,0.18));
}
.fu-item:last-child { border-bottom: 0; }
.fu-who { flex: 1; min-width: 0; }
.fu-who a { font-weight: 600; }
.fu-act { flex: 0 0 auto; }
.fu-clear {
  padding: 12px; border-radius: 8px; font-size: var(--fs-base); line-height: 1.5;
  background: var(--rb-panel-2, rgba(128,128,128,0.08));
}
.fu-clear strong { display: block; margin-bottom: 2px; }
/* The board link sits next to Log contact, not stacked under it: they are two
   ways of acting on the same person and belong on the same line. Top-aligned to
   match the Log contact summary beside it, which takes flex-start from the
   list item. This needs to out-specify the global ".btn { align-self: center }"
   below, which otherwise centres it against a two-line item and leaves the pair
   sitting at different heights. */
.fu-item > .fu-board { align-self: flex-start; }

/* --- Getting to the board -------------------------------------------------
   The lead cell on the Roles and Client role tables. Fixed and narrow so the
   action column cannot push the name column about as labels change between
   "Open board" and "Pick wave". */
.row-go { width: 1%; white-space: nowrap; }

/* The wave picker, shown on a role only when two or more waves are open. Cards
   rather than table rows: this is a choice being made, not data being read. */
.wave-pick-grid {
  display: grid; gap: 10px; margin-top: 10px;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.wave-pick-card {
  display: block; padding: 12px 14px; text-decoration: none;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm); color: inherit;
}
.wave-pick-card:hover {
  border-color: var(--rb-accent); background: var(--rb-accent-soft);
}
.wave-pick-when {
  font-weight: 600; font-size: var(--fs-md); color: var(--rb-heading);
}
.wave-pick-counts { font-size: var(--fs-sm); margin-top: 4px; }
.wave-pick-go {
  display: inline-block; margin-top: 8px;
  font-size: var(--fs-sm); color: var(--rb-accent);
}

/* A card arrived at by a #card-N deep link from Pipeline or a follow-up list.
   Without this you land on the right board and still have to find the person. */
.board-card:target {
  border-color: var(--rb-accent);
  box-shadow: 0 0 0 2px var(--rb-accent-soft);
}

/* Per-stage counts on the Roles list. Each one is a link into that stage's
   group on the role page, so a number is never a dead end. */
.stage-counts { white-space: nowrap; }
.stage-count {
  display: inline-block; margin: 0 8px 2px 0; font-size: var(--fs-sm);
  text-decoration: none; opacity: 0.95;
}
.stage-count strong { font-variant-numeric: tabular-nums; }
.stage-count.zero { opacity: 0.45; }
.stage-count.placed { opacity: 0.8; }

/* Stage groups on the role page, the anchors those counts land on. */
.stage-group { margin-top: 18px; scroll-margin-top: 20px; }
.stage-heading { margin: 0 0 6px; font-size: var(--fs-md); }
.stage-group:target .stage-heading { text-decoration: underline; }

/* --- Clearance ----------------------------------------------------------
   Never a bare chip. Tier and source are always on screen, and an inferred
   entry is visually distinct from a stated one so the two can't be confused
   at a glance. */
.clearance-row {
  padding: 8px 10px; margin-bottom: 6px; border-radius: 8px;
  border-left: 3px solid var(--rb-hairline, rgba(128,128,128,0.3));
  background: var(--rb-panel-2, rgba(128,128,128,0.06));
}
.clearance-row.is-inferred {
  border-left-style: dashed;
  border-left-color: var(--red, #e0564f);
}
.clearance-row strong { font-size: var(--fs-md); }

/* --- Facet exclusion (NOT) ----------------------------------------------
   An excluded value must read as excluded without relying on colour alone:
   the label is struck through, the chip is prefixed "NOT", and the toggle
   itself is filled in. Colour is the third signal, not the only one. */
.facet-option { display: flex; align-items: center; gap: 6px; }
.facet-pick { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; cursor: pointer; }
.facet-option .facet-label { overflow: hidden; text-overflow: ellipsis; }

.facet-not {
  flex: 0 0 auto; font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.04em;
  padding: 1px 5px; border-radius: 4px; text-decoration: none;
  border: 1px solid var(--rb-border, rgba(128,128,128,0.3));
  color: var(--rb-muted, #8a92a4); opacity: 0.55;
}
.facet-option:hover .facet-not { opacity: 1; }
.facet-not.on {
  opacity: 1; color: #fff;
  background: var(--red, #e0564f); border-color: var(--red, #e0564f);
}
.facet-option.is-excluded .facet-label {
  text-decoration: line-through; opacity: 0.7;
}
.facet-option.is-excluded .facet-count { opacity: 0.4; }

/* An excluded chip: struck through and carrying the word NOT. */
.chip.chip-not {
  border-color: var(--red, #e0564f);
  background: rgba(224, 86, 79, 0.12);
}
.chip.chip-not .chip-src { opacity: 0.75; }

/* --- Retention track ----------------------------------------------------
   A status timeline, not a chase list: each dot is a milestone the placement
   either survived, is working towards, or never reached. Deliberately styled
   apart from the amber aftercare badges so the two are not confused. */
.ret-track { display: flex; gap: 3px; align-items: center; }
.ret-dot {
  min-width: 22px; padding: 1px 4px; border-radius: 4px;
  font-size: var(--fs-2xs); font-weight: 600; text-align: center;
  border: 1px solid var(--rb-border, rgba(128,128,128,0.3));
  color: var(--rb-muted, #8a92a4);
}
.ret-dot.is-passed  { background: var(--green, #3fb68b); border-color: var(--green, #3fb68b); color: #06231a; }
.ret-dot.is-current { background: var(--rb-accent-soft, rgba(232,134,62,0.18));
                      border-color: var(--rb-accent, #e8863e); color: var(--rb-accent, #e8863e); }
.ret-dot.is-missed  { background: transparent; border-style: dashed;
                      border-color: var(--red, #e0564f); color: var(--red, #e0564f); }
.rb-headline-row { display: flex; gap: 26px; flex-wrap: wrap; }
.rb-headline { min-width: 150px; }

/* --- Export page --------------------------------------------------------
   A disabled area still shows, so a gap in the tool is visible rather than
   silently absent. It is dimmed and struck out of reach, never hidden. */
.export-areas { display: grid; gap: 10px; max-width: 620px; }
.export-area {
  display: flex; gap: 10px; align-items: flex-start; cursor: pointer;
  padding: 10px 12px; border-radius: 8px;
  border: 1px solid var(--rb-border, rgba(128,128,128,0.25));
  background: var(--rb-panel-2, rgba(128,128,128,0.06));
}
.export-area:hover { border-color: var(--rb-accent, #e8863e); }
.export-area.is-disabled { opacity: 0.55; cursor: not-allowed; }
.export-area.is-disabled:hover { border-color: var(--rb-border, rgba(128,128,128,0.25)); }
.export-area input { margin-top: 3px; }

/* --- Log contact ---------------------------------------------------------
   Compact by design: this gets used dozens of times a day, so it is one row
   of controls plus an optional note, never a page of fields. */
.contact-form { display: grid; gap: 5px; margin-top: 6px; }
.contact-form-row { display: flex; gap: 5px; align-items: center; }
.contact-form-row select,
.contact-form-row input[type="date"] { font-size: var(--fs-sm); padding: 3px 5px; }
.contact-form input[type="text"] { font-size: var(--fs-sm); padding: 4px 6px; }
.contact-log-toggle { font-size: var(--fs-xs); cursor: pointer; }
details.contact-log > summary { list-style: none; }
details.contact-log > summary::-webkit-details-marker { display: none; }

.contact-history { list-style: none; margin: 0; padding: 0; }
.contact-history li {
  padding: 8px 0; border-bottom: 1px solid var(--rb-hairline, rgba(128,128,128,0.18));
}
.contact-history li:last-child { border-bottom: 0; }
.ch-head { display: flex; gap: 8px; align-items: center; }
.ch-note { font-size: var(--fs-base); margin-top: 3px; opacity: 0.9; }

/* --- Scheduled interviews ------------------------------------------------
   A date with a clock on it, so it reads differently from a stage badge.
   "Soon" (today or tomorrow) is amber-filled rather than outlined, because at
   that point it is the only thing on the card that matters. */
.iv-badge {
  margin-top: 6px; padding: 4px 7px; border-radius: 6px; font-size: var(--fs-sm);
  border: 1px solid var(--rb-accent, #e8863e); color: var(--rb-accent, #e8863e);
}
.iv-badge.soon {
  background: var(--rb-accent, #e8863e); color: #241004; font-weight: 600;
}
.iv-badge.soon .faint { color: #241004; opacity: 0.75; }
.iv-row.soon { border-left: 3px solid var(--rb-accent, #e8863e); }
.ps-stage-grid { display: flex; gap: 10px; flex-wrap: wrap; }
.ps-stage {
  min-width: 108px; padding: 10px 12px; border-radius: 8px; text-decoration: none;
  border: 1px solid var(--rb-border, rgba(128,128,128,0.25));
  background: var(--rb-panel-2, rgba(128,128,128,0.06));
}
.ps-stage:hover { border-color: var(--rb-accent, #e8863e); }
.ps-stage .n { font-size: var(--fs-3xl); font-weight: 700; }
.ps-stage.zero { opacity: 0.5; }
.move-arrow { opacity: 0.6; padding: 0 4px; }

/* --- Search clear control ------------------------------------------------ */
.q-wrap { position: relative; display: block; }
.q-wrap input { width: 100%; padding-right: 26px; }
.q-clear {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  border: 0; background: none; cursor: pointer; font-size: var(--fs-xl); line-height: 1;
  padding: 0 4px; color: var(--rb-muted, #8a92a4); visibility: hidden;
}
.q-clear:hover { color: var(--rb-accent, #e8863e); }

/* --- Topbar clock -------------------------------------------------------- */
.topbar-clock {
  margin-left: auto; padding-right: 14px; white-space: nowrap;
  font-size: var(--fs-sm); color: var(--rb-muted, #8a92a4);
  font-variant-numeric: tabular-nums;
}

/* --- Interview confirmation --------------------------------------------
   A tentative interview is dashed and carries the word "tentative"; a
   confirmed one is solid with a tick. Two signals, not colour alone. */
.iv-badge.tentative { border-style: dashed; }
.iv-tick {
  display: inline-block; font-weight: 700;
  color: var(--green, #3fb68b); margin-right: 2px;
}
.iv-badge.soon .iv-tick { color: #0f3d2c; }
.iv-row.tentative td:first-child { border-left: 3px dashed var(--rb-muted, #8a92a4); }

/* =========================================================================
   STANDARDS: controls
   Everything below is deliberately last in the file so it wins over the
   older per-component rules, and everything reads from the theme tokens, so
   adjusting the whole app is editing theme.css rather than hunting here.
   ========================================================================= */

/* --- Inputs: ONE size for every field ------------------------------------
   Text, select, date, time, number, textarea. The board-card date and time
   fields were 12px with 3px padding, roughly half the height of a Settings
   field; they now match everything else. Native date/time pickers need the
   height stated explicitly or WebKit renders them small regardless. */
input[type="text"], input[type="email"], input[type="search"],
input[type="tel"], input[type="url"], input[type="number"],
input[type="date"], input[type="time"], input[type="datetime-local"],
input[type="password"], select, textarea {
  font-family: var(--rb-font-ui);
  font-size: var(--fs-base);
  line-height: var(--lh-tight);
  min-height: var(--control-h);
  padding: var(--control-pad-y) var(--control-pad-x);
  border-radius: var(--control-radius);
  box-sizing: border-box;
}
textarea { min-height: calc(var(--control-h) * 2); line-height: var(--lh-body); }
select { padding-right: calc(var(--control-pad-x) + 8px); }

/* WebKit sizes the inner date/time spinner independently of the field. */
input[type="date"]::-webkit-datetime-edit,
input[type="time"]::-webkit-datetime-edit {
  font-size: var(--fs-base);
  padding: 0;
}
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator { opacity: 0.7; }

input[type="checkbox"], input[type="radio"] {
  width: 16px; height: 16px; min-height: 0; vertical-align: middle;
}

/* --- Buttons: four kinds, two sizes, nothing else -------------------------
   primary      one main action per screen (amber)
   secondary    everything else (outlined, the default .btn)
   destructive  delete and remove (red)
   link         plain text action, no chrome
   Size comes from the tokens, so a button is the same height wherever it is. */
.btn {
  font-family: var(--rb-font-ui);
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: var(--lh-tight);
  min-height: var(--btn-h);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border-radius: var(--control-radius);
  display: inline-flex; align-items: center; justify-content: center;
  gap: 6px; white-space: nowrap; box-sizing: border-box;
}
.btn-sm {
  font-size: var(--fs-xs);
  min-height: var(--btn-sm-h);
  padding: var(--btn-sm-pad-y) var(--btn-sm-pad-x);
}
.btn-danger, .btn-destructive {
  background: var(--red, #e0564f);
  border-color: var(--red, #e0564f);
  color: #fff;
}
.btn-danger:hover, .btn-destructive:hover { filter: brightness(1.08); }
.btn-link {
  background: none; border: 0; padding: 0; min-height: 0;
  color: var(--rb-accent, #e8863e); text-decoration: underline;
  font-weight: 500; cursor: pointer;
}

/* --- Room for the larger type -------------------------------------------
   The bump needs a little more breathing space in the dense places, or the
   text grows while its container does not. */
body { font-size: var(--fs-base); line-height: var(--lh-body); }
table.grid th, table.grid td { padding: 10px 12px; font-size: var(--fs-base); }
table.grid th { font-size: var(--fs-xs); }
.badge { font-size: var(--fs-xs); padding: 3px 8px; white-space: nowrap; }
.chip { font-size: var(--fs-sm); padding: 4px 10px; }
.chip-src { font-size: var(--fs-2xs); }
label { font-size: var(--fs-sm); }
.faint.small, .small { font-size: var(--fs-sm); }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }
.topbar-title { font-size: var(--fs-3xl); }
.facet-option { padding: 3px 0; }
.facet-count { font-size: var(--fs-xs); }

/* --- Dark-theme native controls -----------------------------------------
   The date picker inherited color-scheme from a parent but the time picker
   did not, so it rendered as a white box on a dark card. Stated on the
   controls themselves so every native widget follows the theme. */
input, select, textarea, button { color-scheme: dark; }
input[type="time"], input[type="date"], input[type="datetime-local"] {
  color-scheme: dark;
  background: var(--rb-panel-2, #1b2640);
  color: var(--rb-text, #d7dbe4);
  border: 1px solid var(--rb-border, rgba(255,255,255,0.12));
}

/* Full-width field inside a narrow container, e.g. a board card. */
.field-full { width: 100%; display: block; margin-bottom: 6px; }

/* Board cards are a narrow column: keep their controls readable rather than
   truncated, and let long option text shrink a step rather than clip. */
.board-card select, .board-card input { max-width: 100%; }
.board-card select { font-size: var(--fs-sm); }

/* A checkbox and its wrapping label, aligned rather than the box floating
   against the first line of text. */
.check-row { display: flex; align-items: flex-start; gap: 8px; margin: 4px 0 8px; }
.check-row input[type="checkbox"] { margin-top: 2px; flex: 0 0 auto; }

/* A button must never stretch to its container. Inside a flex parent (the
   .row-actions cells use one) an inline-flex child inherits align-items:
   stretch and grows to the full cell height, which made the Settings rule
   buttons 447px tall. Height is fixed rather than minimum because buttons are
   single-line by definition here (white-space: nowrap above). */
.btn {
  height: var(--btn-h);
  min-height: var(--btn-h);
  align-self: center;
  flex: 0 0 auto;
}
.btn-sm { height: var(--btn-sm-h); min-height: var(--btn-sm-h); }

/* Long option text in a narrow board column: let the control shrink its own
   text a step rather than clip the value. */
.board-card select,
.board-card input,
.board-card textarea { min-width: 0; width: 100%; }

/* Slot "fill this opening" selects sit in a narrow slot row. Give them the
   room the larger type needs rather than letting the value clip. */
.slot-row select, select[name="placement_id"] { min-width: 220px; }

/* The pipeline-row interview edit opens as a small panel rather than
   stretching the table cell, so the row keeps its shape while editing. */
.iv-edit { position: relative; }
.iv-edit[open] > summary { margin-bottom: 6px; }
.iv-edit-form {
  position: absolute; right: 0; z-index: 20; width: 260px;
  padding: 12px; border-radius: var(--control-radius);
  background: var(--rb-panel, #151d30);
  border: 1px solid var(--rb-accent, #e8863e);
  box-shadow: 0 10px 30px rgba(0,0,0,0.45);
}

/* --- Live clock ----------------------------------------------------------
   Hard right in the topbar. Tabular numerals so the seconds changing does not
   shuffle the text left and right once a second. */
.topbar-clock {
  margin-left: 18px; padding-left: 18px;
  border-left: 1px solid var(--rb-border, rgba(255,255,255,0.10));
  display: flex; flex-direction: column; align-items: flex-end;
  line-height: 1.2; white-space: nowrap;
}
.topbar-clock .clock-date { font-size: var(--fs-xs); color: var(--rb-muted, #8a92a4); }
.topbar-clock .clock-time {
  font-size: var(--fs-lg); font-weight: 600;
  color: var(--rb-text, #d7dbe4); font-variant-numeric: tabular-nums;
}
.topbar-actions { margin-left: auto; }

/* --- Inline editing on a candidate profile --------------------------------
   The value looks like a value, not a form field, until you point at it. A
   page of visible input boxes reads as a form to fill in; the point here is a
   record you can correct in passing. */
.inline-field { min-width: 0; }
.inline-field-view {
  display: inline-flex; align-items: baseline; gap: 8px;
  padding: 3px 7px; margin: -3px -7px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: text; max-width: 100%;
}
.inline-field-view:hover,
.inline-field-view:focus-visible {
  border-color: var(--border);
  background: var(--rb-panel-2, rgba(128, 128, 128, 0.08));
  outline: none;
}
/* The affordance only appears on hover or keyboard focus: a permanent "edit"
   against every row is visual noise on a page with a dozen of them. */
.inline-field-pencil {
  font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--rb-accent); opacity: 0; flex: 0 0 auto;
}
.inline-field-view:hover .inline-field-pencil,
.inline-field-view:focus-visible .inline-field-pencil { opacity: 1; }
.inline-field-empty { font-style: italic; }
.inline-field-notes { white-space: pre-wrap; }

.inline-field-form { display: block; max-width: 420px; }
.inline-field-form > label { display: block; margin-top: 6px; }
.inline-field-form .field-full { margin-top: 2px; }
.inline-field-actions {
  display: flex; align-items: center; gap: 8px; margin-top: 8px;
}
.inline-field-hint { margin-top: 6px; }
.inline-field-warn {
  margin-top: 6px; padding: 6px 8px; border-radius: var(--radius-sm);
  background: var(--rb-warn-soft, rgba(232, 134, 62, 0.14));
  color: var(--rb-heading);
}

/* The contact badge names the gap, so it is a link to the fix. The slot is
   always in the DOM (it is the out-of-band swap target), so it must collapse
   to nothing when there is no gap rather than leaving a gap of its own. */
.contact-badge-slot:empty { display: none; }
.badge-fix { text-decoration: none; cursor: pointer; }
.badge-fix:hover { filter: brightness(1.15); }

/* --- Pipeline history on a candidate profile ------------------------------
   One block per role put forward for. Bordered rather than separated by rules,
   because a journey is a unit: its steps, its interviews and its outcome have
   to read as belonging to that role and not to the one below. */
.journey {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  margin-top: 12px;
}
.journey-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.journey-role { font-weight: 600; font-size: var(--fs-md); }
.journey-meta { margin-top: 2px; }
.journey-empty { margin: 8px 0 0; }

.journey-steps {
  list-style: none; margin: 10px 0 0; padding: 0 0 0 14px;
  border-left: 2px solid var(--border);
}
.journey-step { display: flex; gap: 12px; padding: 4px 0; align-items: baseline; }
.journey-date {
  flex: 0 0 92px; font-variant-numeric: tabular-nums;
  color: var(--text-faint); font-size: var(--fs-sm);
}
.journey-move { min-width: 0; }
/* A step backwards and a final outcome are the two things worth spotting
   without reading the whole list. */
.journey-step.is-back .journey-move { opacity: 0.85; }
.journey-step.is-outcome .journey-move strong { color: var(--rb-heading); }

.journey-interviews {
  margin-top: 10px; padding-top: 8px; border-top: 1px dashed var(--border);
}
.journey-interview { margin-top: 4px; }
.journey-outcome {
  margin-top: 2px; padding: 4px 8px; border-radius: var(--radius-sm);
  background: var(--rb-panel-2, rgba(128, 128, 128, 0.08));
}

/* --- Conversion funnel on Analytics --------------------------------------
   A bar per stage with the drop-off written between them, rather than a chart:
   the interesting number here is the one BETWEEN two bars, and a chart puts
   that nowhere. */
.conv { margin-top: 12px; }
.conv-step { margin-bottom: 2px; }
.conv-bar-wrap {
  position: relative; border-radius: var(--radius-sm); overflow: hidden;
  background: var(--rb-panel-2, rgba(128, 128, 128, 0.08));
  min-height: 42px; display: flex; align-items: center;
}
.conv-bar {
  position: absolute; inset: 0 auto 0 0;
  background: var(--rb-accent-soft, rgba(232, 134, 62, 0.14));
  border-right: 2px solid var(--rb-accent, #e8863e);
  min-width: 2px;
}
.conv-bar-label {
  position: relative; display: flex; align-items: baseline; gap: 8px;
  padding: 0 12px; flex-wrap: wrap;
}
.conv-bar-label strong { font-size: var(--fs-lg); font-variant-numeric: tabular-nums; }
.conv-gap {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 6px 12px; font-size: var(--fs-sm);
}
.conv-arrow { color: var(--text-faint); }
.conv-conv { font-weight: 600; }
.conv-drop { color: var(--text-muted); }
.conv-outcomes {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 12px;
}
.lost-row { padding: 6px 0; border-bottom: 1px solid var(--border); }
.lost-row:last-child { border-bottom: 0; }

/* --- Placement salary and its currency ------------------------------------
   The amount and the currency sit on one row and stay together at every width.
   A currency that wraps onto its own line stops reading as part of the figure
   it describes, which is the whole point of having it. */
.salary-pair { display: flex; gap: 12px; align-items: flex-end; }
.salary-pair .field { margin-bottom: 10px; }
.salary-pair .field:first-child { flex: 2 1 0; min-width: 0; }
.salary-pair .field:last-child { flex: 0 0 122px; }
.pay-line {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: 6px;
}
.pay-line strong { font-variant-numeric: tabular-nums; }

/* --- Signed-out pages ------------------------------------------------------
   Their own shell, with no sidebar and no job poller: nothing on this page
   should be making authenticated requests, since the caller is not. */
.auth-body { display: block; background: var(--bg); }
.auth-shell {
  min-height: 100vh; display: flex; flex-direction: column;
  align-items: center; justify-content: center; padding: 24px; gap: 14px;
}
.auth-card {
  width: 100%; max-width: 400px; padding: 28px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.auth-brand {
  display: flex; align-items: center; gap: 12px; margin-bottom: 20px;
  font-weight: 700; letter-spacing: 0.05em; font-size: var(--fs-lg);
  color: var(--rb-heading);
}
.auth-brand img { border-radius: 10px; display: block; }
.auth-title { font-size: var(--fs-xl); margin: 0 0 14px; }
.auth-form { margin-top: 14px; }
.auth-submit { width: 100%; justify-content: center; margin-top: 6px; }
.auth-note { margin-top: 16px; }
.auth-foot { max-width: 400px; text-align: center; color: var(--text-faint);
             font-size: var(--fs-sm); margin: 0; }

/* Who is signed in, and the way out. Sits after the clock, hard right. */
.topbar-user { display: flex; align-items: center; gap: 8px; }
.topbar-who {
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted);
  max-width: 150px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- CV upload -------------------------------------------------------------
   The dropzone is the whole target, not a small button inside it: on a VPS
   this is the only way a CV gets into the system, so it should be hard to
   miss and hard to miss-hit. */
.dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  padding: 28px 20px;
  text-align: center;
  cursor: pointer;
  background: var(--rb-panel-2, rgba(128, 128, 128, 0.05));
  transition: border-color 0.12s, background 0.12s;
}
.dropzone:hover, .dropzone:focus-visible {
  border-color: var(--rb-accent); outline: none;
}
/* While a file is over it. Deliberately loud: dropping a CV on the wrong part
   of the page loses it silently, so the target has to be unmistakable. */
.dropzone.is-over {
  border-color: var(--rb-accent);
  background: var(--rb-accent-soft, rgba(232, 134, 62, 0.14));
}
.dropzone-lead {
  font-size: var(--fs-lg); font-weight: 600; color: var(--rb-heading);
}
.dropzone-link { color: var(--rb-accent); text-decoration: underline; }
.dropzone-limits { margin-top: 8px; }

.upload-chosen { margin-top: 14px; }
.upload-list { list-style: none; margin: 6px 0 0; padding: 0; }
.upload-list li {
  padding: 5px 0; border-bottom: 1px solid var(--border);
  font-size: var(--fs-base);
}
.upload-list li:last-child { border-bottom: 0; }
.upload-list code { word-break: break-all; }
.upload-remove {
  background: none; border: 0; padding: 0 4px; cursor: pointer;
  color: var(--text-faint); font: inherit; font-size: var(--fs-sm);
  text-decoration: underline;
}
.upload-remove:hover { color: var(--red); }

/* An author-level `display` beats the browser's own rule for [hidden], so a
   flex container marked hidden would still be laid out. This puts the
   attribute back in charge, and applies to every hidden block on the page
   rather than only the ones noticed so far. */
[hidden] { display: none !important; }

.upload-actions {
  display: flex; align-items: center; gap: 10px; margin-top: 14px; flex-wrap: wrap;
}
.upload-progress { margin-top: 14px; }
.upload-bar {
  height: 8px; border-radius: 999px; overflow: hidden;
  background: var(--rb-panel-2, rgba(128, 128, 128, 0.14));
}
.upload-bar-fill {
  height: 100%; width: 0; background: var(--rb-accent);
  transition: width 0.15s linear;
}
.upload-group { margin-top: 14px; }
.upload-next {
  margin-top: 16px; padding-top: 12px;
  border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.upload-next p { flex: 1 1 100%; margin: 0 0 4px; }

/* Parse-quality flags on a profile. */
.quality-flag { padding: 6px 0; border-bottom: 1px solid var(--border); }
.quality-flag:last-of-type { border-bottom: 0; }

/* A journey the candidate has been taken off. Kept on the record, and marked. */
.journey-removed {
  margin: 6px 0 4px; padding: 6px 10px;
  border-left: 3px solid var(--amber, #c9a227);
  background: var(--rb-panel-2, rgba(128, 128, 128, 0.08));
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

/* --- Live-role matches, inside the Suitability panel --------------------- */
.live-matches { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border); }
.live-match {
  padding: 8px 10px; margin-bottom: 8px;
  border-left: 3px solid var(--rb-accent, #e8863e);
  background: var(--rb-panel-2, rgba(128, 128, 128, 0.06));
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.live-match-role { font-weight: 600; }
.live-match-reason { margin-top: 4px; }
.live-match-no { display: block; margin-top: 4px; }
.live-match-foot {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px;
}
