/**
 * CallWerx
 * Author: Michael Park
 * Date: 2026-09-13
 *
 * Rebranded from "FirstRing" (formerly "Switchboard"). "switchboard-
 * lamp theme" below is a design metaphor (the physical indicator lamps
 * on an old cord board), not a brand-name reference, so it's left as-is
 * through every rename.
 *
 * style.css v2 — the light/modern rebuild, replacing the v1 dark
 * switchboard-lamp theme per direct feedback that it read too DOS-y for
 * a platform meant to feel current. Warm off-white surfaces (not the
 * stock cream-and-terracotta combo), a deep "Bell System" blue accent —
 * grounded in telephone-company heritage rather than a generic SaaS
 * indigo — and status shown as soft tinted pills instead of glowing
 * lamps. Inter carries the whole UI; monospace is reserved specifically
 * for numbers (counters, wait times) so they align cleanly, the one
 * remaining nod to the teleprinter idea, used sparingly rather than
 * everywhere.
 *
 * Added the On-Call Schedule calendar grid (Day/Week/Month + a
 * contacts panel) — see the dedicated section near the end of this file.
 *
 * Added the Reporting view (builder panel + results table) at the end
 * of this file.
 */

:root {
  /* Palette drawn directly from Johnny's new logo (blue \u2192 violet
     gradient: bright blue, through a blue-violet midpoint, to a deep
     violet) \u2014 not a full rebrand of every color in the app, just the
     primary accent + purple family, so it reads as "this app's colors,
     now brand-aligned" rather than a jarring redesign. The background/
     border/text foundation shifts from the previous warm/cream tone to
     a very slight COOL tint instead \u2014 still light and clean (Johnny's
     own framing), just one that actually harmonizes with a blue-violet
     accent rather than clashing against it. */
  --bg: #f7f7fb;
  --surface: #ffffff;
  --border: #e3e1ef;
  --border-soft: #efedf7;
  --text: #1c1b23;
  --text-muted: #6b6875;
  --accent: #5b4fe0; /* the logo's own mid-gradient blue-violet \u2014 vibrant enough to notice, not neon/oversaturated for something used all day */
  --accent-hover: #4a3fc7;
  --accent-pale: #eeecfb; /* light tint of --accent, for hover/selected states that need to feel branded without being loud */
  /* A hard, solid "destructive action" red — deliberately its own thing,
     not reused from --acw-stuck-text/--queue-crit-text (both muted
     status-pill tones meant for soft tinted backgrounds). This one was
     already being used consistently for the softphone hangup button,
     the vault clear-all button, and the disconnected status text, just
     as repeated raw hex instead of a real token like every other color
     in this file. */
  --danger: #c53030;
  --danger-hover: #a82828;
  --dot-idle: #b0aebc; /* the "nobody's doing anything" status dot — no
    existing status color actually matches this lightness (--text-muted
    is noticeably darker/more saturated), so this gets its own token
    instead of forcing a reuse that would visibly darken the dot. */
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  --pending-bg: #fff4e0; --pending-text: #92600b;
  --transfer-bg: #e9f1fb; --transfer-text: #5b4fe0;
  --active-bg: #e9f7ea; --active-text: #1e7a34;
  --wrapup-bg: #fdf1e3; --wrapup-text: #a15c07;
  --queue-warn-bg: #fdf6d8; --queue-warn-text: #8a7209;
  --queue-alert-bg: #fde8d3; --queue-alert-text: #b85c0a;
  --queue-crit-bg: #fbe3e3; --queue-crit-text: #b02a2a;
  --holding-bg: #e6f5f3; --holding-text: #0f5c54;
  --acw-bg: #f3eefb; --acw-text: #5b3e96;
  --acw-stuck-bg: #fdeaea; --acw-stuck-text: #9b2c2c;
  --dispatched-bg: #f1f0ee; --dispatched-text: #5a574f;
  --pinned-bg: #fdeef5; --pinned-text: #b83280; /* light pink, per Johnny's request \u2014 his wife's favorite color and a permanent marker for the first successful AI-Assisted call */
  --sched-armed-bg: #d97706; --sched-armed-bg-hover: #b45309; /* solid orange — a placing-mode indicator needs to actually stand out, unlike the soft status-pill tints elsewhere in this file */
  /* Lightened from the logo's own bold #5b21b6/#7c3aed per Johnny's own
     earlier follow-up (wanted airier, less "in your face"), then
     brought back down slightly after the purple hover treatment got
     extended everywhere in the app — as HOVER TEXT specifically,
     #8b5cf6 didn't have enough contrast against the pale background to
     read comfortably. #7c3aed is the logo's own violet — genuinely
     darker/more legible as text, while still meaningfully lighter than
     the original solid-bar treatment. --purple-light moved lighter in
     turn, to keep a real visual gap between the two now that deep moved
     darker again. */
  --purple-deep: #7c3aed;
  --purple-light: #c4b5fd;
  --purple-pale: #f5f1fd; /* a much-lighter tint of --purple-light — Johnny wanted hover/selected states purple-toned instead of blue, now that groups are purple */
  /* Split out from --purple-deep specifically for solid-background bars
     with white text on top (Directory group headers, etc.) — Johnny
     wants the overall app to read as pastel/soft now, and #7c3aed as a
     solid fill was too bold/"in your face" for that, even though that
     same color works fine as hover TEXT on a light background (a much
     smaller, less dominant use of the color). Still dark enough for
     white text to stay legible, just softer than the bold original. */
  --purple-bar: #a78bfa;
  /* "Currently on call" indicator, specifically tuned for the dark
     purple bar it sits on — the existing --acw-stuck-text/--active-text
     status-pill colors are muted for LIGHT backgrounds and would look
     dull here; these are brighter so "nobody on call" reads as an
     at-a-glance warning and "someone's covering" reads as a clear go. */
  --sched-oncall-none: #ff6b6b;
  --sched-oncall-active: #4ade80;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  min-height: 100vh;
}

/* ---------- Top bar ----------
   Three-column grid (not flex space-between) so the nav sits truly
   centered regardless of how wide the wordmark or the user-info block on
   the right happen to be — a flex approach would center it relative to
   the leftover space between two unequal-width siblings, not the header
   as a whole. */
.topbar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 14px 28px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 10; /* above ordinary page content, but clearly below .modal-bg (50) and context menus (200) — no ambiguous tie */
}
.topbar[hidden] { display: none; } /* .topbar's own `display: grid` (a class selector) otherwise beats the browser's built-in [hidden] rule (a low-specificity attribute selector) — the header kept rendering despite the hidden attribute being correctly present */
.topbar-left {
  display: flex;
  align-items: center;
}
.wordmark {
  font-weight: 600;
  font-size: 20px;
  letter-spacing: -0.01em;
}
/* The ™ on the wordmark — small and muted so it reads as a legal mark,
   not part of the name itself, but present everywhere the brand name
   shows up (topbar + login) since Johnny wants consistent, documented
   use as evidence for a future trademark claim. */
.tm {
  font-size: 0.65em;
  font-weight: 500;
  vertical-align: super;
  color: var(--text);
  margin-left: 2px;
}
.nav {
  display: flex;
  align-items: center;
  gap: 2px;
  justify-self: center;
}
.nav[hidden] { display: none; }
.topbar-right {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 14px;
}
.nav-btn {
  background: none;
  border: none;
  border-radius: 7px;
  color: var(--text-muted);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  padding: 7px 12px;
  cursor: pointer;
}
.nav-btn:hover { background: var(--purple-pale); color: var(--purple-deep); }
.nav-btn.is-active { background: var(--accent); color: #ffffff; }
.nav-btn.is-active:hover { background: var(--accent); color: #ffffff; } /* stays solid on hover too — no lighter flash on the page you're already on */
.nav-gear { padding: 7px 9px; display: inline-flex; align-items: center; }
.nav-gear[hidden] { display: none; }
.connected-indicator {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 500;
}
.connected-indicator[hidden] { display: none; }
.user-label {
  color: var(--text-muted);
  font-size: 13px;
}
.my-status-select {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 13px;
  padding: 5px 8px;
}
.my-status-select[hidden] { display: none; }
.btn-link {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 13px;
  cursor: pointer;
  padding: 0;
}
.btn-link:hover { color: var(--purple-deep); }

/* ---------- Status dots (used only in the roster panel + connected pill) ---------- */
.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}
.dot--idle { background: var(--dot-idle); }
.dot--active { background: var(--active-text); }
.dot--acw { background: var(--acw-text); }
.dot--stuck { background: var(--acw-stuck-text); }

/* ---------- Layout ---------- */
main {
  /* No max-width cap anymore — the fixed-width centered layout was
     leaving huge empty gutters on wider screens (see the screenshot).
     0.75in side margins instead (72px at the standard 96px/in CSS
     reference), so content actually uses the available width rather
     than floating in a fixed-size column regardless of viewport size. */
  padding: 28px 72px 60px;
}
.view[hidden] { display: none; }

/* ---------- Login ---------- */
.login-page {
  min-height: calc(100vh - 88px); /* roughly cancels out main's own top+bottom padding, so this centers in the true full viewport now that the header contributes zero height on this page */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.login-wordmark {
  font-size: 36px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 18px;
  letter-spacing: -0.01em;
}
.login-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 320px;
  width: 100%;
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 28px;
}
.login-title {
  font-size: 18px;
  font-weight: 500;
  margin: 0 0 4px;
}
.login-form label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: var(--text-muted);
}
.login-form input {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 14px;
}
.login-form input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.error-text {
  color: var(--acw-stuck-text);
  font-size: 13px;
  margin: 0;
}

/* ---------- Counters ---------- */
.counters {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 20px;
}
.counter-cell {
  padding: 16px 14px;
  border-left: 1px solid var(--border-soft);
  background: none;
  cursor: default;
  text-align: left;
  font-family: var(--font-sans);
}
.counter-cell:first-child { border-left: none; }
.counter-cell.is-clickable { cursor: pointer; }
.counter-cell.is-clickable:hover { background: var(--purple-pale); color: var(--purple-deep); }
/* Queue tile urgency tiers — 5+/10+/15+ waiting callers, escalating
   "look at me" colors. Applied to the whole cell (background + text)
   same treatment as every other status color in the app, not just the
   number, so it's impossible to miss even glancing quickly. */
.counter-cell.queue-tier-warn { background: var(--queue-warn-bg); color: var(--queue-warn-text); }
.counter-cell.queue-tier-alert { background: var(--queue-alert-bg); color: var(--queue-alert-text); }
.counter-cell.queue-tier-crit { background: var(--queue-crit-bg); color: var(--queue-crit-text); }
.counter-label.is-bold { font-weight: 400; }
.counter-value {
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 500;
  line-height: 1.2;
}
/* Queue tile's value is a combined "N — Waiting M:SS" string, not a bare
   number like the other tiles — matches the app's regular UI font (the
   same one used in the header tabs) instead of the numeric monospace,
   since the monospace treatment reads oddly once the string has an em
   dash and label text mixed in with the digits. */
.counter-value--queue {
  font-family: var(--font-sans);
}
.counter-label {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 4px;
}

/* ---------- Roster panel ---------- */
.roster-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px 18px;
  margin-bottom: 20px;
}
.roster-panel-header {
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 10px;
}
.roster-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-top: 1px solid var(--border-soft);
  font-size: 13px;
}
.roster-row:first-child { border-top: none; }
.roster-name { flex: 1; }
.roster-status {
  font-size: 12px;
  color: var(--text-muted);
}
.roster-row.is-stuck { color: var(--acw-stuck-text); }
.roster-row.is-stuck .roster-status { color: var(--acw-stuck-text); font-weight: 500; }

/* ---------- Queue table ---------- */
.queue-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
.queue-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.queue-table th {
  text-align: left;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.sortable-col { cursor: pointer; user-select: none; }
.sortable-col:hover { color: var(--purple-deep); }
.sortable-col.sorted-asc::after { content: ' \25B4'; }
.sortable-col.sorted-desc::after { content: ' \25BE'; }
.queue-table td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-soft);
  vertical-align: middle;
}
.queue-table tr:last-child td { border-bottom: none; }
/* Scoped by id, not a blanket .queue-table rule — the Settings tables
   (Users/Email Accounts/Signatures/Channels) reuse .queue-table styling
   but their rows aren't click-to-navigate, only their buttons are, so a
   pointer cursor there would be misleading. */
#queue-rows tr, #accounts-rows tr { cursor: pointer; }
#queue-rows tr:hover, #accounts-rows tr:hover { background: var(--purple-pale); }
.queue-table tr.is-stuck { background: var(--acw-stuck-bg); }
/* Email Accounts (4 columns: Account/Email/Status/actions) and
   Signatures (3 columns: Account/Signature/actions) are two separate
   <table> elements that each auto-size their own columns independently
   — different column counts meant "Signature" (2nd of 3) landed at a
   different x-position than "Email" (2nd of 4) directly above it, even
   though both tables' first column is the same "Account" content.
   Pinning that first column to a matching width in both forces every
   later column to start at the same spot regardless of how many total
   columns either table has. */
#email-accounts-rows td:first-child, #email-accounts-body th:first-child,
#signatures-rows td:first-child, #signatures-body th:first-child {
  width: 160px;
}
.channel-label { color: var(--text-muted); font-size: 12px; }
.wait-time { font-family: var(--font-mono); color: var(--text-muted); font-size: 12px; }
.queue-empty {
  padding: 32px 14px;
  text-align: center;
  color: var(--text-muted);
  font-size: 13px;
}

/* ---------- Status pills ---------- */
.status-pill {
  display: inline-block;
  border-radius: 20px;
  padding: 3px 11px;
  font-size: 12px;
  font-weight: 500;
}
.status-pill[hidden] { display: none; }
.status-pill--pending { background: var(--pending-bg); color: var(--pending-text); }
.status-pill--transfer { background: var(--transfer-bg); color: var(--transfer-text); }
.status-pill--active { background: var(--active-bg); color: var(--active-text); }
.status-pill--holding { background: var(--holding-bg); color: var(--holding-text); }
.status-pill--acw { background: var(--acw-bg); color: var(--acw-text); }
.status-pill--acw.is-stuck { background: var(--acw-stuck-bg); color: var(--acw-stuck-text); }
.status-pill--dispatched { background: var(--dispatched-bg); color: var(--dispatched-text); }

/* ---------- Buttons ---------- */
.btn-primary, .btn-secondary, .btn-small {
  border: 1px solid var(--border);
  border-radius: 7px;
  font-family: var(--font-sans);
  font-weight: 500;
  cursor: pointer;
}
.btn-primary:disabled, .btn-secondary:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn-primary:disabled:hover { background: var(--accent); border-color: var(--accent); }
.btn-secondary:disabled:hover { background: var(--surface); }
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
  padding: 10px 18px;
  font-size: 13px;
}
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-secondary {
  background: var(--surface);
  color: var(--text);
  padding: 10px 18px;
  font-size: 13px;
}
.btn-secondary:hover { background: var(--purple-pale); }
.btn-danger {
  border: 1px solid var(--acw-stuck-text);
  border-radius: 7px;
  background: var(--acw-stuck-text);
  color: #ffffff;
  padding: 10px 18px;
  font-size: 13px;
  font-family: var(--font-sans);
  font-weight: 500;
  cursor: pointer;
}
.btn-danger:hover { opacity: 0.88; }
.btn-small {
  background: var(--surface);
  color: var(--accent);
  padding: 6px 12px;
  font-size: 12px;
  border-color: var(--transfer-bg);
}
.btn-small:hover { background: var(--transfer-bg); }

/* ---------- Detail view ---------- */
.back-link { margin-bottom: 14px; display: inline-block; }
.detail-view-topbar .back-link { margin-bottom: 0; }

/* ---------- Account page (greeting + 30/70 Client Info / script split) ----------
   Robert's spec: greeting banner across the top, then a left column with
   reference material (name/address/hours/notes/map) an agent can glance
   at mid-call, and the script + actions on the right. */
.account-greeting {
  background: var(--transfer-bg);
  color: var(--transfer-text);
  border-radius: 10px;
  padding: 14px 18px;
  font-size: 18px;
  font-style: italic;
  font-weight: 600;
  text-align: center;
  margin-top: 28px;
  margin-bottom: 18px;
}
/* Agent Verbiage — Johnny's own request: "smaller versions of our
   current greeting bar" so agents recognize it as the same kind of
   thing on sight (same colors/shape), just visually secondary to the
   actual account greeting above. Left-aligned rather than centered —
   this sits inline in the middle of a script's own field list, not as
   a standalone header the way the top greeting bar is. */
.field-agent-verbiage {
  padding: 8px 14px; /* reduced from 16px \u2014 was 10px 14px padding + margin: 6px 0 combined into one padding value — margin collapses with whatever's adjacent (start of the list, a normal field, nothing at all), which is exactly what was making the gap above and below look inconsistent. Padding never collapses, so this guarantees the same footprint regardless of neighbors. */
  font-size: 14px;
  text-align: left;
  background: none;
  font-style: normal;
}
.account-page {
  display: grid;
  grid-template-columns: 3fr 7fr; /* the 30/70 split, literally */
  gap: 20px;
  align-items: stretch; /* was: start — both columns now match height, whichever is taller (typically the script card at 6-7 fields), so the Client Info card's bottom edge lines up with it instead of ending wherever its own shorter content stops */
}
.account-page-left { display: flex; flex-direction: column; } /* was a plain unstyled div — .account-page-right is an explicit flex column, and that structural mismatch between two supposedly-twin columns is exactly what let their top edges drift apart */
.client-info-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px;
  position: sticky;
  top: 20px; /* stays visible while scrolling a long script — reference material should stay put */
  flex: 1; /* was height:100% — now matches #detail-card's own flex:1 exactly, since both cards are the sole child of a same-structure flex column */
  box-sizing: border-box;
}
.client-info-block { padding: 16px 0; border-top: 1px solid var(--border-soft); }
.client-info-block--first { padding-top: 0; border-top: none; } /* was :first-child, which broke the moment the hamburger button/dropdown were added as earlier siblings in the DOM */
/* Johnny's own request: same font size as the blue greeting bar (18px),
   same all-caps treatment as every other card label in this column, and
   bold — so an agent can confirm at a glance which account's number
   they're actually in, right above the company name itself. */
#client-info-account-number {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text);
  margin-bottom: 12px;
}
/* Corrected hierarchy: the section TITLE (label) is the bold, larger
   element; the info underneath it is lighter and smaller — the reverse
   of an earlier pass, which made the values bold/equal-size instead.
   This also fixes Company Name reading smaller than the rest, since
   every value (h3 included) now shares this exact same lighter style. */
.client-info-label {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--text);
  text-transform: uppercase;
  margin-bottom: 4px;
}
.client-info-card h3,
.client-info-value {
  font-size: 12px;
  font-weight: 400;
  color: var(--text);
  margin: 0;
  white-space: pre-line; /* hours/notes are often multi-line free text */
}
#client-info-map iframe {
  width: 100%;
  height: 300px; /* was 180px — uses the extra vertical room now that this card stretches to match the script card's height */
  border: 0;
  border-radius: 8px;
  margin-top: 14px;
}
.client-info-placeholder {
  color: var(--text-muted);
  font-size: 13px;
  font-style: italic;
}

.detail-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 24px;
  flex: 1; /* fills the remaining height of .account-page-right after the tools row — see that rule below for why this needed a flex column, not just height:100% */
  box-sizing: border-box;
}
/* The right column needs to be a flex column (not just height:100%) so
   .detail-card can fill whatever's LEFT after .account-tools-row's own
   natural height, rather than 100%-ing the WHOLE column and overflowing
   past it. .client-info-card on the left doesn't need this — it's the
   only child of .account-page-left, so plain height:100% already works
   there without a sibling to account for. This was the actual bug
   behind Client Info hanging below the script card: only the left side
   was set up to stretch at all. */
.account-page-right { display: flex; flex-direction: column; }
.account-tools-row { flex-shrink: 0; }
/* Persistent script-management entry point — shown above the script
   card in BOTH live-alert and reference-only modes (admin-tier only),
   since managing a script shouldn't require an active call to get to. */
/* Row holding the (now short) live-status bar and the bigger standalone
   tool buttons side by side — was one single full-width bar; Johnny
   wanted the freed-up space used for Contacts/Message History/Manage
   Script to stand on their own, same height as the status bar. */
.account-tools-row {
  display: flex;
  align-items: stretch;
  gap: 12px;
  margin-bottom: 16px;
}
.live-status-bar {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 18px;
  font-size: 13px;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  white-space: nowrap;
}
.account-tools-group { display: flex; gap: 8px; flex: 1; }
.btn-tool {
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 12px;
  padding: 12px 22px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  color: #ffffff;
  cursor: pointer;
  white-space: nowrap; /* guarantees single-line text regardless of container width — was wrapping inside the old narrower Contacts directory column */
}
.btn-tool:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-tool:disabled { opacity: 0.45; cursor: not-allowed; }
.detail-fields-empty {
  text-align: center;
  padding: 32px 16px;
  color: var(--text-muted);
}
.detail-fields-empty p { margin: 0 0 14px; font-size: 13px; }

/* ---------- Script Builder (modal content) ---------- */
.script-list-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 0;
  border-top: 1px solid var(--border-soft);
}
.script-list-row[draggable="true"] { cursor: grab; }
.script-list-row.dragging { opacity: 0.35; }
.script-list-row:first-child { border-top: none; }
.script-list-name { flex: 1; font-size: 13px; }

/* Contacts modal — two columns, same conceptual split as the account
   page (a directory tree on the left, selected item's details on the
   right), just contained inside a modal instead of a full view. */
.contacts-layout {
  display: grid;
  grid-template-columns: 3fr 7fr; /* was a fixed 200px — proportional 30/70 split gives Directory real room to breathe as the modal itself grows wider */
  gap: 20px;
  min-height: 620px; /* kept in sync with .contacts-detail's own min-height below */
}
.contacts-directory {
  border-right: 1px solid var(--border);
  padding-right: 18px;
  display: flex;
  flex-direction: column;
}
.directory-group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 16px 0 6px;
  background: var(--purple-bar);
  color: #ffffff;
  padding: 7px 10px;
  border-radius: 6px;
}
.directory-group-header:first-child { margin-top: 0; }
.directory-group-label {
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.02em;
  color: #ffffff;
}
.directory-group-actions { display: flex; gap: 2px; }
.directory-group-btn {
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.85);
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 4px;
  line-height: 1;
}
.directory-group-btn:hover { background: rgba(255, 255, 255, 0.18); color: #ffffff; }
.directory-group-btn:disabled { opacity: 0.35; cursor: default; }
.directory-group-btn:disabled:hover { background: none; color: var(--text); }
.directory-contact-item {
  padding: 7px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  color: var(--text);
}
.directory-contact-item[draggable="true"] { cursor: grab; }
.directory-contact-item:hover { background: var(--purple-pale); color: var(--purple-deep); }
.directory-contact-item.is-selected { background: var(--purple-pale); color: var(--purple-deep); font-weight: 500; }
/* Whole group section highlights while a dragged contact is over it —
   not just the header or a single row, since the drop target is the
   group as a whole (including its empty space), not any one contact. */
.directory-group-section.is-drop-target {
  background: var(--purple-pale);
  border-radius: 8px;
  outline: 2px dashed var(--purple-light);
  outline-offset: 2px;
}
.contacts-detail { min-height: 620px; } /* was 480px — too low a guess; a fully populated contact (name/email/method/group/3 phone rows/notes) genuinely needs more room than that, so New Group's fixed minimum still came up short against a real contact view */
.contacts-detail .detail-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.script-list-meta { font-size: 12px; color: var(--text-muted); }
.default-badge {
  display: inline-block;
  background: var(--active-bg);
  color: var(--active-text);
  border-radius: 10px;
  padding: 1px 8px;
  font-size: 12px;
  margin-left: 6px;
}
/* Field rows are drag-and-drop reorderable (native HTML5 DnD, same
   dragstart/dragover/dragleave/drop primitives as TrackIt's existing
   drag-to-reorder pattern). draggable="true" is set in JS per row. */
.script-field-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-top: 1px solid var(--border-soft);
  cursor: grab;
}
.script-field-row:first-child { border-top: none; }
.script-field-row.dragging { opacity: 0.35; }
.script-field-row.drag-over { border-top: 2px solid var(--accent); }
.script-field-drag-handle { color: var(--text-muted); font-size: 14px; user-select: none; }
.script-field-info { flex: 1; min-width: 0; }
.script-field-label { font-size: 13px; font-weight: 500; }
.script-field-meta { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.script-field-type-badge {
  display: inline-block;
  background: var(--transfer-bg);
  color: var(--transfer-text);
  border-radius: 10px;
  padding: 1px 8px;
  font-size: 12px;
  margin-right: 6px;
}
.detail-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-bottom: 16px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.detail-header[hidden] { display: none; }
/* Outbound relay call bar — a fixed, persistent banner rather than a
   modal, since Johnny specifically wants the script/message form to
   stay visible and readable while the agent is talking. Dynamically
   inserted into document.body when a relay call starts, removed when
   it ends — deliberately NOT tied to any one view, since the agent
   could in principle navigate while still on the call. */
.outbound-relay-call-bar {
  position: fixed;
  top: 70px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 40; /* above ordinary content, below modals (50) */
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(28, 27, 25, 0.18);
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-sans);
  font-size: 13px;
}
.outbound-relay-call-bar .orc-status { color: var(--text-muted); }
.outbound-relay-call-bar .orc-name { font-weight: 600; color: var(--text); }
.detail-channel-label {
  font-size: 12px;
  color: var(--text-muted);
}
.detail-header .live-status-bar { margin-left: auto; } /* now the right-most item in the row — was on .detail-channel-label before it moved next to Preview/status */
/* Account actions hamburger — replaces the old always-visible row of
   five separate buttons above the script card, moved here per Johnny's
   own request so that space goes back to the script card instead.
   No extra position rule needed here — .client-info-card's own
   position:sticky (above) already provides a valid anchor for this
   button's position:absolute. A redundant `.client-info-card {
   position: relative; }` was added here earlier and quietly broke
   things: CSS overrides per-property, not per-rule, so it silently
   won over "position: sticky" while leaving the original rule's
   "top: 20px" un-overridden — the card ended up computing as
   "position: relative; top: 20px", genuinely shifting it 20px down
   from its normal position. That's what caused the top-edge mismatch
   against the script card. */
.account-menu-btn {
  position: absolute;
  top: 14px;
  right: 14px;
  height: 32px;
  padding: 0 14px 0 16px;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: var(--accent);
  color: #ffffff;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.account-menu-btn:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
/* Account-search results for IVR menu greetings — a real dropdown card
   (matches .account-menu-dropdown's look) instead of bare rows sitting
   directly on the page background. :not(:empty) keeps it invisible
   until there's actually something to show, so an empty search doesn't
   leave a blank white box floating under the input. */
#ivr-greetings-account-results:not(:empty) {
  margin-top: 6px;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(28, 27, 25, 0.18);
}
/* Matches .settings-section-toggle h2's size/weight (the collapsible
   bar titles just below) instead of falling back to the browser's
   default 16px/400 body text, which read as visually inconsistent
   with the rest of this panel. */
.ivr-greetings-account-result {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 500;
}
.account-menu-dropdown {
  position: absolute;
  top: 50px;
  right: 14px;
  z-index: 20;
  min-width: 180px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(28, 27, 25, 0.18);
  padding: 6px;
}
.field-row {
  display: grid;
  grid-template-columns: 170px 1fr;
  gap: 16px;
  align-items: center;
  padding: 11px 0;
  border-bottom: 1px solid var(--border-soft);
}
.field-row:last-child { border-bottom: none; }
.field-label {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
}
.field-input {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 9px 11px;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 14px;
  width: 100%;
}
.field-input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.field-input.is-manual { border-color: var(--pending-text); }
/* Recipient (send_to) display, not a real input — green when the
   resolved contact is actually ready to be paged (right method, a
   plausible phone/email on file), red when something about it would
   make a real Send/Dial fail. Same color pair as the Active status pill
   / ACW-stuck styling elsewhere, so "ready" and "problem" read
   consistently with the rest of the app rather than introducing a new
   color language just for this. */
.field-send-to-display.recipient-ready { background: var(--active-bg); color: var(--active-text); border-color: var(--active-text); font-weight: 500; }
.field-send-to-display.recipient-problem { background: var(--acw-stuck-bg); color: var(--acw-stuck-text); border-color: var(--acw-stuck-text); font-weight: 500; }
.field-input--textarea { resize: none; font-family: var(--font-sans); line-height: 1.4; } /* fixed 2 rows, not user-draggable — avoids someone accidentally resizing it into growing the whole card */
/* Radio/bubble field group — no shared outer box anymore; each option
   is its own small bordered "bubble" instead of all of them sitting
   together inside one container that looked like a single field. */
.field-radio-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.field-radio-group--horizontal { flex-direction: row; flex-wrap: wrap; gap: 10px; }
.field-radio-option {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  color: var(--text);
  font-weight: 400;
  cursor: pointer;
  margin: 0;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
}
.field-radio-option input[type="radio"] { width: auto; cursor: pointer; }

/* Bubble List / Dropdown options editor — a visible bordered container
   around the rows + "+ Add option" button, matching the contained
   look the old single textarea had. Without this the rows floated
   loose with nothing visually grouping them, which read as "the box is
   gone" once the row-based editor replaced the textarea. */
.choice-options-box {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px;
  background: var(--bg);
}

.dispatch-picker { margin-top: 16px; }
.dispatch-picker label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: var(--text-muted);
  max-width: 280px;
}
.dispatch-picker select {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 9px 11px;
  font-family: var(--font-sans);
  font-size: 14px;
}

.detail-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 22px;
  flex-wrap: nowrap; /* one row by request — see the 720px override below for small screens, where 5 buttons genuinely won't fit */
}
.save-confirm { color: var(--active-text); font-size: 13px; margin-top: 10px; }

/* ---------- Small screens ---------- */
@media (max-width: 720px) {
  .counters { grid-template-columns: repeat(4, 1fr); }
  .counter-cell:nth-child(4n+1) { border-left: none; }
  .account-page { grid-template-columns: 1fr; }
  .client-info-card { position: static; }
  .detail-actions { flex-wrap: wrap; }
}
@media (max-width: 480px) {
  .counters { grid-template-columns: repeat(2, 1fr); }
  .counter-cell:nth-child(2n+1) { border-left: none; }
  .field-row { grid-template-columns: 1fr; gap: 4px; }
  .queue-table { font-size: 12px; }
  .account-page { grid-template-columns: 1fr; }
  .client-info-card { position: static; }
}

/* ---------- Accounts / Settings section headers ---------- */
.view-toolbar { display: flex; justify-content: flex-end; margin-bottom: 28px; }
.view-toolbar--split { justify-content: space-between; align-items: flex-start; }
.view-toolbar--split .softphone-controls { margin-bottom: 0; }
.settings-section-header {
  display: flex;
  justify-content: flex-start; /* was flex-end — moved to match the "+ New account"/"+ New script" left-alignment convention used elsewhere */
  margin-bottom: 12px;
}

/* ---------- Collapsible Settings sections (Users/Outbound Email/
   Signatures/Channels/Account Codes) — all default to collapsed on
   page load; clicking a toggle bar reveals its "+ New X" button and
   table below it. Kept generic (data-target driven, one shared click
   handler in console.js) rather than bespoke per section, since more
   of these will likely get added over time. */
.settings-section { margin-bottom: 12px; }
.settings-section-toggle { cursor: grab; }
.settings-section.dragging { opacity: 0.35; }
.settings-section.drag-over { border-top: 2px solid var(--accent); }
.settings-section-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 20px;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-sans);
}
.settings-section-toggle:hover { background: var(--purple-pale); }
.settings-section-toggle h2 {
  font-size: 14px;
  font-weight: 500;
  margin: 0;
}
.settings-section-chevron {
  color: var(--text-muted);
  font-size: 18px;
  display: inline-block;
  transition: transform 0.15s ease;
}
.settings-section.is-open .settings-section-chevron { transform: rotate(90deg); }
.settings-section-body { padding-top: 12px; }
.settings-section-body[hidden] { display: none; }
/* Admin Outbound's Email/Text/Call row — equal width, starts plain
   white/inactive, and only lights up the standard purple accent for
   whichever methods the currently-selected contact actually has on
   file (see updateAdminOutboundMethodButtons). No contact selected at
   all means all three stay white. */
.admin-outbound-method-row { display: flex; gap: 10px; }
.admin-outbound-method-btn {
  flex: 1;
  padding: 12px 18px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
}
.admin-outbound-method-btn:hover { border-color: var(--purple-light); }
.admin-outbound-method-btn.is-available {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
}
/* "Wrap Up" button (dispatch flow) — was green + "Done", which Johnny
   pointed out reads as already-finished rather than an action you
   still need to take. Orange + "Wrap Up" is the standard telephony
   term for exactly this state (After Call Work), so the label and
   color now both signal "this still needs you" instead of looking
   pre-completed. Only ever shown once Send or Call has actually been
   clicked (see wireDoneButtonReveal) — starts hidden so the flow
   visually guides toward "do something, then wrap up" rather than
   presenting it as an equal option from the very start. */
.btn-wrapup {
  background: var(--wrapup-bg);
  border: 1px solid var(--wrapup-text);
  color: var(--wrapup-text);
  font-weight: 500;
  padding: 10px 18px;
  border-radius: 7px;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: 13px;
}
.btn-wrapup:hover { background: #fbe6cd; }
.btn-wrapup:disabled { opacity: 0.6; cursor: not-allowed; }
/* Tabs within a modal — new pattern, first used on the Account/User edit
   modals now that they're the size of the Schedule modal and have real
   room to organize into groups instead of one long scrolling form. */
.modal-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 20px;
}
.modal-tab-btn {
  padding: 10px 16px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px; /* sits flush over the tab bar's own border-bottom */
}
.modal-tab-btn:hover { background: var(--purple-pale); color: var(--purple-deep); border-radius: 6px 6px 0 0; }
.modal-tab-btn.is-active { color: var(--accent); border-bottom-color: var(--accent); }
/* Stacks every tab's content in the same grid cell — grid sizing takes
   the LARGEST item sharing a cell, so the wrapper is always exactly as
   tall as the tallest tab (Contact Info, currently) regardless of
   which one is actually showing. That's what locks the modal's size
   instead of it shrinking to fit whatever's active — visibility:hidden
   (not display:none) is what keeps inactive tabs contributing to that
   sizing while still being invisible and unclickable. */
.modal-tab-content-wrap { display: grid; }
.modal-tab-content {
  grid-column: 1;
  grid-row: 1;
  visibility: hidden;
  pointer-events: none;
}
.modal-tab-content.is-active {
  visibility: visible;
  pointer-events: auto;
}

/* Greetings page specifically — NOT the shared .reporting-layout grid
   used on Reporting/Billing (that one caused a real overlap bug here:
   explicit CSS Grid row placement means both columns share row TRACKS,
   so a short item in one column can get squeezed into the same row
   height as a tall item in the other column, and the next row starts
   before the tall one actually finished). Two independent flex columns
   instead — each one just stacks its own content top-to-bottom with no
   cross-column row coupling at all, so this can't happen by construction. */
.greetings-layout { display: flex; gap: 24px; align-items: flex-start; }
.greetings-layout-col { display: flex; flex-direction: column; gap: 24px; flex: 1; min-width: 0; }
.greetings-layout-col.is-narrow { flex: 0 0 340px; }
/* .reporting-builder's own position:sticky (meant for the original
   Reporting/Billing pages, where a builder form stays visible while
   scrolling a long results list beside it) doesn't fit here — these are
   two independent, self-contained input panels, not "reference form +
   long scrolling list." Worse, with TWO sticky panels stacked in the
   same column, the second one catches up and visually slides over the
   first as the page scrolls. Reset to normal flow, scoped to just this
   page's own layout. */
.greetings-layout-col .reporting-builder { position: static; }

/* Reuses .queue-table styling (already established) for every settings/
   accounts table — same visual language throughout the app rather than
   introducing a second table style. */
.actions-cell { display: flex; gap: 6px; justify-content: flex-start; }
/* justify-content: flex-start (not flex-end) so the FIRST button in the
   group — Edit, or Set up — always starts at the same x position
   whether or not a second button (Disable/Delete/Remove) follows it in
   that particular row. Right-aligning meant a lone "Edit" (no Disable)
   sat flush against the far right edge, visibly further right than an
   "Edit Disable" pair's Edit button in the row above/below it. */
/* Scripts tab specifically wants its (5-button) action group centered
   in the remaining space rather than left-anchored — scoped narrowly so
   Settings' flex-start convention above is untouched. */
#scripts-view .actions-cell { justify-content: center; }
/* Users/Outbound Email/Signatures/Channels all get a fixed-width
   trailing actions column so their Edit/Delete/Set up/Remove buttons
   line up at the same right-edge position across separate <table>
   elements — without this, each table's own auto column-sizing
   (browser default) lands the actions column at a different x-position
   depending on that table's other column content. */
.actions-col { width: 190px; }
/* Scoped to Settings specifically (not Dashboard/Accounts, which weren't
   part of this complaint) — table-layout: fixed makes .actions-col's
   width AUTHORITATIVE instead of a mere hint. Under the default `auto`
   layout, a width on one column is just a suggestion the browser can
   override based on that table's OTHER column content — which is
   exactly why five separate tables with five different column shapes
   never actually lined up at 190px consistently even though they all
   had the same class. Fixed layout removes that per-table guesswork. */
#settings-view .queue-table { table-layout: fixed; }
.icon-btn {
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 5px 10px;
  font-size: 12px;
  color: var(--text);
  cursor: pointer;
  font-family: var(--font-sans);
}
.icon-btn:hover { background: var(--purple-pale); }
.icon-btn.danger { color: var(--acw-stuck-text); border-color: var(--acw-stuck-bg); }
.icon-btn.danger:hover { background: var(--acw-stuck-bg); }
.sig-preview {
  max-width: 320px;
  font-size: 13px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- Modal system ----------
   Didn't exist before this session — everything up to now was inline in
   the detail view. Same shape as TrackIt's modal-bg/modal: a dimmed
   full-screen backdrop, a centered card, Cancel/Save actions. */
.modal-bg {
  position: fixed;
  inset: 0;
  background: rgba(28, 27, 25, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 50;
}
.modal {
  background: var(--surface);
  border-radius: 12px;
  width: 100%;
  max-width: 440px;
  max-height: 90vh; /* the real, total cap now — was previously only on .modal-scroll independently, which could let scroll+footer TOGETHER exceed the viewport on shorter screens once a footer is added */
  overflow: hidden; /* clips .modal-scroll's content to the rounded corners, including the scrollbar itself */
  position: relative; /* anchors the themed-confirm overlay below, regardless of which modal size variant is open */
  display: flex;
  flex-direction: column;
}
.modal-scroll {
  padding: 24px;
  flex: 1 1 auto;
  min-height: 0; /* the actual fix — without this, a flex child won't shrink below its content's natural height, defeating the whole point of giving the footer guaranteed room */
  overflow-y: auto;
}
/* Wider variant — used by the Account modal, which is growing a lot of
   fields ("a handful of settings to each one"). Reflows sideways instead
   of getting taller: see .modal-grid below. Other modals (User, Email
   Account, Signature, Channel) stay at the narrower default width. */
.modal.modal--wide { max-width: 720px; }
.modal.modal--xwide { max-width: 960px; } /* Contacts specifically — the directory needs more breathing room than the standard wide modal gives */
/* Message Vault specifically — sized relative to the viewport rather
   than a fixed px guess, since Johnny tests on a taller/wider display
   than most agents will actually have. min(1400px, 92vw) means it
   scales down gracefully on a smaller screen instead of overflowing,
   and won't balloon absurdly on an ultrawide monitor either. Height is
   FIXED (not just capped) at 85vh, matching roughly how tall an
   expanded message makes it — so opening/closing a message's inline
   detail no longer visibly grows or shrinks the modal itself, only the
   list scrolls within an already-reserved, constant-size frame. */
/* display:flex + fixed height here (rather than the fixed height living
   on .modal-scroll alone, as before) is specifically to make room for
   .modal-footer below: .modal-scroll now flexes to fill whatever's left
   after the footer's natural height, so the footer sits fixed at the
   bottom of the box instead of scrolling away with the message list.
   The overall box is still pinned to 85vh regardless of content, same
   "reserve the space up front" intent as before. */
.modal.modal--xxwide {
  max-width: min(1400px, 92vw);
  height: 85vh;
  display: flex;
  flex-direction: column;
}
.modal.modal--xxwide .modal-scroll {
  flex: 1 1 auto;
  min-height: 0; /* without this a flex child won't shrink below its content size, and the list would push the footer off the bottom instead of scrolling internally */
  height: auto;
  max-height: none;
}
/* Sits outside .modal-scroll (see openModal's optional footerHtml param)
   so it never scrolls with the modal's content — used by Message Vault
   so Close/Back are always reachable without scrolling past the message
   list, instead of trailing after the last row like a piece of content. */
.modal-footer {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  padding: 14px 24px;
  border-top: 1px solid var(--border);
  flex: 0 0 auto;
}
/* Back (when shown) sits on the left, Close stays pinned right either
   way — matches every other modal's Cancel/Close-on-the-right
   convention instead of Close jumping around based on Back's visibility. */
/* #vault-back-btn's own margin-right:auto was removed — that was for
   the OLD layout, where Close sat on the right and Back needed to pull
   itself left, away from it. Now Close itself carries margin-right:auto
   (see the conditional inline style where this button is generated in
   console.js), so Back just follows normally right after it instead of
   the two auto-margins fighting each other. */
.modal.modal--schedule { max-width: 1360px; max-height: 92vh; } /* On-Call Schedule — Week view's 7 columns + the contacts panel need real width; taller cap (was the shared 85vh, now also lifted from .modal-scroll to the outer .modal now that .modal-scroll flexes to fill whatever the footer leaves) so more of the grid is visible before it has to scroll internally */
.modal-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 20px;
}
.modal-grid .modal-field--full { grid-column: 1 / -1; }
@media (max-width: 600px) {
  .modal-grid { grid-template-columns: 1fr; } /* narrow screens: fall back to one column */
}
.modal h3 {
  font-size: 16px;
  font-weight: 500;
  margin: 0 0 18px;
}
.modal-field { margin-bottom: 14px; }
.modal-field label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 5px;
}
.modal-field input, .modal-field select, .modal-field textarea {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 9px 11px;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text);
}
/* Selects specifically need more right padding than text inputs — the
   native dropdown arrow otherwise sits crammed right against the edge
   with barely any breathing room, since the same 11px right padding
   used for plain text was never enough space for the arrow itself. */
.modal-field select, select.field-input, .dispatch-picker select {
  padding-right: 30px;
}
.modal-hint { font-size: 12px; color: var(--text-muted); margin-top: 5px; }

/* Rich-text formatting toolbar for field Labels and Agent Verbiage text
   — a plain, dependency-free contenteditable + execCommand setup, not
   a full editor widget. */
.rich-text-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 2px;
  margin-bottom: 6px;
  padding: 4px 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  width: fit-content;
  max-width: 100%;
}
.rich-text-divider {
  width: 1px;
  height: 20px;
  background: var(--border);
  margin: 0 4px;
  flex-shrink: 0;
}
.rich-text-btn {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 5px;
  background: none;
  color: var(--text-muted);
  font-size: 13px;
  font-family: var(--font-sans);
  cursor: pointer;
}
.rich-text-btn:hover { background: var(--border-soft); color: var(--text); }
.rich-text-btn.is-active { background: var(--accent-pale); color: var(--accent); }
.rich-text-btn sub { font-size: 11px; }
select.rich-text-size {
  height: 28px;
  flex-shrink: 0;
  width: 84px; /* was sizing to content and clipping "Size…" — fixed, comfortable width instead */
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface);
  font-size: 12px;
  font-family: var(--font-sans);
  color: var(--text);
  padding: 0 4px;
}
.rich-text-color-wrap { position: relative; flex-shrink: 0; }
.rich-text-color-btn {
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 5px;
  background: none;
  font-weight: 700;
  font-size: 13px;
  font-family: var(--font-sans);
  color: var(--text-muted);
  cursor: pointer;
}
.rich-text-color-btn:hover { background: var(--border-soft); color: var(--text); }
.rich-text-color-popover[hidden] { display: none; }
.rich-text-color-popover {
  position: absolute;
  top: 34px;
  left: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: repeat(7, 22px);
  gap: 4px;
  padding: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
}
.rich-text-swatch {
  width: 22px;
  height: 22px;
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  padding: 0;
  cursor: pointer;
}
.rich-text-swatch:hover { transform: scale(1.12); }
.rich-text-editor {
  width: 100%;
  min-height: 38px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 9px 11px;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text);
}
.rich-text-editor:focus { outline: none; border-color: var(--accent); }
.rich-text-editor--tall { min-height: 76px; } /* roughly matches the old 3-row textarea it replaced */
/* Native placeholder text only applies to inputs/textareas, not
   contenteditable — this fakes the same look for an empty editor. */
.rich-text-editor:empty::before {
  content: attr(data-placeholder);
  color: var(--text-muted);
}
.modal-checkbox-group {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.modal-checkbox-group label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text);
  font-weight: 400;
  margin: 0;
  cursor: pointer;
}
.modal-checkbox-group input[type="checkbox"] { width: auto; }
/* Qualified with the element type (not just the class) so this ties
   .modal-field label's specificity instead of losing to it — these rows
   are <label> elements nested inside a .modal-field (via the accounts
   list div), so the plain class-only selector was being beaten by that
   more-specific rule, silently forcing display:block and throwing off
   the checkbox/text vertical alignment despite align-items: center
   being set right here. */
label.greeting-account-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  text-align: left;
}
.greeting-account-row input[type="checkbox"] { flex-shrink: 0; width: auto; margin: 0; }
.greeting-account-row span { text-align: left; }
/* Same .modal-field-nested-label issue as above, plus these checkboxes
   were also inheriting the generic .modal-field input's width: 100% —
   harmless on a text input, but it stretches a checkbox's layout box
   to fill the row and shoves the phone number off to the far right.
   Mirrors .greeting-account-row's exact selector shape below (type +
   attribute selector on the checkbox itself) rather than a bare class,
   since a bare class selector here ties .modal-field input's own
   specificity and LOSES the tie-break by appearing earlier in the file
   — that half-applied fix (flex-shrink:0 with width still 100%) is
   what caused the row to overflow sideways instead of just misalign. */
label.ivr-bulk-line-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
}
.ivr-bulk-line-row input[type="checkbox"] { flex-shrink: 0; width: auto; margin: 0; }
.ivr-bulk-line-row span { text-align: left; }
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}
#sig-editor {
  min-height: 100px;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  font-family: var(--font-sans);
  font-size: 14px;
}
#sig-editor:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ---------- On-Call Schedule (modal content) ----------
   25/75 split — contacts + on-call-now/check panel on the left,
   Day/Week/Month calendar grid on the right. Grid cells are plain divs
   positioned by explicit grid-row/grid-column (see console.js) rather
   than one DOM node per rendered minute, so an hours-long window still
   shows as one solid colored block with one label instead of 48
   repeated text rows. */
.sched-layout {
  display: grid;
  grid-template-columns: 1fr 3fr; /* 25/75 — was 30/70 (3fr 7fr) */
  gap: 20px;
  height: 80vh; /* bumped from 70vh once min-height:0 was actually in
    place everywhere in the chain (see .sched-contacts and .sched-schedule)
    and the bound was genuinely being respected for the first time —
    70vh alone then felt too short, since it had previously only ever
    been a soft, unenforced number. .modal--schedule's own 92vh cap
    leaves enough room above/below this for the header and footer. */
}
.sched-contacts { border-right: 1px solid var(--border); padding-right: 18px; display: flex; flex-direction: column; height: 100%; min-height: 0; }
.sched-oncall-now {
  display: flex;
  flex-direction: column; /* stacked, not the inline row this used to be at the top of the whole modal — narrower now that it lives in the 25% left column */
  align-items: flex-start;
  gap: 6px;
  margin-bottom: 16px;
  margin-top: 0;
  font-size: 13px;
  background: var(--purple-bar);
  color: #ffffff;
  padding: 8px 10px;
  border-radius: 6px;
}
.sched-asof {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  font-size: 12px;
  color: var(--text-muted);
}
.sched-asof label { display: flex; align-items: center; gap: 6px; }
.sched-asof input[type="datetime-local"] {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 6px;
  font-size: 12px;
  font-family: var(--font-sans);
  color: var(--text);
}
#sched-asof-result { font-weight: 500; color: var(--text); }

.sched-contact-item {
  padding: 7px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  color: var(--text);
}
.sched-contact-item:hover { background: var(--purple-pale); color: var(--purple-deep); }
.sched-contact-item.is-armed-source { background: var(--purple-pale); color: var(--purple-deep); font-weight: 500; }
.sched-contact-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.sched-schedule { min-width: 0; min-height: 0; display: flex; flex-direction: column; } /* min-width:0 lets the grid actually shrink inside the CSS grid track instead of overflowing the modal; min-height:0 does the same job vertically. flex column so .sched-grid-scroll below can flex:1 to fill whatever's left after the toolbar, instead of tracking .sched-layout's own height as a separate hardcoded number that has to be kept in sync by hand. */
.sched-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 16px;
  margin-bottom: 12px;
}
.sched-view-toggle {
  display: flex;
  border: 1px solid var(--border);
  border-radius: 7px;
  overflow: hidden;
}
.sched-view-btn {
  background: var(--surface);
  border: none;
  border-right: 1px solid var(--border);
  padding: 6px 14px;
  font-size: 13px;
  font-family: var(--font-sans);
  color: var(--text-muted);
  cursor: pointer;
}
.sched-view-btn:last-child { border-right: none; }
.sched-view-btn:hover { background: var(--purple-pale); color: var(--purple-deep); }
.sched-view-btn.is-active { background: var(--accent); color: #ffffff; }
.sched-nav {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
}
.sched-range-label { font-weight: 500; color: var(--text); min-width: 150px; text-align: center; }
/* Groups Undo, "Delete Selected (N)", and Set Contact together at the
   right edge of the toolbar — Set Contact stays last/rightmost (Johnny
   wanted it to keep its corner spot), with Undo and Delete Selected
   appearing to its LEFT, in that order, only when each is relevant. */
.sched-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
}
.sched-delete-selected-group { display: flex; align-items: center; gap: 4px; }
.sched-delete-selected-group .btn-link { font-size: 18px; line-height: 1; padding: 0 4px; color: var(--text-muted); }
.sched-delete-selected-group .btn-link:hover { color: var(--acw-stuck-text); }

.sched-grid-scroll {
  flex: 1;
  min-height: 0; /* was max-height: 70vh — a second, separately-tracked
    number that had to be manually kept in sync with .sched-layout's own
    height any time either one changed (exactly the kind of drift that
    caused tonight's back-and-forth). flex:1 on a flex-column parent
    means this always fills whatever space is actually left after the
    toolbar above it, with no magic number to maintain at all. */
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.sched-day-headers {
  display: grid;
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.sched-day-header {
  padding: 8px 6px;
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  border-left: 1px solid var(--border-soft);
}
.sched-grid {
  display: grid;
  position: relative;
}
.sched-time-label {
  grid-column: 1;
  font-size: 12px;
  color: var(--text-muted);
  text-align: right;
  padding-right: 8px;
  padding-top: 2px;
  border-right: 1px solid var(--border-soft);
}
.sched-cell {
  border-top: 1px solid var(--border-soft);
  border-left: 1px solid var(--border-soft);
}
.sched-cell.is-shaded { background: var(--bg); } /* light grey zebra, per hour rather than per 30-min slot */
.sched-cell.is-armed { cursor: crosshair; }
.sched-cell.is-armed:hover { background: var(--transfer-bg); } /* "ready to accept" highlight */
.sched-cell.is-painting { background: var(--transfer-bg) !important; }
.sched-entry {
  position: relative;
  margin: 1px 2px;
  border-radius: 5px;
  overflow: hidden;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  background: var(--purple-pale);
}
.sched-entry-slot-label {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  align-items: center;
  padding: 0 6px;
  font-size: 12px;
  font-weight: 500;
  color: var(--purple-deep);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  border-top: 1px solid rgba(255, 255, 255, 0.6); /* faint seam between stacked half-hour slots so a multi-hour window still reads as separate 30-min chunks, not one solid bar */
}
.sched-entry-slot-label:first-child { border-top: none; padding-right: 16px; }
.sched-entry-delete {
  position: absolute;
  top: 2px;
  right: 4px;
  background: none;
  border: none;
  color: var(--purple-deep);
  opacity: 0.55;
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  padding: 0;
}
.sched-entry-delete:hover { opacity: 1; }

/* Month view — vertical day list, same list-row rhythm as the rest of
   the app rather than a true calendar grid (see console.js comment). */
.sched-month-list { display: flex; flex-direction: column; }
.sched-month-row {
  display: flex;
  gap: 16px;
  padding: 10px 12px;
  border-top: 1px solid var(--border-soft);
  cursor: pointer;
}
.sched-month-row:first-child { border-top: none; }
.sched-month-row:hover { background: var(--purple-pale); }
.sched-month-row.is-today { background: var(--active-bg); }
.sched-month-date {
  width: 150px;
  flex-shrink: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.sched-month-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  font-size: 12px;
  color: var(--text);
}
.sched-month-entry { display: inline-flex; align-items: center; gap: 6px; }

/* ---------- On-Call Schedule entry form: custom date/time field ----------
   Replaces a native datetime-local input — its calendar/clock popup is
   OS/browser-rendered, so there's no way to put a "Set" button inside
   it, and clicking outside it to "save" wasn't obvious it worked. No
   toggle/collapse/Set step either — the row is just always live, and
   the form's own Create/Save button reads it directly (see
   getSchedDateTimeLocalValue in console.js). Width overrides below use
   .sched-dt-field-prefixed selectors (two classes) rather than
   !important specifically to out-specificity .modal-field input/select
   { width:100% } — that global rule is what was stretching every one
   of these onto its own full-width row. */
.sched-dt-editor {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.sched-dt-field .sched-dt-date {
  width: 132px;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 7px 8px;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--text);
}

/* Time picker — dropdown-and-flyout style (Johnny's reference: a list
   of hours, click one and it flies out :00/:15/:30/:45 to pick from).
   Kept in 12-hour AM/PM display rather than the 24hr the reference
   happened to use, per the earlier "regular time in the UI" request.
   .sched-time-picker-menu and .sched-time-submenu both use the
   [hidden]/.is-expanded-vs-class-display pattern already established
   elsewhere in this file (see .topbar[hidden]) — flex/block is only
   ever applied for the visible state, never unconditionally. */
.sched-time-picker { position: relative; }
.sched-time-picker-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 7px 10px;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
  min-width: 110px;
  justify-content: space-between;
}
.sched-time-picker-btn:hover { border-color: var(--purple-light); }
.sched-time-picker-caret { color: var(--text-muted); font-size: 12px; }
.sched-time-picker-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 20;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(28, 27, 25, 0.14);
  max-height: 280px;
  overflow-y: auto;
  min-width: 130px;
}
.sched-time-picker-menu[hidden] { display: none; }
.sched-time-hour-row { }
.sched-time-hour-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  background: none;
  border: none;
  padding: 7px 10px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text);
  cursor: pointer;
  text-align: left;
}
.sched-time-hour-btn:hover { background: var(--purple-pale); }
.sched-time-hour-row.is-expanded > .sched-time-hour-btn { background: var(--transfer-bg); color: var(--transfer-text); }
.sched-time-hour-arrow {
  color: var(--text-muted);
  font-size: 12px;
  display: inline-block;
  transition: transform 0.1s ease;
}
.sched-time-hour-row.is-expanded .sched-time-hour-arrow { transform: rotate(90deg); }
/* An inline accordion expansion, NOT a sideways position:absolute
   flyout — .sched-time-picker-menu (the parent list) has
   overflow-y:auto, and per the CSS overflow spec, setting only one
   axis to auto forces the other to clip too. A sideways flyout would
   have been silently cut off by that same scroll container. Expanding
   the quarter-hour options downward, in normal document flow, sidesteps
   the clipping bug entirely instead of fighting it with JS-computed
   fixed positioning. */
.sched-time-submenu { display: none; background: var(--bg); }
.sched-time-hour-row.is-expanded .sched-time-submenu { display: block; }
.sched-time-option {
  display: block;
  width: 100%;
  background: none;
  border: none;
  padding: 6px 10px 6px 28px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text);
  cursor: pointer;
  text-align: left;
}
.sched-time-option:hover { background: var(--purple-pale); }
.sched-time-option.is-selected { background: var(--accent); color: #ffffff; }

/* "Click to Stop Placing" — shown only while a contact is armed for
   painting. Deliberately loud (solid orange, near-full-width) rather
   than a quiet text link: it's the only visible indicator that the
   grid is currently in an active "clicks will place someone" mode, so
   it needs to read as a real button, not a subtle aside. */
.btn-sched-disarm {
  display: block;
  width: 100%;
  margin-top: 12px;
  background: var(--sched-armed-bg);
  color: #ffffff;
  border: none;
  border-radius: 7px;
  padding: 10px 14px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.btn-sched-disarm:hover { background: var(--sched-armed-bg-hover); }

/* ---------- On-Call Schedule: named-schedule switcher ----------
   Sits at the top of the left column, under the modal title. The
   select itself uses the same full-width .modal-field select styling
   as everywhere else in the app — only the row of text-link actions
   underneath it needs its own layout. */
.sched-schedule-picker { margin-bottom: 16px; }
.sched-schedule-picker label {
  font-size: 13px; /* bumped past the generic 12px field-label floor — this reads more like a section header than an ordinary field label */
  font-weight: 600;
  color: var(--text);
}
.sched-schedule-actions {
  display: flex;
  gap: 14px;
  margin-top: 6px;
}

/* ---------- On-Call Schedule: "+ New" as a real button ---------- */
.sched-new-schedule-btn { padding: 5px 12px; font-size: 12px; }

/* ---------- On-Call Schedule: inline New/Rename schedule form ----------
   Replaces what used to be a separate modal — Johnny: too many modals
   gets tedious once things are busy, and there was plenty of room right
   here in the schedule modal's left column to just do it in place. */
.sched-name-inline-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.sched-name-inline-actions {
  display: flex;
  gap: 8px;
}
.sched-name-inline-actions button { flex: 1; padding: 7px 10px; font-size: 12px; }

/* ---------- On-Call Schedule: inline "Set Contact" / edit panel ----------
   A third column (25%) that only appears while active, instead of the
   modal this used to be — same "fewer popups" reasoning as the name
   form above. .sched-layout is 1fr 3fr (25/75) normally; with the panel
   open it becomes roughly 20/55/25 so the grid still gets the majority
   of the width. */
.sched-layout.sched-layout--with-panel { grid-template-columns: 1fr 2.2fr 1fr; }
.sched-entry-panel {
  border-left: 1px solid var(--border);
  padding-left: 18px;
  min-width: 0;
}
.sched-entry-panel-actions {
  display: flex;
  gap: 8px;
  margin-top: 18px;
}
.sched-entry-panel-actions button { flex: 1; }

/* ---------- On-Call Schedule: Notes section (left column) ----------
   Schedule-level running feed — agent-typed notes plus the auto-logged
   "XX modified Schedule Name" lines from server.js, newest first. No
   longer clickable/tied to a specific window (that's what it was
   before) since the auto-log entries are about the SCHEDULE, not one
   interval. Sits at the bottom of the left column, below the contacts
   list, so it doesn't push contacts (the paint-arming targets) down. */
.sched-notes-section {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border-soft);
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0; /* lets the flex child below actually shrink/scroll instead of forcing the column taller */
}
.sched-notes-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.sched-notes-header { font-size: 13px; font-weight: 600; color: var(--text); }
.sched-add-note-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 12px;
}
.sched-add-note-form textarea {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text);
  resize: vertical;
}
.sched-add-note-actions { display: flex; gap: 8px; }
.sched-add-note-actions button { flex: 1; padding: 7px 10px; font-size: 12px; }
.sched-notes-list {
  flex: 1;
  min-height: 60px; /* keeps a sensible minimum when there are very few notes, rather than collapsing to almost nothing */
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  border: 1px solid var(--border);
  border-radius: 8px; /* matches .sched-grid-scroll's own rounded corners, so both scrollable panes in this modal read as the same kind of thing */
  padding: 10px;
}
.sched-note-item {
  background: var(--bg);
  border: 1px solid var(--border-soft);
  border-radius: 7px;
  padding: 8px 10px;
}
.sched-note-item.is-auto { background: transparent; border-style: dashed; } /* auto-logged change lines read lighter than something someone actually typed */
.sched-note-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.sched-note-initials {
  display: inline-block;
  font-weight: 700;
  color: var(--accent);
  margin-right: 4px;
}
.sched-note-text { font-size: 12px; color: var(--text); white-space: pre-wrap; word-break: break-word; flex: 1; }
.sched-note-item.is-auto .sched-note-text { color: var(--text-muted); font-style: italic; }
.sched-note-meta { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.sched-note-delete {
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0 2px;
  flex-shrink: 0;
}
.sched-note-delete:hover { color: var(--acw-stuck-text); }

/* ---------- On-Call Schedule: drag-to-select for delete ----------
   No separate "mode" — whenever nothing's armed for painting (see
   .is-armed), a real drag on the grid highlights in red instead of the
   painting blue, then selects whatever existing intervals it crossed
   on release; a plain click still opens an entry's edit panel. */
.sched-cell.is-select-painting { background: var(--acw-stuck-bg) !important; }
/* Was .sched-entry.is-selected-for-delete (outlined the WHOLE window) —
   moved onto the individual .sched-entry-slot-label rows instead, now
   that drag-select tracks selection per half-hour slot rather than per
   entire entry (see scheduleDeleteSelection's composite keys). Smaller
   negative offset than before since a slot row is much shorter than a
   whole multi-hour block. */
.sched-entry-slot-label.is-selected-for-delete {
  outline: 2px solid var(--acw-stuck-text);
  outline-offset: -1px;
}
.sched-undo-btn { color: var(--accent); font-weight: 500; }

/* ---------- Themed confirm (replaces window.confirm()) ----------
   Absolutely positioned over whichever .modal is currently open (which
   has position:relative set on the base .modal rule) rather than a new
   top-level modal — a contextual card, not another popup. Generic on
   purpose (not schedule-specific despite the class prefix history). */
.themed-confirm-overlay {
  position: absolute;
  inset: 0;
  background: rgba(28, 27, 25, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: inherit;
  z-index: 50;
}
.themed-confirm-card {
  background: var(--surface);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(28, 27, 25, 0.22);
  padding: 20px 22px;
  max-width: 360px;
  width: calc(100% - 48px);
}
.themed-confirm-message { font-size: 14px; color: var(--text); margin: 0 0 18px; line-height: 1.4; }
.themed-confirm-actions { display: flex; gap: 10px; justify-content: flex-end; }

/* ---------- Reporting view ---------- */
.reporting-layout {
  display: grid;
  grid-template-columns: 340px 1fr;
  gap: 24px;
  align-items: start;
}
.reporting-builder {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 20px;
  position: sticky;
  top: 16px;
}
.reporting-builder .btn-primary { width: 100%; margin-top: 4px; }
.report-columns-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--border-soft);
  border-radius: 7px;
  padding: 10px;
}
.report-column-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
  padding: 3px 2px;
  line-height: 1.3;
}
.report-column-check input[type="checkbox"] {
  flex-shrink: 0;
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: var(--accent);
}
.report-filters-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 10px;
}
.report-filter-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  background: var(--bg);
  border: 1px solid var(--border-soft);
  border-radius: 7px;
  padding: 8px;
}
.report-filter-row select,
.report-filter-row input[type="text"],
.report-filter-row input[type="number"],
.report-filter-row input[type="date"] {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 8px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text);
  min-width: 0;
}
.report-filter-column { flex: 1 1 110px; }
.report-filter-op { flex: 0 0 auto; }
.report-filter-value-wrap { display: flex; align-items: center; gap: 6px; flex: 1 1 130px; flex-wrap: wrap; }
.report-filter-value-wrap input, .report-filter-value-wrap select { width: 100%; }
.report-filter-value-a, .report-filter-value-b { flex: 1 1 0; }
.report-filter-and { color: var(--text-muted); font-size: 12px; }
.report-inline-check { display: flex; align-items: center; gap: 4px; font-size: 12px; color: var(--text); white-space: nowrap; }
.report-inline-check input[type="checkbox"] { flex-shrink: 0; width: 14px; height: 14px; margin: 0; accent-color: var(--accent); }
.report-filter-remove {
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0 2px;
  margin-left: auto;
}
.report-filter-remove:hover { color: var(--acw-stuck-text); }
.report-sort-row { display: flex; gap: 8px; }
.report-sort-row select { flex: 1; }

.reporting-results-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.reporting-export-actions { display: flex; gap: 10px; }
.report-results-table-wrap { overflow-x: auto; }
.report-results-table { white-space: nowrap; }
/* Invoice preview — was entirely unstyled browser table defaults, which
   is why the section headers, line items, and message activity block
   all read at different, inconsistent sizes with no deliberate spacing
   rhythm. Explicit type scale, top to bottom: account name 20px, the
   "N calls, N minutes" caption and billing-period line both 12px muted
   (matching .modal-hint elsewhere), section headers 14px bold, line
   items 14px regular, total 15px bold with its own top border, message
   activity 12px throughout (both its own header and body, no longer
   two different ad-hoc sizes stacked on top of each other). */
.invoice-preview-caption { font-size: 12px; color: var(--text-muted); margin: 0 0 14px; }
.invoice-preview-card { max-width: 520px; }
.invoice-preview-account-name { font-size: 18px; font-weight: 700; margin: 0 0 4px; }
.invoice-preview-period { font-size: 12px; color: var(--text-muted); margin: 0 0 18px; }
.invoice-preview-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.invoice-preview-table td { padding: 7px 0; line-height: 1.5; }
.invoice-preview-section-header td { font-size: 14px; font-weight: 700; padding-top: 18px; padding-bottom: 4px; }
.invoice-preview-total td { font-size: 14px; font-weight: 700; padding-top: 12px; border-top: 1px solid var(--border); }
.invoice-preview-message-activity { margin-top: 20px; padding: 12px 14px; background: var(--bg); border-radius: 8px; font-size: 12px; }
.invoice-preview-message-activity-header { font-weight: 700; margin-bottom: 6px; }
.invoice-preview-message-activity-header span { font-weight: 400; color: var(--text-muted); }
.invoice-preview-message-activity-row { color: var(--text-muted); line-height: 1.6; }
.invoice-line-desc-input, .invoice-line-amount-input {
  border: 1px solid transparent;
  background: none;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text);
  padding: 4px 6px;
  border-radius: 5px;
  width: 100%;
}
.invoice-line-amount-input { text-align: right; }
.invoice-line-desc-input:hover, .invoice-line-amount-input:hover { border-color: var(--border); }
.invoice-line-desc-input:focus, .invoice-line-amount-input:focus { border-color: var(--accent); outline: none; background: var(--surface); }
.invoice-line-remove-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 5px;
}
.invoice-line-remove-btn:hover { background: var(--acw-stuck-bg); color: var(--acw-stuck-text); }

/* ---------- Message Vault ----------
   Filters run across the top as one row; the list is full-width below;
   clicking a row expands its detail inline (.vault-row-detail, empty
   until populated) rather than into a separate side panel. */
.vault-filters-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border-soft);
}
.vault-filters-row .modal-field { margin-bottom: 0; }
.vault-filters-row #vault-search { min-width: 220px; }
.vault-bulk-row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 14px;
}
.vault-select-all { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text); cursor: pointer; }
.vault-bulk-actions { display: flex; gap: 10px; margin-left: auto; }

.vault-row-wrap { margin-bottom: 6px; }
.vault-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  cursor: pointer;
  border: 1px solid transparent;
}
.vault-row:hover { background: var(--purple-pale); }
.vault-row.is-expanded { background: var(--purple-pale); border-color: var(--purple-light); }
.vault-row.is-unread { border-left: 3px solid var(--accent); }
.vault-row.is-pinned { background: var(--pinned-bg); border-color: var(--pinned-text); }
.vault-row.is-pinned:hover { background: var(--pinned-bg); }
.vault-row-pin-badge { font-size: 11px; font-weight: 700; color: var(--pinned-text); background: #fff; border: 1px solid var(--pinned-text); border-radius: 999px; padding: 2px 8px; white-space: nowrap; }
.vault-row-checkbox { margin-top: 3px; flex-shrink: 0; width: 15px; height: 15px; }
.vault-row-main { flex: 1; min-width: 0; }
.vault-row-top { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.vault-row-when { margin-left: auto; }
.vault-row-from { font-size: 13px; color: var(--text); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vault-row-phone { font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.vault-row-name { font-size: 13px; color: var(--text); font-weight: 500; white-space: nowrap; }
.vault-row-problem { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
.vault-row-detail {
  padding: 0 12px;
}
.vault-row-detail:not(:empty) {
  padding: 10px 12px;
  margin: 0 0 4px;
  background: var(--bg);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
}
.vault-detail-actions { display: flex; gap: 10px; margin-top: 10px; }
/* Was a plain purple text link; Johnny asked for it to read as an
   actual button, in the same deep-purple-bar treatment as the Directory
   group headers (.directory-group-header/.directory-group-label above),
   not just colored text. */
.vault-inline-back-btn {
  display: inline-flex;
  align-items: center;
  background: var(--purple-bar);
  color: #ffffff;
  border: none;
  font-size: 13px;
  font-weight: 400; /* matches .directory-group-label's unbolded weight */
  letter-spacing: 0.02em;
  cursor: pointer;
  padding: 7px 10px;
  border-radius: 6px;
  margin-bottom: 8px;
}
.vault-inline-back-btn:hover { background: var(--purple-deep); }

/* Deliberately its own, dedicated class set rather than reusing
   .sched-notes-*/.sched-note-* — those need their current, more
   spacious sizing for the Scheduling module's own notes UI, and
   tightening them globally would cramp that unrelated feature. This
   history view genuinely needs to be as vertically compact as
   possible: agents (especially dispatchers) need to see a message's
   fields AND its full history together without scrolling, and a card
   with several field edits could otherwise run long. Each history
   entry is now a single-line flex row (initials · text · timestamp)
   instead of stacking the timestamp on its own line below.
*/
.vault-history-section {
  margin-top: 18px;
  padding-top: 10px;
  border-top: 1px solid var(--border-soft);
}
.vault-history-header { font-size: 12px; font-weight: 600; color: var(--text); margin-bottom: 4px; }
.vault-history-list {
  max-height: 200px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.vault-history-item {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 3px 4px;
  font-size: 12px;
  line-height: 1.3;
}
.vault-history-initials { font-weight: 700; color: var(--purple-deep); flex-shrink: 0; }
.vault-history-text { color: var(--text); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vault-history-when { color: var(--text-muted); flex-shrink: 0; font-size: 11px; }

/* Scoped to the Message Vault's own read-only field preview
   specifically — .field-row itself stays at its normal, more spacious
   padding everywhere else (the live, active-call script-fields view
   genuinely needs that breathing room for actual data entry). This view
   is read-only/reference, not active typing, so a tighter layout here
   is a real, safe win rather than a compromise. */
#vault-fields .field-row { padding: 5px 0; }

/* ---------- Message Vault: right-click context menu ----------
   Not the browser's native context menu (contextmenu is prevented) —
   a small themed one, positioned at the cursor, appended to
   document.body since it needs to render outside the modal's own
   overflow/stacking context. */
.vault-context-menu {
  position: absolute;
  z-index: 200;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(28, 27, 25, 0.18);
  overflow: hidden;
  min-width: 180px;
}
.vault-context-menu-item {
  display: block;
  width: 100%;
  background: none;
  border: none;
  text-align: left;
  padding: 9px 14px;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}
.vault-context-menu-item:hover { background: var(--purple-pale); color: var(--purple-deep); }

.detail-view-topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}
.detail-view-topbar .softphone-controls { margin-bottom: 0; }

.softphone-controls {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 14px;
  margin-bottom: 28px;
  font-size: 13px;
}
.softphone-controls-status { color: var(--text-muted); }
.softphone-controls-status .softphone-status-value { font-weight: 700; }
.softphone-controls-status .softphone-status-value.is-connected { color: #1a8a4a; }
.softphone-controls-status .softphone-status-value.is-disconnected { color: var(--danger); }
.softphone-supervisor-warning:not([hidden]) {
  color: var(--danger);
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.softphone-supervisor-warning .softphone-supervisor-retry-btn { color: var(--danger); text-decoration: underline; }

/* A gentle, continuous pulse on the incoming-call card itself — Johnny's
   own ask for something "more obvious." A static card, however large,
   is easy to miss from peripheral vision; a slow, soft glow pulsing on
   the shadow keeps subtly drawing the eye for as long as the call rings,
   without being so fast/bright it feels alarming or distracting. */
.softphone-incoming-call-card {
  animation: softphone-incoming-pulse 1.6s ease-in-out infinite;
}
@keyframes softphone-incoming-pulse {
  0%, 100% { box-shadow: 0 30px 90px rgba(0, 0, 0, 0.45), 0 0 0 0 rgba(91, 79, 224, 0.35); }
  50% { box-shadow: 0 30px 90px rgba(0, 0, 0, 0.45), 0 0 40px 12px rgba(91, 79, 224, 0.35); }
}

.softphone-controls button {
  font-size: 13px;
  padding: 6px 14px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  cursor: pointer;
}
.softphone-controls button:disabled { opacity: 0.4; cursor: default; }
.softphone-controls .btn-softphone-hangup { color: #fff; background: var(--danger); border-color: var(--danger); }
.vault-clear-danger-btn { color: #fff; background: var(--danger); border-color: var(--danger); }
.vault-clear-danger-btn:hover { background: var(--danger-hover); border-color: var(--danger-hover); }
.softphone-controls .btn-softphone-mute.is-muted { background: var(--bg); border-color: var(--accent); color: var(--accent); }
.softphone-controls .btn-softphone-hold.is-on-hold { background: var(--holding-bg); border-color: var(--holding-text); color: var(--holding-text); }
.softphone-controls button:hover:not(:disabled) { background: var(--purple-pale); border-color: var(--purple-light); }
.softphone-controls .btn-softphone-hangup:hover:not(:disabled) { background: var(--danger-hover); border-color: var(--danger-hover); }
.softphone-ready-status {
  font-size: 13px;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  cursor: pointer;
}
/* A subtle green tint specifically for Ready — the one state genuinely
   worth noticing at a glance among the four, since it's the only one
   that actually determines whether this agent can be routed a call.
   Toggled via JS (see updateSoftphoneControlsUI), not a CSS :has()
   selector — :has(option:checked) is genuinely unreliable across
   browsers for a closed/collapsed <select>. */
.softphone-ready-status.is-ready {
  background: var(--active-bg);
  border-color: var(--active-text);
  color: var(--active-text);
  font-weight: 600;
}
/* color/font-weight on a <select> are inherited by its <option> children
   by default — without this, setting the closed select's text green for
   "Ready" also turned every option green inside the open dropdown list,
   not just the selected one. Options always render in normal weight/color
   regardless of the select's own current-value styling. */
.softphone-ready-status.is-ready option {
  color: var(--text);
  font-weight: 400;
  background: var(--surface);
}
