/* Primera Works internal UI — dense, keyboard-driven, restrained.
 * ui_ux.md §1: density-first for staff doing this all day. §5: AA contrast,
 * visible focus, color is never the only carrier of meaning, motion is
 * respectful. §6: the UI disappearing so the user can trust the data is the
 * design success.
 *
 * Visual language: Linear / GitHub-Enterprise calm. Sans-serif body with
 * monospace utility for IDs, hashes, currency, timestamps, codes. A persistent
 * left sidebar in the brand color carries the nav. Cards on a slate-50 page
 * background; subtle shadows; restrained accents. Honest-state badges keep
 * their semantic palette + icons so color is never the sole signal. */

/* ============================================================================
 * Tokens — swap --brand and --accent here when the real palette arrives.
 * ========================================================================= */

:root {
  /* Brand — sampled from the PWX logo set. Swap here to retheme the whole UI. */
  --brand:          #2c3947;   /* PWX slate-navy (logo background) */
  --brand-deep:     #1f2a35;   /* darker shade for sidebar hovers/active */
  --brand-soft:     #e5edf0;   /* tinted background for active rows etc. */
  --accent:         #6bb6c2;   /* PWX teal — links-on-dark, focus on dark, active indicator */
  --accent-soft:    #d4eaef;   /* tinted teal for badge backgrounds */

  /* Neutrals */
  --fg:             #0f172a;   /* slate-900 */
  --fg-muted:       #64748b;   /* slate-500 */
  --fg-subtle:      #94a3b8;   /* slate-400 */
  --bg:             #ffffff;
  --bg-alt:         #f8fafc;   /* slate-50 — page background */
  --surface:        #ffffff;   /* card surface */
  --border:         #e2e8f0;   /* slate-200 */
  --border-strong:  #cbd5e1;   /* slate-300 */
  --row-hover:      #f1f5f9;   /* slate-100 */
  --zebra:          #fafbfc;

  /* Semantic */
  --danger:         #b42318;
  --danger-bg:      #fef3f2;
  --danger-border:  #fecdca;
  --warning:        #8a5a00;
  --warning-bg:     #fffaeb;
  --warning-border: #fde2a5;
  --ok:             #027a48;
  --ok-bg:          #ecfdf3;
  --ok-border:      #a6f4c5;
  --info:           #0b4a90;
  --info-bg:        #eff6ff;
  --info-border:    #b9d6f5;

  /* Shape */
  --radius:         6px;
  --radius-lg:      8px;
  --shadow-sm:      0 1px 2px rgba(15, 23, 42, 0.04), 0 1px 3px rgba(15, 23, 42, 0.06);
  --shadow-md:      0 2px 4px rgba(15, 23, 42, 0.06), 0 4px 12px rgba(15, 23, 42, 0.08);

  /* Layout */
  --sidebar-w:      208px;

  /* Typography */
  --font-sans:      system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono:      ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

/* ============================================================================
 * Reset + base
 * ========================================================================= */

* {
  box-sizing: border-box;
}
html,
body {
  margin: 0;
  padding: 0;
}
html {
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--fg);
  background: var(--bg-alt);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
body {
  min-height: 100vh;
}

h1, h2, h3, h4 {
  margin: 0 0 8px;
  color: var(--fg);
  font-weight: 600;
  line-height: 1.3;
}
h1 { font-size: 20px; }
h2 { font-size: 16px; }
h3 { font-size: 14px; }
h4 { font-size: 13px; color: var(--fg-muted); text-transform: uppercase; letter-spacing: 0.04em; }

p { margin: 0 0 8px; }
a {
  color: var(--brand);
  text-decoration: none;
}
a:hover { text-decoration: underline; }

code, time, .currency, .mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
code {
  background: var(--bg-alt);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 0 4px;
  font-size: 0.92em;
}
time {
  font-size: 0.92em;
}

/* Focus is always visible. Floor requirement, not polish (ui_ux.md §5).
   Uses the brand teal so the ring reads clearly on both light pages and the
   dark sidebar. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* Motion is decoration here, never load-bearing (ui_ux.md §5). */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ============================================================================
 * App shell — sidebar + main content
 * ========================================================================= */

body.app-shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: 100vh;
  background: var(--bg-alt);
}

/* --- Sidebar -------------------------------------------------------------- */

.app-sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--brand);
  color: #fff;
  border-right: 1px solid var(--brand-deep);
  /* Width transition kept short so collapse/expand feels responsive but isn't
     showy. `prefers-reduced-motion` zeroes it out via the global rule. */
  transition: width 0.15s ease;
}
.app-sidebar__brand {
  padding: 16px 18px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  min-height: 64px;
  display: flex;
  align-items: center;
}
.app-sidebar__brand a {
  display: flex;
  align-items: center;
  color: #fff;
  text-decoration: none;
}
.app-sidebar__brand a:hover { text-decoration: none; }
/* Default state (expanded sidebar): the wide wordmark is visible, the
   square icon is hidden. The collapsed-state rules at the bottom flip them. */
.brand-logo {
  display: block;
  user-select: none;
}
.brand-logo--full {
  height: 32px;
  width: auto;
  max-width: 100%;
}
.brand-logo--icon {
  display: none;
  height: 28px;
  width: 28px;
  /* The placeholder pwx-icon.svg uses the same wide viewBox as the wordmark;
     contain keeps it from stretching when the slot is square. A square icon
     file replacing it will simply fill the slot edge-to-edge. */
  object-fit: contain;
}
/* Kept for compatibility with `Primera Works` text in the auth shell. */
.brand-wordmark {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.92);
}

.app-sidebar__nav {
  flex: 1;
  padding: 10px 8px;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.app-sidebar__nav .nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  color: rgba(255, 255, 255, 0.82);
  text-decoration: none;
  border-radius: var(--radius);
  border-left: 3px solid transparent;
  margin-left: -3px;
  font-size: 13.5px;
  position: relative;
}
.nav-item__icon {
  flex-shrink: 0;
  color: rgba(255, 255, 255, 0.6);
  transition: color 0.1s ease;
}
.app-sidebar__nav .nav-item:hover .nav-item__icon,
.app-sidebar__nav .nav-item[aria-current="page"] .nav-item__icon {
  color: rgba(255, 255, 255, 0.95);
}
.nav-item__label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.app-sidebar__nav .nav-item:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  text-decoration: none;
}
.app-sidebar__nav .nav-item[aria-current="page"] {
  background: rgba(255, 255, 255, 0.10);
  color: #fff;
  border-left-color: var(--accent);
  font-weight: 600;
}
.app-sidebar__nav .nav-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Section sub-navigation (e.g. Sales → Pipeline/Companies/Contacts/
   Triage/Activity). Rendered indented beneath the active top-level
   item, replacing the former in-page tab strip. */
.app-sidebar__subnav {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 2px 0 4px 0;
  padding-left: 34px; /* align under the parent item's label, past its icon */
}
.app-sidebar__subnav .nav-subitem {
  display: block;
  padding: 5px 10px;
  color: rgba(255, 255, 255, 0.62);
  text-decoration: none;
  border-radius: var(--radius);
  border-left: 2px solid transparent;
  margin-left: -2px;
  font-size: 12.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.app-sidebar__subnav .nav-subitem:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  text-decoration: none;
}
.app-sidebar__subnav .nav-subitem[aria-current="page"] {
  color: #fff;
  border-left-color: var(--accent);
  font-weight: 600;
}
.app-sidebar__subnav .nav-subitem:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
/* Collapsed rail shows icons only — the text sub-nav would be
   meaningless without labels, so hide it. */
html.sidebar-collapsed .app-sidebar__subnav {
  display: none;
}

.nav-badge {
  display: inline-flex;
  align-items: center;
  padding: 1px 6px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  background: var(--warning-bg);
  color: var(--warning);
  border: 1px solid var(--warning-border);
  border-radius: 999px;
  white-space: nowrap;
}

.app-sidebar__footer {
  padding: 8px 12px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.sidebar-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 28px;
  padding: 0;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius);
  color: rgba(255, 255, 255, 0.7);
  cursor: pointer;
  transition: background 0.1s ease, color 0.1s ease;
}
.sidebar-toggle:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.18);
}
.sidebar-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.sidebar-toggle__icon--expand { display: none; }

.app-sidebar__principal {
  padding: 10px 14px 14px;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.85);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.app-sidebar__principal .principal-line {
  font-family: var(--font-sans);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.78);
  word-break: break-word;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sidebar-signout {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.sidebar-signout > svg { flex-shrink: 0; }
.sidebar-signout__label { white-space: nowrap; }

/* --- Collapsed state — icon-only sidebar -------------------------------- */
/* Toggled via `html.sidebar-collapsed` (pre-paint script in <head> sets it
   from localStorage so there is no flash on navigation). */

html.sidebar-collapsed body.app-shell {
  grid-template-columns: 56px 1fr;
}
html.sidebar-collapsed .brand-wordmark,
html.sidebar-collapsed .nav-item__label,
html.sidebar-collapsed .nav-badge,
html.sidebar-collapsed .principal-line,
html.sidebar-collapsed .sidebar-signout__label {
  display: none;
}
html.sidebar-collapsed .app-sidebar__brand {
  padding: 14px 0;
  display: flex;
  justify-content: center;
  min-height: 56px;
}
html.sidebar-collapsed .app-sidebar__brand a {
  justify-content: center;
  align-items: center;
  gap: 0;
}
/* Swap which logo is visible when collapsed: full hides, icon shows. */
html.sidebar-collapsed .brand-logo--full { display: none; }
html.sidebar-collapsed .brand-logo--icon { display: block; }
html.sidebar-collapsed .app-sidebar__nav {
  padding: 10px 6px;
}
html.sidebar-collapsed .app-sidebar__nav .nav-item {
  justify-content: center;
  padding: 8px 0;
  border-left: none;
  margin-left: 0;
  gap: 0;
}
html.sidebar-collapsed .app-sidebar__nav .nav-item[aria-current="page"] {
  background: rgba(255, 255, 255, 0.10);
  /* Collapsed: a left accent stripe is hard to see in a centered icon row.
     Switch to a full-bleed amber dot under the icon. */
  position: relative;
}
html.sidebar-collapsed .app-sidebar__nav .nav-item[aria-current="page"]::after {
  content: "";
  position: absolute;
  bottom: 4px;
  left: 50%;
  transform: translateX(-50%);
  width: 14px;
  height: 2px;
  border-radius: 1px;
  background: var(--accent);
}
/* Surface the warn-badge as a small dot on the Account icon when 2FA isn't
   set up. Color isn't the only carrier — the title attribute still says it. */
html.sidebar-collapsed .app-sidebar__nav .nav-item:has(.nav-badge)::before {
  content: "";
  position: absolute;
  top: 4px;
  right: 8px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--warning);
  border: 1.5px solid var(--brand);
}
html.sidebar-collapsed .app-sidebar__footer {
  padding: 6px;
}
html.sidebar-collapsed .sidebar-toggle__icon--collapse { display: none; }
html.sidebar-collapsed .sidebar-toggle__icon--expand { display: inline-flex; }
html.sidebar-collapsed .app-sidebar__principal {
  padding: 6px;
  align-items: center;
}
html.sidebar-collapsed .sidebar-signout {
  width: 32px;
  height: 32px;
  justify-content: center;
  border-radius: var(--radius);
}
html.sidebar-collapsed .sidebar-signout:hover {
  background: rgba(255, 255, 255, 0.06);
}

/* A text-style button that reads as a link on the dark sidebar. */
.link-on-dark {
  background: none;
  border: none;
  color: var(--accent);
  cursor: pointer;
  padding: 0;
  font: inherit;
  text-decoration: underline;
}
.link-on-dark:hover { color: #fff; }
.link-on-dark:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* --- Main column --------------------------------------------------------- */

.app-content {
  display: flex;
  flex-direction: column;
  min-width: 0;            /* allow children with overflow to behave */
}
.app-content__topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 24px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  min-height: 44px;
}
/* Secondary locator; the canonical title is the body's <h1>. Kept here as a
   persistent breadcrumb-style anchor for when the body scrolls. */
.app-content__title {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--fg-muted);
  letter-spacing: 0.01em;
  display: flex;
  align-items: center;
  gap: 6px;
}
.app-content__title::before {
  content: "";
  display: inline-block;
  width: 3px;
  height: 14px;
  background: var(--accent);
  border-radius: 2px;
}
.app-content__meta {
  font-size: 11.5px;
}
.app-content__main {
  padding: 20px 24px 32px;
  flex: 1;
}

/* ============================================================================
 * Pre-auth shell (sign-in, MFA wall)
 * ========================================================================= */

body.auth-shell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: var(--bg-alt);
  padding: 24px;
}
.auth-shell__brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  margin-bottom: 24px;
}
.auth-shell__brand:hover { text-decoration: none; }
.auth-shell__brand .brand-logo--full {
  height: 56px;
  width: auto;
}
/* The icon variant is hidden in the auth shell — we always show the full
   wordmark there since space isn't constrained. */
.auth-shell__brand .brand-logo--icon { display: none; }
.auth-shell__main {
  width: 100%;
  max-width: 420px;
}
.auth-shell__main .auth-page {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 28px 28px 24px;
}
.auth-shell__main .auth-page h1 {
  font-size: 18px;
  margin-bottom: 16px;
}
.auth-shell__footer {
  margin-top: 16px;
  font-size: 11.5px;
  color: var(--fg-muted);
}

/* ============================================================================
 * Flash messages + banners
 * ========================================================================= */

.flash {
  margin: 0 0 16px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.flash--error {
  background: var(--danger-bg);
  border-color: var(--danger-border);
  color: var(--danger);
}
.flash--success {
  background: var(--ok-bg);
  border-color: var(--ok-border);
  color: var(--ok);
}
.flash--info {
  background: var(--info-bg);
  border-color: var(--info-border);
  color: var(--info);
}

.banner {
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin: 0 0 16px;
  background: var(--surface);
}
.banner--warn {
  background: var(--warning-bg);
  border-color: var(--warning-border);
  color: var(--warning);
}
.banner--danger {
  background: var(--danger-bg);
  border-color: var(--danger-border);
  color: var(--danger);
}
.banner--info {
  background: var(--info-bg);
  border-color: var(--info-border);
  color: var(--info);
}
.banner a { color: inherit; text-decoration: underline; }

/* ============================================================================
 * Forms
 * ========================================================================= */

form .field {
  margin-bottom: 12px;
}
form label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--fg-muted);
  margin-bottom: 4px;
}
form input,
form select,
form textarea {
  font: inherit;
  font-family: var(--font-sans);
  padding: 6px 10px;
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--fg);
  width: 100%;
  max-width: 520px;
  border-radius: var(--radius);
  min-height: 32px;
  transition: border-color 0.1s ease, box-shadow 0.1s ease;
}
form input:focus,
form select:focus,
form textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(107, 182, 194, 0.22); /* tinted teal focus ring */
}
form textarea {
  resize: vertical;
  min-height: 64px;
  line-height: 1.4;
}
form .inline {
  display: inline;
}
form .form-actions {
  margin-top: 16px;
  display: flex;
  gap: 8px;
  align-items: center;
}

/* ============================================================================
 * Buttons
 * ========================================================================= */

button {
  font: inherit;
  font-family: var(--font-sans);
  font-weight: 500;
  padding: 6px 14px;
  min-height: 32px;
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--fg);
  cursor: pointer;
  border-radius: var(--radius);
  transition: background 0.1s ease, border-color 0.1s ease, box-shadow 0.1s ease;
}
button:hover {
  background: var(--row-hover);
  border-color: var(--fg-subtle);
}
button:active {
  background: var(--border);
}
button:disabled {
  background: var(--bg-alt);
  color: var(--fg-subtle);
  cursor: not-allowed;
}

button.primary {
  background: var(--brand);
  color: #fff;
  border-color: var(--brand);
  box-shadow: var(--shadow-sm);
}
button.primary:hover {
  background: var(--brand-deep);
  border-color: var(--brand-deep);
}

button.danger {
  background: var(--surface);
  color: var(--danger);
  border-color: var(--danger-border);
}
button.danger:hover {
  background: var(--danger);
  color: #fff;
  border-color: var(--danger);
}

button.link {
  background: none;
  border: none;
  color: var(--brand);
  cursor: pointer;
  padding: 0;
  min-height: 0;
  font: inherit;
  text-decoration: underline;
}
button.link:hover { color: var(--brand-deep); background: none; }

/* Sign-out (and similar) anchored on the dark sidebar — must beat
   `button.link` on specificity (tag + class > .link-on-dark alone). */
button.link-on-dark {
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.92);
  cursor: pointer;
  padding: 0;
  min-height: 0;
  font: inherit;
  font-size: 12px;
  text-decoration: underline;
  text-underline-offset: 2px;
}
button.link-on-dark:hover {
  color: #fff;
  background: none;
}
button.link-on-dark:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ============================================================================
 * Tables
 * ========================================================================= */

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
caption {
  text-align: left;
  padding: 8px 12px;
  font-weight: 600;
  caption-side: top;
}
th, td {
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
tbody tr:last-child td { border-bottom: none; }
th {
  background: var(--bg-alt);
  font-weight: 600;
  font-size: 12px;
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border);
}
tbody tr:nth-child(even) {
  background: var(--zebra);
}
tbody tr:hover {
  background: var(--row-hover);
}

/* Empty state — deliberate composition, not a lonely dashed strip. Pages
   may add a CTA `<p>` or `<a>` below the message paragraph. */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  text-align: center;
  padding: 36px 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  color: var(--fg-muted);
}
.empty::before {
  content: "○";
  display: block;
  font-size: 28px;
  color: var(--fg-subtle);
  line-height: 1;
  margin-bottom: 4px;
}
.empty p, .empty a, .empty button {
  margin: 0;
}
.empty a, .empty button {
  color: var(--brand);
}

/* ============================================================================
 * Key/value list
 * ========================================================================= */

dl.kv {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 6px 20px;
  margin: 0;
  font-size: 13.5px;
}
dl.kv dt {
  color: var(--fg-muted);
  font-weight: 500;
}
dl.kv dd {
  margin: 0;
}

/* ============================================================================
 * Cards / sections used inside pages
 * ========================================================================= */

.card,
.create-form,
section.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: 16px 18px;
  margin: 0 0 16px;
}
.card h2,
section.card h2 {
  margin-top: 0;
  margin-bottom: 12px;
  font-size: 15px;
}
.card h3,
section.card h3 {
  margin-top: 0;
  margin-bottom: 8px;
}

/* <details> as a "collapsible card" (e.g. the leads create form). */
details.create-form {
  padding: 0;
  overflow: hidden;
}
details.create-form > summary {
  list-style: none;
  padding: 12px 16px;
  cursor: pointer;
  background: var(--bg-alt);
  border-bottom: 1px solid transparent;
  font-weight: 600;
}
details.create-form[open] > summary {
  border-bottom-color: var(--border);
}
details.create-form > summary::-webkit-details-marker { display: none; }
details.create-form > form { padding: 16px; }

.row-actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* ============================================================================
 * Badges
 * ========================================================================= */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  background: var(--bg);
  color: var(--fg);
  white-space: nowrap;
  line-height: 1.4;
}
.badge--ok {
  background: var(--ok-bg);
  border-color: var(--ok-border);
  color: var(--ok);
}
.badge--warn {
  background: var(--warning-bg);
  border-color: var(--warning-border);
  color: var(--warning);
}
.badge--danger {
  background: var(--danger-bg);
  border-color: var(--danger-border);
  color: var(--danger);
}
.badge--muted {
  background: var(--bg-alt);
  border-color: var(--border);
  color: var(--fg-muted);
}
.badge--info {
  background: var(--info-bg);
  border-color: var(--info-border);
  color: var(--info);
}

/* ============================================================================
 * Modal dialogs (confirm)
 * ========================================================================= */

dialog.confirm {
  /* These modals are injected via htmx with the `open` attribute (not
     showModal()), so they render as NON-modal dialogs — i.e. in normal
     document flow. Appended at the end of <body>, that put them near the
     bottom of a long page: open one after scrolling and it appeared
     off-screen / cut off. Pin to the viewport center instead, capped at
     90vh with internal scroll so a tall form is always fully reachable.
     The big spread box-shadow stands in for ::backdrop (which only
     paints for true modal dialogs). */
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  z-index: 1000;
  max-height: 90vh;
  overflow-y: auto;
  padding: 20px 24px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--fg);
  width: auto;
  min-width: min(360px, calc(100vw - 32px));
  max-width: min(560px, calc(100vw - 32px));
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md), 0 0 0 100vmax rgba(15, 23, 42, 0.32);
}
dialog.confirm::backdrop {
  background: rgba(15, 23, 42, 0.32);
}
dialog.confirm h2 {
  margin: 0 0 8px;
  font-size: 16px;
}
.confirm__consequence {
  padding: 8px 0 14px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 14px;
  color: var(--fg);
}
.confirm__actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 14px;
}

/* ============================================================================
 * Page-level error page
 * ========================================================================= */

.page-error {
  padding: 28px 32px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--fg);
  max-width: 640px;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  border-top: 3px solid var(--danger);
}
.page-error__status {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--danger);
  margin-bottom: 6px;
}
.page-error h1 {
  margin: 0 0 12px;
  color: var(--fg);
  font-size: 20px;
}
.page-error__message {
  padding: 10px 14px;
  background: var(--danger-bg);
  border: 1px solid var(--danger-border);
  border-radius: var(--radius);
  color: var(--danger);
  font-family: var(--font-mono);
  font-size: 12.5px;
  margin: 0 0 12px;
  word-break: break-word;
}
.page-error__actions {
  margin-top: 18px;
  display: flex;
  align-items: center;
  gap: 16px;
}
.page-error__actions .btn-link {
  display: inline-block;
  padding: 7px 16px;
  background: var(--brand);
  color: #fff;
  text-decoration: none;
  border-radius: var(--radius);
  font-weight: 500;
}
.page-error__actions .btn-link:hover {
  background: var(--brand-deep);
  text-decoration: none;
}

/* ============================================================================
 * Tabs
 * ========================================================================= */

.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 16px;
}
/* The settings-tabs strip sits above any page-specific sub-tabs (e.g. the
   catalog page's offerings/templates sub-tabs). Keep them visually distinct
   with a tighter bottom margin so the two rows read as one group. */
.tabs.settings-tabs,
.tabs.sales-tabs {
  margin-bottom: 12px;
}
/* Sales sub-nav lives in the left sidebar on desktop (layout.ts), so the
   in-page strip is hidden here. On mobile the rail is icon-only with no
   room for it, so the @media (max-width:768px) block re-shows this strip
   and hides the sidebar sub-nav instead. (Two-class selector beats the
   base `.tabs{display:flex}`.) */
.tabs.sales-tabs {
  display: none;
}

/* People list on the deal detail page — compact stack of person rows in the
   right-column "People" card. */
.people-list {
  list-style: none;
  padding: 0;
  margin: 0 0 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.people-list li {
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
}
.people-list li:last-child {
  border-bottom: none;
}

/* Inline-add forms (company detail's "Add contact" mini-form, etc.) and the
   collapsible "+ Add a new contact" disclosure on the create-deal form.
   Tighter, slightly indented to read as a nested action. */
.inline-add {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed var(--border);
}
details.card-nested {
  margin: 12px 0;
  padding: 10px 12px;
  border: 1px dashed var(--border);
  border-radius: 6px;
  background: var(--bg-alt);
}
details.card-nested > summary {
  cursor: pointer;
  font-weight: 500;
  user-select: none;
}
details.card-nested[open] > summary {
  margin-bottom: 10px;
}

/* Filter bar above a list (used on the Contacts tab). Same density as a
   regular .card but with a slightly muted background to read as chrome. */
.filters {
  background: var(--bg-alt);
}

/* ============================================================================
 * Triage queue — Gmail-style keyboard-driven list. The whole point of the
 * triage-first CRM is that humans can clear this queue fast; the styles
 * here optimize for scannability and a visible keyboard cursor.
 * ========================================================================= */

.triage-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 12px;
}

.triage-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  cursor: pointer;
  transition: background 80ms ease, border-color 80ms ease;
}

.triage-row:hover {
  background: var(--bg-alt);
}

.triage-row.is-selected {
  border-color: var(--brand);
  box-shadow: inset 3px 0 0 var(--brand);
}

.triage-row__main {
  flex: 1 1 auto;
  min-width: 0;
}

.triage-row__name {
  font-weight: 500;
  margin-bottom: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.triage-row__meta {
  font-size: 0.9em;
}

.triage-row__match {
  margin-top: 4px;
  font-size: 0.9em;
}

.triage-row__actions {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}

.btn-small {
  padding: 4px 10px;
  font-size: 0.9em;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 4px;
  cursor: pointer;
}

.btn-small:hover {
  background: var(--bg-alt);
  border-color: var(--brand);
}

/* Activity timeline used in the portal project detail. A vertical
 * stack of events with a bullet on the left, action line + actor/
 * timestamp on the right. Renders bottom-padded so the last event
 * doesn't crash into the card edge. */
.activity-timeline {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
}
.activity-timeline__item {
  display: flex;
  gap: 12px;
  padding: 8px 0;
  border-left: 2px solid transparent;
}
.activity-timeline__item + .activity-timeline__item {
  border-top: 1px solid var(--border);
  margin-top: 4px;
}
.activity-timeline__bullet {
  width: 8px;
  height: 8px;
  margin-top: 7px;
  background: var(--accent);
  border-radius: 50%;
  flex: none;
}
.activity-timeline__body {
  flex: 1 1 auto;
  min-width: 0;
}
.activity-timeline__line {
  font-size: 14px;
  line-height: 1.4;
}
.activity-timeline__meta {
  font-size: 12px;
  margin-top: 2px;
}

/* Folder heading inside the portal Files & links card. Groups files
 * by folder label; renders one heading per group followed by its
 * own table. The "Root" heading uses a muted styling so it doesn't
 * compete with real folder names. */
.folder-heading {
  font-size: 14px;
  font-weight: 600;
  color: var(--fg);
  margin: 18px 0 6px;
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.folder-heading:first-of-type {
  margin-top: 8px;
}
.folder-heading--root {
  color: var(--fg-muted);
  font-weight: 500;
  font-style: italic;
}
.folder-heading .muted {
  font-size: 12px;
  font-weight: 400;
}

/* Recipient picker (portal upload / link forms). The global form-input
 * rule above expands every <input> to 100% width, which makes a
 * checkbox render as a huge full-width box. Reset the geometry to
 * native checkbox dimensions and lay out each row as a 3-column flex
 * line: checkbox, contact name, muted email. */
.recipient-picker {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin: 12px 0;
}
.recipient-picker > legend {
  font-weight: 600;
  font-size: 13px;
  padding: 0 6px;
}
.recipient-picker > p.muted {
  margin: 0 0 10px;
  font-size: 13px;
}
.recipient-picker__list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.recipient-picker__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
  cursor: pointer;
}
.recipient-picker__row input[type="checkbox"] {
  /* Override the global form input width rule for checkboxes. */
  width: auto;
  min-height: 0;
  margin: 0;
  flex: none;
}
.recipient-picker__row .recipient-picker__name {
  font-weight: 500;
  flex: 0 0 auto;
}
.recipient-picker__row .recipient-picker__email {
  font-size: 13px;
  flex: 1 1 auto;
}
.recipient-picker__empty {
  margin: 12px 0;
  padding: 12px 14px;
  background: var(--bg-alt);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  font-size: 13px;
}

/* Inline checkbox label (used on the "Email recipients when…" toggle
 * above the picker). Reset width on the checkbox here too — same root
 * cause as above. */
label.checkbox-line {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-weight: 500;
}
label.checkbox-line > input[type="checkbox"] {
  width: auto;
  min-height: 0;
  margin: 0;
  flex: none;
}

/* Destructive variant — same shape as .btn-small but with a danger
 * outline + text color, so an admin clearly sees this is the
 * irreversible action. The Archive button stays in the safe gray
 * style; only Delete picks this up. Hover deepens to a filled red. */
.btn-small.btn-danger {
  color: var(--danger);
  border-color: var(--danger-border);
  background: var(--surface);
}
.btn-small.btn-danger:hover {
  color: #ffffff;
  background: var(--danger);
  border-color: var(--danger);
}

/* Inline keyboard shortcut hint used in the triage subtitle. */
.kbd {
  display: inline-block;
  padding: 1px 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
  background: var(--bg-alt);
  border: 1px solid var(--border);
  border-radius: 3px;
  box-shadow: 0 1px 0 var(--border);
}

/* Small count pill on the Triage sub-tab — soft nudge to clear the
   queue. Reuses the .badge--info palette but lives inline with the tab
   label so it doesn't push tab spacing around. */
.tab-badge {
  display: inline-block;
  margin-left: 4px;
  padding: 0 6px;
  font-size: 0.8em;
  background: var(--brand);
  color: #fff;
  border-radius: 10px;
  font-weight: 500;
  line-height: 1.4;
}
/* Empty queue: render the pill in a quieter palette so 0 reads as
   "clear" rather than as a nudge. */
.tab-badge--zero {
  background: var(--border-strong);
  color: var(--fg-muted);
}

/* Row-action group used on tables that have multiple inline forms
   per row (e.g. mailbox subscription: Sync/Pause/Resume). */
.row-actions {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}
.row-actions form.inline {
  display: inline;
}

/* Security / configuration checklists — used on the Integrations admin
   page to surface operator-attested items (e.g. Application Access
   Policy) the platform can't programmatically verify. */
.checklist {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 16px;
}
.checklist__item {
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg-alt);
}
.checklist__head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}

/* Code blocks (e.g. PowerShell snippet on the Integrations page). The
   inline `<code>` style covers single-token uses; this is for multi-line
   blocks where we want a scrollable rectangle. */
.code-block {
  background: #1e293b;
  color: #f1f5f9;
  border-radius: 4px;
  padding: 12px 14px;
  overflow-x: auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
  line-height: 1.5;
}
.code-block code {
  background: transparent;
  color: inherit;
  padding: 0;
}

/* Promote modal — wider than the default .confirm dialog because the
   company-picker fieldset has three modes and the modal carries more
   form structure than a typical confirm. Selector is dialog.confirm-
   specific so it out-weighs the base `dialog.confirm` width above. */
dialog.confirm.promote-modal {
  width: min(640px, calc(100vw - 32px));
  max-width: min(640px, calc(100vw - 32px));
}

/* AI-suggested field hint — a small sparkle next to fields the LLM
   pre-filled. Tooltip clarifies what it means; the visual is light so
   it reads as a hint, not a warning. */
.ai-hint {
  color: var(--accent);
  font-size: 0.9em;
  cursor: help;
}

/* Three-mode company picker on the promote modal. The radio buttons
   stack vertically; the conditional fields (existing/new company)
   indent slightly so the form structure is visible at a glance. */
.promote-company {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px;
  margin-bottom: 12px;
}
.promote-company legend {
  font-weight: 500;
  padding: 0 6px;
}
.promote-company__choice {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  margin: 6px 0;
  cursor: pointer;
  user-select: none;
}
.promote-company__choice > input[type="radio"] {
  margin: 0;
  flex-shrink: 0;
  width: auto;
}
.promote-company > [data-company-existing],
.promote-company > [data-company-new] {
  margin-left: 24px;
  margin-bottom: 8px;
  padding-left: 12px;
  border-left: 2px solid var(--border);
}

/* Toggle row — single inline label+checkbox for boolean settings like
   the AI enrichment opt-out on the Integrations page. */
.toggle-row {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  margin-bottom: 4px;
  user-select: none;
}
.toggle-row > input[type="checkbox"] {
  margin: 0;
  flex-shrink: 0;
  width: auto;
}
.tabs a {
  display: inline-block;
  padding: 8px 14px;
  text-decoration: none;
  color: var(--fg-muted);
  border-bottom: 2px solid transparent;
  font-weight: 500;
  margin-bottom: -1px;
}
.tabs a:hover {
  color: var(--fg);
  text-decoration: none;
}
.tabs a[aria-current="page"] {
  color: var(--brand);
  border-bottom-color: var(--brand);
  font-weight: 600;
}

/* ============================================================================
 * Page header — used by detail pages to render a richer title block
 * (eyebrow + h1 + meta row). Keeps the h1 prominent without crowding.
 * ========================================================================= */

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 16px;
}
.page-header__title {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.page-header__eyebrow {
  font-size: 12px;
  font-weight: 500;
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.page-header__title h1 {
  margin: 0;
  font-size: 22px;
  line-height: 1.25;
}
.page-header__subtitle {
  margin: 4px 0 0;
  color: var(--fg-muted);
  font-size: 13px;
}
.page-header__actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Inline meta row used under a page header (status badge + id + timestamp). */
.detail-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0 0 16px;
  font-size: 13px;
  color: var(--fg-muted);
}
.detail-meta > * {
  /* inline-flex on the child collapses internal whitespace, so
   * "industry <strong>X</strong>" renders as "industryX". Use
   * inline-block so the space-between-text-and-strong survives. */
  display: inline-block;
  vertical-align: middle;
}

/* ============================================================================
 * Danger zone — groups irreversible/destructive actions so they don't render
 * as a lonely red button. ui_ux.md §3 — every irreversible action carries
 * visible weight.
 * ========================================================================= */

.danger-zone {
  background: var(--surface);
  border: 1px solid var(--danger-border);
  border-radius: var(--radius-lg);
  padding: 14px 18px;
  margin: 24px 0 0;
  box-shadow: var(--shadow-sm);
}
.danger-zone h2 {
  margin: 0 0 6px;
  font-size: 13px;
  color: var(--danger);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.danger-zone p {
  margin: 0 0 12px;
  color: var(--fg-muted);
  font-size: 13px;
}
.danger-zone__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Standard "back to X" link with chevron, used on detail pages. */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 13px;
  color: var(--fg-muted);
  text-decoration: none;
  margin: 16px 0 0;
}
.back-link::before {
  content: "←";
  display: inline-block;
}
.back-link:hover {
  color: var(--brand);
  text-decoration: underline;
}
/* Variant: back link sits ABOVE the page header on view-first detail
   pages. The `←` already comes from the ::before pseudo, so the
   anchor's own leading-arrow text gets hidden in the markup. */
.back-link--top {
  margin: 0 0 8px;
}

/* ============================================================================
 * Offerings checkbox grid — used on opportunity/project edit forms and the
 * win-opportunity flow. Two-column grid keeps the list compact at typical
 * org sizes (4–12 offerings).
 * ========================================================================= */

.offerings-checkboxes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 6px 16px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-alt);
}
.offerings-checkbox {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px;
  border-radius: var(--radius);
  font-size: 13px;
  cursor: pointer;
}
.offerings-checkbox:hover {
  background: var(--surface);
}
.offerings-checkbox input[type="checkbox"] {
  width: auto;
  margin: 0;
  min-height: 0;
}

/* ============================================================================
 * Utility
 * ========================================================================= */

.muted {
  color: var(--fg-muted);
}
.qr-code {
  display: block;
  margin: 16px 0;
  max-width: 220px;
}
.qr-code svg {
  display: block;
  background: #fff;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.intake-pending {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--warning);
}

/* htmx polling indicators: a small dot beside live regions */
.live-indicator {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ok);
  margin-left: 6px;
}

/* ============================================================================
 * Button-style anchor utilities (page-header__actions, etc.)
 * ========================================================================= */

.btn-primary,
.btn-secondary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  min-height: 36px;
  border-radius: var(--radius);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid var(--border-strong);
}
.btn-primary {
  background: var(--brand);
  color: #fff;
  border-color: var(--brand);
  box-shadow: var(--shadow-md);
  /* Subtle accent on the bottom edge so primary CTAs stand out
     against the page background on top-of-page action rows. */
  box-shadow:
    0 1px 0 var(--brand-deep) inset,
    var(--shadow-md);
}
.btn-primary:hover {
  background: var(--brand-deep);
  border-color: var(--brand-deep);
  text-decoration: none;
  color: #fff;
  transform: translateY(-1px);
  box-shadow:
    0 1px 0 var(--brand-deep) inset,
    0 4px 8px rgba(15, 23, 42, 0.12);
}
.btn-primary:active {
  transform: translateY(0);
  box-shadow:
    0 1px 0 var(--brand-deep) inset,
    var(--shadow-sm);
}
.btn-secondary {
  background: var(--bg);
  color: var(--fg);
}
.btn-secondary:hover {
  background: var(--row-hover);
  border-color: var(--fg-subtle);
  text-decoration: none;
}

/* ============================================================================
 * Pipeline metrics strip — top of /ui/sales
 * ========================================================================= */

.pipeline-metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
  margin: 0 0 16px;
}
.pipeline-metrics__stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 14px 16px;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pipeline-metrics__value {
  font-size: 22px;
  font-weight: 700;
  color: var(--fg);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.pipeline-metrics__label {
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-muted);
}

/* ============================================================================
 * Detail-page two-column layout — used by /ui/sales/:id
 * ========================================================================= */

.detail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 20px;
  align-items: start;
}
.detail-layout__main > *,
.detail-layout__side > * {
  margin-bottom: 16px;
}
.detail-layout__main > *:last-child,
.detail-layout__side > *:last-child {
  margin-bottom: 0;
}
.detail-layout__side .card,
.detail-layout__side .danger-zone {
  padding: 14px 16px;
}
.detail-layout__side h2 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg-muted);
}
@media (max-width: 1000px) {
  .detail-layout {
    grid-template-columns: 1fr;
  }
}

/* ============================================================================
 * Required-field marker + checkbox row helpers
 * ========================================================================= */

.field-required-marker {
  color: var(--danger);
  font-weight: 700;
  margin-left: 2px;
}
.field-help {
  margin: 4px 0 0;
  font-size: 12px;
}
/* Two fields side-by-side on the create / edit forms. Collapses to a single
   column on narrow viewports (matches the existing form input max-width). */
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 12px;
}
.field-row > .field {
  margin-bottom: 0;
}
@media (max-width: 640px) {
  .field-row {
    grid-template-columns: 1fr;
  }
}
.checkbox-line {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 500;
  cursor: pointer;
}
.checkbox-line input[type='checkbox'] {
  width: auto;
  margin: 0;
}

/* ============================================================================
 * Kanban — the Sales pipeline board (one column per active pipeline stage)
 * ========================================================================= */

.kanban {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 12px;
  min-height: 400px;
}
.kanban__column {
  flex: 0 0 280px;
  background: var(--bg-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 200px);
}
.kanban__column-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
  border-top-left-radius: var(--radius-lg);
  border-top-right-radius: var(--radius-lg);
}
.kanban__column-name {
  font-weight: 600;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg);
}
.kanban__column-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 11px;
  background: var(--border);
  color: var(--fg-muted);
  font-size: 11px;
  font-weight: 600;
}
.kanban__column-value {
  font-size: 11px;
  font-weight: 500;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}
.kanban__cards {
  flex: 1;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
}
.kanban__empty {
  margin: 0;
  text-align: center;
  font-size: 12px;
  padding: 16px 8px;
}
.kanban__card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: box-shadow 0.1s ease, border-color 0.1s ease, opacity 0.1s ease;
}
.kanban__card[draggable='true'] {
  cursor: grab;
}
.kanban__card.dragging {
  opacity: 0.5;
  cursor: grabbing;
}
.kanban__card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--border-strong);
}
/* Highlight the target column while a card is hovered over it. */
.kanban__cards.drag-over {
  background: var(--accent-soft);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  outline: 2px dashed var(--accent);
  outline-offset: -6px;
}
.kanban__card-title {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--fg);
  text-decoration: none;
  line-height: 1.3;
}
.kanban__card-title:hover {
  color: var(--brand);
  text-decoration: none;
}
.kanban__card-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 12px;
  color: var(--fg-muted);
}
.kanban__card-meta .currency,
.kanban__card-meta strong {
  color: var(--fg);
}
.kanban__card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 11px;
}
.kanban__card-next {
  font-size: 11px;
  margin: 4px 0;
  padding: 4px 8px;
  border-radius: var(--radius);
  background: var(--bg-alt);
  color: var(--fg);
  line-height: 1.4;
}
.kanban__card-next--missing {
  background: var(--warning-bg);
  color: var(--warning);
  font-weight: 500;
}
.kanban__card-activity {
  font-variant-numeric: tabular-nums;
}
.kanban__card-activity--stale {
  color: var(--danger);
  font-weight: 500;
}

/* Stale highlight: a deal with no cached activity in > N days picks
   up a warning ring + soft yellow background so it pops out of its
   column. The org's deal_stale_threshold_days drives which deals
   count as stale; the tile renders a tooltip with the actual
   threshold. */
.kanban__card--stale {
  border-color: var(--warning-border);
  background: var(--warning-bg);
  box-shadow: var(--shadow-sm);
}
.kanban__card--stale::before {
  content: "⚠";
  position: absolute;
  top: 6px;
  right: 8px;
  font-size: 11px;
  color: var(--warning);
}
.kanban__card {
  position: relative;
}

/* Activity dashboard: "last updated" hint sits next to the window
   picker so users can see snapshot age + know when the data was
   refreshed. */
.activity-cache-status label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--fg-muted);
  display: block;
  margin-bottom: 2px;
}
.activity-cache-status > span {
  display: inline-block;
  padding-top: 4px;
}

/* Closed-lost columns hidden by default; user opts in with the toggle below
   the kanban (persisted in localStorage as pw-show-lost). */
.kanban__column[data-category='lost'] {
  display: none;
}
html.show-lost .kanban__column[data-category='lost'] {
  display: flex;
}

.kanban-toggle-row {
  display: flex;
  justify-content: center;
  margin: 12px 0 0;
}
.kanban-toggle {
  font-size: 12px;
  font-weight: 500;
  color: var(--fg-muted);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 14px;
  min-height: 0;
  cursor: pointer;
  transition: background 0.1s ease, color 0.1s ease, border-color 0.1s ease;
}
.kanban-toggle:hover {
  background: var(--bg);
  border-color: var(--border-strong);
  color: var(--fg);
}
/* Show/hide the right label based on the html class state. */
.kanban-toggle__hide { display: none; }
html.show-lost .kanban-toggle__show { display: none; }
html.show-lost .kanban-toggle__hide { display: inline; }

/* ============================================================================
 * Activity timeline — used on the contact detail page and the company
 * detail page. Groups items by date bucket (Today / Yesterday / This
 * week / Earlier this month / month name) and renders each item with
 * a leading icon (✉ email, 📅 meeting, ☎/📝 manual call or note).
 * ========================================================================= */

.timeline {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.timeline__bucket-label {
  font-size: 0.85em;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--fg-muted);
  margin-bottom: 6px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border);
}

.timeline__item {
  display: flex;
  gap: 12px;
  padding: 8px 0;
  align-items: flex-start;
}

.timeline__item + .timeline__item {
  border-top: 1px solid var(--border);
}

.timeline__icon {
  flex-shrink: 0;
  width: 28px;
  text-align: center;
  font-size: 1.1em;
  color: var(--fg-muted);
  padding-top: 2px;
}

.timeline__icon-arrow {
  font-size: 0.85em;
  margin-left: 1px;
}

.timeline__body {
  flex: 1 1 auto;
  min-width: 0;
}

.timeline__header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 2px;
}

.timeline__subject {
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.timeline__time {
  font-size: 0.85em;
  flex-shrink: 0;
}

.timeline__meta {
  font-size: 0.85em;
  margin-bottom: 4px;
}

.timeline__preview {
  font-size: 0.9em;
  line-height: 1.4;
  margin-top: 2px;
  /* Subtle "we trimmed this" feel via a clamp at ~3 lines. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* "Show all activity" footer at the bottom of a windowed timeline.
   Visible only when the page is showing a capped view (default 30
   days) — the user reaches the bottom, sees the hint, clicks to
   expand the unbounded view. */
.timeline__load-more {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px dashed var(--border);
  text-align: center;
}
.timeline__load-more-hint {
  font-size: 12px;
  margin: 0 0 10px;
}
.timeline__load-more-button {
  display: inline-block;
}

/* The "+ Log activity" disclosure form above the timeline on the
   contact detail page. Reuses .card-nested for the dashed-border
   container; this rule just gives the open form a bit more breathing
   room and a clear visual separation from the timeline below. */
.log-activity[open] {
  margin-bottom: 16px;
}

/* Activity card header — the h2 "Activity" on the left, the inline
   "log activity" disclosure on the right. The log disclosure styles
   itself as a secondary button when closed so it doesn't read like
   text. */
.activity-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.activity-header h2 {
  margin: 0;
  flex-shrink: 0;
}
.activity-header .log-activity {
  margin: 0;
  flex: 0 1 auto;
  max-width: 480px;
  width: 100%;
}
/* Closed disclosure = compact secondary button. Opens into the regular
   card-nested look. */
.activity-header .log-activity:not([open]) {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-style: solid;
  padding: 6px 12px;
}
.activity-header .log-activity:not([open]) > summary {
  font-size: 13px;
  color: var(--fg);
}
.activity-header .log-activity:not([open]):hover {
  border-color: var(--brand);
  background: var(--row-hover);
}

/* The compact contact-info row under the contact header (email + phone). */
.detail-meta--contact-card {
  margin-top: -4px;
  margin-bottom: 16px;
}
.detail-meta--contact-card a {
  text-decoration: none;
}
.detail-meta--contact-card a:hover {
  text-decoration: underline;
}

/* Compact multi-select disclosure used on the deal detail page in
   place of always-expanded checkbox grids. Closed state shows "N
   selected · edit ↓"; open expands to a scrollable checkbox list
   that's vertically capped so a long catalog doesn't push everything
   below the fold. */
.multi-select {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  margin: 0 0 8px;
}
.multi-select > summary {
  cursor: pointer;
  padding: 8px 12px;
  font-size: 13px;
  font-weight: 500;
  user-select: none;
  list-style: none;
}
.multi-select > summary::-webkit-details-marker {
  display: none;
}
.multi-select > summary::marker {
  content: "";
  display: none;
}
.multi-select[open] > summary {
  border-bottom: 1px solid var(--border);
}
.multi-select__options {
  display: flex;
  flex-direction: column;
  max-height: 240px;
  overflow-y: auto;
  padding: 6px 8px;
}
.multi-select__option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px;
  border-radius: var(--radius);
  font-size: 13px;
  cursor: pointer;
}
.multi-select__option:hover {
  background: var(--row-hover);
}
.multi-select__option input[type="checkbox"] {
  width: auto;
  margin: 0;
  min-height: 0;
}

/* "Move to stage" action card. Lives in the deal-detail right
   sidebar — stacked layout (select on top, button below) reads as
   the primary sidebar action without competing with the main
   content. */
.deal-stage-actions h2 {
  margin: 0 0 10px;
}
.deal-stage-actions__form-stacked {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.deal-stage-actions__form-stacked > select {
  width: 100%;
}
.deal-stage-actions__form-stacked > button {
  align-self: flex-start;
}
.deal-stage-actions__hint {
  font-size: 12px;
  margin: 8px 0 0;
}

/* Deal-details form: full-width within the main column. Each
   .field-row pairs two fields side-by-side; .field takes 100% so
   the textarea spans the whole card. */
.deal-details-form .field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.deal-details-form .field {
  min-width: 0;
}
.deal-details-form .field input,
.deal-details-form .field select,
.deal-details-form .field textarea {
  width: 100%;
}
.deal-details-form textarea {
  min-height: 240px;
  font-family: var(--font-sans);
  line-height: 1.5;
}
.field--required-missing input {
  border-color: var(--warning);
  background: var(--warning-bg);
}

/* Collapsed sidebar cards (offerings / deliverables) — closed
   state shows a one-line "X selected" summary; open expands the
   form. Saves vertical space when the catalog is set but rarely
   edited. Reuses .card framing so the borders match. */
.card.collapsed-card {
  padding: 0;
}
.card.collapsed-card > summary {
  list-style: none;
  cursor: pointer;
  padding: 12px 18px;
  font-size: 15px;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  user-select: none;
}
.card.collapsed-card > summary::-webkit-details-marker {
  display: none;
}
.card.collapsed-card > summary::after {
  content: "▾";
  color: var(--fg-muted);
  font-size: 12px;
  transition: transform 120ms ease;
}
.card.collapsed-card[open] > summary::after {
  transform: rotate(180deg);
}
.card.collapsed-card[open] > summary {
  border-bottom: 1px solid var(--border);
}
.card.collapsed-card > :not(summary) {
  padding: 14px 18px;
}
.collapsed-card__count {
  font-size: 12px;
  font-weight: 400;
}

/* Deal activity card buckets — "Upcoming" / "Recent" headers above
   the per-bucket timeline. */
.deal-activity__bucket + .deal-activity__bucket {
  margin-top: 16px;
}
.deal-activity__bucket-label {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-muted);
  margin: 0 0 8px;
}
/* Deferred-activity placeholder: shown on the company/contact/deal
   detail pages while htmx fetches the activity-partial endpoint.
   The Graph fan-out can take several seconds; the placeholder
   keeps the rest of the page interactive while the timeline
   streams in. */
.deferred-activity__placeholder {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 20px 0;
  font-size: 14px;
  color: var(--fg-muted);
}
.deferred-activity__spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--border);
  border-top-color: var(--brand);
  animation: deferred-activity-spin 0.8s linear infinite;
}
@keyframes deferred-activity-spin {
  to { transform: rotate(360deg); }
}

/* Hidden-by-default tail of recent activity items. Click the "Load
   more" button below to reveal — ui.js toggles is-expanded on the
   list container. */
.deal-activity__more {
  display: none;
}
.deal-activity__list.is-expanded .deal-activity__more {
  display: block;
}
.deal-activity__load-more {
  margin-top: 8px;
}

/* Auto-save indicator on sidebar pickers (offerings / deliverables /
   people). Hidden in the resting state; shows "Saving…" while a POST
   is in flight, then a quick "Saved ✓" before fading out. */
.auto-save-indicator {
  margin-top: 8px;
  font-size: 12px;
  min-height: 16px;
  text-align: right;
}
.auto-save-indicator__saving,
.auto-save-indicator__saved {
  display: none;
}
.auto-save-form.is-saving .auto-save-indicator__saving {
  display: inline;
}
.auto-save-form.is-saved .auto-save-indicator__saved {
  display: inline;
  color: var(--ok);
  font-weight: 500;
  animation: auto-save-fade 2s ease-out forwards;
}
@keyframes auto-save-fade {
  0% { opacity: 1; }
  70% { opacity: 1; }
  100% { opacity: 0; }
}

/* Poll-diagnostics cell on the mailbox subscriptions table — shows
   the last poll's inbox-message + calendar-event counts side by side
   so a silent permission failure (0 events) is visible. */
.poll-diag {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.poll-diag > div {
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.poll-diag > div.danger strong {
  color: var(--danger);
}
.poll-diag__error {
  margin-top: 4px;
  font-size: 11px;
}
.poll-diag__error > summary {
  color: var(--warning);
  cursor: pointer;
  font-weight: 500;
}
.poll-diag__error > p {
  margin: 4px 0 0;
  max-width: 320px;
  white-space: normal;
}

/* Permission reference list inside the security checklist. */
.permission-list {
  margin: 8px 0 0;
  padding-left: 20px;
}
.permission-list li {
  margin-bottom: 6px;
  font-size: 13px;
}
.permission-list code {
  font-size: 12px;
}

/* Inline meeting details on the activity timeline. Reuses the email
   disclosure pattern so Teams meeting cards behave the same as email
   cards — click to expand, htmx fetches the panel, click again to
   collapse. */
.timeline__meeting-disclosure {
  margin: 0;
}
.timeline__meeting-disclosure > summary {
  cursor: pointer;
  list-style: none;
}
.timeline__meeting-disclosure > summary::-webkit-details-marker {
  display: none;
}
.timeline__meeting-disclosure > summary::marker {
  display: none;
  content: "";
}
.timeline__meeting-disclosure > summary:hover .timeline__subject {
  color: var(--accent);
  text-decoration: underline;
}
.timeline__meeting-disclosure[open] > summary .timeline__subject {
  color: var(--brand);
}
.timeline__meeting-details {
  margin-top: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-alt);
  padding: 12px;
}
.meeting-details__recording {
  margin-bottom: 12px;
  font-size: 14px;
}
.meeting-details__summary {
  margin-bottom: 12px;
}
.meeting-details__summary h4 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--fg-muted);
  margin: 0 0 6px;
}
.meeting-details__summary p {
  margin: 0 0 8px;
}
.meeting-details__key-points {
  margin: 0 0 8px;
  padding-left: 20px;
}
.meeting-details__key-points li {
  margin-bottom: 4px;
}
.meeting-details__summary-note {
  font-size: 12px;
  margin-top: 8px;
}
.meeting-details__no-transcript,
.meeting-details__empty {
  font-size: 13px;
}
.meeting-details__transcript-toggle {
  border-top: 1px solid var(--border);
  padding-top: 10px;
}
.meeting-details__transcript-toggle > summary {
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  color: var(--fg-muted);
}
.meeting-details__transcript-toggle > summary:hover {
  color: var(--brand);
}
.meeting-details__transcript-toggle[open] > summary {
  margin-bottom: 8px;
}
.meeting-details__transcript {
  white-space: pre-wrap;
  font-family: var(--font-sans);
  font-size: 13px;
  margin: 0;
  background: var(--bg);
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-height: 60vh;
  overflow: auto;
  line-height: 1.5;
}

/* Inline email reader on the activity timeline. Clicking the subject
   expands the body fetched via htmx into a sandboxed iframe so the user
   stays on the contact page instead of opening Outlook. */
.timeline__email-disclosure {
  margin: 0;
}
.timeline__email-disclosure > summary {
  cursor: pointer;
  list-style: none;
  /* Remove the default disclosure marker — the chevron is implied by
     the .timeline__subject color shift on hover. */
}
.timeline__email-disclosure > summary::-webkit-details-marker {
  display: none;
}
.timeline__email-disclosure > summary::marker {
  display: none;
  content: "";
}
.timeline__email-disclosure > summary .timeline__subject {
  cursor: pointer;
}
.timeline__email-disclosure > summary:hover .timeline__subject {
  color: var(--accent);
  text-decoration: underline;
}
.timeline__email-disclosure[open] > summary .timeline__subject {
  color: var(--brand);
}
.timeline__email-body {
  margin-top: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-alt);
  padding: 12px;
}
.email-body__headers {
  font-size: 13px;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.email-body__headers > div {
  margin-bottom: 2px;
}
.email-body__open {
  margin-top: 6px;
  font-size: 12px;
}
.email-body__iframe {
  width: 100%;
  min-height: 320px;
  /* Most marketing/transactional emails are 600–800px tall; cap so
     the timeline doesn't become a single screen of email. Users can
     still scroll inside the iframe for longer messages. */
  max-height: 70vh;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
}
.email-body__text {
  white-space: pre-wrap;
  font-family: var(--font-sans);
  font-size: 13px;
  margin: 0;
  background: var(--bg);
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-height: 70vh;
  overflow: auto;
}
.email-body__error {
  padding: 8px 0;
}

/* The "notes" card on the contact detail page — soft-yellow tint so it
   reads like a sticky note. */
.card.card--note {
  background: #fef9c3;
  border-color: #fde047;
}
.card.card--note h2 {
  font-size: 1em;
  margin-bottom: 4px;
}
.card.card--note p {
  white-space: pre-wrap;
  margin: 0;
}

/* Soft-info card — used for callouts like "Mailboxes without a matching
   user" on the activity dashboard. Same shape as a regular .card, soft
   blue tint to signal informational rather than alarming. */
.card.card--info {
  background: var(--info-bg);
  border-color: var(--info-border);
}

/* Section header inside a card — title on the left, action affordance
   (an "Add", "+ New", a window picker) on the right. Used on the
   company + contact detail pages so each section's primary actions
   live next to their title without nesting more headers. */
.card-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.card-section-header h2 {
  margin: 0;
}
.activity-window-hint {
  font-size: 12px;
}
.activity-window-row {
  font-size: 12px;
  margin-bottom: 8px;
}

/* The "+ Add contact" disclosure inside the Contacts card on company
   detail — closed-state is a small secondary affordance; open
   expands the inline-add form. Reuses the disclosure pattern from
   the log-activity disclosure (kept visually distinct from .card so
   the form doesn't read as a nested card). */
.add-contact {
  margin: 0;
}
.add-contact > summary {
  cursor: pointer;
  font-size: 13px;
  padding: 4px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  user-select: none;
}
.add-contact > summary:hover {
  border-color: var(--brand);
  background: var(--row-hover);
}
.add-contact[open] > summary {
  margin-bottom: 10px;
}

/* Hidden-by-default "Edit company details" disclosure on the company
   detail page. Renders flat (no double-card frame) when closed. */
.edit-company-toggle {
  margin-top: 16px;
}
.edit-company-toggle > summary {
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  color: var(--fg-muted);
  user-select: none;
}
.edit-company-toggle > summary:hover {
  color: var(--brand);
}
.edit-company-toggle[open] > summary {
  margin-bottom: 12px;
  color: var(--fg);
}

/* Activity metrics dashboard — per-rep table of email/meeting/manual
   activity totals. Numbers are right-aligned, tabular-nums for clean
   stacking. */
.activity-metrics__table {
  width: 100%;
}
.activity-metrics__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.activity-metrics__role {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* ============================================================================
 * Mobile (≤ 768px) — phone-friendly defaults
 *
 * The desktop layout assumes a wide viewport. On a phone we keep the same
 * markup but adjust spacing, force the sidebar to its icon-only collapsed
 * state, and make wide elements (tables, the topbar code) behave on a
 * narrow screen. No JS or markup changes — pure CSS overrides at the
 * end of the file so they win without !important.
 * ========================================================================= */

@media (max-width: 768px) {
  /* --- App shell + sidebar ------------------------------------------------ */
  /* Lock the sidebar into its icon-only state on mobile. The 56px column
     fits cleanly next to ~320px of content on a 375-414px phone. The
     toggle button is hidden because the desktop-collapsed-state classes
     would otherwise let a tap toggle into the 240px-wide state and crowd
     out the content. */
  body.app-shell {
    grid-template-columns: 56px 1fr;
  }
  .brand-wordmark,
  .nav-item__label,
  .nav-badge,
  .principal-line,
  .sidebar-signout__label {
    display: none;
  }
  .app-sidebar__brand {
    padding: 14px 0;
    justify-content: center;
    min-height: 56px;
  }
  .app-sidebar__brand a {
    justify-content: center;
    gap: 0;
  }
  .brand-logo--full {
    display: none;
  }
  .brand-logo--icon {
    display: block;
  }
  .app-sidebar__nav {
    padding: 10px 6px;
  }
  .app-sidebar__nav .nav-item {
    justify-content: center;
    padding: 10px 0;
    border-left: none;
    margin-left: 0;
    gap: 0;
  }
  /* The icon-only rail has no room for the text section sub-nav. Hide it
     here; the in-page .sales-tabs strip (re-shown below) carries the
     sub-nav on mobile instead. */
  .app-sidebar__subnav {
    display: none;
  }
  .sidebar-toggle {
    /* The user can't usefully un-collapse the sidebar on mobile — the
       wide state would crowd out content. Hide the toggle entirely. */
    display: none;
  }

  /* --- Topbar + main content padding -------------------------------------- */
  /* Tighten the breathing room so the usable content area expands. */
  .app-content__topbar {
    padding: 8px 12px;
    /* The trace id is dev-noise on a phone; the breadcrumb title is more
       useful. Hide the trace meta but keep the title for orientation. */
  }
  .app-content__meta {
    display: none;
  }
  .app-content__main {
    padding: 14px 12px 24px;
  }

  /* --- Cards + page header ------------------------------------------------ */
  .card {
    padding: 14px 14px;
  }
  /* page-header__actions normally sits on the right of the title row.
     On mobile, stack the actions under the title so they don't collide
     with the heading or get pushed off-screen. */
  .page-header {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  .page-header__actions {
    width: 100%;
    flex-wrap: wrap;
  }
  .page-header__actions > .btn-primary,
  .page-header__actions > .btn-secondary,
  .page-header__actions > form {
    flex: 1 1 auto;
    justify-content: center;
  }
  .page-header__title h1 {
    font-size: 20px;
  }
  .page-header__subtitle {
    font-size: 12px;
  }

  /* --- Detail meta line --------------------------------------------------- */
  /* The meta row's inline spans wrap into multiple lines on a phone — let
     them, but tighten the gap so the wrap reads as a list rather than
     scattered chips. */
  .detail-meta {
    gap: 6px 10px;
    font-size: 12px;
  }

  /* --- Tabs --------------------------------------------------------------- */
  /* The sub-tab strip (Pipeline · Companies · Contacts · Triage · Reports)
     can overflow a phone. Make it horizontally scrollable + hide the
     scrollbar so it reads as a swipe affordance. */
  .tabs {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    flex-wrap: nowrap;
    scrollbar-width: none;
  }
  .tabs::-webkit-scrollbar {
    display: none;
  }
  .tabs a {
    flex: 0 0 auto;
    white-space: nowrap;
  }
  /* Re-show the sales sub-nav strip on mobile (hidden on desktop, where
     it lives in the sidebar). Same specificity as the desktop hide, but
     declared later + inside this media query, so it wins ≤768px. */
  .tabs.sales-tabs {
    display: flex;
  }

  /* --- Tables ------------------------------------------------------------- */
  /* Tables (dataTable component) blow past 320px on most pages — the
     deals/contacts/companies lists carry 5-7 columns. Make each table
     its own horizontal-scroll viewport so the rest of the page stays
     usable. -webkit-overflow-scrolling is iOS's momentum scroll opt-in. */
  table {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* Reset some properties display:block knocks out so the table still
       looks like a table inside its scroll container. */
    white-space: nowrap;
  }
  /* The activity metrics table needs to keep number columns aligned —
     opt out of the display:block override so it stays a real table. */
  .activity-metrics__table {
    display: table;
    overflow-x: visible;
    white-space: normal;
  }

  /* --- Pipeline kanban ---------------------------------------------------- */
  /* The columns already scroll horizontally on desktop too; on mobile,
     narrow each column slightly so two are visible at once on a typical
     414px phone. */
  .kanban__column {
    min-width: 260px;
  }

  /* --- Field rows --------------------------------------------------------- */
  /* Most field-rows already collapse via the existing @media (max-width:
     640px) rule. Mirror that for the deal-details-form's grid layout. */
  .deal-details-form .field-row {
    grid-template-columns: 1fr;
  }

  /* --- Detail layout ------------------------------------------------------ */
  /* The existing @media (max-width: 1000px) rule flips .detail-layout
     to single-column at 1000px — that's already mobile-friendly. Just
     reduce the gap between sections on a phone. */
  .detail-layout {
    gap: 16px;
  }

  /* --- Buttons: finger-friendly tap targets ------------------------------- */
  /* iOS HIG recommends 44pt minimum; we bump primary/secondary to 44px and
     give .btn-small a generous 36px so it doesn't feel cramped either. */
  .btn-primary,
  .btn-secondary {
    min-height: 44px;
    padding: 10px 18px;
  }
  .btn-small {
    min-height: 36px;
    padding: 8px 14px;
  }

  /* --- Multi-select dropdowns -------------------------------------------- */
  /* The sidebar pickers (offerings/deliverables/people) use a max-height
     scroll list. On a phone that height is too tall — leave room for the
     surrounding card. */
  .multi-select__options {
    max-height: 200px;
  }
}

/* Small phones (≤ 380px) — Pixel 4a / iPhone SE width. Even tighter. */
@media (max-width: 380px) {
  body.app-shell {
    grid-template-columns: 48px 1fr;
  }
  .app-content__main {
    padding: 12px 10px 20px;
  }
  .card {
    padding: 12px 12px;
  }
}

/* ============================================================================
 * Client portal (/portal/*) — authenticated chrome.
 *
 * The /portal/* surface lives in src/platform/http/portal/ and serves
 * external client_users. Pre-auth pages (login, setup, TOTP) reuse the
 * existing .auth-shell classes from earlier in this file — same
 * centered-card-with-logo treatment as staff sign-in. THIS section is
 * for the authenticated portal pages (project list, file list): a
 * stripped-down top bar (logo + user controls + sign-out) with the
 * content below, on the same slate-50 page background as the staff
 * app but without the dense left sidebar. Density-first staff
 * affordances (keyboard nav, dense tables) do NOT apply here — the
 * audience is a client clicking through once a week to grab a file.
 * ========================================================================= */

body.portal-shell {
  background: var(--bg-alt);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
.portal-shell__header {
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  padding: 12px 0;
}
.portal-shell__header-inner {
  max-width: 880px;
  margin: 0 auto;
  padding: 0 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.portal-shell__brand {
  display: inline-flex;
  align-items: center;
  color: inherit;
  text-decoration: none;
}
.portal-shell__brand .brand-logo {
  height: 28px;
  width: auto;
}
.portal-shell__user {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 13px;
  color: var(--fg-muted);
}
.portal-shell__user form.inline {
  margin: 0;
}
.portal-shell__user .btn-link,
.portal-shell__user button.btn-link {
  background: none;
  border: 0;
  color: var(--brand);
  cursor: pointer;
  padding: 0;
  font: inherit;
  text-decoration: underline;
}
.portal-shell__user .btn-link:hover { color: var(--brand-deep); }
.portal-shell__main {
  flex: 1;
  max-width: 880px;
  width: 100%;
  margin: 0 auto;
  padding: 28px 24px 48px;
  box-sizing: border-box;
}
.portal-shell__main h1 {
  font-size: 22px;
  margin: 0 0 8px;
}
.portal-shell__eyebrow {
  color: var(--fg-muted);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0 0 4px;
}
.portal-shell__eyebrow a { color: inherit; }
.portal-shell__footer {
  border-top: 1px solid var(--border);
  background: var(--bg);
  padding: 16px 24px;
  font-size: 12px;
  color: var(--fg-muted);
  text-align: center;
}

/* Cards inside the portal use the same .card class as the staff app
 * (no overrides needed). Tables ditto — .data-table just works on
 * the lighter portal content area. */

/* The pre-auth .auth-shell variant for /portal pages: same as the
 * staff .auth-shell except the brand mark links back to /portal/login
 * (set in markup) — no CSS difference needed. */

@media (max-width: 640px) {
  .portal-shell__header-inner,
  .portal-shell__main {
    padding-left: 16px;
    padding-right: 16px;
  }
}


/* ============================================================================
 * Upload tray — fixed bottom-right widget driven by portal-uploads.js
 *
 * Lives outside #main so it persists across hx-boost soft navigations.
 * Two visual states:
 *   - Expanded: a card with a list of upload rows (filename, progress,
 *     actions). Default state when uploads exist.
 *   - Minimized: a compact pill showing "N uploads · M%". Click to expand.
 * Hidden when the queue is empty (controlled by the [hidden] attribute).
 * ========================================================================== */

.upload-tray {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 1000;
  /* The tray itself is just a positioning anchor; the panel below
     paints the actual surface. Width caps so very long filenames
     don't blow out the layout. */
  width: min(360px, calc(100vw - 32px));
  pointer-events: none; /* enable on children so the empty space passes through */
}
.upload-tray[hidden] { display: none; }

.upload-tray__panel,
.upload-tray__pill {
  pointer-events: auto;
}

.upload-tray__panel {
  background: var(--brand);            /* slate-navy, matches sidebar */
  color: #fff;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  font-size: 13px;
  line-height: 1.4;
}

.upload-tray__header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  background: var(--brand-deep);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.upload-tray__header strong { font-weight: 600; font-size: 13px; }
.upload-tray__count { flex: 1; color: rgba(255, 255, 255, 0.65); }
.upload-tray__count.muted { color: rgba(255, 255, 255, 0.65); }

.upload-tray__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: rgba(255, 255, 255, 0.85);
  cursor: pointer;
}
.upload-tray__btn:hover {
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
}
.upload-tray__btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.upload-tray__list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 60vh;
  overflow-y: auto;
}

.upload-tray__row {
  padding: 10px 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  transition: opacity 400ms ease;
}
.upload-tray__row:last-child { border-bottom: 0; }
.upload-tray__row.is-fading { opacity: 0; }

.upload-tray__row-head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.upload-tray__status {
  flex: 0 0 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.upload-tray__row.is-ok .upload-tray__status   { color: #6bdca0; }
.upload-tray__row.is-error .upload-tray__status { color: #f8a39a; }
.upload-tray__row.is-canceled .upload-tray__status { color: rgba(255,255,255,0.5); }

.upload-tray__filename {
  flex: 1;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.upload-tray__actions {
  flex: 0 0 auto;
  display: inline-flex;
  gap: 4px;
}

.upload-tray__sub {
  font-size: 12px;
  margin-top: 2px;
  color: rgba(255, 255, 255, 0.6);
}
.upload-tray__sub.muted { color: rgba(255, 255, 255, 0.6); }

.upload-tray__progress {
  margin-top: 6px;
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.12);
  overflow: hidden;
}
.upload-tray__progress-fill {
  height: 100%;
  background: var(--accent);
  transition: width 200ms ease;
}
.upload-tray__progress-text {
  margin-top: 4px;
  font-size: 11px;
  color: rgba(255, 255, 255, 0.6);
}
.upload-tray__progress-text.muted { color: rgba(255, 255, 255, 0.6); }
/* A part is mid-retry — amber so it reads as "working through a blip",
   distinct from neutral progress text and the red failed state. */
.upload-tray__progress-text--retry { color: #f4c773; }

.upload-tray__error {
  margin-top: 6px;
  padding: 6px 8px;
  border-radius: 4px;
  background: rgba(248, 163, 154, 0.12);
  color: #fbd2cd;
  font-size: 12px;
  word-break: break-word;
}

.upload-tray__spinner {
  display: inline-block;
  width: 12px;
  height: 12px;
  border: 2px solid rgba(255, 255, 255, 0.2);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: upload-tray-spin 700ms linear infinite;
}
@keyframes upload-tray-spin {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .upload-tray__spinner { animation: none; }
}

.upload-tray__pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: var(--brand);
  color: #fff;
  border: 0;
  border-radius: 999px;
  box-shadow: var(--shadow-md);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.upload-tray__pill:hover { background: var(--brand-deep); }
.upload-tray__pill:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ============================================================================
 * Pager — prev/next pagination control (triage queue, reusable elsewhere)
 * ========================================================================== */

.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.pager__controls {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.pager__page { white-space: nowrap; }
.pager .is-disabled {
  opacity: 0.4;
  pointer-events: none;
  cursor: default;
}

/* Triage promote modal — company search box above the picker. */
.promote-company__search {
  width: 100%;
  margin-bottom: 0;
}

/* Search-only combobox (triage company picker). An input with an
   absolutely-positioned results list beneath it; a hidden field carries
   the chosen id. */
.combo {
  position: relative;
}
.combo__results {
  position: absolute;
  left: 0;
  right: 0;
  margin: 4px 0 0;
  padding: 4px;
  list-style: none;
  max-height: 220px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.14);
  z-index: 30;
}
.combo__option {
  padding: 7px 10px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13.5px;
}
.combo__option:hover {
  background: #f1f5f9;
}
.combo__empty {
  margin: 8px 2px 2px;
  font-size: 12.5px;
}

/* Button busy state — a spinner + dim while an action is in flight, so
   a slow submit (e.g. triage "Add to CRM") visibly acknowledges the
   click. The spinner reads on the dark primary button (white border). */
button.is-loading {
  opacity: 0.85;
  cursor: progress;
}
button.is-loading::before {
  content: "";
  display: inline-block;
  width: 13px;
  height: 13px;
  margin-right: 8px;
  vertical-align: -2px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.45);
  border-top-color: #ffffff;
  animation: btn-spin 0.7s linear infinite;
}
@keyframes btn-spin {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  button.is-loading::before { animation: none; }
}

/* Busy state for a button that fires an htmx request (e.g. triage's row
   "Add to CRM", which opens a modal after a few-second AI-enrichment
   fetch). htmx puts `htmx-request` on the triggering element for the
   whole request; we hide the label and center a spinner over the button
   so the click is acknowledged immediately. No width jump (text is just
   made transparent), and no double-fire (pointer-events disabled). */
button.btn-busy.htmx-request {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
button.btn-busy.htmx-request::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.45);
  border-top-color: #ffffff;
  animation: btn-spin 0.7s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  button.btn-busy.htmx-request::after { animation: none; }
}

/* Building SF + projected-close lines on a kanban deal card (sit under
   company/value). */
.kanban__card-sf,
.kanban__card-close {
  font-size: 12px;
  margin-top: 2px;
}

/* ============================================================================
 * Tasks (top-level Tasks page + the Tasks card on record detail pages)
 * ========================================================================== */

.task-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin-bottom: 16px;
}
.task-filters__group {
  display: inline-flex;
  gap: 4px;
}
.filter-pill {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--fg-muted);
  font-size: 12.5px;
  text-decoration: none;
}
.filter-pill:hover {
  border-color: var(--border-strong);
  color: var(--fg);
  text-decoration: none;
}
.filter-pill.is-active {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}

.task-due--overdue {
  color: var(--danger);
  font-weight: 600;
}
.task-due--today {
  color: var(--warning);
  font-weight: 600;
}
.task-due--soon {
  color: var(--fg);
  font-weight: 500;
}

/* Urgency-grouped task list (top-level Tasks page). */
.task-group {
  margin-bottom: 16px;
}
.task-group__header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.task-group__title {
  margin: 0;
  font-size: 14px;
}
.task-group__title--overdue {
  color: var(--danger);
}
.task-group__title--today {
  color: var(--warning);
}
.task-group__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 7px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--fg-muted);
  font-size: 12px;
}
.task-title-link {
  font-weight: 600;
}

/* Collapsible "+ New task" quick-add at the top of the Tasks page. */
.task-quickadd {
  margin-bottom: 16px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
}
.task-quickadd__summary {
  cursor: pointer;
  padding: 10px 14px;
  font-weight: 600;
  color: var(--brand);
  list-style: none;
}
.task-quickadd__summary::-webkit-details-marker {
  display: none;
}
.task-quickadd[open] .task-quickadd__summary {
  border-bottom: 1px solid var(--border);
}
.task-quickadd__body {
  padding: 4px 14px 14px;
}
.task-quickadd__body .task-form {
  border-top: 0;
  padding-top: 8px;
}

/* Compact task list used inside the record Tasks card. */
.task-list {
  list-style: none;
  margin: 0 0 12px 0;
  padding: 0;
}
.task-list__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.task-list__row:last-child {
  border-bottom: 0;
}
.task-list__main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.task-list__title {
  font-weight: 500;
}
.task-list__meta {
  font-size: 12px;
}
.task-list__row.is-done .task-list__title {
  text-decoration: line-through;
  color: var(--fg-muted);
}

/* The inline "new task" form (record card uses the compact variant). */
.task-form {
  border-top: 1px solid var(--border);
  padding-top: 12px;
}
