/* freeDMS — minimal, dependency-free stylesheet (low overhead, no CDN). */
:root {
  --bg: #f4f6f8;
  --panel: #ffffff;
  --ink: #1f2933;
  --muted: #647280;
  --line: #dfe4ea;
  --brand: #1f6feb;
  --brand-dark: #1457c4;
  --crm: #16a34a;
  --ok: #137a52;
  --warn: #9a6700;
  --err: #b42318;
  --radius: 10px;
  /* Report-chart categorical palette (static/js/report-chart.js). The order
     is the colorblind-safety mechanism (adjacent pairs validated) — never
     re-shuffle or insert hues. Slots 3/4/5 sit under 3:1 on white, which is
     allowed because the result table always renders beside the chart. */
  --chart-1: #2a78d6;
  --chart-2: #eb6834;
  --chart-3: #1baf7a;
  --chart-4: #eda100;
  --chart-5: #e87ba4;
  --chart-6: #008300;
  --chart-7: #4a3aa7;
  --chart-8: #e34948;
  /* Real height of the sticky .topbar, measured by base.html so in-page
     sticky rails can offset themselves below it. 0 on pages without a
     topbar (sign-in, external portals). */
  --topbar-h: 0px;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font: 15px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* Top bar — sticky, so the header and its shortcuts survive scrolling.
   z-index sits above the in-page sticky rails (≤20) but below the floating
   tray (950), context menus (3000) and tour overlay (5000). */
.topbar {
  display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap;
  background: var(--panel); border-bottom: 1px solid var(--line);
  padding: 0 1.25rem; min-height: 56px;
  position: sticky; top: 0; z-index: 100;
}
.brand { display: flex; align-items: center; gap: .4rem; text-decoration: none; color: var(--ink); font-size: 1.1rem; }
.brand-mark {
  display: inline-grid; place-items: center; width: 26px; height: 26px;
  background: var(--brand); color: #fff; border-radius: 7px;
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic; font-weight: 700; line-height: 1;
}
.brand-word { font-weight: 600; letter-spacing: -.01em; }
/* freeCRM section: green app icon (set in base.html when in the CRM module). */
.brand-crm .brand-mark { background: var(--crm); }
.auth-brand .brand-word { font-weight: 600; }
.navwrap { display: flex; flex: 1; align-items: center; justify-content: space-between; gap: 1rem; }
.mainnav { display: flex; gap: .25rem; flex-wrap: wrap; }
.mainnav a { text-decoration: none; color: var(--muted); padding: .4rem .6rem; border-radius: 7px; white-space: nowrap; }
.mainnav a:hover { background: var(--bg); color: var(--ink); }
.usermenu { display: flex; align-items: center; gap: .9rem; }
.usermenu a { color: var(--muted); text-decoration: none; white-space: nowrap; }
.usermenu a:hover { color: var(--ink); }
.inline { display: inline; margin: 0; }
.linkbtn { background: none; border: none; color: var(--muted); cursor: pointer; font: inherit; padding: 0; }
.linkbtn:hover { color: var(--err); }
/* Personal-action badge over the topbar avatar (base.html): something waits
   on the user themselves — the count floats on the 👤 like an app icon badge. */
.avatar-wrap { position: relative; display: inline-block; }
.avatar-badge { position: absolute; top: -.55em; right: -.7em; margin-left: 0;
  vertical-align: baseline; }

/* Masquerade (docs/MASQUERADE.md): black mask icon in the user menu + the
   amber always-on banner shown while an admin drives another user's view. */
.masq-link { display: inline-flex; align-items: center; color: var(--ink); }
.masq-link:hover { color: var(--brand); }
.masq-icon { display: block; }
.masq-banner {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  background: #fff3cd; border-bottom: 1px solid #f0c36d; color: #7a5200;
  padding: .4rem 1.25rem; font-size: .92rem;
}
.masq-banner strong { color: #5c3d00; }
.masq-banner .masq-exit { margin-left: auto; }
.masq-banner .btn { padding: .2rem .6rem; font-size: .82rem; background: #fffaf0;
  border-color: #f0c36d; color: #7a5200; }
.masq-banner .btn:hover { background: #ffe9a8; }
.masq-form .option-input { max-width: 24rem; width: 100%; }

/* Hamburger toggle (shown on mobile only; CSS-only via the checkbox hack) */
.nav-toggle { display: none; }
.nav-burger { display: none; cursor: pointer; user-select: none; margin-left: auto;
  padding: .5rem; border-radius: 8px; }
.nav-burger:hover { background: var(--bg); }
.nav-burger-bar, .nav-burger-bar::before, .nav-burger-bar::after {
  content: ""; display: block; width: 22px; height: 2px; background: var(--ink);
  border-radius: 2px; transition: transform .15s, opacity .15s;
}
.nav-burger-bar { position: relative; }
.nav-burger-bar::before { position: absolute; top: -7px; }
.nav-burger-bar::after { position: absolute; top: 7px; }

/* Layout */
.content { flex: 1; width: 100%; max-width: 1100px; margin: 0 auto; padding: 1.5rem 1.25rem; }
.footer {
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  border-top: 1px solid var(--line); padding: .75rem 1.25rem; color: var(--muted); font-size: .85rem;
}
.page-header { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; margin-bottom: 1.25rem; flex-wrap: wrap; }
.page-header h1 { margin: 0; font-size: 1.5rem; }
.subtitle { margin: .25rem 0 0; color: var(--muted); }
/* Pronunciation line under a contact's name (freecrm/_phonetic_name.html):
   ▶ clip playback + "Sounds like …", plus an inline record/dictate editor.
   The form keeps its input compact (inputs are width:100% by default). */
.phonetic-name { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin: .25rem 0 0; font-size: .9rem; }
.phonetic-form { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.phonetic-form input[name=phonetic_name] { width: auto; flex: 0 1 16rem; min-width: 10rem; }
.phonetic-hint, .phonetic-status, .phonetic-suggested { flex-basis: 100%; }
.phonetic-suggested { color: var(--ok); }
.phonetic-record { white-space: nowrap; }
.phonetic-mic.listening, .phonetic-record.listening { border-color: var(--err); color: var(--err); animation: ai-pulse 1.2s ease-in-out infinite; }
/* Section header: a section title with an action (e.g. "New") aligned to the right. */
.section-header { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; flex-wrap: wrap; margin: 1.5rem 0 .75rem; }
.section-header h2 { margin: 0; }

/* Cards */
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 1rem; }
/* On the full-width CRM landing, keep the KPI card band a comfortable width and
   centered instead of stretched/left-justified across the whole viewport. */
.card-grid-center { max-width: 1100px; margin-inline: auto; }
.card { display: block; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.1rem; text-decoration: none; color: var(--ink); transition: border-color .15s, transform .15s; }
.card:hover { border-color: var(--brand); transform: translateY(-2px); }
.card-icon { font-size: 1.6rem; }
.card h2 { margin: .4rem 0 .25rem; font-size: 1.05rem; }
.card p { margin: 0; color: var(--muted); font-size: .9rem; }

/* Panels & detail lists */
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.25rem; }
.detail-list { display: grid; grid-template-columns: 180px 1fr; gap: .5rem 1rem; margin: 0 0 1rem; }
.detail-list dt { color: var(--muted); }
.detail-list dd { margin: 0; }

/* Tables */
.data-table { width: 100%; border-collapse: collapse; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.data-table th, .data-table td { text-align: left; padding: .6rem .75rem; border-bottom: 1px solid var(--line); }
.data-table th { background: #fafbfc; color: var(--muted); font-weight: 600; font-size: .8rem; text-transform: uppercase; letter-spacing: .02em; }
.data-table tr:last-child td { border-bottom: none; }
/* Bulk edit (document list): tight checkbox column + the action bar above the table. */
.data-table .col-check { width: 2rem; text-align: center; }
.bulk-bar { display: flex; align-items: center; gap: .6rem; margin-bottom: .5rem; }
/* Sortable column headers keep the plain header look (arrow marks the active sort). */
.data-table th a.th-sort { color: inherit; text-decoration: none; }
.data-table th a.th-sort:hover { color: var(--ink); }

/* Forms / buttons */
input, select, textarea { font: inherit; padding: .5rem .6rem; border: 1px solid var(--line); border-radius: 8px; width: 100%; background: #fff; }
/* Radios & checkboxes keep their native size — the full-width rule above is for
   text inputs and would otherwise stretch them away from their labels. */
input[type=radio], input[type=checkbox] { width: auto; padding: 0; }
/* File pickers stay natural-width so the "or drop file here" pill sits beside them. */
input[type=file] { width: auto; max-width: 100%; }
.filterbar { display: flex; gap: .5rem; margin-bottom: 1rem; flex-wrap: wrap; }
.filterbar input { width: auto; flex: 1; min-width: 160px; }
/* Below-the-table switches (e.g. the accounts list's "Include archived?") */
.list-footer { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap;
  margin-top: 1rem; padding-top: .8rem; border-top: 1px solid var(--line); font-size: .9rem; }
.list-footer label { display: flex; gap: .4rem; align-items: center; cursor: pointer; }
.list-footer input[type=checkbox] { width: auto; flex: 0 0 auto; margin: 0; }
.list-footer .note { color: var(--muted); }
.btn { display: inline-block; padding: .5rem .9rem; border: 1px solid var(--line); border-radius: 8px; background: #fff; color: var(--ink); text-decoration: none; cursor: pointer; }
.btn:hover { border-color: var(--brand); }
.btn-primary { background: var(--brand); border-color: var(--brand); color: #fff; }
.btn-primary:hover { background: var(--brand-dark); }
.btn-sm { padding: .3rem .7rem; font-size: .85rem; }
/* `.btn`'s display would otherwise override the UA `[hidden]` rule, leaving a
   button with the `hidden` attribute visible (cf. `.ai-panel[hidden]`). */
.btn[hidden] { display: none; }
/* A disabled Run must look dead, not just swallow the click silently. */
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn:disabled:hover { border-color: var(--line); }

/* Stacked form fields (label above control) + decision radio group */
.field { margin: 0 0 1rem; }
.field > label, .field-label { display: block; margin: 0 0 .3rem; font-size: .85rem; color: var(--muted); }
.field-hint { margin: .3rem 0 0; font-size: .8rem; color: var(--muted); }
.field-error { margin: .3rem 0 0; font-size: .82rem; color: var(--err); }
.radio-group label { display: flex; align-items: center; gap: .45rem; padding: .2rem 0; cursor: pointer; }
.radio-group input[type=radio] { flex: 0 0 auto; }

/* Modal confirmation dialog (e.g. the signing manifestation shown on approval) */
dialog.sign-dialog { max-width: 380px; width: calc(100% - 2rem); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.5rem; box-shadow: 0 10px 40px rgba(0,0,0,.2); color: var(--ink); }
dialog.sign-dialog::backdrop { background: rgba(15,23,42,.45); }
dialog.sign-dialog h2 { margin: 0 0 .5rem; font-size: 1.15rem; }
dialog.sign-dialog label { display: block; margin: .75rem 0 .25rem; font-size: .85rem; color: var(--muted); }
dialog.sign-dialog .dialog-actions { display: flex; gap: .5rem; justify-content: flex-end; margin-top: 1.25rem; }

/* Generic "Are you sure?" modal — sits inside the form it guards, so its own
   submit button is the confirmation (e.g. archiving a CRM account). */
dialog.confirm-dialog { max-width: 420px; width: calc(100% - 2rem); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.5rem; box-shadow: 0 10px 40px rgba(0,0,0,.2); color: var(--ink); }
dialog.confirm-dialog::backdrop { background: rgba(15,23,42,.45); }
dialog.confirm-dialog h2 { margin: 0 0 .5rem; font-size: 1.15rem; }
dialog.confirm-dialog p { margin: 0 0 .5rem; }
dialog.confirm-dialog .dialog-actions { display: flex; gap: .5rem; justify-content: flex-end; margin-top: 1.25rem; }

/* Badges & states */
.badge { display: inline-block; padding: .1rem .5rem; margin: 0 .2rem .2rem 0; background: #eef2f7; border-radius: 999px; font-size: .78rem; color: var(--muted); }
.empty-state { text-align: center; color: var(--muted); padding: 2rem 1rem; }

/* Messages */
.messages { list-style: none; padding: 0; margin: 0 0 1rem; }
.msg { padding: .6rem .9rem; border-radius: 8px; margin-bottom: .5rem; border: 1px solid var(--line); }
.msg-success { background: #e7f6ee; border-color: #b6e3ca; color: var(--ok); }
.msg-error, .msg-danger { background: #fdeceb; border-color: #f6c5c0; color: var(--err); }
.msg-warning { background: #fdf6e3; border-color: #f1deb0; color: var(--warn); }
.msg-info { background: #eaf2fd; border-color: #c3dbf8; color: var(--brand-dark); }

/* Auth */
.auth-card { max-width: 380px; margin: 3rem auto; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 2rem; }
.auth-brand { font-size: 1.2rem; margin-bottom: 1rem; display: flex; gap: .4rem; align-items: center; }
.auth-card h1 { margin: 0 0 1rem; font-size: 1.3rem; }
.auth-card label { display: block; margin: .75rem 0 .25rem; font-size: .85rem; color: var(--muted); }
.auth-card .btn { width: 100%; margin-top: 1.25rem; text-align: center; }
.auth-note { margin-top: 1rem; font-size: .8rem; color: var(--muted); }

/* Pagination */
.pagination { display: flex; gap: 1rem; align-items: center; justify-content: center; margin-top: 1.25rem; color: var(--muted); }
.pagination a { color: var(--brand); text-decoration: none; }

/* Lifecycle / status pills (shared vocabulary for feature apps) */
.pill { display: inline-block; padding: .15rem .55rem; border-radius: 999px; font-size: .78rem; font-weight: 600; }
.pill-draft { background: #eef2f7; color: #5b6b7b; }
.pill-in_review, .pill-reviewed { background: #fdf6e3; color: var(--warn); }
.pill-for_approval { background: #eae3fb; color: #6b46c1; }
.pill-approved, .pill-effective { background: #e7f6ee; color: var(--ok); }
.pill-superseded, .pill-obsolete, .pill-archived, .pill-cancelled { background: #f0f1f3; color: var(--muted); }

/* Sentiment chips (account news) — reuse the message colour vocabulary */
.sentiment { display: inline-block; flex: none; padding: .12rem .5rem; border-radius: 999px; font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .02em; }
.sentiment-positive { background: #e7f6ee; color: var(--ok); }
.sentiment-neutral { background: #eef2f7; color: var(--muted); }
.sentiment-negative { background: #fdeceb; color: var(--err); }
/* "Straight from the company" badge on IR/press-sourced news */
.news-company { display: inline-block; flex: none; padding: .12rem .5rem; border-radius: 999px; font-size: .72rem; font-weight: 600; background: #eae3fb; color: #6b46c1; }

/* Account newsfeed (home panel, account page, full feed) */
.news-list { display: flex; flex-direction: column; gap: .9rem; margin: .5rem 0 1rem; }
/* Account headings when System → News orders the feed "grouped by account". */
.news-group-head { font-size: 1.05rem; margin: .6rem 0 -.2rem; }
.news-group-head a { text-decoration: none; }
.news-group-head a:hover { text-decoration: underline; }
/* Auto-scrolling viewport: JS caps the height to a few cards and drives the
   scroll. `scroll-behavior: auto` keeps the seamless loop instant (smooth would
   animate the wrap into a visible spring-back). */
.news-list[data-autoscroll] { overflow-y: auto; scrollbar-width: thin; scroll-behavior: auto; }
.news-item { padding: .75rem .9rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); }
.news-item-head { display: flex; align-items: baseline; gap: .5rem; }
.news-item-title { font-weight: 600; text-decoration: none; color: var(--brand); }
.news-item-title:hover { text-decoration: underline; }
.news-item-meta { margin: .3rem 0 0; font-size: .8rem; color: var(--muted); }
.news-item-meta a { color: var(--brand); text-decoration: none; }
.news-item-summary { margin: .45rem 0 0; font-size: .9rem; line-height: 1.45; }
.news-list-compact .news-item { padding: .55rem .7rem; }
.news-list-compact .news-item-summary { font-size: .85rem; }
.feature-more { font-size: .8rem; color: var(--brand); text-decoration: none; white-space: nowrap; }
.feature-more:hover { text-decoration: underline; }

/* News chyron — a TV-style ticker fixed to the bottom of the CRM home screen
   (FR-CRM-NEWS). Pure-CSS marquee: the item set is rendered twice and the track
   slides 0 → -50%, so it repeats with no seam. Pauses on hover/focus; degrades to
   a static, manually scrollable strip under reduced-motion. body.crm-home (below)
   reserves matching space so the bar never hides the footer or the AI launcher. */
.news-chyron {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  display: flex; align-items: stretch; height: var(--chyron-h, 2.85rem);
  background: var(--panel); border-top: 1px solid var(--line);
  box-shadow: 0 -2px 10px rgba(0, 0, 0, .06);
}
.news-chyron-label {
  display: flex; align-items: center; gap: .35rem; flex: 0 0 auto; padding: 0 .9rem;
  background: var(--crm); color: #fff; font-weight: 700; font-size: .82rem; white-space: nowrap;
}
.news-chyron-viewport {
  flex: 1; position: relative; overflow: hidden;
  /* Fade the headlines in and out at both edges. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
}
.news-chyron-track {
  display: flex; align-items: center; gap: 2.25rem; height: 100%; width: max-content;
  padding-left: 2.25rem; animation: chyron-scroll 60s linear infinite; will-change: transform;
}
.news-chyron:hover .news-chyron-track,
.news-chyron:focus-within .news-chyron-track { animation-play-state: paused; }
@keyframes chyron-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.news-chyron-item {
  display: inline-flex; align-items: center; gap: .5rem; white-space: nowrap;
  text-decoration: none; color: var(--ink); font-size: .88rem;
}
.news-chyron-item:hover .chyron-title { color: var(--crm); text-decoration: underline; }
.chyron-title { font-weight: 600; }
.chyron-src, .chyron-date { color: var(--muted); font-size: .8rem; }
.chyron-src::before, .chyron-date::before { content: "· "; }
.chyron-dot { flex: 0 0 auto; width: .55rem; height: .55rem; border-radius: 50%; background: var(--muted); }
.chyron-positive { background: var(--ok); }
.chyron-neutral { background: var(--muted); }
.chyron-negative { background: var(--err); }
.news-chyron-more {
  flex: 0 0 auto; display: flex; align-items: center; padding: 0 .9rem;
  border-left: 1px solid var(--line); background: var(--panel);
  color: var(--crm); font-weight: 600; font-size: .82rem; white-space: nowrap; text-decoration: none;
}
.news-chyron-more:hover { text-decoration: underline; }
@media (prefers-reduced-motion: reduce) {
  .news-chyron-viewport { overflow-x: auto; scrollbar-width: none; }
  .news-chyron-track { animation: none; }
}
/* Reserve room for the fixed chyron so it never covers the footer, and lift the
   bottom-right AI launcher/panel above the bar. */
body.crm-home { --chyron-h: 2.85rem; padding-bottom: calc(var(--chyron-h) + .35rem); }
body.crm-home #ai-fab-wrap { bottom: calc(1rem + var(--chyron-h)); }
body.crm-home .ai-panel { bottom: calc(4.75rem + var(--chyron-h)); }

/* Wide tables scroll horizontally inside their wrapper (added by base.html JS) */
.table-wrap { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* In-browser document viewer */
.viewer-panel { padding: .5rem; }
.doc-viewer { width: 100%; height: 78vh; border: 1px solid var(--line); border-radius: 8px; background: #fff; }
.doc-viewer-imgwrap { text-align: center; }
.doc-viewer-img { max-width: 100%; max-height: 78vh; border: 1px solid var(--line); border-radius: 8px; }
@media (max-width: 640px) { .doc-viewer { height: 68vh; } }

/* pdf.js canvas viewer (works on mobile + desktop) */
.pdf-toolbar { display: flex; gap: .4rem; align-items: center; margin-bottom: .5rem; }
.pdf-canvas-container {
  max-height: 80vh; overflow: auto; background: #525659; border-radius: 8px;
  padding: .5rem; text-align: center; -webkit-overflow-scrolling: touch;
}
.pdf-canvas-container .pdf-page-wrap {
  position: relative; display: inline-block; margin: 0 auto .5rem; width: 100%;
}
.pdf-canvas-container .pdf-page {
  display: block; width: 100%; height: auto;
  background: #fff; box-shadow: 0 1px 4px rgba(0,0,0,.4);
}
@media (max-width: 640px) { .pdf-canvas-container { max-height: 72vh; } }

/* ======================================================================
   Responsive / mobile
   ====================================================================== */
@media (max-width: 820px) {
  /* Collapse the nav behind the hamburger. */
  .nav-burger { display: block; }
  .navwrap {
    display: none; flex-basis: 100%; order: 3;
    flex-direction: column; align-items: stretch; gap: 0;
    padding-bottom: .5rem;
  }
  .nav-toggle:checked ~ .navwrap { display: flex; }

  /* When open, morph the burger into an X. */
  .nav-toggle:checked ~ .nav-burger .nav-burger-bar { background: transparent; }
  .nav-toggle:checked ~ .nav-burger .nav-burger-bar::before { top: 0; transform: rotate(45deg); }
  .nav-toggle:checked ~ .nav-burger .nav-burger-bar::after { top: 0; transform: rotate(-45deg); }

  .mainnav, .usermenu { flex-direction: column; align-items: stretch; gap: 0; width: 100%; }
  .usermenu { border-top: 1px solid var(--line); margin-top: .35rem; padding-top: .35rem; }
  .mainnav a, .usermenu a, .usermenu .inline { display: block; width: 100%; }
  .mainnav a, .usermenu a, .linkbtn {
    padding: .85rem .5rem; border-radius: 8px; font-size: 1rem; min-height: 44px;
    display: flex; align-items: center; box-sizing: border-box;
  }
  .linkbtn { width: 100%; justify-content: flex-start; }
}

@media (max-width: 640px) {
  .content { padding: 1rem .85rem; }

  /* Page headers: title over full-width actions. */
  .page-header { flex-direction: column; align-items: stretch; }
  .page-header h1 { font-size: 1.3rem; }
  .page-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
  .page-actions .btn, .page-actions form, .page-actions .inline { flex: 1 1 auto; }
  .page-actions .btn { text-align: center; }

  /* Detail lists stack: label above value. */
  .detail-list { grid-template-columns: 1fr; gap: .1rem .5rem; }
  .detail-list dt { margin-top: .6rem; font-weight: 600; color: var(--muted); }
  .detail-list dt:first-child { margin-top: 0; }

  /* Tables keep their columns and scroll sideways rather than squashing. */
  .data-table th, .data-table td { white-space: nowrap; }

  /* Filter bars and inline action forms stack to full width. */
  .filterbar { flex-direction: column; align-items: stretch; }
  .filterbar input, .filterbar select, .filterbar .btn { width: 100%; }

  /* Comfortable tap targets for all controls. */
  .btn, button, input, select, textarea { min-height: 44px; font-size: 16px; } /* 16px avoids iOS zoom */
  .btn { padding: .65rem 1rem; }

  /* Panels & forms a touch tighter. */
  .panel { padding: 1rem; }
  .auth-card { margin: 1.5rem auto; padding: 1.5rem; }

  .footer { flex-direction: column; gap: .2rem; text-align: center; }
}

/* ======================================================================
   freeCRM home — feature panels (Next best actions / News) + draggable
   quick-access cards. These classes are used only on the CRM home page, so
   they lean on the CRM green accent (--crm) to reinforce the module identity.
   ====================================================================== */
.feature-panel { display: flex; flex-direction: column; }
.feature-head { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
.feature-head h2 { margin: 0; font-size: 1.15rem; }
.feature-icon { margin-right: .15rem; }
.badge-soon { background: #eef2f7; color: var(--muted); text-transform: uppercase;
  letter-spacing: .04em; font-size: .64rem; font-weight: 700; padding: .15rem .5rem;
  border-radius: 999px; white-space: nowrap; }
.feature-lead { margin: .35rem 0 .9rem; color: var(--muted); font-size: .9rem; }
.feature-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .55rem; }
.feature-item { display: flex; gap: .6rem; align-items: flex-start; }
.feature-item-icon { font-size: 1.05rem; line-height: 1.4; flex: 0 0 auto; }
.feature-item-body { display: flex; flex-direction: column; min-width: 0; }
.feature-item-body a { color: var(--ink); text-decoration: none; font-weight: 600; }
.feature-item-body a:hover { color: var(--crm); }
.feature-item-body small { color: var(--muted); }
/* Faint ghost rows that anchor where real items will land (paired with the
   "Coming soon" badge so they read as placeholders, not a loading spinner). */
.feature-skeleton { position: relative; display: flex; flex-direction: column; gap: .35rem;
  padding: .2rem 0 .2rem 1.4rem; opacity: .5; }
.feature-skeleton::before { content: ""; position: absolute; left: 0; top: .2rem;
  width: .85rem; height: .85rem; border-radius: 50%; background: var(--line); }
.feature-skeleton span { display: block; height: .55rem; border-radius: 4px; background: var(--line); }
.feature-skeleton span:first-child { width: 72%; }
.feature-skeleton span:last-child { width: 46%; }
.feature-empty { color: var(--muted); font-size: .82rem; padding-top: .45rem; }

/* Data Quality landing page (Home › Accounts › Data Quality): action cards —
   the shared .card look, but non-clickable with a Run form at the foot. */
.dq-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.dq-card { display: flex; flex-direction: column; gap: .3rem; }
.dq-card:hover { transform: none; }
.dq-card form { margin-top: auto; padding-top: .6rem; }
.dq-stats { font-size: .85rem; }
.dq-ok { color: var(--ok); }
.dq-bad { color: var(--err); }
.dq-foot { margin-top: 1rem; }
.dq-knobs { display: flex; flex-direction: column; gap: .35rem;
  margin-bottom: .6rem; font-size: .85rem; }
.dq-knobs label { color: var(--muted); }
.dq-knobs input[type="number"] { width: 4.2rem; padding: .15rem .3rem;
  font-size: .85rem; }
.dq-knob-hint { display: block; font-size: .78rem; color: var(--muted);
  opacity: .8; }
.dq-knob-check input[type="checkbox"] { margin-right: .3rem;
  vertical-align: middle; }
.dq-report-group { margin-bottom: 1rem; }
.dq-report-group h2 { font-size: 1.05rem; margin-bottom: .5rem; }
.dq-report-group:hover { transform: none; }
.dq-report-rows { display: flex; flex-direction: column; gap: .45rem; }
.dq-report-row { padding: .35rem 0; border-top: 1px solid var(--line);
  font-size: .9rem; }
.dq-report-addresses { display: flex; flex-wrap: wrap; gap: .35rem .6rem;
  margin-top: .3rem; }
.dq-address code { font-size: .85rem; }
.dq-address-generic { opacity: .65; }
.dq-address-name { font-size: .8rem; color: var(--muted);
  margin-left: .25rem; }

/* Contact email deliverability indicator (❓/✅/✖ next to addresses) */
.email-q { cursor: help; font-size: .85em; }

/* Quick-access card grid */
.qa-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: .8rem; }
.qa-card { position: relative; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); transition: border-color .15s, transform .15s, box-shadow .15s; }
.qa-card:hover { border-color: var(--crm); transform: translateY(-2px); }
.qa-card-link { display: flex; align-items: center; gap: .7rem; padding: .85rem .9rem;
  text-decoration: none; color: var(--ink); }
.qa-icon { font-size: 1.5rem; line-height: 1; flex: 0 0 auto; }
.qa-text { display: flex; flex-direction: column; min-width: 0; }
.qa-label { font-weight: 600; }
.qa-desc { color: var(--muted); font-size: .8rem; }
/* Grip handle: the only drag affordance, so a swipe on the card body still
   scrolls on touch. Hidden until hover on fine pointers; always shown on touch. */
.qa-handle { position: absolute; top: .3rem; right: .3rem; width: 1.7rem; height: 1.7rem;
  display: flex; align-items: center; justify-content: center; padding: 0; border: none;
  background: none; color: var(--muted); font-size: 1rem; line-height: 1; border-radius: 6px;
  cursor: grab; opacity: 0; transition: opacity .15s; touch-action: none; }
.qa-card:hover .qa-handle { opacity: .6; }
.qa-handle:hover { opacity: 1; background: var(--bg); }
.qa-handle:active { cursor: grabbing; }
@media (hover: none) { .qa-handle { opacity: .5; } }
/* The lifted card (position:fixed is applied inline by the drag script). */
.qa-dragging { z-index: 1000; pointer-events: none; transform: none;
  border-color: var(--crm); box-shadow: 0 10px 28px rgba(0,0,0,.18); }
.qa-placeholder { border: 2px dashed var(--crm); border-radius: var(--radius);
  background: rgba(22, 163, 74, .06); }

/* System Options form */
.option-row { padding: .75rem 0; border-bottom: 1px solid var(--line); }
.option-row:last-child { border-bottom: 0; }
.option-label { font-weight: 600; display: flex; align-items: center; gap: .5rem; }
.option-row input[type="checkbox"] { flex: 0 0 auto; width: 1.1rem; height: 1.1rem; min-height: 0; }
.option-input { display: block; margin-top: .35rem; max-width: 12rem; padding: .4rem .5rem;
  border: 1px solid var(--line); border-radius: 6px; }
.option-help { margin: .35rem 0 0; max-width: 48rem; }

/* ---------------------------------------------------------------- AI agent */
#ai-fab-wrap { position: fixed; right: 1rem; bottom: 1rem; z-index: 1000; }
.ai-fab { width: 52px; height: 52px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--brand); color: #fff; font-size: 1.5rem; line-height: 52px;
  box-shadow: 0 4px 14px rgba(0,0,0,.25); }
.ai-fab:hover { background: var(--brand-dark); }
.ai-fab:focus-visible { outline: 3px solid var(--brand-dark); outline-offset: 2px; }
.ai-panel { position: fixed; right: 1rem; bottom: 4.75rem; width: min(380px, calc(100vw - 2rem));
  max-height: min(560px, calc(100vh - 6rem)); display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 8px 28px rgba(0,0,0,.2); overflow: hidden; }
/* The `display: flex` above overrides the UA stylesheet's `[hidden] { display: none }`,
   so the panel's `hidden` attribute needs a more specific rule to actually collapse it. */
.ai-panel[hidden] { display: none; }
/* On phones the panel goes full-screen so the chat (and camera) own the foreground.
   The flex column keeps the header pinned top, the log growing, the form at the bottom. */
@media (max-width: 640px) {
  .ai-panel { inset: 0; left: 0; right: 0; top: 0; bottom: 0; width: 100%;
    max-height: none; border-radius: 0; height: 100vh; }
  .ai-panel { height: 100dvh; }
  /* The crm-home chyron offset (app.css ~245-247) sits outside this query and would
     otherwise push the full-screen panel up; pin it back to the viewport edges. */
  body.crm-home .ai-panel { inset: 0; bottom: 0; }
  .ai-msg { max-width: 92%; font-size: 1rem; }
}
.ai-panel-head { display: flex; align-items: center; justify-content: space-between;
  gap: .5rem; padding: .6rem .8rem; border-bottom: 1px solid var(--line); font-weight: 600; }
.ai-head-actions { display: flex; align-items: center; gap: .6rem; }
/* GPU/model status dot beside the panel title. States mirror /ai/status/:
   standby (amber — model cold) · loading (pulsing amber) · ready (green) ·
   busy (red — another app owns the shared GPU) · offline/unknown (grey).
   Amber is a dedicated hex: var(--warn) reads brown at 9px. */
.ai-status-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  margin-left: .35rem; vertical-align: 1px; background: var(--muted); cursor: help; }
.ai-status-dot.st-standby, .ai-status-dot.st-loading { background: #e8a013; }
.ai-status-dot.st-ready { background: var(--ok); }
.ai-status-dot.st-busy { background: var(--err); }
.ai-status-dot.st-loading { animation: ai-dot-pulse 1.1s ease-in-out infinite; }
@keyframes ai-dot-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(232, 160, 19, .55); }
  50% { opacity: .55; box-shadow: 0 0 0 5px rgba(232, 160, 19, 0); }
}
@media (prefers-reduced-motion: reduce) { .ai-status-dot.st-loading { animation: none; } }
.ai-log { flex: 1; overflow-y: auto; padding: .8rem; display: flex; flex-direction: column;
  gap: .5rem; }
.ai-hint { color: var(--muted); font-size: .85rem; margin: 0; }
.ai-msg { padding: .45rem .65rem; border-radius: 10px; max-width: 85%; font-size: .9rem;
  white-space: pre-wrap; overflow-wrap: anywhere; }
.ai-user { align-self: flex-end; background: var(--brand); color: #fff; }
.ai-bot { align-self: flex-start; background: var(--bg); border: 1px solid var(--line); }
.ai-msg strong { font-weight: 700; }
.ai-msg code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .85em; background: rgba(0,0,0,.06); padding: .05rem .3rem; border-radius: 4px; }
.ai-msg .ai-tablewrap { overflow-x: auto; margin: .3rem 0; }
.ai-msg .ai-table { border-collapse: collapse; font-size: .85em; }
.ai-msg .ai-table th, .ai-msg .ai-table td { border: 1px solid var(--line);
  padding: .15rem .45rem; text-align: left; white-space: nowrap; }
.ai-msg .ai-table th { background: rgba(0,0,0,.04); font-weight: 600; }
.ai-notice { color: var(--warn); }
/* "domo arigato" easter egg — the video reply bubble. The iframe scales to
   the panel at 16:9 instead of YouTube's fixed 560x315 default. */
.ai-msg.ai-egg { align-self: flex-start; width: 92%; max-width: 92%; padding: .3rem; }
.ai-video { position: relative; width: 100%; aspect-ratio: 16 / 9; }
.ai-video iframe { width: 100%; height: 100%; border: 0; border-radius: 8px; display: block; }
.ai-step { align-self: flex-start; font-size: .82rem; color: var(--ok); }
.ai-step.err { color: var(--err); }
/* "Working…" indicator shown while the agent runs (animated bouncing dots). */
.ai-typing { align-self: flex-start; display: inline-flex; gap: 4px; align-items: center;
  padding: .55rem .7rem; background: var(--bg); border: 1px solid var(--line); border-radius: 10px; }
.ai-typing span { width: 7px; height: 7px; border-radius: 50%; background: var(--muted);
  animation: ai-typing-bounce 1.2s infinite ease-in-out both; }
.ai-typing span:nth-child(2) { animation-delay: .18s; }
.ai-typing span:nth-child(3) { animation-delay: .36s; }
@keyframes ai-typing-bounce { 0%, 80%, 100% { transform: translateY(0); opacity: .35; }
  40% { transform: translateY(-4px); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .ai-typing span { animation: none; opacity: .55; } }
.ai-confirm { align-self: stretch; border: 1px solid var(--warn); border-radius: 8px;
  padding: .55rem .7rem; background: #fff8e6; }
.ai-confirm-q { margin: 0 0 .45rem; font-size: .88rem; }
.ai-confirm-risk { float: right; text-transform: uppercase; font-size: .62rem; font-weight: 700;
  color: var(--warn); border: 1px solid var(--warn); border-radius: 4px; padding: .02rem .3rem; }
.ai-confirm-pre { display: block; font-size: .78rem; background: #fff; border: 1px solid var(--line);
  border-radius: 6px; padding: .35rem .5rem; margin-bottom: .5rem; overflow-x: auto; }
/* Editable confirm form: a label-over-input field per proposed argument. */
.ai-cf { display: flex; flex-direction: column; gap: .12rem; margin-bottom: .45rem; }
.ai-cf-label { font-size: .72rem; font-weight: 600; color: var(--muted); }
.ai-cf input[type="text"], .ai-cf input[type="number"], .ai-cf select, .ai-cf textarea {
  width: 100%; padding: .35rem .45rem; font-size: .85rem; border: 1px solid var(--line);
  border-radius: 6px; background: #fff; }
.ai-cf textarea { resize: vertical; }
.ai-cf-check { flex-direction: row; align-items: center; gap: .45rem; margin-bottom: .35rem; }
.ai-cf-check input { width: auto; min-height: 0; flex: 0 0 auto; }
.ai-cf-check .ai-cf-label { font-size: .85rem; color: var(--ink); }
.ai-confirm form > .btn { margin-top: .35rem; }
.ai-form { position: relative; display: flex; flex-wrap: wrap; gap: .4rem; padding: .6rem; border-top: 1px solid var(--line); align-items: center; }
/* The composer is a real multi-line box on its own full row (order:-1 lifts it
   above the button row without touching the DOM): ~2 lines tall at rest,
   auto-grown by the widget script up to max-height as the draft lengthens. */
.ai-input { flex: 1 1 100%; order: -1; padding: .45rem .55rem; border: 1px solid var(--line); border-radius: 6px;
  resize: none; min-height: 3.4rem; max-height: 160px; line-height: 1.4; overflow-y: auto; }
.ai-send { white-space: nowrap; margin-left: auto; }
/* The shared `.linkbtn` is forced to width:100% inside the mobile-nav media query
   (≤820px). The AI panel reuses `.linkbtn` for its icon/attach buttons, so opt them
   back out — otherwise on phones the 📎 button fills the row and crushes the input. */
.ai-panel .linkbtn { width: auto; }
.ai-attach { flex: 0 0 auto; font-size: 1.15rem; line-height: 1; padding: .2rem .25rem; cursor: pointer; }
.ai-attach-chip { display: flex; align-items: center; gap: .35rem; margin: 0 .6rem; padding: .3rem .5rem;
  background: var(--surface, #f5f5f5); border: 1px solid var(--line); border-radius: 6px; font-size: .85rem; }
.ai-attach-chip[hidden] { display: none; }   /* author display:flex would otherwise beat [hidden] */
.ai-attach-chip .ai-attach-x { margin-left: auto; }
.ai-attach-tag { opacity: .75; font-style: italic; }

/* Attachment menu (📎 → Camera / Photos / Files), anchored above the form row. */
.ai-attach-menu { position: absolute; left: .5rem; bottom: calc(100% + .4rem); z-index: 6;
  min-width: 9.5rem; display: flex; flex-direction: column; padding: .25rem;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0,0,0,.2); }
.ai-attach-menu[hidden] { display: none; }   /* author display:flex would otherwise beat [hidden] */
.ai-attach-item { display: flex; align-items: center; gap: .6rem; width: 100%; min-height: 44px;
  padding: 0 .7rem; border: none; border-radius: 7px; background: none; cursor: pointer;
  font: inherit; color: var(--ink); text-align: left; }
.ai-attach-item:hover, .ai-attach-item:focus-visible { background: var(--bg); }
.ai-attach-item svg { width: 20px; height: 20px; flex: 0 0 auto; color: var(--muted); }

/* In-panel camera (getUserMedia): a full-panel overlay with a CSS framing guide. */
.ai-camera { position: absolute; inset: 0; z-index: 20; background: #000;
  display: flex; align-items: center; justify-content: center; }
.ai-camera[hidden] { display: none; }
.ai-cam-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ai-cam-video.mirror { transform: scaleX(-1); }   /* natural preview for the front camera */
/* Framing guide: a centered rectangle drawn from four white corner brackets (no images). */
.ai-cam-frame { position: relative; width: 78%; height: 60%; pointer-events: none; }
.ai-cam-corner { position: absolute; width: 26px; height: 26px; border: 3px solid rgba(255,255,255,.9); }
.ai-cam-corner.tl { top: 0; left: 0; border-right: none; border-bottom: none; border-top-left-radius: 5px; }
.ai-cam-corner.tr { top: 0; right: 0; border-left: none; border-bottom: none; border-top-right-radius: 5px; }
.ai-cam-corner.bl { bottom: 0; left: 0; border-right: none; border-top: none; border-bottom-left-radius: 5px; }
.ai-cam-corner.br { bottom: 0; right: 0; border-left: none; border-top: none; border-bottom-right-radius: 5px; }
/* Control bar pinned to the bottom of the camera view; 44px tap targets for mobile. */
.ai-cam-bar { position: absolute; left: 0; right: 0; bottom: 0; z-index: 21;
  display: flex; align-items: center; justify-content: space-around;
  padding: 1rem 1.25rem calc(1rem + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(to top, rgba(0,0,0,.6), rgba(0,0,0,0)); }
.ai-cam-btn { display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(255,255,255,.15); color: #fff; font-size: 1.05rem; line-height: 1; }
.ai-cam-btn:hover { background: rgba(255,255,255,.3); }
.ai-cam-btn svg { width: 22px; height: 22px; }
.ai-cam-shutter { width: 62px; height: 62px; border-radius: 50%; padding: 0; cursor: pointer;
  background: rgba(255,255,255,.25); border: 3px solid #fff; }
.ai-cam-shutter span { display: block; width: 100%; height: 100%; border-radius: 50%;
  background: #fff; box-shadow: inset 0 0 0 3px #000; }
.ai-cam-shutter:hover { background: rgba(255,255,255,.4); }

/* voice chat mode — the toggle now lives in the form row next to 📎 (crisp SVG mic). */
.ai-voice-toggle { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  line-height: 1; padding: .2rem .25rem; cursor: pointer; }
.ai-voice-toggle svg { display: block; }
.ai-voice-toggle[aria-pressed="true"] { color: var(--brand); }
.ai-voice-toggle[disabled] { opacity: .4; cursor: not-allowed; }
.ai-voice-orb { margin: .5rem .8rem 0; padding: .5rem .7rem; border-radius: 8px;
  font-size: .85rem; font-weight: 600; text-align: center; }
.ai-voice-orb:empty { display: none; }
.ai-voice-orb.listening { background: #e6f0ff; color: var(--brand-dark); }
.ai-voice-orb.thinking  { background: #fff8e6; color: var(--warn); }
.ai-voice-orb.speaking  { background: #e7f7ef; color: var(--ok); }
.ai-voice-orb.confirm   { background: #fff8e6; color: var(--warn); }
.ai-voice-orb.listening::before { content: "● "; }
.ai-voice-orb.listening, .ai-voice-orb.speaking { animation: ai-pulse 1.2s ease-in-out infinite; }
@keyframes ai-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
/* Voice mode keeps the FULL transcript on screen — bubbles, tool steps and the
   working indicator all stay visible; the orb above the log only signals whose
   turn it is. Only the intro hint hides, to leave room for the conversation. */
.ai-panel.ai-voice-on .ai-log .ai-hint { display: none; }
/* Live caption while the mic listens: what the recogniser has heard so far,
   firming into a real user bubble on the final transcript. */
.ai-msg.ai-interim { opacity: .6; font-style: italic; }
/* The playful status line that rides along with the typing dots. */
.ai-typing-note { margin-left: .45rem; font-size: .8rem; color: var(--muted); font-style: italic; }
@media (prefers-reduced-motion: reduce) { .ai-voice-orb { animation: none !important; } }
.ai-config-toggle.active { color: var(--brand); }
.ai-config-indicator { margin: .4rem .8rem 0; padding: .35rem .6rem; border-radius: 6px;
  background: #fff8e6; color: var(--warn); font-size: .8rem; font-weight: 600; text-align: center; }

/* --------------------------------------------------------------------------- *
   Activity sidebar (freeCRM contact/account detail): two-column layout, threaded
   activities and editable status. Built on the shared design tokens.
 * --------------------------------------------------------------------------- */
.small { font-size: .85rem; }

/* CRM detail pages break out of the 1100px content cap to use the full viewport,
   so the activity sidebar is a true flush-right rail — not a nudge to the left. */
.content-wide { max-width: none; }
.crm-detail-layout { display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 1.5rem; align-items: start; }
.crm-detail-main { min-width: 0; }

/* Detail label/value block (all CRM detail pages). Previously an unstyled <dl>
   that stacked in a thin strip; lay it out as label/value pairs flowing across
   the available width so wide pages don't waste horizontal space. */
.detail-grid { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem 1.25rem; margin-bottom: 1.25rem; }
.detail-grid dl { display: grid; grid-template-columns: max-content 1fr; gap: .5rem 1.5rem; margin: 0; align-items: baseline; }
.detail-grid dt { color: var(--muted); }
.detail-grid dd { margin: 0; }
@media (min-width: 700px)  { .detail-grid dl { grid-template-columns: max-content 1fr max-content 1fr; } }
@media (min-width: 1200px) { .detail-grid dl { grid-template-columns: repeat(3, max-content 1fr); } }

/* Sticky, independently scrollable right rail that fills the viewport height. */
.activity-sidebar { position: sticky; top: calc(var(--topbar-h) + 1rem);
  max-height: calc(100vh - var(--topbar-h) - 2rem); overflow: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem; }
.activity-sidebar .section-header { margin: 0 0 .5rem; }
.activity-section { margin-top: 1rem; }
.activity-section h3 { margin: 0 0 .5rem; font-size: .75rem; text-transform: uppercase; letter-spacing: .03em; color: var(--muted); }

/* Type-filter chips reuse the .badge base; the active one is brand-filled. */
.activity-chips { display: flex; flex-wrap: wrap; gap: .25rem; margin-bottom: .75rem; }
.activity-chips .badge { cursor: pointer; }
.activity-chips .chip-active { background: var(--brand); color: #fff; }

/* Compose / reveal panels (log activity, reply, follow-up) via <details>. */
.activity-new { margin-bottom: 1rem; }
.activity-compose { margin-top: .4rem; }
/* --- Pop-up email composer (✉ New email on contact/account sidebars) ------ */
.compose-launch { margin-bottom: .75rem; }
dialog.email-compose-dialog { border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.1rem 1.25rem; width: min(46rem, 94vw); max-height: 90vh; overflow-y: auto; }
dialog.email-compose-dialog::backdrop { background: rgba(15, 25, 35, .45); }
.email-compose-dialog .section-header { margin: 0 0 .75rem; align-items: center; }
.email-compose-form label { display: block; margin: .7rem 0 .2rem; font-size: .85rem;
  color: var(--muted); font-weight: 600; }
.email-compose-form input[type="text"], .email-compose-form select,
.email-compose-form textarea { width: 100%; font: inherit; }
.email-compose-form textarea { resize: vertical; min-height: 10rem; }
.email-compose-form .compose-fixed { display: block; color: var(--ink); font-weight: 400;
  padding: .2rem 0; }
.email-compose-dialog .dialog-actions { display: flex; gap: .5rem;
  justify-content: flex-end; margin-top: 1rem; }
.activity-compose > summary { cursor: pointer; color: var(--brand); font-size: .85rem; list-style: none; display: inline-block; }
.activity-compose > summary::-webkit-details-marker { display: none; }
.activity-new > summary { font-weight: 600; font-size: .9rem; }
.activity-compose[open] > summary { margin-bottom: .4rem; }
.activity-compose form { display: grid; gap: .4rem; }
/* Edit panel: pack the type/direction/status selects onto one wrapping row. */
.activity-compose .edit-row { display: flex; gap: .4rem; flex-wrap: wrap; }
.activity-compose .edit-row select { width: auto; flex: 1 1 90px; min-width: 90px; }

/* One activity row */
.activity-item { padding: .5rem 0; border-top: 1px solid var(--line); }
.activity-item:first-child { border-top: none; }
.activity-head { display: flex; align-items: center; flex-wrap: wrap; gap: .3rem; }
.activity-subject { font-weight: 600; margin: .2rem 0; }
.activity-meta { margin-top: .15rem; }
.activity-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-top: .4rem; }
.activity-actions .activity-status-form { display: inline-flex; gap: .25rem; align-items: center; }
.activity-actions select { width: auto; padding: .2rem .35rem; font-size: .8rem; }
.linkbtn-ok { color: var(--ok); }
.linkbtn-ok:hover { color: var(--ok); text-decoration: underline; }

/* Direction glyphs (received vs sent) */
.dir { font-size: .72rem; font-weight: 700; }
.dir-in { color: var(--brand); }
.dir-out { color: var(--muted); }

/* Type-aware activity forms: rows hidden by activity-form.js must actually
   hide even inside the grid form (the `hidden` vs `display:` gotcha). */
.activity-form [hidden], .activity-compose [hidden] { display: none !important; }
.activity-form p { margin: 0; }
.activity-form p > label { display: block; font-size: .78rem; color: var(--muted); margin-bottom: .15rem; }
.activity-form .af-invite { display: flex; align-items: baseline; gap: .4rem; }
.activity-form .af-invite input { width: auto; }
.activity-form .af-invite label { display: inline; margin: 0; }
.activity-form .af-glance { margin: .25rem 0; }

/* Invitee picker (meetings): bounded checkbox list, one person per line. */
.af-invitees > span { display: block; font-size: .78rem; margin-bottom: .15rem; }
.invitee-list { max-height: 9.5rem; overflow-y: auto; border: 1px solid var(--line); border-radius: 6px; padding: .3rem .45rem; display: grid; gap: .15rem; }
.invitee-opt { display: flex; align-items: baseline; gap: .35rem; font-size: .82rem; cursor: pointer; }
.invitee-opt input { width: auto; margin: 0; }

/* Attendee chips + call outcome on the activity card. */
.attendee-chip { display: inline-block; border: 1px solid var(--line); border-radius: 999px; padding: .05rem .5rem; margin: 0 .15rem .15rem 0; font-size: .75rem; }
.pill-outcome { background: var(--panel-2, #eef1f5); color: var(--muted); }

/* Thread card: master + nested replies/follow-ons */
.activity-thread { border: 1px solid var(--line); border-radius: var(--radius); padding: .3rem .7rem; margin-bottom: .6rem; }
.activity-replies { border-left: 2px solid var(--line); margin: 0 0 .2rem .3rem; padding-left: .7rem; }

/* Activity status pills (extend the shared vocabulary; .pill-cancelled exists) */
.pill-pending   { background: #fdf6e3; color: var(--warn); }
.pill-completed { background: #e7f6ee; color: var(--ok); }
.pill-overdue   { background: #fdeceb; color: var(--err); }
/* 1:1 email tracking chips on activity rows (docs/EMAIL_TRACKING.md) */
.pill-opened    { background: #e8f1fd; color: #2563eb; }
.pill-replied   { background: #e7f6ee; color: var(--ok); }
/* Marks a timeline email as bulk campaign mail rather than a 1:1 send */
.pill-campaign  { background: #f3e8ff; color: #7e22ce; }
/* Open-event provenance: fetched via a provider image proxy, and the
   suspiciously-soon-after-send fetch that marks a machine, not a reader. */
.pill-proxy     { background: var(--panel-2, #eef1f5); color: var(--muted); }
.pill-machine   { background: #fdf6e3; color: var(--warn); }

/* @mentions — rendered tokens + the inline typeahead dropdown */
.mention { color: var(--brand); font-weight: 600; text-decoration: none; }
.mention:hover { text-decoration: underline; }
.mention-user { cursor: default; }
.mention-menu, .picker-menu {
  position: absolute; z-index: 60; background: var(--panel);
  border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 6px 18px rgba(20, 40, 70, .14);
  min-width: 220px; max-width: 380px; max-height: 220px; overflow-y: auto;
}
.mention-opt, .picker-opt {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: .75rem; padding: .35rem .6rem; cursor: pointer;
}
.mention-opt.active, .mention-opt:hover,
.picker-opt.active, .picker-opt:hover { background: var(--bg); }
.mention-opt-label, .picker-opt-label { font-weight: 600; }
.mention-opt-sub, .picker-opt-sub {
  color: var(--muted); font-size: .78rem; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

/* Record picker (lead form): shadow preview, locked mirrors, linked chip. */
.picker-shadow { color: var(--muted); font-style: italic; }
input.picker-locked {
  background: var(--bg); color: var(--muted); cursor: not-allowed;
}
.picker-chip {
  display: flex; align-items: center; flex-wrap: wrap; gap: .4rem;
  background: #e8f1fd; border: 1px solid #cfe0f8; border-radius: 8px;
  padding: .45rem .7rem; margin-bottom: .9rem;
}
.picker-chip a { font-weight: 600; }
.picker-unlink { margin-left: auto; }

/* Notes section (contact/account detail) */
.notes-section { margin-top: 1.5rem; }
.note-new { margin: .3rem 0 .6rem; }
.notes-list { margin-top: .3rem; }
.note-item { border-top: 1px solid var(--line); padding: .55rem 0; }
.note-item:first-child { border-top: none; }
.note-item.pinned { background: #fffdf3; border: 1px solid #f3e7c4; border-radius: 8px; padding: .55rem .7rem; margin-bottom: .4rem; }
.note-body { white-space: normal; overflow-wrap: anywhere; }
.note-meta { margin-top: .3rem; }
.note-meta form.inline { display: inline; }
.check { display: inline-flex; align-items: center; gap: .35rem; font-size: .85rem; }
.check input { width: auto; }

/* Collapse to a single column on narrow screens (align with existing 820 bp). */
@media (max-width: 900px) {
  .crm-detail-layout { grid-template-columns: 1fr; }
  .activity-sidebar { position: static; max-height: none; }
}

/* ======================================================================
   Next Best Action panels (home worklist + account/contact record panels).
   Reuses .panel / .feature-panel; adds the ranked list, priority badges and
   the inline accept / snooze / dismiss controls. See docs/CRM_NBA.md.
   ====================================================================== */
.nba-panel { margin-bottom: 1.25rem; }
.nba-count { background: var(--crm); color: #fff; font-weight: 700; }
.nba-allclear { margin: .5rem 0 0; color: var(--ok); }
.nba-list { list-style: none; margin: .5rem 0 0; padding: 0; display: flex; flex-direction: column; }
/* A tinted left rule keys each row to its priority without shouting. */
.nba-item { display: flex; gap: .6rem; align-items: flex-start; padding: .6rem 0 .6rem .6rem;
  border-top: 1px solid var(--line); border-left: 3px solid transparent; }
.nba-item:first-child { border-top: none; }
.nba-prio-high { border-left-color: var(--err); }
.nba-prio-medium { border-left-color: var(--warn); }
.nba-prio-low { border-left-color: var(--line); }
.nba-item-icon { font-size: 1.1rem; line-height: 1.4; flex: 0 0 auto; }
.nba-item-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.nba-item-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: .4rem; }
.nba-item-title { color: var(--ink); text-decoration: none; font-weight: 600; }
.nba-item-title:hover { color: var(--crm); text-decoration: underline; }
.nba-reason { color: var(--muted); margin-top: .15rem; }
.nba-ai { cursor: help; }
/* Priority badges reuse the .badge pill base with state colours. */
.badge-priority { text-transform: uppercase; font-size: .64rem; font-weight: 700; letter-spacing: .04em; }
.badge-priority-high { background: #fdeceb; color: var(--err); }
.badge-priority-medium { background: #fdf6e3; color: var(--warn); }
.badge-priority-low { background: #eef2f7; color: var(--muted); }
/* Compact, right-aligned inline controls. The mobile-nav rule forces .linkbtn to
   width:100%, so opt these back to auto (same fix as the AI panel). */
.nba-item-actions { display: flex; gap: .5rem; align-items: center; flex: 0 0 auto; }
.nba-item-actions .linkbtn { width: auto; font-size: .95rem; line-height: 1; }
.nba-snooze:hover { color: var(--warn); }

/* ======================================================================
   eSignature envelopes — recipient rows, drag-chip field placement, and the
   standalone signer portal (docs/EXTERNAL_ESIGNATURES.md). Reuses .panel /
   .btn / .data-table / .auth-card; chips carry their recipient colour inline.
   ====================================================================== */
.esign-suggest { display: flex; flex-wrap: wrap; gap: .4rem; margin: .4rem 0 .8rem; }
.esign-external-fields { display: flex; gap: .4rem; flex-wrap: wrap; }
.esign-external-fields[hidden], .esign-internal-fields[hidden] { display: none; }
.esign-placement-layout { display: grid; grid-template-columns: 280px 1fr; gap: 1rem; align-items: start; }
.esign-palette { position: sticky; top: calc(var(--topbar-h) + 1rem); }
.esign-pages { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }
.esign-page { position: relative; border: 1px solid var(--line); background: #fff;
  box-shadow: 0 1px 4px rgba(15, 23, 42, .08); }
.esign-page img { display: block; width: 100%; height: auto; user-select: none; -webkit-user-select: none; }
.esign-page-number { position: absolute; right: .4rem; bottom: .3rem; font-size: .7rem;
  color: var(--muted); background: rgba(255, 255, 255, .85); padding: 0 .3rem; border-radius: 3px; }
.sig-chip { display: flex; align-items: center; gap: .3rem; border: 2px dashed currentColor;
  border-radius: 6px; padding: .3rem .55rem; font-size: .85rem; font-weight: 600;
  background: rgba(255, 255, 255, .88); cursor: grab; touch-action: none;
  user-select: none; -webkit-user-select: none; margin: .3rem 0;
  overflow: hidden; white-space: nowrap; }
.sig-chip[hidden] { display: none; }
.sig-chip-done { opacity: .45; }
.sig-chip-placed { position: absolute; margin: 0; z-index: 5; }
.sig-chip-ghost { position: fixed; z-index: 100; pointer-events: none; opacity: .8; margin: 0; }
@media (max-width: 900px) {
  .esign-placement-layout { grid-template-columns: 1fr; }
  .esign-palette { position: static; }
}
/* Signer portal (standalone pages, gate-page pattern; reuse .auth-card). */
.portal-card { max-width: 760px; margin: 2rem auto; }
.portal-doc { display: flex; flex-direction: column; gap: 1rem; margin: 1rem 0; }
.portal-doc img { width: 100%; height: auto; display: block; border: 1px solid var(--line); }
.portal-consent { display: flex; gap: .5rem; align-items: flex-start;
  background: var(--panel, #f8fafc); border: 1px solid var(--line);
  border-radius: 6px; padding: .6rem .8rem; margin: .8rem 0; }
.otp-input { font-size: 1.4rem; letter-spacing: .4em; text-align: center; }

/* Click-to-sign: document with field overlays, adoption modal, progress bar. */
.sign-doc { display: flex; flex-direction: column; gap: 1rem; margin: 1rem 0; }
.sign-page { position: relative; }
.sign-progress { position: sticky; top: var(--topbar-h); z-index: 20; display: flex;
  align-items: center; gap: .6rem 1rem; flex-wrap: wrap;
  background: var(--panel, #f8fafc); border: 1px solid var(--line);
  border-radius: 8px; padding: .6rem .8rem; margin: 1rem 0; }
.sign-progress-count { font-weight: 700; }
.sign-field { position: absolute; z-index: 5; box-sizing: border-box; margin: 0;
  display: flex; align-items: center; justify-content: center; gap: .2rem;
  padding: 0 .2rem; border: 2px dashed #2563eb; border-radius: 5px;
  background: rgba(37, 99, 235, .14); color: #1b2a6b; cursor: pointer;
  font-size: .72rem; font-weight: 700; line-height: 1; overflow: hidden;
  white-space: nowrap; box-shadow: 0 0 0 2px rgba(255, 255, 255, .55); }
.sign-field:hover, .sign-field:focus { background: rgba(37, 99, 235, .24);
  outline: none; }
.sign-field-next { animation: signFieldPulse 1.3s ease-in-out infinite; }
@keyframes signFieldPulse {
  0%, 100% { box-shadow: 0 0 0 2px rgba(255, 255, 255, .55); }
  50% { box-shadow: 0 0 0 5px rgba(37, 99, 235, .55); }
}
.sign-field-filled { border-style: solid; border-color: #16a34a;
  background: rgba(255, 255, 255, .92); cursor: default; }
.sign-field-label { pointer-events: none; }
.sign-field-mark { max-width: 100%; max-height: 100%; object-fit: contain;
  display: block; pointer-events: none; }
.adopt-modal { position: fixed; inset: 0; z-index: 200; display: flex;
  align-items: center; justify-content: center; padding: 1rem;
  background: rgba(15, 23, 42, .55); }
.adopt-modal[hidden] { display: none; }
.adopt-modal-card { background: #fff; border-radius: 10px; padding: 1rem 1.2rem;
  width: 100%; max-width: 680px; max-height: 92vh; overflow: auto;
  box-shadow: 0 10px 40px rgba(15, 23, 42, .35); }
.adopt-modal-card .adopt-block { border: 0; box-shadow: none; padding: 0; }
.adopt-head { display: flex; align-items: center; justify-content: space-between;
  gap: .5rem; flex-wrap: wrap; margin-bottom: .4rem; }
.adopt-heading { margin: 0; }

/* Signature adoption blocks (draw canvas + handwriting-style picker). */
.adopt-block { margin-bottom: 1rem; }
.adopt-block[hidden] { display: none; }
.adopt-canvas { width: 100%; max-width: 600px; height: auto; display: block;
  border: 1px dashed var(--line); border-radius: 6px; background: #fff;
  touch-action: none; cursor: crosshair; }
.adopt-draw[hidden], .adopt-style[hidden] { display: none; }
.adopt-tab-active { border-color: #2563eb; color: #2563eb; font-weight: 700; }
.adopt-style-options { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: .5rem; }
.adopt-style-option { display: flex; align-items: center; gap: .5rem;
  border: 2px solid var(--line); border-radius: 6px; padding: .4rem .6rem;
  cursor: pointer; background: #fff; }
.adopt-style-option:has(input:checked) { border-color: #2563eb; }
.adopt-style-option img { max-height: 56px; width: auto; display: block; }
/* Placement palette: one row per signer, two chip kinds. */
.esign-signer { margin: .5rem 0 .8rem; }
.esign-signer-name { font-weight: 700; font-size: .9rem; margin-bottom: .25rem; }
.esign-chip-row { display: flex; gap: .5rem; flex-wrap: wrap; }
.esign-chip-row .sig-chip { margin: 0; }
.sig-chip-initials { font-size: .75rem; padding: .2rem .45rem; }

/* ======================================================================
   Document taxonomy — collapsible folder-tree rail on the Documents page.
   Two-column grid (rail + list), opting into content-wide to break the 1100px
   cap. #rail-toggle is a drawer handle pinned to the rail's right edge; it
   slides the rail open/closed by animating the grid column (folder-tree.js).
   Nodes expand/collapse via the .open class (CSS below), persisted by the same
   JS. Single column under 900px, mirroring the CRM/eSign rail breakpoints.
   ====================================================================== */
.doc-browse-layout { display: grid; grid-template-columns: 280px minmax(0, 1fr);
  gap: 1.25rem; align-items: start; transition: grid-template-columns .28s ease; }
.doc-browse-layout.rail-collapsed { grid-template-columns: 13px minmax(0, 1fr); }
.doc-browse-main { min-width: 0; }

/* The rail column is the sticky + positioning context; it never clips, so the
   toggle handle can protrude past the panel's right edge like a drawer tab. */
.folder-rail-col { position: sticky; top: calc(var(--topbar-h) + 1rem); align-self: start; }
/* The panel clips horizontally while its width animates; the tree scrolls on the
   fixed-width inner so it never reflows/squishes mid-slide. */
.folder-rail { overflow: hidden; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); transition: background .28s ease, border-color .28s ease; }
.folder-rail-inner { width: 280px; max-height: calc(100vh - var(--topbar-h) - 2rem); overflow-y: auto;
  transition: opacity .2s ease; }
.folder-rail-head { display: flex; align-items: center; gap: .5rem;
  padding: .55rem .7rem; border-bottom: 1px solid var(--line);
  position: sticky; top: 0; background: var(--panel); z-index: 1; }
.folder-rail-title { font-weight: 600; font-size: .9rem; white-space: nowrap; }
.folder-rail-body { padding: .5rem .45rem .7rem; }
/* Collapsed: the panel fades to the page background and the tree hides, leaving
   just the handle — the reference drawer behaviour. */
.rail-collapsed .folder-rail { background: transparent; border-color: transparent; }
.rail-collapsed .folder-rail-inner { opacity: 0; pointer-events: none; }
/* Drawer handle: a rounded tab centred on the rail's right edge. Its left:100%
   resolves against the (animating) column width, so it glides with the slide. */
.rail-toggle { position: absolute; top: 50%; left: 100%; transform: translate(-50%, -50%);
  width: 24px; height: 46px; display: grid; place-items: center; cursor: pointer;
  background: var(--panel); color: var(--muted); border: 1px solid var(--line);
  border-radius: 8px; box-shadow: 0 2px 6px rgba(15, 23, 42, .12);
  font-size: 1.1rem; line-height: 1; padding: 0; min-height: 0; z-index: 4;
  transition: color .15s, background .15s; }
.rail-toggle:hover { background: var(--bg); color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
  .doc-browse-layout, .folder-rail, .folder-rail-inner { transition: none; }
}

/* Tree */
.folder-tree, .folder-children { list-style: none; margin: 0; padding: 0; }
.folder-children { padding-left: .85rem; display: none; }
.folder-node.open > .folder-children { display: block; }
.folder-row { display: flex; align-items: center; gap: .1rem; border-radius: 6px; }
.folder-row:hover { background: var(--bg); }
.folder-row.active { background: #eaf2fd; }
.folder-twist { flex: 0 0 auto; width: 1.2rem; height: 1.5rem; display: flex;
  align-items: center; justify-content: center; padding: 0; background: none;
  border: none; cursor: pointer; color: var(--muted); font-size: .65rem;
  min-height: 0; transition: transform .12s ease; }
.folder-node.open > .folder-row .folder-twist { transform: rotate(90deg); }
.folder-twist-spacer { flex: 0 0 auto; width: 1.2rem; }
.folder-link { display: flex; align-items: center; gap: .4rem; min-width: 0;
  padding: .26rem .3rem; text-decoration: none; color: var(--ink); font-size: .9rem;
  flex: 1 1 auto; }
.folder-row.active > .folder-link { color: var(--brand-dark); font-weight: 600; }
.folder-emoji { flex: 0 0 auto; font-size: .85rem; line-height: 1; }
.folder-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.folder-count { flex: 0 0 auto; font-size: .7rem; color: var(--muted);
  background: var(--bg); border-radius: 999px; padding: .02rem .42rem; }
.folder-row.active .folder-count { background: #fff; }
/* Encryption-at-rest marker — shown on the folder that sets it AND on every
   folder beneath, because the whole subtree really is encrypted. */
.folder-lock { flex: 0 0 auto; font-size: .7rem; line-height: 1; opacity: .75; }

/* Encryption block in the folder permissions dialog. */
.perm-encryption { border: 1px solid var(--line); border-radius: var(--radius);
  padding: .6rem .7rem; background: var(--bg); }
.perm-encryption p { margin: 0 0 .45rem; font-size: .88rem; }
.perm-encryption form { margin: 0; display: block; }
.perm-encryption .perm-inherited { margin-bottom: 0; }

/* Add-folder controls (coordinator/admin) — reuse the <details> compose pattern */
.folder-admin { margin-top: .6rem; padding-top: .6rem; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: .2rem; }
.folder-admin .activity-compose > summary { font-size: .82rem; }
.folder-admin form { display: flex; gap: .35rem; margin-top: .35rem; }
.folder-admin input { flex: 1; min-width: 0; }
.folder-admin .btn { white-space: nowrap; }
.folder-empty-hint { font-size: .85rem; }
/* Discoverability for drag-&-drop upload, under the tree in the rail. */
.folder-drop-hint { margin: .5rem .25rem 0; font-size: .75rem; line-height: 1.35; }

/* Breadcrumb + include-subfolders toggle */
.folder-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem;
  margin-bottom: .85rem; font-size: .9rem; color: var(--muted); }
.folder-crumbs a { color: var(--brand); text-decoration: none; }
.folder-crumbs a:hover { text-decoration: underline; }
.folder-crumb-sep { color: var(--muted); }
.folder-crumb-current { font-weight: 600; color: var(--ink); }
.folder-sub-toggle { margin-left: .5rem; font-size: .82rem; }

@media (max-width: 900px) {
  .doc-browse-layout, .doc-browse-layout.rail-collapsed { grid-template-columns: 1fr; }
  /* On phones the rail is full width and the handle sits at the header's
     top-right (not an edge tab); collapsing just hides the tree, keeping the
     title so it can be reopened. */
  .folder-rail-col { position: relative; top: auto; }
  .folder-rail { overflow: visible; }
  .folder-rail-inner { width: 100%; max-height: none; overflow-y: visible; opacity: 1; }
  .rail-collapsed .folder-rail { background: var(--panel); border-color: var(--line); }
  .rail-collapsed .folder-rail-inner { opacity: 1; pointer-events: auto; }
  .rail-collapsed .folder-rail-body { display: none; }
  .folder-rail-head { padding-right: 3rem; }
  .rail-toggle { top: .5rem; left: auto; right: .5rem; transform: none;
    width: 32px; height: 32px; box-shadow: none; font-size: 1rem; }
}

/* ---- Folder management (rename / retype / move / delete) + drag-to-move ---- */
.btn-danger { color: var(--err); border-color: #f6c5c0; }
.btn-danger:hover { background: #fdeceb; border-color: var(--err); }

/* Drag grip on each row (managers only). Hidden until row hover on fine
   pointers; always shown on touch — mirrors the CRM quick-card handle so a
   swipe over the row body still scrolls on touch. */
.folder-drag { flex: 0 0 auto; width: 1rem; height: 1.5rem; display: flex;
  align-items: center; justify-content: center; padding: 0; background: none;
  border: none; color: var(--muted); font-size: .8rem; line-height: 1;
  cursor: grab; opacity: 0; min-height: 0; touch-action: none; }
.folder-row:hover .folder-drag { opacity: .55; }
.folder-drag:hover { opacity: 1; }
.folder-drag:active { cursor: grabbing; }
@media (hover: none) { .folder-drag { opacity: .5; } }

/* Row being dragged + the fixed ghost that trails the pointer. */
.folder-node.folder-dragging > .folder-row { opacity: .4; }
.folder-drag-ghost { position: fixed; z-index: 1000; pointer-events: none;
  background: var(--panel); border: 1px solid var(--brand); border-radius: 6px;
  padding: .2rem .55rem; font-size: .85rem; box-shadow: 0 6px 18px rgba(0,0,0,.18);
  max-width: 260px; overflow: hidden; white-space: nowrap; }

/* Drop feedback: highlight "into" a row, or an inset rule for before/after
   (inset box-shadow avoids any layout shift while dragging). */
.folder-row.drop-inside { outline: 2px solid var(--brand); outline-offset: -2px;
  background: #eaf2fd; border-radius: 6px; }
.folder-row.drop-before { box-shadow: inset 0 2px 0 0 var(--brand); }
.folder-row.drop-after  { box-shadow: inset 0 -2px 0 0 var(--brand); }

/* ---- Desktop file drag-&-drop (file-drop.js) ------------------------------ */
/* "or drop file here" pill injected beside every native file picker. */
.file-drop { display: inline-block; margin-left: .5rem; padding: .3rem .75rem;
  border: 1.5px dashed var(--line); border-radius: 999px; color: var(--muted);
  font-size: .82rem; white-space: nowrap; vertical-align: middle; }
.file-drop.over { border-color: var(--brand); color: var(--brand-dark); background: #eaf2fd; }

/* Folder rows + the list's empty-state placeholder as upload drop targets
   (dashed = "files land here", vs the solid outline of a folder move). */
.folder-row.drop-file { outline: 2px dashed var(--brand); outline-offset: -2px;
  background: #eaf2fd; border-radius: 6px; }
.drop-zone { border: 2px dashed transparent; border-radius: var(--radius); }
.drop-zone.over { border-color: var(--brand); background: #eaf2fd; }
.drop-busy { opacity: .55; pointer-events: none; }

/* Dropped-folder upload: the live progress panel, which is also the run report
   for the drop (per-file rows, failures kept). Bottom-LEFT so it never fights
   the notification tray on the right. */
.upload-panel { position: fixed; left: 1rem; bottom: 1rem; z-index: 940;
  width: min(380px, calc(100vw - 2rem)); background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(31, 41, 51, .18); font-size: .82rem; }
.upload-panel-head { display: flex; justify-content: space-between; align-items: center;
  gap: .5rem; padding: .45rem .75rem; border-bottom: 1px solid var(--line); }
.upload-panel-x { border: none; background: none; cursor: pointer; color: var(--muted);
  font-size: .9rem; line-height: 1; padding: 0 .15rem; }
.upload-panel-body { padding: .55rem .75rem; }
.upload-bar { height: 8px; border-radius: 999px; background: var(--panel-2, #eef1f5);
  overflow: hidden; }
.upload-bar-fill { height: 100%; width: 0; border-radius: 999px; background: var(--brand);
  transition: width .2s ease; }
.upload-status { margin: .45rem 0 0; color: var(--muted); }
.upload-log { list-style: none; margin: .4rem 0 0; padding: 0; max-height: 8.5rem;
  overflow-y: auto; font-size: .78rem; }
.upload-log:empty { display: none; }
.upload-log li { padding: .15rem 0; border-top: 1px dashed var(--line);
  overflow-wrap: anywhere; }
.upload-row-ok { color: var(--muted); }
.upload-row-bad { color: var(--err); }
.upload-panel-actions { display: flex; gap: .4rem; justify-content: flex-end;
  padding: .5rem .75rem; border-top: 1px solid var(--line); }

/* Manage panel: stacked mini-forms separated by hairlines. */
.folder-manage form { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center;
  padding: .45rem 0; border-top: 1px dashed var(--line); margin: 0; }
.folder-manage form:first-of-type { border-top: none; }
.folder-manage input[type=text], .folder-manage select { flex: 1 1 130px; min-width: 0; }
.folder-manage .btn { white-space: nowrap; }
.folder-manage-label { flex: 1 0 100%; font-size: .72rem; color: var(--muted); margin: .15rem 0 0; }
.folder-manage-note { margin: .45rem 0 0; font-size: .78rem; color: var(--muted); }

/* ======================================================================
   Signature Properties — the click-to-inspect card (shared by the panel
   modal, the standalone page and the printable signature "certificate"),
   plus the clickable hotspots + side panel in the signed-document viewer.
   Reuses .detail-list / .pill / .btn / .badge; positioning mirrors .sign-field.
   ====================================================================== */
.sig-props-head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: .6rem; flex-wrap: wrap; }
.sig-props-head strong { display: block; }
.sig-props-summary { margin: .2rem 0 .6rem; }
.sig-props h3 { margin: 1rem 0 .3rem; font-size: .82rem; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); }
.sig-props .detail-list { margin: 0; }
.sig-hash { word-break: break-all; font-size: .82rem; }
.sig-ua { word-break: break-word; font-size: .82rem; color: var(--muted); }
.sig-timeline { list-style: none; margin: .4rem 0 0; padding: 0; }
.sig-timeline li { display: flex; justify-content: space-between; gap: 1rem;
  padding: .2rem 0; border-top: 1px dashed var(--line); }
.sig-timeline li:first-child { border-top: none; }
.sig-verify-result { border-radius: 6px; padding: .5rem .7rem; margin: .3rem 0 .6rem;
  border: 1px solid var(--line); }
.sig-verify-result ul { margin: .3rem 0 0 1rem; }
.sig-verify-ok { background: #e9f8ef; border-color: #16a34a; }
.sig-verify-bad { background: #fdecec; border-color: #dc2626; }
.sig-props-actions { margin-top: .8rem; }

/* Modal that hosts the card when a signature is clicked. */
.sig-modal { position: fixed; inset: 0; z-index: 200; display: flex;
  align-items: flex-start; justify-content: center; padding: 1.5rem 1rem;
  overflow: auto; background: rgba(15, 23, 42, .55); }
.sig-modal[hidden] { display: none; }
.sig-modal-card { background: #fff; border-radius: 10px; padding: 1rem 1.2rem;
  width: 100%; max-width: 640px; box-shadow: 0 10px 40px rgba(15, 23, 42, .35); }
.sig-modal-head { display: flex; align-items: center; justify-content: space-between;
  gap: .5rem; margin-bottom: .5rem; }
.sig-modal-head h2 { margin: 0; font-size: 1.1rem; }

/* Signed-document viewer: pages on the left, a "Signatures" side panel on the
   right; a clickable hotspot sits over each visible mark on the pdf.js canvas. */
.sig-viewer-layout { display: flex; gap: 1rem; align-items: flex-start; }
.sig-viewer-main { flex: 1 1 auto; min-width: 0; }
.sig-sidepanel { flex: 0 0 232px; position: sticky; top: calc(var(--topbar-h) + 1rem); align-self: flex-start;
  border: 1px solid var(--line); border-radius: 8px; background: var(--panel, #f8fafc);
  padding: .6rem .7rem; max-height: 80vh; overflow: auto; }
.sig-sidepanel h3 { margin: 0 0 .4rem; font-size: .8rem; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); }
.sig-sidepanel-row { display: block; width: 100%; text-align: left; cursor: pointer;
  border: 1px solid var(--line); border-radius: 6px; background: #fff;
  padding: .4rem .5rem; margin-bottom: .4rem; }
.sig-sidepanel-row:hover, .sig-sidepanel-row:focus { border-color: var(--brand); outline: none; }
.sig-sidepanel-row .subtitle { display: block; }
.sig-hotspot { position: absolute; z-index: 5; box-sizing: border-box; margin: 0;
  display: block; padding: 0; cursor: pointer; border: 2px solid rgba(22, 163, 74, .8);
  border-radius: 4px; background: rgba(22, 163, 74, .10);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .5); }
.sig-hotspot::after { content: "🔏"; position: absolute; top: -.6rem; right: -.6rem;
  font-size: .8rem; background: #fff; border-radius: 50%; line-height: 1;
  box-shadow: 0 1px 3px rgba(15, 23, 42, .3); }
.sig-hotspot:hover, .sig-hotspot:focus { background: rgba(22, 163, 74, .24); outline: none; }
.sig-hotspot-broken, .sig-hotspot-changed { border-color: rgba(220, 38, 38, .85);
  background: rgba(220, 38, 38, .12); }
@media (max-width: 820px) {
  /* Stack the viewer and lift the Signatures panel ABOVE the (often long)
     document so it's visible without scrolling past the whole PDF. */
  .sig-viewer-layout { flex-direction: column; }
  .sig-sidepanel { order: -1; position: static; flex-basis: auto; width: 100%; max-height: none; }
}
/* Envelope recipient rows: on phones the 5-column table (with fixed 11rem/14rem
   columns and stacked name+email inputs) can't fit — stack each row into a card
   with full-width inputs instead of squashing/side-scrolling. */
@media (max-width: 640px) {
  .esign-recip-table thead { display: none; }
  .esign-recip-table, .esign-recip-table tbody,
  .esign-recip-table tr, .esign-recip-table td { display: block; }
  /* Card per recipient; top padding leaves room for the "Signer N" + ✕ header. */
  .esign-recip-table tr { position: relative; background: #fff; border: 1px solid var(--line);
    border-radius: 8px; padding: 1.9rem .6rem .6rem; margin-bottom: .6rem; }
  .esign-recip-table td { border: none; padding: .3rem 0; white-space: normal; }
  /* Field name above each field (the <thead> is hidden on mobile). */
  .esign-recip-table td[data-label]::before { content: attr(data-label); display: block;
    font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
    color: var(--muted); margin-bottom: .2rem; }
  .esign-recip-table .esign-order { position: absolute; top: .55rem; left: .7rem; padding: 0;
    color: var(--muted); font-size: .8rem; font-weight: 700; }
  .esign-recip-table .esign-order::before { content: "Signer "; }
  .esign-recip-table .esign-remove-cell { position: absolute; top: .35rem; right: .5rem; padding: 0; }
  .esign-recip-table .esign-external-fields { flex-direction: column; gap: .4rem; }
  .esign-recip-table input, .esign-recip-table select { width: 100%; box-sizing: border-box; }
}
@media print {
  .sig-props-actions, .sig-modal, .sig-verify-form { display: none !important; }
}

/* CTG Import (FR-CTG): ClinicalTrials.gov search form + candidate results.
   Two-column filter grid; checkbox groups flow horizontally instead of the
   default one-per-line stack; candidate table reuses .data-table/.pill. */
.ctg-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .9rem 1.4rem; max-width: 62rem; margin-bottom: 1.6rem; }
.ctg-form .field { margin: 0; }
.ctg-form .field-full { grid-column: 1 / -1; }
.field .help { display: block; margin-top: .25rem; font-size: .78rem; color: var(--muted); }
.ctg-choices > div { display: flex; flex-wrap: wrap; gap: .15rem 1.1rem; }
.ctg-choices > div label { display: inline-flex; align-items: center; gap: .4rem;
  font-size: .9rem; white-space: nowrap; }
.ctg-submit { grid-column: 1 / -1; display: flex; align-items: center; gap: .8rem; }
@media (max-width: 700px) { .ctg-form { grid-template-columns: 1fr; } }
.ctg-actions { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  margin: .4rem 0 .8rem; }
.ctg-flag { background: #fdf6e3; color: var(--warn); }
.ctg-conditions { max-width: 16rem; }
.ctg-table td { vertical-align: top; }
.ctg-contacts { max-width: 15rem; word-break: break-all; }
/* CTG staging area: state tabs, nested per-company study lists, trials panel. */
.ctg-tabs { display: flex; gap: .4rem; flex-wrap: wrap; margin: .3rem 0 .9rem; }
.ctg-tabs .badge { text-decoration: none; cursor: pointer; }
.ctg-tabs .ctg-tab-active { background: var(--crm, var(--brand)); color: #fff; }
.ctg-studies-cell summary { cursor: pointer; white-space: nowrap; }
.ctg-study-list { list-style: none; margin: .4rem 0 0; padding: 0 0 0 .2rem; }
.ctg-study-list li { padding: .15rem 0; border-top: 1px dotted var(--line); font-size: .85rem; }
.ctg-actions-cell form { display: flex; gap: .3rem; flex-wrap: wrap; margin: 0 0 .25rem; }
/* Staging auto-screen: the ▶ sweep's live progress panel (polled via HTMX). */
.ctg-screen-panel { border: 1px solid var(--line); border-radius: 10px; padding: .7rem .9rem;
  margin: 0 0 1rem; background: var(--panel, #fff); display: flex; flex-direction: column; gap: .45rem; }
.ctg-screen-head { display: flex; align-items: baseline; gap: .7rem; flex-wrap: wrap; }
.ctg-progress { height: 8px; border-radius: 999px; background: var(--panel-2, #eef1f5); overflow: hidden; }
.ctg-progress-fill { height: 100%; border-radius: 999px; background: var(--crm, var(--brand));
  transition: width .6s ease; }
.ctg-screen-now { font-size: .92rem; }
.ctg-screen-log { list-style: none; margin: 0; padding: 0; }
.ctg-screen-log li { padding: .18rem 0; border-top: 1px dotted var(--line);
  display: flex; gap: .45rem; align-items: baseline; flex-wrap: wrap; }
/* CTG run page: the live registry-walk panel reuses the screen-panel look;
   the search form groups its auto-screen dials under a bordered fieldset. */
.ctg-run-stop { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin: 0; }
.ctg-rules { grid-column: 1 / -1; border: 1px solid var(--line); border-radius: 10px;
  margin: .2rem 0 0; padding: .6rem .9rem .8rem; display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .9rem 1.4rem; }
.ctg-rules legend { font-weight: 600; font-size: .92rem; padding: 0 .35rem; }
.ctg-rules .ctg-rules-note { grid-column: 1 / -1; margin: 0; }
.ctg-rule-switch label { display: inline-flex; align-items: center; gap: .45rem;
  font-weight: 600; }
@media (max-width: 700px) { .ctg-rules { grid-template-columns: 1fr; } }
/* Duplicates console: keep/keep/dismiss sit on one line per candidate row, and
   each side of a pair shows the detail that tells the two records apart. */
.dup-actions { display: flex; gap: .3rem; flex-wrap: wrap; align-items: center; }
.dup-actions form { display: flex; gap: .3rem; margin: 0; }
.dup-sub { display: block; font-size: .78rem; color: var(--muted); overflow-wrap: anywhere; }
/* Contact discovery (account page): two actions share the Contacts section
   header; the results panel reuses the ctg-screen-panel look. */
.section-actions { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
.contact-scan-pages summary { cursor: pointer; }
.contact-scan-pages ul { list-style: none; margin: .3rem 0 0; padding: 0; }
.contact-scan-pages li { padding: .12rem 0; border-top: 1px dotted var(--line); }
.contact-scan-facts .pill { margin-left: .25rem; }
.contact-scan-offices { list-style: none; margin: 0; padding: 0; }
.contact-scan-offices li { padding: .12rem 0; border-top: 1px dotted var(--line); }
.contact-scan-offices .pill { margin-left: .25rem; }
.scan-archive { margin-left: auto; }
/* Live narration while a scan/refresh runs: the trail of steps under the
   spinner line (contact discovery, manual news refresh). */
.news-refresh-log, .contact-scan-log { list-style: none; margin: 0; padding: 0; }
.news-refresh-log li, .contact-scan-log li { padding: .15rem 0;
  border-top: 1px dotted var(--line); overflow-wrap: anywhere; }

.ctg-trials { display: flex; flex-direction: column; gap: .35rem; margin: .4rem 0 1rem; }
.ctg-trial { border: 1px solid var(--line); border-radius: 8px; padding: .45rem .6rem; background: var(--panel, #fff); }
.ctg-trial summary { cursor: pointer; }
.ctg-trial-body { margin: .5rem 0 .1rem 1.1rem; display: flex; flex-direction: column; gap: .25rem; font-size: .9rem; }

/* A voice-cancelled confirm card stays visible but clearly inert. */
.ai-confirm-cancelled { opacity: .55; }
.ai-confirm-cancelled::after { content: "Cancelled."; display: block; font-size: .8rem;
  color: var(--muted); margin-top: .3rem; }

/* --- User Management (System → Users) ------------------------------------ */
.tier-badge { display: inline-block; padding: .05rem .45rem; border-radius: 999px;
  font-size: .72rem; font-weight: 600; white-space: nowrap; }
.tier-read { background: #eef2f7; color: #4a5768; }
.tier-contribute { background: #e7f4ea; color: #256b34; }
.tier-edit { background: #fdf1e2; color: #8a5a17; }
.tier-admin { background: #f5e8f7; color: #7a3390; }
.role-group-title { margin: .9rem 0 .3rem; font-size: .95rem; }
.role-row { display: grid; grid-template-columns: auto max-content max-content 1fr;
  align-items: center; gap: .55rem; padding: .3rem .2rem; border-bottom: 1px dotted var(--line); }
.role-row:last-of-type { border-bottom: 0; }
.role-row input[type="checkbox"] { width: 1.05rem; height: 1.05rem; min-height: 0; }
.role-name { font-weight: 600; }
.role-desc { color: var(--muted); font-size: .85rem; }
@media (max-width: 720px) { .role-row { grid-template-columns: auto 1fr; }
  .role-desc { grid-column: 1 / -1; } }
.badge-ok { background: #e7f4ea; color: #256b34; }
.badge-off { background: #fdecea; color: #a03027; }
.checkbox-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: .25rem .8rem; }
.checkbox-cell { display: flex; align-items: center; gap: .45rem; padding: .25rem 0; }
.checkbox-cell input[type="checkbox"] { width: 1.05rem; height: 1.05rem; min-height: 0; }
.grant-picker { max-height: 22rem; overflow-y: auto; border: 1px solid var(--line);
  border-radius: 8px; margin-top: .4rem; }
.grant-picker .data-table { border: 0; }
.folder-picker { padding: .4rem .6rem; background: var(--panel); }
.folder-pick-row { display: flex; align-items: center; gap: .45rem; padding: .18rem 0; }
.folder-pick-row input[type="checkbox"] { width: 1rem; height: 1rem; min-height: 0; }

/* --- Folder right-click menu + permissions dialog ------------------------- */
.ctx-menu { position: fixed; z-index: 3000; min-width: 12rem; background: var(--panel, #fff);
  border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 8px 24px rgba(20,30,40,.18);
  padding: .3rem; }
.ctx-menu button { display: block; width: 100%; text-align: left; background: none;
  border: 0; padding: .45rem .6rem; border-radius: 6px; cursor: pointer; font: inherit;
  color: var(--ink); }
.ctx-menu button:hover { background: var(--bg); }
.folder-perms-dialog { border: 1px solid var(--line); border-radius: var(--radius);
  padding: 0; width: min(44rem, 94vw); }
.folder-perms-dialog::backdrop { background: rgba(15, 25, 35, .45); }
/* Restricted CRM accounts: the padlock by the name + the edit-page panel. */
.account-lock { font-size: .7em; vertical-align: .12em; margin-left: .15rem; cursor: help; }
.restrict-panel { margin-top: 1.2rem; }
.restrict-panel .data-table { margin: .6rem 0; }
.restrict-panel .data-table form { margin: 0; }

.folder-add-dialog { width: min(24rem, 94vw); padding: 1.1rem 1.25rem; }
.folder-add-dialog h2 { margin-top: 0; }
.folder-add-dialog input[type="text"] { width: 100%; }
.folder-add-actions { display: flex; gap: .5rem; margin-top: .8rem; }
.folder-perms-body { padding: 1.1rem 1.25rem; max-height: 80vh; overflow-y: auto; }
.folder-perms-body h2 { margin-top: 0; }
.perm-inherited { color: var(--muted); font-size: .85rem; }
.perm-add-row { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin: .4rem 0; }
.perm-add-row select { min-height: 0; padding: .35rem .45rem; }

/* --------------------------------------------------------------------------
   Notifications: topbar bell + the floating draggable tray (base.html) and
   the /notifications/ active+history page. Default corner sits just above
   the AI launcher (#ai-fab-wrap, bottom-right).
   -------------------------------------------------------------------------- */
.notif-count { background: var(--err); color: #fff; border-radius: 999px; font-size: .65rem; padding: 0 .35em; vertical-align: super; margin-left: .1rem; }
.notif-tray { position: fixed; right: 1rem; bottom: 4.75rem; width: min(340px, calc(100vw - 2rem)); z-index: 950; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: 0 8px 24px rgba(31, 41, 51, .18); cursor: grab; }
.notif-tray[hidden] { display: none; }
.notif-tray.dragging { cursor: grabbing; user-select: none; }
.notif-tray-head { display: flex; justify-content: space-between; align-items: center; gap: .5rem; padding: .45rem .75rem; border-bottom: 1px solid var(--line); font-size: .85rem; color: var(--muted); }
.notif-tray-all { text-decoration: none; }
.notif-item { padding: .55rem .75rem; border-bottom: 1px solid var(--line); border-left: 3px solid transparent; }
.notif-item:last-child { border-bottom: none; }
.notif-item.notif-active { border-left-color: var(--brand); }
.notif-item.notif-done { border-left-color: var(--ok); }
.notif-item.notif-error { border-left-color: var(--err); }
.notif-item.notif-cancelled { border-left-color: var(--muted); }
/* Paused: the job stopped because a provider is refusing to serve (a search
   quota, an anti-bot wall — docs/SEARCH_LIMITS.md). Amber, not red: nothing
   failed. The ⏸ icon's class differs from the card's status lane class — as
   .notif-stopped does for .notif-cancelled — so the lane rule can't tint the
   whole card's text. */
.notif-item.notif-paused { border-left-color: var(--warn); }
.notif-stopped { color: var(--muted); }
.notif-pause { color: var(--warn); }
.notif-stop:hover { color: var(--warn); }
.notif-head { display: flex; align-items: baseline; gap: .4rem; }
.notif-title { flex: 1; font-size: .9rem; }
.notif-x { background: none; border: none; cursor: pointer; color: var(--muted); font: inherit; font-size: .9rem; padding: 0 .15rem; line-height: 1; }
.notif-x:hover { color: var(--err); }
.notif-detail { font-size: .85rem; margin-top: .15rem; overflow-wrap: anywhere; }
.notif-meta { margin-top: .15rem; }
.notif-ok { color: var(--ok); }
.notif-err { color: var(--warn); }
.notif-spin { display: inline-block; width: .65em; height: .65em; border: 2px solid var(--brand); border-top-color: transparent; border-radius: 50%; animation: notifspin 1s linear infinite; }
@keyframes notifspin { to { transform: rotate(360deg); } }
.notif-page-item { max-width: 620px; background: var(--panel); border: 1px solid var(--line); border-left-width: 3px; border-radius: var(--radius); margin-bottom: .5rem; }

/* Grouped child rows inside a notification card (e.g. each account's outcome
   in the bulk contact scan). Scroll-capped so a big job stays a small card. */
.notif-kids { margin-top: .3rem; border-top: 1px dashed var(--line); padding-top: .3rem;
  max-height: 9.5rem; overflow-y: auto; }
.notif-kid { display: flex; align-items: baseline; gap: .35rem; font-size: .82rem;
  padding: .12rem 0; }
.notif-kid a { text-decoration: none; }
.notif-kid .muted { overflow-wrap: anywhere; }

/* System → Web Search: the live provider-refusal panel (docs/SEARCH_LIMITS.md
   §8). Same amber lane as a paused notification card, because it is the same
   condition seen from the administrator's side. */
.ws-block { border-left: 3px solid var(--warn); }
.ws-block-reason { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .85rem;
  background: var(--panel-2, #f6f8fa); border: 1px solid var(--line); border-radius: 8px;
  padding: .5rem .7rem; overflow-wrap: anywhere; }

/* --- "Scan for Contacts" page (Home › Accounts, admins) ------------------- */
/* The two scan lanes render as Data-Quality-style cards; these are just the
   job-title form's own bits (category/scope radios + the title textarea). */
.title-scan-cats { border: 0; margin: .6rem 0 .35rem; padding: 0; }
.title-scan-cats label { display: inline-flex; align-items: center; gap: .3rem;
  margin-right: 1rem; }
.title-scan-cats legend { margin-bottom: .25rem; }
#title-scan-list { width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo,
  Consolas, monospace; font-size: .85rem; }
.title-scan-knobs .knob-input { width: 5.5rem; margin-left: .35rem; }
.title-scan-queries { margin: .25rem 0 .5rem 1.2rem; padding: 0; }
.title-scan-queries li { padding: .12rem 0; }
.title-scan-queries code { overflow-wrap: anywhere; }

/* --- Campaign email broadcasts (docs/CRM_CAMPAIGNS.md) -------------------- */
/* Broadcast/delivery status pills extend the shared .pill vocabulary
   (.pill-draft/.pill-cancelled already exist). */
.pill-scheduled { background: #e8f0fe; color: #1a56db; }
.pill-sending   { background: #fdf6e3; color: var(--warn); }
.pill-sent      { background: #e7f6ee; color: var(--ok); }
.pill-paused    { background: #fdf6e3; color: var(--warn); }
.pill-queued    { background: #eef2f7; color: #5b6b7b; }
.pill-retrying  { background: #fdf6e3; color: var(--warn); }
.pill-bounced, .pill-failed { background: #fdecea; color: var(--danger, #b42318); }
.pill-suppressed { background: #f0f1f3; color: var(--muted); }
/* The contact "Executive" badge (VP and above) — amber, like the star. */
.pill-exec { background: #fdf6e3; color: var(--warn); }

.broadcast-review { grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); align-items: start; }
.broadcast-checklist { list-style: none; margin: 0 0 1rem; padding: 0; }
.broadcast-checklist li { padding: .3rem 0; }
.broadcast-progress-row { display: flex; justify-content: space-between; gap: .75rem;
  align-items: baseline; margin-bottom: .5rem; flex-wrap: wrap; }
.broadcast-stats { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; margin-top: .75rem; }
.broadcast-stat b { font-size: 1.25rem; margin-right: .3rem; }
.broadcast-stat span { color: var(--muted); font-size: .85rem; }
.broadcast-events { list-style: none; margin: 0; padding: 0; }
.broadcast-events li { padding: .3rem 0; border-bottom: 1px solid var(--line); }
.broadcast-events li:last-child { border-bottom: 0; }

/* Marketing email preview: sandboxed iframe so stored HTML renders without
   running in the app's origin; the text fallback keeps author line breaks. */
.email-preview { width: 100%; min-height: 22rem; border: 1px solid var(--line);
  border-radius: 10px; background: #fff; }
.email-preview-text { white-space: pre-wrap; background: var(--panel-2, #f6f8fa);
  border: 1px solid var(--line); border-radius: 10px; padding: .8rem; }

/* Template gallery (docs/CRM_CAPABILITY_GAPS.md D4): the "start from one of
   these" strip above the email list. Cards, not rows — a template is picked
   by recognising it, and a table of names is not recognisable. */
.tmpl-gallery { display: grid; gap: .6rem; margin: .3rem 0 1rem;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
.tmpl-card { border: 1px solid var(--line); border-radius: 10px; padding: .7rem;
  background: var(--panel, #fff); display: flex; flex-direction: column;
  gap: .35rem; }
.tmpl-card h4 { margin: 0; font-size: .95rem; }
.tmpl-card p { margin: 0; }
.tmpl-card .btn { align-self: flex-start; margin-top: auto; }

/* The broadcast form's folded-away UTM builder (D5) — open only when the send
   is actually tagged, so the common case stays a short form. */
.utm-builder { border: 1px solid var(--line); border-radius: 10px;
  padding: .6rem .8rem; margin: .6rem 0; background: var(--panel-2, #f6f8fa); }
.utm-builder summary { cursor: pointer; font-weight: 600; }
.utm-builder p { margin: .5rem 0; }

/* Account data-quality (docs/ACCOUNT_ENRICHMENT.md): the website verdict
   pills on the account page + the discovered-address evidence list. */
.pill-site-ok      { background: #e7f6ee; color: var(--ok); }
.pill-site-invalid { background: #fdeceb; color: var(--err); }
/* A deciphered format its own bounced guesses call into question. */
.pill-format-question { background: #fdf6e3; color: var(--warn); }
.email-samples { display: inline-block; margin-left: .4rem; font-size: .85rem; }
.email-samples > summary { cursor: pointer; color: var(--muted); }
.email-samples ul { margin: .3rem 0 .2rem; padding-left: 1.1rem; }
.email-samples li { margin: .15rem 0; }
.email-samples li a { margin-left: .35rem; font-size: .8rem; }

/* Query builder (docs/CRM_SEGMENTS.md): reusable drag & drop field → filter
   canvas (static/js/query-builder.js) + the segment pages that host it. */
.qb-layout { display: grid; grid-template-columns: minmax(15rem, 19rem) 1fr;
  gap: 1rem; align-items: start; margin: 1rem 0; }
@media (max-width: 900px) { .qb-layout { grid-template-columns: 1fr; } }
.qb-palette { background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .9rem; position: sticky; top: calc(var(--topbar-h) + 1rem); }
.qb-palette-head { display: flex; align-items: center; gap: .6rem; margin-bottom: .6rem; }
.qb-filter { flex: 1; min-width: 0; border: 1px solid var(--line); border-radius: 6px;
  padding: .3rem .5rem; font: inherit; font-size: .85rem; }
.qb-groups { max-height: 26rem; overflow-y: auto; }
.qb-group h4 { margin: .6rem 0 .3rem; font-size: .78rem; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); }
.qb-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
.qb-chip { border: 1px solid var(--line); background: var(--bg); color: var(--ink);
  border-radius: 999px; padding: .22rem .65rem; font: inherit; font-size: .85rem;
  cursor: grab; touch-action: none; }
.qb-chip:hover { border-color: var(--crm); color: var(--crm); }
.qb-palette-hint { color: var(--muted); font-size: .8rem; margin: .6rem 0 0; }
.qb-ghost { position: fixed; z-index: 1200; pointer-events: none; background: var(--panel);
  border: 1px solid var(--crm); border-radius: 999px; padding: .25rem .7rem;
  font-size: .85rem; box-shadow: 0 6px 18px rgba(0,0,0,.18); opacity: .92; }
.qb-zones { display: flex; flex-direction: column; gap: .9rem; }
.qb-zone { background: var(--panel); border: 2px dashed var(--line);
  border-radius: var(--radius); padding: .8rem .9rem; transition: border-color .15s, background .15s; }
.qb-zone-over { border-color: var(--crm); background: #f2fbf5; }
.qb-zone-head { display: flex; align-items: baseline; gap: .6rem; margin-bottom: .5rem; }
.qb-zone-hint { color: var(--muted); font-size: .8rem; }
.qb-zone-empty { color: var(--muted); font-size: .85rem; margin: .2rem 0;
  text-align: center; padding: .5rem; }
.qb-zone-filled .qb-zone-empty { display: none; }
/* Conditions shrink to their content and flow left-to-right, wrapping onto
   new lines — a dropped field never grabs the zone's whole width. */
.qb-conds { display: flex; flex-wrap: wrap; align-items: flex-start; gap: .45rem; }
.qb-cond { display: inline-flex; align-items: center; gap: .55rem; flex-wrap: wrap;
  max-width: 100%;
  border: 1px solid var(--line); border-radius: 8px; padding: .4rem .6rem; background: var(--bg); }
.qb-grip { cursor: grab; color: var(--muted); touch-action: none; user-select: none; }
.qb-cond-field { font-weight: 600; font-size: .9rem; }
.qb-op, .qb-value { border: 1px solid var(--line); border-radius: 6px;
  width: auto;                  /* undo the global full-width input/select rule */
  padding: .28rem .45rem; font: inherit; font-size: .85rem; background: var(--panel); }
.qb-value { min-width: 9rem; }
input[type="number"].qb-value { min-width: 5.5rem; width: 6.5rem; }
/* "between" (two boxes) and the behavioural "in the last N days" window. */
.qb-range { display: inline-flex; align-items: center; gap: .35rem; }
.qb-range-sep, .qb-days-label { color: var(--muted); font-size: .8rem; }
.qb-value-part, .qb-days { border: 1px solid var(--line); border-radius: 6px;
  width: auto; padding: .28rem .45rem; font: inherit; font-size: .85rem;
  background: var(--panel); min-width: 5rem; }
.qb-days { width: 6rem; }
/* Segment detail: the hand-pinned membership lists (added / excluded). */
.seg-pin-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 0 1.5rem; }
.seg-pins { list-style: none; margin: .3rem 0 0; padding: 0; }
.seg-pins li { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .3rem 0; border-bottom: 1px solid var(--line); }
.seg-pins li span { flex: 1 1 8rem; }
.qb-remove { margin-left: auto; border: 0; background: none; color: var(--muted);
  font-size: 1.05rem; cursor: pointer; line-height: 1; padding: .1rem .3rem; }
.qb-remove:hover { color: var(--err); }
.qb-note { color: var(--warn); font-size: .85rem; margin: 0; }
.qb-form-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 0 1.25rem; }
.qb-preview { background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .9rem 1rem; margin: 1rem 0; }
.qb-preview-head { display: flex; align-items: baseline; gap: .8rem; flex-wrap: wrap;
  margin-bottom: .5rem; }
.qb-preview-head h3 { margin: 0; font-size: .95rem; }
.qb-preview-count strong { font-size: 1.25rem; }
.qb-preview-error { color: var(--err); font-size: .9rem; }
.table-scroll { overflow-x: auto; }
.qb-definition { margin-bottom: 1.25rem; }
.qb-def-zone { display: flex; align-items: baseline; gap: .45rem; flex-wrap: wrap; }
.qb-def-label { font-size: .75rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em; }
.qb-def-chip { display: inline-block; background: var(--bg); border: 1px solid var(--line);
  border-radius: 999px; padding: .2rem .7rem; font-size: .85rem; }

/* Report builder (docs/CRM_REPORTS.md): the plain-English box, the
   group-by/measures trays, the display-options row and the chart output
   (static/js/report-chart.js, static/js/report-nl.js). */
.entity-picker { margin: 0 0 1rem; }
.entity-picker-label { margin: 0 0 .45rem; }
.entity-cards { display: flex; flex-wrap: wrap; gap: .55rem; }
.entity-card { display: flex; align-items: center; gap: .5rem;
  border: 1px solid var(--line); background: var(--panel); border-radius: 10px;
  padding: .5rem .8rem; cursor: pointer; font: inherit; color: var(--ink); }
.entity-card:hover { border-color: var(--crm); }
.entity-card-active { border-color: var(--crm);
  box-shadow: inset 0 0 0 1px var(--crm); background: #f2fbf5; }
.entity-card-icon { font-size: 1.15rem; }
.entity-card-label { font-weight: 600; font-size: .9rem; }
.entity-card-count { color: var(--muted); font-size: .8rem;
  background: var(--bg); border-radius: 999px; padding: .1rem .5rem; }
.report-nl { background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .8rem 1rem; margin: 0 0 1rem; }
.report-nl-row { display: flex; gap: .6rem; margin-top: .45rem; }
.report-nl-row input { flex: 1; min-width: 0; border: 1px solid var(--line);
  border-radius: 8px; padding: .5rem .7rem; font: inherit; }
.report-nl-status { margin: .5rem 0 0; font-size: .85rem; color: var(--muted); }
.report-nl-error { color: var(--err); }
.qb-zones-split { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem; }
@media (max-width: 900px) { .qb-zones-split { grid-template-columns: 1fr; } }
.qb-zone-add { margin-left: auto; max-width: 11rem; border: 1px solid var(--line);
  border-radius: 6px; padding: .25rem .35rem; font-size: .8rem; color: var(--muted);
  background: var(--panel); }
.report-options { display: flex; gap: 1.25rem; flex-wrap: wrap; align-items: end;
  margin: 1rem 0; }
.report-options p { margin: 0; display: flex; flex-direction: column; gap: .25rem; }
.report-result { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: 1.1rem; align-items: start; }
@media (max-width: 980px) { .report-result { grid-template-columns: 1fr; } }
.report-result-table .data-table td:not(:first-child),
.report-result-table .data-table th:not(:first-child) { text-align: right; }
.report-tiles { display: flex; gap: 1rem; flex-wrap: wrap; margin: .5rem 0 1rem; }
.report-tile { background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .9rem 1.3rem; min-width: 11rem; }
.report-tile strong { display: block; font-size: 1.7rem; }
.report-tile span { color: var(--muted); font-size: .85rem; }
.report-chart svg { width: 100%; height: auto; display: block; }
.chart-label { font-size: 11px; fill: var(--muted); }
.chart-grid { stroke: var(--line); stroke-width: 1; }
.chart-axis { stroke: var(--line); stroke-width: 1.5; }
.chart-hero { font-size: 26px; font-weight: 700; fill: var(--ink); }
.chart-donut { display: flex; gap: 1.1rem; align-items: center; flex-wrap: wrap; }
.chart-donut-svg { max-width: 15rem; }
.chart-legend { list-style: none; margin: 0; padding: 0; display: flex;
  flex-direction: column; gap: .3rem; font-size: .85rem; }
.chart-legend li { display: flex; align-items: center; gap: .45rem; }
.chart-swatch { width: .8rem; height: .8rem; border-radius: 3px; flex: none; }
.chart-tip { position: fixed; z-index: 1300; pointer-events: none;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 6px 18px rgba(15, 23, 42, .18); padding: .45rem .65rem;
  font-size: .85rem; max-width: 20rem; }

/* Report drill-down (static/js/report-drill.js): result rows, stat tiles and
   chart marks are clickable; the records beneath the clicked group land in
   the .report-drill panel below the result. */
.report-result tbody tr[data-drill-key] { cursor: pointer; }
.report-result tbody tr[data-drill-key]:hover td { background: var(--bg); }
.report-tile[data-drill-all] { cursor: pointer; }
.report-tile[data-drill-all]:hover { border-color: var(--crm); }
.chart-drill { cursor: pointer; }
.report-drill-hint { font-size: .8rem; margin: .35rem 0 0; }
.report-drill { background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .9rem 1rem; margin: 1rem 0; }
.report-drill[hidden] { display: none; }
.report-drill-head { display: flex; align-items: baseline; gap: .8rem;
  margin-bottom: .5rem; }
.report-drill-head h3 { margin: 0; font-size: .95rem; }
.report-drill-close { margin-left: auto; border: 0; background: none;
  color: var(--muted); font-size: 1.1rem; cursor: pointer; line-height: 1; }
.report-drill-close:hover { color: var(--err); }

/* Account page — Contacts panel edit toggle (_account_contacts_table/grid). */
.account-contacts-bar { display: flex; align-items: center; gap: .8rem;
  margin: 0 0 .5rem; font-size: .85rem; }
.account-contacts-bar .btn { margin-left: auto; flex: none; }
/* Departure lane in that panel's Status column: the verdict buttons sit quiet
   until the row is hovered, so a table of active people reads as names and
   emails rather than a wall of 🚪. A departed row itself is dimmed — kept for
   history, out of every send. */
.contact-status { white-space: nowrap; }
.contact-status form { display: inline; }
.contact-status .btn { opacity: .35; transition: opacity .12s; }
tr:hover .contact-status .btn, .contact-status .btn:focus { opacity: 1; }
tr.contact-gone td { opacity: .6; }
tr.contact-gone .contact-status { opacity: 1; }
.chart-tip[hidden] { display: none; }

/* Marketing email composer (docs/CRM_CAMPAIGNS.md): variables palette +
   WYSIWYG HTML-body editor + per-recipient segment preview
   (static/js/email-composer.js). */
.mec-layout { display: grid; grid-template-columns: minmax(13rem, 16rem) 1fr;
  gap: 1.1rem; align-items: start; margin: 1rem 0; }
@media (max-width: 900px) { .mec-layout { grid-template-columns: 1fr; } }
.mec-vars { position: sticky; top: calc(var(--topbar-h) + 1rem); }
.mec-vars h3 { margin-top: 0; }
.mec-var-list { display: flex; flex-direction: column; gap: .4rem; margin: .6rem 0; }
.mec-var { display: flex; flex-direction: column; align-items: flex-start; gap: .05rem;
  border: 1px solid var(--line); background: var(--bg); border-radius: 8px;
  padding: .4rem .6rem; cursor: grab; text-align: left; }
.mec-var:hover { border-color: var(--crm); }
.mec-var:active { cursor: grabbing; }
.mec-var-name { font-weight: 600; font-size: .9rem; }
.mec-var-token { font-size: .72rem; color: var(--muted); word-break: break-all; }
.mec-var-group { margin: .9rem 0 .3rem; font-size: .72rem; font-weight: 700;
  color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
/* Live footer identity: what every broadcast appends, and where to fix it. */
.mec-footer-card { border: 1px solid var(--line); border-radius: 8px;
  background: var(--bg); padding: .55rem .7rem; }
.mec-footer-card p { margin: 0 0 .45rem; }
.mec-footer-line { font-size: .82rem; line-height: 1.45; }
/* Valid drop surfaces light up while a variable is dragged over them. */
.mec-drop-over { outline: 2px dashed var(--crm); outline-offset: 2px; }
.mec-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 0 1rem; }
.mec-field { margin: 0 0 1rem; }
/* Editor chrome: toolbar over a white canvas — email clients render on
   white, so the authoring surface should too. */
.mec-editor { border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel); overflow: hidden; }
.mec-toolbar { display: flex; flex-wrap: wrap; gap: .15rem; align-items: center;
  padding: .3rem .35rem; border-bottom: 1px solid var(--line); background: var(--bg); }
.mec-tool { border: 1px solid transparent; background: none; border-radius: 6px;
  min-width: 1.9rem; width: auto; padding: .25rem .45rem; font-size: .85rem;
  cursor: pointer; color: var(--ink); }
.mec-tool:hover { border-color: var(--line); background: var(--panel); }
.mec-tool:disabled { opacity: .35; cursor: default; }
.mec-tool[aria-pressed="true"], .mec-tool.mec-tool-on { background: var(--crm);
  border-color: var(--crm); color: #fff; }
.mec-tool-b { font-weight: 700; }
.mec-tool-i { font-style: italic; }
.mec-tool-u { text-decoration: underline; }
.mec-block { width: auto; padding: .2rem .3rem; font-size: .85rem; }
.mec-toolbar-sep { width: 1px; align-self: stretch; background: var(--line);
  margin: .15rem .25rem; }
.mec-toolbar-right { margin-left: auto; font-family: ui-monospace, Menlo, Consolas, monospace; }
.mec-editor-area { min-height: 16rem; padding: .9rem 1.1rem; background: #fff;
  color: #111; overflow-y: auto; }
.mec-editor-area:focus { outline: none; }
.mec-editor-area[hidden] { display: none; }
.mec-linkbar { display: flex; gap: .4rem; align-items: center; padding: .35rem;
  border-bottom: 1px solid var(--line); background: var(--panel); }
.mec-linkbar[hidden] { display: none; }
.mec-linkbar input { flex: 1; width: auto; padding: .3rem .5rem; }
/* Raw-source mode: the backing textarea shown inside the editor frame. */
.mec-editor .mec-html-source { border: 0; border-radius: 0; min-height: 16rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .85rem; }
.mec-editor .mec-html-source[hidden] { display: none; }
/* A/B testing: the Version B panel + the A/B badges used across the
   composer, email detail and broadcast-results pages. */
.mec-ab { margin: 1rem 0; border: 1px solid var(--line);
  border-left: 4px solid var(--crm); border-radius: 10px;
  background: var(--panel); padding: .8rem 1rem; }
.mec-ab[hidden] { display: none; }
.mec-ab-title { margin: 0 0 .3rem; font-size: 1rem; }
.mec-ab-badge { display: inline-block; min-width: 1.3rem; text-align: center;
  padding: .05rem .35rem; border-radius: 6px; background: var(--crm);
  color: #fff; font-size: .78rem; font-weight: 700; }
.mec-ab-toggle label { display: inline-flex; align-items: center; gap: .45rem;
  cursor: pointer; }
.mec-ab-pick label { display: inline-flex; align-items: center; gap: .25rem;
  cursor: pointer; margin-left: .35rem; }
.mec-ab-pick[hidden] { display: none; }
/* Preview panel: segment picker + the rendered recipient page. */
.mec-preview { margin-top: 1.25rem; border: 1px solid var(--line);
  border-radius: 10px; background: var(--panel); padding: .9rem 1rem; }
.mec-preview[hidden] { display: none; }
.mec-preview-head { display: flex; align-items: center; gap: .8rem;
  flex-wrap: wrap; margin-bottom: .6rem; }
.mec-preview-head h3 { margin: 0; font-size: .95rem; }
.mec-preview-pick { display: flex; align-items: center; gap: .4rem;
  font-size: .9rem; color: var(--muted); }
.mec-preview-pick select { width: auto; max-width: 18rem; padding: .3rem .5rem; }
.mec-preview-nav { display: flex; align-items: center; gap: .7rem;
  margin-bottom: .6rem; }
.mec-preview-who { display: flex; flex-direction: column; gap: .1rem;
  min-width: 0; }
.mec-preview-subject { margin: .3rem 0 .5rem; }

/* --- Traffic & Analytics (System) — docs/ANALYTICS.md ---------------------- */
/* Log tables want the whole viewport: pages opt out of the 1100px column via
   {% block content_class %} content-wide{% endblock %} (hook in base.html). */
.content-wide { max-width: none; }
/* Log viewer: dense, monospace, IP-first table. */
.log-table-wrap { overflow-x: auto; }
.log-table { width: 100%; border-collapse: collapse; font-size: .8rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.log-table th { position: sticky; top: 0; background: #fafbfc; color: var(--muted);
  font-weight: 600; font-size: .72rem; text-transform: uppercase; letter-spacing: .02em;
  text-align: left; padding: .35rem .5rem; border-bottom: 1px solid var(--line); }
.log-table td { padding: .3rem .5rem; border-bottom: 1px solid #f0f2f5;
  white-space: nowrap; vertical-align: top; }
.log-table td.wrap { white-space: normal; word-break: break-all; }
.log-ip { font-weight: 700; }
.lane-pill { display: inline-block; padding: 0 .45rem; border-radius: 999px;
  font-size: .72rem; font-weight: 600; line-height: 1.5; }
.lane-edge { background: #fde8e8; color: #9b1c1c; }
.lane-lan { background: #e1effe; color: #1e429f; }
.lane-internal { background: #f0f1f3; color: var(--muted); }
.status-2xx { color: #046c4e; }
.status-3xx { color: #1e429f; }
.status-4xx { color: #9b6700; }
.status-5xx { color: #9b1c1c; font-weight: 700; }
.traffic-filters { display: flex; gap: .5rem; flex-wrap: wrap; align-items: flex-end;
  margin-bottom: .9rem; }
.traffic-filters label { display: block; font-size: .72rem; color: var(--muted);
  margin-bottom: .15rem; }
.traffic-filters input, .traffic-filters select { padding: .35rem .5rem;
  border: 1px solid var(--line); border-radius: 7px; font-size: .85rem; }

/* --- Analytics dashboard --- */
/* KPI stat tiles: value + label; values wear ink, never a data color. */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 1rem; }
.kpi-value { font-size: 1.8rem; font-weight: 700; }
.kpi-unit { font-size: .95rem; font-weight: 400; color: var(--muted); }
.kpi-lanes { display: flex; flex-wrap: wrap; gap: .25rem; padding: .55rem 0 .3rem; }
/* Requests-over-time chart. Series colors are existing tokens (brand blue vs
   err red — the pair passes the CVD + contrast checks on the white panel);
   the grid is a recessive solid hairline one step off the surface. Narrow
   screens scroll the chart instead of shrinking its text to illegibility. */
.chart-scroll { overflow-x: auto; }
.chart-svg { display: block; width: 100%; height: auto; min-width: 640px; }
.chart-svg text { fill: var(--muted); font-size: 11px; }
.chart-grid { stroke: #edf0f4; stroke-width: 1; }
.chart-axis { stroke: var(--line); stroke-width: 1; }
.chs-other { fill: var(--brand); }
.chs-edge { fill: var(--err); }
.chart-hover { fill: transparent; }
.chart-hover:hover { fill: rgba(31, 111, 235, .07); }
.chart-legend { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap;
  color: var(--muted); font-size: .82rem; }
.chart-swatch { display: inline-block; width: 10px; height: 10px; border-radius: 3px;
  vertical-align: -1px; }
.swatch-edge { background: var(--err); }
.swatch-other { background: var(--brand); }
/* Route heatmap: sequential one-hue ramp (brand blue family), light→dark,
   log-binned. The cold end is deliberately faint — heat means "barely used" —
   and the printed hits/users text on every tile keeps color from being the
   only channel. Tiles sit on a --bg grid so the 2px gaps do the separating. */
.heat-ns { margin-bottom: 1rem; }
.heat-ns:last-child { margin-bottom: 0; }
.heat-ns-head { margin-bottom: .35rem; font-size: .85rem; }
.heat-grid { display: flex; flex-wrap: wrap; gap: 2px; background: var(--bg);
  padding: 2px; border-radius: 8px; }
.heat-tile { flex: 1 1 130px; min-width: 130px; max-width: 240px;
  padding: .4rem .55rem; border-radius: 4px; }
.heat-1 { background: #dbe9fc; }
.heat-2 { background: #b6d3f8; }
.heat-3 { background: #8cb6f2; }
.heat-4 { background: #5e93e9; }
.heat-5 { background: #2f6fdb; }
.heat-6 { background: #174ea6; }
.ht-name { font-weight: 600; font-size: .78rem; overflow-wrap: anywhere; }
.ht-meta { font-size: .72rem; color: var(--muted); }
/* Text on tinted fills switches with the fill's luminance so it always reads. */
.heat-2 .ht-meta, .heat-3 .ht-meta, .heat-4 .ht-meta { color: var(--ink); }
.heat-5, .heat-6 { color: #fff; }
.heat-5 .ht-meta, .heat-6 .ht-meta { color: rgba(255, 255, 255, .85); }
/* Cold features (URLconf coverage) */
.cov-cols { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 1rem; }
.cov-ns-name { margin: 0 0 .3rem; font-size: .85rem; }
.cov-list-label { font-size: .72rem; color: var(--muted); text-transform: uppercase;
  letter-spacing: .02em; margin: .35rem 0 .2rem; }
.badge-rare { background: #fdf6e3; color: var(--warn); }
/* Desire paths: journey chip-chains + side-by-side entry/exit tables. */
.journey-row { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap;
  padding: .45rem 0; border-bottom: 1px solid #f0f2f5; }
.journey-row:last-child { border-bottom: none; }
.route-chip { display: inline-block; padding: .1rem .5rem; background: #eef2f7;
  border: 1px solid var(--line); border-radius: 999px; font-size: .78rem; }
.journey-arrow { color: var(--muted); }
.journey-count { margin-left: .25rem; }
.side-by-side { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 700px) { .side-by-side { grid-template-columns: 1fr; } }
/* Numeric table cells: right-aligned, tabular figures (columns only —
   never on the big KPI values). */
.data-table th.num, .data-table td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Contacts bulk-edit grid (freecrm/contact_bulk_edit.html + contact-grid.js):
   inputs sit flush in the cells until hovered/focused; the status cell flashes
   ✓ on save and holds the first validation message on error. */
.bulk-grid-wrap { overflow-x: auto; }
.bulk-grid td { padding: .2rem .4rem; white-space: nowrap; }
.bulk-grid tr[hidden] { display: none; }
.bulk-grid input {
  width: 100%; min-width: 6.5rem; font: inherit; color: inherit;
  border: 1px solid transparent; border-radius: 6px; background: transparent;
  padding: .3rem .45rem;
}
.bulk-grid input[name="phone"] { min-width: 5rem; }
.bulk-grid input:hover { border-color: var(--line); }
.bulk-grid input:focus {
  border-color: var(--brand); background: var(--panel); outline: none;
  box-shadow: 0 0 0 2px rgba(31, 111, 235, .15);
}
.bulk-grid input[aria-invalid] { border-color: var(--err); background: #fdeceb; }
.bulk-grid .grid-number a { font-variant-numeric: tabular-nums; }
.bulk-grid .grid-greeting, .bulk-grid .grid-account {
  max-width: 12rem; overflow: hidden; text-overflow: ellipsis; }
.bulk-grid .grid-actions { white-space: nowrap; }
.bulk-grid .grid-exec { text-align: center; }
.grid-x {
  border: none; background: none; color: var(--err); cursor: pointer;
  font-size: .95rem; line-height: 1; padding: .3rem .5rem; border-radius: 6px;
}
.grid-x:hover { background: #fdeceb; }
.grid-x.armed { background: var(--err); color: #fff; font-size: .8rem; }
.grid-status { font-size: .78rem; margin-left: .25rem; }
.grid-status-saved { color: var(--ok); }
.grid-status-saving { color: var(--muted); }
.grid-status-error { color: var(--err); }
tr.row-error td { background: #fdeceb33; }
/* Grid column headers: each name is a click-to-filter target (the search
   input swaps in and stays while it holds text) and the ⇅/▲/▼ button beside
   it sorts client-side. The col-check lane feeds the Delete-selected bar. */
.bulk-grid th .grid-head, #events-grid th .grid-head { display: flex; align-items: center; gap: .2rem; }
.bulk-grid .grid-col-name, .bulk-grid .grid-sort,
#events-grid .grid-col-name, #events-grid .grid-sort {
  border: none; background: none; padding: 0; cursor: pointer;
  font: inherit; color: inherit; text-transform: inherit;
  letter-spacing: inherit; white-space: nowrap;
}
.bulk-grid .grid-col-name:hover, #events-grid .grid-col-name:hover { color: var(--ink); text-decoration: underline dotted; }
.bulk-grid .grid-sort, #events-grid .grid-sort { padding: 0 .2rem; border-radius: 4px; }
.bulk-grid .grid-sort:hover, #events-grid .grid-sort:hover { color: var(--ink); background: var(--line); }
.bulk-grid .grid-sort.active, #events-grid .grid-sort.active { color: var(--brand); }
.bulk-grid th .grid-col-filter, #events-grid th .grid-col-filter {
  width: 8.5rem; min-width: 0; padding: .15rem .4rem;
  font-size: .8rem; font-weight: 400; text-transform: none;
  letter-spacing: normal; border: 1px solid var(--brand);
  border-radius: 6px; background: var(--panel);
}
#events-grid .grid-col-name[hidden],
#events-grid th .grid-col-filter[hidden],
.bulk-grid .grid-col-name[hidden],
.bulk-grid th .grid-col-filter[hidden] { display: none; }
.bulk-grid input[type="checkbox"] { width: auto; min-width: 0; padding: 0; }
.bulk-grid .grid-created { font-variant-numeric: tabular-nums; }
/* Resizable columns: contact-grid.js pins the measured auto layout into a
   <colgroup> and adds .grid-sized, after which the column widths (not the
   content) decide the layout — so cell content must clip and the inputs must
   be free to shrink below their comfortable minimum. */
.bulk-grid.grid-sized { table-layout: fixed; }
.bulk-grid.grid-sized td { overflow: hidden; text-overflow: ellipsis; }
.bulk-grid.grid-sized input { min-width: 0; }
.bulk-grid.grid-sized .grid-greeting,
.bulk-grid.grid-sized .grid-account { max-width: none; }
.bulk-grid th { position: relative; }
.bulk-grid .grid-resize {
  position: absolute; top: 0; right: 0; width: 7px; height: 100%;
  cursor: col-resize; touch-action: none; user-select: none;
}
.bulk-grid .grid-resize:hover, .bulk-grid .grid-resize.dragging {
  background: var(--brand); opacity: .5;
}
body.grid-resizing { cursor: col-resize; user-select: none; }
.bulk-bar .btn.armed { background: var(--err); border-color: var(--err); color: #fff; }

/* --------------------------------------------------------------------------
   Leads workspace (docs/CRM_LEADS.md): status/rating pills extend the shared
   .pill vocabulary; the path bar, stat tiles, aging row tints, convert cards
   and settings console all reuse the panel/table bases. */
.pill-new          { background: #e8f1fd; color: #2563eb; }
.pill-working      { background: #fdf6e3; color: var(--warn); }
.pill-nurturing    { background: #eae3fb; color: #6b46c1; }
.pill-qualified    { background: #e7f6ee; color: var(--ok); }
.pill-disqualified { background: #f0f1f3; color: var(--muted); }
.pill-hot          { background: #fdeceb; color: var(--err); }
.pill-warm         { background: #fdf6e3; color: var(--warn); }
.pill-cold         { background: #e8f1fd; color: #2563eb; }

.lead-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
              gap: .75rem; margin: 0 0 1rem; }
.lead-stat { background: var(--panel); border: 1px solid var(--line);
             border-radius: var(--radius); padding: .6rem .9rem; }
.lead-stat h2 { margin: 0; font-size: 1.5rem; }
.lead-stat p { margin: 0; color: var(--muted); font-size: .8rem; }
.lead-sources-report { margin: -0.25rem 0 1rem; }
.lead-sources-report summary { cursor: pointer; color: var(--muted); font-size: .85rem; }
.lead-sources-report .data-table { margin-top: .5rem; max-width: 560px; }

.lead-bulk-bar { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap;
                 margin: 0 0 .6rem; }
.lead-bulk-bar select { width: auto; }

/* Account health + corporate family (docs/CRM_CAPABILITY_GAPS.md B1-B4).
   Both panels reuse .card / .broadcast-stats; only the grade badge and the
   subsidiary list need anything of their own. The grade colours follow the
   message vocabulary — green good, amber wobbling, red in trouble. */
.account-health-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.account-health-score b { font-size: 1.35rem; }
.health-grade { display: inline-block; min-width: 1.9rem; text-align: center;
  padding: .15rem .5rem; border-radius: 8px; font-weight: 700; font-size: 1.05rem; }
.health-grade-a { background: #e7f6ee; color: var(--ok); }
.health-grade-b { background: #eaf2fd; color: var(--brand-dark); }
.health-grade-c { background: #fdf6e3; color: var(--warn); }
.health-grade-d { background: #fdeceb; color: var(--err); }
.account-family-crumbs { margin: 0 0 .5rem; }
.account-family-heading { font-size: .95rem; margin: .9rem 0 .3rem; }
.account-family-children { list-style: none; margin: 0; padding: 0; }
.account-family-children li { padding: .2rem 0; }

/* Aging cues: amber past the staleness threshold, red at twice it. */
.data-table tr.lead-age-amber td { background: #fdf6e3; }
.data-table tr.lead-age-red td { background: #fdeceb; }

/* The status path bar — click an open pill to move the lead there. */
.lead-path { display: flex; gap: .35rem; flex-wrap: wrap; align-items: center;
             margin: .25rem 0; }
.lead-path-step { display: inline-block; border: 1px solid var(--line);
                  background: var(--panel); color: var(--muted);
                  padding: .3rem .85rem; border-radius: 999px; font-size: .85rem;
                  text-decoration: none; cursor: pointer; }
button.lead-path-step:hover, a.lead-path-step:hover { border-color: var(--crm, var(--brand)); color: var(--ink); }
.lead-path-step.done { background: #e7f6ee; border-color: #bfe3d0; color: var(--ok); }
.lead-path-step.current { background: var(--crm, var(--brand)); border-color: transparent;
                          color: #fff; font-weight: 600; cursor: default; }
.lead-path-qualify { color: var(--ok); font-weight: 600; }
.lead-path-disqualify { color: var(--err); }
.lead-guidance { color: var(--muted); font-size: .85rem; margin: 0 0 1rem; }

.lead-converted-banner, .lead-dq-banner { border: 1px solid var(--line);
  border-radius: var(--radius); padding: .6rem .9rem; margin: 0 0 1rem;
  font-size: .9rem; }
.lead-converted-banner { background: #e7f6ee; }
.lead-dq-banner { background: #f0f1f3; color: var(--muted); }

/* Detail/settings card grid; .panel supplies the chrome. */
.lead-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
              gap: 1rem; align-items: start; margin: 0 0 1.25rem; }
.lead-cards .panel h3 { margin: 0 0 .5rem; display: flex; align-items: center;
                        gap: .5rem; flex-wrap: wrap; }
.lead-cards .panel h4 { margin: .6rem 0 .2rem; font-size: .85rem; color: var(--muted); }
.lead-cards .panel ul { margin: .2rem 0; padding-left: 1.1rem; }
.lead-dl { display: grid; grid-template-columns: auto 1fr; gap: .25rem .75rem; margin: 0; }
.lead-dl dt { color: var(--muted); font-size: .85rem; }
.lead-dl dd { margin: 0; }
.lead-score-table td { padding: .3rem .5rem; }
.lead-dupes-panel { border-color: #e8d9a8; }

/* Convert page: choice cards stack; radio lists lose their bullets. */
.convert-form .panel { margin: 0 0 1rem; max-width: 720px; }
.convert-form .panel > p { margin: .25rem 0; }
.convert-form ul { list-style: none; margin: .3rem 0; padding: 0; }
.convert-form ul li { padding: .15rem 0; }
.convert-form input[type="radio"], .convert-form input[type="checkbox"] { width: auto; margin-right: .4rem; }
.convert-newname { margin: .4rem 0 0; }
.convert-opp-fields { margin-left: 1.4rem; }
.field-error { color: var(--err); font-size: .85rem; }

.campaign-members summary { cursor: pointer; color: var(--muted); font-size: .85rem; }
.campaign-members ul { margin: .3rem 0; padding-left: 1.2rem; }

/* Hottest-contacts journey: wheat vs chaff. Human engagement reads bold at
   full ink; scanner/bot/security steps recede — lighter and italic — so the
   handoff between real touches is legible at a glance. Ink token (not
   literal black) keeps both themes honest. */
.journey-human { color: var(--ink); font-weight: 700; font-style: normal; }
.journey-machine { color: #9aa7b2; font-style: italic; }
.journey-machine code, .journey-machine a { color: inherit; }

/* Engagement grid pills: toggled-off classes dim but stay clickable. */
.verdict-pills { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin: .4rem 0 .6rem; }
.verdict-pills .pill { cursor: pointer; border: none; font: inherit; font-size: .8rem; }
.verdict-pills .pill[aria-pressed="false"] { opacity: .3; }
.verdict-pills select { margin-left: auto; }

/* Campaign / broadcast scorecard (services.campaign_metrics + the
   _campaign_scorecard.html partial). Only the big letter grade has no reusable
   class — the rates reuse .broadcast-stats/.broadcast-stat, the box reuses
   .card. Grade colours ride the shared --ok/--warn/--err tokens. */
.scorecard-title { margin-top: 0; }
.scorecard { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 1rem 1.4rem; }
.scorecard-grade { font-size: 3rem; font-weight: 700; line-height: .95; text-align: center; min-width: 2ch; }
.scorecard-grade small { display: block; font-size: .68rem; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--muted); }
.scorecard-body { flex: 1 1 18rem; }
.scorecard-reason { margin: 0 0 .5rem; font-size: 1.05rem; }
.scorecard-bad { color: var(--err); }
.grade-a, .grade-b { color: var(--ok); }
.grade-c { color: var(--warn); }
.grade-d, .grade-f { color: var(--err); }

/* Contact scoring, lifecycle & org chart (docs/CRM_CAPABILITY_GAPS.md A1–A5).
   Reuses .panel/.feature-panel/.pill/.badge — only the grade badge, the two
   figures and the tree's indent guides need anything of their own. */
.score-panel .score-grade { font-size: 1rem; font-weight: 700; letter-spacing: .04em; }
.score-figures { display: flex; flex-wrap: wrap; gap: .2rem 1.6rem; margin: .5rem 0 .4rem; }
.score-figures dt { flex: 0 0 auto; font-weight: 600; color: var(--muted);
  font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; align-self: center; }
.score-figures dd { flex: 0 0 auto; margin: 0 1.4rem 0 .4rem; font-size: 1.35rem; font-weight: 700; }
.score-figures dd .small { font-size: .78rem; font-weight: 400; }
.score-reason { margin: .1rem 0 .4rem; }

/* Buying roles read as a row of quiet tags; the lifecycle stage warms up as
   the relationship does, so a customer never looks like a subscriber. */
.pill-role { background: var(--panel-2, #eef1f5); color: var(--muted); margin-right: .25rem; }
/* …and on the contact form the seven checkboxes flow across instead of
   stacking into a column taller than the rest of the form (same treatment as
   .ctg-choices; the form framework ids the wrapper after the field). */
#id_buying_roles { display: flex; flex-wrap: wrap; gap: .15rem 1.1rem; }
#id_buying_roles label { display: inline-flex; align-items: center; gap: .4rem;
  font-size: .9rem; white-space: nowrap; }
.pill-stage-subscriber { background: #eef2f7; color: #5b6b7b; }
.pill-stage-lead { background: #e8f0fe; color: #1a56db; }
.pill-stage-mql { background: #e8f1fd; color: #2563eb; }
.pill-stage-sql { background: #eae3fb; color: #6b46c1; }
.pill-stage-opportunity { background: #fdf6e3; color: var(--warn); }
.pill-stage-customer { background: #e7f6ee; color: var(--ok); }
.pill-stage-evangelist { background: #d8f3e4; color: var(--ok); }
.pill-stage-other { background: #f0f1f3; color: var(--muted); }
.pill-cold { background: #e8f1fd; color: #2563eb; margin-left: .35rem; }

/* Org chart: nested lists with a single indent guide per level — no JS, no
   library, and it degrades to a plain indented list without the border. */
.org-chart { list-style: none; margin: .3rem 0 0; padding: 0; }
.org-chart .org-chart { margin-left: .55rem; padding-left: .9rem;
  border-left: 1px solid var(--line); }
.org-node { padding: .18rem 0; }
.org-node .pill { margin-left: .3rem; }

/* Consent & preferences (docs/CRM_PREFERENCES.md).

   The preference centre is the only page in the app a stranger ever sees, and
   they arrive from a mail client on whatever device is to hand — so it stays
   narrow, the tap targets are whole rows rather than the checkbox alone, and
   nothing here depends on JS. Everything else reuses .panel / .data-table. */
.pref-centre { max-width: 40rem; margin: 0 auto; }
.pref-panel { margin-bottom: 1rem; }
.pref-panel h2 { margin-top: 0; font-size: 1.05rem; }
.pref-topic { display: flex; gap: .6rem; align-items: flex-start;
  padding: .55rem .2rem; border-top: 1px solid var(--line); cursor: pointer; }
.pref-topic:first-of-type { border-top: 0; }
.pref-topic input { margin-top: .2rem; flex: 0 0 auto; }
.pref-paused { border-left: 3px solid var(--warn); }
.pref-pause { display: flex; flex-wrap: wrap; gap: .4rem; }
/* The one irreversible control on the page: folded away, and only ever opened
   deliberately. `details` is doing the work, so it needs no JS. */
.pref-leave > summary { cursor: pointer; padding: .2rem 0; }
.pref-leave[open] { border-left: 3px solid var(--err); }
.pref-leave ul, .pref-leave label { display: block; }
.pref-leave input[type="text"] { width: 100%; max-width: 22rem; margin: .3rem 0; }

/* Contact record's consent panel — a plain table plus one warning badge. */
.consent-table td { vertical-align: top; }
.consent-panel .badge-warn { background: #fdecea; color: #a03027; }

/* Journeys / drip sequences (docs/CRM_JOURNEYS.md).

   The step builder is a plain ordered list: each step is a row with up/down
   buttons and a folded-away edit form. No drag-and-drop library — reordering
   two adjacent rows does not justify a dependency, and the buttons work on a
   phone where dragging does not. */
.jrn-fieldset { border: 1px solid var(--line); border-radius: var(--radius);
  padding: .8rem 1rem; margin: 0 0 1rem; }
.jrn-fieldset legend { padding: 0 .4rem; font-weight: 600; }

.jrn-steps { list-style: none; margin: 0; padding: 0; counter-reset: jrn; }
.jrn-step { border: 1px solid var(--line); border-radius: var(--radius);
  padding: .6rem .8rem; margin-bottom: .5rem; background: var(--panel); }
.jrn-step-empty { border-style: dashed; }
.jrn-step-head { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
.jrn-step-no { display: inline-flex; align-items: center; justify-content: center;
  width: 1.6rem; height: 1.6rem; border-radius: 999px; background: var(--panel-2, #eef1f5);
  font-size: .8rem; font-weight: 700; flex: 0 0 auto; }
.jrn-step-counts { display: flex; gap: .3rem; }
.jrn-step-actions { margin-left: auto; display: flex; gap: .25rem; }
.jrn-step-stats { margin: .35rem 0 0; }
.jrn-step-edit > summary, .jrn-step-add > summary { cursor: pointer; padding: .3rem 0;
  color: var(--muted); font-size: .9rem; }

/* Per-type step settings: every group is rendered and CSS shows only the ones
   belonging to the selected type, so the whole interaction is one inline
   onchange and it survives an HTMX swap with nothing to re-bind. `hidden`
   would lose to a later display rule, so this is display-driven throughout. */
.jstep-form .jstep-fields { display: none; }
.jstep-form[data-type="send_email"] .jstep-fields[data-for="send_email"],
.jstep-form[data-type="wait"] .jstep-fields[data-for="wait"],
.jstep-form[data-type="condition"] .jstep-fields[data-for="condition"],
.jstep-form[data-type="task"] .jstep-fields[data-for="task"],
.jstep-form[data-type="goal"] .jstep-fields[data-for="goal"] { display: block; }

.jrn-enroll-hits { list-style: none; margin: .4rem 0; padding: 0; }
.jrn-enroll-hits li { display: flex; gap: .6rem; align-items: center;
  justify-content: space-between; padding: .3rem 0;
  border-top: 1px solid var(--line); }

/* Journey + enrollment status pills (extend the shared vocabulary). */
.pill-active { background: #e7f6ee; color: var(--ok); }
.pill-paused { background: #fdf6e3; color: var(--warn); }
.pill-exited { background: #eef2f7; color: #5b6b7b; }
.pill-failed { background: #fdeceb; color: var(--err); }

/* --- Notifications area: section tabs + What's New ------------------------- */
/* Two pages under /notifications/: what your jobs are doing, and what changed
   in the app. The tabs are the only navigation between them. */
.subnav { display: flex; gap: .25rem; border-bottom: 1px solid var(--line); margin: 0 0 1.25rem; flex-wrap: wrap; }
.subnav-tab {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .5rem .85rem; text-decoration: none; color: var(--muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px; font-size: .92rem;
}
.subnav-tab:hover { color: var(--ink); }
.subnav-tab.is-active { color: var(--brand); border-bottom-color: var(--brand); font-weight: 600; }
.subnav-badge {
  background: var(--brand); color: #fff; border-radius: 999px;
  font-size: .68rem; font-weight: 700; padding: .05rem .4rem; line-height: 1.5;
}

/* The topbar flag. Sits beside the bell but is its own thing — the bell counts
   running jobs, this counts unread release notes. It is only in the DOM while
   something is unread, so it never becomes furniture people stop seeing. */
.whats-new-flag { text-decoration: none; margin-left: .15rem; }

/* ---- Webmail (docs/WEBMAIL.md) ------------------------------------------- */
/* Same separate-affordance rule as the flag above: this one counts unread
   mail on the user's pseudo-mailbox, and exists only while something is unread. */
.mail-flag { text-decoration: none; margin-left: .15rem; }
.mail-table .mail-dir-col { width: 1.5rem; text-align: center; color: var(--muted); }
.mail-row-unread td { font-weight: 600; }
.mail-row-unread .mail-dir-col { color: var(--brand); }
.mail-regarding { margin: -0.5rem 0 .75rem; }
.pill-bounced { background: #fdecea; color: #a4262c; }
/* On the meeting but not yet invited — dashed, so the chip reads as pending
   rather than as a guest Google has already emailed. */
.attendee-uninvited { border-style: dashed; opacity: .8; }
.mail-body { white-space: pre-wrap; overflow-wrap: anywhere; }
.mail-thread-item { padding: .5rem .9rem; margin-bottom: .4rem; }
.mail-thread-item p { margin: 0; }
.mail-compose-form input[type="email"] { width: 100%; font: inherit; }
.mail-compose-form .page-actions { display: flex; gap: .5rem;
  justify-content: flex-end; margin-top: 1rem; }

.rn-caught-up { margin: -.5rem 0 1.25rem; }

/* Each release is a <details>: collapsed by default so the page opens as an
   index you can scan. No JS — the element does the work. */
.rn-release {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  margin: 0 0 .6rem;
}
/* An unread release is marked down its edge rather than by tinting the whole
   card: the notes still have to be comfortable to read, and a page of coloured
   panels is a page nobody reads. */
.rn-release.is-new { border-left: 3px solid var(--brand); }

.rn-summary-row {
  display: flex; align-items: flex-start; gap: .6rem;
  padding: .85rem 1.1rem; cursor: pointer; list-style: none;
  border-radius: var(--radius);
}
/* Suppress the native disclosure triangle in both engines — we draw our own
   caret so it can sit where the text does and rotate on open. */
.rn-summary-row::-webkit-details-marker { display: none; }
.rn-summary-row::marker { content: ""; }
.rn-summary-row:hover { background: var(--bg); }
.rn-summary-row:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

.rn-caret {
  color: var(--muted); font-size: .8rem; line-height: 1.6;
  transition: transform .12s ease; transform-origin: 50% 50%; flex: none;
}
.rn-release[open] > .rn-summary-row > .rn-caret { transform: rotate(90deg); }
.rn-release[open] > .rn-summary-row { border-bottom: 1px solid var(--line); border-radius: var(--radius) var(--radius) 0 0; }

.rn-head-text { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.rn-title { font-size: 1.05rem; font-weight: 600; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.rn-meta { color: var(--muted); font-size: .8rem; display: flex; gap: .4rem; flex-wrap: wrap; }
.rn-version {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--bg); border: 1px solid var(--line); border-radius: 5px; padding: 0 .35em;
}

.rn-body { padding: 1rem 1.25rem 1.15rem; }
.rn-blurb { margin: 0 0 1rem; color: var(--ink); max-width: 68ch; }
.rn-section { margin: 0 0 1rem; }
.rn-section:last-child { margin-bottom: 0; }
.rn-section h3 {
  margin: 0 0 .4rem; font-size: .78rem; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); font-weight: 700;
}
.rn-list { margin: 0; padding-left: 1.1rem; }
.rn-list li { margin: 0 0 .45rem; line-height: 1.55; max-width: 76ch; }
.rn-list li:last-child { margin-bottom: 0; }
.rn-foot { margin-top: 1.5rem; }

@media (max-width: 640px) {
  .rn-summary-row { padding: .75rem .85rem; }
  .rn-body { padding: .85rem 1rem 1rem; }
}

/* --- Secure client upload (docs/CLIENT_UPLOADS.md) --- */
/* Staff dialog: red chrome when the recipient is not a known contact. */
.client-upload-dialog { width: min(40rem, 94vw); }
.client-upload-dialog.cu-danger { border: 2px solid var(--err); }
.client-upload-dialog.cu-danger::backdrop { background: rgba(120, 20, 10, .45); }
.cu-override-warn { margin: .5rem 0; }
.cu-ack-row { display: flex; align-items: center; gap: .45rem; margin: .5rem 0; font-size: .9rem; }
.cu-ack-row input[type="checkbox"] { width: auto; }
.cu-form-row { display: flex; gap: 1rem; flex-wrap: wrap; }
.cu-form-row > div { flex: 1 1 10rem; }
.cu-size-custom { display: flex; gap: .4rem; align-items: center; margin-top: .35rem; }
.cu-size-custom[hidden] { display: none; }  /* display:flex would defeat [hidden] */
.cu-size-custom input { width: 6rem; }
.cu-size-custom select { width: auto; }
.cu-secret-block { margin: .9rem 0; }
.cu-secret-block > label { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 700; }
.cu-secret-row { display: flex; gap: .5rem; align-items: center; margin-top: .3rem; }
.cu-secret-row input { flex: 1; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .85rem; }
.cu-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 700; letter-spacing: .08em; }
.cu-links-head { margin: 1.2rem 0 .4rem; font-size: .95rem; }
.cu-links-table td { vertical-align: middle; }

/* Link activity page */
.cu-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: .6rem 1.2rem; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: .9rem 1.1rem; margin: 1rem 0; }
.cu-facts .subtitle { display: block; font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; }
.cu-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin: 1rem 0; }
.cu-warn-tag { color: var(--err); font-size: .85rem; }
.cu-newcode .cu-code { font-size: 1.15rem; margin: 0 .3rem; }
.cu-error-line { color: var(--err); }
.cu-st-active { background: #e8f3ec; color: var(--ok); }
.cu-st-revoked, .cu-st-expired { background: #eef1f4; color: var(--muted); }
.cu-st-killed, .cu-st-locked, .cu-st-failed { background: #fdeceb; color: var(--err); }
.cu-st-receiving, .cu-st-processing { background: #e7effc; color: var(--brand); }
.cu-st-complete { background: #e8f3ec; color: var(--ok); }

/* Progress bars (portal + activity page) */
.cu-bar { height: 8px; background: #e6ebf0; border-radius: 999px; overflow: hidden; min-width: 7rem; }
.cu-bar-fill { height: 100%; width: 0; background: var(--brand); border-radius: 999px; transition: width .25s ease; }
.cu-bar-fill.cu-fill-good { background: var(--ok); }
.cu-bar-fill.cu-fill-bad, .cu-bar-bad { background: var(--err); }

/* External portal (write-only page) */
.cu-portal-card { max-width: 44rem; }
.cu-req { margin: .8rem 0 1.1rem; padding-left: 1.2rem; }
.cu-req li { margin: 0 0 .45rem; line-height: 1.5; }
.cu-access-form { display: flex; flex-direction: column; gap: .55rem; margin: 1rem 0; }
.cu-access-form input { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 1.1rem; letter-spacing: .12em; text-transform: uppercase; }
.cu-access-hint { margin-top: .8rem; }
.cu-drop { border: 2px dashed var(--line); border-radius: var(--radius); padding: 1.6rem 1rem; text-align: center; display: flex; flex-direction: column; gap: .4rem; align-items: center; background: var(--panel); cursor: pointer; }
.cu-drop.cu-drop-hot { border-color: var(--brand); background: #eef4fe; }
/* .auth-card .btn forces full-width login-style buttons — undo inside the
   portal card, but keep the access form's Continue full-width. */
.cu-portal-card .btn { width: auto; margin-top: 0; }
.cu-access-form .btn { width: 100%; margin-top: .75rem; }
.cu-files { list-style: none; margin: 1rem 0 0; padding: 0; }
.cu-file { border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); padding: .7rem .9rem; margin-bottom: .6rem; display: flex; flex-direction: column; gap: .35rem; }
.cu-file-name { font-weight: 600; overflow-wrap: anywhere; }
.cu-file-phase { font-size: .9rem; }
.cu-file-phase.cu-good { color: var(--ok); font-weight: 600; }
.cu-file-phase.cu-bad { color: var(--err); font-weight: 600; }
.cu-file-actions { display: flex; gap: .5rem; }

/* ------------------------------------------------------------------ */
/* Guided walk-throughs (static/js/tour.js + static/js/tours/*)       */
/* ------------------------------------------------------------------ */
/* Topbar Help button: hidden until a tour matches the current page. */
.tour-help-btn { background: none; border: 1px solid var(--line); border-radius: 999px;
  padding: .15rem .65rem; color: var(--muted); cursor: pointer; font: inherit;
  font-size: .9rem; white-space: nowrap; }
.tour-help-btn:hover { border-color: var(--brand); color: var(--ink); }
.tour-help-btn[hidden] { display: none; }

/* The spotlight: a fixed cutout whose huge box-shadow dims everything
   else, plus a white ring so the highlight never relies on dim alone. */
.tour-spot { position: fixed; z-index: 5000; pointer-events: none; border-radius: 8px;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .85), 0 0 0 200vmax rgba(15, 23, 42, .55);
  transition: left .25s ease, top .25s ease, width .25s ease, height .25s ease; }

/* Full-screen click shield: the tour can narrate but never operate the
   page (demo-only). Clicking the dim advances to the next step. */
.tour-blocker { position: fixed; inset: 0; z-index: 5001; cursor: pointer; }

/* Step popover */
.tour-pop { position: fixed; z-index: 5002; width: min(340px, calc(100vw - 24px));
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 12px 40px rgba(15, 23, 42, .35); padding: .9rem 1rem 1rem; }
.tour-pop-center { left: 50% !important; top: 45% !important; transform: translate(-50%, -50%); }
.tour-pop-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.tour-pop-kicker { font-size: .75rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; color: var(--brand); }
.tour-x { background: none; border: none; color: var(--muted); cursor: pointer;
  font: inherit; font-size: 1rem; line-height: 1; padding: .1rem .2rem; }
.tour-x:hover { color: var(--ink); }
.tour-pop-title { margin: .35rem 0 .3rem; font-size: 1.02rem; }
.tour-pop-body { color: var(--ink); font-size: .92rem; line-height: 1.5; }
.tour-live { position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; }
.tour-pop-foot { display: flex; align-items: center; justify-content: space-between;
  gap: .6rem; margin-top: .8rem; }
.tour-dots { display: flex; flex-wrap: wrap; gap: 4px; max-width: 9rem; }
.tour-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); }
.tour-dot-on { background: var(--brand); }
.tour-pop-btns { display: flex; gap: .4rem; white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .tour-spot { transition: none; }
}

/* My Profile — Preferences + mail-address panels (templates/accounts/profile.html). */
.pref-side { margin: 1rem 0 .4rem; font-size: .95rem; }
.pref-side:first-of-type { margin-top: .25rem; }
.addr-input { display: flex; align-items: center; gap: .35rem; max-width: 26rem; }
.addr-input input { flex: 1; min-width: 0; }
.addr-domain { color: var(--muted); white-space: nowrap; }
