/* imagine — design language aligned with himslite.fadafad.com
 * Material Design 3, light theme, deep-teal primary, Roboto. */

/* Click-to-view image preview / lightbox.
   Used when an attachment chip (composer or chat message) is clicked.
   Tap outside the image, hit Esc, or tap the × to dismiss. */
.imagine-img-lightbox {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.82);
  z-index: 10000;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  cursor: zoom-out;
  animation: imagine-img-lightbox-in 140ms ease-out;
}
@keyframes imagine-img-lightbox-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.imagine-img-lightbox img {
  max-width: 96vw; max-height: 92vh;
  border-radius: 8px;
  box-shadow: 0 14px 60px rgba(0, 0, 0, 0.5);
  cursor: default;
  background: #fff;
}
.imagine-img-lightbox-caption {
  position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%);
  color: #fff; font-size: 13px; opacity: 0.85;
  pointer-events: none;
}
.imagine-img-lightbox-close {
  position: absolute; top: 18px; right: 22px;
  background: rgba(255,255,255,0.12);
  border: none; color: #fff;
  width: 36px; height: 36px; border-radius: 50%;
  font-size: 22px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background 140ms ease;
}
.imagine-img-lightbox-close:hover { background: rgba(255,255,255,0.22); }
/* Composer attachment chip — when it carries an image, make the whole row
   clickable so the user gets the preview without hunting for a specific
   button (per the Telegram / Slack pattern). */
#attachments .chip.is-image {
  cursor: zoom-in;
}
#attachments .chip.is-image:hover img {
  filter: brightness(1.05);
  transition: filter 120ms ease;
}

:root {
  /* Brand */
  --primary: #0D7377;
  --primary-hover: #0A5D60;
  --primary-pressed: #084E51;
  --primary-tint: rgba(13, 115, 119, 0.08);
  --primary-tint-strong: rgba(13, 115, 119, 0.14);
  --on-primary: #ffffff;

  /* Neutrals */
  --bg: #F3F5F8;
  --surface: #ffffff;
  --surface-alt: #F8FAFC;
  --surface-sunk: #EEF2F6;
  --border: #E3E8EF;
  --border-strong: #CBD5E1;
  --divider: #EDF1F6;

  /* Text */
  --text: #0F172A;
  --text-muted: #475569;
  --text-dim: #64748B;
  --text-faint: #94A3B8;

  /* Semantic */
  --danger: #DC2626;
  --danger-tint: rgba(220, 38, 38, 0.08);
  --warning: #D97706;
  --success: #047857;

  /* Chat bubbles */
  --user-bubble: var(--primary);
  --user-bubble-text: #ffffff;
  --assistant-bubble: #ffffff;

  /* Code */
  --code-bg: #0F172A;
  --code-text: #E2E8F0;
  --inline-code-bg: #EEF2F6;
  --inline-code-text: #0F172A;

  /* Elevation */
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.04), 0 1px 3px rgba(15, 23, 42, 0.06);
  --shadow-md: 0 2px 6px rgba(15, 23, 42, 0.06), 0 8px 24px rgba(15, 23, 42, 0.06);
  --shadow-lg: 0 12px 32px rgba(15, 23, 42, 0.10);

  /* Geometry */
  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;
  --radius-xl: 20px;

  /* Sidebar widths */
  --sidebar-w: 300px;
  --folder-panel-w: 260px;

  /* ─── Legacy / fallback aliases ───────────────────────────────────────
     Many older rules in this file (and external partials) reference
     variable names that aren't part of the main palette above, e.g.
     `var(--bg-soft, #f8fafc)` or `var(--card, #fff)`. Because those
     variables were never declared, dark mode couldn't override them —
     the literal fallback colour was baked in. Declaring them here lets
     `html.theme-dark { ... }` flip them in one place, no per-callsite
     hunt needed. Light-mode values mirror the fallbacks already used at
     callsites so the visual diff in light mode is zero.

     Bug surfaced 29 Jun 2026 — Cursor Configuration JSON snippet on the
     MCP setup page became light-text-on-light-bg in dark mode. */
  --bg-soft: #F8FAFC;              /* tinted well — code/snippet backgrounds */
  --card: var(--surface);          /* legacy alias for elevated card surfaces */
  --surface-hover: rgba(15, 23, 42, 0.04); /* hover wash on transparent surfaces */
  --muted: var(--text-dim);        /* legacy alias for secondary text */
  --divider: #EDF1F6;              /* re-stated so dark mode can flip it */
  /* Legacy alias — some inline-style spots and 3 CSS rules use the
     name `--surface-2` (which was never declared at root). Without
     this line they fell back to literal `#f3f4f6` (light grey) and
     stayed that colour in dark mode → white-on-white close button on
     the Approvals-waiting modal. Aliasing to `--surface-sunk` inherits
     the existing dark-mode flip for free. Reported 30 Jun 2026. */
  --surface-2: var(--surface-sunk);
  /* Brand colour aliases — these don't NEED to change in dark mode
     (brand identity holds) but declaring them prevents 181 stale
     fallback values from sitting in the cascade. */
  --brand-teal: var(--primary);
  --brand-teal-tint: var(--primary-tint);
  --brand-blue: #0078BF;
  --brand-blue-bg: rgba(0, 120, 191, 0.12);
  --brand-pink: #E44C9A;
  --brand-amber: #F59E0B;
  --brand-emerald: #16A34A;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
html, body { overflow: hidden; }
body {
  font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 14px;
  line-height: 1.55;
  background: var(--bg);
  color: var(--text);
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr var(--folder-panel-w);
  height: 100vh;
  height: 100dvh; /* account for mobile browser chrome */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Smoothly animate the folder-panel column when the user toggles it.
     Only the grid-template-columns value changes — chat + left sidebar
     stay put; the third column shrinks to 0 and the chat's 1fr eats it. */
  transition: grid-template-columns 240ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* Right-sidebar collapsed state (desktop). Chat's 1fr absorbs the freed space. */
body.folder-panel-collapsed {
  grid-template-columns: var(--sidebar-w) 1fr 0;
}
body.folder-panel-collapsed #folderPanel {
  /* Content hidden behind an overflow clip; visibility off so tab-order skips it
     without pulling it out of the grid layout (which would break the animation). */
  visibility: hidden;
  opacity: 0;
  transition: opacity 180ms ease-out, visibility 0s linear 200ms;
}
#folderPanel {
  transition: opacity 180ms ease-in, visibility 0s;
}

/* ========== Sidebar ========== */
#sidebar {
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  height: 100%;
  min-height: 0;
}
#sidebar header {
  padding: 14px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid var(--divider);
  flex-shrink: 0;
}
/* Middle of the sidebar (everything between <header> and <footer.sidebar-user>):
   takes all remaining vertical space and scrolls when content overflows. Without
   this, long menu + threads lists get clipped because #sidebar is overflow:hidden. */
#sidebar .sidebar-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  /* Momentum scrolling on iOS + lock overscroll-chain so dragging at the top
     of the menu doesn't accidentally pull the page behind it. Combined with
     the parent `overflow: hidden`, this is the single, well-behaved scroll
     surface for the side menu + threads list. */
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  /* native scrollbar styling kept platform-default; falls back gracefully on Firefox + Safari */
  scrollbar-width: thin;
  display: flex;
  flex-direction: column;
}
#sidebar .sidebar-user { flex-shrink: 0; }
.sidebar-section-label { flex-shrink: 0; }
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.brand-mark {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--primary) 0%, #14B8A6 100%);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-sm);
  flex-shrink: 0;
}
.brand-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.brand-name {
  font-weight: 700;
  font-size: 15px;
  color: var(--text);
  letter-spacing: 0.1px;
}
.brand-sub {
  font-size: 11px;
  color: var(--text-faint);
  letter-spacing: 0.3px;
  text-transform: uppercase;
}

.sidebar-section-label {
  padding: 14px 18px 6px;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.8px;
}

.sidebar-user {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid var(--divider);
  background: var(--surface);
  flex-shrink: 0;
  flex-wrap: wrap;
}

/* "Test as…" picker — admin-only convenience for QA, hidden by default and revealed
   in JS when role==='admin'. Renders as a popover anchored to the bottom-left. */
.test-as-picker { position: relative; }
.test-as-picker.hidden { display: none; }
.test-as-summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  cursor: pointer;
  font-size: 11px;
  color: var(--text-muted);
}
.test-as-summary::-webkit-details-marker { display: none; }
.test-as-summary:hover { color: var(--text); border-color: var(--primary); background: var(--surface-sunk); }
.test-as-picker[open] .test-as-summary { color: var(--primary); border-color: var(--primary); }
.test-as-menu {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0,0,0,0.10);
  padding: 4px;
  min-width: 160px;
  display: flex;
  flex-direction: column;
  z-index: 30;
}
.test-as-menu button {
  text-align: left;
  background: transparent;
  border: none;
  padding: 6px 10px;
  border-radius: 5px;
  color: var(--text);
  font-size: 12.5px;
  cursor: pointer;
}
.test-as-menu button:hover { background: var(--surface-sunk); color: var(--primary); }
.sidebar-user-info {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 12.5px;
  color: var(--text-muted);
  overflow: hidden;
}
.sidebar-user-info span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 140px;
}
.sidebar-user-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--primary-tint);
  color: var(--primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* Current Organisation picker (multi-org users + admins) */
.sidebar-current-org {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  order: -1;
  margin-bottom: 6px;
  padding: 6px 8px;
  border-radius: 8px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface-sunk, rgba(15, 23, 42, 0.04));
  box-sizing: border-box;
}
.sidebar-current-org.hidden { display: none !important; }
.sidebar-current-org-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-faint, #94a3b8);
  flex-shrink: 0;
  max-width: 4.6rem;
  line-height: 1.2;
}
.sidebar-current-org select {
  flex: 1;
  min-width: 0;
  font-size: 11.5px;
  padding: 4px 6px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface, #fff);
  color: var(--text);
  max-width: 100%;
}
#logoutBtn {
  font-size: 11.5px;
  padding: 5px 9px;
  flex-shrink: 0;
}

#threadList {
  list-style: none;
  padding: 0 8px 12px;
  margin: 0;
  /* Do NOT scroll internally — the parent `.sidebar-scroll` is the single
     scroll surface for the entire menu + threads stack. If we let this list
     scroll itself AND let it shrink (`flex: 1 1 auto; min-height: 0`), then
     once the side menu above is tall enough to fill `.sidebar-scroll` the
     threads list collapses to 0px and the threads disappear off-screen
     with no way to scroll to them. `flex-shrink: 0` keeps the list at its
     natural content height; the parent scrolls over both menu + threads. */
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Folder group container */
/* ── Organisation groups (Org → Project → Thread) ──
   Declared 8 Aug 2026. Wraps folder-groups under an org header so the
   sidebar reads as Organisation first, then projects, then threads. */
#threadList .org-group {
  list-style: none;
  margin: 0 0 6px;
  padding: 0;
  border-radius: 8px;
  background: transparent;
}
#threadList .org-group + .org-group {
  margin-top: 8px;
  padding-top: 6px;
  border-top: 1px solid var(--border-subtle, rgba(127,127,127,0.18));
}
.org-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 4px;
  cursor: pointer;
  user-select: none;
  color: var(--text-dim);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-radius: 6px;
}
.org-header:hover {
  background: var(--surface-sunk);
  color: var(--text);
}
.org-group.has-active .org-header { color: var(--text); }
.org-group.collapsed .org-chevron { transform: rotate(0deg); }
.org-group:not(.collapsed) .org-chevron { transform: rotate(90deg); }
.org-chevron {
  flex: 0 0 auto;
  transition: transform 0.12s ease;
  opacity: 0.7;
}
.org-icon {
  flex: 0 0 auto;
  font-size: 12px;
  line-height: 1;
  opacity: 0.85;
}
.org-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.org-subtitle {
  flex: 0 0 auto;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.55;
  padding: 1px 5px;
  border-radius: 999px;
  background: var(--surface-sunk, rgba(127,127,127,0.12));
}
.org-group--core .org-subtitle {
  color: var(--primary, #2563eb);
  background: color-mix(in srgb, var(--primary, #2563eb) 12%, transparent);
}
.org-count {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  min-width: 18px;
  text-align: center;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--surface-sunk, rgba(127,127,127,0.12));
  color: var(--text-dim);
}
.org-folder-list {
  list-style: none;
  margin: 0;
  padding: 0 0 2px 4px;
}
.org-group.collapsed .org-folder-list { display: none; }

#threadList .folder-group {
  padding: 0;
  background: transparent;
  border: none;
  cursor: default;
  display: block;
  margin: 4px 0 2px;
}
#threadList .folder-group:hover { background: transparent; }

/* Folder header (clickable) */
.folder-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px 6px 6px;
  border-radius: var(--radius);
  cursor: pointer;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 500;
  user-select: none;
  transition: background-color 120ms;
}
.folder-header:hover { background: var(--surface-sunk); color: var(--text); }
.folder-group.has-active .folder-header { color: var(--text); }

.folder-chevron {
  transition: transform 160ms ease;
  color: var(--text-faint);
  flex-shrink: 0;
}
.folder-group.collapsed .folder-chevron { transform: rotate(0deg); }
.folder-group:not(.collapsed) .folder-chevron { transform: rotate(90deg); }

.folder-icon {
  color: var(--text-faint);
  flex-shrink: 0;
}
/* has-active used to recolour the icon primary — demoted so project kind
   colour stays the primary scannable signal. Active thread still bolded
   via .folder-group.has-active .folder-header. */
.folder-group.has-active .folder-icon { /* kind colour wins */ }

/* ── Project kind colour-codes (8 Aug 2026) ──
   Sidebar folder icons + right folder-panel icons take their colour from
   projects.kind so live apps, demos, test sandboxes etc. are scannable.
   Activity is still shown via the green activity-dot (not icon recolour).

   Visual layers (strongest → softest):
     1. 3px left accent bar on the folder-group (non-normal only)
     2. Coloured + lightly-filled folder icon
     3. Tiny colour dot next to the path (non-normal only)
   Normal stays neutral slate so unmarked folders don't look "tagged". */
.folder-group.folder-kind-live,
.folder-group.folder-kind-development,
.folder-group.folder-kind-demo,
.folder-group.folder-kind-test {
  border-left: 3px solid transparent;
  border-radius: 0 6px 6px 0;
  padding-left: 2px;
  margin-left: 0;
}
.folder-group.folder-kind-live { border-left-color: #16A34A; }
.folder-group.folder-kind-development { border-left-color: #2563EB; }
.folder-group.folder-kind-demo { border-left-color: #7C3AED; }
.folder-group.folder-kind-test { border-left-color: #D97706; }

.folder-group.folder-kind-normal .folder-icon,
.folder-kind-icon[data-kind="normal"] { color: #94A3B8; }
.folder-group.folder-kind-live .folder-icon,
.folder-kind-icon[data-kind="live"] { color: #16A34A; fill: #16A34A; fill-opacity: 0.18; }
.folder-group.folder-kind-development .folder-icon,
.folder-kind-icon[data-kind="development"] { color: #2563EB; fill: #2563EB; fill-opacity: 0.18; }
.folder-group.folder-kind-demo .folder-icon,
.folder-kind-icon[data-kind="demo"] { color: #7C3AED; fill: #7C3AED; fill-opacity: 0.18; }
.folder-group.folder-kind-test .folder-icon,
.folder-kind-icon[data-kind="test"] { color: #D97706; fill: #D97706; fill-opacity: 0.18; }

/* Tiny swatch next to the folder path — only rendered for non-normal kinds */
.folder-kind-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  flex-shrink: 0;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.12);
}
.folder-kind-dot[data-kind="live"] { background: #16A34A; }
.folder-kind-dot[data-kind="development"] { background: #2563EB; }
.folder-kind-dot[data-kind="demo"] { background: #7C3AED; }
.folder-kind-dot[data-kind="test"] { background: #D97706; }

.folder-panel-item.folder-kind-normal .folder-panel-item-icon,
.folder-panel-item-icon.folder-kind-icon[data-kind="normal"] { color: #94A3B8; }
.folder-panel-item.folder-kind-live .folder-panel-item-icon,
.folder-panel-item-icon.folder-kind-icon[data-kind="live"] { color: #16A34A; }
.folder-panel-item.folder-kind-development .folder-panel-item-icon,
.folder-panel-item-icon.folder-kind-icon[data-kind="development"] { color: #2563EB; }
.folder-panel-item.folder-kind-demo .folder-panel-item-icon,
.folder-panel-item-icon.folder-kind-icon[data-kind="demo"] { color: #7C3AED; }
.folder-panel-item.folder-kind-test .folder-panel-item-icon,
.folder-panel-item-icon.folder-kind-icon[data-kind="test"] { color: #D97706; }

/* Left accent on right-panel folder rows for non-normal kinds */
.folder-panel-item.folder-kind-live { box-shadow: inset 3px 0 0 #16A34A; }
.folder-panel-item.folder-kind-development { box-shadow: inset 3px 0 0 #2563EB; }
.folder-panel-item.folder-kind-demo { box-shadow: inset 3px 0 0 #7C3AED; }
.folder-panel-item.folder-kind-test { box-shadow: inset 3px 0 0 #D97706; }

/* Kind picker popover (anchored to folder icon click) */
.project-kind-picker {
  position: fixed;
  z-index: 10050;
  min-width: 200px;
  max-width: 260px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
  box-shadow: 0 8px 28px rgba(15, 23, 42, 0.14), 0 2px 6px rgba(15, 23, 42, 0.06);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.project-kind-picker-head {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-faint, #94a3b8);
  padding: 6px 10px 4px;
}
.project-kind-picker-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text, #0f172a);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  text-align: left;
  padding: 8px 10px;
  border-radius: 7px;
  cursor: pointer;
  transition: background 100ms;
}
.project-kind-picker-item:hover {
  background: var(--surface-sunk, #f1f5f9);
}
.project-kind-picker-item.is-active {
  background: var(--primary-tint, rgba(13, 115, 119, 0.1));
  font-weight: 650;
}
.project-kind-swatch {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  flex-shrink: 0;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.08);
}
.project-kind-label { flex: 1; min-width: 0; }

.vision-kind-chip,
.project-card-kind {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-dim, #475569);
  background: var(--surface-sunk, #f1f5f9);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 999px;
  padding: 3px 10px 3px 7px;
  cursor: pointer;
  font-family: inherit;
  margin-bottom: 10px;
  transition: background 100ms, border-color 100ms;
}
.project-card-kind {
  margin-bottom: 0;
  margin-left: 6px;
  font-size: 10.5px;
  padding: 2px 8px 2px 6px;
}
.vision-kind-chip:hover,
.project-card-kind:hover {
  background: var(--surface, #fff);
  border-color: var(--text-faint, #94a3b8);
}

/* Left accent bar on dashboard project cards by kind */
.project-card.folder-kind-live { border-left: 3px solid #16A34A; }
.project-card.folder-kind-development { border-left: 3px solid #2563EB; }
.project-card.folder-kind-demo { border-left: 3px solid #7C3AED; }
.project-card.folder-kind-test { border-left: 3px solid #D97706; }
.project-card.folder-kind-normal { border-left: 3px solid transparent; }

html.theme-dark .folder-group.folder-kind-normal .folder-icon,
html.theme-dark .folder-kind-icon[data-kind="normal"] { color: #94A3B8; }
html.theme-dark .folder-group.folder-kind-live .folder-icon,
html.theme-dark .folder-kind-icon[data-kind="live"] { color: #4ADE80; fill: #4ADE80; fill-opacity: 0.22; }
html.theme-dark .folder-group.folder-kind-development .folder-icon,
html.theme-dark .folder-kind-icon[data-kind="development"] { color: #60A5FA; fill: #60A5FA; fill-opacity: 0.22; }
html.theme-dark .folder-group.folder-kind-demo .folder-icon,
html.theme-dark .folder-kind-icon[data-kind="demo"] { color: #A78BFA; fill: #A78BFA; fill-opacity: 0.22; }
html.theme-dark .folder-group.folder-kind-test .folder-icon,
html.theme-dark .folder-kind-icon[data-kind="test"] { color: #FBBF24; fill: #FBBF24; fill-opacity: 0.22; }

html.theme-dark .folder-kind-dot[data-kind="live"] { background: #4ADE80; }
html.theme-dark .folder-kind-dot[data-kind="development"] { background: #60A5FA; }
html.theme-dark .folder-kind-dot[data-kind="demo"] { background: #A78BFA; }
html.theme-dark .folder-kind-dot[data-kind="test"] { background: #FBBF24; }

html.theme-dark .folder-panel-item.folder-kind-live .folder-panel-item-icon { color: #4ADE80; }
html.theme-dark .folder-panel-item.folder-kind-development .folder-panel-item-icon { color: #60A5FA; }
html.theme-dark .folder-panel-item.folder-kind-demo .folder-panel-item-icon { color: #A78BFA; }
html.theme-dark .folder-panel-item.folder-kind-test .folder-panel-item-icon { color: #FBBF24; }

html.theme-dark .folder-panel-item.folder-kind-live { box-shadow: inset 3px 0 0 #4ADE80; }
html.theme-dark .folder-panel-item.folder-kind-development { box-shadow: inset 3px 0 0 #60A5FA; }
html.theme-dark .folder-panel-item.folder-kind-demo { box-shadow: inset 3px 0 0 #A78BFA; }
html.theme-dark .folder-panel-item.folder-kind-test { box-shadow: inset 3px 0 0 #FBBF24; }

html.theme-dark .project-kind-picker {
  background: var(--surface, #1e293b);
  border-color: var(--border, #334155);
  box-shadow: 0 10px 32px rgba(0,0,0,0.45);
}

.folder-path {
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  letter-spacing: 0.1px;
}

.folder-count {
  flex-shrink: 0;
  font-size: 10.5px;
  font-weight: 600;
  min-width: 20px;
  text-align: center;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--surface-sunk);
  color: var(--text-faint);
  letter-spacing: 0.2px;
}
.folder-live-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  color: var(--text-faint);
  text-decoration: none;
  flex-shrink: 0;
  transition: background-color 120ms, color 120ms;
}
.folder-live-link:hover {
  background: var(--primary-tint);
  color: var(--primary);
}
.folder-add-thread {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  border: none;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
  transition: background-color 120ms, color 120ms;
}
.folder-add-thread:hover {
  background: var(--primary-tint);
  color: var(--primary);
}
.folder-header:hover .folder-count { background: var(--surface); color: var(--text-dim); }
.folder-group.has-active .folder-count {
  background: var(--primary-tint-strong);
  color: var(--primary);
}

/* Sub-list of threads under each folder */
.folder-threads {
  list-style: none;
  margin: 2px 0 4px;
  padding: 0 0 0 4px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  border-left: 2px solid var(--border);
  margin-left: 12px;
  overflow: hidden;
  max-height: 2000px;
  transition: max-height 260ms ease, opacity 180ms ease, margin 180ms ease;
}
.folder-group.has-active .folder-threads { border-left-color: var(--primary-tint-strong); }
.folder-group.collapsed .folder-threads {
  max-height: 0;
  opacity: 0;
  margin: 0 0 0 12px;
  pointer-events: none;
}

.folder-threads li {
  padding: 8px 10px 8px 12px;
  border-radius: var(--radius);
  cursor: pointer;
  color: var(--text-muted);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background-color 120ms ease, color 120ms ease;
  border: 1px solid transparent;
}
.folder-threads li:hover { background: var(--surface-sunk); color: var(--text); }
.folder-threads li.active {
  background: var(--primary-tint);
  color: var(--primary);
  border-color: var(--primary-tint-strong);
  font-weight: 500;
}
.folder-threads li.active .when { color: var(--primary); opacity: 0.85; }

/* Empty-state li (kept for the "No threads yet" case) */
#threadList > li.empty {
  padding: 10px 12px;
  color: var(--text-faint);
  text-align: center;
  cursor: default;
}

/* Active-thread pin-mode toggle inside a folder-group's thread list — sits
   below the pinned active-thread row and reveals sibling threads on click.
   Same design language as the right folder-panel .folder-panel-others-toggle
   (dashed border · muted text · quiet utility affordance). Rendered as an
   <li> inside the .folder-threads <ul>, so we scope tightly to avoid
   inheriting the standard thread-row hover styles. */
.folder-threads li.thread-list-siblings-toggle {
  margin: 4px 0;
  padding: 6px 10px;
  background: transparent;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.2px;
  cursor: pointer;
  text-align: left;
  transition: background-color 120ms, color 120ms, border-color 120ms;
}
.folder-threads li.thread-list-siblings-toggle:hover {
  background: var(--surface-sunk);
  color: var(--text);
  border-color: var(--border-strong, var(--border));
}
.folder-threads li.thread-list-siblings-toggle:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Active-thread pin-collapse (20 Aug 2026 fix).
   When the folder contains the active thread AND state.threadListShowSiblings
   is false, renderThreadList adds `.pin-collapsed` to the folder-threads UL.
   Every sibling thread row (li[data-id] that is NOT .active) collapses so the
   pinned active thread + the "▼ Show N more thread…" toggle sit alone.
   Previously done via inline `row.style.display = 'none'`, but the search
   filter's own `apply()` on every re-render called `style.removeProperty(
   'display')` on the same rows, wiping the hide and leaving every sibling
   visible while the toggle text still said "Show N more…". A CSS class on
   the parent UL owns the hide instead of per-row inline styles, so the
   collapse can't be inadvertently reset by unrelated code paths. */
.folder-threads.pin-collapsed > li[data-id]:not(.active) {
  display: none;
}
#threadList li .thread-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: 1px;
}
#threadList li .title-row {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
}

/* Per-thread pin / unpin button. Sits at the trailing edge of every row in
   the sidebar threads list. Hidden by default; appears on row hover OR when
   the thread is already pinned (so the user can always see *that* it's
   pinned without hovering). Toggling it floats the thread to the top of
   its folder group via the per-user `thread_pins` table. */
.thread-pin-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 6px;
  border: none;
  background: transparent;
  color: var(--text-faint, #94a3b8);
  cursor: pointer;
  padding: 0;
  margin-left: 2px;
  opacity: 0;
  transition: opacity 0.12s ease, background 0.12s ease, color 0.12s ease;
}
#threadList li:hover .thread-pin-btn,
#threadList li:focus-within .thread-pin-btn,
.thread-pin-btn.is-pinned,
.thread-pin-btn:focus-visible {
  opacity: 1;
}
.thread-pin-btn:hover {
  background: var(--surface-sunk, rgba(0,0,0,0.04));
  color: var(--text, #0f172a);
}
.thread-pin-btn.is-pinned {
  color: var(--brand-amber, #f59e0b);
}
.thread-pin-btn.is-pinned:hover {
  color: var(--brand-amber, #f59e0b);
  background: rgba(245, 158, 11, 0.12);
}
/* Subtle marker on pinned rows so the eye picks them out even before reading
   the title: a thin amber left-edge accent. Doesn't shift layout because we
   use box-shadow inset instead of a border. */
#threadList li.is-pinned {
  box-shadow: inset 2px 0 0 var(--brand-amber, #f59e0b);
}

/* Blinking green activity indicator */
.activity-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #16A34A;
  flex-shrink: 0;
  display: inline-block;
  position: relative;
  box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.6);
  animation: activityPulse 1.2s ease-in-out infinite;
}
.activity-dot::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 1.5px solid rgba(22, 163, 74, 0.35);
  opacity: 0;
  animation: activityRing 1.2s ease-in-out infinite;
}
@keyframes activityPulse {
  0%, 100% {
    background: #16A34A;
    box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.5);
  }
  50% {
    background: #22C55E;
    box-shadow: 0 0 0 4px rgba(22, 163, 74, 0.0);
  }
}
@keyframes activityRing {
  0%   { opacity: 0.6; transform: scale(0.8); }
  80%  { opacity: 0; transform: scale(1.6); }
  100% { opacity: 0; transform: scale(1.6); }
}
.folder-activity-dot {
  margin: 0 2px 0 4px;
}
.folder-group.has-active-prompts .folder-header { color: var(--text); }
/* Activity is shown via the green activity-dot — do NOT recolour the
   folder icon (that colour now encodes project kind). Kept as a no-op
   so older cascade expectations don't break. */
.folder-group.has-active-prompts .folder-icon { /* kind colour wins */ }

/* "A prompt just ended" indicator — glowing yellow dot for ~30s after a prompt in the
   thread completes (or red, when it errored out). Sits in the same slot as the green
   activity dot but with a slower, calmer breath so it reads as "look at me but I'm
   not urgent". Auto-clears via the JS recent-end ticker. */
.recent-end-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #F59E0B;
  flex-shrink: 0;
  display: inline-block;
  position: relative;
  box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.6);
  animation: recentEndPulse 1.6s ease-in-out infinite;
}
.recent-end-dot::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 1.5px solid rgba(245, 158, 11, 0.45);
  opacity: 0;
  animation: recentEndRing 1.6s ease-in-out infinite;
}
.recent-end-dot.is-error {
  background: #DC2626;
  box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.6);
  animation-name: recentEndPulseError;
}
.recent-end-dot.is-error::after {
  border-color: rgba(220, 38, 38, 0.5);
  animation-name: recentEndRingError;
}
@keyframes recentEndPulse {
  0%, 100% { background: #F59E0B; box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.55); }
  50%      { background: #FBBF24; box-shadow: 0 0 0 6px rgba(245, 158, 11, 0); }
}
@keyframes recentEndRing {
  0%   { opacity: 0.6; transform: scale(0.8); }
  80%  { opacity: 0; transform: scale(2.0); }
  100% { opacity: 0; transform: scale(2.0); }
}
@keyframes recentEndPulseError {
  0%, 100% { background: #DC2626; box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.55); }
  50%      { background: #EF4444; box-shadow: 0 0 0 6px rgba(220, 38, 38, 0); }
}
@keyframes recentEndRingError {
  0%   { opacity: 0.6; transform: scale(0.8); }
  80%  { opacity: 0; transform: scale(2.0); }
  100% { opacity: 0; transform: scale(2.0); }
}

/* Reduce motion: stop the animation for users who prefer it */
@media (prefers-reduced-motion: reduce) {
  .activity-dot,
  .activity-dot::after,
  .recent-end-dot,
  .recent-end-dot::after { animation: none !important; }
}
#threadList li .title {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 13.5px;
}
#threadList li .thread-folder {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px;
  color: var(--text-faint);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  letter-spacing: 0.1px;
}
#threadList li.active .thread-folder {
  color: var(--primary);
  opacity: 0.75;
}
/* Content-search snippet — appended under the title when
   /api/threads/search-content returns a hit for the row. Single-line,
   faded, italic; the server has already wrapped …context around the
   matched substring. */
#threadList li .thread-snippet {
  font-size: 11px;
  line-height: 1.35;
  color: var(--text-faint);
  margin-top: 2px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-style: italic;
}
#threadList li.content-match .title {
  font-weight: 600;
}
#threadList li.active .thread-snippet {
  color: var(--primary);
  opacity: 0.85;
}
#threadList li .when {
  font-size: 11px;
  color: var(--text-faint);
  flex-shrink: 0;
}
#threadList .empty {
  color: var(--text-faint);
  text-align: center;
  padding: 28px 16px;
  font-size: 13px;
  cursor: default;
}
#threadList .empty:hover { background: transparent; color: var(--text-faint); }

/* ========== Main container (holds Chat + Dashboard + Project brain) ========== */
#main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  height: 100%;
  position: relative;
  overflow: hidden;
}

/* ========== Primary sections ========== */
/* Every top-level view under #main must be a flex column with height:100%
   + overflow:hidden so its inner body (the element with overflow-y:auto)
   becomes the single scroll surface. Missing entries clip at the fold
   with no scrollbar — body itself is overflow:hidden globally. */
#chat, #dashboard, #project, #wizardSection,
#myDocsView, #myMeetingsView, #ideaQueueView, #actionsPendingView,
#cursorSetupView, #myClientsView, #backupsView,
#myTasksView, #myTeamView, #myChatsView, #myAgentsView, #mastersView,
#myCalendarView, #myTravelPlansView, #myHiringView, #myTeamProfilesView,
#agentDispatchesView,
#organisationsView, #myOrgView, #storageView,
#runtimeModelView, #softRestartView, #myNotesView {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  flex: 1 1 auto;
  height: 100%;
  background: var(--bg);
  overflow: hidden;
}
#chat.hidden, #dashboard.hidden, #project.hidden, #wizardSection.hidden,
#myDocsView.hidden, #myMeetingsView.hidden, #ideaQueueView.hidden, #actionsPendingView.hidden,
#cursorSetupView.hidden, #myClientsView.hidden, #backupsView.hidden,
#myTasksView.hidden, #myTeamView.hidden, #myChatsView.hidden, #myAgentsView.hidden,
#mastersView.hidden,
#myCalendarView.hidden, #myTravelPlansView.hidden, #myHiringView.hidden,
#myTeamProfilesView.hidden, #agentDispatchesView.hidden,
#organisationsView.hidden, #myOrgView.hidden, #storageView.hidden,
#runtimeModelView.hidden, #softRestartView.hidden, #myNotesView.hidden { display: none !important; }

/* My Clients — sidebar submenu and inline composer. The submenu sits
   under the parent button and reveals five sub-tabs as compact rows. */
.sidebar-chevron {
  margin-left: auto;
  font-size: 11px;
  color: var(--muted);
  transition: transform 0.15s ease;
}
.sidebar-dashboard-btn[aria-expanded="true"] .sidebar-chevron {
  transform: rotate(180deg);
}
.sidebar-submenu {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 2px 0 6px 14px;
  border-left: 2px solid var(--border);
  margin-left: 18px;
}
.sidebar-submenu[hidden] { display: none; }
.sidebar-submenu-btn {
  appearance: none;
  background: transparent;
  border: 0;
  text-align: left;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  margin: 0;
  border-radius: 6px;
  color: var(--text);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}
.sidebar-submenu-btn:hover { background: var(--surface-hover, rgba(0,0,0,0.04)); }
.sidebar-submenu-btn.active {
  background: var(--brand-teal-tint, rgba(13,115,119,0.10));
  color: var(--brand-teal, #0d7377);
  font-weight: 600;
}
.sidebar-submenu-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: 0 0 8px;
  box-shadow: 0 0 0 1.5px rgba(255,255,255,0.7);
}

.my-clients-composer {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 10px;
  padding: 14px 16px;
  margin: 12px;
  display: grid;
  gap: 10px;
}
.my-clients-composer.hidden { display: none; }
.my-clients-composer .row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.my-clients-composer label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.my-clients-composer input,
.my-clients-composer select,
.my-clients-composer textarea {
  font: inherit;
  font-size: 13.5px;
  font-weight: 400;
  color: var(--text);
  text-transform: none;
  letter-spacing: normal;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
}
.my-clients-composer textarea { min-height: 70px; resize: vertical; }
.my-clients-composer .composer-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}

.client-row {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 9px;
  padding: 12px 14px;
  margin: 8px 12px;
  display: grid;
  gap: 6px;
}
.client-row .crow-top {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.client-row .crow-title { font-weight: 700; font-size: 14px; color: var(--text); }
.client-row .crow-sub   { font-size: 12px; color: var(--muted); }
.client-row .crow-body  { font-size: 13px; color: var(--text); white-space: pre-wrap; }
.client-row .crow-tags  { display: flex; flex-wrap: wrap; gap: 6px; }
.client-row .crow-tag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600;
  background: rgba(0,0,0,0.05); color: var(--muted);
}
.client-row .crow-tag.status-new        { background: rgba(59,130,246,0.12); color: #2563eb; }
.client-row .crow-tag.status-contacted  { background: rgba(124,58,237,0.12); color: #7c3aed; }
.client-row .crow-tag.status-qualified  { background: rgba(13,115,119,0.12); color: var(--brand-teal, #0d7377); }
.client-row .crow-tag.status-proposal   { background: rgba(245,158,11,0.16); color: #b45309; }
.client-row .crow-tag.status-won        { background: rgba(16,185,129,0.16); color: #047857; }
.client-row .crow-tag.status-lost       { background: rgba(220,38,38,0.12); color: #b91c1c; }
.client-row .crow-tag.status-scheduled  { background: rgba(59,130,246,0.12); color: #2563eb; }
.client-row .crow-tag.status-completed  { background: rgba(16,185,129,0.16); color: #047857; }
.client-row .crow-tag.status-cancelled  { background: rgba(220,38,38,0.12); color: #b91c1c; }
.client-row .crow-tag.status-no_show    { background: rgba(245,158,11,0.16); color: #b45309; }
.client-row .crow-tag.status-open       { background: rgba(245,158,11,0.16); color: #b45309; }
.client-row .crow-tag.status-in_progress{ background: rgba(59,130,246,0.12); color: #2563eb; }
.client-row .crow-tag.status-resolved   { background: rgba(16,185,129,0.16); color: #047857; }
.client-row .crow-tag.status-closed     { background: rgba(107,114,128,0.16); color: #4b5563; }
.client-row .crow-tag.sev-low      { background: rgba(107,114,128,0.16); color: #4b5563; }
.client-row .crow-tag.sev-medium   { background: rgba(245,158,11,0.16); color: #b45309; }
.client-row .crow-tag.sev-high     { background: rgba(239,68,68,0.18);  color: #b91c1c; }
.client-row .crow-tag.sev-urgent   { background: rgba(220,38,38,0.85);  color: #fff; }
.client-row .crow-actions {
  display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px;
}
.client-row .crow-actions button {
  appearance: none; border: 1px solid var(--border);
  background: var(--bg); color: var(--text);
  font: inherit; font-size: 11.5px; font-weight: 600;
  padding: 4px 9px; border-radius: 6px; cursor: pointer;
}
.client-row .crow-actions button:hover { background: var(--surface-hover, rgba(0,0,0,0.04)); }
.client-row .crow-actions button.danger { color: #b91c1c; border-color: rgba(220,38,38,0.35); }
.client-row .crow-rating { color: #f59e0b; letter-spacing: 1px; }

/* ─── Complaints feature: QR codes / matrix / detail panels ─── */
.complaints-card {
  background: var(--card, #fff); border: 1px solid var(--border);
  border-radius: 10px; padding: 14px; margin-bottom: 10px;
  display: flex; flex-direction: column; gap: 8px;
}
.complaints-card.muted { opacity: 0.7; }
.complaints-card .row-top { display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap; }
.complaints-card .title { font-weight: 700; font-size: 14px; color: var(--text); }
.complaints-card .sub { font-size: 12.5px; color: var(--muted); }
.complaints-card .url {
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12px;
  color: var(--muted); word-break: break-all;
  background: rgba(0,0,0,0.04); padding: 4px 8px; border-radius: 6px; display: inline-block;
}
.complaints-card .actions {
  display: flex; gap: 6px; flex-wrap: wrap;
}
.complaints-card .actions a, .complaints-card .actions button {
  appearance: none; border: 1px solid var(--border); background: var(--bg); color: var(--text);
  font: inherit; font-size: 11.5px; font-weight: 600;
  padding: 4px 9px; border-radius: 6px; cursor: pointer; text-decoration: none;
}
.complaints-card .actions button.danger { color: #b91c1c; border-color: rgba(220,38,38,0.35); }
.complaints-card .actions button.primary { background: var(--brand-blue, #1878D0); color: #fff; border-color: var(--brand-blue, #1878D0); }
.complaints-grid { display: grid; gap: 10px; grid-template-columns: 180px 1fr; align-items: center; }
.complaints-grid label { font-size: 12.5px; color: var(--muted); font-weight: 600; }
.complaints-grid input, .complaints-grid select, .complaints-grid textarea {
  width: 100%; padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); color: var(--text); font: inherit;
}
.complaints-matrix-row {
  display: grid; gap: 8px; grid-template-columns: 60px 1fr 1fr 1fr 80px 36px;
  align-items: center; padding: 8px 0; border-bottom: 1px dashed var(--border);
}
.complaints-matrix-row .lvl-num {
  width: 36px; height: 36px; border-radius: 50%; background: var(--brand-blue-bg, rgba(24,120,208,.12));
  color: var(--brand-blue, #1878D0); font-weight: 700; display: inline-flex; align-items: center; justify-content: center;
}
.complaints-event {
  display: flex; gap: 10px; padding: 8px 10px; border-left: 2px solid var(--border);
  margin-bottom: 4px; font-size: 13px; color: var(--text);
}
.complaints-event.escalated { border-left-color: #f59e0b; }
.complaints-event.public_response { border-left-color: var(--brand-blue, #1878D0); }
.complaints-event.internal_note { border-left-color: #6b7280; background: rgba(107,114,128,.05); }
.complaints-event.status_change { border-left-color: #047857; }
.complaints-event .ts { color: var(--muted); font-size: 11.5px; }
.complaints-empty {
  padding: 20px; text-align: center; color: var(--muted); font-size: 13px; border: 1px dashed var(--border); border-radius: 8px;
}
@media (max-width: 700px) {
  .complaints-grid { grid-template-columns: 1fr; }
  .complaints-matrix-row { grid-template-columns: 60px 1fr 1fr 80px 36px; }
}

/* Inner scrolling bodies — the header stays sticky at the top while
   the body scrolls under it. Without this the page just clips at
   the viewport and you can't reach content past the fold. */
.my-docs-body,
#myMeetingsBody,
#ideaQueueBody,
#cursorSetupBody,
.actions-pending-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

#chatHeader {
  padding: 14px 28px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--surface);
  min-height: 64px;
  flex-shrink: 0;
  z-index: 1;
}
.chat-title-wrap {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
/* 2026-08-19 · Chat-header height fix ─────────────────────────────────
   Only the chat page's `.chat-title-wrap` (which wraps a `.thread-title-row`
   as its FIRST child + a series of meta chips as siblings) was stacking each
   chip on its own row. That made the header ~4 rows tall and left a huge
   empty gutter on the right beside the action buttons. Opt in to a horizontal
   flex-wrap row ONLY when we detect the chat-page shape (`:has(> .thread-title-row)`),
   so other pages that use `.chat-title-wrap` with `<h2>` + `<span.chat-subtitle>`
   (dashboard, URLs, menu tiles, etc.) keep their column layout unchanged. */
.chat-title-wrap:has(> .thread-title-row) {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
}
.chat-title-wrap:has(> .thread-title-row) > .thread-title-row {
  flex: 0 0 100%;
}
.chat-title-wrap:has(> .thread-title-row) > .cwd-chip,
.chat-title-wrap:has(> .thread-title-row) > .thread-collaborators-chip,
.chat-title-wrap:has(> .thread-title-row) > .whatsapp-connection-badge,
.chat-title-wrap:has(> .thread-title-row) > .thread-tagged-agents {
  margin-top: 0;   /* reset the per-chip `margin-top:4px` that produced the
                     stacked-column rhythm — the row-level `gap:4px` now
                     owns vertical spacing. */
}
.thread-title-row {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.thread-rename-btn {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 6px;
  background: transparent;
  border: none;
  color: var(--text-faint);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: background-color 120ms, color 120ms, opacity 120ms;
}
.thread-rename-btn:hover:not(:disabled) {
  background: var(--primary-tint);
  color: var(--primary);
}
.thread-rename-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}
.thread-rename-btn:disabled {
  opacity: 0;
  pointer-events: none;
}
#chatHeader h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  color: var(--text);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  max-width: 60ch;
}
.chat-subtitle {
  font-size: 11.5px;
  color: var(--text-faint);
  letter-spacing: 0.2px;
}

.project-title-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.project-rename-btn {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 6px;
  background: transparent;
  border: none;
  color: var(--text-faint);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background-color 120ms, color 120ms;
}
.project-rename-btn:hover {
  background: var(--primary-tint);
  color: var(--primary);
}

.cwd-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 4px;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  line-height: 1.4;
  cursor: pointer;
  max-width: 48ch;
  transition: background-color 120ms, border-color 120ms, color 120ms;
  align-self: flex-start;
}
.cwd-chip svg { opacity: 0.7; flex-shrink: 0; }
.cwd-chip span {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.cwd-chip:hover:not(:disabled) {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
  color: var(--primary);
}
.cwd-chip:hover:not(:disabled) svg { opacity: 1; }
.cwd-chip.is-default {
  color: var(--text-faint);
  border-style: dashed;
}

/* ── Thread collaborators chip (7 Aug 2026 · aiassiztant ask) ─────────
   Prominent avatar stack next to .cwd-chip in the thread header. Same
   pill shell as .cwd-chip so the two chips read as siblings on the
   same row ("this thread is in <folder>, being worked on with
   <these people>"). Auto-hides when the viewer is the only participant.
   Cross-UI parity with .thread-tile-coworkers on tile view + the
   Mini App #tgThreadCollaborators inline block. */
.thread-collaborators-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  padding: 2px 10px 2px 8px;
  border-radius: 999px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 11.5px;
  line-height: 1.4;
  cursor: pointer;
  align-self: flex-start;
  font-family: inherit;
  appearance: none;
  transition: background-color 120ms, border-color 120ms, color 120ms;
}
.thread-collaborators-chip svg { opacity: 0.7; flex-shrink: 0; }
.thread-collaborators-chip:hover:not(:disabled) {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
  color: var(--primary);
}
.thread-collaborators-chip:hover:not(:disabled) svg { opacity: 1; }
.thread-collaborators-avatars {
  display: inline-flex;
  align-items: center;
  gap: 0;
}
.thread-collaborator {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--primary-tint, rgba(0,120,191,0.14));
  color: var(--primary, #0078BF);
  font-size: 10.5px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid var(--surface, #fff);
  margin-left: -6px;
  text-transform: uppercase;
  line-height: 1;
}
.thread-collaborator:first-child { margin-left: 0; }
.thread-collaborators-count {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
  padding-left: 2px;
}
.thread-collaborators-chip:hover:not(:disabled) .thread-collaborators-count {
  color: var(--primary);
}
@media (max-width: 720px) {
  .thread-collaborators-chip { font-size: 10.5px; padding: 2px 8px 2px 6px; }
  .thread-collaborator { width: 18px; height: 18px; font-size: 9.5px; }
}

/* ── WhatsApp connection badge (22 Jul 2026 · aiassiztant ask) ─────────
   Prominent read-only pill in the thread header that surfaces who is
   bridged to WhatsApp for the current thread. WhatsApp brand green so
   it reads as an *external comms* signal at a glance — distinct from
   the neutral .cwd-chip that shares the same row. Auto-hides itself
   when there are no active bridges (see refreshWhatsAppConnectionBadge
   in web/app.js). Owner/admin click opens the manage panel; members
   get the participant list via the title/aria-label tooltip. */
.whatsapp-connection-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  padding: 3px 12px;
  border-radius: 999px;
  /* WhatsApp brand green (#25D366) as a soft tint so it doesn't
     dominate the header, with the darker green for text + icon. */
  background: rgba(37, 211, 102, 0.14);
  border: 1px solid rgba(37, 211, 102, 0.55);
  color: #0f7a3e;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.35;
  cursor: pointer;
  max-width: 64ch;
  transition: background-color 120ms, border-color 120ms, color 120ms, transform 120ms;
  align-self: flex-start;
}
.whatsapp-connection-badge svg { flex-shrink: 0; opacity: 0.85; }
.whatsapp-connection-badge span {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.whatsapp-connection-badge:hover {
  background: rgba(37, 211, 102, 0.22);
  border-color: rgba(37, 211, 102, 0.85);
  color: #0a5f30;
}
.whatsapp-connection-badge:hover svg { opacity: 1; }
.whatsapp-connection-badge:focus-visible {
  outline: 2px solid #25D366;
  outline-offset: 2px;
}
/* Dark-theme tuning — the WhatsApp green still reads as green on dark
   surfaces, but the muted mid-tone body copy needs a lighter fill so
   the pill doesn't visually recede. */
@media (prefers-color-scheme: dark) {
  .whatsapp-connection-badge {
    background: rgba(37, 211, 102, 0.18);
    border-color: rgba(37, 211, 102, 0.65);
    color: #3edb85;
  }
  .whatsapp-connection-badge:hover {
    background: rgba(37, 211, 102, 0.28);
    border-color: rgba(37, 211, 102, 0.95);
    color: #6ff0a5;
  }
}
[data-theme="dark"] .whatsapp-connection-badge {
  background: rgba(37, 211, 102, 0.18);
  border-color: rgba(37, 211, 102, 0.65);
  color: #3edb85;
}
[data-theme="dark"] .whatsapp-connection-badge:hover {
  background: rgba(37, 211, 102, 0.28);
  border-color: rgba(37, 211, 102, 0.95);
  color: #6ff0a5;
}

/* ── Tagged agents strip (23 Jul 2026 · aiassiztant ask) ──
   Chips + "Tag agent" trigger below the thread title. When tagged,
   an agent listens to every prompt + assistant reply (folded into its
   shorttermmemory.md) AND its soul + memory tiers are folded into the
   preamble on every prompt. Popover uses a searchable-combobox pattern
   per the design-rules block. */
.thread-tagged-agents {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  flex-wrap: wrap;
  align-self: flex-start;
  max-width: 100%;
}
.thread-tagged-agents-label {
  font-size: 12px;
  opacity: 0.75;
  user-select: none;
  cursor: help;
}
.thread-tagged-agents-list {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}
.thread-tagged-agent-chip {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px 6px 2px 8px;
  border-radius: 999px;
  background: rgba(0, 120, 191, 0.10);   /* HODO primary blue tint */
  border: 1px solid rgba(0, 120, 191, 0.45);
  color: #0078BF;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.35;
  max-width: 22ch;
}
.thread-tagged-agent-slug {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.thread-tagged-agent-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border: 0;
  background: transparent;
  color: inherit;
  opacity: 0.65;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  border-radius: 999px;
  padding: 0;
}
.thread-tagged-agent-remove:hover {
  opacity: 1;
  background: rgba(0, 120, 191, 0.20);
}
.thread-tag-agent-btn {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border-radius: 999px;
  background: transparent;
  border: 1px dashed rgba(0, 120, 191, 0.55);
  color: #0078BF;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  line-height: 1.35;
  transition: background-color 120ms, border-color 120ms;
}
.thread-tag-agent-btn:hover:not(:disabled) {
  background: rgba(0, 120, 191, 0.10);
  border-color: rgba(0, 120, 191, 0.85);
  border-style: solid;
}
.thread-tag-agent-btn:focus-visible {
  outline: 2px solid #0078BF;
  outline-offset: 2px;
}
.thread-tag-agent-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Dark-theme tuning */
@media (prefers-color-scheme: dark) {
  .thread-tagged-agent-chip {
    background: rgba(0, 120, 191, 0.22);
    border-color: rgba(0, 120, 191, 0.70);
    color: #6ec8ff;
  }
  .thread-tagged-agent-remove:hover {
    background: rgba(0, 120, 191, 0.35);
  }
  .thread-tag-agent-btn {
    border-color: rgba(0, 120, 191, 0.65);
    color: #6ec8ff;
  }
  .thread-tag-agent-btn:hover:not(:disabled) {
    background: rgba(0, 120, 191, 0.20);
    border-color: rgba(0, 120, 191, 0.95);
  }
}
[data-theme="dark"] .thread-tagged-agent-chip {
  background: rgba(0, 120, 191, 0.22);
  border-color: rgba(0, 120, 191, 0.70);
  color: #6ec8ff;
}
[data-theme="dark"] .thread-tagged-agent-remove:hover {
  background: rgba(0, 120, 191, 0.35);
}
[data-theme="dark"] .thread-tag-agent-btn {
  border-color: rgba(0, 120, 191, 0.65);
  color: #6ec8ff;
}
[data-theme="dark"] .thread-tag-agent-btn:hover:not(:disabled) {
  background: rgba(0, 120, 191, 0.20);
  border-color: rgba(0, 120, 191, 0.95);
}

/* Popover for the "Tag agent" searchable-combobox. Portalled into <body>
   so it escapes the chat-header overflow clipping. */
.tag-agent-picker {
  position: absolute;
  z-index: 1200;
  min-width: 260px;
  max-width: 340px;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.14);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.tag-agent-picker-input {
  width: 100%;
  padding: 6px 10px;
  border: 1px solid rgba(0, 0, 0, 0.15);
  border-radius: 6px;
  font-size: 13px;
  outline: none;
}
.tag-agent-picker-input:focus {
  border-color: #0078BF;
  box-shadow: 0 0 0 2px rgba(0, 120, 191, 0.20);
}
.tag-agent-picker-list {
  list-style: none;
  padding: 0;
  margin: 0;
  max-height: 280px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.tag-agent-picker-row {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 6px 10px;
  border-radius: 6px;
  cursor: pointer;
  line-height: 1.3;
}
.tag-agent-picker-row.is-active {
  background: rgba(0, 120, 191, 0.12);
}
.tag-agent-picker-slug {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  font-weight: 600;
  color: #0078BF;
}
.tag-agent-picker-name {
  font-size: 12px;
  color: rgba(0, 0, 0, 0.75);
}
.tag-agent-picker-desc {
  font-size: 11px;
  color: rgba(0, 0, 0, 0.55);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.tag-agent-picker-empty {
  padding: 8px 10px;
  font-size: 12px;
  color: rgba(0, 0, 0, 0.55);
  text-align: center;
}
@media (prefers-color-scheme: dark) {
  .tag-agent-picker {
    background: #1a2233;
    border-color: rgba(255, 255, 255, 0.12);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.60);
  }
  .tag-agent-picker-input {
    background: #0f1626;
    color: #e5e7eb;
    border-color: rgba(255, 255, 255, 0.15);
  }
  .tag-agent-picker-row.is-active {
    background: rgba(0, 120, 191, 0.28);
  }
  .tag-agent-picker-slug { color: #6ec8ff; }
  .tag-agent-picker-name { color: rgba(255, 255, 255, 0.80); }
  .tag-agent-picker-desc { color: rgba(255, 255, 255, 0.55); }
  .tag-agent-picker-empty { color: rgba(255, 255, 255, 0.55); }
}
[data-theme="dark"] .tag-agent-picker {
  background: #1a2233;
  border-color: rgba(255, 255, 255, 0.12);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.60);
}
[data-theme="dark"] .tag-agent-picker-input {
  background: #0f1626;
  color: #e5e7eb;
  border-color: rgba(255, 255, 255, 0.15);
}
[data-theme="dark"] .tag-agent-picker-row.is-active {
  background: rgba(0, 120, 191, 0.28);
}
[data-theme="dark"] .tag-agent-picker-slug { color: #6ec8ff; }
[data-theme="dark"] .tag-agent-picker-name { color: rgba(255, 255, 255, 0.80); }
[data-theme="dark"] .tag-agent-picker-desc { color: rgba(255, 255, 255, 0.55); }
[data-theme="dark"] .tag-agent-picker-empty { color: rgba(255, 255, 255, 0.55); }

/* Shared page-header toolbar — used on My Calendar, My Meetings, My Travel
   Plans, My Hiring, Agent Dispatches, etc. Wraps onto multiple lines when
   the row gets too tight so controls never crush each other; vertical
   alignment is centred so segmented controls + tall buttons + plain labels
   sit on the same baseline. */
.header-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  row-gap: 8px;
  flex-shrink: 0;
  /* Push the toolbar away from a long subtitle so the wrap point lives at
     the natural break, not on top of the title. */
  justify-content: flex-end;
}
/* When the header carries an inline label (e.g. the calendar's
   "Thursday, June 25, 2026" or a meeting count) it should hold its
   natural width and not be the thing that gets squeezed first. */
.header-actions > .chat-subtitle {
  flex-shrink: 0;
  white-space: nowrap;
  color: var(--text-muted, #475569);
  font-size: 12.5px;
  padding: 0 6px;
}
/* Visual separator between toolbar clusters (segmented control · nav ·
   picker · refresh+back). Subtle so it groups without shouting. */
.header-actions .toolbar-sep {
  width: 1px;
  align-self: stretch;
  background: var(--divider, #e2e8f0);
  margin: 4px 2px;
}
@media (max-width: 720px) {
  /* On phones the header naturally stacks; tighten gaps a touch so the
     extra row of buttons doesn't double the header's height. */
  .header-actions { gap: 6px; row-gap: 6px; }
}

/* ── Header ⋯ overflow menu (2026-08-25 · Musheer ask) ──────────────────
   Terminal, Share, Visit App, WhatsApp, Delete collapsed into a dropdown
   so only Search + Git remain always-visible in the header bar. This cuts
   the header from 2-row-wrapped to a single compact 40px row. */
.header-more-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.header-more-btn {
  /* Same size as other header ghost buttons */
  padding: 0 8px;
  min-width: 32px;
  height: 32px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  background: transparent;
  border: none;
  cursor: pointer;
  transition: background 120ms, color 120ms;
  flex-shrink: 0;
}
.header-more-btn:hover:not(:disabled) {
  background: var(--primary-tint, #e0f2f1);
  color: var(--primary, #0D7377);
}
.header-more-btn:disabled { opacity: 0.4; cursor: default; }
.header-more-btn[aria-expanded="true"] {
  background: var(--primary-tint, #e0f2f1);
  color: var(--primary, #0D7377);
}

.header-more-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 180px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0,0,0,.12), 0 2px 6px rgba(0,0,0,.06);
  z-index: 600;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Animate open */
  transform-origin: top right;
  animation: headerMoreIn 140ms ease;
}
.header-more-dropdown[hidden] { display: none; }
@keyframes headerMoreIn {
  from { opacity: 0; transform: scale(.93) translateY(-4px); }
  to   { opacity: 1; transform: scale(1)  translateY(0);     }
}

.header-more-item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 10px;
  border-radius: 8px;
  background: transparent;
  border: none;
  color: var(--text, #1e293b);
  font-size: 13.5px;
  font-family: inherit;
  font-weight: 400;
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
  transition: background 100ms, color 100ms;
}
.header-more-item:hover:not(:disabled) {
  background: var(--primary-tint, #e0f2f1);
  color: var(--primary, #0D7377);
}
.header-more-item:disabled { opacity: 0.4; cursor: default; }
/* Hidden-from-DOM items (e.g. Terminal before git-repo detected) */
.header-more-item.hidden { display: none !important; }

.header-more-item--danger { color: var(--danger, #dc2626); }
.header-more-item--danger:hover:not(:disabled) {
  background: #fee2e2;
  color: var(--danger, #dc2626);
}

.header-more-sep {
  height: 1px;
  background: var(--border, #e2e8f0);
  margin: 4px 4px;
}

/* ========== Messages ========== */
/* The chat column anchors the floating "Jump to latest" pill that appears
   when the user has scrolled up while streaming tokens are still arriving. */
#chat { position: relative; }
#messages {
  flex: 1 1 auto;
  min-height: 0;
  /* ALWAYS-VISIBLE scrollbar (27 Jul 2026 · Ashfak · v5). `overflow-y:
     scroll` forces the scrollbar track to be rendered even when the
     thread hasn't overflowed yet, so the reader never sees a gutter
     appear/disappear mid-conversation. Paired with `scrollbar-gutter:
     stable`, the reserved rail is 100% consistent. */
  overflow-y: scroll;
  overflow-x: hidden;
  padding: 28px 28px 12px;
  scroll-behavior: smooth;
  /* Modern-AI-chat feel (24 Jul 2026 · Ashfak) — dedicated scroll container
     with contained overscroll (no page bounce), iOS momentum, stable
     scrollbar gutter so content doesn't reflow when the scrollbar
     appears/disappears, and Chromium scroll-anchoring so appended
     bubbles don't yank the viewport. */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-gutter: stable;
  overflow-anchor: auto;
  /* NATIVE scrollbar restored + PERMANENTLY VISIBLE (27 Jul 2026 · Ashfak
     · v5). Previously we inherited `scrollbar-width: thin` from the
     global `* { scrollbar-width: thin }` (line ~3397 / ~14476). On
     Chromium 121+ that inheritance collapses the ::-webkit-scrollbar
     rules AND opts into the OS overlay/auto-fade scrollbar — which is
     the "thumb only appears on hover" behaviour the user reported.
     Explicitly setting `scrollbar-width: auto` on #messages restores
     classic (always-visible, non-overlay) scrollbar mode across
     Chromium and Firefox, and re-enables the ::-webkit-scrollbar
     styling below. Idle → still visible; hover → slightly stronger. */
  scrollbar-width: auto;
  /* Explicitly RESET scrollbar-color to `auto` (v7 · 27 Jul 2026 · Ashfak).
     The global `* { scrollbar-color: var(--border-strong) transparent }`
     at line ~3398 was cascading a value here even without a declaration
     on this selector — that engaged Chromium 121+'s themed-scrollbar
     path (Windows 11 Fluent overlay · macOS trackpad auto-hide) which
     is the "only shows on hover" behaviour the user reported. Setting
     `auto` clears the inheritance so the ::-webkit-scrollbar rules below
     become authoritative and render a classic always-visible thumb +
     track. Firefox fallback is handled in the @supports block below. */
  scrollbar-color: auto;
}

/* Firefox-only scrollbar colour (does not fire on Chromium/WebKit).
   The @supports selector `-moz-appearance` is Firefox-specific — this
   block never engages Chromium's themed-scrollbar overlay path. */
@supports (-moz-appearance: none) {
  #messages {
    scrollbar-color: var(--text-faint) transparent;
  }
}

/* WebKit / Chromium classic-scrollbar path (v9 · 27 Jul 2026 · Ashfak).
   Matches the sidebar `.chat-nav-list` house pattern (line ~1823) that
   the user pointed to in their reference image: SLIM 10px rail,
   TRANSPARENT track (no chunky grey column), and a subtle-but-solid
   dark thumb that reads clearly on the light chat surface without
   dominating the viewport. Rejects the v8 chunky 14px + tinted-track
   look — user feedback: "still like that only see the first image i
   need like that" (image 1 = clean slim pattern from sidebar).

   `-webkit-appearance: none` is retained so Chromium 121+ stays on the
   classic always-visible drawing path and does NOT regress to the
   Windows Fluent hover-only overlay. Track background is transparent
   so the rail visually disappears — only the thumb reads. Scoped to
   #messages only, cannot leak elsewhere. */
/* v14 (27 Jul 2026 · Ashfak): drop `-webkit-appearance: none` so Chromium
   renders the native arrow buttons at the top + bottom of the rail — the
   exact same rendering the sidebar `.chat-nav-list` gets by NOT declaring
   the override. User pointed to the sidebar's arrows in image 1 as the
   desired look; our v13 SVG-mask custom arrows weren't rendering visibly
   enough. Mirroring the sidebar verbatim (no appearance override, no
   custom button rule) gets us the native arrows for free. */
#messages::-webkit-scrollbar {
  width: 8px;
  height: 8px;
  background: transparent;
}
#messages::-webkit-scrollbar-track {
  background: transparent !important;
  border-radius: 999px;
}
/* Thumb v12 (27 Jul 2026 · Ashfak): mirror `.chat-nav-list` sidebar
   pattern verbatim — user pointed to the sidebar scrollbar in image 1
   as the desired look (slim + light + subtle · floating pill). v11's
   chunky #4a5568 12px dark rail was too heavy · v10's 0.70 alpha was
   too washed out. This pattern is the exact same colour + width the
   sidebar uses at line ~1823 (`.chat-nav-list`), so the messages
   scrollbar now matches the sidebar visually. */
#messages::-webkit-scrollbar-thumb {
  background: var(--text-faint) !important;
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: 999px;
  min-height: 40px;
}
#messages::-webkit-scrollbar-thumb:hover {
  background: var(--text-dim) !important;
  background-clip: padding-box;
}
#messages::-webkit-scrollbar-thumb:active {
  background: var(--text) !important;
  background-clip: padding-box;
}
/* v14 (27 Jul 2026 · Ashfak): NO custom `::-webkit-scrollbar-button`
   rule — we deliberately let Chromium render the native arrow buttons
   at the top + bottom of the rail, matching the sidebar
   `.chat-nav-list` which also declares no button rule. The native
   arrows are subtle grey glyphs that fit the slim rail perfectly.
   Do NOT re-add a `display: none` rule here — that suppresses the
   very arrows the user asked for in turn 6 of the scrollbar iteration. */
#messages::-webkit-scrollbar-corner {
  background: transparent !important;
}

/* Dark-mode fork — light thumb on transparent rail so the pill stays
   visible on dark chat surface. Fires on both the OS-level
   `prefers-color-scheme` AND the app's explicit `html.theme-dark` class. */
/* Dark mode inherits via CSS vars — `var(--text-faint)` auto-flips
   in dark theme. No per-theme overrides needed for #messages since
   the sidebar `.chat-nav-list` scrollbar uses the same pattern and
   works in both themes automatically. Keeping these @media +
   theme-dark blocks empty-of-thumb-colour rules so nothing overrides
   the base declarations above. */
@media (prefers-color-scheme: dark) {
  #messages::-webkit-scrollbar { background: transparent !important; }
  #messages::-webkit-scrollbar-track { background: transparent !important; }
}
html.theme-dark #messages::-webkit-scrollbar { background: transparent !important; }
html.theme-dark #messages::-webkit-scrollbar-track { background: transparent !important; }

/* "Jump to latest ↓" pill — appears only while the user has scrolled up
   AND new tokens are arriving. Sits just above the composer in the
   bottom-right of the chat column so it's reachable without leaving the
   reading position. Click → snap to bottom and resume stickiness. */
.jump-to-latest-btn {
  position: absolute;
  right: 24px;
  bottom: 200px; /* clear of the composer card + queue chip */
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px 8px 16px;
  border: 1px solid var(--primary-tint-strong, rgba(0,120,191,0.30));
  border-radius: 999px;
  background: var(--primary, #0078BF);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 6px 16px rgba(15, 23, 42, 0.18);
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.jump-to-latest-btn.is-visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.jump-to-latest-btn:hover {
  background: #0061a0;
}
.jump-to-latest-btn:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}
@media (max-width: 720px) {
  .jump-to-latest-btn { right: 12px; bottom: 180px; font-size: 12.5px; padding: 7px 12px; }
}

/* ========================================================================
   Conversation position navigator (27 Jul 2026 · Ashfak · v1)
   A compact floating panel that lists every user prompt in the active
   thread as a clickable "table of contents" so readers of a long
   conversation can jump between earlier prompts without hand-scrolling.

   Separate from the native `#messages` scrollbar (which is restored and
   preserved as-is above). Anchored inside `#chat` (which already has
   `position: relative`) at the right edge, offset so it never covers
   `.jump-to-latest-btn`, the composer, or the right-sidebar toggle.

   Shows only for sufficiently long conversations (JS gates via a
   `.is-active` class). Collapsible via header button; per-thread
   open/closed state is remembered by JS.
   ======================================================================== */
.chat-nav {
  position: absolute;
  /* Middle-right of the chat viewport (27 Jul 2026 · v2 · Ashfak · repositioned
     after the original top:20px overlapped the chat toolbar buttons —
     Search / Terminal / Share / WhatsApp / Delete / folder controls — that
     live at the top of #chat). Vertical-centre anchor + right:24px matches
     the existing .jump-to-latest-btn pill's safe spacing from the
     right-sidebar toggle. Panel grows inward (leftward) by its fixed
     240px width so it stays inside the chat viewport at every breakpoint. */
  top: 50%;
  right: 24px;
  transform: translateY(-50%);
  z-index: 4; /* below .jump-to-latest-btn (z:5) so the pill wins overlap */
  width: 240px;
  max-height: min(60vh, 480px);
  display: none; /* JS flips to `flex` when the thread is long enough */
  flex-direction: column;
  /* Theme-inherited (v3 · 27 Jul 2026 · Ashfak). Every colour reads from
     Imagine's live theme variables — `--surface` / `--border` / `--text` /
     `--muted` / `--surface-sunk` — which `html.theme-dark { … }` (line
     13358) flips atomically. NO `@media prefers-color-scheme` overrides
     here: that would follow the OS setting and mis-paint the nav dark
     when the OS is dark but the app is forced to Light Mode. Matches the
     visual contract of cards / popovers / dropdowns elsewhere in the UI. */
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-md, 0 8px 24px rgba(15, 23, 42, 0.08),
              0 2px 6px rgba(15, 23, 42, 0.05));
  font-size: 12.5px;
  color: var(--text);
  overflow: hidden;
  /* Fade-only entry animation (v2) — no translateY on the enter, because
     the layout transform is `translateY(-50%)` for vertical centring and
     we don't want to fight it during the 180ms animation. */
  opacity: 0;
  transition: opacity 0.18s ease;
  pointer-events: none;
}
.chat-nav.is-active {
  /* Present in the layout (so hover/focus reveal can hit it) but
     invisible until revealed. Reveal happens on `.is-revealed` (JS
     toggles this on hover near the right edge, scroll activity, or
     touch tap), on `:hover` (once the panel is exposed, keeping the
     pointer on it keeps it up), or on `:focus-within` (keyboard
     navigation into the item list keeps it up too). Fade duration
     doubles on exit so the exit feels calmer than the enter, and the
     JS uses a ~1.2 s idle delay before pulling `.is-revealed`. */
  display: flex;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.chat-nav.is-active.is-revealed,
.chat-nav.is-active:hover,
.chat-nav.is-active:focus-within {
  opacity: 1;
  pointer-events: auto;
}
.chat-nav.is-collapsed {
  max-height: none;
  height: auto;
  width: 44px;
}
.chat-nav.is-collapsed .chat-nav-list,
.chat-nav.is-collapsed .chat-nav-title { display: none; }
.chat-nav.is-collapsed .chat-nav-header { justify-content: center; padding: 6px; }

.chat-nav-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px 8px 12px;
  border-bottom: 1px solid var(--border);
  background: transparent;
  flex: 0 0 auto;
}
.chat-nav-title {
  flex: 1 1 auto;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.chat-nav-btn {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  line-height: 1;
  transition: background 0.12s ease, color 0.12s ease;
}
.chat-nav-btn:hover { background: var(--surface-hover); color: var(--text); }
.chat-nav-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }

/* Scoped native scrollbar for the navigator's own internal list. Does
   NOT touch or leak into `#messages`. `scrollbar-color` uses the
   currentColor-neutral pattern so `--text-faint` supplies the thumb
   colour in both themes automatically. */
.chat-nav-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 4px 0;
  margin: 0;
  list-style: none;
  scrollbar-color: var(--text-faint) transparent;
}
.chat-nav-list::-webkit-scrollbar { width: 8px; }
.chat-nav-list::-webkit-scrollbar-track { background: transparent; }
.chat-nav-list::-webkit-scrollbar-thumb {
  background: var(--text-faint);
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: 999px;
  min-height: 24px;
}
.chat-nav-list::-webkit-scrollbar-thumb:hover { background: var(--text-dim); background-clip: padding-box; }

.chat-nav-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 7px 12px;
  border: none;
  background: transparent;
  color: inherit;
  text-align: left;
  width: 100%;
  cursor: pointer;
  font: inherit;
  font-size: 12.5px;
  line-height: 1.35;
  border-left: 2px solid transparent;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.chat-nav-item:hover { background: var(--surface-hover); }
.chat-nav-item:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}
.chat-nav-item.is-active {
  /* --primary-tint flips per theme (root=rgba(13,115,119,0.08) →
     theme-dark=rgba(13,115,119,0.18)) so the highlight reads on both
     surfaces without a hardcoded fork. */
  background: var(--primary-tint);
  border-left-color: var(--primary);
  color: var(--text);
  font-weight: 600;
}
.chat-nav-item-index {
  flex: 0 0 auto;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-faint);
  min-width: 18px;
  padding-top: 1px;
  font-variant-numeric: tabular-nums;
}
.chat-nav-item.is-active .chat-nav-item-index { color: var(--primary); }
.chat-nav-item-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Floating "open navigator" button — visible when the panel is closed
   (JS toggles `.chat-nav-fab.is-visible`). Every colour reads from
   Imagine's theme variables so light + dark automatically match.

   Anchor stability contract (27 Jul 2026 · v8 · Ashfak · no-vertical-jump)
   ═══════════════════════════════════════════════════════════════════════

   Iteration history:
     v7 (previous) — `position: absolute` inside `#chat`, `top: 50%`
        with `transform: translateY(-50%)`. Vertical anchor recalculates
        every time `#chat`'s height changes: composer auto-grows on
        multi-line input · `#messages` reflow on thread switch or
        streaming · viewport resize · scrollbar appearance flipping
        chat's inner width. Any of those triggers a 50%-of-height
        re-eval that shifts the button vertically.
     v8 (this rule) — `position: fixed` + `top: 50vh` + `transform:
        translateY(-50%)`. The vertical anchor is now VIEWPORT-relative:
        50% of the viewport height, which doesn't change on:
          • #chat height changes (composer expand · thread switch)
          • #messages scroll or scroll-restoration
          • folder panel open/close (grid track collapses to 0, chat's
            width absorbs it, but viewport height stays put)
          • left-sidebar open/close on mobile (viewport height stays)
          • navigator panel open/close (this is what we're fixing)
        Horizontal anchor uses `calc(var(--folder-panel-w) + 24px)`
        from viewport right — 24px inside chat's right edge (24px left
        of the chat ↔ folder-panel divider). Since `--folder-panel-w`
        is a `:root` custom prop that doesn't change on collapse (only
        the grid track does), the button stays in the same absolute
        location on-screen across every state transition.

   Why viewport-fixed instead of chat-absolute:
     The user's ask is "one stable anchor relative to the main chat
     viewport." The chat area IS the viewport (minus a small header
     strip and the sidebar columns), and viewport-relative anchoring
     is IMMUNE to any layout reflow triggered by the state change we're
     debugging (click → panel opens → chat may reflow due to overlay
     rendering, hover styles firing, etc.). Absolute-in-#chat percentage
     anchoring was mathematically stable in most cases but had subtle
     reflow-timing edge cases where the browser recomputed 50% during
     the same paint frame as the class flip, producing a 1-4px jitter.
     Viewport `vh` unit is computed from `window.innerHeight` at
     resize-only intervals — never during a class toggle.

   State-lock invariants (all pseudo-classes MUST preserve):
     • width: 36px
     • height: 36px
     • padding: 0
     • border-width: 1px on all four sides
     • border-radius: 999px
     • transform: translateY(-50%)   ← anchor half-offset stays put
     • box-sizing: border-box        ← border doesn't inflate the box
     • margin: 0
   Only allowed changes across states: opacity (0/1) · visibility ·
   display · pointer-events · background-color · color · box-shadow
   (visual affordance only) · outline (outside the box, no layout). */
.chat-nav-fab {
  position: fixed;
  /* Viewport-vertical anchor — 50% of viewport height with a `-50%`
     transform to center the button on that Y. Doesn't recalculate on
     chat / composer / message-list reflow. */
  top: 50vh;
  /* Horizontal anchor — 24px inside the chat's right edge. Because
     `--folder-panel-w` doesn't change on collapse, this is stable
     regardless of the folder-panel open/closed state. Only shifts on
     viewport-crossing the 1200px breakpoint (fpw 260→220), which is a
     legitimate responsive re-anchor, not a state jump. */
  right: calc(var(--folder-panel-w) + 24px);
  transform: translateY(-50%);
  z-index: 4;
  width: 36px;
  height: 36px;
  padding: 0;
  /* Border-box + explicit margin:0 — belt-and-braces so a browser
     default padding or an inherited margin can't shift the rendered
     box. The 36×36 rect stays 36×36 under every pseudo-class state. */
  box-sizing: border-box;
  margin: 0;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-dim);
  box-shadow: var(--shadow-sm, 0 4px 12px rgba(15, 23, 42, 0.08));
  cursor: pointer;
  display: none;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  line-height: 1;
  /* Same reveal contract as .chat-nav — laid out in the DOM when the
     thread is long enough (`.is-visible`) but visually hidden until
     hover/scroll/touch reveals it. Opacity + pointer-events are the
     gates; `display` stays `inline-flex` for `.is-visible` so the
     reveal transition can animate. */
  opacity: 0;
  pointer-events: none;
  /* `top`, `right`, `transform`, `width`, `height`, `border`, `padding`,
     `margin` DELIBERATELY NOT in the transition list — the whole point
     of v8 is that these values NEVER change, so animating them is
     nonsense and could contribute to sub-pixel jitter on some browsers.
     Only opacity/color/background transition. */
  transition: opacity 0.18s ease, color 0.12s ease, background 0.12s ease;
}
.chat-nav-fab.is-visible { display: inline-flex; }
.chat-nav-fab.is-visible.is-revealed,
.chat-nav-fab.is-visible:hover,
.chat-nav-fab.is-visible:focus-visible {
  opacity: 1;
  pointer-events: auto;
}
/* State-lock invariant (v8 · 27 Jul 2026 · Ashfak · no-vertical-jump).
   Every pseudo-class + reveal-class combination MUST preserve the
   size / border / transform / anchor pair. Any rule elsewhere that
   attempts to change these on hover / focus / active / is-visible /
   is-revealed / is-active will be overridden by this lockdown block.
   Adding a new pseudo-class rule that changes width/height/border/
   transform for the FAB is a regression — extend this block instead. */
.chat-nav-fab,
.chat-nav-fab:hover,
.chat-nav-fab:focus,
.chat-nav-fab:focus-visible,
.chat-nav-fab:focus-within,
.chat-nav-fab:active,
.chat-nav-fab.is-visible,
.chat-nav-fab.is-revealed,
.chat-nav-fab.is-visible.is-revealed {
  width: 36px;
  height: 36px;
  padding: 0;
  border-width: 1px;
  border-style: solid;
  border-radius: 999px;
  transform: translateY(-50%);
  box-sizing: border-box;
  margin: 0;
  top: 50vh;
  right: calc(var(--folder-panel-w) + 24px);
  position: fixed;
}
/* v9 anti-jump — beats the global `:where(button):active { transform:
   translateY(1px) }` press-affordance at line 14240 (specificity 0,3,0).
   The `#chat` prefix bumps our selector to (1,2,0) so the FAB does NOT
   inherit the global 1px dip on mousedown. Without this, the global rule
   REPLACES `transform: translateY(-50%)` with `translateY(1px)` on press,
   dropping the FAB from centred-on-viewport-half to +1px-from-top — the
   exact "click makes it move" behaviour reported 27 Jul 2026. Enumerate
   every reveal-state variant so the fix holds regardless of which classes
   the FAB carries when clicked. */
#chat .chat-nav-fab:active,
#chat .chat-nav-fab.is-visible:active,
#chat .chat-nav-fab.is-revealed:active,
#chat .chat-nav-fab.is-visible.is-revealed:active {
  transform: translateY(-50%);
}
/* Strict SSoT CSS invariant (27 Jul 2026 · v7 · Ashfak · final).
   `#chat.chat-nav-open` is the JS-side single source of truth for
   "panel is up". The rules below give that container class higher
   specificity than every reveal/hover/focus/scroll rule in the file
   so no pseudo-class can override the hide. Selectors are enumerated
   explicitly instead of relying on a single wildcard match — each
   `:hover` / `:focus` / `:focus-visible` variant on the FAB gets its
   own override so a pseudo-class match cannot beat the open state
   even by winning specificity. The `html` prefix adds one more level
   of specificity as a floor; combined with the belt-and-braces
   `!important` triad on every visibility property the rule wins the
   cascade under any signal ordering. */
html #chat.chat-nav-open .chat-nav-fab,
html #chat.chat-nav-open .chat-nav-fab.is-visible,
html #chat.chat-nav-open .chat-nav-fab.is-revealed,
html #chat.chat-nav-open .chat-nav-fab.is-visible.is-revealed,
html #chat.chat-nav-open .chat-nav-fab:hover,
html #chat.chat-nav-open .chat-nav-fab:focus,
html #chat.chat-nav-open .chat-nav-fab:focus-visible,
html #chat.chat-nav-open .chat-nav-fab:active {
  opacity: 0 !important;
  visibility: hidden !important;
  display: none !important;
  pointer-events: none !important;
}
/* Panel side (v7): when the container carries `.chat-nav-open`, the
   panel MUST be unconditionally visible — no dependency on the
   `.is-revealed` class, no dependency on hover / focus-within, no
   fade-in dance. This pins the OPEN state so the reveal timer (which
   still runs on CLOSED state) can't accidentally lower opacity when
   the state flips. */
html #chat.chat-nav-open .chat-nav.is-active {
  opacity: 1 !important;
  visibility: visible !important;
  pointer-events: auto !important;
}
/* Belt-and-braces sibling-combinator floor (kept from v5, harmless
   with v7's higher-specificity rules — additional safety layer). */
.chat-nav.is-active ~ .chat-nav-fab { display: none !important; }
.chat-nav-fab:hover { color: var(--text); background: var(--surface-sunk); }
.chat-nav-fab:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Theme integration (27 Jul 2026 · v3 · Ashfak):
   No `@media (prefers-color-scheme: dark)` block, no `html.theme-dark
   .chat-nav*` overrides — every colour above already binds to Imagine's
   live theme variables. `html.theme-dark { --surface / --border / --text
   / --text-dim / --text-faint / --surface-hover / --primary-tint / … }`
   (styles.css line 13358) flips the entire palette atomically. Adding
   an `@media prefers-color-scheme` here would follow the OS setting
   instead of the app's theme toggle — that was the bug reported 27 Jul
   2026: nav rendered dark in Light Mode when the OS was set to dark. */

/* Mobile — collapse the inline panel to a floating bottom-right button
   that opens a bottom-anchored sheet on tap. Coarse-pointer OR narrow
   viewport, both classes of device get the same compact treatment. */
@media (max-width: 720px), (hover: none) and (pointer: coarse) {
  .chat-nav {
    /* Bottom-sheet posture — full-width strip pinned above composer,
       swipe/scroll list inside. Hidden until FAB is tapped. */
    position: fixed;
    top: auto;
    left: 12px;
    right: 12px;
    bottom: 12px;
    width: auto;
    max-height: 50vh;
    border-radius: 14px;
    /* Kill the desktop vertical-centre translate — mobile uses a bottom
       anchor, so translateY(-50%) would drag the sheet up by half its
       height and cut off content behind the composer. */
    transform: none;
  }
  /* Mobile FAB — bottom-anchored above composer. Override the desktop
     v8 state-lock's `top: 50vh` + `transform: translateY(-50%)` +
     `right: calc(...)` triad with mobile-specific anchors. All
     pseudo-class + reveal-class variants MUST also carry these
     overrides so the desktop lockdown block can't accidentally
     re-apply on mobile via specificity (both blocks target the same
     base class, but the mobile media query wins by cascade order
     inside its @media scope). */
  .chat-nav-fab,
  .chat-nav-fab:hover,
  .chat-nav-fab:focus,
  .chat-nav-fab:focus-visible,
  .chat-nav-fab:focus-within,
  .chat-nav-fab:active,
  .chat-nav-fab.is-visible,
  .chat-nav-fab.is-revealed,
  .chat-nav-fab.is-visible.is-revealed {
    position: fixed;
    top: auto;
    right: 12px;
    bottom: 180px; /* just above the composer + queue pill, matches .jump-to-latest-btn spacing */
    transform: none;
    width: 36px;
    height: 36px;
    padding: 0;
    border-width: 1px;
    border-style: solid;
    border-radius: 999px;
    box-sizing: border-box;
    margin: 0;
  }
  .chat-nav.is-collapsed { width: auto; }
  .chat-nav.is-collapsed .chat-nav-list,
  .chat-nav.is-collapsed .chat-nav-title { display: none; }
}
/* End .chat-nav */

#messages > .empty {
  color: var(--text-faint);
  text-align: center;
  padding: 64px 24px;
  font-size: 14px;
}

.msg {
  margin: 0 auto 20px;
  max-width: 820px;
}
.msg .role {
  font-size: 11px;
  color: var(--text-faint);
  margin-bottom: 6px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  display: flex;
  gap: 8px;
  align-items: center;
  font-weight: 500;
}
.msg .status {
  font-size: 10px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  letter-spacing: 0.3px;
}
.msg .status.queued { color: var(--text-dim); }
.msg .status.streaming {
  color: var(--primary);
  border-color: var(--primary-tint-strong);
  background: var(--primary-tint);
}
.msg .status.error {
  color: var(--danger);
  background: var(--danger-tint);
  border-color: rgba(220, 38, 38, 0.2);
}
.msg .status.done { color: var(--success); }

.queue-pos-label {
  font-size: 10.5px;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px dashed var(--border-strong);
  color: var(--text-dim);
  letter-spacing: 0.25px;
  background: transparent;
  text-transform: none;
  font-weight: 500;
}
.queue-pos-label.running {
  color: var(--primary);
  border: 1px solid var(--primary-tint-strong);
  background: var(--primary-tint);
  border-style: solid;
}
.queue-pos-label.waiting {
  color: var(--warning);
  border-color: rgba(217, 119, 6, 0.35);
  background: rgba(217, 119, 6, 0.07);
}

.msg.user { text-align: right; }
.msg.user .role { justify-content: flex-end; }
.msg.user .bubble {
  background: var(--user-bubble);
  color: var(--user-bubble-text);
  padding: 12px 16px;
  border-radius: 16px 16px 4px 16px;
  word-wrap: break-word;
  display: inline-flex;
  flex-direction: column;
  gap: 8px;
  text-align: left;
  max-width: min(720px, 92%);
  box-shadow: var(--shadow-sm);
}
.msg.user .user-text {
  white-space: pre-wrap;
}
.msg.user .attachment-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 0;
}
.msg.user .attachment-grid:last-child { margin-bottom: 0; }

/* Image attachments inside the user bubble — strip the dark card so the
   image renders cleanly against the blue bubble background. */
.msg.user .attachment-card.is-image {
  background: transparent;
  border: none;
  box-shadow: none;
  border-radius: 10px;
  overflow: hidden;
}
.msg.user .attachment-card.is-image:hover {
  transform: translateY(-1px);
  border: none;
}
.msg.user .attachment-card.is-image img {
  border-radius: 10px;
  max-width: 260px;
  max-height: 260px;
  display: block;
  object-fit: cover;
}

/* Non-image file cards inside the user bubble — keep the card look
   but invert to white/light so it contrasts against the blue bubble. */
.msg.user .attachment-card:not(.is-image) {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.3);
  color: #fff;
  box-shadow: none;
}
.msg.user .attachment-card:not(.is-image):hover {
  border-color: rgba(255, 255, 255, 0.55);
}
.msg.user .attachment-card:not(.is-image) .attachment-icon {
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
}
.msg.user .attachment-card:not(.is-image) .attachment-meta {
  color: rgba(255, 255, 255, 0.65);
}

.msg.assistant .bubble {
  background: var(--assistant-bubble);
  color: var(--text);
  padding: 16px 20px;
  border-radius: 16px 16px 16px 4px;
  word-wrap: break-word;
  white-space: normal;
  display: block;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}
.msg.assistant .bubble p { margin: 0 0 10px; }
.msg.assistant .bubble p:last-child { margin: 0; }
.msg.assistant .bubble h1,
.msg.assistant .bubble h2,
.msg.assistant .bubble h3,
.msg.assistant .bubble h4 {
  margin: 18px 0 8px;
  font-weight: 600;
  color: var(--text);
}
.msg.assistant .bubble h1 { font-size: 20px; }
.msg.assistant .bubble h2 { font-size: 17px; }
.msg.assistant .bubble h3 { font-size: 15px; }
.msg.assistant .bubble h4 { font-size: 14px; }
.msg.assistant .bubble ul,
.msg.assistant .bubble ol { margin: 8px 0 10px; padding-left: 22px; }
.msg.assistant .bubble li { margin: 3px 0; }
.msg.assistant .bubble a { color: var(--primary); text-decoration: none; }
.msg.assistant .bubble a:hover { text-decoration: underline; }
.msg.assistant .bubble blockquote {
  margin: 10px 0;
  padding: 8px 14px;
  border-left: 3px solid var(--primary);
  background: var(--surface-sunk);
  color: var(--text-muted);
  border-radius: 0 6px 6px 0;
}
.msg.assistant .bubble pre {
  background: var(--code-bg);
  color: var(--code-text);
  border: none;
  padding: 14px 16px;
  border-radius: 10px;
  overflow-x: auto;
  margin: 12px 0;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  line-height: 1.55;
}
.msg.assistant .bubble code {
  background: var(--inline-code-bg);
  color: var(--inline-code-text);
  padding: 1.5px 6px;
  border-radius: 4px;
  font-size: 12.5px;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}
.msg.assistant .bubble pre code {
  background: transparent;
  color: inherit;
  padding: 0;
}

/* ── Code block copy button + selection legibility ────────────────────
   Wrapper is added by _enhanceCodeBlocks() in app.js — every rendered
   <pre> in an assistant bubble is wrapped so the button can sit in the
   top-right corner without being pushed off by horizontal code scroll.
   The <pre> stays scrollable; the wrapper is the positioning context.

   Reported by Musheer 28 Jul 2026:
     · No copy button on code blocks → added button below.
     · Text selection was invisible on the dark code surface (the global
       ::selection uses a light-teal tint with `color: var(--text)` which
       renders dark-text on dark-teal on top of #0F172A — unreadable).
       Overriding ::selection for pre/pre code with a bright, high-contrast
       pair (white text on brand teal) fixes it. */
.msg.assistant .bubble .code-block-wrap {
  position: relative;
  margin: 12px 0;
}
.msg.assistant .bubble .code-block-wrap > pre {
  margin: 0;
}
.msg.assistant .bubble .code-block-copy {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  border: 1px solid rgba(226, 232, 240, 0.18);
  background: rgba(15, 23, 42, 0.72);
  color: #E2E8F0;
  font: 500 11px/1 'Inter', system-ui, -apple-system, sans-serif;
  padding: 5px 9px;
  border-radius: 6px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 120ms ease, background 120ms ease, border-color 120ms ease;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.msg.assistant .bubble .code-block-wrap:hover .code-block-copy,
.msg.assistant .bubble .code-block-copy:focus-visible,
.msg.assistant .bubble .code-block-copy:disabled {
  opacity: 1;
}
.msg.assistant .bubble .code-block-copy:hover {
  background: rgba(15, 23, 42, 0.92);
  border-color: rgba(226, 232, 240, 0.32);
}
.msg.assistant .bubble .code-block-copy:disabled {
  cursor: default;
  color: #86efac;
  border-color: rgba(134, 239, 172, 0.42);
}

/* Legible selection on the dark code surface — override the app-wide
   pale-teal ::selection which becomes invisible on #0F172A. Use the
   brand primary with white text so highlighted code stays readable
   in both light and dark modes. `::selection` is not inheritable —
   we have to target every leaf that can hold text inside the pre. */
.msg.assistant .bubble pre::selection,
.msg.assistant .bubble pre code::selection,
.msg.assistant .bubble pre *::selection {
  background: var(--primary, #0D7377);
  color: #ffffff;
}
.msg.assistant .bubble em { color: var(--text-dim); font-style: italic; }
.msg.assistant .bubble hr {
  border: none;
  border-top: 1px solid var(--divider);
  margin: 14px 0;
}
.msg.assistant .bubble table {
  border-collapse: collapse;
  width: 100%;
  margin: 10px 0;
  font-size: 13px;
}
.msg.assistant .bubble th,
.msg.assistant .bubble td {
  padding: 8px 10px;
  border: 1px solid var(--border);
  text-align: left;
}
.msg.assistant .bubble th { background: var(--surface-sunk); font-weight: 500; }

/* Assistant message status footer — explicit state indicator per message */
.msg.assistant .msg-status-footer {
  margin-top: 10px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 10px;
  font-size: 12px;
  line-height: 1.4;
  border: 1px solid var(--border);
  background: var(--surface-sunk);
  color: var(--text-muted);
  max-width: 100%;
  flex-wrap: wrap;
}
.msg.assistant .msg-status-footer .status-icon {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  flex-shrink: 0;
}
.msg.assistant .msg-status-footer .status-label {
  font-weight: 600;
  letter-spacing: 0.1px;
  white-space: nowrap;
}
.msg.assistant .msg-status-footer .status-desc {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text-dim);
  font-weight: 400;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Accordion-style preview: when the user prompt is longer than the one-line preview,
   the desc becomes a click/Enter target. Collapsed = single line with caret + ellipsis.
   Expanded = breaks onto its own row inside the wrap container, full text wraps with
   pre-wrap. Caret rotates 90deg on expand so the visual state matches the keyboard
   `aria-expanded` value (no modal — design rule: avoid dialog boxes for inline UI). */
.msg.assistant .msg-status-footer .status-desc.status-desc-collapsible {
  cursor: pointer;
  user-select: none;
}
.msg.assistant .msg-status-footer .status-desc.status-desc-collapsible:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
  border-radius: 3px;
}
.msg.assistant .msg-status-footer .status-desc-caret {
  display: inline-block;
  font-size: 10px;
  margin-right: 4px;
  transition: transform 0.15s ease;
  transform-origin: center;
}
.msg.assistant .msg-status-footer .status-desc.is-expanded .status-desc-caret {
  transform: rotate(90deg);
}
.msg.assistant .msg-status-footer .status-desc.is-expanded {
  /* Take the entire row in the footer's flex-wrap container so the long text isn't
     squeezed by sibling chips on the same line. */
  flex: 1 1 100%;
  white-space: pre-wrap;
  overflow: visible;
  text-overflow: clip;
  word-break: break-word;
  max-height: 280px;
  overflow-y: auto;
  padding: 6px 0 2px;
}
.msg.assistant .msg-status-footer .status-desc.is-expanded .status-desc-text {
  white-space: pre-wrap;
  word-break: break-word;
}
.msg.assistant .msg-status-footer .status-extra {
  flex-shrink: 0;
  color: var(--text-faint);
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.04);
  white-space: nowrap;
}

/* Queued — subtle amber */
.msg.assistant .msg-status-footer.state-queued {
  background: #FEF7E7;
  border-color: #F5D27A;
  color: #92510E;
}
.msg.assistant .msg-status-footer.state-queued .status-icon { background: #FBE1A0; color: #92510E; }
.msg.assistant .msg-status-footer.state-queued .status-desc { color: #7C4A11; }
.msg.assistant .msg-status-footer.state-queued .status-extra { background: rgba(146, 81, 14, 0.10); color: #92510E; }

/* Running — primary teal */
.msg.assistant .msg-status-footer.state-streaming {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
  color: var(--primary);
}
.msg.assistant .msg-status-footer.state-streaming .status-icon {
  background: var(--primary);
  color: #fff;
  padding: 0;
}
.msg.assistant .msg-status-footer.state-streaming .status-desc { color: var(--primary); opacity: 0.85; }
.msg.assistant .msg-status-footer.state-streaming .status-extra {
  background: rgba(13, 115, 119, 0.14);
  color: var(--primary);
}

/* Completed — green */
.msg.assistant .msg-status-footer.state-done {
  background: #E7F8EF;
  border-color: #A7E3C3;
  color: #086A44;
}
.msg.assistant .msg-status-footer.state-done .status-icon {
  background: #0B9E60;
  color: #fff;
  font-weight: 700;
}
.msg.assistant .msg-status-footer.state-done .status-desc { color: #0B6F48; }
/* Engine/model pill on the done (green) strip — previously fell back to the
   default `--text-faint` grey on a barely-visible `rgba(15,23,42,0.04)` pill,
   which rendered as almost-invisible text on the light green background so
   users couldn't read "Engine: claude:famedico · Model: …". Give it the same
   tint-on-strip treatment the other states already have. */
.msg.assistant .msg-status-footer.state-done .status-extra {
  background: rgba(11, 158, 96, 0.14);
  color: #086A44;
  font-weight: 600;
}

/* Failed — red */
.msg.assistant .msg-status-footer.state-error {
  background: #FDECEC;
  border-color: #F4B6B6;
  color: #A31A1A;
}
.msg.assistant .msg-status-footer.state-error .status-icon {
  background: var(--danger);
  color: #fff;
}
.msg.assistant .msg-status-footer.state-error .status-desc { color: #902020; }
.msg.assistant .msg-status-footer.state-error .status-extra {
  background: rgba(220, 38, 38, 0.12);
  color: var(--danger);
}

/* Interrupted — soft amber. Used when the message ended in `status='error'` because of an
   intentional server restart or a manual queue-clear, not a real failure. We surface this
   distinctly so a deploy doesn't read like a crash. */
.msg.assistant .msg-status-footer.state-interrupted {
  background: #FFF4E0;
  border-color: #F2C77E;
  color: #8A4B07;
}
.msg.assistant .msg-status-footer.state-interrupted .status-icon {
  background: #F39C20;
  color: #fff;
}
.msg.assistant .msg-status-footer.state-interrupted .status-desc { color: #7A4407; }
.msg.assistant .msg-status-footer.state-interrupted .status-extra {
  background: rgba(243, 156, 32, 0.15);
  color: #8A4B07;
}

/* Tiny status pill in the role line — match the same amber for "interrupted". */
.msg .role .status.interrupted {
  background: #FFE3B0;
  color: #7A4407;
  border: 1px solid #F2C77E;
}

/* In-bubble informational note for benign interruptions — replaces the red `error: …` text. */
.bubble-interrupted-note {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 14px;
  border-radius: 10px;
  background: #FFF7E6;
  border: 1px solid #F4D391;
  color: #7A4407;
  font-size: 13px;
  line-height: 1.5;
}
.bubble-interrupted-note .bubble-interrupted-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #F39C20;
  color: #fff;
  font-weight: 700;
  font-size: 13px;
  flex-shrink: 0;
}

/* Streaming spinner dot inside the icon circle */
.msg.assistant .msg-status-footer .spinner-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #fff;
  animation: spinPulse 1s ease-in-out infinite;
  display: inline-block;
}
@keyframes spinPulse {
  0%, 100% { transform: scale(0.6); opacity: 0.5; }
  50% { transform: scale(1); opacity: 1; }
}

/* ─────────────────────────────────────────────────────────────
   Inline "thinking" status (24 Aug 2026)
   Replaces the chunky teal "Running · #N" bar with a lightweight,
   ChatGPT/Claude-style inline indicator: 3 pulsing dots · verb ·
   small "Claude · famedico" · compact ✕ stop.
   No card background, no border, no bright block.
   ───────────────────────────────────────────────────────────── */
.msg.assistant .msg-status-footer.is-thinking-inline {
  background: transparent;
  border: none;
  padding: 4px 2px 2px;
  border-radius: 0;
  color: var(--text-dim, #64748B);
  gap: 8px;
  font-size: 12.5px;
  line-height: 1.35;
  flex-wrap: nowrap;
  animation: thinkingFadeIn 180ms ease-out both;
}
.msg.assistant .msg-status-footer.is-thinking-inline .think-dots {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  flex-shrink: 0;
}
.msg.assistant .msg-status-footer.is-thinking-inline .think-dots i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
  display: inline-block;
  animation: thinkingDot 1.2s ease-in-out infinite;
}
.msg.assistant .msg-status-footer.is-thinking-inline .think-dots i:nth-child(2) {
  animation-delay: 0.18s;
}
.msg.assistant .msg-status-footer.is-thinking-inline .think-dots i:nth-child(3) {
  animation-delay: 0.36s;
}
.msg.assistant .msg-status-footer.is-thinking-inline .think-label {
  font-weight: 500;
  color: var(--text-muted, #475569);
  letter-spacing: 0.1px;
  white-space: nowrap;
}
.msg.assistant .msg-status-footer.is-thinking-inline .think-meta {
  font-size: 11px;
  color: var(--text-faint, #94A3B8);
  font-weight: 400;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 0 1 auto;
}
.msg.assistant .msg-status-footer.is-thinking-inline .think-meta::before {
  content: '·';
  margin: 0 6px 0 2px;
  opacity: 0.6;
}
/* Compact stop button — smaller, no green pulse, no glow ring.
   Sits inline at natural size; hover reveals the danger intent. */
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-compact {
  width: 18px;
  height: 18px;
  margin-left: 4px;
  background: transparent;
  color: var(--text-faint, #94A3B8);
  border: 1px solid var(--border, #E2E8F0);
  box-shadow: none;
  animation: none;
  border-radius: 4px;
}
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-compact:hover {
  background: #FEE2E2;
  color: #B91C1C;
  border-color: #FCA5A5;
  transform: none;
  box-shadow: none;
}
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-compact .msg-stop-square {
  width: 7px;
  height: 7px;
  background: currentColor;
  border-radius: 1px;
}
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-compact.is-stopping {
  background: transparent;
  color: #B45309;
  border-color: #FCD34D;
}
/* When streaming finishes, the footer is replaced by the 'done' variant.
   Cross-fade it in so the visual swap feels calm rather than a hard pop. */
.msg.assistant .msg-status-footer.state-done,
.msg.assistant .msg-status-footer.state-error,
.msg.assistant .msg-status-footer.state-interrupted {
  animation: thinkingFadeIn 220ms ease-out both;
}
@keyframes thinkingDot {
  0%, 80%, 100% { opacity: 0.25; transform: scale(0.85); }
  40% { opacity: 1; transform: scale(1); }
}
@keyframes thinkingFadeIn {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .msg.assistant .msg-status-footer.is-thinking-inline,
  .msg.assistant .msg-status-footer.is-thinking-inline .think-dots i,
  .msg.assistant .msg-status-footer.state-done,
  .msg.assistant .msg-status-footer.state-error,
  .msg.assistant .msg-status-footer.state-interrupted {
    animation: none !important;
  }
  .msg.assistant .msg-status-footer.is-thinking-inline .think-dots i {
    opacity: 0.6;
  }
}

/* ─────────────────────────────────────────────────────────────
   Empty bubble while thinking — drop the card chrome.

   While the assistant is streaming with no visible response
   content yet, .is-empty-thinking is added on the .msg row by
   renderMessage(). We collapse the empty .bubble's background,
   border, padding, and shadow so the lightweight inline
   thinking indicator (● ● ●  Thinking…  · Claude · famedico
   ■ Stop) floats free instead of being visually trapped inside
   a big rounded card. The moment the first non-tool token
   arrives, the next re-render omits the class and the bubble
   pops back into its normal card look — with the response
   already inside.
   ───────────────────────────────────────────────────────────── */
.msg.assistant.is-empty-thinking > .bubble {
  background: transparent;
  border: none;
  box-shadow: none;
  padding: 0;
  min-height: 0;
}
.msg.assistant.is-empty-thinking > .msg-status-footer.is-thinking-inline {
  margin-top: 2px;
}

/* ─────────────────────────────────────────────────────────────
   Compact pill Stop button — used while streaming.
     ┌──────────┐
     │ ■  Stop  │   28px high, muted outline
     └──────────┘   red accent on hover / focus
   Sits at the tail of the thinking row, next to the model hint.
   Same POST /api/messages/:id/cancel handler — pure UI.
   ───────────────────────────────────────────────────────────── */
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  min-width: 64px;
  padding: 0 12px;
  margin-left: auto;                    /* pushes the pill to the far right */
  background: transparent;
  color: var(--text-muted, #64748B);
  border: 1px solid var(--border, #E2E8F0);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.1px;
  cursor: pointer;
  box-shadow: none;
  animation: none;
  transition:
    background-color 140ms ease,
    color 140ms ease,
    border-color 140ms ease,
    box-shadow 140ms ease,
    transform 140ms ease;
}
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-pill:hover,
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-pill:focus-visible {
  background: #FEF2F2;
  color: #B91C1C;
  border-color: #FCA5A5;
  outline: none;
  box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12);
}
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-pill:active {
  transform: translateY(0.5px);
  background: #FEE2E2;
  color: #991B1B;
  border-color: #F87171;
}
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-pill .msg-stop-square {
  width: 9px;
  height: 9px;
  background: currentColor;
  border-radius: 2px;
  display: inline-block;
  flex: 0 0 auto;
}
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-pill .msg-stop-text {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-pill.is-stopping {
  background: #FFFBEB;
  color: #B45309;
  border-color: #FCD34D;
  box-shadow: none;
  cursor: default;
}
.msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-pill.is-stopping .msg-stop-square {
  border-radius: 50%;                   /* square → dot while cancelling */
}
/* Push the model-hint chip so it doesn't fight the pill for the flex tail —
   the pill's own margin-left:auto handles the alignment. */
.msg.assistant .msg-status-footer.is-thinking-inline .think-meta {
  margin-right: 0;
}
@media (prefers-reduced-motion: reduce) {
  .msg.assistant .msg-status-footer.is-thinking-inline .msg-stop-btn.is-pill {
    transition: none;
  }
}

/* ─────────────────────────────────────────────────────────────
   "Assign as task" affordance on user prompts — minimal action
   bar under the bubble + inline expanding picker panel (no
   modal/dialog per design rule). On submit, the bar swaps to a
   pink "📋 Assigned as task #N →" chip that deep-links to the
   spawned task.
   ───────────────────────────────────────────────────────────── */
.msg-assign-bar {
  display: flex; justify-content: flex-end;
  margin: 4px 0 0 0; padding: 0;
}
.msg-assign-btn {
  background: transparent;
  border: 1px solid var(--border, #e0e6ed);
  color: var(--muted, #6b7280);
  font-size: 11.5px; font-weight: 600;
  padding: 4px 10px; border-radius: 16px;
  cursor: pointer; transition: 0.15s;
  font-family: inherit;
}
.msg-assign-btn:hover {
  border-color: var(--brand-pink, #E44C9A);
  color: var(--brand-pink, #E44C9A);
  background: #fdf2f8;
}
.msg-assigned-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: #fdf2f8;
  border: 1px solid var(--brand-pink, #E44C9A);
  color: var(--brand-pink, #E44C9A);
  font-size: 11.5px; font-weight: 700;
  padding: 4px 10px; border-radius: 16px;
  text-decoration: none;
}
.msg-assigned-chip:hover { background: #fce7f3; }

.msg-assign-panel {
  margin: 6px 0 0 0; padding: 12px 14px;
  background: var(--bg-soft, #f8fafc);
  border: 1px solid var(--border, #e0e6ed);
  border-left: 3px solid var(--brand-pink, #E44C9A);
  border-radius: 8px;
  font-size: 12.5px;
}
.msg-assign-row {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 8px;
}
.msg-assign-row-stack { align-items: flex-start; }
.msg-assign-lbl {
  flex: 0 0 90px; font-weight: 700; color: var(--muted, #6b7280);
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
}
.msg-assign-panel select,
.msg-assign-panel input,
.msg-assign-panel textarea {
  flex: 1; padding: 6px 10px;
  border: 1px solid var(--border, #d0d7e0);
  border-radius: 6px; font-size: 13px;
  font-family: inherit; background: white;
}
.msg-assign-panel textarea { resize: vertical; min-height: 40px; }
.msg-assign-prio {
  display: inline-flex; gap: 4px; flex-wrap: wrap;
}
.prio-pill {
  background: white;
  border: 1px solid var(--border, #d0d7e0);
  color: var(--muted, #6b7280);
  font-size: 11.5px; font-weight: 600;
  padding: 4px 10px; border-radius: 12px;
  cursor: pointer; font-family: inherit;
}
.prio-pill.is-on {
  background: var(--brand-blue, #0078BF);
  border-color: var(--brand-blue, #0078BF);
  color: white;
}
.msg-assign-actions {
  display: flex; align-items: center; gap: 8px;
  justify-content: flex-end; margin-top: 4px;
}
.msg-assign-feedback {
  flex: 1; font-size: 11.5px; color: var(--muted, #6b7280);
}
.msg-assign-cancel, .msg-assign-submit {
  padding: 6px 14px; font-size: 12.5px; font-weight: 700;
  border-radius: 6px; cursor: pointer; font-family: inherit;
}
.msg-assign-cancel {
  background: transparent;
  border: 1px solid var(--border, #d0d7e0);
  color: var(--muted, #6b7280);
}
.msg-assign-submit {
  background: var(--brand-pink, #E44C9A);
  border: 1px solid var(--brand-pink, #E44C9A);
  color: white;
}
.msg-assign-submit:disabled {
  opacity: 0.5; cursor: not-allowed;
}

/* Deep-link highlight: when a message is opened via ?thread=&msg=,
   give the bubble a brief pink halo so the recipient knows where
   to look. Auto-fades after 4s via JS class-removal. */
.msg.msg-deep-linked {
  animation: msgDeepLinkPulse 1.2s ease-in-out 0s 3;
}
@keyframes msgDeepLinkPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(228, 76, 154, 0); }
  50%      { box-shadow: 0 0 0 6px rgba(228, 76, 154, 0.18); }
}
/* Highlight pulse for ?meeting=N deep-linked meeting cards. Reuses the
   same pink accent as message deep-links for visual consistency across
   surfaces. Fires 3 times on landing, then the .meeting-deep-linked
   class is removed by the JS handler after ~4s. */
.actions-pending-card-row.meeting.meeting-deep-linked {
  animation: msgDeepLinkPulse 1.2s ease-in-out 0s 3;
}

/* Agent typing-indicator dots: three pellets that bounce in sequence
   while an @-mentioned agent is processing a mention inside a task-group
   chat. Subtle but visible enough that the user knows things are
   happening behind the scenes. Drives `.taskgroup-typing-indicator`
   spans in app.js (parity with Mini App's typing-indicator). */
@keyframes typingBounce {
  0%, 80%, 100% { transform: translateY(0);    opacity: 0.4; }
  40%           { transform: translateY(-3px); opacity: 1; }
}

/* ─────────────────────────────────────────────────────────────
   Per-prompt Stop button — the green glowing button sitting at
   the right edge of every queued/streaming message footer.
   Clicking it cancels just THAT prompt (server aborts the SDK
   iteration, message status flips to 'error' = "stopped by user",
   footer re-renders into soft amber "Interrupted" state).
   The pulsing green glow is intentional — it tells the user the
   prompt is still alive AND that this control will halt it.
   ───────────────────────────────────────────────────────────── */
.msg.assistant .msg-status-footer .msg-stop-btn {
  position: relative;
  appearance: none;
  border: none;
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: 50%;
  background: #16A34A;          /* same green as the sidebar activity-dot */
  color: #fff;
  cursor: pointer;
  flex-shrink: 0;
  margin-left: auto;            /* push to the right edge of the footer */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.6);
  animation: stopBtnPulse 1.4s ease-in-out infinite;
  transition: transform 0.12s ease, background 0.12s ease;
}
.msg.assistant .msg-status-footer .msg-stop-btn:hover {
  background: #DC2626;          /* red on hover — telegraphs "stop / dangerous" */
  animation: none;               /* hold still while user is hovering to click */
  transform: scale(1.08);
  box-shadow: 0 0 0 4px rgba(220, 38, 38, 0.18);
}
.msg.assistant .msg-status-footer .msg-stop-btn:focus-visible {
  outline: 2px solid #16A34A;
  outline-offset: 2px;
}
.msg.assistant .msg-status-footer .msg-stop-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  animation: none;
}
.msg.assistant .msg-status-footer .msg-stop-btn.is-stopping {
  background: #b45309;          /* amber while the cancel POST is in flight */
}
.msg.assistant .msg-status-footer .msg-stop-btn .msg-stop-square {
  width: 9px;
  height: 9px;
  background: currentColor;
  display: inline-block;
  border-radius: 1.5px;
  /* Subtle scale so the icon visually responds to hover too */
  transition: transform 0.12s ease;
}
.msg.assistant .msg-status-footer .msg-stop-btn:hover .msg-stop-square {
  transform: scale(1.1);
}
/* Outer pulsing ring — same animation as .activity-dot's ::after but tuned
   for a larger element. The .msg-stop-glow span is purely decorative. */
.msg.assistant .msg-status-footer .msg-stop-btn .msg-stop-glow {
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 2px solid rgba(22, 163, 74, 0.4);
  opacity: 0;
  animation: stopBtnRing 1.4s ease-in-out infinite;
  pointer-events: none;
}
.msg.assistant .msg-status-footer .msg-stop-btn:hover .msg-stop-glow {
  animation: none;
  opacity: 0;
}
@keyframes stopBtnPulse {
  0%, 100% {
    background: #16A34A;
    box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.5);
  }
  50% {
    background: #22C55E;
    box-shadow: 0 0 0 6px rgba(22, 163, 74, 0);
  }
}
@keyframes stopBtnRing {
  0% { transform: scale(0.85); opacity: 0.7; }
  70% { transform: scale(1.4); opacity: 0; }
  100% { transform: scale(1.4); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .msg.assistant .msg-status-footer .msg-stop-btn,
  .msg.assistant .msg-status-footer .msg-stop-btn .msg-stop-glow {
    animation: none !important;
  }
}

/* ========== Composer ========== */
#composer {
  border-top: 1px solid var(--border);
  background: var(--surface);
  padding: 14px 28px 18px;
  position: relative;
  flex-shrink: 0;
  z-index: 1;
}

#attachments {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0 0 10px;
  max-width: 820px;
  margin: 0 auto;
}
#attachments .chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 6px 4px 12px;
  font-size: 12.5px;
  max-width: 260px;
  color: var(--text);
  transition: border-color 120ms;
}
#attachments .chip:hover { border-color: var(--primary-tint-strong); }
#attachments .chip.is-image { padding-left: 4px; }
#attachments .chip img {
  width: 26px;
  height: 26px;
  object-fit: cover;
  border-radius: 50%;
  display: block;
  border: 1px solid var(--border);
}
#attachments .chip .chip-name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  max-width: 140px;
}
#attachments .chip .chip-size {
  color: var(--text-faint);
  font-size: 11px;
}
#attachments .chip .chip-remove {
  width: 22px;
  height: 22px;
  padding: 0;
  line-height: 1;
  font-size: 15px;
  color: var(--text-faint);
  border-radius: 50%;
  background: transparent;
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
#attachments .chip .chip-remove:hover:not(:disabled) {
  background: var(--danger-tint);
  color: var(--danger);
}
/* ─── Upload progress ─────────────────────────────────────────────
 * Aggregate banner rendered as the first child of #attachments while
 * any file is uploading. Sits above the chip row. Bar sweeps a brand
 * gradient (teal→blue→pink) with a subtle shimmer overlay so even at
 * 0% something visibly animates and the user knows we're moving.
 * Per-chip bars stay too — the banner is the summary, the chip is the
 * per-file read.
 */
#attachments .upload-agg-banner {
  flex: 1 0 100%;
  width: 100%;
  box-sizing: border-box;
  background: linear-gradient(180deg, var(--surface-sunk), var(--surface));
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: 10px;
  padding: 10px 14px 12px;
  margin-bottom: 4px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}
#attachments .upload-agg-banner.is-stalled { border-left-color: #d97706; }
#attachments .upload-agg-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
#attachments .upload-agg-spin {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 2px solid var(--primary-tint);
  border-top-color: var(--primary);
  animation: upload-agg-spin 0.75s linear infinite;
}
#attachments .upload-agg-banner.is-stalled .upload-agg-spin {
  border-color: #fde68a;
  border-top-color: #d97706;
  animation-duration: 1.4s;
}
@keyframes upload-agg-spin { to { transform: rotate(360deg); } }
#attachments .upload-agg-text { flex: 1 1 auto; min-width: 0; }
#attachments .upload-agg-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  color: var(--text);
}
#attachments .upload-agg-title strong { font-weight: 600; }
#attachments .upload-agg-pct {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--primary);
  font-size: 13.5px;
}
#attachments .upload-agg-sub {
  font-size: 11.5px;
  color: var(--text-faint);
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}
#attachments .upload-agg-stalled { color: #b45309; font-weight: 600; }
#attachments .upload-agg-track {
  position: relative;
  height: 8px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: 5px;
  overflow: hidden;
}
#attachments .upload-agg-fill {
  position: relative;
  height: 100%;
  min-width: 2px;
  background: linear-gradient(90deg, #0D7377 0%, #2563eb 55%, #E44C9A 100%);
  background-size: 200% 100%;
  border-radius: 4px;
  transition: width 0.18s ease-out;
  animation: upload-agg-gradient-shift 2.4s linear infinite;
}
#attachments .upload-agg-fill::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.45) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  animation: upload-agg-shimmer 1.6s linear infinite;
  border-radius: inherit;
}
#attachments .upload-agg-banner.is-indeterminate .upload-agg-fill {
  min-width: 30%;
  animation: upload-agg-gradient-shift 2.4s linear infinite,
             upload-agg-indeterminate 1.7s ease-in-out infinite;
}
@keyframes upload-agg-gradient-shift {
  0%   { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}
@keyframes upload-agg-shimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
@keyframes upload-agg-indeterminate {
  0%   { margin-left: 0%;  }
  50%  { margin-left: 65%; }
  100% { margin-left: 0%;  }
}
@media (prefers-reduced-motion: reduce) {
  #attachments .upload-agg-spin { animation-duration: 2s; }
  #attachments .upload-agg-fill,
  #attachments .upload-agg-fill::after,
  #attachments .upload-agg-banner.is-indeterminate .upload-agg-fill {
    animation: none;
  }
}
/* Per-chip upload progress — subtle shimmer over the fill so even at
 * 0% something visibly animates and the user knows the upload hasn't
 * frozen. Track height + gradient inline in JS; this adds the shimmer. */
#attachments .chip.is-uploading .chip-upload-bar-fill {
  position: relative;
  overflow: hidden;
}
#attachments .chip.is-uploading .chip-upload-bar-fill::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.55) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  animation: upload-agg-shimmer 1.6s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  #attachments .chip.is-uploading .chip-upload-bar-fill::after { animation: none; }
}

/* Extension badge — shown on the fallback file-tile when a chip can't
 * render as a thumbnail (missing url, non-image mime, or img-onerror
 * swap). Mirrors the "PNG image.png 66.8 KB" reference design.
 * Reported by Mohammed Ashfak, 2 Jul 2026. */
#attachments .chip .chip-ext-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 20px;
  padding: 0 6px;
  border-radius: 4px;
  background: var(--primary-tint);
  color: var(--primary);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  line-height: 1;
}

.composer-card {
  max-width: 820px;
  margin: 0 auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 4px 4px 4px 0;
  box-shadow: var(--shadow-sm);
  transition: border-color 120ms, box-shadow 120ms;
}
.composer-card:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}

#prompt {
  width: 100%;
  resize: vertical;
  min-height: 56px;
  max-height: 280px;
  background: transparent;
  color: var(--text);
  border: none;
  padding: 14px 16px 4px;
  font: inherit;
  font-size: 14px;
  line-height: 1.55;
}
#prompt::placeholder { color: var(--text-faint); }
#prompt:focus { outline: none; }

.composer-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 8px;
}
/* The full unified composer-toolbar block that owns wrap, sizing,
   spacing, and Send-anchoring lives at the bottom of this file — search
   "Composer action bar — unification pass". Keeping the baseline above
   minimal so the unified pass is the single source of truth. */

.prompt-guide-panel {
  margin: 0 10px 10px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-left: 4px solid var(--brand-blue, #0078BF);
  border-radius: 12px;
  background: var(--surface-sunk, #F8FAFC);
  color: var(--text);
  font-size: 13px;
  line-height: 1.5;
}
.prompt-guide-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.prompt-guide-head > div { display: flex; flex-direction: column; gap: 2px; }
.prompt-guide-head span { color: var(--text-dim); font-size: 12px; }
.prompt-guide-panel ol { margin: 10px 0; padding-left: 20px; }
.prompt-guide-panel li + li { margin-top: 4px; }
.prompt-guide-panel p { margin: 0; padding-top: 10px; border-top: 1px solid var(--border); }
.prompt-handbook-link { flex: 0 0 auto; color: var(--brand-blue, #0078BF); font-weight: 700; }
.prompt-guide-btn[aria-expanded="true"] { color: var(--brand-blue, #0078BF); background: var(--primary-tint); }
html.theme-dark .prompt-guide-panel { background: #111A2C; }

@media (max-width: 640px) {
  .prompt-guide-head { flex-direction: column; }
  .prompt-guide-panel { margin-inline: 4px; }
}

.queue-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--primary);
  background: var(--primary-tint);
  padding: 4px 10px;
  border-radius: 999px;
  font-weight: 500;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color 120ms, border-color 120ms;
}
.queue-pill:hover:not(:disabled) {
  background: var(--primary-tint-strong);
  color: var(--primary);
  border-color: var(--primary-tint-strong);
}
.queue-pill[aria-expanded="true"] {
  background: var(--primary-tint-strong);
  border-color: var(--primary);
}
.queue-pill b { font-weight: 700; }
.queue-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--primary);
  animation: pulse 1.4s ease-in-out infinite;
  flex-shrink: 0;
}

/* Queue popover */
.queue-popover {
  position: absolute;
  bottom: calc(100% + 8px);
  right: 28px;
  width: min(420px, calc(100% - 48px));
  max-height: 60vh;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  z-index: 20;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: popoverIn 140ms ease-out;
}
@keyframes popoverIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.queue-popover-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--divider);
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  background: var(--surface-alt);
}
.queue-popover-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.queue-popover-clear {
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.2px;
  padding: 4px 10px;
  border-radius: 6px;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.queue-popover-clear:hover:not(:disabled) {
  background: var(--danger-tint);
  color: var(--danger);
  border-color: rgba(220, 38, 38, 0.3);
}
.queue-popover-close {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 50%;
  background: transparent;
  border: none;
  color: var(--text-dim);
  font-size: 18px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.queue-popover-close:hover {
  background: var(--surface-sunk);
  color: var(--text);
}
.queue-list {
  list-style: none;
  margin: 0;
  padding: 6px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.queue-list .queue-empty {
  padding: 24px 16px;
  color: var(--text-faint);
  text-align: center;
  font-size: 13px;
}
.queue-item {
  padding: 10px 12px;
  border-radius: var(--radius);
  cursor: pointer;
  border: 1px solid transparent;
  transition: background-color 120ms, border-color 120ms;
}
.queue-item:hover {
  background: var(--surface-sunk);
  border-color: var(--border);
}
.queue-item-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}
.queue-item-pos {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-faint);
  letter-spacing: 0.4px;
}
.queue-item-status {
  font-size: 10px;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-sunk);
  color: var(--text-dim);
  letter-spacing: 0.3px;
  text-transform: uppercase;
}
.queue-item-status.streaming {
  color: var(--primary);
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
}
.queue-item-preview {
  font-size: 13px;
  color: var(--text);
  line-height: 1.45;
  white-space: pre-wrap;
  word-wrap: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.queue-item-preview.muted { color: var(--text-faint); font-style: italic; }
.queue-item-meta {
  margin-top: 4px;
  font-size: 11px;
  color: var(--text-faint);
}

/* Flash highlight when jumping to a message from the queue popover */
.msg.flash .bubble {
  animation: flashBubble 1.2s ease-out;
}
@keyframes flashBubble {
  0%   { box-shadow: 0 0 0 3px var(--primary-tint-strong); }
  100% { box-shadow: var(--shadow-sm); }
}
@keyframes pulse {
  0%, 100% { opacity: 0.35; transform: scale(0.9); }
  50% { opacity: 1; transform: scale(1.15); }
}

.hidden { display: none !important; }

/* ========== Buttons ========== */
.btn, button {
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.2px;
  border-radius: 8px;
  padding: 8px 14px;
  cursor: pointer;
  border: 1px solid transparent;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
  white-space: nowrap;
}
.btn svg, button svg { flex-shrink: 0; }
button:disabled, .btn:disabled {
  opacity: 0.45;
  cursor: default;
  pointer-events: none;
}

.btn-primary, #newThreadBtn, #sendBtn {
  background: var(--primary);
  color: var(--on-primary);
  border-color: var(--primary);
  box-shadow: var(--shadow-sm);
}
.btn-primary:hover:not(:disabled),
#newThreadBtn:hover:not(:disabled),
#sendBtn:hover:not(:disabled) {
  background: var(--primary-hover);
  border-color: var(--primary-hover);
}
.btn-primary:active:not(:disabled),
#newThreadBtn:active:not(:disabled),
#sendBtn:active:not(:disabled) {
  background: var(--primary-pressed);
  border-color: var(--primary-pressed);
}
.btn-sm { padding: 6px 10px; font-size: 12.5px; }

/* ── Composer mode picker (Cursor-style) ───────────────────────────────
   Anchored next to the Attach button on the composer row. The button
   itself looks like a pill with "∞ Agent ▾"; clicking it pops a menu
   upward (composer is bottom-of-viewport) with the 5 modes. Selected
   mode persists in localStorage. */
.mode-picker-wrap { position: relative; display: inline-flex; }
.mode-picker-btn {
  gap: 6px;
  padding: 6px 8px 6px 10px;
  font-weight: 500;
}
.mode-picker-btn .mode-picker-icon {
  font-size: 14px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px;
}
.mode-picker-btn .mode-picker-label { font-size: 12.5px; }
.mode-picker-btn .mode-picker-chev { opacity: 0.7; transition: transform 120ms ease; }
.mode-picker-btn[aria-expanded="true"] .mode-picker-chev { transform: rotate(180deg); }

/* Provider-picker loading state — shown while the async /api/providers
   fetch is in-flight. Dims the button so the user sees the click registered
   and knows to wait. Pointer-events are kept on so the toggle-off click
   can still reach the already-open-check path if the menu appears quickly. */
#threadProviderBtn.is-loading {
  opacity: 0.55;
  cursor: wait;
}
#threadProviderBtn.is-loading .mode-picker-chev {
  opacity: 0;  /* hide chevron while loading — shows it's a different state */
}
@keyframes providerBtnPulse {
  0%, 100% { opacity: 0.55; }
  50%       { opacity: 0.80; }
}
#threadProviderBtn.is-loading {
  animation: providerBtnPulse 900ms ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  #threadProviderBtn.is-loading { animation: none; opacity: 0.55; }
}

/* Subtle accent tint when a non-default mode is active so the user is
   reminded the next send won't behave like a normal agent run. */
.mode-picker-btn[data-mode="plan"]      { color: var(--brand-blue); border-color: rgba(0, 120, 191, 0.25); }
.mode-picker-btn[data-mode="debug"]     { color: var(--brand-amber); border-color: rgba(245, 158, 11, 0.30); }
.mode-picker-btn[data-mode="multitask"] { color: var(--brand-pink); border-color: rgba(228, 76, 154, 0.30); }
.mode-picker-btn[data-mode="ask"]       { color: var(--primary); border-color: var(--primary-tint-strong); background: var(--primary-tint); }

.mode-picker-menu {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  /* 22 Aug 2026 — rev 2 ("details gone / unstructured"): compact BUT the
     descriptions must remain readable. Widened to 260–300 so the fuller
     detail text can wrap to a clean 2-line max, no ellipsis clipping. */
  min-width: 260px;
  max-width: 300px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 200;
  display: flex; flex-direction: column;
  gap: 2px;
}
.mode-picker-menu.hidden { display: none; }
.mode-picker-item {
  all: unset;
  display: grid;
  grid-template-columns: 22px 1fr 16px;
  align-items: flex-start;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  font: inherit;
  color: var(--text);
  text-align: left;
  transition: background 120ms ease;
}
.mode-picker-item:hover,
.mode-picker-item:focus-visible { background: var(--surface-sunk); outline: none; }
.mode-picker-item .mpi-icon {
  font-size: 15px; line-height: 1.2;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-muted);
  padding-top: 1px;
}
.mode-picker-item .mpi-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.mode-picker-item .mpi-name { font-size: 13px; font-weight: 600; color: var(--text); line-height: 1.25; }
.mode-picker-item .mpi-desc {
  font-size: 11.5px; color: var(--text-dim); line-height: 1.35;
  /* Allow up to 2 clean lines — long enough to keep the "why" of each
     mode, short enough to keep the popover compact. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}
.mode-picker-item .mpi-check {
  color: var(--primary); font-weight: 700; opacity: 0;
  align-self: flex-start; font-size: 13px; line-height: 1.25; padding-top: 1px;
}
.mode-picker-item[aria-checked="true"] { background: var(--primary-tint); }
.mode-picker-item[aria-checked="true"]:hover,
.mode-picker-item[aria-checked="true"]:focus-visible { background: var(--primary-tint-strong); }
.mode-picker-item[aria-checked="true"] .mpi-check { opacity: 1; }
.mode-picker-item[aria-checked="true"] .mpi-name { color: var(--primary); }
.mode-picker-item[aria-checked="true"] .mpi-icon { color: var(--primary); }

/* ── Composer LLM engine picker (next to Send) ─────────────────────────
   Same interaction model as the mode picker: pill button + upward menu.
   Every thread participant with prompt access can switch the engine for
   that particular thread. */
.llm-picker-wrap { position: relative; display: inline-flex; }
.llm-picker-btn {
  gap: 6px;
  padding: 6px 8px 6px 10px;
  font-weight: 500;
}
.llm-picker-btn .llm-picker-icon {
  font-size: 14px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px;
}
.llm-picker-btn .llm-picker-label { font-size: 12.5px; }
.llm-picker-btn .llm-picker-chev { opacity: 0.7; transition: transform 120ms ease; }
.llm-picker-btn[aria-expanded="true"] .llm-picker-chev { transform: rotate(180deg); }
.llm-picker-btn[data-provider="grok"] {
  color: #0369a1;
  border-color: rgba(14, 165, 233, 0.35);
  background: rgba(14, 165, 233, 0.08);
}
.llm-picker-btn[data-provider="claude"] {
  color: var(--text);
}
.llm-picker-btn[data-provider="opencode"] {
  color: #0d7377;
  border-color: rgba(13, 115, 119, 0.35);
  background: rgba(13, 115, 119, 0.08);
}
.llm-picker-btn.is-pinned {
  box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.55);
}
.llm-picker-btn:disabled {
  opacity: 0.75;
  cursor: default;
}
.llm-picker-menu {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  min-width: 300px;
  max-width: 360px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.llm-picker-menu.hidden { display: none; }
.llm-picker-item {
  all: unset;
  display: grid;
  grid-template-columns: 24px 1fr 16px;
  align-items: start;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  font: inherit;
  color: var(--text);
  text-align: left;
}
.llm-picker-item:hover,
.llm-picker-item:focus-visible { background: var(--surface-sunk); outline: none; }
.llm-picker-item.disabled,
.llm-picker-item:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.llm-picker-item .lpi-icon {
  font-size: 16px; line-height: 1.3;
  display: inline-flex; align-items: center; justify-content: center;
}
.llm-picker-item .lpi-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.llm-picker-item .lpi-name { font-size: 13px; font-weight: 600; color: var(--text); }
.llm-picker-item .lpi-desc { font-size: 11.5px; color: var(--text-dim); line-height: 1.4; }
.llm-picker-item .lpi-check { color: var(--primary); font-weight: 700; opacity: 0; align-self: center; }
.llm-picker-item[aria-checked="true"] .lpi-check { opacity: 1; }
.llm-picker-item[aria-checked="true"] .lpi-name { color: var(--primary); }
.llm-picker-pin-note {
  margin: 4px 8px 6px;
  padding: 6px 8px;
  border-radius: 8px;
  background: rgba(245, 158, 11, 0.12);
  border: 1px solid rgba(245, 158, 11, 0.35);
  color: var(--text);
  font-size: 11.5px;
  line-height: 1.4;
}

/* Sidebar header right-side button cluster (theme toggle + New). Lives in the
   sidebar <header> so the two controls hug the right edge with a tight gap. */
.sidebar-header-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}

/* Dark-mode toggle. Ghost-style square button so it sits politely beside the
   filled primary "+ New" button. Glyph swaps between 🌙 (light → switch to
   dark) and ☀ (dark → switch back to light) — both SVGs are present in markup
   and we hide one via the `html.theme-dark` class. */
.theme-toggle-btn {
  width: 32px; height: 32px;
  padding: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.theme-toggle-btn:hover {
  background: var(--surface-sunk);
  color: var(--text);
  border-color: var(--border-strong);
}
.theme-toggle-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
/* Show the moon icon (i.e. "click to switch to dark") in light theme, sun in dark. */
.theme-toggle-icon-sun { display: none; }
.theme-toggle-icon-moon { display: inline-block; }
html.theme-dark .theme-toggle-icon-sun { display: inline-block; }
html.theme-dark .theme-toggle-icon-moon { display: none; }

.btn-ghost, #deleteBtn, #attachBtn {
  background: transparent;
  color: var(--text-muted);
  border-color: var(--border);
}
.btn-ghost:hover:not(:disabled),
#deleteBtn:hover:not(:disabled),
#attachBtn:hover:not(:disabled) {
  background: var(--surface-sunk);
  color: var(--text);
  border-color: var(--border-strong);
}
.btn-danger:hover:not(:disabled),
#deleteBtn:hover:not(:disabled) {
  color: var(--danger);
  background: var(--danger-tint);
  border-color: rgba(220, 38, 38, 0.3);
}

#attachBtn { margin-right: auto; }

/* Focus ring for accessibility (himslite requires this) */
button:focus-visible, .btn:focus-visible,
#threadList li:focus-visible,
#prompt:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.composer-card:focus-within button:focus-visible {
  outline-offset: 2px;
}

/* ========== Drop overlay ========== */
#dropOverlay {
  position: absolute;
  inset: 8px;
  background: rgba(13, 115, 119, 0.06);
  border: 2px dashed var(--primary);
  border-radius: var(--radius-lg);
  color: var(--primary);
  font-weight: 500;
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 2;
  backdrop-filter: blur(1px);
}

/* ========== Attachment cards (in messages) ========== */
.attachment-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  text-decoration: none;
  color: var(--text);
  min-width: 150px;
  max-width: 240px;
  box-shadow: var(--shadow-sm);
  transition: border-color 120ms, transform 120ms;
}
.attachment-card:hover {
  border-color: var(--primary);
  transform: translateY(-1px);
}
.attachment-card.is-image {
  padding: 0;
  min-width: 0;
  border-color: rgba(255, 255, 255, 0.2);
}
.attachment-card.is-image img {
  display: block;
  max-width: 240px;
  max-height: 240px;
  width: auto;
  height: auto;
  object-fit: cover;
}
.attachment-card .attachment-icon {
  background: var(--primary-tint);
  color: var(--primary);
  font-size: 11px;
  font-weight: 600;
  padding: 16px;
  text-align: center;
  letter-spacing: 1px;
}
.attachment-card .attachment-name {
  padding: 8px 12px 0;
  font-size: 12.5px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.attachment-card .attachment-meta {
  padding: 0 12px 8px;
  font-size: 11px;
  color: var(--text-faint);
}

/* ========== Assistant-produced file artefacts (download chip) ==========
   Injected by _enhanceFileArtefacts() in web/app.js on any inline <code>
   that contains an absolute path with a known artefact extension. Mirrors
   the visual language of .attachment-card but lays out horizontally so the
   chip flows naturally after the referenced path in the message body. */
.artefact-chip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 6px 4px;
  padding: 6px 12px 6px 6px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 10px;
  text-decoration: none;
  color: var(--text, #111);
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(0,0,0,0.05));
  transition: border-color 120ms, transform 120ms, box-shadow 120ms;
  vertical-align: middle;
  max-width: 100%;
  font-family: inherit;
  font-size: 12.5px;
  line-height: 1.3;
}
.artefact-chip:hover {
  border-color: var(--primary, #0078BF);
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0,0,0,0.08);
}
.artefact-chip:focus-visible {
  outline: 2px solid var(--primary, #0078BF);
  outline-offset: 2px;
}
.artefact-chip .artefact-chip-icon {
  flex: 0 0 auto;
  background: var(--primary-tint, #e6f2fb);
  color: var(--primary, #0078BF);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  padding: 6px 8px;
  border-radius: 6px;
  min-width: 34px;
  text-align: center;
}
.artefact-chip .artefact-chip-meta {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  max-width: 320px;
}
.artefact-chip .artefact-chip-name {
  font-weight: 600;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.artefact-chip .artefact-chip-hint {
  font-size: 11px;
  color: var(--text-faint, #6b7280);
}

/* ========== Scrollbars (subtle, himslite-style) ========== */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--text-faint); background-clip: padding-box; border: 2px solid transparent; }

/* ========== Folder "Ideas" sidebar link ========== */
.folder-ideas-link {
  padding: 6px 10px 6px 12px !important;
  display: flex !important;
  align-items: center !important;
  gap: 8px !important;
  font-size: 12.5px !important;
  color: var(--text-faint) !important;
  cursor: pointer;
  border-radius: var(--radius);
  font-style: italic;
  transition: background-color 120ms, color 120ms;
}
.folder-ideas-link:hover {
  background: var(--surface-sunk);
  color: #D97706 !important;
}
/* "Brain" variant — uses a 💡 emoji icon */
.folder-brain-emoji {
  font-size: 13px;
  line-height: 1;
  display: inline-block;
  width: 14px;
  text-align: center;
}
.folder-brain-link {
  font-style: normal !important;
  color: var(--text-muted) !important;
  font-weight: 500;
}
.folder-brain-link:hover {
  color: var(--primary) !important;
}
.folder-brain-link .folder-ideas-count.has-pending {
  /* Show the ideas-pending count pill in a calmer style than the old amber one. */
  background: rgba(217, 119, 6, 0.12);
  color: #D97706;
}
.folder-ideas-link .folder-ideas-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 1;
}
.folder-ideas-count {
  flex-shrink: 0;
  font-size: 10.5px;
  font-weight: 600;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--surface-sunk);
  color: var(--text-faint);
  font-style: normal;
  letter-spacing: 0.2px;
}
.folder-ideas-count.has-pending {
  background: rgba(217, 119, 6, 0.12);
  color: #D97706;
}

/* ========== Ideas board ========== */
#ideasHeader {
  padding: 14px 28px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--surface);
  min-height: 64px;
  flex-shrink: 0;
  z-index: 1;
}
#ideasHeader h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  color: var(--text);
}
.ideas-board {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  padding: 24px 28px 32px;
  align-items: start;
}
.ideas-loading, .ideas-error {
  grid-column: 1 / -1;
  padding: 48px;
  text-align: center;
  color: var(--text-faint);
}
.ideas-col {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 12px 14px 14px;
  min-height: 120px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-shadow: var(--shadow-sm);
}
.ideas-col.phase-current { border-top: 3px solid var(--primary); }
.ideas-col.phase-next    { border-top: 3px solid #0EA5E9; }
.ideas-col.phase-futuristic { border-top: 3px solid #A855F7; }

.ideas-col-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--divider);
}
.ideas-col-name {
  font-weight: 600;
  font-size: 13px;
  color: var(--text);
  letter-spacing: 0.2px;
}
.ideas-col-count {
  font-size: 11px;
  font-weight: 600;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--surface-sunk);
  color: var(--text-faint);
}
.ideas-col-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ideas-col-empty {
  padding: 20px 8px;
  text-align: center;
  color: var(--text-faint);
  font-size: 12px;
  font-style: italic;
}

.idea-card {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: border-color 120ms, background-color 120ms;
}
.idea-card:hover { border-color: var(--border-strong); }
.idea-card.priority-critical { border-left: 4px solid var(--danger); }
.idea-card.priority-normal { border-left: 4px solid var(--primary); }
.idea-card.priority-nice_to_have { border-left: 4px solid var(--border-strong); }

.idea-card.status-done {
  opacity: 0.65;
  background: var(--surface);
}
.idea-card.status-done .idea-text {
  text-decoration: line-through;
  color: var(--text-dim);
}
.idea-card.status-queued {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
}

.idea-head {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}

.priority-chip {
  font-size: 10px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}
.priority-chip.chip-critical {
  background: var(--danger-tint);
  color: var(--danger);
  border: 1px solid rgba(220, 38, 38, 0.2);
}
.priority-chip.chip-normal {
  background: var(--primary-tint);
  color: var(--primary);
  border: 1px solid var(--primary-tint-strong);
}
.priority-chip.chip-nice_to_have {
  background: var(--surface-sunk);
  color: var(--text-muted);
  border: 1px solid var(--border);
}

.idea-status-chip {
  font-size: 10px;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: 999px;
  letter-spacing: 0.2px;
  border: 1px solid var(--border);
  background: var(--surface-sunk);
  color: var(--text-dim);
}
.idea-status-chip.status-chip-queued {
  background: rgba(217, 119, 6, 0.12);
  color: #D97706;
  border-color: rgba(217, 119, 6, 0.25);
}
.idea-status-chip.status-chip-done {
  background: #E7F8EF;
  color: #086A44;
  border-color: #A7E3C3;
}
.idea-status-chip.status-chip-error {
  background: var(--danger-tint);
  color: var(--danger);
  border-color: rgba(220, 38, 38, 0.25);
}
/* New testing-handoff statuses. Distinct purple for "in testing" and
   a more solid green for "tested" so they're scannable next to "done". */
.idea-status-chip.status-chip-testing {
  background: rgba(124, 58, 237, 0.12);
  color: #6D28D9;
  border-color: rgba(124, 58, 237, 0.30);
}
.idea-status-chip.status-chip-tested {
  background: rgba(16, 185, 129, 0.18);
  color: #047857;
  border-color: rgba(16, 185, 129, 0.45);
  font-weight: 700;
}
.idea-tester-chip {
  display: inline-flex; align-items: center;
  font-size: 11px; font-weight: 600;
  padding: 2px 8px; border-radius: 999px;
  background: rgba(0, 0, 0, 0.05);
  color: var(--text);
  margin-left: 6px;
}
.idea-tester-chip-self {
  background: rgba(245, 158, 11, 0.14);
  color: #B45309;
}
/* Inactive tester — visually muted so the user can see at a glance
   that the assignee was deactivated, but still readable. Italic to
   reinforce "stale". */
.idea-tester-chip-inactive {
  background: rgba(107, 114, 128, 0.14);
  color: #6b7280;
  font-style: italic;
}
/* "Testing for me" pill in the Brain → Ideas header. Hidden by default;
   JS reveals it when the viewer is the assignee on >0 testing ideas.
   When pressed (filter active), shifts to solid teal to communicate
   "you're seeing a filtered view". */
.ideas-testing-for-me {
  appearance: none; cursor: pointer; font: inherit;
  font-size: 12px; font-weight: 700;
  padding: 4px 12px; border-radius: 14px;
  border: 1px solid rgba(124, 58, 237, 0.45);
  background: rgba(124, 58, 237, 0.10);
  color: #6D28D9;
  display: inline-flex; align-items: center; gap: 6px;
  margin-right: 8px;
}
.ideas-testing-for-me.hidden { display: none; }
.ideas-testing-for-me[aria-pressed="true"] {
  background: #6D28D9; color: #fff; border-color: #6D28D9;
}
.ideas-testing-for-me #ideasTestingForMeCount {
  display: inline-block; padding: 0 6px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.35); font-weight: 800;
}
.idea-test-notes {
  font-size: 12px; line-height: 1.5;
  color: #047857;
  background: rgba(16, 185, 129, 0.08);
  border-left: 3px solid rgba(16, 185, 129, 0.5);
  padding: 6px 10px; margin: 6px 0 0;
  border-radius: 4px;
  white-space: pre-wrap;
}

.idea-text {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
  white-space: pre-wrap;
  word-wrap: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.idea-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 4px;
}
.idea-actions .btn-sm {
  font-size: 11.5px;
  padding: 4px 9px;
}
.idea-thread-link {
  font-size: 11.5px;
  color: var(--primary);
  text-decoration: none;
  margin-top: 2px;
}
.idea-thread-link:hover { text-decoration: underline; }

/* ========== Modal ========== */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 24px;
  backdrop-filter: blur(2px);
  animation: fadeIn 160ms ease-out;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 540px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: modalIn 180ms ease-out;
}
@keyframes modalIn {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--divider);
  background: var(--surface-alt);
}
.modal-header h3 { margin: 0; font-size: 15px; font-weight: 600; color: var(--text); }
.modal-close {
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: 50%;
  background: transparent;
  border: none;
  color: var(--text-dim);
  font-size: 20px;
  line-height: 1;
}
.modal-close:hover { background: var(--surface-sunk); color: var(--text); }

.modal-body {
  padding: 18px 20px 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow-y: auto;
}
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1;
}
.field-label {
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.field textarea, .field input, .field select {
  font: inherit;
  font-size: 13.5px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  resize: vertical;
  font-family: inherit;
}
.field select { background: var(--surface); cursor: pointer; }
.field textarea:focus, .field input:focus, .field select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.modal-actions {
  display: flex;
  gap: 8px;
  padding-top: 4px;
  align-items: center;
}

/* Compact variant used by confirmDialog() */
.modal.modal-sm { max-width: 420px; }
.confirm-body {
  padding: 18px 20px 6px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.confirm-body .confirm-message {
  font-size: 13.5px;
  color: var(--text);
  line-height: 1.5;
}
.confirm-body .confirm-detail {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.4;
  word-break: break-word;
}
.confirm-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  padding: 14px 20px 18px;
}

/* ─── Quick-add idea queue modal ─────────────────────────────────
   Used by the popup behind the composer's "💡 Queue idea" button.
   Mirror lives in web/telegram-app.html (same visual contract). */
.queue-idea-ctx {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  background: var(--surface-sunk);
  border-radius: var(--radius-md);
  font-size: 12.5px;
  line-height: 1.4;
}
.queue-idea-ctx-row { display: flex; gap: 8px; }
.queue-idea-ctx-label {
  flex: 0 0 60px;
  color: var(--text-muted);
  font-weight: 500;
}
.queue-idea-ctx-val {
  color: var(--text);
  word-break: break-word;
}
.queue-idea-ctx-val code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  color: var(--text-muted);
  background: transparent;
  padding: 0;
}
.queue-idea-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: -6px;
}
.queue-idea-textarea {
  width: 100%;
  min-height: 110px;
  padding: 10px 12px;
  font-size: 14px;
  font-family: inherit;
  line-height: 1.5;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-md);
  resize: vertical;
  box-sizing: border-box;
}
.queue-idea-textarea:focus {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
  border-color: transparent;
}
.queue-idea-attach-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.queue-idea-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex: 1;
}
.queue-idea-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 6px 3px 10px;
  background: var(--surface-sunk);
  border-radius: 999px;
  font-size: 12px;
  color: var(--text);
  max-width: 220px;
}
.queue-idea-chip > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.queue-idea-chip-x {
  width: 18px;
  height: 18px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-muted);
  border-radius: 50%;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
}
.queue-idea-chip-x:hover { background: var(--divider); color: var(--text); }
.queue-idea-err {
  color: var(--danger);
  font-size: 12.5px;
  min-height: 16px;
}
.btn-danger-solid {
  background: var(--danger);
  color: #fff;
  border-color: var(--danger);
}
.btn-danger-solid:hover:not(:disabled) {
  background: #b91c1c;
  border-color: #b91c1c;
  color: #fff;
}
.btn-danger-solid:active:not(:disabled) {
  background: #991b1b;
  border-color: #991b1b;
}

/* ========== All-Projects sidebar button ========== */
.sidebar-dashboard-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 8px 12px 4px;
  padding: 10px 12px;
  border-radius: var(--radius);
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 120ms, border-color 120ms, color 120ms;
}
.sidebar-dashboard-btn:hover {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
  color: var(--primary);
}

/* ========== Root dashboard ========== */
#dashboardHeader, #projectHeader {
  padding: 14px 28px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--surface);
  min-height: 64px;
  flex-shrink: 0;
}
#dashboardHeader h2, #projectHeader h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
}
.projects-grid {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 16px;
  padding: 24px 28px 32px;
  align-content: start;
}
.project-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-shadow: var(--shadow-sm);
  transition: border-color 120ms, transform 120ms, box-shadow 120ms;
}
.project-card:hover {
  border-color: var(--primary-tint-strong);
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}
.project-card.has-activity {
  border-left: 3px solid #16A34A;
  padding-left: 16px;
}
.project-card-head {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.project-card-name-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.project-card-name {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
}
.project-card-live {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  background: var(--primary-tint);
  color: var(--primary);
  border: 1px solid var(--primary-tint-strong);
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2px;
  text-decoration: none;
  white-space: nowrap;
}
.project-card-live:hover {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.project-card-folder {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  color: var(--text-faint);
}
.project-card-desc {
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.project-card-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-top: 4px;
}
.stat {
  text-align: center;
  padding: 8px 6px;
  border-radius: 8px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
}
.stat-value {
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
  line-height: 1;
}
.stat-label {
  font-size: 10px;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-top: 4px;
}
.stat-sub {
  font-size: 10px;
  color: var(--text-dim);
  margin-top: 2px;
}
.stat.stat-active { background: rgba(22, 163, 74, 0.08); border-color: rgba(22, 163, 74, 0.25); }
.stat.stat-active .stat-value { color: #0B9E60; }
.project-card-actions {
  display: flex;
  gap: 6px;
  margin-top: 6px;
}

/* ========== Project brain tabs ========== */
.brain-tabs {
  display: flex;
  gap: 2px;
  padding: 4px 28px 0;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-shrink: 0;
}
.brain-tab {
  padding: 10px 16px;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  border-radius: 0;
}
.brain-tab:hover { color: var(--text); background: var(--surface-sunk); }
.brain-tab.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
}
.brain-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  background: var(--bg);
}
.brain-tab-panel {
  padding: 20px 28px 32px;
}
.brain-tab-panel.hidden { display: none; }

/* ========== Project wizard view ========== */
/* Layout properties (flex, height, hidden) come from the shared `#chat, #dashboard,
   #project, #wizardSection` rule above so the wizard occupies the centre column. */
#wizardHeader {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 28px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  gap: 12px;
}
.wizard-title-wrap h2 { margin: 0; font-size: 18px; }
.wizard-subtitle { font-size: 12px; color: var(--text-faint); margin-top: 2px; }
.wizard-progress {
  flex-shrink: 0;
  display: flex;
  gap: 0;
  overflow-x: auto;
  padding: 6px 28px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.wizard-step-pill {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  font-size: 12px;
  color: var(--text-faint);
  border-bottom: 2px solid transparent;
  cursor: default;
  white-space: nowrap;
}
.wizard-step-pill .wizard-step-num {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface-sunk);
  color: var(--text-faint);
  font-size: 10.5px;
  font-weight: 700;
}
.wizard-step-pill.is-done {
  color: #086A44;
}
.wizard-step-pill.is-done .wizard-step-num {
  background: #0B9E60;
  color: #fff;
}
.wizard-step-pill.is-current {
  color: var(--primary);
  border-bottom-color: var(--primary);
  font-weight: 600;
}
.wizard-step-pill.is-current .wizard-step-num {
  background: var(--primary);
  color: #fff;
}
.wizard-chat {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 20px 28px 100px;
}
.wizard-turn {
  margin-bottom: 18px;
  max-width: 820px;
}
.wizard-turn.assistant .wizard-turn-bubble {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px 12px 12px 2px;
  padding: 12px 14px;
  /* Cap runaway assistant bubbles (e.g. the old plan-proposal blob that dumped 6–12
     detailed multi-paragraph prompts into a single bubble). Scroll instead of pushing
     the rest of the Done screen off-page. */
  max-height: 340px;
  overflow-y: auto;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.wizard-turn.assistant .wizard-turn-bubble > *:first-child { margin-top: 0; }
.wizard-turn.assistant .wizard-turn-bubble > *:last-child { margin-bottom: 0; }
.wizard-turn.user .wizard-turn-bubble {
  background: var(--primary-tint);
  border: 1px solid var(--primary-tint-strong);
  color: var(--primary);
  border-radius: 12px 12px 2px 12px;
  padding: 10px 14px;
  margin-left: auto;
  max-width: 720px;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.wizard-turn-bubble pre, .wizard-turn-bubble code {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 12.5px;
  background: var(--surface-sunk);
  padding: 1px 4px;
  border-radius: 3px;
}
.wizard-turn-bubble pre {
  padding: 8px 10px;
  overflow-x: auto;
  border: 1px solid var(--border);
}
/* Highlight a checked plan row whose title or body is still empty — this is the
   exact trap from the reported bug (a checked-but-blank row silently drops on
   submit and the wizard marches to Done with 0 prompts queued). */
.wizard-plan-row.is-blank-checked {
  border: 1px dashed #d97706;
  background: rgba(217, 119, 6, 0.06);
  border-radius: 8px;
  padding: 4px;
}
.wizard-plan-row.is-blank-checked .wizard-plan-title,
.wizard-plan-row.is-blank-checked .wizard-plan-body {
  border-color: #d97706;
}
/* "AI is working" heartbeat overlay in the wizard chat area. Injected during
   regenerate / accept-next-step so long LLM calls aren't perceived as a freeze. */
.wizard-busy-overlay {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  margin: 12px 0;
  background: var(--primary-tint, #eef2ff);
  border: 1px solid var(--primary-tint-strong, #c7d2fe);
  border-radius: 10px;
  font-size: 13px;
  color: var(--primary, #4338ca);
  max-width: 720px;
}
.wizard-busy-spinner {
  width: 14px; height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: wizardBusySpin 0.8s linear infinite;
  flex-shrink: 0;
}
.wizard-busy-label { flex: 1 1 auto; }
.wizard-busy-timer {
  font-variant-numeric: tabular-nums;
  opacity: 0.7;
  font-size: 12px;
}
@keyframes wizardBusySpin {
  to { transform: rotate(360deg); }
}
.wizard-turn-meta {
  font-size: 11px;
  color: var(--text-faint);
  margin-bottom: 4px;
}
.wizard-editor {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  margin-top: 6px;
  max-width: 820px;
}
.wizard-editor h4 { margin: 0 0 10px; font-size: 13px; }
.wizard-editor textarea, .wizard-editor input[type=text], .wizard-editor input[type=number] {
  width: 100%;
  font: inherit;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 8px;
  color: var(--text);
}
.wizard-editor textarea { min-height: 100px; resize: vertical; font-family: ui-monospace, SFMono-Regular, monospace; }
.wizard-editor .field-row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.wizard-editor .field-row label { min-width: 110px; color: var(--text-muted); font-size: 12px; }
.wizard-editor .field-row input { flex: 1 1 auto; }
.wizard-list-item {
  display: grid;
  grid-template-columns: 1fr 2fr auto;
  gap: 8px;
  margin-bottom: 6px;
  align-items: start;
}
.wizard-list-item.with-priority { grid-template-columns: 1fr 2fr 110px auto; }
.wizard-list-item textarea { min-height: 36px; }
.wizard-add-row {
  display: flex; justify-content: flex-start; margin-top: 6px;
}
.wizard-list-meta {
  font-size: 11px;
  color: var(--text-faint);
  margin-bottom: 6px;
}
.wizard-phase-block {
  margin-bottom: 14px;
  padding: 10px;
  background: var(--surface-sunk);
  border-radius: 8px;
}
.wizard-phase-block h5 {
  margin: 0 0 6px;
  font-size: 12.5px;
  color: var(--primary);
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}

/* Plan & Execute step: an ordered list of editable prompt cards */
.wizard-plan-row {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 8px;
  padding: 10px;
  margin-bottom: 10px;
}
.wizard-plan-row-head {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-bottom: 6px;
}
.wizard-plan-row-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 22px;
  padding: 0 6px;
  border-radius: 11px;
  background: var(--primary);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
}
.wizard-plan-title {
  flex: 1 1 auto;
  font-weight: 600;
}
.wizard-plan-body {
  width: 100%;
  min-height: 100px;
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 12.5px;
  line-height: 1.45;
  resize: vertical;
}
.wizard-plan-execute {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  padding: 10px 12px;
  background: var(--primary-tint);
  border: 1px solid var(--primary-tint-strong);
  border-radius: 8px;
  font-size: 13px;
  color: var(--primary);
}
.wizard-plan-execute label { cursor: pointer; }
.wizard-plan-ran {
  margin-top: 10px;
  padding: 10px 12px;
  background: #FFF7E6;
  border: 1px dashed #F2C77E;
  border-radius: 8px;
  font-size: 12.5px;
  color: #7A4407;
}
.wizard-plan-ran a { color: var(--primary); font-weight: 600; }

/* Per-row accept checkbox + visual de-emphasis when a row is excluded. */
.wizard-plan-accept {
  margin: 0;
  width: 16px; height: 16px;
  accent-color: var(--primary);
  cursor: pointer;
}
.wizard-plan-row.is-excluded {
  opacity: 0.45;
  background: var(--surface-sunk);
}
.wizard-plan-row.is-excluded .wizard-plan-row-num {
  background: var(--text-faint);
}
.wizard-plan-row.is-excluded .wizard-plan-title,
.wizard-plan-row.is-excluded .wizard-plan-body {
  text-decoration: line-through;
  color: var(--text-faint);
}

/* ========== Auto-build progress strip (chat view) ========== */
.build-progress {
  flex-shrink: 0;
  margin: 0;
  padding: 12px 28px 14px;
  background: linear-gradient(180deg, rgba(13, 115, 119, 0.06), rgba(13, 115, 119, 0.02));
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  color: var(--text);
}
.build-progress.hidden { display: none; }
.build-progress-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.build-progress-title {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  color: var(--primary);
  letter-spacing: 0.2px;
}
.build-progress-icon { font-size: 15px; }
.build-progress-meta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
#buildProgressResumeBtn { margin-left: 4px; }
#buildProgressResumeBtn.hidden { display: none; }
.build-progress-sep { color: var(--text-faint); }
.build-progress-bar {
  height: 6px;
  background: var(--surface-sunk);
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 8px;
}
.build-progress-fill {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--primary), #14a59a);
  transition: width 240ms ease-out;
  border-radius: 4px;
}
.build-progress.is-running .build-progress-fill {
  /* Soft pulsing band while a step is active so the user can see it's alive even when
     the percentage hasn't moved (Claude turns can take a while). */
  background-image: linear-gradient(90deg, var(--primary), #14a59a, var(--primary));
  background-size: 200% 100%;
  animation: buildPulse 2.4s linear infinite;
}
@keyframes buildPulse {
  from { background-position: 0% 0; }
  to   { background-position: -200% 0; }
}
.build-progress-now {
  display: flex;
  gap: 10px;
  align-items: baseline;
  margin-bottom: 8px;
  min-height: 22px;
  padding: 6px 10px;
  border-radius: 6px;
  /* Subtle background so the "now" line reads as the active strip even when nothing
     is animating. While running we layer a soft glow on top via the .is-running
     parent class. */
  background: rgba(13, 115, 119, 0.06);
  border: 1px solid rgba(13, 115, 119, 0.16);
  transition: box-shadow 240ms ease-out, border-color 240ms;
}
.build-progress.is-running .build-progress-now {
  border-color: rgba(13, 115, 119, 0.45);
  /* Soft pulsing glow that breathes — gives a clear "live" feel without being noisy. */
  animation: buildNowGlow 2.4s ease-in-out infinite;
}
@keyframes buildNowGlow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(13, 115, 119, 0.18), 0 0 14px 0 rgba(13, 115, 119, 0.12); }
  50%      { box-shadow: 0 0 0 4px rgba(13, 115, 119, 0.10), 0 0 22px 4px rgba(13, 115, 119, 0.20); }
}
.build-progress-now-label {
  font-weight: 700;
  color: var(--primary);
  white-space: nowrap;
  font-size: 13.5px;
  letter-spacing: 0.1px;
}
.build-progress-now-detail {
  flex: 1 1 auto;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.build-progress.is-running .build-progress-now-detail {
  color: var(--primary);
}

/* Heartbeat row: a small dot that pulses on every token arrival + a "Last activity"
   counter so the user can confirm the run isn't stuck even when no prose is streaming. */
.build-progress-heartbeat {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
  font-size: 11.5px;
  color: var(--text-faint);
}
.build-progress-heartbeat.is-stale { color: #8A4B07; }
.build-progress-heartbeat.is-very-stale { color: var(--danger); }
.build-progress-heartbeat-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #cbd1dc;
  flex-shrink: 0;
}
.build-progress-heartbeat-dot.is-active {
  background: #0B9E60;
  box-shadow: 0 0 0 0 rgba(11, 158, 96, 0.6);
  animation: heartbeatPulse 1.2s ease-out;
}
.build-progress-heartbeat.is-stale .build-progress-heartbeat-dot { background: #F39C20; }
.build-progress-heartbeat.is-very-stale .build-progress-heartbeat-dot { background: var(--danger); }
@keyframes heartbeatPulse {
  0%   { box-shadow: 0 0 0 0 rgba(11, 158, 96, 0.6); }
  100% { box-shadow: 0 0 0 10px rgba(11, 158, 96, 0); }
}
.build-progress-steps {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}
.build-step-pip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  font-size: 11px;
  color: var(--text-muted);
  white-space: nowrap;
  cursor: default;
}
.build-step-pip.is-done {
  background: #E7F8EF;
  border-color: #A7E3C3;
  color: #086A44;
}
/* Active step: vivid filled pill with a pulsing glow so the user can spot
   "what's running right now" at a glance, distinct from done/error pips. */
.build-step-pip.is-running {
  background: linear-gradient(135deg, #F59E0B 0%, #F97316 100%);
  border-color: #F59E0B;
  color: #FFFFFF;
  font-weight: 700;
  animation: buildPipGlow 1.6s ease-in-out infinite;
  position: relative;
  z-index: 1;
}
@keyframes buildPipGlow {
  0%   { box-shadow: 0 0 0 0   rgba(245, 158, 11, 0.55), 0 0 6px  rgba(249, 115, 22, 0.45); }
  60%  { box-shadow: 0 0 0 8px rgba(245, 158, 11, 0.00), 0 0 14px rgba(249, 115, 22, 0.65); }
  100% { box-shadow: 0 0 0 0   rgba(245, 158, 11, 0.00), 0 0 6px  rgba(249, 115, 22, 0.45); }
}
@media (prefers-reduced-motion: reduce) {
  .build-step-pip.is-running { animation: none; }
}
.build-step-pip.is-error {
  background: #FDECEC;
  border-color: #F4B6B6;
  color: #A31A1A;
}
.build-step-pip-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  background: rgba(0, 0, 0, 0.06);
  border-radius: 50%;
  font-size: 9.5px;
  font-weight: 700;
}
.build-step-pip.is-done .build-step-pip-num { background: #0B9E60; color: #fff; }
.build-step-pip.is-running .build-step-pip-num { background: #FFFFFF; color: #B45309; }
.build-step-pip.is-error .build-step-pip-num { background: var(--danger); color: #fff; }
.build-step-pip:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* ──────────────────────────────────────────────────────────────────────────
   Live activity panel — opens when the user clicks the glowing (running)
   step pip. Shows a scrolling list of "tool → file" entries fed live by
   `message.tool` SSE events as Claude touches each file.
   ────────────────────────────────────────────────────────────────────────── */
.live-activity-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.42);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9000;
  animation: liveActivityFadeIn 120ms ease-out;
}
@keyframes liveActivityFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.live-activity-panel {
  width: min(680px, 92vw);
  max-height: 72vh;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #E2E8F0);
  border-radius: 14px;
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.32);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  outline: none;
}
.live-activity-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border, #E2E8F0);
  background: linear-gradient(135deg, rgba(245, 158, 11, 0.10) 0%, rgba(249, 115, 22, 0.06) 100%);
}
.live-activity-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #F59E0B;
  box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.5);
  animation: liveActivityDotPulse 1.5s ease-in-out infinite;
}
@keyframes liveActivityDotPulse {
  0%   { box-shadow: 0 0 0 0   rgba(245, 158, 11, 0.55); }
  70%  { box-shadow: 0 0 0 10px rgba(245, 158, 11, 0);    }
  100% { box-shadow: 0 0 0 0   rgba(245, 158, 11, 0);    }
}
.live-activity-panel.is-finished .live-activity-dot {
  background: var(--text-muted, #64748B);
  animation: none;
}
.live-activity-title {
  flex: 1;
  font-weight: 600;
  font-size: 14px;
  color: var(--text, #0F172A);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.live-activity-close {
  background: transparent;
  border: 0;
  font-size: 22px;
  line-height: 1;
  color: var(--text-muted, #64748B);
  cursor: pointer;
  padding: 0 6px;
  border-radius: 6px;
}
.live-activity-close:hover { color: var(--text, #0F172A); background: rgba(0,0,0,0.04); }
.live-activity-close:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.live-activity-list {
  flex: 1;
  overflow-y: auto;
  padding: 6px 0;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12.5px;
  scroll-behavior: smooth;
}
.live-activity-list:focus-visible { outline: none; }

.live-activity-row {
  display: grid;
  grid-template-columns: 22px 70px 14px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 5px 16px;
  border-bottom: 1px dashed rgba(148, 163, 184, 0.18);
  color: var(--text, #0F172A);
}
.live-activity-row:last-child { border-bottom: 0; }
.live-activity-row.is-fresh {
  animation: liveActivitySlideIn 600ms ease-out;
  background: linear-gradient(90deg, rgba(245, 158, 11, 0.18) 0%, rgba(245, 158, 11, 0) 100%);
}
@keyframes liveActivitySlideIn {
  0%   { transform: translateX(8px); opacity: 0; }
  100% { transform: translateX(0);    opacity: 1; }
}
.live-activity-icon {
  text-align: center;
  color: #B45309;
}
.live-activity-tool {
  font-weight: 700;
  color: #B45309;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.live-activity-arrow { color: var(--text-muted, #64748B); }
.live-activity-detail {
  color: var(--text, #0F172A);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.live-activity-time {
  color: var(--text-muted, #64748B);
  font-size: 11px;
  white-space: nowrap;
}
.live-activity-empty {
  padding: 32px 16px;
  text-align: center;
  color: var(--text-muted, #64748B);
  font-style: italic;
  font-size: 12.5px;
}
.live-activity-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;
  border-top: 1px solid var(--border, #E2E8F0);
  font-size: 11.5px;
  color: var(--text-muted, #64748B);
  background: rgba(248, 250, 252, 0.6);
}
@media (prefers-reduced-motion: reduce) {
  .live-activity-row.is-fresh { animation: none; }
  .live-activity-dot { animation: none; }
  .live-activity-overlay { animation: none; }
}

/* Summary line under the plan list */
.wizard-plan-summary {
  margin: 8px 0 4px;
  font-size: 12.5px;
  color: var(--text-muted);
  font-style: italic;
}
.wizard-footer {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 28px;
  background: var(--surface);
  border-top: 1px solid var(--border);
}
.wizard-start-hint { font-size: 13px; color: var(--text-muted); margin-bottom: 12px; }
.wizard-start-flash {
  margin: 8px 0;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 12.5px;
}
.wizard-start-flash.is-error { background: #FDECEC; color: #A31A1A; border: 1px solid #F4B6B6; }
.folder-panel-head-actions { display: inline-flex; gap: 6px; }

/* Wizard start modal: resume + mode tabs */
.wizard-resume-block {
  margin-bottom: 16px;
  padding: 10px 12px;
  border: 1px solid var(--primary-tint-strong);
  background: var(--primary-tint);
  border-radius: 10px;
}
.wizard-resume-head {
  font-weight: 700;
  color: var(--primary);
  font-size: 12.5px;
  margin-bottom: 8px;
  letter-spacing: 0.2px;
  text-transform: uppercase;
}
.wizard-resume-list { display: flex; flex-direction: column; gap: 6px; }
.wizard-resume-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 13px;
}
.wizard-resume-row .wizard-resume-info { flex: 1 1 auto; min-width: 0; }
.wizard-resume-row .wizard-resume-name { font-weight: 600; color: var(--text); }
.wizard-resume-row .wizard-resume-meta { font-size: 11.5px; color: var(--text-faint); margin-top: 2px; }
.wizard-resume-divider {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 14px 0 4px;
  color: var(--text-faint);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.wizard-resume-divider::before, .wizard-resume-divider::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}
.wizard-mode-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 14px;
}
.wizard-mode-tab {
  padding: 8px 14px;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.wizard-mode-tab:hover { color: var(--text); }
.wizard-mode-tab.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
}
.wizard-mode-pane.hidden { display: none; }
#wizardExistingPick { width: 100%; }

/* Delete-project confirmation */
.delete-project-warning {
  font-size: 13px;
  color: #A31A1A;
  background: #FDECEC;
  border: 1px solid #F4B6B6;
  padding: 10px 12px;
  border-radius: 6px;
  margin-bottom: 10px;
}
.delete-project-checklist {
  margin: 0 0 12px 18px;
  padding: 0;
  font-size: 12.5px;
  color: var(--text-muted);
}
.delete-project-checklist li { margin: 3px 0; }
.btn-danger.btn-primary {
  background: var(--danger) !important;
  color: #fff !important;
  border-color: var(--danger) !important;
}
.btn-danger.btn-primary:hover:not(:disabled) {
  background: #b51919 !important;
  border-color: #b51919 !important;
}

/* "+ New" modal — folder picker + action chooser */
.new-modal-hint { font-size: 13px; color: var(--text-muted); margin-bottom: 12px; }
.new-modal-action-block {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px 4px;
  margin: 12px 0;
  background: var(--surface-sunk);
}
.new-modal-action-block legend {
  padding: 0 6px;
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 600;
  letter-spacing: 0.2px;
  text-transform: uppercase;
}
.new-modal-action-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 8px 6px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 100ms;
}
.new-modal-action-row:hover { background: var(--surface); }
.new-modal-action-row input[type="radio"] { margin-top: 4px; }
.new-modal-action-title { font-size: 13px; font-weight: 600; color: var(--text); }
.new-modal-action-sub { font-size: 11.5px; color: var(--text-faint); margin-top: 2px; line-height: 1.4; }
#newModalFolder { width: 100%; }
#newModalNewFolder, #newModalThreadTitle { width: 100%; }

/* Searchable-select combobox (per global design rule — every dropdown must be
   type-to-filter + arrow-key navigable). Underlying <select> is hidden but kept
   as the source-of-truth for .value; overlay input + <ul> is what the user sees. */
.searchable-select { position: relative; width: 100%; }
.searchable-select-input {
  width: 100%;
  padding: 8px 32px 8px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 14px;
  background: var(--surface);
  color: var(--text);
  box-sizing: border-box;
  font: inherit;
}
.searchable-select-input:focus {
  outline: none;
  border-color: #0D7377;
  box-shadow: 0 0 0 2px rgba(13, 115, 119, 0.15);
}
.searchable-select-chevron {
  position: absolute;
  right: 4px; top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  padding: 4px 8px;
  font-size: 11px;
  line-height: 1;
}
.searchable-select-native {
  position: absolute !important;
  opacity: 0 !important;
  pointer-events: none !important;
  height: 0 !important;
  width: 0 !important;
  overflow: hidden !important;
  clip: rect(0 0 0 0);
}
.searchable-select-results {
  position: absolute; top: 100%; left: 0; right: 0;
  z-index: 20;
  margin: 4px 0 0;
  padding: 4px 0;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  max-height: 260px;
  overflow-y: auto;
  box-shadow: 0 6px 24px rgba(15, 23, 42, 0.14);
}
.searchable-select-results li {
  padding: 8px 12px;
  cursor: pointer;
  font-size: 13px;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 6px;
  line-height: 1.35;
}
.searchable-select-results li.is-active,
.searchable-select-results li:hover {
  background: var(--surface-hover);
}
.searchable-select-results li.is-empty {
  color: var(--text-muted);
  cursor: default;
  font-style: italic;
}
.searchable-select-results li.is-empty:hover { background: transparent; }
.searchable-select-results li.is-create-new {
  border-bottom: 1px solid var(--border);
  color: #0D7377;
  font-weight: 500;
}

/* Subdomain + deploy block (shown only when "+ Create new folder") */
.new-modal-deploy-block {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  margin: 12px 0;
  background: var(--surface-sunk);
}
.new-modal-deploy-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  gap: 10px;
}
.new-modal-deploy-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-muted);
  cursor: pointer;
}
.new-modal-deploy-block .field-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
.new-modal-deploy-block .field-row label {
  flex: 0 0 100px;
  color: var(--text-muted);
  font-size: 12px;
}
.new-modal-deploy-block .field-row input {
  flex: 1 1 auto;
}
.new-modal-suffix {
  color: var(--text-faint);
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 12px;
}
.new-modal-subdomain-status {
  font-size: 11.5px;
  margin: 0 0 8px 108px;
  min-height: 14px;
  color: var(--text-faint);
}
.new-modal-subdomain-status.is-ok { color: #086A44; }
.new-modal-subdomain-status.is-bad { color: var(--danger); }
.new-modal-subdomain-status.is-warn { color: #8A4B07; }

/* ========== Build tab — live generation progress card ========== */
.buildplan-progress-card {
  margin: 0 0 14px;
  padding: 14px 16px;
  border: 1px solid rgba(13, 115, 119, 0.45);
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(13, 115, 119, 0.10), rgba(13, 115, 119, 0.04));
  position: relative;
  overflow: hidden;
}
.buildplan-progress-card.is-active {
  /* Soft pulsing glow that breathes — visible "I'm alive" cue. */
  animation: buildPlanCardGlow 2.4s ease-in-out infinite;
}
@keyframes buildPlanCardGlow {
  0%, 100% {
    box-shadow:
      0 0 0 0 rgba(13, 115, 119, 0.18),
      0 0 14px 0 rgba(13, 115, 119, 0.12);
  }
  50% {
    box-shadow:
      0 0 0 4px rgba(13, 115, 119, 0.10),
      0 0 28px 6px rgba(13, 115, 119, 0.22);
  }
}
.buildplan-progress-card.is-stale {
  border-color: #F2C77E;
  background: linear-gradient(180deg, rgba(243, 156, 32, 0.10), rgba(243, 156, 32, 0.04));
  animation: none;
  box-shadow: 0 0 0 2px rgba(243, 156, 32, 0.18);
}
.buildplan-progress-card.is-very-stale {
  border-color: var(--danger);
  background: linear-gradient(180deg, rgba(220, 38, 38, 0.10), rgba(220, 38, 38, 0.04));
  animation: none;
  box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.18);
}
.buildplan-progress-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}
.buildplan-progress-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--primary);
  box-shadow: 0 0 0 0 rgba(13, 115, 119, 0.6);
  flex-shrink: 0;
}
.buildplan-progress-dot.is-active {
  animation: buildPlanDotPulse 1.2s ease-out;
}
@keyframes buildPlanDotPulse {
  0%   { box-shadow: 0 0 0 0 rgba(13, 115, 119, 0.6); transform: scale(1); }
  50%  { transform: scale(1.4); }
  100% { box-shadow: 0 0 0 14px rgba(13, 115, 119, 0); transform: scale(1); }
}
.buildplan-progress-card.is-stale .buildplan-progress-dot { background: #F39C20; }
.buildplan-progress-card.is-very-stale .buildplan-progress-dot { background: var(--danger); }
.buildplan-progress-title {
  flex: 1 1 auto;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--primary);
}
.buildplan-progress-card.is-stale .buildplan-progress-title { color: #8A4B07; }
.buildplan-progress-card.is-very-stale .buildplan-progress-title { color: var(--danger); }
.buildplan-progress-elapsed {
  font-size: 11.5px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.buildplan-progress-current {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  margin: 6px 0 10px;
  padding: 6px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  word-wrap: break-word;
}
.buildplan-progress-bar {
  height: 6px;
  background: var(--surface-sunk);
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 8px;
}
.buildplan-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--primary), #14a59a);
  background-size: 200% 100%;
  animation: buildPlanFillShimmer 2.4s linear infinite;
  border-radius: 4px;
  transition: width 240ms ease-out;
}
@keyframes buildPlanFillShimmer {
  from { background-position: 0% 0; }
  to   { background-position: -200% 0; }
}
.buildplan-progress-hint {
  font-size: 11.5px;
  color: var(--text-faint);
  font-style: italic;
}

/* ========== Build tab (project-level AI roadmap, auto-runnable) ========== */
.build-tab-actions { display: inline-flex; gap: 6px; align-items: center; }
.build-tab-list { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
/* Each build-plan row reuses the wizard plan styling for visual consistency. The
   milestone-group header is a dedicated divider rendered above the first row of
   each milestone bucket. */
.build-tab-milestone-head {
  margin: 14px 0 4px;
  padding: 6px 10px;
  border-left: 3px solid var(--primary);
  background: var(--surface-sunk);
  border-radius: 4px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--primary);
  letter-spacing: 0.2px;
}
.build-tab-running-banner {
  margin: 8px 0 14px;
  padding: 10px 12px;
  border: 1px solid #F2C77E;
  background: #FFF7E6;
  border-radius: 8px;
  font-size: 13px;
  color: #7A4407;
  display: flex;
  align-items: center;
  gap: 10px;
}
.build-tab-running-banner.hidden { display: none; }
.build-tab-running-banner a {
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
}
.build-tab-running-banner a:hover { text-decoration: underline; }

/* ========== Pending-approvals blocking overlay ========== */
.approval-gate {
  position: fixed; inset: 0;
  background: rgba(15, 30, 51, 0.78);
  backdrop-filter: blur(6px);
  z-index: 9999;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 60px 20px 20px;
  overflow-y: auto;
}
.approval-gate.hidden { display: none; }
body.approval-gate-open { overflow: hidden; }
.approval-gate-card {
  width: 100%; max-width: 640px;
  background: var(--surface, #fff);
  border-radius: 14px;
  box-shadow: 0 24px 64px rgba(15, 30, 51, 0.5);
  padding: 24px 26px;
  display: flex; flex-direction: column; gap: 14px;
}
.approval-gate-head {
  display: flex; align-items: baseline; gap: 12px;
  padding-bottom: 12px; border-bottom: 1px solid var(--border);
}
.approval-gate-head strong { font-size: 20px; color: var(--text); }
.approval-gate-count {
  background: var(--brand-pink, #E44C9A); color: #FFF;
  font-weight: 700; padding: 3px 10px; border-radius: 999px; font-size: 13px;
}
.approval-gate-sub { font-size: 13px; color: var(--text-muted); margin: 0; }
.approval-gate-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 14px; }
/* Category TABS across the top of the Notifications overlay — each tab is
   one bucket ("Pending your approval" · "New signups" · "Invite requests"
   · "New agents"). Clicking a tab swaps the visible panel; only one
   category's items render at a time so a long Pending list doesn't bury
   the rest. Tabs themselves stay pinned at the top via flex-shrink:0 +
   sticky inside the scrollable card. */
.approval-gate-tabs {
  list-style: none;
  display: flex; flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 4px;
  padding: 6px 4px;
  border-bottom: 1px solid var(--border, #e2e8f0);
  position: sticky; top: 0;
  background: var(--surface, #fff);
  z-index: 1;
}
.approval-gate-tab {
  appearance: none;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted, #64748b);
  font: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.approval-gate-tab:hover {
  background: var(--surface-2, #f3f4f6);
  color: var(--text, #0f172a);
}
.approval-gate-tab.is-active {
  background: var(--primary-tint, rgba(0,120,191,0.10));
  color: var(--primary, #0078BF);
  border-color: var(--primary-tint-strong, rgba(0,120,191,0.25));
}
.approval-gate-tab-icon { font-size: 15px; line-height: 1; flex-shrink: 0; }
.approval-gate-tab-label { white-space: nowrap; }
.approval-gate-tab-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 20px; padding: 0 7px;
  border-radius: 999px;
  background: var(--brand-pink, #E44C9A); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 1;
  flex-shrink: 0;
}
.approval-gate-tab:not(.is-active) .approval-gate-tab-count {
  background: var(--text-faint, #94a3b8);
}
/* Panels — one per category, only the active one renders. Children
   re-use the original `.approval-gate-item` card. */
.approval-gate-section {
  list-style: none;
  display: flex; flex-direction: column; gap: 10px;
}
.approval-gate-section.is-hidden { display: none; }
.approval-gate-section-sub {
  font-size: 12.5px; color: var(--text-muted, #64748b);
  margin: 0 2px 2px; line-height: 1.45;
}
.approval-gate-section-list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 12px;
}
/* Pager — 10-per-page navigation strip under each category panel. Rendered
   as "Page X of Y · N total" + a row of « ‹ 1 2 … N › » buttons. Hides
   itself when only one page exists. */
.approval-gate-pager {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--border, #e2e8f0);
}
.approval-gate-pager:empty { display: none; }
.approval-gate-pager-meta {
  font-size: 12.5px; color: var(--text-muted, #64748b);
}
.approval-gate-pager-meta strong { color: var(--text, #0f172a); font-weight: 700; }
.approval-gate-pager-row {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  justify-content: center;
}
.approval-gate-page-btn {
  appearance: none;
  min-width: 32px; height: 32px; padding: 0 10px;
  border: 1px solid var(--border, #e2e8f0); border-radius: 8px;
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.approval-gate-page-btn:hover:not(:disabled):not(.is-active) {
  background: var(--surface-2, #f3f4f6);
  border-color: var(--primary-tint-strong, rgba(0,120,191,0.25));
}
.approval-gate-page-btn.is-active {
  background: var(--primary, #0078BF); color: #fff;
  border-color: var(--primary, #0078BF);
  cursor: default;
}
.approval-gate-page-btn:disabled {
  opacity: 0.4; cursor: not-allowed;
}
.approval-gate-page-prev, .approval-gate-page-next {
  font-size: 16px; line-height: 1; padding: 0 12px;
}
.approval-gate-page-gap {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; color: var(--text-faint, #94a3b8);
  font-size: 14px; padding: 0 2px;
}
.approval-gate-item {
  border: 1px solid var(--border); border-radius: 10px;
  padding: 14px 16px;
  background: rgba(0, 120, 191, 0.04);
  display: flex; flex-direction: column; gap: 8px;
}
.approval-gate-item-title { font-weight: 700; font-size: 15px; color: var(--text); }
.approval-gate-item-sub { font-size: 13px; color: var(--text-muted); line-height: 1.5; }
.approval-gate-item-meta { font-size: 12px; color: var(--text-faint); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; word-break: break-word; }
.approval-gate-item-actions { display: flex; gap: 8px; align-items: center; margin-top: 4px; flex-wrap: wrap; }
.approval-gate-item-actions .approve-btn {
  background: #2A9D4F; color: #FFF; border: none;
  padding: 8px 14px; border-radius: 7px; font-weight: 700; cursor: pointer;
  font-size: 13px; font-family: inherit;
}
.approval-gate-item-actions .approve-btn:hover { background: #237D40; }
.approval-gate-item-actions .reject-btn {
  background: transparent; color: var(--danger); border: 1px solid var(--danger);
  padding: 8px 14px; border-radius: 7px; font-weight: 600; cursor: pointer;
  font-size: 13px; font-family: inherit;
}
.approval-gate-item-actions .reject-btn:hover { background: rgba(220, 53, 69, 0.08); }
.approval-gate-item-reject-row {
  display: flex; gap: 8px; margin-top: 6px;
}
.approval-gate-item-reject-row input {
  flex: 1; padding: 7px 10px; border-radius: 6px;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text); font-size: 13px; font-family: inherit;
}
.approval-gate-empty {
  text-align: center; font-size: 14px; color: var(--text-muted); padding: 16px;
}

/* ========== Impersonation banner (admin "Login as" indicator) ========== */
.impersonation-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 16px;
  background: linear-gradient(90deg, #FFF4E0, #FFE7BD);
  border-bottom: 1px solid #F39C20;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
  font-size: 13px;
  color: #7A4407;
}
.impersonation-banner.hidden { display: none; }
.impersonation-banner .impersonation-icon {
  font-size: 16px;
  flex-shrink: 0;
}
.impersonation-banner .impersonation-text { flex: 1 1 auto; }
.impersonation-banner .impersonation-text b { color: #5A2E04; }
.impersonation-banner .impersonation-sub { color: #8A4B07; opacity: 0.85; margin-left: 6px; }
/* When the banner is visible, push the page content down so it doesn't sit underneath. */
body.has-impersonation-banner { padding-top: 40px; }

/* ========== Sidebar LLM Backend switch (compact Claude / Grok) ========== */
.sidebar-llm-backend {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 4px 12px 4px;
  padding: 8px 10px;
  border-radius: var(--radius);
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  min-height: 40px;
}
.sidebar-llm-backend.is-grok {
  border-color: rgba(14, 165, 233, 0.35);
  background: rgba(14, 165, 233, 0.08);
}
.sidebar-llm-backend.is-opencode {
  border-color: rgba(13, 115, 119, 0.35);
  background: rgba(13, 115, 119, 0.08);
}
.sidebar-llm-backend.is-kilo {
  border-color: rgba(99, 102, 241, 0.35);
  background: rgba(99, 102, 241, 0.08);
}
.sidebar-llm-backend__icon {
  font-size: 14px;
  line-height: 1;
  flex-shrink: 0;
}
.sidebar-llm-backend__label {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sidebar-llm-backend__picker {
  position: relative;
  flex-shrink: 0;
}
.sidebar-llm-backend__btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  max-width: 110px;
}
.sidebar-llm-backend__btn:hover:not(:disabled) {
  border-color: var(--primary);
  color: var(--primary);
}
.sidebar-llm-backend__btn[aria-expanded="true"] {
  border-color: var(--primary);
  color: var(--primary);
}
.sidebar-llm-backend__btn[aria-expanded="true"] .sidebar-llm-backend__chev {
  transform: rotate(180deg);
}
.sidebar-llm-backend__btn.is-grok {
  border-color: rgba(14, 165, 233, 0.45);
  color: #0369a1;
}
.sidebar-llm-backend__btn.is-readonly,
.sidebar-llm-backend__btn:disabled {
  cursor: default;
  opacity: 0.9;
}
.sidebar-llm-backend__btn.is-readonly .sidebar-llm-backend__chev,
.sidebar-llm-backend.is-readonly .sidebar-llm-backend__chev {
  display: none;
}
.sidebar-llm-backend__btn.is-busy {
  opacity: 0.65;
  cursor: wait;
}
.sidebar-llm-backend__value {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sidebar-llm-backend__chev {
  opacity: 0.7;
  flex-shrink: 0;
  transition: transform 120ms ease;
}
.sidebar-llm-backend__menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 140px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-lg);
  padding: 4px;
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.sidebar-llm-backend__menu.hidden { display: none; }
.sidebar-llm-backend__item {
  all: unset;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
}
.sidebar-llm-backend__item:hover,
.sidebar-llm-backend__item:focus-visible {
  background: var(--surface-sunk);
  outline: none;
}
.sidebar-llm-backend__item.is-active .sli-name {
  color: var(--primary);
  font-weight: 700;
}
.sidebar-llm-backend__item .sli-check {
  color: var(--primary);
  font-weight: 700;
  opacity: 0;
}
.sidebar-llm-backend__item[aria-checked="true"] .sli-check,
.sidebar-llm-backend__item.is-active .sli-check {
  opacity: 1;
}
.sidebar-llm-backend__item:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
html.theme-dark .sidebar-llm-backend.is-grok {
  background: rgba(14, 165, 233, 0.12);
}
html.theme-dark .sidebar-llm-backend.is-opencode {
  background: rgba(13, 115, 119, 0.12);
}
html.theme-dark .sidebar-llm-backend.is-kilo {
  background: rgba(99, 102, 241, 0.12);
}
html.theme-dark .sidebar-llm-backend__btn.is-grok {
  color: #7dd3fc;
}

/* ========== Help modal + onboarding overlay ========== */
.help-modal { width: min(96vw, 1100px); max-height: 86vh; }
.help-modal-body {
  display: grid;
  grid-template-columns: 280px 1fr;
  height: calc(86vh - 60px);
  overflow: hidden;
}
.help-sidebar {
  border-right: 1px solid var(--border);
  background: var(--surface-sunk);
  padding: 12px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
#helpSearch {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  font-size: 13px;
  color: var(--text);
}
#helpSearch:focus {
  outline: none;
  border-color: var(--primary-tint-strong);
  box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.10);
}
.help-article-list { display: flex; flex-direction: column; gap: 2px; }
.help-article-list-group-head {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-faint);
  margin: 10px 6px 4px;
}
.help-article-item {
  text-align: left;
  padding: 8px 10px;
  border: none;
  background: transparent;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  color: var(--text);
  line-height: 1.4;
}
.help-article-item:hover { background: var(--surface); }
.help-article-item.is-active {
  background: var(--primary-tint);
  color: var(--primary);
  font-weight: 600;
}
.help-article-item .help-article-snippet {
  display: block;
  font-size: 11.5px;
  color: var(--text-faint);
  margin-top: 2px;
  font-weight: 400;
}
.help-article-item.is-active .help-article-snippet { color: var(--primary); opacity: 0.85; }
.help-article-list-empty {
  font-size: 12.5px;
  color: var(--text-faint);
  font-style: italic;
  padding: 20px 6px;
  text-align: center;
}

.help-content {
  padding: 22px 28px 32px;
  overflow-y: auto;
  font-size: 14px;
  line-height: 1.65;
  color: var(--text);
}
.help-content h1, .help-content h2, .help-content h3 { margin: 18px 0 8px; }
.help-content h1 { font-size: 22px; }
.help-content h2 { font-size: 17px; border-bottom: 1px solid var(--border); padding-bottom: 4px; }
.help-content h3 { font-size: 15px; }
.help-content p { margin: 8px 0; }
.help-content ul, .help-content ol { margin: 8px 0 8px 22px; }
.help-content li { margin: 3px 0; }
.help-content code {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 12.5px;
  background: var(--surface-sunk);
  padding: 1px 5px;
  border-radius: 3px;
}
.help-content pre {
  background: var(--surface-sunk);
  padding: 10px 12px;
  border-radius: 6px;
  overflow-x: auto;
  font-size: 12.5px;
  border: 1px solid var(--border);
}
.help-content kbd {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 11px;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 6px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
  background: var(--surface);
}

/* Onboarding overlay (first-login walkthrough) */
.onboarding-overlay {
  position: fixed;
  inset: 0;
  z-index: 1500;
  background: rgba(15, 17, 23, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.onboarding-overlay.hidden { display: none; }
.onboarding-card {
  width: min(94vw, 720px);
  background: var(--surface);
  border-radius: 14px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.30);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.onboarding-header {
  padding: 22px 28px 12px;
  position: relative;
}
.onboarding-header .modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
}
.onboarding-eyebrow {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  color: var(--primary);
  text-transform: uppercase;
  margin-bottom: 6px;
}
.onboarding-header h2 { margin: 0; font-size: 22px; color: var(--text); }
.onboarding-body {
  padding: 6px 28px 18px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text);
  min-height: 240px;
}
.onboarding-body h3 { margin: 12px 0 6px; font-size: 16px; }
.onboarding-body p { margin: 8px 0; }
.onboarding-body ul { margin: 8px 0 8px 20px; }
.onboarding-footer {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 28px 22px;
  background: var(--surface-sunk);
  border-top: 1px solid var(--border);
}
.onboarding-progress {
  display: inline-flex;
  gap: 6px;
}
.onboarding-progress-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--border);
}
.onboarding-progress-dot.is-active { background: var(--primary); }
.onboarding-progress-dot.is-done { background: var(--primary); opacity: 0.5; }

@media (max-width: 720px) {
  .help-modal-body { grid-template-columns: 1fr; height: auto; max-height: 80vh; }
  .help-sidebar { border-right: none; border-bottom: 1px solid var(--border); max-height: 30vh; }
}

/* ========== Brain mode switch (Normal / Advanced) ========== */
.brain-mode-switch {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px;
  background: var(--surface-sunk);
  margin-right: 6px;
}
.brain-mode-btn {
  padding: 4px 12px;
  border: none;
  background: transparent;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  transition: background 120ms, color 120ms;
}
.brain-mode-btn:hover { color: var(--text); }
.brain-mode-btn.is-active {
  background: var(--surface);
  color: var(--primary);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}

/* MODE: NORMAL — hide power-user controls (upload / raw markdown / future advanced
   surfaces). The tab-doc-panel is the main hide target today; opt-in via
   `.brain-advanced-only` for any future advanced control. */
#project[data-brain-mode="normal"] .tab-doc-panel,
#project[data-brain-mode="normal"] .brain-advanced-only {
  display: none !important;
}

/* MODE: READ — view-only. Hides the same power-user surfaces as normal mode AND
   suppresses every primary-action button on every tab so the brain renders as a
   clean, presentational view (no Add / Edit / Delete / Generate / Save).
   Implementation note: we hide rather than disable so the layout collapses and the
   read-only pages don't look broken. */
#project[data-brain-mode="read"] .tab-doc-panel,
#project[data-brain-mode="read"] .brain-advanced-only,
#project[data-brain-mode="read"] .brain-panel-head .btn-primary,
#project[data-brain-mode="read"] .brain-panel-head .btn-ghost,
#project[data-brain-mode="read"] .brain-card-actions,
#project[data-brain-mode="read"] .wireframe-actions,
#project[data-brain-mode="read"] .build-tab-actions,
#project[data-brain-mode="read"] .build-tab-running-banner,
#project[data-brain-mode="read"] .srs-actions,
#project[data-brain-mode="read"] #ideasAddBtn,
#project[data-brain-mode="read"] .idea-card-actions,
#project[data-brain-mode="read"] .vision-edit-btn,
#project[data-brain-mode="read"] .deploy-panel button,
#project[data-brain-mode="read"] .goal-card-actions,
#project[data-brain-mode="read"] .milestone-actions,
#project[data-brain-mode="read"] [data-add-note] {
  display: none !important;
}
/* Read mode also locks form-style inputs so accidental edits don't accumulate. */
#project[data-brain-mode="read"] input:not([type=button]):not([type=submit]),
#project[data-brain-mode="read"] textarea,
#project[data-brain-mode="read"] select {
  pointer-events: none;
  background: var(--surface-sunk) !important;
  color: var(--text) !important;
  cursor: default;
}
/* A subtle pill in the brain-tabs row so the user always knows the brain is
   read-only — otherwise the missing edit affordances can be confusing. */
#project[data-brain-mode="read"] .brain-tabs::after {
  content: '👁  Read-only — switch to Normal to edit';
  display: inline-block;
  margin-left: auto;
  align-self: center;
  padding: 4px 10px;
  font-size: 11px;
  color: var(--text-faint);
  font-style: italic;
}

/* ========== Per-tab attached document panel (top of every tab) ========== */
.tab-doc-panel {
  /* Sits at the very top of the tab so the Upload button is the first thing the user
     sees. When `.is-filled` is on (a doc is attached), the body grows to dominate the
     viewport — existing structured content stays below, accessible by scroll. */
  margin: 0 0 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.tab-doc-toolbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  background: var(--surface-sunk);
  border-bottom: 1px solid transparent;
  flex-wrap: wrap;
}
.tab-doc-panel.is-open .tab-doc-toolbar { border-bottom-color: var(--border); }
.tab-doc-status {
  font-size: 11.5px;
  color: var(--text-faint);
  margin-left: 4px;
}
.tab-doc-meta {
  font-size: 11.5px;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 38%;
}
.tab-doc-body {
  padding: 14px 16px 18px;
  display: flex;
  flex-direction: column;
}
/* When a doc is attached we let the body expand to take the bulk of the brain area —
   ~60% of the visible tab height — so the document is the focus. The user can resize
   the textarea further if they want; the preview sits below. */
.tab-doc-panel.is-filled .tab-doc-body {
  min-height: calc(70vh - 200px);
}
.tab-doc-textarea {
  width: 100%;
  min-height: 240px;
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 13px;
  line-height: 1.5;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  color: var(--text);
  resize: vertical;
}
.tab-doc-panel.is-filled .tab-doc-textarea {
  /* Expand the textarea by default when a doc is loaded — saves the user from having
     to drag the resize grip every time. */
  min-height: 50vh;
}
.tab-doc-textarea:focus {
  outline: none;
  border-color: var(--primary-tint-strong);
  box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.10);
}
.tab-doc-preview-head {
  margin: 14px 0 6px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.tab-doc-preview {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px 16px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text);
  min-height: 60px;
}
.tab-doc-preview:empty::before {
  content: 'Preview appears here as you type.';
  color: var(--text-faint);
  font-style: italic;
}
.tab-doc-preview h1, .tab-doc-preview h2, .tab-doc-preview h3, .tab-doc-preview h4 {
  margin: 10px 0 6px;
}
.tab-doc-preview h1 { font-size: 17px; }
.tab-doc-preview h2 { font-size: 15px; }
.tab-doc-preview h3 { font-size: 14px; }
.tab-doc-preview pre {
  background: var(--surface);
  padding: 8px 10px;
  border-radius: 4px;
  border: 1px solid var(--border);
  overflow-x: auto;
  font-size: 12.5px;
}
.tab-doc-preview code {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 12.5px;
}

/* ========== SRS tab (one canonical markdown spec per project) ========== */
.srs-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.srs-meta {
  font-size: 12px;
  color: var(--text-faint);
  margin: 4px 0 8px;
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
}
.srs-meta .srs-meta-pill {
  display: inline-flex;
  gap: 4px;
}
.srs-body {
  width: 100%;
  min-height: 360px;
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 13px;
  line-height: 1.5;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  color: var(--text);
  resize: vertical;
}
.srs-body:focus {
  outline: none;
  border-color: var(--primary-tint-strong);
  box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.10);
}
.srs-preview-head {
  margin: 14px 0 6px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.srs-preview {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 18px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text);
  min-height: 80px;
}
.srs-preview:empty::before {
  content: 'Preview appears here as you type.';
  color: var(--text-faint);
  font-style: italic;
}
.srs-preview h1, .srs-preview h2, .srs-preview h3, .srs-preview h4 {
  margin: 12px 0 6px;
}
.srs-preview h1 { font-size: 18px; }
.srs-preview h2 { font-size: 16px; }
.srs-preview h3 { font-size: 14px; }
.srs-preview pre {
  background: var(--surface);
  padding: 8px 10px;
  border-radius: 4px;
  border: 1px solid var(--border);
  overflow-x: auto;
  font-size: 12.5px;
}
.srs-preview code {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 12.5px;
}

/* ========== Brain-note editor modal (Roles, Tech, Workflow, Wireframes) ========== */
.note-editor-hint {
  font-size: 13px;
  color: var(--text-muted);
  margin-bottom: 12px;
  padding: 10px 12px;
  background: var(--surface-sunk);
  border-left: 3px solid var(--primary);
  border-radius: 4px;
  line-height: 1.5;
}
#noteEditorTitleInput,
#noteEditorImageUrl,
#noteEditorBody,
#noteEditorCategory,
#noteEditorVersion {
  width: 100%;
  font: inherit;
  font-size: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  color: var(--text);
}
#noteEditorBody {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 13px;
  line-height: 1.5;
  resize: vertical;
  min-height: 240px;
}
#noteEditorTitleInput:focus,
#noteEditorImageUrl:focus,
#noteEditorBody:focus,
#noteEditorCategory:focus,
#noteEditorVersion:focus {
  outline: none;
  border-color: var(--primary-tint-strong);
  box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.10);
}
.note-editor-tech-row {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 10px;
}
.note-editor-image-preview {
  margin: 0 0 12px;
  padding: 6px;
  background: var(--surface-sunk);
  border: 1px dashed var(--border);
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.note-editor-image-preview img {
  max-width: 100%;
  max-height: 220px;
  border-radius: 4px;
}
.note-editor-preview {
  margin-top: 12px;
  padding: 12px 14px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
  color: var(--text);
  max-height: 220px;
  overflow-y: auto;
}
.note-editor-preview:empty { display: none; }
.note-editor-preview h1,
.note-editor-preview h2,
.note-editor-preview h3 { margin: 6px 0 4px; font-size: 14px; }
.note-editor-preview pre {
  background: var(--surface);
  padding: 8px 10px;
  border-radius: 4px;
  overflow-x: auto;
  font-size: 12.5px;
  border: 1px solid var(--border);
}
.note-editor-preview code {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 12.5px;
}
.note-editor-flash {
  margin: 8px 0;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 12.5px;
  background: #FDECEC;
  color: #A31A1A;
  border: 1px solid #F4B6B6;
}
.note-editor-flash.hidden { display: none; }
.note-editor-upload-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
}
.note-editor-upload-hint {
  font-size: 11.5px;
  color: var(--text-faint);
}

/* Wireframe + workflow card body: render markdown nicely so the card UX matches the
   editor's preview. */
.brain-card-desc, .wireframe-desc {
  white-space: pre-wrap;
  font-size: 13px;
  color: var(--text);
  line-height: 1.5;
}

/* ========== Brain mini-composer ========== */
/* A compact, always-visible prompt input at the bottom of the brain page. The active brain tab
   determines which thread the prompt routes to ("Brain · {Tab}" inside the project's cwd). */
.brain-composer {
  flex-shrink: 0;
  border-top: 1px solid var(--border);
  background: var(--surface);
  padding: 10px 28px 12px;
  z-index: 1;
}
.brain-composer.hidden { display: none; }
.brain-composer-card {
  max-width: 820px;
  margin: 0 auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 8px 10px 10px;
  transition: border-color 120ms, box-shadow 120ms;
}
.brain-composer-card:focus-within {
  border-color: var(--primary-tint-strong);
  box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.10);
}
.brain-composer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 2px 4px 6px;
  font-size: 12px;
  color: var(--text-faint);
}
.brain-composer-target {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.brain-composer-target-label { color: var(--text-faint); }
.brain-composer-tab-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--primary-tint);
  color: var(--primary);
  font-weight: 600;
  font-size: 11.5px;
  letter-spacing: 0.2px;
  border: 1px solid var(--primary-tint-strong);
}
.brain-composer-status {
  font-size: 11.5px;
  color: var(--text-faint);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 60%;
}
.brain-composer-status .open-thread-link {
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
.brain-composer-status .open-thread-link:hover { text-decoration: underline; }
.brain-composer-status.is-success { color: #086A44; }
.brain-composer-status.is-error { color: var(--danger); }
.brain-composer-row {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}
.brain-composer-input {
  flex: 1 1 auto;
  resize: none;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
  padding: 6px 8px;
  min-height: 32px;
  max-height: 140px;
  overflow-y: auto;
}
.brain-composer-input::placeholder { color: var(--text-faint); }

/* Attachment chips — mirror the main composer's chip look but compact. */
.brain-composer-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 4px 0 8px;
}
.brain-composer-attachments.hidden { display: none; }
.brain-composer-attachments .chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px 4px 3px 10px;
  font-size: 11.5px;
  max-width: 220px;
  color: var(--text);
}
.brain-composer-attachments .chip.is-image { padding-left: 3px; }
.brain-composer-attachments .chip img {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  object-fit: cover;
}
.brain-composer-attachments .chip-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 130px;
}
.brain-composer-attachments .chip-size {
  color: var(--text-faint);
  font-size: 10.5px;
}
.brain-composer-attachments .chip-ext-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 18px;
  padding: 0 5px;
  border-radius: 3px;
  background: var(--primary-tint);
  color: var(--primary);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  line-height: 1;
}
.brain-composer-attachments .chip-remove {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
}
.brain-composer-attachments .chip-remove:hover { color: var(--danger); }

/* Drop highlight for the composer card */
.brain-composer-card.is-drop-target {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.18);
}

@media (max-width: 720px) {
  .brain-composer { padding: 8px 14px 10px; }
}
.brain-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}
.brain-panel-head h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}

.vision-view, .vision-edit {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px;
  box-shadow: var(--shadow-sm);
}
.deploy-panel {
  margin-top: 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px 18px;
  box-shadow: var(--shadow-sm);
}
.deploy-panel.hidden { display: none; }
.deploy-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
  gap: 10px;
}
.deploy-panel-title-wrap {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.deploy-panel-head h4 {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}
.deploy-info-btn {
  width: 24px;
  height: 24px;
  padding: 0;
  border-radius: 50%;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-faint);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background-color 120ms, color 120ms, border-color 120ms;
}
.deploy-info-btn:hover,
.deploy-info-btn[aria-expanded="true"] {
  background: var(--primary-tint);
  color: var(--primary);
  border-color: var(--primary-tint-strong);
}

.deploy-info-panel {
  margin: 0 0 14px;
  padding: 14px 16px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: 8px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-muted);
}
.deploy-info-panel.hidden { display: none; }
.deploy-info-panel h5 {
  margin: 14px 0 6px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.deploy-info-panel h5:first-child { margin-top: 0; }
.deploy-info-panel p { margin: 0 0 8px; }
.deploy-info-panel ol,
.deploy-info-panel ul {
  margin: 6px 0 10px;
  padding-left: 22px;
}
.deploy-info-panel li { margin: 3px 0; }
.deploy-info-panel code {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 11.5px;
  color: var(--text);
}
.deploy-info-panel pre {
  background: var(--code-bg);
  color: var(--code-text);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  line-height: 1.5;
  padding: 12px 14px;
  border-radius: 8px;
  overflow-x: auto;
  margin: 8px 0 10px;
}
.deploy-info-panel .deploy-info-footnote {
  margin-top: 14px;
  padding: 8px 10px;
  background: rgba(217, 119, 6, 0.08);
  border: 1px solid rgba(217, 119, 6, 0.25);
  border-radius: 6px;
  font-size: 11.5px;
  color: #92510E;
}
.deploy-status {
  font-size: 12px;
  color: var(--text-faint);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}
.deploy-fields {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.deploy-inline {
  display: flex;
  align-items: center;
  gap: 8px;
}
.deploy-inline input {
  flex: 1;
}
.deploy-suffix {
  color: var(--text-faint);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
}
.deploy-log {
  margin: 14px 0 0;
  max-height: 360px;
  overflow: auto;
  background: var(--code-bg);
  color: var(--code-text);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  line-height: 1.5;
  padding: 12px 14px;
  border-radius: 8px;
  white-space: pre-wrap;
  word-break: break-word;
}
.deploy-log.hidden { display: none; }

.vision-live-url {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 14px;
  background: var(--primary-tint);
  border: 1px solid var(--primary-tint-strong);
  border-radius: 8px;
  font-size: 13px;
}
.vision-live-url a {
  color: var(--primary);
  text-decoration: none;
  font-weight: 500;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}
.vision-live-url a:hover { text-decoration: underline; }
.vision-live-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--primary);
  letter-spacing: 0.4px;
}
.vision-text {
  white-space: pre-wrap;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text);
}
.vision-empty {
  color: var(--text-faint);
  font-style: italic;
  text-align: center;
  padding: 20px;
}
.vision-edit {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.vision-edit.hidden, .vision-view.hidden { display: none; }

.brain-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.brain-empty {
  color: var(--text-faint);
  text-align: center;
  padding: 40px 16px;
  font-style: italic;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
}
.brain-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  box-shadow: var(--shadow-sm);
}
.brain-card.priority-critical { border-left: 4px solid var(--danger); }
.brain-card.priority-normal { border-left: 4px solid var(--primary); }
.brain-card.priority-nice_to_have { border-left: 4px solid var(--border-strong); }
.brain-card.milestone { border-left: 4px solid #0EA5E9; }
.brain-card.status-achieved, .brain-card.status-hit {
  opacity: 0.7;
  background: var(--surface-alt);
}
.brain-card.status-achieved .brain-card-title,
.brain-card.status-hit .brain-card-title {
  text-decoration: line-through;
  color: var(--text-dim);
}
.brain-card-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
  flex-wrap: wrap;
}
.brain-card-title {
  font-weight: 600;
  color: var(--text);
  font-size: 14px;
  flex: 1;
}
.brain-card-chips {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}
.milestone-date {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.1);
  color: #0369A1;
  border: 1px solid rgba(14, 165, 233, 0.25);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}
.brain-card-desc {
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.5;
  white-space: pre-wrap;
}
.brain-card-actions {
  display: flex;
  gap: 6px;
  margin-top: 4px;
  flex-wrap: wrap;
}

/* ========== Brain tabs (overflow scroll for many tabs) ========== */
.brain-tabs { overflow-x: auto; flex-wrap: nowrap; }
.brain-tabs::-webkit-scrollbar { height: 4px; }
.brain-tab { white-space: nowrap; flex-shrink: 0; }

/* ========== Wireframes grid ========== */
.brain-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px;
}
.wireframe-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-sm);
  transition: border-color 120ms, transform 120ms;
}
.wireframe-card:hover { border-color: var(--primary-tint-strong); transform: translateY(-1px); }
.wireframe-image-wrap {
  display: block;
  background: var(--surface-sunk);
  text-decoration: none;
  color: inherit;
  border-bottom: 1px solid var(--border);
  height: 160px;
  overflow: hidden;
  position: relative;
}
.wireframe-image-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.wireframe-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
  font-size: 12px;
  font-style: italic;
}
.wireframe-head {
  padding: 10px 12px 4px;
}
.wireframe-title {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--text);
}
.wireframe-desc {
  margin-top: 4px;
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.wireframe-actions {
  display: flex;
  gap: 6px;
  padding: 6px 12px 10px;
}

/* ========== Staging tab ========== */
.staging-hint {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.55;
  margin: 0 0 14px;
  padding: 10px 12px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.staging-hint code {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 11.5px;
}
.staging-card { border-left: 4px solid #0EA5E9; }
.staging-fqdn {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--primary-tint);
  color: var(--primary);
  border: 1px solid var(--primary-tint-strong);
  text-decoration: none;
}
.staging-fqdn:hover { background: var(--primary); color: #fff; }

/* ========== Files tab ========== */
.brain-tab-files { padding: 0 !important; }
.files-layout {
  display: grid;
  grid-template-columns: 280px 1fr;
  height: 100%;
  min-height: 0;
}
.files-tree-pane {
  border-right: 1px solid var(--border);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
.files-tree-head {
  padding: 8px 10px;
  border-bottom: 1px solid var(--divider);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  flex-shrink: 0;
}
.files-tree-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--text-faint);
  font-weight: 600;
}
.files-tree-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.files-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--text-faint);
  cursor: pointer;
}
.files-toggle input { transform: translateY(1px); accent-color: var(--primary); }

.files-tree {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  padding: 4px 0 12px;
  font-size: 12.5px;
}
.tree-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.tree-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px 3px 0;
  cursor: pointer;
  white-space: nowrap;
  border-radius: 4px;
  margin: 0 4px;
  color: var(--text);
}
.tree-row:hover { background: var(--surface-sunk); }
.tree-row.active { background: var(--primary-tint); color: var(--primary); }
.tree-chevron {
  display: inline-block;
  width: 14px;
  text-align: center;
  font-size: 9px;
  color: var(--text-faint);
  transition: transform 120ms;
}
.tree-chevron.open { transform: rotate(90deg); }
.tree-icon { font-size: 12px; }
.tree-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tree-size {
  font-size: 10.5px;
  color: var(--text-faint);
  margin-left: 8px;
}
.tree-loading, .tree-empty {
  padding: 4px 12px 4px 28px;
  font-size: 11.5px;
  color: var(--text-faint);
  font-style: italic;
}

.files-editor-pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--bg);
}
.files-editor-head {
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--surface);
  flex-shrink: 0;
}
.files-editor-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.files-editor-path {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 60ch;
}
.files-editor-dirty {
  color: var(--warning);
  font-size: 14px;
}
.files-editor-actions {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.files-editor-meta {
  font-size: 11px;
  color: var(--text-faint);
}

.files-editor-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
}
.files-editor-empty {
  margin: auto;
  padding: 32px;
  color: var(--text-faint);
  text-align: center;
  max-width: 520px;
  font-size: 13px;
}
.files-editor-empty kbd {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 6px;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
}
.files-editor-textarea {
  flex: 1 1 auto;
  width: 100%;
  height: 100%;
  resize: none;
  border: none;
  background: var(--code-bg);
  color: var(--code-text);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  line-height: 1.55;
  padding: 14px 16px;
  outline: none;
  tab-size: 2;
  -moz-tab-size: 2;
  white-space: pre;
  overflow: auto;
}

/* Monaco editor host inside the Files-tab full-page editor. */
.files-editor-monaco {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  height: 100%;
  position: relative;
  background: var(--surface);
}
.files-editor-monaco .monaco-editor { background: transparent !important; }

/* Goal/Milestone status chip variants */
.idea-status-chip.status-chip-goal-active {
  background: var(--primary-tint); color: var(--primary); border-color: var(--primary-tint-strong);
}
.idea-status-chip.status-chip-goal-paused {
  background: rgba(217, 119, 6, 0.1); color: #B45309; border-color: rgba(217, 119, 6, 0.25);
}
.idea-status-chip.status-chip-goal-achieved {
  background: #E7F8EF; color: #086A44; border-color: #A7E3C3;
}
.idea-status-chip.status-chip-mst-upcoming {
  background: var(--surface-sunk); color: var(--text-muted); border-color: var(--border);
}
.idea-status-chip.status-chip-mst-in_progress {
  background: var(--primary-tint); color: var(--primary); border-color: var(--primary-tint-strong);
}
.idea-status-chip.status-chip-mst-hit {
  background: #E7F8EF; color: #086A44; border-color: #A7E3C3;
}
.idea-status-chip.status-chip-mst-missed {
  background: var(--danger-tint); color: var(--danger); border-color: rgba(220, 38, 38, 0.25);
}

/* ========== Admin pending-row editable controls ========== */
.admin-row-pending {
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}
.admin-pending-edit {
  width: 100%;
  font: inherit;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  line-height: 1.55;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  resize: vertical;
  min-height: 80px;
}
.admin-pending-edit:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}
.admin-pending-comment {
  width: 100%;
  font: inherit;
  font-size: 12.5px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
}
.admin-pending-comment:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}
.admin-pending-actions {
  justify-content: flex-end;
}

/* ========== Originator badge on the message role line ========== */
.originator-badge {
  font-size: 10.5px;
  letter-spacing: 0.2px;
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-weight: 500;
  text-transform: none;
}
.originator-badge.originator-self {
  background: var(--primary-tint);
  color: var(--primary);
  border-color: var(--primary-tint-strong);
}
.originator-badge.originator-other {
  background: rgba(168, 85, 247, 0.12);
  color: #7E22CE;
  border-color: rgba(168, 85, 247, 0.28);
}

/* Per-message timestamp on the role line. Same compact "HH:MM" or
   "DD Mon · HH:MM" treatment as the rest of the platform. Pushed
   to the right so the originator + status badges stay left-aligned. */
.msg .role .msg-time {
  margin-left: auto;
  font-size: 10.5px;
  letter-spacing: 0.2px;
  color: var(--text-faint);
  font-weight: 400;
  text-transform: none;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.msg .role .msg-time:hover { color: var(--text-muted); }

/* User-prompt bubbles authored by a different developer get a distinct purple bubble
   so it's instantly clear which interactions came from whom in a shared project. */
.msg-other-dev.user .bubble {
  background: linear-gradient(135deg, #7E22CE 0%, #9333EA 100%);
}
.msg-other-dev.user .bubble .diff-word-added {
  background: rgba(255, 255, 255, 0.92);
  color: #581C87;
}

/* Assistant replies that were prompted by another developer get a soft purple left-stripe
   on the bubble — keeps the markdown readable but tags the ownership. */
.msg-other-dev.assistant .bubble {
  border-left: 3px solid #9333EA;
  padding-left: 17px;
}

/* ========== Project access management (admin-only) ==========
   Sits at the top of the Team brain sub-tab. Admin grants / revokes
   per-project access + picks which brain sub-tabs each member can see.
   Inline editor pattern — no popup dialogues, per design rule. */
.team-access-section {
  margin: 0 0 22px;
  padding: 14px 16px 16px;
  background: var(--surface-sunk);
  border: 1px solid var(--divider);
  border-radius: var(--radius-md);
}
.team-access-add {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-md);
  margin-bottom: 14px;
}
.team-access-add-label {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  font-weight: 600;
}
.team-access-add-row {
  display: flex;
  gap: 8px;
  align-items: center;
}
.team-access-select {
  flex: 1;
  padding: 7px 10px;
  font-size: 13.5px;
  font-family: inherit;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--divider);
  border-radius: var(--radius-md);
}
.team-access-select:focus {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
  border-color: transparent;
}
.team-access-tabs-picker {
  border: 1px dashed var(--divider);
  border-radius: var(--radius-md);
  padding: 8px 12px 10px;
  margin: 0;
}
.team-access-tabs-picker legend {
  padding: 0 6px;
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 600;
}
.team-access-hint {
  font-weight: 400;
  color: var(--text-faint);
}
.team-access-tabs-list {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-top: 4px;
}
.team-access-tab-check {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12.5px;
  color: var(--text);
  cursor: pointer;
  user-select: none;
}
.team-access-tab-check input[type=checkbox] {
  margin: 0;
  accent-color: var(--primary);
}
.team-access-flash {
  font-size: 12.5px;
  min-height: 16px;
}
.team-access-flash.is-error { color: var(--danger); }
.team-access-flash.is-success { color: var(--brand-teal, #0078BF); }

/* ── Current-access list ─────────────────────────────────────── */
.team-access-current-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 6px 0 6px;
}
.team-access-count {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-faint);
}
.team-access-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.team-access-row {
  display: grid;
  grid-template-columns: minmax(160px, 1.5fr) minmax(120px, 2fr) auto;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-md);
}
.team-access-row-name {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  word-break: break-word;
}
.team-access-row-sub {
  font-size: 11.5px;
  color: var(--text-muted);
  word-break: break-word;
}
.team-access-row-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.team-access-chip {
  display: inline-block;
  padding: 2px 8px;
  font-size: 11.5px;
  background: var(--surface-sunk);
  color: var(--text);
  border-radius: 999px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.team-access-chip-all {
  background: rgba(0, 120, 191, 0.12);
  color: var(--brand-teal, #0078BF);
  font-family: inherit;
  font-weight: 600;
}
.team-access-row-actions {
  display: flex;
  gap: 6px;
  justify-self: end;
}
.team-access-remove {
  color: var(--danger, #B42318);
}
.team-access-edit-inline {
  margin: 4px 0 8px;
  padding: 10px 12px;
  background: rgba(0, 120, 191, 0.06);
  border: 1px dashed rgba(0, 120, 191, 0.4);
  border-radius: var(--radius-md);
}
.team-access-edit-head {
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.team-access-edit-actions {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
  margin-top: 8px;
}

@media (max-width: 640px) {
  .team-access-row {
    grid-template-columns: 1fr;
  }
  .team-access-row-actions {
    justify-self: start;
  }
}

/* ========== Team summary cards ========== */
.team-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.team-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid #7E22CE;
  border-radius: 10px;
  padding: 14px 16px;
  box-shadow: var(--shadow-sm);
}
.team-card.team-auto-approve { border-left-color: #16A34A; }
.team-card-head {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto auto auto;
  grid-template-areas: "name id" "sub sub" "chips chips";
  gap: 4px 12px;
  margin-bottom: 10px;
}
.team-card-name { grid-area: name; font-size: 15px; font-weight: 600; color: var(--text); }
.team-card-userid {
  grid-area: id;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  color: var(--text-faint);
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  padding: 1px 8px;
  border-radius: 999px;
  align-self: start;
}
.team-card-sub { grid-area: sub; font-size: 12px; color: var(--text-faint); }
.team-card-chips { grid-area: chips; display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }

.team-card-threads {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}
.team-thread-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px 4px 8px;
  border-radius: 999px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 12px;
  cursor: pointer;
  transition: background-color 120ms, border-color 120ms;
}
.team-thread-chip:hover {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
  color: var(--primary);
}
.team-thread-chip.team-thread-active { border-color: rgba(22, 163, 74, 0.45); }
.team-thread-title {
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.team-thread-count {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-faint);
  background: var(--surface-sunk);
  border-radius: 999px;
  padding: 1px 7px;
}

/* ========== Activity feed ========== */
.activity-card { cursor: pointer; }
.activity-card:hover { border-color: var(--primary-tint-strong); }
.activity-card.activity-user { border-left: 3px solid var(--primary); }
.activity-card.activity-assistant { border-left: 3px solid #0EA5E9; }
.activity-role {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  padding: 1px 7px;
  border-radius: 999px;
}
.activity-role-user { background: var(--primary-tint); color: var(--primary); }
.activity-role-assistant { background: rgba(14, 165, 233, 0.12); color: #0369A1; }
.activity-thread {
  color: var(--text-muted);
  font-size: 12.5px;
}
.activity-content {
  white-space: pre-wrap;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  line-height: 1.5;
  background: var(--surface-alt);
  padding: 8px 10px;
  border-radius: 6px;
  margin-top: 6px;
  max-height: 150px;
  overflow: auto;
}

/* ========== Always-visible admin edit teach-view inside the user bubble ========== */
/* Bubble is teal with white text — diff colors must pop on that background. */
.user-text.inline-diff {
  white-space: pre-wrap;
  line-height: 1.6;
}
.diff-word-context { color: #fff; }
.diff-word-added {
  background: rgba(255, 255, 255, 0.92);
  color: #084E51;
  padding: 1px 3px;
  border-radius: 3px;
  font-weight: 600;
}
.diff-word-removed {
  background: rgba(220, 38, 38, 0.85);
  color: #fff;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  padding: 1px 3px;
  border-radius: 3px;
  opacity: 0.85;
}
.admin-edit-inline-note {
  margin-top: 10px;
  padding: 9px 12px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.95);
  color: #084E51;
  border: 1px solid rgba(255, 255, 255, 0.7);
  font-size: 13px;
  line-height: 1.5;
  font-weight: 500;
}
.admin-edit-inline-caption {
  margin-top: 8px;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: rgba(255, 255, 255, 0.75);
  font-weight: 600;
}

.admin-edit-comment {
  background: var(--primary-tint);
  border: 1px solid var(--primary-tint-strong);
  color: var(--primary);
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 13px;
  margin-bottom: 12px;
  line-height: 1.5;
}
.admin-edit-comment.hidden { display: none; }
.admin-edit-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.admin-edit-col-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-faint);
  font-weight: 600;
  margin-bottom: 6px;
}
.admin-edit-pre {
  background: var(--code-bg);
  color: var(--code-text);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  line-height: 1.55;
  padding: 12px 14px;
  border-radius: 8px;
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
  max-height: 320px;
  overflow: auto;
}
.admin-edit-pre.approved {
  border: 1px solid #0B9E60;
  box-shadow: 0 0 0 1px rgba(11, 158, 96, 0.15);
}

/* ========== App toast (floating bottom-center) ========== */
#appToastHost {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translateX(-50%);
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
.app-toast {
  pointer-events: auto;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 10px 18px;
  font-size: 13px;
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 200ms ease, transform 200ms ease;
  max-width: 600px;
}
.app-toast-in { opacity: 1; transform: translateY(0); }
.app-toast-out { opacity: 0; transform: translateY(-8px); }
.app-toast-info { background: var(--surface); }
.app-toast-celebrate {
  background: linear-gradient(135deg, var(--primary) 0%, #14B8A6 100%);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 8px 24px rgba(13, 115, 119, 0.35);
}

/* ========== Admin hint paragraph ========== */
.admin-hint {
  font-size: 12px;
  color: var(--text-muted);
  margin: 0 0 10px;
  line-height: 1.5;
}

/* ========== Admin (invitations + users) modal ========== */
.admin-body {
  gap: 18px;
  display: flex;
  flex-direction: column;
}
.admin-section {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  background: var(--surface);
}
.admin-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 10px;
}
.admin-section-head h4 {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--text);
}
.admin-count {
  font-size: 11.5px;
  color: var(--text-faint);
}
.admin-invite-form {
  display: grid;
  grid-template-columns: 1fr 160px auto;
  gap: 8px;
  align-items: center;
}
.admin-invite-form input,
.admin-invite-form select {
  font: inherit;
  font-size: 13.5px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  height: 38px;
}
.admin-invite-form input:focus,
.admin-invite-form select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}
/* ── Invite modal: organisation picker (shown only when role=organisation) ──
   Sits directly beneath .admin-invite-form. Reuses the parent's border/radius/
   focus tokens so the visual weight matches the invite row above it. */
.admin-invite-org-row {
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: 8px 10px;
  align-items: center;
  margin-top: 10px;
}
.admin-invite-org-label {
  font-size: 12.5px;
  color: var(--text-dim, #555);
  font-weight: 600;
}
.admin-invite-org-select {
  font: inherit;
  font-size: 13.5px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  height: 38px;
}
.admin-invite-org-select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}
.admin-invite-org-hint {
  grid-column: 2;
  font-size: 11.5px;
  color: var(--text-faint, #9aa0aa);
  margin-top: -2px;
}
.admin-invite-org-create {
  grid-column: 2;
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 6px;
  margin-top: 4px;
  padding: 10px;
  background: var(--surface, #fafafa);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.admin-invite-org-create input {
  font: inherit;
  font-size: 13.5px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg, #fff);
  color: var(--text);
  height: 34px;
}
.admin-invite-org-create input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}
.admin-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 280px;
  overflow-y: auto;
}
.admin-empty {
  padding: 14px;
  text-align: center;
  color: var(--text-faint);
  font-style: italic;
  font-size: 12.5px;
}

/* ========== Admin → Assignments panel ========== */
.admin-assign-projects { gap: 10px; }
.assign-project-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.assign-project-top {
  display: flex;
  align-items: center;
  gap: 10px;
}
.assign-project-label { flex: 1 1 auto; font-size: 13px; color: var(--text); }
.assign-cwd-mono {
  font-family: ui-monospace, SFMono-Regular, monospace;
  color: var(--text-faint);
  font-size: 11.5px;
  margin-left: 8px;
}
.assign-tabs-box {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px;
  background: var(--surface-sunk);
  border-radius: 8px;
  font-size: 12px;
  transition: opacity 120ms;
}
.assign-tabs-box.is-disabled { opacity: 0.45; pointer-events: none; }
.assign-tab-all {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
}
.assign-tab-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 4px 10px;
}
.assign-tab-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  color: var(--text-muted);
}
.assign-tab-chip input:disabled + span { color: var(--text-faint); }
.assign-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
}
.assign-status {
  font-size: 12px;
  color: var(--text-muted);
  min-width: 80px;
  text-align: right;
}
.admin-assign-threads-details {
  margin-top: 10px;
  padding: 8px 10px;
  background: var(--surface-sunk);
  border-radius: 8px;
}
.admin-assign-threads-details summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 13px;
  color: var(--text);
  padding: 4px 0;
}
.admin-assign-threads-details .admin-hint-inline {
  color: var(--text-faint);
  font-weight: 400;
  font-size: 12px;
  margin-left: 6px;
}
.admin-assign-threads { gap: 4px; margin-top: 6px; }
.assign-thread-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 7px;
  font-size: 12.5px;
}
.assign-thread-label { flex: 1 1 auto; }
.assign-thread-folder {
  color: var(--text-faint);
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 11px;
  margin-left: 8px;
}
.admin-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.admin-row-disabled { opacity: 0.55; }
.admin-row-main {
  flex: 1;
  min-width: 0;
}
.admin-row-title {
  font-size: 13px;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-row-sub {
  font-size: 11.5px;
  color: var(--text-faint);
  margin-top: 2px;
}
.admin-role-chip {
  font-size: 10.5px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}
.admin-role-chip.role-admin { background: var(--primary-tint); color: var(--primary); border: 1px solid var(--primary-tint-strong); }
.admin-role-chip.role-developer { background: var(--surface-sunk); color: var(--text-muted); border: 1px solid var(--border); }
.admin-role-chip.role-disabled { background: var(--danger-tint); color: var(--danger); border: 1px solid rgba(220,38,38,.25); }
.admin-row-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.admin-role-select {
  font: inherit;
  font-size: 12px;
  padding: 5px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
}

/* ========== Inbox (quick idea capture) modal ========== */
.inbox-subtitle {
  color: var(--text-faint);
  font-weight: 400;
  font-size: 13px;
  margin-left: 4px;
}
.inbox-hint {
  margin: 0 0 10px;
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.5;
}
.inbox-hint code {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 11.5px;
  color: var(--primary);
}
.inbox-projects {
  color: var(--text-faint);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
}
#inboxInput {
  width: 100%;
  font: inherit;
  font-size: 13.5px;
  line-height: 1.55;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  resize: vertical;
  min-height: 90px;
  tab-size: 2;
}
#inboxInput:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}
.inbox-options {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 10px;
  margin: 12px 0 4px;
}
.inbox-fallback-wrap.hidden { display: none; }
.inbox-flash {
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 12.5px;
  margin: 8px 0 0;
}
.inbox-flash.hidden { display: none; }
.inbox-flash.ok {
  background: #E7F8EF;
  border: 1px solid #A7E3C3;
  color: #086A44;
}
.inbox-flash.err {
  background: var(--danger-tint);
  border: 1px solid rgba(220, 38, 38, 0.25);
  color: var(--danger);
}
.inbox-recent-wrap {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--divider);
}
.inbox-recent-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-faint);
  font-weight: 600;
  margin-bottom: 8px;
}
.inbox-recent {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 160px;
  overflow-y: auto;
}
.inbox-recent li {
  font-size: 12px;
  color: var(--text-muted);
  padding: 4px 8px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 6px;
  display: flex;
  gap: 8px;
  align-items: center;
}
.inbox-recent .project-tag {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--primary-tint);
  color: var(--primary);
  border: 1px solid var(--primary-tint-strong);
  flex-shrink: 0;
}
.inbox-recent .preview {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}

/* ========== Global memory modal ========== */
.modal-lg { max-width: 760px; width: 100%; }
.global-memory-hint {
  margin: 0 0 10px;
  color: var(--text-muted);
  font-size: 12.5px;
  line-height: 1.5;
}
.global-memory-hint code {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  padding: 1px 6px;
  border-radius: 4px;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
}
#globalMemoryInput {
  font: inherit;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  line-height: 1.55;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  resize: vertical;
  min-height: 260px;
  width: 100%;
  tab-size: 2;
  -moz-tab-size: 2;
}
#globalMemoryInput:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}
.global-memory-meta {
  font-size: 11px;
  color: var(--text-faint);
  margin: -2px 0 2px;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}
.global-memory-org-picker {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-sunk);
}
.global-memory-org-picker label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}
.global-memory-org-picker select {
  flex: 1;
  font: inherit;
  font-size: 13px;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
}

/* ========== Brand-theme modal (Flavour B surface #2, 20 Jul 2026) ========== */
/*
 * Colour + logo + display-name picker. Reuses `.field` + `.modal-*`
 * base classes and adds a small grid + preview swatch. The CSS variables
 * --org-primary / --org-primary-fg are set at runtime by
 * applyOrgThemeCssVars() in app.js — the fallbacks below match imagine's
 * default deep-teal palette so an unbranded org looks unchanged.
 */
:root {
  --org-primary: var(--primary, #0078BF);
  --org-primary-fg: #ffffff;
}
.brand-theme-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  margin: 8px 0 12px;
}
@media (min-width: 640px) {
  .brand-theme-grid { grid-template-columns: 1fr 1fr; }
  .brand-theme-grid > .field:first-child { grid-column: 1 / -1; }
}
.brand-theme-colour-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.brand-theme-colour-row input[type='color'] {
  width: 42px; height: 34px; padding: 2px;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); cursor: pointer;
  flex: 0 0 auto;
}
.brand-theme-colour-row input[type='text'] {
  flex: 1;
  font: inherit;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  min-width: 0;
}
.brand-theme-hint {
  display: block;
  margin-top: 4px;
  font-size: 11.5px;
  color: var(--text-faint);
}
.brand-theme-hint code {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  padding: 0 4px;
  border-radius: 3px;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
}
.brand-theme-preview {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border: 1px dashed var(--border);
  border-radius: 8px;
  background: var(--surface-sunk);
  margin: 4px 0 8px;
}
.brand-theme-swatch {
  display: inline-flex;
  align-items: center; justify-content: center;
  min-width: 88px; height: 34px;
  padding: 0 14px;
  border-radius: 6px;
  background: var(--org-primary);
  color: var(--org-primary-fg);
  font-weight: 600;
  font-size: 12.5px;
  letter-spacing: 0.3px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.08);
}
.brand-theme-logo-preview {
  width: 40px; height: 40px;
  border-radius: 6px;
  background: var(--surface) center/contain no-repeat;
  border: 1px solid var(--border);
}
.brand-theme-name-preview {
  font-size: 13.5px;
  color: var(--text);
  font-weight: 500;
  flex: 1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ========== Message-footer extra button (View changes) ========== */
.msg-footer-btn {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2px;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  margin-left: auto;
  cursor: pointer;
  transition: background-color 120ms, color 120ms, border-color 120ms;
}
.msg-footer-btn:hover {
  background: var(--primary-tint);
  color: var(--primary);
  border-color: var(--primary-tint-strong);
}

/* ========== Diff modal ========== */
.modal-xl { max-width: 1200px; width: 100%; max-height: 92vh; }
.diff-modal-body {
  display: grid;
  grid-template-columns: 280px 1fr;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
.diff-file-list {
  border-right: 1px solid var(--border);
  background: var(--surface-alt);
  overflow-y: auto;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.diff-loading {
  padding: 16px;
  font-size: 12.5px;
  color: var(--text-faint);
  text-align: center;
}
.diff-file-item {
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: left;
  padding: 8px 10px;
  border-radius: 6px;
  border: 1px solid transparent;
  background: transparent;
  cursor: pointer;
  font-size: 12.5px;
  color: var(--text);
}
.diff-file-item:hover { background: var(--surface-sunk); }
.diff-file-item.active {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
  color: var(--primary);
}
.diff-file-path {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}
.diff-kind {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 700;
  flex-shrink: 0;
}
.diff-kind-new { background: #E7F8EF; color: #0B9E60; }
.diff-kind-deleted { background: var(--danger-tint); color: var(--danger); }
.diff-kind-modified { background: var(--primary-tint); color: var(--primary); }

.diff-panes {
  min-width: 0;
  min-height: 0;
  overflow: auto;
  background: var(--bg);
}
.diff-empty {
  padding: 32px;
  color: var(--text-faint);
  text-align: center;
  font-size: 13px;
}
.diff-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--border);
  min-height: 100%;
}
.diff-col {
  background: var(--surface);
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;             /* clip; horizontal scroll lives on .diff-col-body */
}
.diff-col-title {
  padding: 8px 12px;
  background: var(--surface-alt);
  border-bottom: 1px solid var(--border);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  position: sticky;
  top: 0;
  z-index: 1;
}
.diff-col-body {
  padding: 0;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  line-height: 1.55;
  overflow-x: auto;             /* ONE horizontal scrollbar at the bottom of the column */
  overflow-y: visible;          /* vertical scroll stays on .diff-panes */
  flex: 1 1 auto;
  min-width: 0;
}
.diff-line {
  display: flex;
  padding: 0;
  border-left: 3px solid transparent;
  min-width: max-content;       /* each line is at least as wide as its content — drives the scroll */
}
.diff-line-add {
  background: rgba(11, 158, 96, 0.10);
  border-left-color: #0B9E60;
}
.diff-line-rem {
  background: rgba(220, 38, 38, 0.08);
  border-left-color: var(--danger);
}
.diff-line-pad {
  background: var(--surface-sunk);
  opacity: 0.4;
}
.diff-line-ctx { border-left-color: transparent; }
.diff-num {
  display: inline-block;
  width: 44px;
  padding: 0 8px;
  text-align: right;
  color: var(--text-faint);
  user-select: none;
  flex-shrink: 0;
}
.diff-text {
  flex: 1 0 auto;               /* grow but don't shrink; natural width drives the column's scroll width */
  padding: 0 8px;
  white-space: pre;
  overflow: visible;            /* drop the ugly per-line scrollbar — scroll happens on .diff-col-body */
}

/* ========== Right-side folder panel ========== */
#folderPanel {
  background: var(--surface);
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  height: 100%;
  min-height: 0;
}

/* ── Collapsible right-sidebar toggle (boundary-following pill)
   ─────────────────────────────────────────────────────────────────────────────
   The button lives OUTSIDE the panel so it can remain visible when the panel
   is collapsed. Anchored to the CURRENT position of the chat ↔ folder-panel
   boundary — the visual right edge of the chat area. When the panel is open
   the boundary sits `--folder-panel-w` px from the viewport right; when the
   panel is collapsed the boundary IS the viewport right edge. The toggle
   follows the boundary in both states.

   Anchor stability contract (27 Jul 2026 · Ashfak · v5 · boundary-follow)
   ══════════════════════════════════════════════════════════════════════

   Iteration history:
     v1 — flipped `right` between `var(--folder-panel-w)` (open) and `0`
          (collapsed) → 260px jump on click (posture also flipped).
     v2 — flipped between `calc(var(--folder-panel-w) - 14px)` and `8px`
          → 238px jump on click (posture also flipped).
     v3 — single anchor `right: 0` (tab-pull posture, viewport-edge). No
          jump, but the button was flush against the viewport right edge
          in EVERY state — so when the panel was OPEN, the button sat
          INSIDE the folder panel instead of on the divider.
     v4 — single anchor `right: calc(var(--folder-panel-w) - 14px)`
          (floating pill, divider-anchor). No jump, straddled the divider
          when open — but when the panel COLLAPSED, the button stayed at
          its old x-coordinate (246px inside the now-expanded chat), no
          longer attached to any visible boundary.
     v5 (this rule) — boundary-following. Two anchors, matched to the
          two boundary positions:
            • OPEN     → `right: calc(var(--folder-panel-w) - 14px)`
                         floating pill · straddles divider 50/50
            • COLLAPSED → `right: 0`
                         tab-pull posture · flush against the (now)
                         viewport-edge boundary
          The button MOVES on toggle — that's the goal. It always stays
          attached to whatever the current chat-area right edge is.

   Why v5 accepts a "jump" that v3 / v4 avoided:
     The v3/v4 no-jump requirement traded correctness for stability:
     an immobile button whose position was authoritative in EXACTLY ONE
     state (open for v4, closed for v3) and fictional in the other.
     The v5 explicit-move contract restores correctness — the button's
     job is to mark the current boundary, so it MUST reposition when
     the boundary moves. UX-wise the transition is smooth (240ms cubic
     bezier, matches the `body` grid-template-columns transition on
     line 163) so the button visually slides with the collapsing panel
     rather than teleporting.

   Boundary geometry (28px-wide button):
     • OPEN state — divider at `viewport.width - --folder-panel-w`.
       Button center at divider · spans 14px into chat + 14px into panel.
       Symmetric floating-pill posture (full border, 14px symmetric
       radius, soft omni-shadow).
     • COLLAPSED state — boundary at viewport right edge.
       Button flush against edge · right-edge flush with viewport-right.
       Tab-pull posture (no right border, `14px 0 0 14px` asymmetric
       radius, leftward-only shadow so it visually reads as "attached
       to the right edge, pulling toward the chat").
     • Viewport resize crossing 1200px breakpoint — `--folder-panel-w`
       shifts 260→220px; button follows the (now shifted) divider when
       open, still flush at right:0 when collapsed.
     • Tablet/mobile ≤980px — body becomes single-column, folder panel
       becomes a fixed overlay, no grid divider exists → `right: 0` in
       both states (see media block below).

   Positioning parent: `position: fixed` (viewport-anchored) rather than
   parented to `#folderPanel`. Why: the panel has `overflow: hidden`
   which would clip an absolute-positioned button, and in the collapsed
   state the panel's grid track is 0px wide so `left: -14px` inside the
   panel would still get clipped. Fixed + `--folder-panel-w`-based `right`
   gives boundary-tracking without the clip pitfalls.

   Vertical anchor — `top: 96px`. INVARIANT across open / closed / hover
   / focus / active / navigator-open / navigator-closed / resize. Only
   `right` + the visual posture (border/radius/shadow) switch on collapse.

   Interlock with the Conversation Navigator (`.chat-nav-fab`): the two
   live on independent anchors (the folder toggle follows the folder
   divider; the nav handle sits at chat's middle-right at `right:24px`
   inside `#chat`). Opening / closing the nav does NOT move the folder
   toggle — different positioning contexts (fixed vs absolute-in-#chat),
   no CSS-cascade coupling, no JS-driven reflow of the toggle. */
.folder-panel-toggle {
  position: fixed;
  top: 96px;
  /* OPEN-state anchor — boundary is at `viewport - --folder-panel-w`.
     Button's right edge sits at `--folder-panel-w - 14px` from viewport
     right, so its center coincides with the divider (14px straddles
     onto the chat side, 14px onto the folder-panel side). The
     `body.folder-panel-collapsed .folder-panel-toggle { right: 0 }`
     override (below) flips this to viewport-edge anchoring when the
     panel is collapsed. */
  right: calc(var(--folder-panel-w) - 14px);
  /* z-index bumped from 12 → 45 so sticky page headers (~20–30), dropdown
     scrims (~40), and provider menus don't silently swallow the click.
     Still safely below intentional modal overlays (100+) and the app-toast
     host (200+), so those keep taking precedence when they're active. */
  z-index: 45;
  width: 28px;
  height: 76px;
  padding: 0;
  /* Border-box so a hover-time border tweak (should we ever add one) or
     a browser default-padding change can't shift the visible box size.
     Fixed 28×76 rect stays 28×76 rect under all pseudo-class states. */
  box-sizing: border-box;
  /* No margin / left / transform — those would either offset the button
     off the boundary (margin/left) or introduce sub-pixel drift on
     re-composite (transform). Only {top, right} pair anchors the button. */
  margin: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface, #FFFFFF);
  color: var(--text-faint, #64748B);
  /* OPEN-state chrome — full symmetric border, symmetric radius, soft
     omni-shadow. Pill floats over the divider with content on both sides.
     Collapsed-state override below flips to tab-pull posture. */
  border: 1px solid var(--border, #E2E8F0);
  border-radius: 14px;
  cursor: pointer;
  /* Guarantee the button stays clickable even if an ancestor rule
     (theme wrapper, drag-scrim, etc.) tries to disable pointer events. */
  pointer-events: auto;
  box-shadow: 0 1px 4px rgba(15, 23, 42, 0.08), 0 2px 8px rgba(15, 23, 42, 0.05);
  /* `right` IS transitioned — the whole point of v5 is to slide with the
     collapsing / expanding grid track. Match the 240ms cubic-bezier used
     on `body { transition: grid-template-columns … }` (line 163) so the
     button visually moves in lockstep with the panel, not before or after.
     Border / radius / shadow also transition so the posture morph reads
     as smooth rather than a snap. */
  transition:
    right 240ms cubic-bezier(0.4, 0, 0.2, 1),
    border-radius 240ms cubic-bezier(0.4, 0, 0.2, 1),
    border-right-width 240ms cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow 120ms,
    background-color 120ms,
    color 120ms;
}
/* COLLAPSED-state override — boundary has moved to the viewport right
   edge, so the button follows it. Anchors flush at `right: 0`, adopts
   tab-pull posture (no right border, asymmetric radius, leftward-only
   shadow) so it visually reads as attached to the right edge rather
   than floating over content. */
body.folder-panel-collapsed .folder-panel-toggle {
  right: 0;
  border-right: none;
  border-radius: 14px 0 0 14px;
  box-shadow: -2px 0 6px rgba(15, 23, 42, 0.06);
}
/* Invisible hit-area extension: makes the clickable rectangle ~10px
   taller and ~6px wider on BOTH sides in the OPEN state (pill floats
   with content on both sides). Collapsed-state override below drops
   the right-side extension so the hit area doesn't extend past the
   viewport edge. */
.folder-panel-toggle::before {
  content: '';
  position: absolute;
  top: -10px;
  bottom: -10px;
  left: -6px;
  right: -6px;
  /* Transparent — hit-testing catches it, but visually nothing renders. */
  background: transparent;
}
body.folder-panel-collapsed .folder-panel-toggle::before {
  /* Right edge flush with viewport, so no rightward hit-area extension. */
  right: 0;
}
.folder-panel-toggle:hover {
  color: var(--accent, #0078BF);
  background: var(--surface-sunk, #F1F5F9);
}
.folder-panel-toggle:focus-visible {
  outline: 2px solid var(--accent, #0078BF);
  outline-offset: 2px;
}
.folder-panel-toggle-chevron {
  display: inline-block;
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
  transition: transform 240ms cubic-bezier(0.4, 0, 0.2, 1);
  /* Points left when panel is open (invitation to collapse toward the right edge). */
  transform: rotate(0deg);
}
body.folder-panel-collapsed .folder-panel-toggle-chevron {
  /* Points right when panel is collapsed (invitation to expand back out). */
  transform: rotate(180deg);
}
/* Overlay backdrop (only rendered on tablet/mobile when the user opens the
   collapsed panel over the chat). Click closes the panel. */
.folder-panel-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.45);
  z-index: 10;
}
html.theme-dark .folder-panel-toggle { background: #0B1626; color: #94A3B8; border-color: #1E2E45; }
html.theme-dark .folder-panel-toggle:hover { background: #0F1E33; color: #F1F5F9; }
html.theme-dark .folder-panel-backdrop { background: rgba(0, 0, 0, 0.60); }
.folder-panel-head {
  padding: 14px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  border-bottom: 1px solid var(--divider);
  flex-shrink: 0;
}
.folder-panel-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: 0.1px;
}
.folder-panel-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 6px 8px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.folder-panel-item {
  display: flex;
  align-items: center;
  /* Trimmed from 8px→6px + horizontal padding 10px→8px so the
     path row (`.folder-panel-item-sub`) reclaims a few extra pixels
     for the actual folder-path text before ellipsis has to kick in. */
  gap: 6px;
  padding: 10px 8px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  transition: background-color 120ms, border-color 120ms;
  cursor: pointer;
}
.folder-panel-item:hover {
  background: var(--surface-sunk);
  border-color: var(--border);
}
.folder-panel-item.active {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
}
.folder-panel-item.unclaimed .folder-panel-item-name {
  color: var(--text-muted);
  font-weight: 400;
  font-style: italic;
}
.folder-panel-item.unclaimed .folder-panel-item-icon { opacity: 0.6; }
/* Activity recolour demoted — kind colour on the icon is the primary signal. */
.folder-panel-item.has-activity .folder-panel-item-icon { /* kind colour wins */ }
.folder-panel-item-icon {
  color: var(--text-faint);
  flex-shrink: 0;
  display: inline-flex;
}
.folder-panel-item-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.folder-panel-item-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.folder-panel-item-sub {
  font-size: 11px;
  color: var(--text-faint);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* When the path is longer than the available width, ellipsize on the LEFT
     side so the meaningful tail (the actual project folder) stays visible
     — e.g. `…dev/imagine` instead of `/opt/dev…`. The classic RTL-ellipsis
     trick: flip the container to `direction: rtl` so `text-overflow: ellipsis`
     places the ellipsis at the LEFT edge, but keep `text-align: left` so the
     text visually reads left-to-right for the (strong-LTR) Latin path
     characters. The paired `.folder-panel-item-sub-inner` span carries an
     LRM (`\u200E`) prefix so weak-bidi characters (`/`) don't drift. */
  direction: rtl;
  text-align: left;
}
.folder-panel-item-sub-inner {
  /* The inner span keeps its own LTR base direction so the path reads normally
     (`/opt/dev/imagine`, not the RTL-mirrored form) even inside the RTL parent
     that gives us the left-side ellipsis. */
  unicode-bidi: embed;
  direction: ltr;
}
.folder-panel-item-count {
  font-size: 10.5px;
  color: var(--text-faint);
  font-weight: 600;
  background: var(--surface-sunk);
  border-radius: 999px;
  padding: 1px 7px;
  flex-shrink: 0;
}
.folder-panel-item.active .folder-panel-item-count {
  background: var(--primary-tint-strong);
  color: var(--primary);
}
.folder-panel-actions {
  display: inline-flex;
  gap: 1px;
  flex-shrink: 0;
}
.folder-panel-actions a,
.folder-panel-actions button {
  /* Trimmed 26→22 so the row's actions cluster reclaims ~12px of
     horizontal space per row for the folder-path text. Icons stay
     at the same 12–13px glyph size so hit-target readability
     doesn't visibly regress. */
  width: 22px;
  height: 22px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  background: transparent;
  border: none;
  color: var(--text-faint);
  cursor: pointer;
  transition: background-color 120ms, color 120ms;
  text-decoration: none;
}
.folder-panel-actions a:hover,
.folder-panel-actions button:hover {
  background: var(--primary-tint);
  color: var(--primary);
}
.folder-panel-empty {
  padding: 24px 16px;
  text-align: center;
  color: var(--text-faint);
  font-size: 12.5px;
  font-style: italic;
}
/* Group heading shown above the "Frequent" / "Others" buckets. Subtle so it doesn't
   crowd the panel — just enough to separate the two groups visually. */
.folder-panel-group-head {
  padding: 10px 14px 4px;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-faint);
  letter-spacing: 0.6px;
  text-transform: uppercase;
}
.folder-panel-group-head:first-child { padding-top: 4px; }

/* Active-folder pin-mode toggle: sits below the pinned active-folder row,
   reveals the rest of the folder list on click. Deliberately quiet — this is
   a utility control, not a primary action. See renderFolderPanel() in app.js. */
.folder-panel-others-toggle {
  margin: 8px 4px 6px;
  padding: 8px 10px;
  background: transparent;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  color: var(--text-muted);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.2px;
  cursor: pointer;
  text-align: left;
  transition: background-color 120ms, color 120ms, border-color 120ms;
}
.folder-panel-others-toggle:hover {
  background: var(--surface-sunk);
  color: var(--text);
  border-color: var(--border-strong, var(--border));
}
.folder-panel-others-toggle:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* ========== Responsive ========== */
/* Mobile / hamburger button — hidden on wide screens. The wide layout already shows
   the sidebar permanently, so the hamburger would only add noise. Below 980px the
   sidebar is hidden off-canvas and the button is the only way back. */
.mobile-nav-btn {
  display: none;
  flex-shrink: 0;
  width: 36px; height: 36px;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  color: var(--text);
  margin-right: 6px;
}
.mobile-nav-btn:hover { background: var(--surface-sunk); }
.mobile-nav-btn:active { transform: translateY(1px); }

/* Backdrop for the slide-in sidebar — taps on it close the drawer. Only used on
   narrow screens where the sidebar is off-canvas. */
.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(15, 17, 23, 0.45);
  z-index: 9;
}
body.sidebar-open .sidebar-backdrop { display: block; }

@media (max-width: 1200px) {
  :root { --folder-panel-w: 220px; }
}
@media (max-width: 980px) {
  /* Tablet: hide the right folder panel and hide the sidebar off-canvas. Hamburger
     button (in #chatHeader / #projectHeader) brings the sidebar back. The folder
     panel's content is duplicated inside the sidebar drawer for project navigation —
     see #folderPanel placement below. */
  body { grid-template-columns: 1fr; }
  /* Tablet/mobile: the right-sidebar toggle acts as an overlay opener. The
     folder panel slides in from the right OVER the chat (position:fixed
     transform:translateX(100%↔0)), so the body grid collapses to `1fr`
     and there is NO chat ↔ folder-panel divider column at these widths.
     The desktop divider-straddling anchor (`right: calc(var(--folder-panel-w)
     - 14px)`) would put the toggle 246px inside the chat area on mobile,
     visually floating in the middle of nowhere. Anchor the toggle to the
     viewport's right edge here (`right: 0`) and adopt the tab-pull posture
     (matches the collapsed-desktop styling) — the button is now a permanent
     right-edge fixture regardless of whether `.folder-panel-collapsed` is
     on the body. This override only fires at ≤980px, where the grid
     divider genuinely doesn't exist. */
  .folder-panel-toggle {
    right: 0;
    border-right: none;
    border-radius: 14px 0 0 14px;
    box-shadow: -2px 0 6px rgba(15, 23, 42, 0.06);
  }
  .folder-panel-toggle::before {
    /* Right edge flush with viewport, so no rightward hit-area extension. */
    right: 0;
  }
  #folderPanel {
    /* Collapsed by default on small screens; the toggle button reveals it as an
       overlay. When the .folder-panel-overlay-open class is on <body>, we position
       it fixed on the right edge and slide it in. */
    display: flex;
    position: fixed;
    top: 0; right: 0; bottom: 0;
    width: min(320px, 82%);
    z-index: 11;
    transform: translateX(100%);
    transition: transform 240ms cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: var(--shadow-lg);
    visibility: visible;
    opacity: 1;
  }
  body.folder-panel-overlay-open #folderPanel { transform: translateX(0); }
  /* Legacy 3-column grid overrides that would otherwise collide. */
  body.folder-panel-collapsed { grid-template-columns: 1fr; }
  body:not(.folder-panel-overlay-open) .folder-panel-backdrop { display: none; }
  #sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: 82%;
    max-width: 320px;
    z-index: 10;
    transform: translateX(-100%);
    transition: transform 200ms;
    box-shadow: var(--shadow-lg);
    /* Keep overflow: hidden (from the base #sidebar rule) so the inner
       .sidebar-scroll is the true scroll surface. If we put overflow-y:auto
       here, the parent allows children to overflow and .sidebar-scroll's
       `flex: 1 1 auto` no longer gets height-constrained → the entire sidebar
       (incl. the sticky <footer.sidebar-user>) scrolls as one mass and the
       footer falls below the fold on mobile. The middle .sidebar-scroll
       already handles vertical scrolling (see the base rule above) — that's
       the only scroller we need. Use dvh so iOS Safari URL-bar collapse
       doesn't cut off the bottom of the menu. */
    height: 100dvh;
  }
  body.sidebar-open #sidebar { transform: translateX(0); }
  .mobile-nav-btn { display: inline-flex; }

  /* When the sidebar is open on mobile, also reveal the right-folder-panel content
     INSIDE the sidebar so users have one place to navigate from. We append a clone
     of #folderPanel after the thread list in JS — see initMobileFolderPanel(). */
  body.sidebar-open #sidebar .mobile-folders-section {
    display: block;
    border-top: 1px solid var(--border);
    margin-top: 12px;
    padding-top: 8px;
  }
  body.sidebar-open #sidebar .mobile-folders-section .folder-panel-list {
    display: flex; flex-direction: column; gap: 2px;
  }
  body.sidebar-open #sidebar .mobile-folders-section-head {
    padding: 8px 12px 4px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--text-faint);
  }
}
@media (max-width: 900px) {
  :root { --sidebar-w: 240px; }
  #messages, #composer { padding-left: 16px; padding-right: 16px; }
  #chatHeader { padding-left: 16px; padding-right: 16px; }
}
@media (max-width: 640px) {
  /* Tighten paddings + stack more aggressively. The sidebar slide-in inherits from
     the 980px rule above. */
  #chatHeader, #projectHeader { padding-left: 12px; padding-right: 12px; }
  .header-actions .btn span:not(.mobile-nav-btn span) { display: none; } /* icon-only buttons */
}

/* ============================================================
   Right-panel folder accordion + IDE-style slide-in editor.
   - Each project row in #folderPanel gains a chevron toggle.
   - Expanded rows lazy-load /api/files/list and render an
     inline tree (recursive, also with chevrons).
   - Clicking a file opens #ideEditor (slide in from right).
   ============================================================ */

/* Wrap each row + its accordion children in a single column. */
.fpa-wrap { display: flex; flex-direction: column; }

/* Chevron button placed at the start of each .folder-panel-item. */
.fpa-chev {
  width: 18px;
  height: 18px;
  margin-right: 2px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-faint);
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: color 120ms, background-color 120ms, transform 150ms;
}
.fpa-chev:hover { background: var(--surface-sunk); color: var(--text); }
.fpa-chev:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.fpa-chev.open { transform: rotate(90deg); color: var(--primary); }

/* The expanded children container. */
.fpa-children {
  margin: 2px 0 6px 14px;
  padding-left: 6px;
  border-left: 1px dashed var(--border);
  display: flex;
  flex-direction: column;
  gap: 1px;
  font-size: 12.5px;
  max-height: 360px;
  overflow-y: auto;
}
.fpa-loading, .fpa-empty, .fpa-error {
  padding: 4px 6px;
  color: var(--text-faint);
  font-style: italic;
  font-size: 12px;
}
.fpa-error { color: var(--danger, #c62828); font-style: normal; }

/* Soft "no file access" notice — rendered when the user has thread-only
   access in this cwd (folder card appears via thread visibility, but the
   /api/files/list endpoint is project-assignment-gated). Friendlier than
   raw "403: forbidden", and the chevron self-dims so the dead-end is
   glanceable on re-expand. */
.fpa-forbidden {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  padding: 6px 8px;
  margin: 2px 0;
  background: var(--surface-sunk, #f3f4f6);
  border-radius: 6px;
  color: var(--text-muted, #6B7280);
  font-size: 12px;
  line-height: 1.4;
}
.fpa-forbidden-icon { flex: 0 0 auto; line-height: 1.3; }
.fpa-forbidden-text { word-break: break-word; }
.fpa-chev.is-forbidden {
  opacity: 0.45;
}
.fpa-chev.is-forbidden:hover {
  opacity: 0.7;
}

.fpa-row {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 3px 6px 3px 2px;
  border-radius: 5px;
  cursor: pointer;
  color: var(--text-muted);
  user-select: none;
  min-width: 0;
}
.fpa-row:hover { background: var(--surface-sunk); color: var(--text); }
.fpa-row.active { background: var(--primary-tint); color: var(--primary); }
.fpa-row.is-file:hover { background: var(--primary-tint); color: var(--primary); }
.fpa-row .fpa-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.fpa-row .fpa-size {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px;
  color: var(--text-faint);
  flex-shrink: 0;
}
.fpa-row .fpa-icon {
  width: 14px;
  display: inline-flex;
  justify-content: center;
  flex-shrink: 0;
  font-size: 12px;
  line-height: 1;
}
.fpa-row .fpa-spacer { width: 14px; flex-shrink: 0; }
.fpa-subchev {
  width: 14px;
  height: 14px;
  border: none;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 10px;
  transition: transform 150ms;
}
.fpa-subchev.open { transform: rotate(90deg); color: var(--primary); }

/* ============================================================
   IDE-style slide-in editor (#ideEditor).
   ============================================================ */
.ide-editor {
  position: fixed;
  top: 0;
  right: 0;
  width: min(880px, 80vw);
  height: 100vh;
  background: var(--surface, #fff);
  border-left: 1px solid var(--border, #e2e6ed);
  box-shadow: -8px 0 24px rgba(15, 32, 68, 0.10), -2px 0 6px rgba(15, 32, 68, 0.05);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.ide-editor:not(.hidden) {
  transform: translateX(0);
}
.ide-editor.hidden { pointer-events: none; }

.ide-editor-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-sunk, #f6f9fd);
  flex-shrink: 0;
  min-height: 50px;
}
.ide-editor-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  flex: 1 1 auto;
  font-size: 13.5px;
  color: var(--text-muted);
}
.ide-editor-project { color: var(--text-faint); font-weight: 500; }
.ide-editor-sep { color: var(--text-faint); }
.ide-editor-path {
  color: var(--text);
  font-weight: 600;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}
.ide-editor-dirty { color: var(--primary); font-size: 14px; line-height: 1; }
.ide-editor-meta {
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  color: var(--text-faint);
  flex-shrink: 0;
}
.ide-editor-actions { display: inline-flex; gap: 6px; flex-shrink: 0; }

.ide-editor-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: var(--surface);
}
.ide-editor-empty {
  margin: auto;
  padding: 40px;
  color: var(--text-faint);
  font-size: 13px;
  text-align: center;
}
.ide-editor-textarea {
  flex: 1 1 auto;
  width: 100%;
  border: none;
  resize: none;
  padding: 14px 18px;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  line-height: 1.55;
  background: var(--surface);
  color: var(--text);
  outline: none;
  tab-size: 2;
  -moz-tab-size: 2;
  white-space: pre;
  overflow: auto;
}
.ide-editor-textarea:focus { background: var(--surface); }

/* ── Composer approval banner ──────────────────────────────────────────
   Inline notice that sits at the top of the composer card when the
   active thread is awaiting (or has been declined by) admin approval.
   Replaces the original native `alert('Send failed: 403: …')` that
   brand-new invitees were hitting on their first send. Per the design
   rule "never use dialogue boxes" — this is a proper inline UI. */
.composer-approval-banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  margin: 0 0 8px 0;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-sunk);
  font-size: 12.5px;
  line-height: 1.45;
}
.composer-approval-banner.is-pending {
  background: rgba(245, 158, 11, 0.08);
  border-color: rgba(245, 158, 11, 0.30);
  color: var(--text);
}
.composer-approval-banner.is-rejected {
  background: var(--danger-tint);
  border-color: rgba(220, 38, 38, 0.30);
  color: var(--text);
}
html.theme-dark .composer-approval-banner.is-pending  { background: rgba(245, 158, 11, 0.14); }
html.theme-dark .composer-approval-banner.is-rejected { background: rgba(248, 113, 113, 0.14); }
.composer-approval-banner-icon {
  font-size: 16px;
  line-height: 1.2;
  flex-shrink: 0;
}
.composer-approval-banner.is-pending  .composer-approval-banner-icon { color: var(--warning); }
.composer-approval-banner.is-rejected .composer-approval-banner-icon { color: var(--danger); }
.composer-approval-banner-text {
  display: flex; flex-direction: column; gap: 2px;
  min-width: 0;
}
.composer-approval-banner-title {
  font-weight: 600;
  font-size: 13px;
  color: var(--text);
}
.composer-approval-banner-body {
  color: var(--text-muted);
}

/* ── File-tree icons (VS Code / Cursor-style colour-coding) ────────────
   Used by both the right-panel folder accordion (.fpa-row) and the
   Files-tab tree (.tree-row). Inline SVG with CSS-driven colour:
   `.file-icon-<kind>` for files (extension-based), `.folder-icon-<kind>`
   for folders (name-based). Palette mirrors the Material Icon Theme
   convention so colours feel "right" — HTML orange, MD blue, JS yellow,
   etc. Added 29 Jun 2026. */
.file-type-icon, .folder-type-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  line-height: 1;
}
.file-type-icon svg, .folder-type-icon svg { width: 14px; height: 14px; display: block; }

/* Folders — golden default + a few category overrides. The "open"
   variant inherits the same colour; the SVG shape differs. */
.folder-icon-default    { color: #DCB67A; }
.folder-icon-src        { color: #4FC1FF; }
.folder-icon-docs       { color: #C586C0; }
.folder-icon-modules    { color: #6B7280; }
.folder-icon-dist       { color: #34D399; }
.folder-icon-assets     { color: #FBBF24; }
.folder-icon-tests      { color: #F87171; }
.folder-icon-git        { color: #F05133; }
.folder-icon-config     { color: #9CA3AF; }
.folder-icon-scripts    { color: #A78BFA; }
.folder-icon-styles     { color: #06B6D4; }
.folder-icon-components { color: #14B8A6; }
.folder-icon-pages      { color: #F59E0B; }
.folder-icon-api        { color: #10B981; }
.folder-icon-utils      { color: #94A3B8; }
.folder-icon-hooks      { color: #EC4899; }
.folder-icon-logs       { color: #71717A; }

/* Files — extension-driven colours. Defaults to slate-grey for unknown.
   Hexes follow Material Icon Theme / VS Code lang convention so users
   recognise them at a glance. */
.file-icon-default   { color: #94A3B8; }
.file-icon-html      { color: #E34F26; }
.file-icon-css       { color: #1572B6; }
.file-icon-js        { color: #F7DF1E; }
.file-icon-ts        { color: #3178C6; }
.file-icon-tsx       { color: #61DAFB; }
.file-icon-jsx       { color: #61DAFB; }
.file-icon-json      { color: #FBBF24; }
.file-icon-md        { color: #519ABA; }
.file-icon-py        { color: #3776AB; }
.file-icon-go        { color: #00ADD8; }
.file-icon-rs        { color: #DEA584; }
.file-icon-java      { color: #B07219; }
.file-icon-php       { color: #777BB4; }
.file-icon-ruby      { color: #CC342D; }
.file-icon-shell     { color: #89E051; }
.file-icon-sql       { color: #F29111; }
.file-icon-yaml      { color: #CB171E; }
.file-icon-toml      { color: #9C4221; }
.file-icon-xml       { color: #E37933; }
.file-icon-svg       { color: #FFB13B; }
.file-icon-image     { color: #A074C4; }
.file-icon-pdf       { color: #D83B01; }
.file-icon-archive   { color: #F59E0B; }
.file-icon-audio     { color: #EC4899; }
.file-icon-video     { color: #9333EA; }
.file-icon-csv       { color: #1D6F42; }
.file-icon-lock      { color: #DC2626; }
.file-icon-log       { color: #71717A; }
.file-icon-env       { color: #ECD53F; }
.file-icon-git       { color: #F05133; }
.file-icon-docker    { color: #2496ED; }
.file-icon-tsconfig  { color: #3178C6; }
.file-icon-npm       { color: #CB3837; }
.file-icon-readme    { color: #519ABA; }
.file-icon-license   { color: #FBBF24; }
.file-icon-makefile  { color: #427819; }
.file-icon-lint      { color: #4B32C3; }
.file-icon-vue       { color: #41B883; }
.file-icon-svelte    { color: #FF3E00; }
.file-icon-c         { color: #00599C; }
.file-icon-cpp       { color: #00599C; }
.file-icon-csharp    { color: #239120; }
.file-icon-swift     { color: #FA7343; }
.file-icon-kotlin    { color: #7F52FF; }
.file-icon-dart      { color: #0175C2; }
.file-icon-solidity  { color: #6E7587; }
.file-icon-graphql   { color: #E10098; }

/* Dark-mode legibility — bump the few colours that vanish on dark surfaces. */
html.theme-dark .folder-icon-default   { color: #E5C285; }
html.theme-dark .file-icon-default     { color: #B8C0CC; }
html.theme-dark .file-icon-js          { color: #F7DF1E; }
html.theme-dark .file-icon-md          { color: #5EB8DC; }
html.theme-dark .file-icon-yaml        { color: #EF4444; }
html.theme-dark .folder-icon-modules   { color: #94A3B8; }
html.theme-dark .folder-icon-utils     { color: #B8C0CC; }
html.theme-dark .folder-icon-logs      { color: #94A3B8; }

/* Override the now-redundant .fpa-icon / .tree-icon font-size — the
   sized SVG inside takes over rendering, but `font-size: 12px` from
   the legacy rules would still apply if a non-SVG sibling ever lived
   here. Reset to inherit so layout stays predictable. */
.fpa-row .fpa-icon.file-type-icon,
.fpa-row .fpa-icon.folder-type-icon,
.tree-row .tree-icon.file-type-icon,
.tree-row .tree-icon.folder-type-icon {
  font-size: 0;
}

/* Monaco editor host inside the slide-in IDE. Needs explicit dimensions
   so Monaco's automaticLayout can compute its widget grid. The parent
   .ide-editor-body is flex:1; this child fills the rest. */
.ide-editor-monaco {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  position: relative;
  background: var(--surface);
}
.ide-editor-monaco .monaco-editor { background: transparent !important; }

.ide-editor-foot {
  border-top: 1px solid var(--border);
  background: var(--surface-sunk);
  padding: 6px 14px;
  flex-shrink: 0;
  font-size: 11px;
  color: var(--text-faint);
}
.ide-editor-hint kbd {
  background: var(--surface);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: 1px 5px;
  font-family: inherit;
  font-size: 10.5px;
  color: var(--text-muted);
  margin: 0 2px;
}

@media (max-width: 720px) {
  .ide-editor { width: 100vw; }
}

/* ============================================================
   My Team page (sidebar → My Team)
   ============================================================ */
#myTeamView, #myAgentsView {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--bg, var(--surface, #f6f9fd));
  overflow: hidden;
}
#myAgentsView.hidden, #myTeamView.hidden { display: none; }
#myAgentsHeader {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 22px;
  border-bottom: 1px solid var(--border);
  background: var(--surface, #fff);
  flex-shrink: 0;
}
.myagents-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 18px 22px 60px;
  max-width: 1100px;
  width: 100%;
  margin: 0 auto;
}
.myagents-body section { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; margin-bottom: 18px; }
.myagents-body section h3 { margin: 0; padding: 12px 16px; font-size: 14px; font-weight: 700; border-bottom: 1px solid var(--border); }
.myagents-create-grid {
  display: grid;
  grid-template-columns: 2fr 1.5fr;
  gap: 10px 14px;
  padding: 14px 16px;
}
.myagents-create-grid .field { display: block; }
.myagents-create-grid .field-label { display: block; font-size: 11.5px; color: var(--text-muted); margin-bottom: 4px; }
.myagents-create-grid input, .myagents-create-grid select {
  width: 100%; padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); color: var(--text); font: inherit; font-size: 13px;
}
.myagents-create-grid input:focus, .myagents-create-grid select:focus {
  outline: none; border-color: var(--primary-tint-strong);
  box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.10);
}
.myagents-create-teams, .myagents-create-desc { grid-column: 1 / -1; }
.myagents-create-actions {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: 10px;
  padding-top: 6px; border-top: 1px dashed var(--border); margin-top: 4px;
}
.myagents-list-head { display: flex; align-items: center; gap: 12px; padding-right: 16px; border-bottom: 1px solid var(--border); }
.myagents-list-head h3 { border-bottom: none !important; flex: 1 1 auto; }
.myagents-count { color: var(--text-faint); font-size: 12px; }
.myagents-list { display: flex; flex-direction: column; gap: 0; padding: 0; }
.myagents-empty { padding: 28px 16px; text-align: center; color: var(--text-faint); font-style: italic; font-size: 13px; }
.myagents-card {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px 14px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  align-items: center;
}
.myagents-card:last-child { border-bottom: none; }
.myagents-card-name { font-weight: 600; font-size: 14px; color: var(--text); }
.myagents-card-name code { font-size: 11px; color: var(--text-faint); margin-left: 6px; font-family: ui-monospace, monospace; }
.myagents-card-sub { font-size: 12px; color: var(--text-muted); grid-column: 1 / -1; }
.myagents-card-sub .chip { display: inline-block; background: var(--primary-tint); color: var(--primary); padding: 2px 8px; border-radius: 999px; font-size: 11px; margin-right: 4px; }
.myagents-card-actions { display: inline-flex; gap: 6px; }
.myagents-status-pill {
  font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface-sunk); color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.4px;
}
.myagents-status-pill.is-pending { background: #FFF4E0; border-color: #F2C77E; color: #8A4B07; }
.myagents-status-pill.is-approved { background: #E7F8EF; border-color: #A7E3C3; color: #086A44; }
.myagents-status-pill.is-rejected { background: #FDECEC; border-color: #F4B6B6; color: #A31A1A; }

.myagents-editor { display: flex; flex-direction: column; }
.myagents-editor.hidden { display: none; }
.myagents-editor-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border); }
.myagents-editor-head h3 { border-bottom: none !important; padding: 0 !important; }
.myagents-tabs { display: flex; gap: 0; padding: 0 16px; border-bottom: 1px solid var(--border); }
.myagents-tab {
  padding: 10px 14px; border: none; background: transparent; color: var(--text-muted);
  font-size: 12.5px; font-weight: 600; cursor: pointer; border-bottom: 2px solid transparent; border-radius: 0;
}
.myagents-tab:hover { color: var(--text); }
.myagents-tab.is-active { color: var(--primary); border-bottom-color: var(--primary); }
.myagents-file-body {
  margin: 12px 16px;
  min-height: 360px;
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 13px; line-height: 1.55;
  background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
  padding: 12px 14px; color: var(--text); resize: vertical;
}
.myagents-file-body:focus { outline: none; border-color: var(--primary-tint-strong); box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.10); }
.myagents-editor-footer { display: flex; align-items: center; gap: 10px; padding: 10px 16px 14px; }
.myagents-flash { font-size: 12px; color: var(--text-faint); min-height: 18px; }
.myagents-flash.is-error { color: var(--danger); }
.myagents-flash.is-ok { color: #086A44; }

/* ─── Shared-with-you list heading + card variant ────────────────────── */
.myagents-shared-heading {
  padding: 14px 16px 8px;
  border-top: 1px dashed var(--border);
  margin-top: 4px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.myagents-shared-heading-hint { color: var(--text-faint); font-size: 12px; }
.myagents-card.is-shared-in { background: color-mix(in srgb, var(--primary-tint) 22%, transparent); }
/* Hide the list card whose editor is currently open — the editor below shows
   the same name / status / description, so keeping both on screen looks
   like an accidental duplicate. Restored the moment the editor closes. */
.myagents-card.is-editing-hidden { display: none !important; }
.myagents-card-shared-meta { display: inline-block; font-size: 11.5px; color: var(--text-muted); margin-top: 3px; }
.myagents-card-shared-meta em { color: var(--primary); font-style: normal; font-weight: 600; }
.chip.is-shared {
  background: linear-gradient(135deg, var(--primary-tint), color-mix(in srgb, var(--primary) 18%, transparent));
  color: var(--primary);
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}

/* ─── Shares / Invite tab pane ───────────────────────────────────────── */
.myagents-shares-pane {
  padding: 14px 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.myagents-shares-pane.hidden { display: none; }
.myagents-shares-intro {
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.5;
  padding: 10px 12px;
  background: var(--primary-tint);
  border-radius: 8px;
  border-left: 3px solid var(--primary);
}
.myagents-shares-intro strong { color: var(--text); }
.myagents-shares-intro em { color: var(--primary); font-style: normal; font-weight: 600; }

.myagents-share-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
}
.myagents-share-form.hidden { display: none; }
.myagents-share-form .field { display: block; }
.myagents-share-form .field-label { display: block; font-size: 11.5px; color: var(--text-muted); margin-bottom: 4px; font-weight: 600; }
.myagents-share-form .field-hint { display: block; font-size: 11px; color: var(--text-faint); margin-top: 4px; font-style: italic; }
.myagents-share-form input, .myagents-share-form select {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 7px;
  font: inherit;
  font-size: 13px;
  background: var(--bg);
}
.myagents-share-form input:focus, .myagents-share-form select:focus {
  outline: none; border-color: var(--primary-tint-strong); box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.10);
}
.myagents-share-form-actions {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 10px;
}

.myagents-shares-list-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-top: 4px;
}
.myagents-shares-list-head h4 {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  flex: 1 1 auto;
}
.myagents-shares-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.myagents-share-row {
  display: grid;
  grid-template-columns: 1.4fr 1.3fr auto;
  gap: 12px;
  align-items: center;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
}
.myagents-share-who { min-width: 0; }
.myagents-share-name { font-weight: 600; font-size: 13.5px; color: var(--text); word-break: break-word; }
.myagents-share-email { font-size: 11.5px; color: var(--text-faint); word-break: break-all; }
.myagents-share-meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 12px; color: var(--text-muted); }
.myagents-share-when { color: var(--text-faint); }
.myagents-share-by { color: var(--text-faint); }
.myagents-perm-pill {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  border: 1px solid transparent;
}
.myagents-perm-pill.is-use { background: #E7F0FA; border-color: #A9C6E4; color: #1B3F63; }
.myagents-perm-pill.is-edit { background: #FFF4E0; border-color: #F2C77E; color: #8A4B07; }
.myagents-share-actions { display: inline-flex; gap: 6px; align-items: center; }
.myagents-share-perm-select {
  font: inherit;
  font-size: 12px;
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
}
@media (max-width: 720px) {
  .myagents-share-form { grid-template-columns: 1fr; }
  .myagents-share-row { grid-template-columns: 1fr; gap: 6px; }
  .myagents-share-actions { justify-content: flex-end; }
}

/* ─── Inline-editable Markdown renderer (My Agents → file tabs) ───────
 * Renders the MD source as a mix of <pre> text and live GFM tables.
 * <td> cells are contenteditable so the user can tap → edit a single
 * value (price, count, name) and Enter to save in place. The MD source
 * is reconstructed and PUT to /api/agents/:id/files/:kind on every
 * commit, so the on-disk .md stays in sync cell-by-cell. */
.myagents-rendered {
  margin: 12px 16px;
  max-height: 60vh;
  overflow: auto;
  padding: 4px;
  display: flex; flex-direction: column; gap: 12px;
}
.myagents-rendered.hidden { display: none; }
.myagents-rendered .img-md-text {
  white-space: pre-wrap; word-break: break-word;
  font-size: 13px; line-height: 1.55;
  background: var(--surface-muted, #F5F7FA);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 11px 13px;
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  margin: 0;
}
.myagents-rendered .img-md-text:empty { display: none; }
.myagents-rendered .img-md-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--primary, #0078BF);
  border-radius: 10px;
  background: var(--surface, #fff);
  box-shadow: 0 1px 3px rgba(0,120,191,0.08);
}
.myagents-rendered .img-md-table-caption {
  font-size: 10.5px; color: var(--text-muted);
  padding: 5px 10px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-muted, #F5F7FA);
  letter-spacing: 0.3px; text-transform: uppercase; font-weight: 600;
}
.myagents-rendered .img-md-table {
  border-collapse: collapse; width: 100%;
  font-size: 13px; background: transparent;
}
.myagents-rendered .img-md-table th,
.myagents-rendered .img-md-table td {
  border: 1px solid var(--border);
  padding: 7px 10px;
  vertical-align: top;
  line-height: 1.4;
}
.myagents-rendered .img-md-table th {
  background: var(--surface-muted, #F5F7FA);
  font-weight: 700; color: var(--text);
  text-align: left; font-size: 11.5px;
  letter-spacing: 0.3px; text-transform: uppercase;
  position: sticky; top: 0; z-index: 1;
}
.myagents-rendered .img-md-table td {
  cursor: text; color: var(--text);
  min-width: 48px;
  transition: background 120ms ease;
}
.myagents-rendered .img-md-table td:hover { background: rgba(0,120,191,0.05); }
.myagents-rendered .img-md-table td:focus {
  outline: 2px solid var(--primary, #0078BF);
  outline-offset: -2px;
  background: rgba(0,120,191,0.08);
}
.myagents-rendered .img-md-cell-saving { background: rgba(245,158,11,0.18) !important; }
.myagents-rendered .img-md-cell-saved  { background: rgba(16,185,129,0.22) !important; }
.myagents-rendered .img-md-cell-error  { background: rgba(220,38,38,0.18) !important; }

/* ========== Soul Interview panel ========== */
.myagents-interview {
  margin: 12px 0 16px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: linear-gradient(135deg, rgba(0,120,191,0.04), rgba(228,76,154,0.04));
}
.myagents-interview.hidden { display: none; }
.myagents-interview-head {
  display: flex; align-items: center; gap: 12px;
  padding-bottom: 10px; border-bottom: 1px dashed var(--border); margin-bottom: 12px;
}
.myagents-interview-progress { color: var(--text-muted); font-size: 12px; flex: 1; }
.myagents-interview-body { display: flex; flex-direction: column; gap: 10px; }
.myagents-interview-stage.hidden { display: none; }
.myagents-interview-stage textarea {
  width: 100%; padding: 10px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-family: inherit; font-size: 13px;
  resize: vertical; min-height: 60px;
}
.field-hint { display: block; font-size: 11px; color: var(--text-faint); margin-top: 4px; }
.myagents-interview-acks {
  max-height: 220px; overflow-y: auto; padding: 6px 8px;
  background: rgba(0,0,0,0.03); border-radius: 6px; font-size: 12.5px;
  display: flex; flex-direction: column; gap: 4px;
}
.si-ack { display: flex; gap: 8px; line-height: 1.45; }
.si-ack-q {
  flex-shrink: 0; background: rgba(0,120,191,0.12); border-radius: 4px;
  padding: 1px 6px; font-weight: 600; font-size: 11px; color: #0078BF;
}
.si-question {
  border: 1px solid var(--border); border-radius: 8px; padding: 12px;
  background: var(--surface); display: flex; flex-direction: column; gap: 10px;
}
.si-q-head { display: flex; gap: 8px; align-items: baseline; }
.si-q-section { font-size: 11.5px; color: var(--text-muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
.si-q-help { cursor: help; color: var(--brand-blue, #0078BF); font-size: 13px; }
.si-q-prompt { font-size: 14.5px; font-weight: 600; line-height: 1.4; }
.si-q-options { display: flex; flex-direction: column; gap: 6px; }
.si-pick { display: flex; align-items: flex-start; gap: 8px; padding: 6px 8px; border-radius: 6px; cursor: pointer; }
.si-pick:hover { background: rgba(0,120,191,0.06); }
.si-pick input[type=radio], .si-pick input[type=checkbox] { margin-top: 3px; }
.si-pick-label { font-size: 13px; line-height: 1.4; flex: 1; }
.si-pick-custom input[type=text] {
  margin-left: 6px; padding: 3px 8px; border-radius: 4px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-size: 13px;
}
#si-confirm-rewrite, #si-free {
  width: 100%; padding: 8px 10px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-family: inherit; font-size: 13px;
  resize: vertical; min-height: 60px; margin-top: 4px;
}
.si-confirm-preface {
  padding: 8px 12px; background: rgba(0,120,191,0.08); border-radius: 6px;
  font-style: italic; font-size: 13.5px; line-height: 1.5;
}
.si-q-actions { display: flex; align-items: center; gap: 8px; }
.myagents-interview-preview {
  max-height: 400px; overflow-y: auto; padding: 12px; background: rgba(0,0,0,0.04);
  border-radius: 6px; border: 1px solid var(--border); font-size: 12px; line-height: 1.5;
  white-space: pre-wrap; font-family: inherit;
}
.myagents-interview-finalize { display: flex; align-items: center; gap: 8px; }

/* Attachments band — sits above the question card during Q&A. */
.si-attachments {
  border: 1px dashed var(--border); border-radius: 8px; padding: 10px 12px;
  background: rgba(13, 115, 119, 0.04); display: flex; flex-direction: column; gap: 8px;
}
.si-attachments-head { display: flex; align-items: baseline; flex-wrap: wrap; }
.si-attach-list { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.si-attach-list:empty::before {
  content: 'No references attached yet — optional, but improves the soul.md';
  font-size: 11.5px; color: var(--text-faint); font-style: italic;
}
.si-attach-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(0, 120, 191, 0.08); border: 1px solid rgba(0, 120, 191, 0.25);
  border-radius: 999px; padding: 3px 10px; font-size: 11.5px;
}
.si-attach-chip.has-error { background: rgba(220, 53, 69, 0.08); border-color: rgba(220, 53, 69, 0.35); }
.si-attach-chip .si-attach-x {
  appearance: none; border: none; background: transparent; cursor: pointer;
  font-size: 14px; line-height: 1; color: var(--text-faint); padding: 0 2px;
}
.si-attach-chip .si-attach-x:hover { color: var(--danger); }
.si-attach-actions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.si-url-input {
  flex: 1; min-width: 160px;
  padding: 5px 9px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-size: 12.5px; font-family: inherit;
}

/* ========== Task Groups (multi-party chat) ========== */
.taskgroups-list { display: flex; flex-direction: column; gap: 6px; padding: 8px 0 0; }
.taskgroup-card {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 14px;
  padding: 10px 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; cursor: pointer;
  transition: background 100ms, border-color 100ms;
}
.taskgroup-card:hover { background: var(--surface-sunk); border-color: var(--primary-tint-strong); }
.taskgroup-card.is-active { border-color: var(--primary); background: var(--primary-tint); }
.taskgroup-card-name { font-weight: 600; font-size: 13.5px; color: var(--text); }
.taskgroup-card-sub { grid-column: 1 / -1; font-size: 11.5px; color: var(--text-muted); }
.taskgroup-card-sub .chip {
  display: inline-block; background: var(--surface-sunk); border: 1px solid var(--border);
  padding: 2px 8px; border-radius: 999px; font-size: 11px; margin-right: 4px;
}
.taskgroup-card-sub .chip.is-agent { background: var(--primary-tint); color: var(--primary); border-color: var(--primary-tint-strong); }
.taskgroup-card-actions { display: inline-flex; gap: 4px; }

/* ── Chat panel ── */
.taskgroup-chat {
  padding: 0 !important;
  overflow: hidden;
  /* CRITICAL: .my-team-body is a flex column that scrolls when overfull.
   * Without flex-shrink:0 the panel gets crushed to ~2px whenever the
   * sibling cards (invites list, task-group form, group cards) already
   * fill the container — clicking "Open chat" then appeared to do
   * nothing because the panel HAD unhidden, but only rendered as a
   * 2-pixel sliver below the fold. flex-shrink:0 forces the panel to
   * keep its full content-height and lets the container scroll.
   * (Regression fix · 25 Jul 2026, Jaseena's "can't open chat" report.) */
  flex-shrink: 0;
}
.taskgroup-chat.hidden { display: none; }
.taskgroup-chat-head {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; border-bottom: 1px solid var(--border);
  background: var(--surface-sunk);
}
.taskgroup-chat-head h3 { margin: 0; font-size: 14.5px; }
.taskgroup-chat-sub { display: block; font-size: 11.5px; color: var(--text-faint); }
.taskgroup-chat-titlewrap { flex: 1 1 auto; }
.taskgroup-chat-actions { display: inline-flex; gap: 6px; }

.taskgroup-manage { padding: 10px 14px; border-bottom: 1px solid var(--border); background: var(--surface); }
.taskgroup-manage.hidden { display: none; }
.taskgroup-manage-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.taskgroup-manage-label { font-weight: 600; font-size: 12px; color: var(--text-muted); min-width: 70px; }
.taskgroup-chips { display: inline-flex; gap: 4px; flex-wrap: wrap; flex: 1 1 auto; }
.taskgroup-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 4px 3px 10px; background: var(--surface-sunk); border: 1px solid var(--border);
  border-radius: 999px; font-size: 11.5px;
}
.taskgroup-chip.is-agent { background: var(--primary-tint); color: var(--primary); border-color: var(--primary-tint-strong); }
.taskgroup-chip-x {
  border: none; background: transparent; cursor: pointer; color: var(--text-faint);
  width: 16px; height: 16px; border-radius: 50%; padding: 0; line-height: 1; font-size: 14px;
}
.taskgroup-chip-x:hover { color: var(--danger); }
.taskgroup-add-select {
  padding: 4px 8px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); font-size: 12px; max-width: 220px;
}

.taskgroup-messages {
  height: 380px; overflow-y: auto;
  padding: 12px 14px; background: var(--surface);
  display: flex; flex-direction: column; gap: 8px;
}
.taskgroup-msg { display: flex; gap: 8px; align-items: flex-start; }
.taskgroup-msg-avatar {
  width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-sunk); color: var(--text-muted);
  font-size: 11px; font-weight: 700; border: 1px solid var(--border);
}
.taskgroup-msg.is-agent .taskgroup-msg-avatar {
  background: var(--primary-tint); color: var(--primary); border-color: var(--primary-tint-strong);
}
.taskgroup-msg-bubble {
  background: var(--surface-sunk); border: 1px solid var(--border);
  border-radius: 8px; padding: 8px 12px; max-width: 85%;
}
.taskgroup-msg.is-agent .taskgroup-msg-bubble {
  background: var(--primary-tint); border-color: var(--primary-tint-strong);
}
.taskgroup-msg-meta { font-size: 11px; color: var(--text-faint); margin-bottom: 2px; }
.taskgroup-msg-meta b { color: var(--text); font-weight: 600; }
.taskgroup-msg-content { font-size: 13.5px; line-height: 1.5; color: var(--text); white-space: pre-wrap; word-wrap: break-word; }
.taskgroup-msg.is-self .taskgroup-msg-bubble { background: #E7F8EF; border-color: #A7E3C3; }

.taskgroup-composer {
  display: flex; gap: 8px; padding: 10px 14px;
  border-top: 1px solid var(--border); background: var(--surface-sunk);
}
.taskgroup-composer textarea {
  flex: 1 1 auto; resize: none;
  font: inherit; font-size: 13.5px; line-height: 1.4;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); color: var(--text);
}
.taskgroup-composer textarea:focus {
  outline: none; border-color: var(--primary-tint-strong);
  box-shadow: 0 0 0 3px rgba(13, 115, 119, 0.10);
}
@media (max-width: 760px) {
  .myagents-create-grid { grid-template-columns: 1fr; }
  .myagents-card { grid-template-columns: 1fr; }
}
#myTeamHeader, #myOrgHeader, #organisationsHeader,
.my-cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 22px;
  border-bottom: 1px solid var(--border);
  background: var(--surface, #fff);
  flex-shrink: 0;
}
.my-team-body,
.orgs-body {
  flex: 1 1 auto;
  min-height: 0; /* required so overflow-y actually scrolls in a flex column */
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  scrollbar-width: thin;
}
.my-team-card {
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 18px 20px;
  box-shadow: 0 1px 2px rgba(15,32,68,.04);
}
.my-team-section-title {
  margin: 0 0 14px;
  font-size: 15px;
  color: var(--text, var(--heading));
  display: flex;
  align-items: center;
  gap: 8px;
}
.my-team-counts {
  margin-left: auto;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted, var(--muted));
}
.info-i {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--primary-tint, #e8f1fb); color: var(--primary, #1878D0);
  font-size: 10px; font-weight: 700; cursor: help; border: none; position: relative;
}
.info-i:hover, .info-i:focus-visible { outline: none; background: var(--primary, #1878D0); color: #fff; }
.info-i[data-tip]:hover::after, .info-i[data-tip]:focus-visible::after {
  content: attr(data-tip); position: absolute; bottom: calc(100% + 8px); left: 50%;
  transform: translateX(-50%); background: var(--text, #000A2D); color: #fff;
  font-size: 12px; font-weight: 500; padding: 8px 10px; border-radius: 6px;
  white-space: normal; width: max-content; max-width: 280px; line-height: 1.4;
  text-align: left; z-index: 50; box-shadow: 0 6px 18px rgba(0,0,0,.15); pointer-events: none;
}
.info-i[data-tip]:hover::before, .info-i[data-tip]:focus-visible::before {
  content: ""; position: absolute; bottom: calc(100% + 2px); left: 50%; transform: translateX(-50%);
  border: 6px solid transparent; border-top-color: var(--text, #000A2D); z-index: 50; pointer-events: none;
}

/* Form */
.my-team-form { display: flex; flex-direction: column; gap: 10px; }
.my-team-form-row {
  display: grid;
  grid-template-columns: 2fr 2fr 1fr auto;
  gap: 10px;
  align-items: end;
}
@media (max-width: 880px) { .my-team-form-row { grid-template-columns: 1fr; } }
.my-team-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.my-team-field span { font-size: 12px; font-weight: 600; color: var(--text-muted, var(--muted)); }
.my-team-field input, .my-team-field select {
  width: 100%; padding: 9px 11px; border: 1px solid var(--border);
  border-radius: 8px; background: var(--surface, #fff); font: inherit; color: var(--text, #1a1d26);
}
.my-team-field input:focus, .my-team-field select:focus {
  outline: none; border-color: var(--primary, #1878D0); box-shadow: 0 0 0 3px var(--primary-tint, #e8f1fb);
}
.my-team-optional { color: var(--text-faint, #9aa0aa); font-weight: 400; font-size: 11px; }
.my-team-form-hint { font-size: 11.5px; color: var(--text-faint, var(--muted)); margin: 4px 0 0; }
.my-team-form-hint kbd {
  background: var(--surface, #fff); border: 1px solid var(--border); border-bottom-width: 2px;
  border-radius: 4px; padding: 1px 5px; font-family: inherit; font-size: 10.5px; color: var(--text-muted);
}

/* Banner (replaces alert/dialog) */
.my-team-banner {
  border-radius: 8px; padding: 9px 12px; font-size: 13px;
  display: flex; align-items: center; gap: 8px;
}
.my-team-banner.ok    { background: #e6f4ea; color: #2E7D32; }
.my-team-banner.err   { background: #fdecea; color: #C62828; }
.my-team-banner.info  { background: var(--primary-tint, #e8f1fb); color: var(--primary-dark, #0D5BA6); }
/* warn variant carries the 409 "already-exists → claim to my team" affordance */
.my-team-banner.warn  { background: #FFF7E6; color: #8A5A00; border: 1px solid #F0C875; }

/* List */
.my-team-list { display: flex; flex-direction: column; gap: 6px; }
.my-team-row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface, #fff);
  align-items: center;
}
.my-team-row .who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.my-team-row .who .name { font-weight: 600; color: var(--text, var(--heading)); font-size: 14px; }
.my-team-row .who .email { font-size: 12px; color: var(--text-muted, var(--muted)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.my-team-row .when { font-size: 11.5px; color: var(--text-faint, var(--muted)); white-space: nowrap; }

.my-team-pill {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: .04em;
}
/* ── Organisations admin page (platform multi-tenant hub) ── */
.orgs-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 12px;
}
.orgs-stat {
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-soft, #f7f8fa);
}
.orgs-stat-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .4px;
  color: var(--text-faint, #9aa0aa);
}
.orgs-stat-value {
  margin-top: 4px;
  font-size: 22px;
  font-weight: 700;
  color: var(--text, var(--heading));
  line-height: 1.15;
}
.orgs-stat-sub {
  margin-top: 4px;
  font-size: 11.5px;
  color: var(--text-muted, var(--muted));
  line-height: 1.35;
}
.orgs-invite-row {
  grid-template-columns: 1.6fr 1.2fr 1.4fr auto !important;
}
@media (max-width: 960px) {
  .orgs-invite-row { grid-template-columns: 1fr !important; }
}
.orgs-combo { position: relative; }
.orgs-combo-input {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface, #fff);
  font: inherit;
  color: var(--text, #1a1d26);
}
.orgs-combo-input:focus {
  outline: none;
  border-color: var(--primary, #1878D0);
  box-shadow: 0 0 0 3px var(--primary-tint, #e8f1fb);
}
.orgs-combo-list {
  position: absolute;
  z-index: 40;
  left: 0; right: 0;
  top: calc(100% + 4px);
  max-height: 220px;
  overflow: auto;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 32, 68, .12);
}
.orgs-combo-list.hidden { display: none; }
.orgs-combo-option {
  display: block;
  width: 100%;
  text-align: left;
  border: none;
  background: transparent;
  padding: 8px 10px;
  border-radius: 6px;
  font: inherit;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}
.orgs-combo-option:hover,
.orgs-combo-option.is-active,
.orgs-combo-option:focus-visible {
  background: var(--primary-tint, #e8f1fb);
  color: var(--primary-dark, #0D5BA6);
  outline: none;
}
.orgs-combo-empty {
  padding: 10px;
  font-size: 12.5px;
  color: var(--text-muted, var(--muted));
}
.orgs-list-toolbar { margin-bottom: 10px; }
.orgs-list-search {
  width: 100%;
  max-width: 420px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface, #fff);
  font: inherit;
  color: var(--text);
}
.orgs-list-search:focus {
  outline: none;
  border-color: var(--primary, #1878D0);
  box-shadow: 0 0 0 3px var(--primary-tint, #e8f1fb);
}
.orgs-list { display: flex; flex-direction: column; gap: 8px; }
.orgs-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface, #fff);
  overflow: hidden;
}
.orgs-card.is-archived { opacity: .72; }
.orgs-card-head {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
  align-items: start;
  padding: 12px 14px;
  cursor: pointer;
  border: none;
  width: 100%;
  background: transparent;
  text-align: left;
  font: inherit;
  color: inherit;
}
.orgs-card-head:hover { background: var(--bg-soft, #f7f8fa); }
.orgs-card-head:focus-visible {
  outline: 2px solid var(--primary, #1878D0);
  outline-offset: -2px;
}
.orgs-card-title {
  font-weight: 700;
  font-size: 15px;
  color: var(--text, var(--heading));
}
.orgs-card-sub {
  margin-top: 3px;
  font-size: 12px;
  color: var(--text-muted, var(--muted));
  line-height: 1.4;
}
.orgs-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: flex-end;
  align-items: center;
}
.orgs-card-body {
  border-top: 1px solid var(--border);
  padding: 12px 14px 14px;
  background: var(--bg-soft, #f7f8fa);
}
.orgs-card-body.hidden { display: none; }
.orgs-roles {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 10px;
}
.orgs-role-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11.5px;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  color: var(--text-muted, var(--muted));
}
.orgs-role-chip b { color: var(--text); font-weight: 700; }
.orgs-member-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 10px;
  align-items: center;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface, #fff);
  margin-bottom: 6px;
}
.orgs-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

/* Mixed-case role + org label (e.g. "organisation - Famedico - Admin").
   Not a pill — text-transform:none so org names keep their casing. */
.my-team-role-label {
  display: inline-flex; align-items: center;
  font-size: 12px; font-weight: 600; padding: 2px 0;
  color: var(--text-muted, #64748b);
  text-transform: none; letter-spacing: 0;
  white-space: nowrap; max-width: 280px;
  overflow: hidden; text-overflow: ellipsis;
}
.my-team-pill.role-developer { background: #e8f1fb; color: #1878D0; }
.my-team-pill.role-tester    { background: #f3e5f5; color: #6A1B9A; }
.my-team-pill.role-prompter  { background: #fff3e0; color: #E65100; }
.my-team-pill.role-support   { background: #e0f2f1; color: #00796B; }
.my-team-pill.role-admin     { background: #fce4ec; color: #C62828; }
.my-team-pill.role-sales     { background: #e6f4ea; color: #1B5E20; }
.my-team-pill.role-marketing { background: #fff8e1; color: #B26500; }
.my-team-pill.status-pending   { background: #fff8e1; color: #b26500; }
.my-team-pill.status-approved  { background: #e8f1fb; color: #1878D0; }
.my-team-pill.status-rejected  { background: #fdecea; color: #C62828; }
.my-team-pill.status-joined    { background: #e6f4ea; color: #2E7D32; }
.my-team-pill.status-cancelled { background: #f0f0f0; color: #6b7280; }
.my-team-empty { padding: 14px; text-align: center; font-style: italic; color: var(--text-muted, var(--muted)); }

/* Sidebar dot for "you have a pending request" */
.my-team-pending-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent, #E8578A); margin-left: 6px; flex-shrink: 0;
}

/* ============================================================
   Admin pane: pending invite-requests queue
   ============================================================ */
.admin-req-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
/* Signup approvals can get long (we've seen 70+ at once after the backfill).
   Cap the height and let the list scroll internally so the Admin modal stays
   compact and the sections below (Pending agents / Prompt approvals / Auto-
   approve) remain reachable without scrolling past hundreds of rows. */
#adminSignupReqList {
  max-height: 420px;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 6px;            /* breathing room for the scrollbar gutter */
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px;
  padding: 8px;
  background: var(--surface-sunk, rgba(0,0,0,0.02));
}
.admin-req-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface, #fff);
  align-items: center;
}
.admin-req-row .req-line { font-size: 13px; color: var(--text, var(--heading)); }
.admin-req-row .req-line .who { font-weight: 600; }
.admin-req-row .req-line .arrow { color: var(--text-faint, var(--muted)); margin: 0 6px; }
.admin-req-row .req-line .invitee { font-weight: 600; color: var(--text, var(--heading)); }
.admin-req-row .req-meta { font-size: 11px; color: var(--text-muted, var(--muted)); margin-top: 3px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.admin-req-actions { display: inline-flex; gap: 6px; align-items: center; }
.admin-req-actions input[type="text"] {
  padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; font: inherit;
  width: 180px;
}
/* ─── My Team · Bulk import (spreadsheet upload) ─────────────────── */
.my-team-bulk-tabs { display: flex; gap: 6px; margin-bottom: 10px; border-bottom: 1px solid var(--border); }
.my-team-bulk-tab {
  appearance: none; background: transparent; border: none;
  padding: 8px 14px; font: inherit; font-size: 13px; font-weight: 600;
  color: var(--text-muted, var(--muted)); cursor: pointer;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.my-team-bulk-tab.is-active { color: var(--primary, #1878D0); border-bottom-color: var(--primary, #1878D0); }
.my-team-bulk-source textarea, .my-team-bulk-source input[type="url"], .my-team-bulk-source input[type="text"] {
  width: 100%; padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface, #fff); color: var(--text); font: inherit;
}
.bulk-preview-head { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-size: 12.5px; color: var(--text-muted, var(--muted)); margin-bottom: 8px; }
.bulk-preview-head code { background: rgba(0,0,0,0.05); padding: 1px 5px; border-radius: 4px; font-size: 11.5px; }
.bulk-summary { display: flex; gap: 6px; flex-wrap: wrap; align-items: flex-start; }
.bulk-pill {
  display: inline-block; padding: 2px 9px; border-radius: 10px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.2px;
}
.bulk-pill.ok   { background: #e6f4ea; color: #2E7D32; }
.bulk-pill.skip { background: #fff3e0; color: #B26500; }
.bulk-pill.err  { background: #fdecea; color: #C62828; }
.bulk-table-wrap { max-height: 360px; overflow: auto; border: 1px solid var(--border); border-radius: 6px; margin-top: 8px; }
.bulk-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.bulk-table th, .bulk-table td { padding: 6px 8px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; }
.bulk-table thead th { background: var(--surface, #fafafa); position: sticky; top: 0; z-index: 1; font-weight: 700; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--text-muted, var(--muted)); }
.bulk-table tr.bulk-skip td { opacity: 0.65; }
.bulk-table tr.bulk-err  td { background: rgba(220, 38, 38, 0.04); }
.bulk-note { font-size: 11px; color: var(--text-muted, var(--muted)); margin-top: 3px; }
.bulk-actions { display: flex; gap: 10px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
.bulk-expires { font-size: 11px; color: var(--text-muted, var(--muted)); margin-left: auto; }
.bulk-link { color: var(--primary, #1878D0); font-size: 11.5px; text-decoration: underline; }
.bulk-link:hover { text-decoration: none; }

/* CSV upload-button row above the textarea. */
.my-team-bulk-csv-actions {
  display: flex; gap: 10px; align-items: center; margin-bottom: 6px; flex-wrap: wrap;
}
.my-team-bulk-csv-actions .btn { display: inline-flex; gap: 5px; align-items: center; }
.my-team-bulk-file-name { font-size: 12px; color: var(--text-muted, var(--muted)); }

/* Field-mapping card sits between the source summary and the preview table. */
.bulk-mapping-card {
  background: rgba(0, 120, 191, 0.05);
  border: 1px solid rgba(0, 120, 191, 0.18);
  border-radius: 8px;
  padding: 10px 12px;
  margin: 10px 0;
}
.bulk-mapping-head {
  display: flex; justify-content: space-between; gap: 12px;
  font-size: 12.5px; margin-bottom: 8px; flex-wrap: wrap;
}
.bulk-mapping-hint { color: var(--text-muted, var(--muted)); font-size: 11.5px; }
.bulk-mapping-grid {
  display: grid; grid-template-columns: 1fr 1fr 1fr auto;
  gap: 10px; align-items: end;
}
.bulk-mapping-grid-4 { grid-template-columns: 1fr 1fr 1fr 1fr auto; }
.bulk-remap-btn { white-space: nowrap; }
.bulk-mapping-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 11.5px; color: var(--text-muted, var(--muted)); font-weight: 600; }
.bulk-mapping-grid label .req { color: var(--danger, #C62828); }
.bulk-mapping-grid select {
  padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface, #fff); color: var(--text); font: inherit; font-size: 12.5px;
}
.bulk-mapping-grid button { padding: 7px 12px; white-space: nowrap; }
@media (max-width: 640px) {
  .bulk-mapping-grid { grid-template-columns: 1fr; }
  .bulk-mapping-grid-4 { grid-template-columns: 1fr; }
}

/* Taxonomy summary — departments + roles that this batch references. */
.bulk-taxonomy-card {
  background: rgba(228, 76, 154, 0.04);
  border: 1px solid rgba(228, 76, 154, 0.18);
  border-radius: 8px;
  padding: 10px 12px;
  margin: 0 0 10px 0;
}
.bulk-taxon-group { margin-bottom: 8px; }
.bulk-taxon-group:last-child { margin-bottom: 0; }
.bulk-taxon-title {
  margin: 0 0 6px 0; font-size: 11.5px; font-weight: 700;
  letter-spacing: 0.4px; text-transform: uppercase;
  color: var(--text-muted, var(--muted));
}
.bulk-taxon-items { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.bulk-taxon-item {
  display: inline-flex; gap: 6px; align-items: center;
  padding: 5px 10px; border-radius: 8px;
  background: var(--surface, #fff); border: 1px solid var(--border);
  font-size: 12px;
}
.bulk-taxon-exists { background: rgba(16, 185, 129, 0.08); border-color: rgba(16,185,129,0.25); color: #047857; }
.bulk-taxon-new    { background: rgba(0, 120, 191, 0.08); border-color: rgba(0,120,191,0.25); color: #075985; }
.bulk-taxon-similar {
  background: rgba(245, 158, 11, 0.10); border-color: rgba(245, 158, 11, 0.4); color: #92400E;
  flex-wrap: wrap; padding: 6px 10px;
}
.bulk-taxon-warn { font-size: 14px; }
.bulk-taxon-or { font-size: 10.5px; color: var(--text-muted, var(--muted)); font-style: italic; margin: 0 4px; }
.bulk-taxon-count { font-size: 10px; font-weight: 700; background: rgba(0,0,0,0.08); padding: 1px 6px; border-radius: 8px; }
.bulk-taxon-remap { padding: 3px 6px; border-radius: 5px; border: 1px solid var(--border); background: var(--surface, #fff); font: inherit; font-size: 11.5px; }

/* In-row entity pills (role/dept) */
.bulk-entity { padding: 2px 7px; border-radius: 5px; font-size: 11.5px; }
.bulk-entity-ok   { background: rgba(0,0,0,0.04); color: var(--text); }
.bulk-entity-new  { background: rgba(0, 120, 191, 0.10); color: #075985; font-weight: 600; }
.bulk-entity-warn { background: rgba(245, 158, 11, 0.15); color: #92400E; font-weight: 600; }
.bulk-cell-empty  { color: var(--text-muted, var(--muted)); font-style: italic; }
.bulk-created     { padding: 6px 10px; background: rgba(0,120,191,0.06); border-radius: 6px; margin-bottom: 6px; font-size: 12px; }

.admin-req-empty {
  padding: 14px; text-align: center; font-style: italic; color: var(--text-muted, var(--muted));
  border: 1px dashed var(--border); border-radius: 8px; margin-bottom: 14px;
}

/* ============================================================
   Wireframe React-artifact rendering — live iframe inside a card.
   ============================================================ */
.wireframe-live-wrap {
  position: relative;
  display: block;
  width: 100%;
  border-radius: 8px;
  background: #fff;
  border: 1px solid var(--border);
  overflow: hidden;
}
.wireframe-iframe {
  display: block;
  width: 100%;
  border: 0;
  background: #fff;
}
.wireframe-live-badge {
  position: absolute;
  top: 6px;
  right: 6px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 3px 8px;
  border-radius: 999px;
  pointer-events: none;
  z-index: 1;
}
.note-editor-code-preview {
  margin-top: 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: #fff;
  overflow: hidden;
  min-height: 200px;
}
.note-editor-code-preview .wireframe-iframe { min-height: 380px; }

/* Code textarea: monospace + Tab-friendly */
#noteEditorCode {
  width: 100%;
  min-height: 200px;
  resize: vertical;
}

/* ===== Wireframes: Render-all status banner + per-card render row ===== */
.wireframes-render-status {
  margin: 8px 0 12px;
  padding: 8px 12px;
  border-radius: 8px;
  background: var(--primary-tint, #e8f1fb);
  color: var(--primary-dark, #0D5BA6);
  font-size: 13px;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 8px;
}
.wireframe-render-row {
  margin-top: 10px;
  display: flex;
  justify-content: flex-start;
}
.wireframe-render-row .btn.is-rendering {
  opacity: 0.85;
  cursor: progress;
}

/* ===== Task-group create-time pickers ===== */
.taskgroup-pick-row {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.taskgroup-pick-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-muted, #6b7280);
}
.taskgroup-pick-label { font-weight: 500; }
.taskgroup-pick-label strong { color: var(--text, var(--heading)); font-weight: 700; }
.taskgroup-pick-hint { font-size: 11px; color: var(--text-faint, #9aa0aa); margin-left: 4px; }
.taskgroup-pick-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 8px;
  background: var(--surface-sunk, #f6f9fd);
  border: 1px solid var(--border);
  border-radius: 8px;
  min-height: 44px;
}
.taskgroup-pick-chip {
  appearance: none;
  border: 1px solid var(--border);
  background: var(--surface, #fff);
  color: var(--text-muted, #6b7280);
  border-radius: 999px;
  padding: 5px 11px;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 120ms, color 120ms, border-color 120ms;
}
.taskgroup-pick-chip:hover {
  border-color: var(--primary, #1878D0);
  color: var(--primary, #1878D0);
}
.taskgroup-pick-chip.selected {
  background: var(--primary, #1878D0);
  border-color: var(--primary, #1878D0);
  color: #fff;
}
.taskgroup-pick-chip:focus-visible {
  outline: 2px solid var(--primary, #1878D0);
  outline-offset: 2px;
}
.taskgroup-pick-empty {
  font-style: italic;
  font-size: 12px;
  color: var(--text-faint, #9aa0aa);
  padding: 4px 6px;
}
.taskgroup-create-actions {
  /* Prominent-but-normal-flow action bar for the create-form CTA.
   * History: originally styled sticky (24 Jul 2026 · Jaseena "can't
   * find execute button" fix), but sticky + z-index intercepted
   * clicks on the "Open chat" button beneath the group-card list —
   * so reverted to normal flow, with prominent visual weight instead.
   */
  margin-top: 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--surface-sunk, #f6f9fd);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.taskgroup-create-hint {
  flex: 1 1 auto;
  font-size: 12px;
  color: var(--text-faint, #9aa0aa);
}
/* Weight the primary CTA so it reads unambiguously as the next
 * step to fire — even in the normal-flow position it stands out. */
.taskgroup-create-actions #tgCreateBtn {
  font-weight: 700;
  padding: 8px 16px;
}

/* ===== My Chats — task-group chat list ===== */
#myChatsView {
  display: flex; flex-direction: column; height: 100%;
  background: var(--bg, var(--surface, #f6f9fd)); overflow: hidden;
}
#myChatsHeader {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 22px; border-bottom: 1px solid var(--border);
  background: var(--surface, #fff); flex-shrink: 0;
}
.my-chats-body { flex: 1 1 auto; overflow: auto; padding: 22px; }
.my-chats-list { display: flex; flex-direction: column; gap: 8px; max-width: 760px; }
.my-chats-row {
  appearance: none; background: var(--surface, #fff);
  border: 1px solid var(--border); border-radius: 10px;
  padding: 12px 14px; display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 12px; align-items: center;
  cursor: pointer; text-align: left;
  font: inherit; color: inherit;
  transition: border-color 120ms, background-color 120ms;
}
.my-chats-row:hover {
  border-color: var(--primary, #1878D0);
  background: var(--primary-tint, #e8f1fb);
}
.my-chats-row:focus-visible {
  outline: 2px solid var(--primary, #1878D0); outline-offset: 2px;
}
.my-chats-row-ic {
  width: 34px; height: 34px;
  border-radius: 8px;
  background: var(--primary-tint, #e8f1fb);
  color: var(--primary, #1878D0);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.my-chats-row-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.my-chats-row-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.my-chats-row-name {
  font-weight: 600; font-size: 14.5px; color: var(--text, var(--heading));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.my-chats-row-desc {
  font-size: 12.5px; color: var(--text-muted, var(--muted));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.my-chats-row-meta {
  font-size: 11.5px; color: var(--text-faint, var(--muted));
  font-variant-numeric: tabular-nums;
}
.my-chats-row-arrow {
  font-size: 22px; color: var(--text-faint, #9aa0aa); padding: 0 6px;
}
.my-chats-count-badge {
  margin-left: auto;
  background: var(--primary, #1878D0);
  color: #fff;
  font-size: 11px; font-weight: 700;
  padding: 1px 7px; border-radius: 999px;
  font-variant-numeric: tabular-nums;
}

/* ===== Fullscreen task-group chat (launched from My Chats) =====
   When #myTeamView has .chat-fullscreen, hide every other card in the
   My Team body and let #taskGroupChat fill the available middle column. */
#myTeamView.chat-fullscreen .my-team-body > *:not(#taskGroupChat) { display: none !important; }
#myTeamView.chat-fullscreen .my-team-body { padding: 0; }
#myTeamView.chat-fullscreen #taskGroupChat {
  border: 0;
  border-radius: 0;
  margin: 0;
  height: calc(100vh - 60px); /* leave room for the My Team header */
  display: flex;
  flex-direction: column;
}
#myTeamView.chat-fullscreen #taskGroupChat .taskgroup-messages {
  flex: 1 1 auto;
  min-height: 0;
}
#myTeamView.chat-fullscreen #myTeamHeader, #myOrgHeader { background: var(--surface-sunk, #f6f9fd); }

/* ============================================================
   Admin approvals gate — full-screen blocking modal that
   appears on app load (admin only) when there are pending
   team invites, agents, or developer prompts to review.
   No Esc / no outside-click close. Auto-closes when empty.
   ============================================================ */
body.admin-gate-locked { overflow: hidden; }
.admin-gate-backdrop {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.72);
  z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  backdrop-filter: blur(4px);
}
.admin-gate-backdrop.hidden { display: none; }
.admin-gate-shell {
  background: var(--surface, #fff);
  color: var(--text, #1a1d26);
  border-radius: 14px;
  width: 100%;
  max-width: 880px;
  max-height: calc(100vh - 48px);
  display: flex; flex-direction: column;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
  overflow: hidden;
}
.admin-gate-head {
  padding: 18px 22px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: flex-start; gap: 14px;
  background: linear-gradient(180deg, var(--surface) 0%, var(--surface-sunk, #f6f9fd) 100%);
}
.admin-gate-title-wrap { flex: 1 1 auto; min-width: 0; }
.admin-gate-head h2 {
  margin: 0; font-size: 17px; font-weight: 700;
  color: var(--text, var(--heading));
  display: flex; align-items: center; gap: 8px;
}
.admin-gate-head h2::before {
  content: '🔔'; font-size: 16px;
}
.admin-gate-sub {
  margin: 4px 0 0; font-size: 12.5px; color: var(--text-muted, var(--muted));
  display: flex; align-items: center; gap: 6px;
}
.admin-gate-counts {
  background: var(--accent, #E8578A); color: #fff;
  font-size: 12px; font-weight: 700;
  padding: 5px 11px; border-radius: 999px;
  flex-shrink: 0;
}
.admin-gate-body {
  flex: 1 1 auto;
  overflow: auto;
  padding: 8px 22px 14px;
  display: flex; flex-direction: column; gap: 14px;
}
.admin-gate-section { display: flex; flex-direction: column; gap: 6px; }
.admin-gate-section.hidden { display: none; }
.admin-gate-section-head {
  display: flex; align-items: baseline; gap: 8px;
  padding: 8px 0 4px;
  border-bottom: 1px dashed var(--border);
}
.admin-gate-section-title {
  font-size: 12px; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--text-muted, var(--muted));
}
.admin-gate-section-count {
  background: var(--primary-tint, #e8f1fb);
  color: var(--primary-dark, #0D5BA6);
  font-size: 11px; font-weight: 700;
  padding: 1px 8px; border-radius: 999px;
  font-variant-numeric: tabular-nums;
}
.admin-gate-section-list { display: flex; flex-direction: column; gap: 6px; }
.admin-gate-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 10px; align-items: center;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface, #fff);
  transition: opacity 200ms, transform 200ms;
}
.admin-gate-row.resolving { opacity: 0; transform: translateX(20px); }
.admin-gate-row-text { min-width: 0; }
.admin-gate-row-main {
  font-size: 13.5px; font-weight: 600; color: var(--text, var(--heading));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.admin-gate-row-sub {
  font-size: 11.5px; color: var(--text-muted, var(--muted));
  margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.admin-gate-note {
  width: 180px; padding: 6px 9px;
  border: 1px solid var(--border); border-radius: 6px;
  font: inherit; font-size: 12.5px;
}
.admin-gate-note:focus {
  outline: none;
  border-color: var(--primary, #1878D0);
  box-shadow: 0 0 0 2px var(--primary-tint, #e8f1fb);
}
.admin-gate-row-actions {
  display: inline-flex; gap: 6px; flex-shrink: 0;
}
.admin-gate-err {
  grid-column: 1 / -1;
  font-size: 12px; color: var(--danger, #C62828);
  padding-top: 4px;
}
.admin-gate-foot {
  padding: 10px 22px;
  border-top: 1px solid var(--border);
  background: var(--surface-sunk, #f6f9fd);
  text-align: center;
}
.admin-gate-footnote { font-size: 11px; color: var(--text-faint, #9aa0aa); }

@media (max-width: 720px) {
  .admin-gate-row { grid-template-columns: 1fr; }
  .admin-gate-note { width: 100%; }
}

/* ===== Chat notification toast (bottom-right) — distinct from #appToastHost
   which floats bottom-CENTER. Each card shows sender · group + a 140-char
   preview, slides in, auto-dismisses after 6s, click opens the chat. ===== */
#chatNotifHost {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 250;
  display: flex; flex-direction: column; gap: 10px;
  pointer-events: none;
  max-width: 360px;
}
.chat-notif {
  pointer-events: auto;
  appearance: none;
  background: var(--surface, #fff);
  color: var(--text, #1a1d26);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary, #1878D0);
  border-radius: 10px;
  padding: 10px 14px;
  font: inherit;
  text-align: left;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(15, 32, 68, 0.18), 0 2px 6px rgba(15, 32, 68, 0.06);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 220ms ease, transform 220ms ease;
  width: 360px; max-width: calc(100vw - 44px);
}
.chat-notif:hover { border-left-color: var(--accent, #E8578A); }
.chat-notif-in  { opacity: 1; transform: translateY(0); }
.chat-notif-out { opacity: 0; transform: translateX(20px); }
.chat-notif-head {
  display: flex; gap: 6px; align-items: baseline;
  font-size: 12.5px; margin-bottom: 4px;
}
.chat-notif-sender {
  font-weight: 700;
  color: var(--text, var(--heading));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60%;
}
.chat-notif-group {
  color: var(--text-muted, var(--muted));
  font-size: 11.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-notif-body {
  font-size: 13px;
  color: var(--text-muted, var(--muted));
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ===== My Chats: per-row unread pill + has-unread highlight ===== */
.my-chats-row.has-unread { border-color: var(--accent, #E8578A); background: var(--surface, #fff); }
.my-chats-row.has-unread .my-chats-row-name { font-weight: 700; }
.my-chats-row-unread {
  background: var(--accent, #E8578A); color: #fff;
  font-size: 11px; font-weight: 700;
  padding: 2px 8px; border-radius: 999px;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}

/* ===== Feedback panel (sales / marketing / support replacement for the chat composer) ===== */
.feedback-panel {
  margin: 0 22px 12px;
  padding: 14px 16px;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent, #E8578A);
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(15, 32, 68, 0.04);
}
.feedback-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 8px;
}
.feedback-title {
  font-size: 13.5px; font-weight: 700;
  color: var(--text, var(--heading));
}
.feedback-form { display: flex; flex-direction: column; gap: 8px; }
#feedbackInput {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit; font-size: 13.5px; line-height: 1.5;
  resize: vertical;
  min-height: 52px;
}
#feedbackInput:focus {
  outline: none;
  border-color: var(--primary, #1878D0);
  box-shadow: 0 0 0 3px var(--primary-tint, #e8f1fb);
}
.feedback-actions {
  display: flex; align-items: center; gap: 12px;
}
.feedback-hint { flex: 1 1 auto; font-size: 11.5px; color: var(--text-faint, #9aa0aa); }
.feedback-hint kbd {
  background: var(--surface, #fff);
  border: 1px solid var(--border); border-bottom-width: 2px;
  border-radius: 4px; padding: 1px 5px;
  font-family: inherit; font-size: 10.5px; color: var(--text-muted);
}
.feedback-flash {
  font-size: 12.5px;
  padding: 6px 10px; border-radius: 6px;
  background: #fdecea; color: #C62828;
}
.feedback-flash.ok { background: #e6f4ea; color: #2E7D32; }

/* ===== Workflow → Role flowchart (Mermaid) ===== */
.flowchart-section {
  margin-top: 22px;
  padding-top: 14px;
  border-top: 1px dashed var(--border);
}
.flowchart-flash {
  margin: 8px 0;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 12.5px;
  background: var(--primary-tint, #e8f1fb);
  color: var(--primary-dark, #0D5BA6);
}
.flowchart-flash.ok  { background: #e6f4ea; color: #2E7D32; }
.flowchart-flash.err { background: #fdecea; color: #C62828; }
.flowchart-preview {
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 10px;
  margin-top: 8px;
  overflow: hidden;
  min-height: 80px;
}
.flowchart-empty {
  padding: 24px; text-align: center; color: var(--text-faint, #9aa0aa);
  font-size: 13.5px;
}
.flowchart-iframe { display: block; width: 100%; border: 0; background: #fff; }
.flowchart-edit-wrap {
  margin-top: 12px;
  background: var(--surface-sunk, #f6f9fd);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
}
.flowchart-edit-summary {
  cursor: pointer;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted, #6b7280);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  user-select: none;
}
.flowchart-code {
  width: 100%;
  margin-top: 8px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  line-height: 1.5;
  resize: vertical;
  background: var(--surface, #fff);
  tab-size: 2;
}
.flowchart-code:focus {
  outline: none;
  border-color: var(--primary, #1878D0);
  box-shadow: 0 0 0 3px var(--primary-tint, #e8f1fb);
}
.flowchart-hint {
  margin-top: 6px;
  font-size: 11px;
  color: var(--text-faint, #9aa0aa);
}
.flowchart-hint kbd {
  background: var(--surface, #fff);
  border: 1px solid var(--border); border-bottom-width: 2px;
  border-radius: 4px; padding: 1px 5px;
  font-family: inherit; font-size: 10.5px; color: var(--text-muted);
}

/* ===== Masters — admin reference-data editor ===== */
#mastersView {
  display: flex; flex-direction: column; height: 100%;
  background: var(--bg, var(--surface, #f6f9fd)); overflow: hidden;
}
#mastersHeader {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; row-gap: 8px; flex-wrap: wrap;
  padding: 14px 22px; border-bottom: 1px solid var(--border);
  background: var(--surface, #fff); flex-shrink: 0;
}
.masters-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: 1100px;
  scrollbar-width: thin;
}
.masters-roles-list { display: flex; flex-direction: column; gap: 6px; }

/* Masters sub-section tabs (Departments / Roles / Permissions) */
.masters-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.masters-tab {
  appearance: none; background: transparent; border: none;
  padding: 10px 16px; font: inherit; font-size: 14px; font-weight: 600;
  color: var(--text-muted, var(--muted)); cursor: pointer;
  border-bottom: 3px solid transparent; margin-bottom: -1px;
  transition: color 0.15s, border-color 0.15s;
}
.masters-tab:hover { color: var(--text); }
.masters-tab.is-active { color: var(--primary, #0078BF); border-bottom-color: var(--primary, #0078BF); }
.masters-panel.hidden { display: none; }
.masters-show-archived {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--text-muted, var(--muted));
  margin: 4px 0 10px 0; cursor: pointer;
}
.masters-show-archived input[type="checkbox"] { margin: 0; }

/* CRUD table (departments + team roles) */
.masters-table-wrap { overflow: auto; border: 1px solid var(--border); border-radius: 6px; }
.masters-crud-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.masters-crud-table th, .masters-crud-table td { padding: 8px 12px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: middle; }
.masters-crud-table thead th { background: var(--surface, #fafafa); font-weight: 700; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--text-muted, var(--muted)); }
.masters-crud-table tr.is-archived td { opacity: 0.55; }
.masters-crud-table tr.is-builtin td { background: rgba(0, 120, 191, 0.025); }
.masters-crud-table code { background: rgba(0,0,0,0.05); padding: 1px 5px; border-radius: 4px; font-size: 11.5px; }
.masters-crud-table .actions-col { width: 1%; white-space: nowrap; text-align: right; }
.masters-status { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 700; }
.masters-status.active   { background: rgba(16, 185, 129, 0.12); color: #047857; }
.masters-status.archived { background: rgba(0, 0, 0, 0.06); color: var(--text-muted, var(--muted)); }
.masters-status.builtin  { background: rgba(0, 120, 191, 0.12); color: #075985; }
.masters-act {
  appearance: none; background: transparent; border: 1px solid var(--border);
  border-radius: 5px; padding: 4px 8px; font-size: 13px; cursor: pointer; margin-left: 3px;
}
.masters-act:hover:not([disabled]) { background: rgba(0, 0, 0, 0.04); }
.masters-act.danger:hover:not([disabled]) { background: rgba(220, 38, 38, 0.08); border-color: rgba(220, 38, 38, 0.3); }
.masters-act[disabled], .masters-act.disabled { opacity: 0.35; cursor: not-allowed; }

/* Permissions matrix */
.masters-perms-wrap { overflow: auto; }
.masters-perms-table {
  border-collapse: collapse;
  font-size: 13px;
  background: var(--surface, #fff);
  width: 100%;
  min-width: 720px;
}
.masters-perms-table th,
.masters-perms-table td {
  padding: 8px 10px;
  text-align: center;
  border: 1px solid var(--border);
  white-space: nowrap;
}
.masters-perms-table thead th {
  background: var(--surface-sunk, #f6f9fd);
  font-weight: 600;
  color: var(--text-muted, #6b7280);
  font-size: 12px;
  position: sticky; top: 0;
}
.masters-perms-table th.masters-perms-roleh {
  text-align: left;
  position: sticky;
  left: 0;
  background: var(--surface, #fff);
  z-index: 1;
}
.masters-perms-cell input[type="checkbox"] {
  width: 16px; height: 16px;
  cursor: pointer;
  accent-color: var(--primary, #1878D0);
}
.masters-perms-cell.is-dirty {
  background: var(--primary-tint, #e8f1fb);
}
.masters-perms-actions {
  display: flex; gap: 8px; justify-content: flex-end;
  margin-top: 10px;
}

/* ===== Sidebar menu accordion (frees space for the Threads list) ===== */
.sidebar-menu-toggle {
  display: flex; align-items: center; gap: 6px;
  margin: 6px 12px 4px;
  padding: 5px 9px;
  background: transparent;
  border: 1px solid var(--border, #2a2d3a);
  border-radius: 6px;
  color: var(--text-faint, #6b7280);
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 120ms, color 120ms, border-color 120ms;
}
.sidebar-menu-toggle:hover {
  background: var(--surface-sunk, rgba(255,255,255,0.05));
  color: var(--text, var(--heading));
  border-color: var(--primary, #1878D0);
}
.sidebar-menu-toggle .sidebar-menu-chev {
  transition: transform 180ms;
  flex-shrink: 0;
}
.sidebar-menu-toggle.is-collapsed .sidebar-menu-chev { transform: rotate(-90deg); }
.sidebar-menu-toggle:focus-visible { outline: 2px solid var(--primary, #1878D0); outline-offset: 1px; }

.sidebar-menu {
  display: flex;
  flex-direction: column;
  /* Never get squeezed by the threadList sibling. The whole menu must always
     render at its natural height when expanded, and shrink to 0 only when the
     .collapsed class is applied. */
  flex-shrink: 0;
  transition: max-height 240ms ease, opacity 180ms ease, margin 180ms ease;
}

/* ═══════════════════════════════════════════════════════════════════════
   Sidebar menu inline search (added 8 Jun 2026)
   ─────────────────────────────────────────────────────────────────────
   Compact text input pinned at the top of #sidebarMenu so a long menu
   becomes navigable without scrolling. Filters all .sidebar-dashboard-btn
   and .sidebar-submenu-btn children in real time. See app.js
   `initSidebarMenuSearch()` for the filter logic.
   ─────────────────────────────────────────────────────────────────── */
.sidebar-menu-search-wrap {
  position: relative;
  margin: 4px 12px 8px;
  display: flex;
  align-items: center;
}
/* Variant — when the search lives at the top of .sidebar-scroll (above the
   Menu disclosure) rather than inside the Menu list. Slightly more top
   margin separates it cleanly from the sidebar <header>. */
.sidebar-global-search-wrap {
  margin: 8px 12px 10px;
}
/* Variant — threads-only search input that sits directly under the
   "Threads" accordion toggle. Tighter top/bottom margin so it tucks
   right under the header without breaking the sidebar density. */
.sidebar-threads-search-wrap {
  margin: 2px 12px 8px;
  gap: 6px;
}

/* ═══════════════════════════════════════════════════════════════════════
   Thread-marker button + popover (added 10 Jul 2026)
   ─────────────────────────────────────────────────────────────────────
   Compact button that sits IMMEDIATELY BEFORE the "Search threads…"
   input inside .sidebar-threads-search-wrap. Same visual grammar as the
   search input (matching border-radius, background, hover/focus tint) so
   it reads as a peer control, not a foreign element. Click opens the
   popover below, which lets the user (a) filter the sidebar list by a
   marker, or (b) assign / clear the marker on the currently-open thread.
   Marker registry (21 emoji labels + 7 colour dots) lives in app.js.
   ─────────────────────────────────────────────────────────────────── */
.sidebar-thread-marker-btn {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-sunk, rgba(255,255,255,0.04));
  border: 1px solid var(--border, #2a2d3a);
  border-radius: 6px;
  color: var(--text, #e5e7eb);
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  transition: background-color 120ms, border-color 120ms, transform 120ms;
}
.sidebar-thread-marker-btn:hover {
  background: var(--surface, rgba(255,255,255,0.09));
  border-color: var(--primary, #1878D0);
}
.sidebar-thread-marker-btn:focus-visible {
  outline: 2px solid var(--primary, #1878D0);
  outline-offset: 1px;
}
.sidebar-thread-marker-btn:active { transform: scale(0.94); }
/* When the filter is active OR the current thread has a marker, the
   button lights up so the state is visible at a glance. Also swaps the
   glyph via JS (state → picks glyph from active marker). */
.sidebar-thread-marker-btn.is-active {
  background: rgba(24, 120, 208, 0.18);
  border-color: var(--primary, #1878D0);
  color: #fff;
}
.sidebar-thread-marker-btn.is-filtering {
  background: rgba(228, 76, 154, 0.20);
  border-color: var(--secondary, #E44C9A);
}
.sidebar-thread-marker-glyph {
  display: inline-block;
  font-size: 14px;
  line-height: 1;
}

/* Marker popover styles retained but unused — button/popover removed 22 Jul 2026. */
.thread-marker-popover {
  position: fixed;
  z-index: 500;
  min-width: 280px;
  max-width: 320px;
  background: var(--surface, #111827);
  border: 1px solid var(--border, #2a2d3a);
  border-radius: 8px;
  padding: 10px 12px 12px;
  box-shadow: 0 12px 32px rgba(0,0,0,0.45);
  color: var(--text, #e5e7eb);
  font-size: 12.5px;
  animation: thread-marker-popover-in 140ms ease-out;
}
.thread-marker-popover[hidden] { display: none !important; }
@keyframes thread-marker-popover-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.thread-marker-popover-mode {
  display: flex;
  gap: 4px;
  padding: 2px;
  background: var(--surface-sunk, rgba(255,255,255,0.04));
  border-radius: 6px;
  margin-bottom: 8px;
}
.thread-marker-mode-tab {
  flex: 1;
  padding: 5px 8px;
  background: transparent;
  border: none;
  border-radius: 4px;
  color: var(--text-faint, #94a3b8);
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  transition: background-color 120ms, color 120ms;
}
.thread-marker-mode-tab:hover { color: var(--text, #e5e7eb); }
.thread-marker-mode-tab.is-active {
  background: var(--primary, #1878D0);
  color: #fff;
  font-weight: 600;
}
.thread-marker-popover-hint {
  font-size: 11px;
  color: var(--text-faint, #94a3b8);
  margin-bottom: 8px;
  line-height: 1.35;
}
.thread-marker-popover-hint[hidden] { display: none !important; }
.thread-marker-popover-section + .thread-marker-popover-section { margin-top: 8px; }
.thread-marker-popover-heading {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-faint, #94a3b8);
  margin-bottom: 5px;
}
.thread-marker-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
.thread-marker-cell {
  min-height: 44px;
  padding: 6px 8px;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  background: var(--surface-sunk, rgba(255,255,255,0.04));
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--text, #e5e7eb);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  transition: background-color 120ms, border-color 120ms, transform 120ms;
}
.thread-marker-cell-label {
  font-size: 10px;
  line-height: 1.15;
  color: var(--text-faint, #94a3b8);
  text-align: center;
  font-weight: 500;
}
.thread-marker-cell:hover .thread-marker-cell-label {
  color: var(--text, #e5e7eb);
}
.thread-marker-cell.is-selected .thread-marker-cell-label {
  color: #fff;
}
.thread-marker-cell:hover {
  background: var(--surface, rgba(255,255,255,0.10));
  border-color: var(--primary, #1878D0);
  transform: translateY(-1px);
}
.thread-marker-cell:focus-visible {
  outline: 2px solid var(--primary, #1878D0);
  outline-offset: 1px;
}
.thread-marker-cell.is-selected {
  background: rgba(24, 120, 208, 0.30);
  border-color: var(--primary, #1878D0);
  box-shadow: 0 0 0 1px var(--primary, #1878D0) inset;
}
.thread-marker-popover-footer {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--border, #2a2d3a);
}
.thread-marker-clear-btn,
.thread-marker-close-btn {
  padding: 5px 10px;
  background: transparent;
  border: 1px solid var(--border, #2a2d3a);
  border-radius: 5px;
  color: var(--text-faint, #94a3b8);
  cursor: pointer;
  font: inherit;
  font-size: 11.5px;
  transition: background-color 120ms, color 120ms, border-color 120ms;
}
.thread-marker-clear-btn:hover {
  background: rgba(228, 76, 154, 0.12);
  border-color: var(--secondary, #E44C9A);
  color: var(--secondary, #E44C9A);
}
.thread-marker-close-btn:hover {
  background: rgba(24, 120, 208, 0.14);
  border-color: var(--primary, #1878D0);
  color: var(--text, #e5e7eb);
}

/* Marker prefix inside a thread-row title (sidebar list) and inside
   the conversation-header title + folder-panel entries. Small tap on
   its own to keep the marker visually decoupled from the text. */
.thread-marker-prefix {
  display: inline-block;
  margin-right: 5px;
  font-size: 1em;
  line-height: 1;
  vertical-align: -1px;
}
.thread-marker-prefix.header-size {
  font-size: 1.05em;
  margin-right: 6px;
}

/* Mobile / narrow-sidebar responsive tweak — keep the button + popover
   comfortable on small viewports. */
@media (max-width: 480px) {
  .thread-marker-popover {
    min-width: 240px;
    max-width: calc(100vw - 24px);
    padding: 9px 10px 10px;
  }
  .thread-marker-grid,
  .thread-marker-grid.is-dots {
    grid-template-columns: repeat(6, 1fr);
  }
  .sidebar-thread-marker-btn {
    width: 24px;
    height: 24px;
  }
}
/* Filter-state classes used by the threads-only search to hide non-
   matching folder groups and thread rows in-place. The `display:none`
   is set inline as a defensive fallback; the class is what we toggle
   so tests + other code can detect filter state. */
#threadList li.thread-search-hidden { display: none !important; }
#threadList > li.thread-search-empty {
  padding: 10px 12px;
  color: var(--text-faint, #94a3b8);
  text-align: center;
  font-size: 12.5px;
  cursor: default;
}
.sidebar-menu-search-icon {
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-faint, #6b7280);
  pointer-events: none;
}
.sidebar-menu-search-input {
  width: 100%;
  padding: 6px 24px 6px 28px;
  background: var(--surface-sunk, rgba(255,255,255,0.04));
  border: 1px solid var(--border, #2a2d3a);
  border-radius: 6px;
  color: var(--text, var(--heading, #e5e7eb));
  font: inherit;
  font-size: 12.5px;
  outline: none;
  transition: border-color 120ms, background-color 120ms;
  /* Strip the native search-input clear "×" — we render our own */
  -webkit-appearance: none;
  appearance: none;
}
.sidebar-menu-search-input::-webkit-search-cancel-button { display: none; }
.sidebar-menu-search-input::placeholder {
  color: var(--text-faint, #6b7280);
  opacity: 0.9;
}
.sidebar-menu-search-input:focus {
  border-color: var(--primary, #1878D0);
  background: var(--surface, rgba(255,255,255,0.06));
}
.sidebar-menu-search-clear {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: none;
  color: var(--text-faint, #6b7280);
  font-size: 16px;
  line-height: 1;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background-color 120ms, color 120ms;
}
.sidebar-menu-search-clear:hover {
  background: var(--surface-sunk, rgba(255,255,255,0.08));
  color: var(--text, #e5e7eb);
}
/* Hide a button or submenu when the search filter doesn't match. Inline
   `style="display:none"` would clash with the existing `.hidden` admin gate,
   so we use our own class. */
.sidebar-search-hidden { display: none !important; }
/* When the search has a value AND the user has expanded a submenu via the
   filter, force-show it (submenu uses `hidden` attribute by default; this
   wins over the attribute via attribute selector + !important). */
.sidebar-submenu.sidebar-search-force-open[hidden] {
  display: flex !important;
}
/* Empty-state hint when the search matches nothing. JS toggles `is-empty`
   on the wrap and reads aria-live region for screen readers. */
.sidebar-menu-search-wrap.is-empty::after {
  content: "no matches — press Esc";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  margin-top: 4px;
  padding: 6px 10px;
  font-size: 11px;
  color: var(--text-faint, #6b7280);
  text-align: center;
  font-style: italic;
  pointer-events: none;
}
.sidebar-menu.collapsed {
  /* Only override flow when collapsed — keeps the base state spacious. */
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  margin: 0;
  pointer-events: none;
}

/* Shared "section toggle" style for both Menu and Threads headers. */
.sidebar-section-toggle {
  margin-top: 8px;
}

/* Threads accordion. Mirrors .sidebar-menu — base state takes natural height,
   `.collapsed` shrinks to 0. Scrolling is handled by the outer
   `.sidebar-scroll` parent (one scroll surface for menu + threads). */
#threadList {
  transition: max-height 240ms ease, opacity 180ms ease, margin 180ms ease;
}
#threadList.collapsed {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  margin: 0;
  pointer-events: none;
}

/* ============================================================
   Actions Pending — hero card on dashboard + 3-tab view
   ============================================================ */
.actions-pending-card {
  appearance: none;
  display: flex; align-items: center; gap: 14px;
  width: 100%; max-width: 920px; margin: 12px auto 18px;
  flex-shrink: 0;
  padding: 16px 20px;
  background: linear-gradient(135deg, var(--brand-pink, #E44C9A), var(--brand-teal, #0d7377));
  color: #fff;
  border: none; border-radius: 14px;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 4px 18px rgba(228, 76, 154, 0.18);
  transition: transform 120ms ease, box-shadow 120ms ease;
}
.actions-pending-card:hover { transform: translateY(-2px); box-shadow: 0 6px 22px rgba(228, 76, 154, 0.28); }
.actions-pending-card-icon { font-size: 30px; }
.actions-pending-card-body { display: flex; flex-direction: column; flex: 1; gap: 2px; }
.actions-pending-card-label { font-weight: 700; font-size: 18px; letter-spacing: -0.2px; }
.actions-pending-card-blurb { font-size: 13px; opacity: 0.92; }
.actions-pending-card-count {
  font-weight: 800; font-size: 22px; min-width: 44px;
  text-align: center; padding: 6px 14px;
  background: rgba(255, 255, 255, 0.22);
  border-radius: 999px;
}
.actions-pending-card-count.zero { background: rgba(255, 255, 255, 0.12); font-size: 17px; opacity: 0.7; }

#actionsPendingHeader { display: flex; align-items: center; justify-content: space-between; padding: 14px 20px; border-bottom: 1px solid var(--border, #e2e8f0); }
.actions-pending-tabs { display: flex; gap: 8px; padding: 12px 20px; border-bottom: 1px solid var(--border, #e2e8f0); }
.actions-pending-tab {
  appearance: none; padding: 7px 14px; border-radius: 8px; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 700;
  background: transparent; color: var(--muted, #64748b);
  border: 1px solid var(--border, #e2e8f0);
}
.actions-pending-tab.active {
  background: var(--brand-teal, #0d7377); color: #fff; border-color: var(--brand-teal, #0d7377);
}
.actions-pending-body { padding: 16px 20px; display: flex; flex-direction: column; gap: 18px; }
.actions-pending-loading, .actions-pending-empty, .actions-pending-err {
  color: var(--muted, #64748b); font-size: 14px; padding: 8px 0;
}
.actions-pending-err { color: var(--danger, #c0392b); }
.actions-pending-section { display: flex; flex-direction: column; gap: 8px; }
.actions-pending-section-title {
  font-size: 12px; color: var(--brand-teal, #0d7377);
  font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase;
}
.actions-pending-card-row {
  border: 1px solid var(--border, #e2e8f0); border-radius: 10px;
  padding: 12px 14px; background: var(--surface, #fff);
  display: flex; flex-direction: column; gap: 6px;
  border-left: 4px solid var(--brand-teal, #0d7377);
}
.actions-pending-card-row.task.prio-critical { border-left-color: var(--danger, #c0392b); }
.actions-pending-card-row.task.prio-high { border-left-color: var(--brand-amber, #f59e0b); }
.actions-pending-card-row.meeting { border-left-color: var(--brand-pink, #E44C9A); }
.apc-title { font-weight: 700; font-size: 15px; color: var(--text, #0f172a); }
.apc-desc { color: var(--muted, #64748b); font-size: 13px; line-height: 1.45; }
.apc-meta { display: flex; gap: 10px; flex-wrap: wrap; font-size: 12px; color: var(--muted, #64748b); }
.apc-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.apc-link { font-size: 13px; color: var(--brand-blue, #0078BF); font-weight: 700; text-decoration: none; }
.apc-link:hover { text-decoration: underline; }
.apc-pill { padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 700; color: #fff; background: var(--brand-amber, #f59e0b); }
.apc-pill.prio-critical { background: var(--danger, #c0392b); }
.apc-pill.prio-high { background: var(--brand-amber, #f59e0b); }

.actions-pending-meeting-composer {
  margin: 0 20px 18px; padding: 14px;
  border: 2px solid var(--brand-teal, #0d7377); border-radius: 10px;
  display: flex; flex-direction: column; gap: 10px;
  background: var(--surface, #fff);
}
.actions-pending-meeting-composer.hidden { display: none; }
.actions-pending-meeting-composer input,
.actions-pending-meeting-composer textarea {
  padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 14px;
}
.actions-pending-meeting-composer textarea { resize: vertical; min-height: 50px; }
.apm-row.two { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.apm-row.two label { display: flex; flex-direction: column; gap: 3px; font-size: 12px; color: var(--muted, #64748b); font-weight: 600; }
.apm-err { color: var(--danger, #c0392b); font-size: 12px; }
.apm-actions { display: flex; gap: 8px; justify-content: flex-end; }

/* ============================================================
   Idea Queue — composer + status-grouped list
   ============================================================ */
#ideaQueueHeader,
#myCalendarHeader,
#myMeetingsHeader,
#myTravelPlansHeader,
#myHiringHeader,
#myTeamProfilesHeader,
#agentDispatchesHeader,
#actionsPendingHeader,
#myTasksHeader,
#myTeamHeader, #myOrgHeader, #organisationsHeader,
#myChatsHeader,
#myAgentsHeader,
#myClientsHeader,
#myMarketingWebsitesHeader,
#myMarketingBlogsHeader,
#myMarketingContentPipelineHeader,
#myMessagesHeader,
#myBillingHeader,
#backupsHeader,
#storageHeader,
#trainingLinksHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border, #e2e8f0);
  flex-shrink: 0;
  /* Let the toolbar wrap onto a second row when the title + actions don't
     fit. The .chat-title-wrap inside is min-width:0 so the title truncates
     gracefully instead of pushing the actions off-screen. */
  flex-wrap: wrap;
  row-gap: 8px;
}
.idea-queue-body { padding: 16px 20px; display: flex; flex-direction: column; gap: 18px; }
.idea-queue-composer {
  border: 2px solid var(--brand-amber, #f59e0b);
  border-radius: 12px; padding: 14px 16px;
  display: flex; flex-direction: column; gap: 8px;
  background: var(--surface, #fff);
}
.idea-queue-label {
  font-size: 11px; color: var(--muted, #64748b);
  font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
}
.idea-queue-composer textarea {
  width: 100%; padding: 10px 12px; border-radius: 8px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 14px; line-height: 1.45;
  resize: vertical; min-height: 64px; box-sizing: border-box;
}
.idea-queue-composer-row {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.idea-queue-composer-row select {
  flex: 1 1 220px; min-width: 0;
  padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 14px;
}
.idea-queue-err { color: var(--danger, #c0392b); font-size: 12px; flex: 1; }

/* Inline create/rename thread cluster lives next to the thread <select>.
   When the user is editing a name, the cluster is hidden and the inline-
   edit row takes its place — the surrounding composer (textarea,
   attachments, project pick) stays mounted so no draft state is lost. */
.iq-thread-cluster { display: inline-flex; align-items: center; gap: 6px; flex: 1 1 220px; min-width: 0; }
.iq-thread-cluster select { flex: 1 1 auto; min-width: 0; }
.iq-thread-cluster .btn { flex: 0 0 auto; padding: 6px 10px; }
.iq-thread-edit { display: inline-flex; align-items: center; gap: 6px; flex: 1 1 320px; min-width: 0; }
.iq-thread-edit.hidden { display: none; }
.iq-thread-edit input {
  flex: 1 1 auto; min-width: 0;
  padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 14px;
}
.iq-thread-edit input:focus-visible {
  outline: 2px solid var(--primary, #f59e0b); outline-offset: 2px;
}
.iq-thread-edit .btn { flex: 0 0 auto; padding: 6px 10px; }
.iq-thread-edit-err { color: var(--danger, #c0392b); font-size: 12px; }

/* Tally-style keyboard hint strip below the composer. Tiny, muted, only
   shows what the user can do without lifting their hands. */
.idea-queue-kbd-hints {
  font-size: 11px; color: var(--muted, #64748b);
  margin-top: 4px; line-height: 1.6;
}
.idea-queue-kbd-hints kbd {
  display: inline-block; padding: 1px 6px; min-width: 16px; text-align: center;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px; background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-bottom-width: 2px; border-radius: 4px;
  color: var(--text, #0f172a);
}

/* ─── Idea Queue Phase 3: chips + snooze menu + label input ─── */
.iqc-phase3-chips {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin-top: 6px;
}
.iqc-chip {
  display: inline-flex; align-items: center;
  padding: 1px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600;
  background: rgba(0,0,0,0.06); color: var(--text, #0f172a);
  border: 1px solid rgba(0,0,0,0.08);
}
.iqc-chip-archived { background: rgba(107,114,128,0.16); color: #4b5563; }
.iqc-chip-snoozed  { background: rgba(245,158,11,0.16); color: #b45309; }
.iqc-chip-source   { background: rgba(13,115,119,0.12); color: var(--brand-teal, #0d7377); text-transform: lowercase; }
.iqc-chip-label    { background: rgba(124,58,237,0.12); color: #6d28d9; }
.iqc-snooze-menu {
  position: absolute; z-index: 50;
  margin-top: 4px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px; padding: 4px;
  display: flex; flex-direction: column;
  box-shadow: 0 6px 18px rgba(0,0,0,0.12);
}
.iqc-snooze-menu button {
  appearance: none; background: transparent; border: 0;
  padding: 6px 10px; cursor: pointer; text-align: left;
  font-size: 12.5px; color: var(--text, #0f172a);
  border-radius: 6px;
}
.iqc-snooze-menu button:hover { background: rgba(245,158,11,0.12); }
.iqc-label-input { display: inline-flex; margin-left: 4px; }
.iqc-label-input input {
  padding: 4px 8px; border: 1px solid var(--border, #e2e8f0);
  border-radius: 6px; font: inherit; font-size: 12px;
  background: var(--surface, #fff); color: var(--text, #0f172a);
}

/* ─── Idea Queue: Folder + Thread resolution strip ───
   Sits directly beneath the status pill on each card (per spec). Two
   compact rows; each value either renders live, shows a placeholder
   while unresolved, or shows a red error chip if the dispatcher
   failed to acquire it (never a permanent spinner). */
.iqc-resolution {
  display: flex; flex-direction: column; gap: 3px;
  margin-top: 6px; padding: 6px 8px;
  background: rgba(245, 158, 11, 0.05);
  border: 1px solid rgba(245, 158, 11, 0.18);
  border-radius: 6px;
  font-size: 12px;
}
.iqc-res-row {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.iqc-res-label {
  flex: 0 0 auto;
  color: var(--muted, #64748b);
  font-weight: 600; font-size: 11px;
  letter-spacing: 0.4px; text-transform: uppercase;
  min-width: 52px;
}
.iqc-res-val {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; color: var(--text, #0f172a);
  word-break: break-all;
}
.iqc-res-clickable {
  cursor: pointer;
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}
.iqc-res-clickable:hover { color: var(--brand-amber, #b45309); }
.iqc-res-pending {
  color: var(--muted, #64748b);
  font-style: italic;
  /* Subtle pulse so the placeholder feels live without a spinner. */
  animation: iqcResPulse 1.6s ease-in-out infinite;
}
@keyframes iqcResPulse {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 0.95; }
}
.iqc-res-err {
  color: var(--danger, #c0392b);
  background: rgba(192, 57, 43, 0.08);
  padding: 1px 6px; border-radius: 4px;
  border: 1px solid rgba(192, 57, 43, 0.25);
}
.iqc-res-tag {
  margin-left: 4px;
  font-size: 10px; font-weight: 700;
  padding: 1px 6px; border-radius: 999px;
  background: rgba(16, 185, 129, 0.16); color: #047857;
  letter-spacing: 0.4px; text-transform: uppercase;
}
.iqc-res-tag-target {
  background: rgba(59, 130, 246, 0.16); color: #1d4ed8;
}

/* ─── Idea Queue: dependent / nested ideas ─── */
.iqc-children {
  margin-left: 24px;
  border-left: 2px solid var(--brand-amber, #f59e0b);
  padding-left: 12px;
  margin-top: 4px;
  display: flex; flex-direction: column; gap: 6px;
}
.idea-queue-card.iqc-is-child {
  background: var(--surface, #fff);
  border-left: 3px solid var(--brand-amber, #f59e0b);
}
.iqc-childof {
  font-size: 11px; color: var(--muted, #64748b);
  margin-top: 2px;
}
.iqc-childcount {
  font-size: 11px; color: var(--brand-amber, #b45309);
  font-weight: 600; margin-top: 2px;
}
.iqc-blocked {
  display: inline-block; margin-top: 4px; padding: 2px 8px;
  border-radius: 999px; font-size: 11px; font-weight: 600;
  background: rgba(245, 158, 11, 0.16); color: #b45309;
  border: 1px solid rgba(245, 158, 11, 0.35);
}

/* Per-card inline child-idea composer. */
.iqc-child-composer {
  margin-top: 8px; padding: 10px;
  border: 1px dashed var(--brand-amber, #f59e0b);
  border-radius: 8px; background: rgba(245, 158, 11, 0.04);
  display: flex; flex-direction: column; gap: 6px;
}
.iqc-cc-label {
  font-size: 11px; color: var(--muted, #64748b);
  font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
}
.iqc-child-composer textarea {
  width: 100%; padding: 8px 10px; border-radius: 6px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 13.5px; line-height: 1.45;
  resize: vertical; min-height: 56px; box-sizing: border-box;
}
.iqc-child-composer textarea:focus-visible {
  outline: 2px solid var(--primary, #f59e0b); outline-offset: 2px;
}
.iqc-cc-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.iqc-cc-row .iqc-cc-spacer { flex: 1 1 auto; }
.iqc-cc-files { font-size: 12px; }
.iqc-cc-err { color: var(--danger, #c0392b); font-size: 12px; min-height: 14px; }

/* Make the focus ring visible on every Idea-Queue control — same accent
   the rest of the app uses. Don't override the global :focus-visible
   reset; just add a slightly stronger ring inside the composer card so
   keyboard users always see where they are. */
.idea-queue-composer textarea:focus-visible,
.idea-queue-composer-row select:focus-visible,
.idea-queue-composer-row .btn:focus-visible,
#ideaQueueSubmit:focus-visible {
  outline: 2px solid var(--primary, #f59e0b);
  outline-offset: 2px;
}

/* File-attachments composer row + chips below the textarea. */
.idea-queue-attachments-row {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  margin: 4px 0 6px;
}
.idea-queue-attach-hint { font-size: 11.5px; color: var(--muted, #64748b); }

/* Quick-pick chips — two short rows under the attach controls. The
   wrapper is hidden when the caller has no usable history; each
   inner row also hides itself when it has no items. */
.idea-queue-quickpicks { display: flex; flex-direction: column; gap: 4px; margin: 4px 0 2px; }
.idea-queue-quickpicks.hidden { display: none; }
.iq-quickpicks-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.iq-quickpicks-row.hidden { display: none; }
.iq-quickpicks-label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.4px;
  text-transform: uppercase; color: var(--muted, #64748b);
  flex: 0 0 auto;
}
.iq-quickpicks-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.iq-quickpick-chip {
  appearance: none; cursor: pointer; font: inherit; font-size: 12px; font-weight: 600;
  padding: 4px 10px; border-radius: 14px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  white-space: nowrap; max-width: 240px; overflow: hidden; text-overflow: ellipsis;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.iq-quickpick-chip:hover { background: var(--brand-teal-tint, rgba(13, 115, 119, 0.10)); }
.iq-quickpick-chip[aria-pressed="true"] {
  background: var(--brand-teal, #0d7377); color: #fff;
  border-color: var(--brand-teal, #0d7377);
}
.iq-quickpick-chip:focus-visible {
  outline: 2px solid var(--brand-blue, #0078BF); outline-offset: 2px;
}

/* Cross-folder thread search — sits below the quick-pick chips, above
   the folder/thread dropdown row. Match the chip-row visual rhythm so
   the eye doesn't have to retrain. */
.iq-thread-search-row {
  display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap;
  margin: 6px 0 4px;
}
.iq-thread-search-row .iq-quickpicks-label { padding-top: 8px; }
.iq-thread-search-wrap {
  position: relative; flex: 1 1 280px; min-width: 240px;
}
.iq-thread-search-input {
  width: 100%; box-sizing: border-box;
  padding: 6px 10px; font: inherit; font-size: 13px;
  border: 1px solid var(--border, #e2e8f0); border-radius: 8px;
  background: var(--surface, #fff); color: var(--text, #0f172a);
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.iq-thread-search-input:focus-visible {
  outline: none; border-color: var(--brand-blue, #0078BF);
  box-shadow: 0 0 0 2px rgba(0, 120, 191, 0.18);
}
.iq-thread-search-results {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0;
  max-height: 260px; overflow-y: auto;
  border: 1px solid var(--border, #e2e8f0); border-radius: 8px;
  background: var(--surface, #fff);
  box-shadow: 0 10px 28px rgba(15, 23, 42, 0.14);
  z-index: 40;
  display: flex; flex-direction: column;
}
.iq-thread-search-results.hidden { display: none; }
.iq-thread-search-item {
  display: flex; flex-direction: column; gap: 1px;
  padding: 8px 12px; cursor: pointer; border: none; background: none;
  text-align: left; font: inherit; color: var(--text, #0f172a);
  border-bottom: 1px solid var(--border-soft, #f1f5f9);
}
.iq-thread-search-item:last-child { border-bottom: none; }
.iq-thread-search-item:hover,
.iq-thread-search-item.is-active {
  background: var(--brand-teal-tint, rgba(13, 115, 119, 0.10));
}
.iq-thread-search-item-title {
  font-size: 13px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.iq-thread-search-item-folder {
  font-size: 11px; color: var(--muted, #64748b);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.iq-thread-search-empty,
.iq-thread-search-loading {
  padding: 8px 12px; font-size: 12px; color: var(--muted, #64748b);
  font-style: italic;
}
.idea-queue-attachments {
  display: flex; flex-direction: column; gap: 6px;
  margin: 0 0 4px;
}
.idea-queue-attachment-chip {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 8px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, rgba(0,0,0,0.03));
  font-size: 12.5px;
}
.idea-queue-attachment-chip .iqa-icon { font-size: 16px; flex: 0 0 18px; }
.idea-queue-attachment-chip .iqa-name {
  flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
  font-weight: 600;
}
.idea-queue-attachment-chip .iqa-meta { font-size: 11px; color: var(--muted, #64748b); }
.idea-queue-attachment-chip button {
  appearance: none; border: 1px solid var(--border, #e2e8f0);
  background: transparent; color: var(--text);
  font: inherit; font-size: 11px; font-weight: 600;
  padding: 3px 8px; border-radius: 6px; cursor: pointer;
}
.idea-queue-attachment-chip button.danger { color: #b91c1c; border-color: rgba(220,38,38,0.4); }
.idea-queue-attachment-editor {
  display: flex; flex-direction: column; gap: 6px;
  padding: 8px 10px; margin-top: -2px;
  border-radius: 0 0 8px 8px;
  border: 1px solid var(--border, #e2e8f0);
  border-top: 0;
  background: rgba(0,0,0,0.03);
}
.idea-queue-attachment-editor textarea {
  min-height: 120px; font: inherit; font-size: 12.5px;
  padding: 8px 10px; border-radius: 6px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--bg); color: var(--text); resize: vertical;
}
.idea-queue-attachment-editor .iqa-hint { font-size: 11.5px; color: var(--muted); }

/* Parked side-queue section header — a subtle warm tint sets it apart
   from active pipeline statuses. The cards themselves keep the same
   status-* visuals so users still see why each parked idea was set aside. */
.idea-queue-section.status-parked {
  border-top: 1px dashed var(--border, #e2e8f0);
  padding-top: 10px;
  margin-top: 8px;
}
.idea-queue-section.status-parked .idea-queue-section-title {
  color: #b45309;
  background: rgba(245, 158, 11, 0.10);
  padding: 5px 10px;
  border-radius: 6px;
  display: inline-block;
  align-self: flex-start;
}

/* Drag-and-drop highlight on the composer when files are being dragged
   over. Pinned to the composer block so the highlight covers the whole
   panel including the textarea + project pickers — makes it obvious
   where to drop. */
.idea-queue-composer.iq-drag-over {
  outline: 2px dashed var(--brand-blue, #0078BF);
  outline-offset: 2px;
  background: rgba(0, 120, 191, 0.04);
  border-radius: 8px;
}
.idea-queue-attachment-chip .iqa-kind { display: inline-block; }

.idea-queue-list { display: flex; flex-direction: column; gap: 14px; }
.idea-queue-loading, .idea-queue-empty {
  color: var(--muted, #64748b); font-size: 14px; padding: 8px 0;
}
.idea-queue-section { display: flex; flex-direction: column; gap: 8px; }
.idea-queue-section-title {
  font-size: 12px; font-weight: 700; letter-spacing: 0.5px;
  text-transform: uppercase; color: var(--muted, #64748b);
}
.idea-queue-section.status-pending   .idea-queue-section-title { color: var(--muted, #64748b); }
.idea-queue-section.status-compiling .idea-queue-section-title { color: var(--brand-blue, #0078BF); }
.idea-queue-section.status-queued    .idea-queue-section-title { color: var(--brand-amber, #f59e0b); }
.idea-queue-section.status-running   .idea-queue-section-title { color: var(--brand-teal, #0d7377); }
.idea-queue-section.status-done      .idea-queue-section-title { color: var(--brand-emerald, #16a34a); }
.idea-queue-section.status-failed    .idea-queue-section-title { color: var(--danger, #c0392b); }
.idea-queue-card {
  border: 1px solid var(--border, #e2e8f0); border-radius: 10px;
  padding: 12px 14px; background: var(--surface, #fff);
  display: flex; flex-direction: column; gap: 6px;
  border-left: 4px solid var(--brand-amber, #f59e0b);
}
.idea-queue-card.status-running { border-left-color: var(--brand-teal, #0d7377); }
.idea-queue-card.status-done    { border-left-color: var(--brand-emerald, #16a34a); }
.idea-queue-card.status-failed  { border-left-color: var(--danger, #c0392b); }
.idea-queue-card.status-cancelled, .idea-queue-card.status-pending { border-left-color: var(--muted, #64748b); }

/* ════════════════════════════════════════════════════════════════
   Running-card glow — instantly draws the eye to the prompt that's
   currently executing. The breathing box-shadow halo sits OUTSIDE
   the card so the inner background (which carries the text colour
   for dark/light themes) is untouched. Two layers:
     • a wider faint halo that breathes (0→18px spread, ~40-60% α)
     • a static 1px teal outline-via-box-shadow that lifts the
       whole card edge into teal — the 4px left border stays as-is
   We avoid border-width / margin changes so the layout never shifts.
   Applies to BOTH `.idea-queue-card.status-running` (Web UI) and
   `.idea-queue-row.status-running` (Telegram Mini App rows).
   ════════════════════════════════════════════════════════════════ */
/* Three-layer halo:
     • 1px solid teal border (keeps the card edge crisp)
     • 2px soft outer ring at α 0.35 (constant — gives the eye a fixed
       anchor under the breathing halo so the effect reads as "alive"
       not "flickering")
     • outer pulsing halo, 0px → 24px spread, α 0 → 0.65, breathing on
       a 1.8s ease-in-out cycle. Higher peak than the earlier version
       so the running card is unmistakable against the dark Telegram
       Mini App theme. */
@keyframes idea-queue-running-pulse {
  0%, 100% {
    box-shadow:
      0 0 0 1px var(--brand-teal, #0d7377),
      0 0 0 2px rgba(13, 115, 119, 0.35),
      0 0 0 0 rgba(13, 115, 119, 0);
  }
  50% {
    box-shadow:
      0 0 0 1px var(--brand-teal, #0d7377),
      0 0 0 2px rgba(13, 115, 119, 0.35),
      0 0 24px 0 rgba(13, 115, 119, 0.65);
  }
}
.idea-queue-card.status-running,
.idea-queue-row.status-running {
  animation: idea-queue-running-pulse 1.8s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .idea-queue-card.status-running,
  .idea-queue-row.status-running {
    animation: none;
    /* Static halo at peak intensity (matches the 50% keyframe) so
       reduced-motion users still get the same "this one is running"
       visual weight, just without the breathing. */
    box-shadow:
      0 0 0 1px var(--brand-teal, #0d7377),
      0 0 0 2px rgba(13, 115, 119, 0.35),
      0 0 20px 0 rgba(13, 115, 119, 0.55);
  }
}
.iqc-head { display: flex; align-items: flex-start; gap: 8px; }
.iqc-text { flex: 1; font-size: 14px; line-height: 1.45; color: var(--text, #0f172a); }
.iqc-status {
  font-size: 11px; font-weight: 700;
  padding: 3px 9px; border-radius: 10px;
  background: var(--brand-amber, #f59e0b); color: #fff; white-space: nowrap;
}
.iqc-status.status-running { background: var(--brand-teal, #0d7377); }
.iqc-status.status-done    { background: var(--brand-emerald, #16a34a); }
.iqc-status.status-failed  { background: var(--danger, #c0392b); }
.iqc-status.status-pending, .iqc-status.status-compiling, .iqc-status.status-cancelled { background: var(--muted, #64748b); }
.iqc-meta { font-size: 11.5px; color: var(--muted, #64748b); }
.iqc-err  { color: var(--danger, #c0392b); font-size: 12px; }
.iqc-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.iqc-prompt {
  margin: 6px 0 0; padding: 10px 12px;
  background: var(--bg-soft, #f8fafc);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px; font-size: 12px;
  max-height: 320px; overflow: auto;
  white-space: pre-wrap; word-break: break-word;
}

/* ============================================================
   My Documents
   ============================================================ */
#myDocsHeader { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; row-gap: 8px; flex-shrink: 0; padding: 14px 20px; border-bottom: 1px solid var(--border, #e2e8f0); }
.my-docs-body { padding: 16px 20px; display: flex; flex-direction: column; gap: 18px; }
.my-docs-composer {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px 16px; border: 2px solid var(--brand-blue, #0078BF);
  border-radius: 12px; background: var(--surface, #fff);
}
.my-docs-section-title {
  font-size: 11px; color: var(--muted, #64748b);
  font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
  margin-top: 4px;
}
.my-docs-composer input,
.my-docs-composer select,
.my-docs-composer textarea {
  padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 14px;
}
.my-docs-composer textarea { resize: vertical; min-height: 64px; }
.my-docs-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.my-docs-row input[type="file"] { flex: 1 1 220px; }
.my-docs-list { display: flex; flex-direction: column; gap: 12px; }
.my-docs-loading, .my-docs-empty { color: var(--muted, #64748b); font-size: 14px; padding: 8px 0; }
.my-docs-err { color: var(--danger, #c0392b); font-size: 14px; }

/* ───── Created-by-AI showcase (sits above the user's own docs) ───── */
.my-docs-ai-section { display: flex; flex-direction: column; gap: 10px; margin-bottom: 4px; }
.my-docs-ai-section:empty { display: none; }
.my-docs-ai-header { display: flex; flex-direction: column; gap: 2px; }
.my-docs-ai-header .my-docs-section-title { display: flex; align-items: center; gap: 8px; }
.my-docs-ai-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 20px; padding: 0 7px;
  background: var(--brand-blue, #0078BF); color: #fff;
  border-radius: 999px; font-size: 11px; font-weight: 700;
}
.my-docs-ai-sub { font-size: 12.5px; color: var(--muted, #64748b); }
.my-docs-ai-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.my-doc-ai-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px 14px 12px;
  text-decoration: none; color: inherit;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-left: 4px solid var(--brand-blue, #0078BF);
  border-radius: 12px;
  transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
  position: relative;
  overflow: hidden;
}
.my-doc-ai-card:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(15, 32, 68, 0.08);
  border-color: var(--brand-blue, #0078BF);
}
.my-doc-ai-card:focus-visible {
  outline: 2px solid var(--brand-blue, #0078BF);
  outline-offset: 2px;
}
.my-doc-ai-card.accent-pink { border-left-color: var(--brand-pink, #E44C9A); }
.my-doc-ai-card.accent-pink:hover { border-color: var(--brand-pink, #E44C9A); }
.my-doc-ai-card.accent-teal { border-left-color: var(--brand-teal, #0d7377); }
.my-doc-ai-card.accent-teal:hover { border-color: var(--brand-teal, #0d7377); }

.my-doc-ai-top { display: flex; align-items: center; gap: 10px; }
.my-doc-ai-icon { font-size: 24px; line-height: 1; flex-shrink: 0; }
.my-doc-ai-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.my-doc-ai-kind { font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--brand-blue, #0078BF); }
.my-doc-ai-card.accent-pink .my-doc-ai-kind { color: var(--brand-pink, #E44C9A); }
.my-doc-ai-card.accent-teal .my-doc-ai-kind { color: var(--brand-teal, #0d7377); }
.my-doc-ai-aud { font-size: 11.5px; color: var(--muted, #64748b); }
.my-doc-ai-title { font-size: 15.5px; font-weight: 700; color: var(--text, #0f172a); line-height: 1.25; }
.my-doc-ai-blurb { font-size: 13px; color: var(--muted, #64748b); line-height: 1.45; }
.my-doc-ai-actions {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-top: auto; padding-top: 4px;
}
.my-doc-ai-open { font-size: 12.5px; font-weight: 700; color: var(--brand-blue, #0078BF); }
.my-doc-ai-card.accent-pink .my-doc-ai-open { color: var(--brand-pink, #E44C9A); }
.my-doc-ai-card.accent-teal .my-doc-ai-open { color: var(--brand-teal, #0d7377); }
.my-doc-ai-download {
  font-size: 12px; font-weight: 700; text-decoration: none;
  padding: 4px 10px; border-radius: 999px;
  background: var(--bg-soft, #f8fafc); color: var(--text, #0f172a);
  border: 1px solid var(--border, #e2e8f0);
}
.my-doc-ai-download:hover { background: var(--surface, #fff); border-color: var(--brand-blue, #0078BF); color: var(--brand-blue, #0078BF); }
.my-doc-ai-download:focus-visible { outline: 2px solid var(--brand-blue, #0078BF); outline-offset: 2px; }

.my-doc-card {
  border: 1px solid var(--border, #e2e8f0); border-radius: 10px;
  padding: 12px 14px; background: var(--surface, #fff);
  display: flex; flex-direction: column; gap: 6px;
  border-left: 4px solid var(--brand-blue, #0078BF);
}
.my-doc-card.status-error { border-left-color: var(--danger, #c0392b); }
.my-doc-card.status-processing { border-left-color: var(--brand-amber, #f59e0b); }
.mdc-head { display: flex; align-items: flex-start; gap: 8px; }
.mdc-title { flex: 1; font-weight: 700; font-size: 15px; color: var(--text, #0f172a); word-break: break-word; }
.mdc-status {
  font-size: 11px; font-weight: 700;
  padding: 3px 9px; border-radius: 10px;
  background: var(--brand-amber, #f59e0b); color: #fff;
}
.mdc-status.status-error { background: var(--danger, #c0392b); }
.mdc-status.status-processing { background: var(--brand-amber, #f59e0b); }
.mdc-meta { font-size: 11.5px; color: var(--muted, #64748b); }
.mdc-desc { font-size: 13px; color: var(--muted, #64748b); }
.mdc-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.mdc-summary {
  margin: 6px 0 0; padding: 10px 12px;
  background: var(--bg-soft, #f8fafc);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px; font-size: 12px;
  max-height: 320px; overflow: auto; white-space: pre-wrap;
}
.mdc-inject, .mdc-share {
  margin-top: 6px; padding: 10px 12px;
  background: var(--bg-soft, #f8fafc);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px; font-size: 13px;
  display: flex; flex-direction: column; gap: 6px;
}
.mdc-inject-label, .mdc-share-label {
  font-size: 11px; color: var(--muted, #64748b);
  font-weight: 700;
}
.mdc-inject .btn { margin-right: 4px; }
.mdc-share-row { display: flex; gap: 6px; align-items: center; padding: 2px 0; }
.mdc-share-revoke {
  appearance: none; border: none; background: transparent;
  color: var(--danger, #c0392b); cursor: pointer; font-weight: 700;
}
.mdc-share-empty { color: var(--muted, #64748b); font-size: 12px; }
.mdc-share-sel {
  padding: 6px 8px; border-radius: 6px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 12px;
}
.mdc-share-add-row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }

/* My Documents — share picker type tabs */
.mdc-share-tabs { display: flex; gap: 4px; margin: 6px 0 4px; }
.mdc-share-tab {
  appearance: none; padding: 4px 10px; border-radius: 6px;
  background: transparent; color: var(--muted, #64748b);
  border: 1px solid var(--border, #e2e8f0);
  font: inherit; font-size: 11.5px; font-weight: 700;
  cursor: pointer;
}
.mdc-share-tab.active {
  background: var(--brand-teal, #0d7377); color: #fff;
  border-color: var(--brand-teal, #0d7377);
}
.mdc-share-level { color: var(--muted, #64748b); font-size: 11px; }

/* My Documents — inline markdown editor */
.mdc-editor {
  margin-top: 8px; padding: 12px 14px;
  background: var(--bg-soft, #f8fafc);
  border: 1px solid var(--brand-teal, #0d7377);
  border-radius: 10px;
  display: flex; flex-direction: column; gap: 8px;
}
.mdc-editor-label {
  font-size: 11px; color: var(--muted, #64748b);
  font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
}
.mdc-editor-ta {
  width: 100%; padding: 10px 12px;
  border-radius: 8px; border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px; line-height: 1.5;
  resize: vertical; min-height: 200px; box-sizing: border-box;
}
.mdc-editor-status { font-size: 11.5px; color: var(--muted, #64748b); }
.mdc-editor-status.ok { color: var(--brand-emerald, #16a34a); }
.mdc-editor-status.err { color: var(--danger, #c0392b); }
.mdc-editor-actions { display: flex; gap: 8px; justify-content: flex-end; }
.mdc-editor-err { color: var(--danger, #c0392b); font-size: 13px; }

/* My Documents — separated Upload + Generate cards + reference chips */
.my-docs-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px 16px;
  border-radius: 12px; background: var(--surface, #fff);
}
.my-docs-upload-card    { border: 2px solid var(--brand-blue, #0078BF); }
.my-docs-generate-card  { border: 2px solid var(--brand-pink, #E44C9A); }
.my-docs-pill-label {
  font-size: 11px; color: var(--muted, #64748b);
  font-weight: 600; margin-top: 2px;
}
.my-docs-references {
  display: flex; flex-direction: column; gap: 4px;
  max-height: 200px; overflow-y: auto;
  padding: 8px 10px;
  border: 1px solid var(--border, #e2e8f0); border-radius: 8px;
  background: var(--bg-soft, #f8fafc);
}
.my-docs-references-empty { color: var(--muted, #64748b); font-size: 12px; }
.my-docs-ref-chip {
  display: flex; gap: 8px; align-items: center;
  font-size: 13px; cursor: pointer;
}
.my-docs-ref-chip.disabled { color: var(--muted, #64748b); cursor: not-allowed; }
.my-docs-ref-warn { color: var(--muted, #64748b); font-size: 11px; }

/* ── Fill-a-template-with-@doco card + inline chat panel ─────────── */
.my-docs-fill-card {
  border: 2px solid var(--brand-teal, #0d7377);
  background: linear-gradient(180deg, rgba(13,115,119,0.04) 0%, var(--surface, #fff) 60%);
}
.my-docs-fill-sub {
  font-size: 12px; color: var(--muted, #64748b); margin-bottom: 4px;
}
.my-docs-fill-row {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.my-docs-fill-select {
  flex: 1 1 260px; min-width: 200px;
  padding: 7px 10px; border-radius: 8px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); font: inherit; font-size: 13px;
}
.my-docs-fill-open-sessions {
  margin-top: 6px; padding: 10px 12px;
  background: var(--bg-soft, #f8fafc); border-radius: 8px;
  border: 1px dashed var(--border, #e2e8f0);
}
.my-docs-fill-open-label {
  font-size: 11px; color: var(--muted, #64748b); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 6px;
}
.my-docs-fill-open-list {
  display: flex; flex-direction: column; gap: 4px;
}
.my-docs-fill-open-row {
  display: flex; gap: 8px; align-items: center; justify-content: space-between;
  padding: 6px 8px; border-radius: 6px; background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0); font-size: 13px;
}
.my-docs-fill-open-row .badge {
  font-size: 11px; color: var(--muted, #64748b);
  padding: 2px 8px; border-radius: 999px;
  background: var(--bg-soft, #f8fafc);
  border: 1px solid var(--border, #e2e8f0);
}
.my-docs-fill-chat {
  margin-top: 12px;
  border: 1px solid var(--border, #e2e8f0); border-radius: 10px;
  background: var(--surface, #fff);
  display: flex; flex-direction: column;
  max-height: 70vh;
}
.my-docs-fill-chat-header {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-bottom: 1px solid var(--border, #e2e8f0);
  background: linear-gradient(90deg, rgba(0,120,191,0.06), rgba(228,76,154,0.06));
}
.my-docs-fill-chat-title { font-weight: 700; font-size: 14px; flex: 1; min-width: 0; }
.my-docs-fill-chat-progress {
  font-size: 12px; color: var(--brand-teal, #0d7377);
  background: rgba(13,115,119,0.10); padding: 3px 10px;
  border-radius: 999px; font-weight: 700;
}
.my-docs-fill-chat-body {
  display: grid; grid-template-columns: 1fr 260px;
  gap: 0; min-height: 320px;
}
.my-docs-fill-messages {
  padding: 12px 14px;
  overflow-y: auto;
  display: flex; flex-direction: column; gap: 10px;
  border-right: 1px solid var(--border, #e2e8f0);
  min-height: 220px; max-height: 55vh;
}
.my-docs-fill-msg {
  padding: 8px 12px; border-radius: 10px;
  max-width: 88%; font-size: 13.5px; line-height: 1.55;
  white-space: pre-wrap; word-wrap: break-word;
}
.my-docs-fill-msg.role-agent {
  align-self: flex-start;
  background: rgba(0,120,191,0.08);
  border: 1px solid rgba(0,120,191,0.20);
  color: var(--text, #0f172a);
}
.my-docs-fill-msg.role-user {
  align-self: flex-end;
  background: rgba(228,76,154,0.10);
  border: 1px solid rgba(228,76,154,0.25);
  color: var(--text, #0f172a);
}
.my-docs-fill-msg.role-system {
  align-self: center; background: var(--bg-soft, #f8fafc);
  color: var(--muted, #64748b); font-style: italic; font-size: 12px;
}
.my-docs-fill-sidebar {
  padding: 12px; overflow-y: auto; max-height: 55vh;
  background: var(--bg-soft, #f8fafc);
}
.my-docs-fill-sidebar-title {
  font-size: 11px; color: var(--muted, #64748b); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 8px;
}
.my-docs-fill-field-list { display: flex; flex-direction: column; gap: 8px; }
.my-docs-fill-field-group-title {
  font-size: 11.5px; color: var(--brand-blue, #0078BF); font-weight: 700;
  margin-top: 6px; margin-bottom: 2px;
}
.my-docs-fill-field {
  display: flex; gap: 6px; align-items: flex-start;
  padding: 4px 6px; border-radius: 6px;
  font-size: 12.5px;
}
.my-docs-fill-field.answered {
  background: rgba(16,185,129,0.08);
  border: 1px solid rgba(16,185,129,0.25);
}
.my-docs-fill-field.pending {
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
}
.my-docs-fill-field .tick { flex: 0 0 auto; color: var(--brand-teal, #0d7377); font-weight: 700; }
.my-docs-fill-field .label { flex: 1; min-width: 0; }
.my-docs-fill-field .value {
  font-size: 11.5px; color: var(--muted, #64748b);
  word-break: break-word; margin-top: 2px;
}
.my-docs-fill-composer {
  border-top: 1px solid var(--border, #e2e8f0);
  padding: 10px 12px;
  display: flex; flex-direction: column; gap: 8px;
}
.my-docs-fill-composer textarea {
  width: 100%; resize: vertical;
  padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border, #e2e8f0);
  font: inherit; font-size: 13px;
}
.my-docs-fill-composer-actions {
  display: flex; gap: 8px; flex-wrap: wrap;
}
@media (max-width: 700px) {
  .my-docs-fill-chat-body { grid-template-columns: 1fr; }
  .my-docs-fill-sidebar { border-top: 1px solid var(--border, #e2e8f0); }
  .my-docs-fill-messages { max-height: 40vh; }
}

/* Per-thread AI provider chip + picker menu */
.provider-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  background: rgba(13, 115, 119, 0.10);
  border: 1px solid rgba(13, 115, 119, 0.35);
  color: var(--brand-teal, #0d7377);
  border-radius: 999px;
  font: inherit; font-size: 11.5px; font-weight: 700;
  cursor: pointer;
  margin-left: 6px;
}
.provider-chip:hover:not(:disabled) { background: rgba(13, 115, 119, 0.18); }
.provider-chip:disabled { opacity: 0.5; cursor: not-allowed; }
.provider-chip.hidden { display: none; }
.provider-chip.is-grok {
  background: rgba(15, 23, 42, 0.06);
  border-color: rgba(15, 23, 42, 0.40);
  color: var(--text, #0f172a);
}
.provider-menu {
  position: fixed;
  z-index: 9999;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 12px;
  box-shadow: 0 12px 34px rgba(15, 32, 68, 0.22);
  /* Fixed ~335 px envelope per size spec — narrow enough to feel compact
     on 13" laptops, wide enough for the Claude card head line
     (name + plan pill + CLI ACTIVE) to stay on one row. */
  padding: 3px; min-width: 335px; max-width: 335px;
  /* Cap height at 72vh (spec: 70–75vh) so the picker never runs off the
     viewport. Internal scroll kicks in via overflow-y:auto below when
     the provider list is taller than the cap. vh fallback + dvh handle
     mobile URL-bar collapse without letting the picker jump. */
  max-height: 72vh;
  max-height: 72dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex; flex-direction: column; gap: 1px;
}
.provider-menu-row {
  appearance: none; border: none; background: transparent;
  text-align: left;
  /* Non-Claude rows land at ~42–46 px total: 12 px padding + ~15 px
     label + ~14 px desc. Claude account cards override this via
     .pm-claude-card below. */
  padding: 6px 8px; border-radius: 6px;
  cursor: pointer; display: flex; gap: 8px; align-items: center;
  font: inherit; color: var(--text, #0f172a);
}
.provider-menu-row:hover:not(:disabled) { background: var(--bg-soft, #f8fafc); }
.provider-menu-row.is-active { background: rgba(13, 115, 119, 0.10); }
.provider-menu-row.disabled, .provider-menu-row:disabled { opacity: 0.55; cursor: not-allowed; }
.provider-menu-icon { font-size: 14px; flex: 0 0 auto; line-height: 1; }
.provider-menu-body { display: flex; flex-direction: column; gap: 0; flex: 1; min-width: 0; }
.provider-menu-label { font-weight: 700; font-size: 12px; line-height: 1.25; }
/* Description clamped to one line with ellipsis so a long provider blurb can't
   stretch the row height. Full text is still available via the native `title`
   tooltip set at render time in openProviderPicker(). */
.provider-menu-desc {
  font-size: 10.5px; color: var(--muted, #64748b); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Not-configured warning is a tiny inline chip that sits on the same row as
   the label instead of consuming its own line. */
.provider-menu-warn {
  display: inline-block;
  font-size: 10px; color: var(--danger, #c0392b); font-weight: 700;
  margin-left: 6px; padding: 0 5px; border-radius: 999px;
  background: rgba(192, 57, 43, 0.10);
  vertical-align: middle;
  text-transform: uppercase; letter-spacing: 0.3px;
}
/* `CLI active` badge — manualmode.fadafad.com's box-wide ambient account
   pointer. Distinct from `✓` (this thread's pinned provider) so the two
   concerns can't be confused. Neutral slate tint, not primary, so it
   doesn't compete with the primary-tinted `is-active` row background. */
.provider-menu-cli-active {
  display: inline-block;
  font-size: 10px; color: var(--muted, #64748b); font-weight: 700;
  margin-left: 6px; padding: 0 5px; border-radius: 999px;
  background: rgba(100, 116, 139, 0.14);
  border: 1px solid rgba(100, 116, 139, 0.28);
  vertical-align: middle;
  text-transform: uppercase; letter-spacing: 0.3px;
}
/* =====================================================================
   Claude account card layout — matches the reference design:
     • Larger icon column
     • Big bold account name + inline plan pill + green CLI ACTIVE badge
     • Description on its own line, clamped to one line with ellipsis
     • Session · 5h / Weekly · 7d meters (labeled, fatter bars, big %)
     • `resets in Xd · last known · Xm ago` footer line
   Only applied when the row has .pm-claude-card (Claude account rows);
   generic `claude` row and non-Claude providers stay compact.
   ===================================================================== */
.provider-menu-row.pm-claude-card {
  padding: 5px 7px;
  align-items: flex-start;
  gap: 6px;
  border-radius: 8px;
}
.provider-menu-row.pm-claude-card.is-active {
  background: rgba(13, 115, 119, 0.09);
  outline: 1px solid rgba(13, 115, 119, 0.22);
}
.pm-card-icon {
  font-size: 14px;
  line-height: 1.1;
  flex: 0 0 auto;
  margin-top: 1px;
  color: var(--text, #0f172a);
}
.pm-card-body {
  display: flex; flex-direction: column;
  gap: 1px;
  flex: 1; min-width: 0;
}
.pm-card-head {
  display: flex; align-items: center; gap: 5px;
  flex-wrap: wrap;
  min-width: 0;
}
.pm-card-name {
  font-weight: 700; font-size: 12.5px; line-height: 1.2;
  color: var(--text, #0f172a);
}
.pm-tick { color: #16a34a; font-weight: 700; font-size: 11.5px; }
/* Plan pill — Max / Pro / Team etc. — subtle slate chip next to the name. */
.pm-plan {
  display: inline-block;
  font-size: 8px; font-weight: 700;
  color: var(--text, #0f172a);
  padding: 0 4px; border-radius: 999px;
  background: rgba(15, 23, 42, 0.08);
  border: 1px solid rgba(15, 23, 42, 0.14);
  text-transform: uppercase; letter-spacing: 0.3px;
  line-height: 1.5;
}
/* Prominent CLI ACTIVE badge — green pill (reference: bright green fill).
   Distinct from `provider-menu-cli-active` (compact slate chip used on
   non-card rows). */
.pm-cli-active {
  display: inline-block;
  font-size: 8px; font-weight: 800;
  color: #ffffff;
  padding: 0 5px; border-radius: 999px;
  background: #16a34a;
  border: 1px solid #15803d;
  text-transform: uppercase; letter-spacing: 0.4px;
  line-height: 1.5;
  box-shadow: 0 1px 2px rgba(22, 163, 74, 0.35);
}
.pm-card-desc {
  font-size: 10.5px; color: var(--muted, #64748b); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Email + plan lines under the account name — mirror the manualmode
   dashboard cards: display name (bold) / email (muted) / plan (muted)
   stacked on their own lines instead of a cramped one-line description.
   Server ships these via `accountMeta: { name, email, plan }` on each
   /api/providers claude-* row (see src/routes.ts). */
.pm-card-email {
  font-size: 10.5px; color: var(--muted, #64748b); line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  margin-top: -1px;
}
.pm-card-plan {
  font-size: 10.5px; color: var(--muted, #64748b); line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  margin-top: -1px;
}
/* Claude account usage strip — Session · 5h + Weekly · 7d meters.
   Only rendered for `claude-<account>` provider rows; other providers
   ship no `usage` field so the block is absent from their DOM. Values
   come from src/claudeAccounts.ts::getClaudeAccountUsage (Anthropic's
   /api/oauth/usage endpoint) — never calculated client-side. */
.provider-menu-usage {
  display: flex; flex-direction: column; gap: 3px;
  margin-top: 2px;
  font-size: 10px; color: var(--muted, #64748b);
  line-height: 1.2;
}
.pmu-row {
  display: grid;
  grid-template-columns: 60px 1fr 32px;
  align-items: center; gap: 6px;
}
.pmu-label {
  font-weight: 600; font-size: 10px;
  color: var(--muted, #64748b);
  letter-spacing: 0.1px;
  white-space: nowrap;
}
.pmu-bar {
  position: relative;
  height: 4px; min-width: 0;
  border-radius: 999px;
  /* Track — visible rail even at 0% fill. */
  background: rgba(100, 116, 139, 0.20);
  overflow: hidden;
}
.pmu-fill {
  display: block;
  height: 100%;
  /* Minimum visible tick even at 0% utilisation so the meter never
     looks like an empty row. Applied via min-width; the bar clip
     (overflow:hidden on .pmu-bar) still contains it. */
  min-width: 3px;
  border-radius: 999px;
  transition: width 220ms ease;
}
.pmu-fill.pmu-ok    { background: #16a34a; }
.pmu-fill.pmu-warn  { background: #f59e0b; }
.pmu-fill.pmu-crit  { background: #dc2626; }
.pmu-fill.pmu-unknown { background: rgba(100, 116, 139, 0.5); }
.pmu-pct {
  font-variant-numeric: tabular-nums;
  font-weight: 700; font-size: 10.5px;
  text-align: right;
  color: var(--text, #0f172a);
}
.pmu-pct.pmu-ok    { color: #16a34a; }
.pmu-pct.pmu-warn  { color: #b45309; }
.pmu-pct.pmu-crit  { color: #dc2626; }
.pmu-pct.pmu-unknown { color: var(--muted, #64748b); }
/* Per-meter reset sub-line — rendered directly below its own meter row.
   Matches manualmode: `resets in 42m` under Session · 5h, `resets in 1d 23h`
   under Weekly · 7d. Reset times are NEVER combined into one line. */
.pmu-reset-line {
  font-variant-numeric: tabular-nums;
  font-size: 8.5px; color: var(--muted, #64748b);
  margin-top: -1px; margin-bottom: 0;
  padding-left: 66px;   /* align under the bar column, past the label */
  line-height: 1.2;
}
/* Separate status line — used for `· last known values (endpoint busy)`
   when the payload is stale. Its own line so the resets above stay clean. */
.pmu-status {
  font-variant-numeric: tabular-nums;
  font-size: 8.5px; color: var(--muted, #64748b);
  font-style: italic;
  margin-top: 0;
  padding-left: 66px;   /* align under the bar column */
  line-height: 1.2;
}
/* Legacy footer class — kept as a defensive fallback for any cached JS still
   rendering the combined footer. New JS uses .pmu-reset-line + .pmu-status. */
.pmu-foot {
  font-variant-numeric: tabular-nums;
  font-size: 8.5px; color: var(--muted, #64748b);
  margin-top: 0;
  padding-left: 66px;
  line-height: 1.2;
}
/* Usage unavailable — italic muted line under the description. */
.pmu-unavailable {
  font-size: 9.5px; color: var(--muted, #64748b);
  font-style: italic;
  margin-top: 1px;
}
/* Legacy classes kept for any external callers still rendering the old
   inline .pmu-reset / .pmu-error / .pmu-stale spans (defensive). */
.pmu-reset {
  font-variant-numeric: tabular-nums;
  font-size: 10px; color: var(--muted, #64748b);
  padding: 0 4px; border-radius: 999px;
  background: rgba(100, 116, 139, 0.10);
}
.pmu-reset.pmu-reset-empty { opacity: 0.55; background: transparent; padding: 0 2px; }
.pmu-error { display: inline-block; font-size: 10.5px; color: var(--muted, #64748b); font-style: italic; margin-top: 3px; }
.pmu-stale { display: inline-block; font-size: 10px; color: var(--muted, #64748b); font-style: italic; margin-top: 1px; }

/* Admin → AI engines panel */
.admin-engines-list { display: flex; flex-direction: column; gap: 12px; }
.admin-engine-card {
  border: 1px solid var(--border, #e2e8f0); border-radius: 10px;
  padding: 10px 12px; background: var(--surface, #fff);
  display: flex; flex-direction: column; gap: 6px;
}
.admin-engine-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.admin-engine-name { font-weight: 700; font-size: 14px; }
.admin-engine-cwd { font-size: 11.5px; color: var(--muted, #64748b); font-family: ui-monospace, monospace; }
.admin-engine-row { display: flex; align-items: center; gap: 8px; font-size: 12.5px; }
.admin-engine-label { color: var(--muted, #64748b); font-weight: 600; }
.admin-engine-sel {
  padding: 5px 8px; border-radius: 6px; border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 12.5px;
}
.admin-engine-sel.sm { padding: 3px 6px; font-size: 11.5px; }
.admin-engine-threads-label { font-size: 11.5px; color: var(--muted, #64748b); font-weight: 700; margin-top: 4px; }
.admin-engine-threads { display: flex; flex-direction: column; gap: 3px; max-height: 240px; overflow-y: auto; padding: 4px 0; }
.admin-engine-thread-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border-radius: 5px; }
.admin-engine-thread-row:hover { background: var(--bg-soft, #f8fafc); }
.admin-engine-thread-title { flex: 1; font-size: 12px; color: var(--text, #0f172a); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ============================================================
   Cursor Setup — connect Cursor to imagine over MCP
   ============================================================ */
#cursorSetupHeader { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; row-gap: 8px; flex-shrink: 0; padding: 14px 20px; border-bottom: 1px solid var(--border, #e2e8f0); }
.cursor-setup-body { padding: 20px; display: flex; flex-direction: column; gap: 16px; max-width: 880px; margin: 0 auto; width: 100%; }
.cursor-setup-card {
  border: 1px solid var(--border, #e2e8f0); border-radius: 12px;
  padding: 16px 18px; background: var(--surface, #fff);
  display: flex; flex-direction: column; gap: 10px;
}
.cursor-setup-section-title {
  font-size: 13px; color: var(--brand-teal, #0d7377);
  font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
}
.cursor-setup-section-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
.cursor-setup-prose { font-size: 14px; line-height: 1.55; color: var(--text, #0f172a); margin: 0; }
.cursor-setup-prose code {
  font-family: ui-monospace, SF Mono, monospace; font-size: 12.5px;
  background: var(--bg-soft, #f8fafc); padding: 1px 6px; border-radius: 4px;
  color: var(--brand-blue, #0078BF);
}
.cursor-setup-snippet {
  margin: 0; padding: 12px 14px;
  background: var(--bg-soft, #f8fafc);
  color: var(--text);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px;
  font-family: ui-monospace, SF Mono, monospace; font-size: 12.5px;
  line-height: 1.5; white-space: pre; overflow-x: auto;
}
#cursorKeyLabel {
  padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff); color: var(--text, #0f172a);
  font: inherit; font-size: 14px;
}
.cursor-keys-list { display: flex; flex-direction: column; gap: 6px; }
.cursor-key-row {
  display: grid; grid-template-columns: 1fr auto auto auto;
  gap: 10px; align-items: center;
  padding: 8px 10px; border-radius: 8px;
  background: var(--bg-soft, #f8fafc);
  font-size: 12.5px;
}
.cursor-key-row.revoked { opacity: 0.55; }
.cursor-key-label { font-weight: 700; color: var(--text, #0f172a); }
.cursor-key-prefix { font-family: ui-monospace, monospace; color: var(--brand-blue, #0078BF); }
.cursor-key-meta { color: var(--muted, #64748b); font-size: 11px; }
.cursor-key-revoked { color: var(--danger, #c0392b); font-weight: 700; font-size: 11px; }
.cursor-setup-empty, .cursor-setup-loading, .cursor-setup-err { color: var(--muted, #64748b); font-size: 14px; padding: 8px 0; }
.cursor-setup-err { color: var(--danger, #c0392b); }
.cursor-setup-new-key {
  background: linear-gradient(135deg, var(--brand-emerald, #16a34a), var(--brand-teal, #0d7377));
  color: #fff; padding: 14px 16px; border-radius: 10px;
  display: flex; flex-direction: column; gap: 8px;
}
.cursor-setup-new-key.hidden { display: none; }
.cursor-new-key-head { font-weight: 700; font-size: 14px; }
.cursor-new-key-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.cursor-new-key-row code {
  flex: 1; min-width: 200px;
  font-family: ui-monospace, monospace; font-size: 12px;
  background: rgba(0,0,0,0.25); padding: 8px 10px; border-radius: 6px;
  word-break: break-all;
}
.cursor-new-key-note { font-size: 12px; opacity: 0.92; }

/* ───────────── My Messages — Unified Inbox (Phase 2) ───────────── */
/* Inbound-health pill — surfaces /api/inbound/health in the header so the
   admin spots a dead Gmail forwarder before it costs a missed reply. */
.my-messages-inbound-health {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; cursor: pointer; user-select: none;
}
.my-messages-inbound-health.hidden { display: none; }
.inbound-health-pill {
  padding: 4px 10px; border-radius: 12px;
  font-weight: 600; font-size: 11.5px;
  border: 1px solid transparent;
}
.inbound-health-ok    { background: rgba(16, 185, 129, 0.10); color: #047857; border-color: rgba(16, 185, 129, 0.25); }
.inbound-health-stale { background: rgba(245, 158, 11, 0.15); color: #92400E; border-color: rgba(245, 158, 11, 0.4); }
.inbound-health-loading { color: var(--text-muted, var(--muted)); font-size: 11.5px; }

.my-messages-body {
  display: grid;
  grid-template-columns: 320px 1fr;
  gap: 12px;
  height: calc(100vh - 180px);
  min-height: 400px;
}
.my-messages-list {
  overflow-y: auto;
  border-right: 1px solid var(--border);
  padding-right: 6px;
}

/* Channel-filter tab strip at the top of the conversations list. Splits
   the mixed WhatsApp / Telegram / Email / SMS inbox into discrete
   channel views — All · 🟢 WhatsApp · ✈️ Telegram · ✉️ Email · 📱 SMS.
   Tabs render in a flex wrap so all five fit on a narrow sidebar.
   Sticky-pinned to the top of the scrollable list so the user can switch
   channels even after scrolling deep into a long conversation list. */
.my-msg-channel-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 8px 4px 10px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--border, #e2e8f0);
  position: sticky;
  top: 0;
  background: var(--surface, #fff);
  z-index: 2;
}
.my-msg-channel-tab {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 999px;
  background: var(--surface, #fff);
  color: var(--text-muted, #64748b);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.my-msg-channel-tab:hover:not(.is-active) {
  background: var(--surface-2, #f3f4f6);
  color: var(--text, #0f172a);
  border-color: var(--primary-tint-strong, rgba(0,120,191,0.25));
}
.my-msg-channel-tab.is-active {
  background: var(--primary, #0078BF);
  color: #fff;
  border-color: var(--primary, #0078BF);
}
.my-msg-channel-tab-icon { font-size: 13px; line-height: 1; }
.my-msg-channel-tab-label { white-space: nowrap; }
.my-msg-channel-tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 18px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--text-faint, #94a3b8);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1;
}
.my-msg-channel-tab.is-active .my-msg-channel-tab-count {
  background: rgba(255, 255, 255, 0.28);
  color: #fff;
}
.my-messages-thread {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.my-msg-row {
  padding: 10px 12px;
  border-radius: 8px;
  cursor: pointer;
  border: 1px solid transparent;
  margin-bottom: 6px;
}
.my-msg-row:hover { background: var(--surface-hover, rgba(0,0,0,0.04)); }
.my-msg-row.active { background: rgba(0,120,191,0.08); border-color: var(--brand-blue, #0078BF); }
.my-msg-row-head { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.my-msg-row-head strong { font-size: 14px; }
.my-msg-when { font-size: 11px; opacity: 0.65; }
.my-msg-preview { font-size: 12.5px; opacity: 0.85; margin-top: 2px; }
.my-msg-channels { display: flex; gap: 4px; margin-top: 4px; flex-wrap: wrap; }
.my-msg-chip {
  font-size: 10.5px; padding: 1px 6px; border-radius: 10px;
  background: rgba(0,0,0,0.06); opacity: 0.85;
}
.my-msg-thread-head {
  padding: 10px 12px; border-bottom: 1px solid var(--border); display: flex; align-items: baseline; gap: 12px;
}
.my-msg-meta { font-size: 12px; opacity: 0.75; margin-left: 10px; }
.my-msg-msgs {
  flex: 1; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 8px;
}
.my-msg-bubble {
  max-width: 75%;
  /* min-width:0 + overflow-wrap:anywhere keep an unbreakable long token
     (URL, base64 blob, foreign-script run) from pushing the bubble past
     its max-width — which would otherwise cause the page to develop a
     horizontal scrollbar and jitter on touch. */
  min-width: 0;
  padding: 8px 12px; border-radius: 12px;
  overflow-wrap: anywhere; word-break: break-word; word-wrap: break-word;
}
.my-msg-bubble.inbound  { align-self: flex-start; background: rgba(0,0,0,0.06); }
.my-msg-bubble.outbound { align-self: flex-end;   background: rgba(0,120,191,0.18); }
.my-msg-bubble-body { font-size: 14px; line-height: 1.35; white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; }
.my-msg-bubble-meta { font-size: 10.5px; opacity: 0.65; margin-top: 4px; overflow-wrap: anywhere; }
.my-msg-msgs { overflow-x: hidden; min-width: 0; }
.my-msg-reply {
  display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--border); align-items: flex-end;
}
.my-msg-reply textarea {
  flex: 1; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-family: inherit; font-size: 14px; resize: vertical; min-height: 40px;
}
.my-msg-channel-select {
  padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-family: inherit; font-size: 13px;
}

/* My Messages — responder + observers config (Phase: routing v1) */
.my-msg-config {
  display: flex; flex-direction: column; gap: 4px;
  margin-left: auto; font-size: 12px;
}
.my-msg-config-row {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
}
.my-msg-config-label { font-weight: 600; color: var(--muted); }
.my-msg-config-select {
  padding: 3px 8px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-size: 12px; font-family: inherit;
}
.my-msg-observer-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: rgba(0,120,191,0.08); border: 1px solid rgba(0,120,191,0.25);
  padding: 2px 8px; border-radius: 12px; font-size: 11.5px;
}
.my-msg-observer-x {
  appearance: none; border: none; background: transparent; cursor: pointer;
  font-size: 14px; line-height: 1; color: var(--muted); padding: 0 2px;
}
.my-msg-observer-x:hover { color: var(--danger); }
.my-msg-muted { opacity: 0.6; font-size: 11px; }
.my-msg-thread-head { flex-wrap: wrap; }

/* My Messages — internal notes (Phase: comments v1) */
.my-msg-comments {
  border-top: 1px dashed var(--border);
  padding: 10px 12px 4px;
  display: flex; flex-direction: column; gap: 8px;
  background: rgba(255,200,0,0.04);
}
.my-msg-comments-head {
  display: flex; align-items: baseline; gap: 8px; font-size: 12px;
}
.my-msg-comments-title { font-weight: 600; color: var(--muted); }
.my-msg-comments-list { display: flex; flex-direction: column; gap: 6px; }
.my-msg-comment {
  background: rgba(255,200,0,0.08);
  border-left: 3px solid rgba(255,180,0,0.6);
  padding: 6px 10px; border-radius: 6px;
  font-size: 13px;
}
.my-msg-comment.resolved { opacity: 0.55; border-left-color: rgba(120,120,120,0.4); }
.my-msg-comment-meta { display: flex; flex-wrap: wrap; gap: 8px; font-size: 11.5px; align-items: baseline; }
.my-msg-comment-assignee { color: var(--brand-pink, #c84a8a); font-weight: 600; }
.my-msg-comment-body { margin-top: 3px; white-space: pre-wrap; line-height: 1.35; }
.my-msg-comment-actions { display: flex; gap: 8px; margin-top: 4px; font-size: 11.5px; }
.my-msg-comment-resolve, .my-msg-comment-delete {
  appearance: none; border: 1px solid var(--border); background: transparent;
  color: var(--muted); padding: 2px 8px; border-radius: 4px; cursor: pointer;
  font-size: 11.5px; font-family: inherit;
}
.my-msg-comment-resolve:hover { color: var(--success, #2a9d4f); border-color: currentColor; }
.my-msg-comment-delete:hover { color: var(--danger, #c0392b); border-color: currentColor; }
.my-msg-comment-resolved { color: var(--success, #2a9d4f); font-size: 11.5px; }
.my-msg-comment-train {
  appearance: none; border: 1px solid rgba(228, 76, 154, 0.4);
  background: rgba(228, 76, 154, 0.08); color: var(--brand-pink, #c84a8a);
  padding: 2px 8px; border-radius: 4px; cursor: pointer;
  font-size: 11.5px; font-family: inherit; font-weight: 600;
}
.my-msg-comment-train:hover { background: rgba(228, 76, 154, 0.18); }
.my-msg-comment-trained {
  color: var(--brand-pink, #c84a8a); font-size: 11.5px; font-weight: 600;
}
.my-msg-comment.is-training {
  border-left-color: var(--brand-pink, #c84a8a);
  background: rgba(228, 76, 154, 0.06);
}
.my-msg-training-toggle {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11.5px; color: var(--muted); cursor: pointer; user-select: none;
  padding: 2px 6px; border-radius: 4px;
}
.my-msg-training-toggle:hover { background: rgba(228, 76, 154, 0.08); }
.my-msg-training-toggle input[type=checkbox] { margin: 0; }
.my-msg-comment-form { display: flex; flex-direction: column; gap: 6px; }
.my-msg-comment-form textarea {
  padding: 6px 10px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-family: inherit; font-size: 13px; resize: vertical; min-height: 36px;
}
.my-msg-comment-row { display: flex; gap: 8px; align-items: center; }
.my-msg-comment-row select { flex: 1; }

/* ─── My Calendar view ──────────────────────────────────────────
   Two-column layout: the month grid on the left, the unscheduled-tasks
   side rail on the right. Layout collapses to a single column on narrow
   screens (the rail stacks under the grid). All interactive cells expose
   a focus ring so the surface works without a mouse — design rule. */
/* ─── 📞 Call an agent view (03 Aug 2026) ────────────────────── */
#callView { display: flex; flex-direction: column; min-height: 0; }
#callView > #callViewHeader { flex: 0 0 auto; }
.call-view-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 20px 24px 32px;
  overflow: auto;
}
/* ─── 🔌 Connectors view (17 Aug 2026, Step 2 · sibling of Call Agent) ─────
   Mirrors the primary-sections pattern so the header stays put and
   .connectors-body becomes the single scroll surface. Without this rule
   the <section> defaults to display:block and the 6-card grid overflows
   #main's overflow:hidden clip — no scrollbar appears anywhere, which is
   what caused the "can't scroll and see" report. Every re-visit of the
   view repeated the same broken state ("happening again and again"). */
#connectorsView {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  flex: 1 1 auto;
  height: 100%;
  background: var(--bg);
  overflow: hidden;
}
#connectorsView.hidden { display: none !important; }
#connectorsView > #connectorsViewHeader { flex: 0 0 auto; }
.connectors-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong, #94A3B8) transparent;
}
/* Direct Call @marko hero (05 Aug 2026) — one-click English voice surface */
.call-marko-direct {
  max-width: 720px;
  margin: 0 auto 18px;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  border-radius: 16px;
  border: 1px solid rgba(108, 92, 255, 0.35);
  background:
    radial-gradient(ellipse at 12% 20%, rgba(108, 92, 255, 0.18) 0%, transparent 55%),
    linear-gradient(135deg, #0f172a 0%, #1e1b4b 55%, #312e81 100%);
  color: #f5f3ff;
  box-shadow: 0 10px 36px rgba(49, 46, 129, 0.28);
}
.call-marko-direct-avatar {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(135deg, #6c5cff 0%, #ff5c9a 100%);
  box-shadow: 0 6px 20px rgba(108, 92, 255, 0.45);
}
.call-marko-direct-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.call-marko-direct-title {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.01em;
}
.call-marko-direct-sub {
  font-size: 12.5px;
  color: #c4b5fd;
  line-height: 1.35;
}
.call-marko-direct-btn {
  flex: 0 0 auto;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: #22c55e;
  color: #fff;
  font-weight: 700;
  font-size: 14px;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(34, 197, 94, 0.35);
  transition: background .12s ease, transform .06s ease, box-shadow .12s ease;
}
.call-marko-direct-btn:hover {
  background: #16a34a;
  box-shadow: 0 8px 22px rgba(22, 163, 74, 0.4);
}
.call-marko-direct-btn:active { transform: scale(.97); }
.call-marko-direct-btn:disabled {
  opacity: 0.65;
  cursor: wait;
  transform: none;
}
.call-marko-direct-btn:focus-visible {
  outline: 2px solid #a78bfa;
  outline-offset: 3px;
}
@media (max-width: 560px) {
  .call-marko-direct {
    flex-wrap: wrap;
  }
  .call-marko-direct-btn {
    width: 100%;
    text-align: center;
  }
}
.call-view-picker {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.call-view-input {
  width: 100%;
  padding: 14px 18px;
  font-size: 16px;
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 12px;
  background: var(--surface, #fff);
  color: var(--text, #0F172A);
  outline: none;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.call-view-input::placeholder {
  color: var(--text-faint, #94A3B8);
}
.call-view-input:focus {
  border-color: var(--primary, #0D7377);
  box-shadow: 0 0 0 3px var(--primary-tint, rgba(13,115,119,.18));
}
.call-view-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.call-view-empty {
  padding: 24px;
  text-align: center;
  color: var(--text-muted, #475569);
  font-size: 14px;
  border: 1px dashed var(--border, #E3E8EF);
  border-radius: 12px;
  background: var(--surface, #fff);
}
.call-view-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 12px;
  background: var(--surface, #fff);
  color: var(--text, #0F172A);
  cursor: pointer;
  transition: background .1s ease, border-color .1s ease, transform .06s ease;
}
.call-view-row:hover,
.call-view-row.is-active,
.call-view-row:focus-visible {
  border-color: var(--primary, #0D7377);
  background: var(--primary-tint, rgba(13,115,119,.08));
  outline: none;
}
.call-view-row-icon {
  font-size: 22px;
  line-height: 1;
  flex: 0 0 auto;
}
.call-view-row-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.call-view-row-slug {
  font-weight: 700;
  font-size: 15px;
  color: var(--text, #0F172A);
}
.call-view-row-name {
  font-size: 13px;
  color: var(--text-muted, #475569);
}
.call-view-row-desc {
  font-size: 12px;
  color: var(--text-dim, #64748B);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.call-view-row-call {
  flex: 0 0 auto;
  padding: 8px 14px;
  border: 0;
  border-radius: 999px;
  background: #22c55e;
  color: #fff;
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
  transition: background .12s ease, transform .06s ease;
}
.call-view-row-call:hover { background: #16a34a; }
.call-view-row-call:active { transform: scale(.97); }
.call-view-hint {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--text-dim, #64748B);
}

/* Recent calls — history lives in Call view only (not sidebar threads) */
.call-recent-section {
  max-width: 720px;
  margin: 28px auto 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.call-recent-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.call-recent-title {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text, #0F172A);
}
.call-recent-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.call-recent-empty {
  margin: 0;
  padding: 16px;
  text-align: center;
  border: 1px dashed var(--border, #E3E8EF);
  border-radius: 12px;
  font-size: 13px;
  color: var(--text-muted, #475569);
  background: var(--surface, #fff);
}
.call-recent-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 12px;
  background: var(--surface, #fff);
  color: var(--text, #0F172A);
  cursor: pointer;
  transition: background .1s ease, border-color .1s ease;
}
.call-recent-row:hover {
  border-color: var(--primary, #0D7377);
  background: var(--primary-tint, rgba(13,115,119,.08));
}
.call-recent-avatar {
  width: 40px; height: 40px;
  border-radius: 50%;
  background: linear-gradient(135deg, #6c5cff, #ff5c9a);
  color: #fff;
  font-weight: 700;
  font-size: 15px;
  display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
}
.call-recent-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.call-recent-slug {
  font-weight: 700;
  font-size: 14px;
  color: var(--text, #0F172A);
}
.call-recent-meta {
  font-size: 12px;
  color: var(--text-muted, #475569);
}
.call-recent-summary {
  font-size: 13px;
  font-weight: 500;
  color: var(--text, #0F172A);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.92;
}
.call-recent-summary.has-turns {
  color: var(--text, #0F172A);
}
.call-recent-summary.is-empty {
  color: var(--text-muted, #64748B);
  font-style: italic;
  font-weight: 400;
}
.call-recent-actions {
  display: flex;
  gap: 6px;
  flex: 0 0 auto;
}
.call-recent-actions .btn {
  font-size: 12px;
  padding: 6px 10px;
}

/* Prefer app theme class over OS prefers-color-scheme so light app
   theme never gets dark navy rows with dark-on-dark invisible text. */
html.theme-dark .call-view-input,
html.theme-dark .call-view-row,
html.theme-dark .call-view-empty,
html.theme-dark .call-recent-row,
html.theme-dark .call-recent-empty {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text);
}
html.theme-dark .call-view-row:hover,
html.theme-dark .call-view-row.is-active,
html.theme-dark .call-recent-row:hover {
  background: var(--primary-tint);
  border-color: var(--primary);
}
html.theme-dark .call-view-row-slug,
html.theme-dark .call-recent-slug,
html.theme-dark .call-recent-title {
  color: var(--text);
}
html.theme-dark .call-view-row-name,
html.theme-dark .call-view-row-desc,
html.theme-dark .call-view-hint,
html.theme-dark .call-recent-meta,
html.theme-dark .call-view-empty,
html.theme-dark .call-recent-empty {
  color: var(--text-muted);
}
html.theme-dark .call-recent-summary {
  color: var(--text, #E5E7EB);
}
html.theme-dark .call-recent-summary.is-empty {
  color: var(--text-muted, #94A3B8);
}

.my-calendar-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 18px;
  padding: 16px 18px 28px;
  align-items: start;
  /* Take all remaining vertical space inside #myCalendarView (which is a
     flex column with overflow:hidden) and let the body scroll when the
     month-list / 3-day / day-timeline content exceeds the viewport.
     Without these three lines the body sat at its natural content height
     and the bottom days fell off the page with no way to reach them. */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}
@media (max-width: 1100px) {
  .my-calendar-body { grid-template-columns: 1fr; }
}
.my-calendar-grid-wrap {
  display: flex; flex-direction: column; gap: 8px;
  min-width: 0;
  overflow: hidden;
}
.my-calendar-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  padding: 0 2px;
}
.my-calendar-weekday {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-muted, #64748b);
  text-align: center;
  padding: 4px 0;
}
.my-calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: minmax(96px, 1fr);
  gap: 6px;
  background: var(--surface-sunk, #f8fafc);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 12px;
  padding: 6px;
}
.my-calendar-cell {
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px;
  padding: 6px 6px 4px;
  min-height: 96px;
  display: flex; flex-direction: column;
  gap: 4px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
  outline: none;
}
.my-calendar-cell:hover { background: rgba(0, 120, 191, 0.04); }
.my-calendar-cell:focus-visible {
  border-color: var(--primary, #0078BF);
  box-shadow: 0 0 0 2px rgba(0, 120, 191, 0.18);
}
.my-calendar-cell.off-month { background: rgba(148, 163, 184, 0.06); color: var(--text-faint, #94a3b8); }
.my-calendar-cell.off-month .my-calendar-cell-head { color: var(--text-faint, #94a3b8); }
.my-calendar-cell.is-today { border-color: var(--primary, #0078BF); }
.my-calendar-cell.is-today .my-calendar-cell-head { color: var(--primary, #0078BF); font-weight: 700; }
.my-calendar-cell.is-armed {
  border-color: var(--brand-amber, #f59e0b);
  background: rgba(245, 158, 11, 0.10);
  box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.22);
}
.my-calendar-cell-head {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12px; font-weight: 600; color: var(--text, #0f172a);
  padding: 0 2px;
}
.my-calendar-today-dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--primary, #0078BF);
}
.my-calendar-chips {
  display: flex; flex-direction: column; gap: 3px;
  margin-top: 2px; min-height: 0; overflow: hidden;
}
.my-calendar-chip {
  display: inline-flex; align-items: center; gap: 5px;
  width: 100%;
  padding: 3px 6px;
  border-radius: 6px;
  border: 1px solid transparent;
  font-size: 11px;
  font-weight: 500;
  color: var(--text, #0f172a);
  background: rgba(0, 120, 191, 0.08);
  cursor: pointer;
  text-align: left;
  overflow: hidden;
  white-space: nowrap;
}
.my-calendar-chip:hover { filter: brightness(0.97); }
.my-calendar-chip:focus-visible { outline: 2px solid var(--primary, #0078BF); outline-offset: 1px; }
.my-calendar-chip.is-meeting { background: rgba(228, 76, 154, 0.12); border-color: rgba(228, 76, 154, 0.30); color: #88296a; }
.my-calendar-chip.is-task { background: rgba(16, 185, 129, 0.12); border-color: rgba(16, 185, 129, 0.30); color: #047857; }
.my-calendar-chip.is-task.priority-critical { background: rgba(220, 38, 38, 0.12); border-color: rgba(220, 38, 38, 0.30); color: #b91c1c; }
.my-calendar-chip.is-task.priority-nice_to_have { background: rgba(148, 163, 184, 0.18); border-color: rgba(148, 163, 184, 0.35); color: #475569; }
.my-calendar-chip-icon { flex-shrink: 0; }
.my-calendar-chip-time { font-variant-numeric: tabular-nums; flex-shrink: 0; opacity: 0.85; font-size: 10px; }
.my-calendar-chip-title { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

.my-calendar-detail { margin-top: 10px; }
.my-calendar-detail-card {
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
  background: var(--surface, #fff);
  padding: 12px 14px;
  display: flex; flex-direction: column; gap: 8px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.my-calendar-detail-card.is-meeting { border-left: 4px solid var(--brand-pink, #E44C9A); }
.my-calendar-detail-card.is-task { border-left: 4px solid var(--brand-emerald, #10b981); }
.my-calendar-detail-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.my-calendar-detail-head h4 { margin: 0; font-size: 15px; font-weight: 600; }
.my-calendar-detail-meta {
  font-size: 12px;
  color: var(--text-muted, #475569);
  font-variant-numeric: tabular-nums;
}
.my-calendar-detail-link {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--primary, #0078BF);
  text-decoration: none;
  font-weight: 500;
  font-size: 13px;
}
.my-calendar-detail-link:hover { text-decoration: underline; }
.my-calendar-detail-desc {
  font-size: 13px;
  color: var(--text, #0f172a);
  white-space: pre-wrap;
  word-break: break-word;
  padding: 6px 0;
}
.my-calendar-detail-actions { display: flex; flex-wrap: wrap; gap: 8px; }

.my-calendar-armed-note {
  font-size: 12px;
  background: rgba(245, 158, 11, 0.10);
  border: 1px solid rgba(245, 158, 11, 0.35);
  border-radius: 8px;
  padding: 8px 12px;
  color: #854d0e;
}

/* Side rail — unscheduled tasks pool. `overflow-x: hidden` + `min-width: 0`
   on every flex descendant is critical: task titles often contain long
   email addresses / URLs without word breaks, and without these the row
   blows past the rail's 320 px column and visually leaks to the left
   (clipping the start of the title). `overflow-wrap: anywhere` on the
   text spans is the second half of the same fix — it lets the browser
   break inside the long token instead of growing the box. */
.my-calendar-siderail {
  background: var(--surface-sunk, #f8fafc);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 12px;
  padding: 12px;
  display: flex; flex-direction: column; gap: 10px;
  position: sticky;
  top: 12px;
  max-height: calc(100vh - 80px);
  overflow-y: auto;
  overflow-x: hidden;
  min-width: 0;
}
.my-calendar-siderail-head { min-width: 0; }
.my-calendar-siderail-head h3 { margin: 0 0 4px; font-size: 14px; font-weight: 600; }
.my-calendar-siderail-head .chat-subtitle { font-size: 11px; line-height: 1.4; }
.my-calendar-unscheduled-list {
  display: flex; flex-direction: column; gap: 8px;
  min-width: 0;
}
.my-calendar-task-row {
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-left: 4px solid var(--brand-emerald, #10b981);
  border-radius: 8px;
  padding: 8px 10px;
  display: flex; flex-direction: column; gap: 4px;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
}
.my-calendar-task-row.priority-critical { border-left-color: var(--danger, #dc2626); }
.my-calendar-task-row.priority-nice_to_have { border-left-color: var(--text-faint, #94a3b8); }
.my-calendar-task-head {
  display: flex; flex-direction: column; gap: 2px;
  background: transparent; border: none; padding: 0;
  text-align: left; font: inherit; color: inherit;
  cursor: pointer;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  outline: none;
}
.my-calendar-task-head:focus-visible {
  outline: 2px solid var(--primary, #0078BF);
  outline-offset: 2px;
  border-radius: 4px;
}
.my-calendar-task-title {
  font-size: 13px; font-weight: 600; color: var(--text, #0f172a);
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
  line-height: 1.35;
}
.my-calendar-task-meta {
  font-size: 11px; color: var(--text-muted, #64748b);
  text-transform: capitalize;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.my-calendar-task-desc {
  font-size: 12px; color: var(--text-muted, #475569);
  overflow-wrap: anywhere;
  word-break: break-word;
  line-height: 1.45;
  /* Two-line clamp so cards stay scannable instead of paragraph-shaped. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.my-calendar-inline-planner {
  display: flex; flex-wrap: wrap; align-items: end; gap: 8px;
  padding-top: 6px;
  border-top: 1px dashed var(--border, #e2e8f0);
  margin-top: 6px;
}
.my-calendar-inline-field {
  display: flex; flex-direction: column; gap: 2px;
  font-size: 11px; color: var(--text-muted, #475569);
}
.my-calendar-inline-field input {
  padding: 4px 6px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 6px;
  font: inherit;
  font-size: 13px;
}
.my-calendar-planner-hint {
  font-size: 11px;
  color: var(--text-faint, #94a3b8);
  flex-basis: 100%;
  font-style: italic;
}
.my-calendar-empty {
  font-size: 12px;
  color: var(--text-muted, #64748b);
  padding: 12px 6px;
  text-align: center;
}
.my-calendar-loading { padding: 16px; color: var(--text-muted, #64748b); font-size: 13px; text-align: center; }
.my-calendar-err {
  padding: 8px 12px; border-radius: 6px;
  background: rgba(220, 38, 38, 0.08);
  border: 1px solid rgba(220, 38, 38, 0.30);
  color: var(--danger, #b91c1c);
  font-size: 12px;
  margin-top: 6px;
}

/* ─── My Calendar — view toggle + admin picker (header bar) ────────────
   Pill group for Today / Next 3 days / Month list. The active button
   reads the primary brand colour so it's obvious without colour
   blindness issues. Admin user picker sits in the same header. */
.my-calendar-view-toggle {
  display: inline-flex;
  background: var(--surface-sunk, #f1f5f9);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px;
  padding: 2px;
  gap: 2px;
}
.my-calendar-view-toggle button {
  padding: 4px 10px;
  border-radius: 6px;
  border: none;
  background: transparent;
  color: var(--text-muted, #475569);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
}
.my-calendar-view-toggle button:focus-visible {
  outline: 2px solid var(--primary, #0078BF);
  outline-offset: 1px;
}
.my-calendar-view-toggle button.is-active {
  background: var(--surface, #fff);
  color: var(--primary, #0078BF);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
  font-weight: 600;
}
.my-calendar-user-picker {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--text-muted, #475569);
}
.my-calendar-user-picker-label { font-weight: 500; }
.my-calendar-user-picker select {
  padding: 4px 8px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 6px;
  font-size: 12px;
  background: var(--surface, #fff);
}

/* ─── Availability summary ────────────────────────────────────────── */
.my-calendar-summary {
  padding: 0 18px;
  display: flex; flex-direction: column; gap: 8px;
}
.my-calendar-availability {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
  padding: 10px 14px;
  background: var(--surface-sunk, #f8fafc);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
  font-size: 13px;
  color: var(--text, #0f172a);
}
.my-calendar-avail-day { font-weight: 600; font-size: 14px; }
.my-calendar-avail-stat { color: var(--text-muted, #475569); }
.my-calendar-avail-stat b { color: var(--text, #0f172a); font-weight: 600; }
.my-calendar-avail-booked b { color: var(--brand-pink, #E44C9A); }
.my-calendar-avail-free b   { color: var(--brand-emerald, #10b981); }
.my-calendar-admin-badge {
  align-self: flex-start;
  font-size: 11px; padding: 4px 10px;
  background: rgba(245, 158, 11, 0.12);
  border: 1px solid rgba(245, 158, 11, 0.35);
  color: #854d0e;
  border-radius: 999px;
  font-weight: 500;
}
.my-calendar-add-here { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* ─── Today / 3-day timeline columns ─────────────────────────────── */
.my-calendar-today-view { padding: 4px 18px 24px; display: flex; flex-direction: column; gap: 8px; }
.my-calendar-three-day-view {
  padding: 4px 18px 24px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  align-items: start;
}
.my-calendar-tl-col {
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
  padding: 8px;
  display: flex; flex-direction: column;
  min-width: 0;
}
.my-calendar-tl-col.is-today { border-color: var(--primary, #0078BF); box-shadow: 0 0 0 1px rgba(0,120,191,0.12); }
.my-calendar-tl-col-head {
  display: flex; align-items: baseline; gap: 8px;
  padding: 4px 6px 8px;
  border-bottom: 1px solid var(--border, #e2e8f0);
}
.my-calendar-tl-day-name { font-size: 12px; text-transform: uppercase; letter-spacing: 0.3px; color: var(--text-muted, #64748b); font-weight: 600; }
.my-calendar-tl-day-num { font-size: 14px; font-weight: 600; color: var(--text, #0f172a); }
.my-calendar-tl-day-tag { margin-left: auto; font-size: 11px; color: var(--text-muted, #64748b); }
.my-calendar-tl-add-row { display: flex; flex-direction: column; gap: 6px; padding: 8px 4px; border-bottom: 1px solid var(--border, #e2e8f0); }
.my-calendar-tl-scroll {
  position: relative;
  margin-top: 6px;
  overflow: hidden;
}
.my-calendar-tl-hour {
  position: relative;
  border-top: 1px dashed var(--border, #e2e8f0);
  display: flex;
}
.my-calendar-tl-hour-label {
  flex: 0 0 46px;
  font-size: 10px;
  color: var(--text-faint, #94a3b8);
  padding-top: 2px;
  font-variant-numeric: tabular-nums;
}
.my-calendar-tl-block {
  position: absolute;
  left: 50px; right: 4px;
  border-radius: 6px;
  border: 1px solid transparent;
  padding: 4px 8px;
  text-align: left;
  font-size: 11px;
  font-weight: 500;
  display: flex; flex-direction: column; gap: 1px;
  overflow: hidden;
  cursor: pointer;
  background: rgba(0, 120, 191, 0.10);
  color: var(--text, #0f172a);
  min-width: 0;
}
.my-calendar-tl-block:focus-visible {
  outline: 2px solid var(--primary, #0078BF);
  outline-offset: 1px;
}
.my-calendar-tl-block.is-meeting { background: rgba(228, 76, 154, 0.12); border-color: rgba(228, 76, 154, 0.30); color: #88296a; }
.my-calendar-tl-block.is-task    { background: rgba(16, 185, 129, 0.12); border-color: rgba(16, 185, 129, 0.30); color: #047857; }
.my-calendar-tl-block.is-task.priority-critical { background: rgba(220, 38, 38, 0.12); border-color: rgba(220, 38, 38, 0.30); color: #b91c1c; }
.my-calendar-tl-block.is-task.priority-nice_to_have { background: rgba(148, 163, 184, 0.18); border-color: rgba(148, 163, 184, 0.35); color: #475569; }
.my-calendar-tl-block-time { font-size: 10px; opacity: 0.85; font-variant-numeric: tabular-nums; }
.my-calendar-tl-block-title {
  font-weight: 600; font-size: 12px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0;
}
.my-calendar-tl-now {
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  background: var(--brand-pink, #E44C9A);
  z-index: 2;
}
.my-calendar-tl-now::before {
  content: ''; position: absolute;
  left: 44px; top: -3px; width: 8px; height: 8px;
  background: var(--brand-pink, #E44C9A);
  border-radius: 50%;
}
.my-calendar-tl-offscreen {
  position: absolute;
  left: 50px; right: 4px;
  font-size: 10px;
  color: var(--text-muted, #64748b);
  background: rgba(15, 23, 42, 0.04);
  padding: 2px 8px;
  border-radius: 4px;
  cursor: pointer;
}

/* ─── Month list (long agenda) view ──────────────────────────────── */
.my-calendar-month-list-view {
  padding: 4px 18px 24px;
  display: flex; flex-direction: column;
  gap: 6px;
}
.my-calendar-ml-day {
  display: flex; flex-direction: column;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
  background: var(--surface, #fff);
  overflow: hidden;
}
.my-calendar-ml-day.is-today { border-color: var(--primary, #0078BF); box-shadow: 0 0 0 1px rgba(0,120,191,0.10); }
.my-calendar-ml-day-head {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px;
  background: var(--surface-sunk, #f8fafc);
  border-bottom: 1px solid var(--border, #e2e8f0);
}
.my-calendar-ml-day-label { display: flex; align-items: baseline; gap: 8px; }
.my-calendar-ml-day-num { font-size: 18px; font-weight: 700; color: var(--text, #0f172a); }
.my-calendar-ml-day-name { font-size: 12px; color: var(--text-muted, #64748b); text-transform: uppercase; letter-spacing: 0.3px; font-weight: 600; }
.my-calendar-ml-day-actions { margin-left: auto; }
.my-calendar-ml-empty {
  padding: 8px 14px;
  font-size: 12px;
  color: var(--text-faint, #94a3b8);
  font-style: italic;
}
.my-calendar-ml-list { display: flex; flex-direction: column; }
.my-calendar-ml-row {
  display: grid;
  grid-template-columns: 60px 22px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 8px 14px;
  text-align: left;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border, #e2e8f0);
  border-left: 3px solid transparent;
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.my-calendar-ml-row:last-child { border-bottom: none; }
.my-calendar-ml-row:hover { background: rgba(0, 120, 191, 0.04); }
.my-calendar-ml-row:focus-visible {
  outline: 2px solid var(--primary, #0078BF);
  outline-offset: -2px;
}
.my-calendar-ml-row.is-meeting { border-left-color: var(--brand-pink, #E44C9A); }
.my-calendar-ml-row.is-task    { border-left-color: var(--brand-emerald, #10b981); }
.my-calendar-ml-row.is-task.priority-critical { border-left-color: var(--danger, #dc2626); }
/* Due-state stripes override the default by priority / kind. Order in
   this file matters because all of these are equal-specificity .is-*
   selectors — keep due-state rules AFTER the kind/priority rules so they
   win for the visual cases that matter most: overdue + today. Stripe also
   widens slightly (4px vs 3px) so overdue rows stand out more on a long
   scrolling agenda. */
.my-calendar-ml-row.is-overdue  { border-left-color: var(--danger, #dc2626); border-left-width: 4px; }
.my-calendar-ml-row.is-overdue  .my-calendar-ml-row-time,
.my-calendar-ml-row.is-overdue  .my-calendar-ml-row-title { color: var(--danger, #dc2626); }
.my-calendar-ml-row.is-today    { border-left-color: var(--brand-amber, #D97706); border-left-width: 4px; }
.my-calendar-ml-row.is-today    .my-calendar-ml-row-time { color: var(--brand-amber, #D97706); font-weight: 600; }
.my-calendar-ml-row.is-tomorrow { border-left-color: var(--brand-teal, #0D7377); }
.my-calendar-ml-row-time { font-size: 12px; font-variant-numeric: tabular-nums; color: var(--text-muted, #475569); }
.my-calendar-ml-row-icon { text-align: center; }
.my-calendar-ml-row-title {
  font-size: 13px; font-weight: 500; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.my-calendar-ml-row-dur { font-size: 11px; color: var(--text-faint, #94a3b8); }

/* ─── Quick-add task inline form ─────────────────────────────────── */
.my-calendar-quick-add {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 8px 12px;
  background: var(--surface-sunk, #f8fafc);
  border-top: 1px dashed var(--border, #e2e8f0);
  margin-top: 4px;
}
.my-calendar-quick-add input[type=text] { flex: 1 1 200px; min-width: 140px; padding: 5px 10px; font-size: 13px; border: 1px solid var(--border, #e2e8f0); border-radius: 6px; }
.my-calendar-quick-add input[type=time],
.my-calendar-quick-add input[type=number],
.my-calendar-quick-add select { padding: 5px 8px; font-size: 13px; border: 1px solid var(--border, #e2e8f0); border-radius: 6px; }
.my-calendar-quick-add input[type=number] { width: 72px; }
.my-calendar-qa-hint { font-size: 11px; color: var(--text-faint, #94a3b8); font-style: italic; flex-basis: 100%; }

/* ── Agent Training UI (Phase 5) ────────────────────────────────────── */
.training-body { padding: 16px; max-width: 980px; margin: 0 auto; display: grid; gap: 16px; }
.training-tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--border, #e2e8f0); }
.training-tab { background: transparent; border: none; padding: 8px 14px; font-size: 13px; font-weight: 600;
  color: var(--text-faint, #64748b); cursor: pointer; border-bottom: 2px solid transparent; border-radius: 0; }
.training-tab.active { color: #0078BF; border-bottom-color: #0078BF; }
.training-tab:focus-visible { outline: 2px solid #0078BF; outline-offset: 2px; }
.training-panel { display: grid; gap: 16px; }
.training-panel.hidden { display: none; }
.training-list { display: grid; gap: 8px; }
.training-row { background: var(--surface, #fff); border: 1px solid var(--border, #e2e8f0); border-radius: 10px;
  padding: 12px 14px; display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: center; }
.training-row .meta { color: var(--text-faint, #64748b); font-size: 12px; }
.training-row .actions { display: flex; gap: 6px; }
.training-row.archived { opacity: 0.55; }
.training-add-form { background: var(--surface, #fff); border: 1px solid var(--border, #e2e8f0); border-radius: 10px;
  padding: 14px; display: grid; gap: 10px; }
.training-add-form h4 { margin: 0 0 4px; font-size: 13px; font-weight: 700; color: #0078BF; text-transform: uppercase; letter-spacing: 1.5px; }
.training-add-form .field { display: grid; gap: 4px; }
.training-add-form .field-label { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: var(--text-faint, #64748b); }
.training-add-form input, .training-add-form select { padding: 6px 10px; font-size: 13px; border: 1px solid var(--border, #e2e8f0); border-radius: 6px; background: var(--bg, #fff); color: inherit; }
.training-form-actions { display: flex; align-items: center; gap: 6px; }
.training-empty { background: #FFF4F8; border: 1px dashed #E44C9A; border-radius: 10px; padding: 14px; text-align: center; }
.training-empty p { margin: 0 0 10px; font-size: 13px; color: #6B7280; }
.training-result { background: #F7FAFC; border: 1px solid #cfe5f5; border-radius: 10px; padding: 14px; display: grid; gap: 10px; }
.training-result .url-box { font-family: monospace; font-size: 12px; padding: 8px 10px; background: #fff; border: 1px solid var(--border, #e2e8f0); border-radius: 6px; word-break: break-all; }
.training-result .qr-box { display: flex; justify-content: center; padding: 8px; background: #fff; border-radius: 8px; }
.training-result .qr-box svg { width: 200px; height: 200px; }
.training-detail { background: #fff; border: 1px solid var(--border, #e2e8f0); border-radius: 10px; padding: 14px; display: grid; gap: 10px; }
.training-detail h4 { margin: 0; font-size: 13px; }
.training-msg { padding: 8px 10px; border-radius: 8px; font-size: 13px; line-height: 1.5; }
.training-msg.trainer { background: #EEF6FC; border-left: 3px solid #0078BF; }
.training-msg.agent { background: #F8F5FB; border-left: 3px solid #E44C9A; }
.training-msg.error { background: #FDECEC; border-left: 3px solid #B42318; }
.training-msg .meta { font-size: 11px; color: var(--text-faint, #64748b); margin-bottom: 2px; }
@media (max-width: 720px) {
  .training-row { grid-template-columns: 1fr; }
  .training-row .actions { justify-content: flex-end; }
}

/* ── Share / Publish panel + visitor banner (thread publishing) ──
 * Inline panels per the design rule "never use dialogue boxes".
 * sharePanel toggles from the Share button in the chat header.
 * shareVisitorBanner appears above the message list when the viewer
 * is opening a published thread they don't own.
 */
/* WhatsApp share panel — variant of .share-panel, drops below the chat
   header next to the existing publish panel. Styled with a WhatsApp-green
   accent so it's instantly distinguishable from the standard share panel. */
.whatsapp-share-panel { border-left: 3px solid #25D366; }
.whatsapp-share-add {
  margin: 8px 0 12px;
  padding: 10px 12px;
  background: var(--surface, #f9fafb);
  border: 1px solid var(--divider, #e5e7eb);
  border-radius: 8px;
}
.whatsapp-share-label {
  display: block;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 700;
  color: var(--text-muted, #6b7280);
  margin-bottom: 4px;
}
.whatsapp-share-add-row {
  display: flex;
  gap: 8px;
  align-items: center;
}
/* ── Multi-number composer (22 Jul 2026 group share) ─────────────────
   Each row = one (phone, participant-name) pair. Grid so the two inputs
   size predictably and the delete button clings to the right. */
.whatsapp-share-add-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.whatsapp-share-add-row-multi {
  display: grid;
  grid-template-columns: minmax(140px, 1fr) minmax(120px, 1fr) auto;
  gap: 6px;
  align-items: center;
}
.whatsapp-share-add-row-multi .whatsapp-share-input { flex: none; }
.whatsapp-share-add-row-remove {
  padding: 4px 8px;
  font-size: 12px;
  color: var(--danger, #b91c1c);
  border: 1px solid transparent;
  background: transparent;
  border-radius: 6px;
  cursor: pointer;
}
.whatsapp-share-add-row-remove:hover {
  background: rgba(239, 68, 68, 0.08);
  border-color: rgba(239, 68, 68, 0.35);
}
.whatsapp-share-add-row-remove[disabled] {
  opacity: 0.35;
  cursor: not-allowed;
}
.whatsapp-share-add-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 8px;
  flex-wrap: wrap;
}
/* Group-name row — hidden until 2+ rows or 2+ existing bridges. */
.whatsapp-share-group-row {
  margin-bottom: 8px;
}
.whatsapp-share-group-row.hidden { display: none; }
/* Per-participant name pill on a rendered bridge row. */
.whatsapp-share-row-name {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text, #111);
  margin-right: 6px;
}
.whatsapp-share-row-name-input {
  padding: 3px 6px;
  font-size: 12.5px;
  font-family: inherit;
  background: var(--surface, #fff);
  color: var(--text, #111);
  border: 1px dashed var(--divider, #d1d5db);
  border-radius: 5px;
  width: 130px;
  max-width: 40vw;
}
.whatsapp-share-row-name-input:focus {
  outline: 2px solid #25D366;
  outline-offset: -2px;
  border-color: transparent;
  border-style: solid;
}
.whatsapp-share-input {
  flex: 1;
  padding: 7px 10px;
  font-size: 13.5px;
  font-family: inherit;
  background: var(--surface, #fff);
  color: var(--text, #111);
  border: 1px solid var(--divider, #d1d5db);
  border-radius: 6px;
}
.whatsapp-share-input:focus {
  outline: 2px solid #25D366;
  outline-offset: -2px;
  border-color: transparent;
}
.whatsapp-share-current {
  margin-top: 10px;
}
.whatsapp-share-current-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted, #6b7280);
  margin-bottom: 6px;
}
.whatsapp-share-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.whatsapp-share-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--surface, #fff);
  border: 1px solid var(--divider, #e5e7eb);
  border-radius: 6px;
}
.whatsapp-share-row-phone {
  font-size: 13.5px;
  font-weight: 600;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--text, #111);
}
.whatsapp-share-row-sub {
  font-size: 11.5px;
  color: var(--text-muted, #6b7280);
  margin-top: 1px;
}
/* Multi-thread routing indicator per bridge row (23 Jul 2026 · aiassiztant
   ask). Only visible when the phone is bound to 2+ threads — the underlying
   `_renderWhatsAppBridgesList` gates on `b.routing.ambiguous`. Three
   states: is-current (green, this thread is the default route),
   is-elsewhere (amber, another thread is the default — action button
   offered), is-pending (grey, user hasn't picked yet from the WhatsApp
   menu). */
.whatsapp-share-row-routing {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 11.5px;
  margin-top: 4px;
  padding: 4px 8px;
  border-radius: 6px;
  line-height: 1.35;
}
.whatsapp-share-row-routing.is-current {
  background: rgba(37, 211, 102, 0.08);
  color: #15803d;
}
.whatsapp-share-row-routing.is-elsewhere {
  background: rgba(217, 119, 6, 0.08);
  color: #b45309;
}
.whatsapp-share-row-routing.is-pending {
  background: rgba(107, 114, 128, 0.08);
  color: var(--text-muted, #6b7280);
}
.whatsapp-share-row-routing .whatsapp-share-route-here {
  padding: 2px 8px;
  font-size: 11.5px;
  border-radius: 999px;
  color: var(--brand-teal, #0f766e);
  border: 1px solid currentColor;
  background: transparent;
  cursor: pointer;
}
.whatsapp-share-row-routing .whatsapp-share-route-here:hover {
  background: rgba(15, 118, 110, 0.08);
}
.whatsapp-share-row-status {
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-radius: 999px;
}
.whatsapp-share-row-status.status-pending {
  background: rgba(217, 119, 6, 0.12);
  color: #b45309;
}
.whatsapp-share-row-status.status-active {
  background: rgba(37, 211, 102, 0.16);
  color: #15803d;
}
.whatsapp-share-row-status.status-revoked {
  background: rgba(239, 68, 68, 0.12);
  color: #b91c1c;
}
.whatsapp-share-revoke { color: var(--danger, #b91c1c); }

.share-panel {
  background: var(--card, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px;
  margin: 8px 16px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
  /* Inline panel under #chatHeader. #chat is a flex column with
     overflow:hidden and #messages is flex:1 — so this panel MUST
     NOT shrink (flex-shrink:0). Earlier flex:0 1 auto + min-height:0
     let #messages crush it to header-only height (body invisible).
     Cap height and scroll internally when invite roster / WhatsApp
     rows get long. */
  flex: 0 0 auto;
  max-height: min(70vh, 520px);
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.share-panel.hidden { display: none; }
.share-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Keep title + close sticky while the panel body scrolls. */
  position: sticky;
  top: -14px; /* cancel panel padding so sticky sits flush at top edge */
  margin: -14px -16px 0;
  padding: 14px 16px 8px;
  background: var(--card, #fff);
  z-index: 2;
}
.share-panel-blurb {
  margin: 0;
  font-size: 13px;
  color: var(--text-muted, #64748b);
  line-height: 1.45;
}
.share-panel-mode {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.share-mode-opt {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
}
.share-mode-opt:has(input:checked) {
  border-color: #0078BF;
  background: #f0f8fe;
}
.share-mode-label { line-height: 1.4; }
/* Auto-approve checkbox row — sits between the mode radios and the share URL.
   Greys out when disabled (Fork mode) so the dimming makes the gating obvious. */
.share-auto-approve {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 8px 10px;
  /* margin-bottom removed 20 Aug 2026 — parent `.share-panel` gap:10px
     already spaces this from the Publish row below. The extra 8px was
     stacking on top of the gap and made the Auto-approve → Publish
     gutter noticeably larger than the other row-to-row gaps. */
  margin: 0;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 6px;
  background: #fafbfc;
  cursor: pointer;
}
.share-auto-approve input[type="checkbox"] { margin-top: 3px; }
.share-auto-approve:has(input:disabled) { opacity: .5; cursor: not-allowed; }
.share-auto-approve:has(input:checked:not(:disabled)) {
  border-color: #0078BF;
  background: #f0f8fe;
}
.share-auto-approve-label { line-height: 1.4; font-size: 13px; }
.share-auto-approve-sub { color: var(--muted, #64748b); font-size: 12px; display: block; margin-top: 2px; }
.share-url-row {
  display: flex;
  gap: 6px;
  align-items: center;
}
.share-url-row.hidden { display: none; }
.share-url-input {
  flex: 1;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  padding: 7px 9px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 4px;
  background: #f8fafc;
}
.share-panel-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.share-panel-flash {
  font-size: 12px;
  color: var(--text-muted, #64748b);
}
.share-panel-flash.error { color: #B42318; }
.share-panel-flash.success { color: #059669; }

/* ─────────────────────────────────────────────────────────────────────
   Visit App / Website popover — surfaces the project's live_url +
   extra_urls in a flip-down list under the thread header. Reuses the
   .share-panel chrome so admins recognize the pattern; extra styling
   here is just the list rows themselves. Declared 16 Jul 2026 v1 ·
   Musheer ask (see #visitAppBtn in index.html + updateThreadHeader
   in app.js). Left border tint distinguishes it from Share/WhatsApp.
   ───────────────────────────────────────────────────────────────────── */
.visit-app-popover { border-left: 3px solid #0078BF; }
.visit-app-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.visit-app-list-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 6px;
  background: #fafbfc;
  color: var(--text, #0f172a);
  text-decoration: none;
  font-size: 13px;
  transition: background 0.12s, border-color 0.12s;
  min-height: 44px; /* keyboard + touch target parity with mini app */
  box-sizing: border-box;
}
.visit-app-list-item:hover,
.visit-app-list-item:focus-visible {
  background: #f0f8fe;
  border-color: #0078BF;
  outline: none;
}
.visit-app-list-item-label {
  font-weight: 600;
  flex: 0 0 auto;
}
.visit-app-list-item-url {
  color: var(--text-muted, #64748b);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
  min-width: 0;
}
.visit-app-list-item-external {
  flex: 0 0 auto;
  color: var(--text-muted, #64748b);
  display: inline-flex;
  align-items: center;
}
.visit-app-list-item:hover .visit-app-list-item-external,
.visit-app-list-item:focus-visible .visit-app-list-item-external {
  color: #0078BF;
}

/* ─────────────────────────────────────────────────────────────────────
   Invite team members — direct-invite path parallel to the share URL.
   Sits at the bottom of the share panel. Backed by the
   /api/threads/:id/invitees GET/POST/DELETE endpoints. Uses a
   searchable combobox (keyboard-only navigable — arrow keys + Enter +
   Esc — per the global design rule).
   ───────────────────────────────────────────────────────────────────── */
.share-invite-section {
  /* Tightened 20 Aug 2026 (v2) — the parent `.share-panel` already has
     gap:10px between every child, so any margin-top / padding-top here
     stacks on top of that gap and produces a visibly larger gutter
     under Publish than between the other cards. Drop margin-top to 0
     and let the dashed border sit right at the top edge of the section;
     use only a small internal padding for breathing room between the
     rule and the "Invite team members" header. Net gap under Publish
     is now identical to the gaps between the other stacked rows. */
  margin-top: 0;
  padding-top: 6px;
  border-top: 1px dashed var(--border, #e2e8f0);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.share-invite-current-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-top: 2px;
}
.share-invite-current-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted, #64748b);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.share-invite-current-count {
  font-size: 11px;
  color: var(--text-muted, #94a3b8);
  font-weight: 500;
}
.share-invite-head strong { font-size: 13px; }
.share-invite-sub {
  color: var(--text-muted, #64748b);
  font-size: 12px;
  margin-left: 6px;
}
.share-invite-composer {
  display: flex;
  align-items: stretch;
  gap: 8px;
  flex-wrap: wrap;
}
.share-invite-combobox {
  position: relative;
  flex: 1 1 220px;
  min-width: 180px;
}
.share-invite-input {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 4px;
  font-size: 13px;
  background: #fff;
  box-sizing: border-box;
}
.share-invite-input:focus {
  outline: none;
  border-color: #0078BF;
  box-shadow: 0 0 0 2px rgba(0, 120, 191, 0.15);
}
.share-invite-results {
  position: absolute;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  max-height: 220px;
  overflow-y: auto;
  margin: 0;
  padding: 4px 0;
  list-style: none;
  background: #fff;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  z-index: 20;
}
.share-invite-results.hidden { display: none; }
.share-invite-result {
  padding: 6px 10px;
  font-size: 13px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
  line-height: 1.35;
}
.share-invite-result.is-active,
.share-invite-result:hover {
  background: #f0f8fe;
}
.share-invite-result-name { font-weight: 500; color: var(--text, #0f172a); }
.share-invite-result-meta { font-size: 11px; color: var(--text-muted, #64748b); }
.share-invite-result-empty {
  padding: 8px 10px;
  font-size: 12px;
  color: var(--text-muted, #64748b);
  font-style: italic;
}
.share-invite-auto-approve {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-muted, #475569);
  cursor: pointer;
  user-select: none;
}
.share-invite-auto-approve.hidden { display: none; }
.share-invite-list {
  list-style: none;
  padding: 0;
  margin: 4px 0 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.share-invite-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 10px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 4px;
  background: #fafbfc;
  font-size: 13px;
}
.share-invite-row-main {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  flex: 1;
}
.share-invite-row-name { font-weight: 500; color: var(--text, #0f172a); }
.share-invite-row-meta { font-size: 11px; color: var(--text-muted, #64748b); }
.share-invite-row-badge {
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 10px;
  background: #dcfce7;
  color: #166534;
  margin-left: 6px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.share-invite-row-revoke {
  border: none;
  background: transparent;
  color: #B42318;
  cursor: pointer;
  padding: 4px 6px;
  font-size: 12px;
  border-radius: 4px;
}
.share-invite-row-revoke:hover { background: #FEE2E2; }
.share-invite-empty {
  font-size: 12px;
  color: var(--text-muted, #64748b);
  font-style: italic;
  padding: 2px 0;
}

.share-visitor-banner {
  background: linear-gradient(180deg, #f0f8fe 0%, #fff 100%);
  border: 1px solid #0078BF;
  border-radius: 8px;
  margin: 8px 16px;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
}
.share-visitor-banner.hidden { display: none; }
.share-visitor-meta {
  display: flex;
  align-items: center;
  gap: 8px;
}
.share-visitor-emoji { font-size: 16px; }

@media (max-width: 720px) {
  .share-panel, .share-visitor-banner { margin: 6px 8px; }
  .share-visitor-banner { flex-direction: column; align-items: flex-start; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Dark mode — applied by `html.theme-dark`, toggled from the sidebar
   header button (#themeToggleBtn). The strategy is to re-bind the small
   set of CSS variables defined at :root so every var()-based surface
   flips automatically. A handful of hard-coded `#fff` / `rgba(0,0,0,*)`
   spots in this file are mopped up below.

   Palette mirrors the brand email dark-template:
     bg          #0B1220   page background
     surface     #111A2C   cards / sidebar / composer
     surface-2   #1A2436   hover / sunk surfaces, code chips
     border      #1F2A40   dividers
     text        #E5E7EB   primary text
     text-muted  #9CA3AF   secondary text
     text-faint  #6B7280   placeholder / labels
   The brand colors (primary / danger / success / warning) are unchanged
   so brand accents remain instantly recognisable across themes.
   ═══════════════════════════════════════════════════════════════════════ */
html.theme-dark {
  color-scheme: dark;

  /* Brand tint is re-tuned because the alpha on a dark surface looks
     washed out at 8%/14% — bump it to 16%/24%. The base #0D7377 stays
     so logos / pills keep their exact identity. */
  --primary-tint: rgba(13, 115, 119, 0.18);
  --primary-tint-strong: rgba(13, 115, 119, 0.30);

  /* Neutrals */
  --bg: #0B1220;
  --surface: #111A2C;
  --surface-alt: #131D33;
  --surface-sunk: #1A2436;
  --border: #1F2A40;
  --border-strong: #2C3A55;
  --divider: #18223A;

  /* Text */
  --text: #E5E7EB;
  --text-muted: #B8C0CC;
  --text-dim: #9CA3AF;
  --text-faint: #6B7280;

  /* Semantic — slightly desaturated for dark backdrops */
  --danger: #F87171;
  --danger-tint: rgba(248, 113, 113, 0.16);
  --warning: #FBBF24;
  --success: #34D399;

  /* Chat bubbles — assistant bubble needs to be a dark surface, not white. */
  --assistant-bubble: #1A2436;

  /* Code — flip the inline-code colors so a teal-on-dark chip reads */
  --inline-code-bg: #1F2A40;
  --inline-code-text: #E5E7EB;
  /* keep --code-bg / --code-text (dark slab) the same — already dark */

  /* Legacy / fallback aliases — flip these too so the 181 callsites that
     use `var(--bg-soft, #f8fafc)` etc. pick up the dark equivalent.
     This is what fixed the Cursor Configuration JSON snippet
     (white-on-white bug reported 29 Jun 2026 by Ashfak). */
  --bg-soft: #1A2436;              /* dark well for code snippets / chips */
  --card: var(--surface);          /* keep alias = surface in both modes */
  --surface-hover: rgba(255, 255, 255, 0.04); /* hover wash on dark surfaces */
  --muted: var(--text-dim);
  /* Brand colours hold their identity — no override needed for
     --brand-teal/-blue/-pink/-amber/-emerald in dark mode. The tint
     and bg variants get a small boost since alpha-on-dark needs more
     opacity to read. */
  --brand-teal-tint: rgba(13, 115, 119, 0.20);
  --brand-blue-bg: rgba(0, 120, 191, 0.20);

  /* Elevation — black is fine, just slightly stronger shadow opacity */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.32), 0 1px 3px rgba(0, 0, 0, 0.40);
  --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.36), 0 8px 24px rgba(0, 0, 0, 0.40);
  --shadow-lg: 0 14px 36px rgba(0, 0, 0, 0.55);
}

/* Mop-up: surfaces that hard-coded a white background look wrong in dark
   mode. These re-route them through the variables so they pick up the
   dark surface automatically. Limit the scope to `html.theme-dark` so
   light mode keeps its current pixel-perfect appearance. */
html.theme-dark .imagine-img-lightbox img { background: var(--surface); }
html.theme-dark body { background: var(--bg); color: var(--text); }
html.theme-dark .brand-mark { color: #fff; }
/* Image previews on white backgrounds become eye-stinging — dim slightly. */
html.theme-dark img:not(.imagine-no-dim) { filter: brightness(0.94); }
html.theme-dark img:hover:not(.imagine-no-dim) { filter: brightness(1.0); }

/* Inputs / textareas: many use a hard white bg or rely on the page body
   bg. Pin them to --surface-alt so they read as a darker well in dark
   mode while still standing out from the page in light mode. */
html.theme-dark input,
html.theme-dark textarea,
html.theme-dark select {
  background-color: var(--surface-alt);
  color: var(--text);
  border-color: var(--border);
}
html.theme-dark input::placeholder,
html.theme-dark textarea::placeholder {
  color: var(--text-faint);
}

/* Scrollbar tint — the platform default is fine in light mode but the
   white track shows through against a near-black page in dark mode. */
html.theme-dark * {
  scrollbar-color: var(--border-strong) var(--surface);
}
html.theme-dark *::-webkit-scrollbar-thumb {
  background-color: var(--border-strong);
  border-radius: 6px;
}
html.theme-dark *::-webkit-scrollbar-track {
  background-color: var(--surface);
}

/* Email Approvals — sidebar badge for pending count (added with feature) */
.sidebar-badge {
  display: inline-block;
  margin-left: 6px;
  background: #E44C9A;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  padding: 3px 7px;
  border-radius: 9px;
  min-width: 18px;
  text-align: center;
  vertical-align: middle;
}
html.theme-dark .sidebar-badge { background: #E44C9A; color: #fff; }

/* ─────────────────────────────────────────────────────────────────
   Notifications → per-kind sub-links in the left sidebar.
   Rendered by renderNotificationKindLinks() below the parent
   #notificationsBtn. Each row is a small indented button with the
   kind label + optional unread pill (reuses .sidebar-badge).
   Visual language matches .sidebar-dashboard-btn but scaled down
   and offset with a subtle left rail so the parent/child link is
   obvious at a glance.
   ────────────────────────────────────────────────────────────── */
.sidebar-kind-links {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 2px 12px 6px 26px; /* indent under bell icon */
  padding-left: 8px;
  border-left: 1px dashed var(--border);
}
.sidebar-kind-links.hidden { display: none; }

.sidebar-kind-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 5px 8px;
  border-radius: 6px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted, var(--text));
  font-size: 12px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: background-color 120ms, border-color 120ms, color 120ms;
}
.sidebar-kind-link:hover {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
  color: var(--primary);
}
.sidebar-kind-link.is-active {
  background: var(--primary-tint);
  border-color: var(--primary-tint-strong);
  color: var(--primary);
  font-weight: 600;
}
.sidebar-kind-link-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar-kind-link-badge {
  margin-left: 0; /* override .sidebar-badge default margin */
  flex-shrink: 0;
}
html.theme-dark .sidebar-kind-link { color: var(--text-muted, #cfd3da); }
html.theme-dark .sidebar-kind-link:hover,
html.theme-dark .sidebar-kind-link.is-active { color: var(--primary); }

/* ═══════════════════════════════════════════════════════════════════════
   Mobile responsive pass (admin-set 29 Jun 2026 · Ashfak)
   ─────────────────────────────────────────────────────────────────────
   Three breakpoint tiers refining what already lives elsewhere in this
   file:

     • 1200px — light: shrinks the right folder panel
     • 980px  — tablet / large phone landscape: layout collapses to a
                single column, sidebar becomes an off-canvas drawer
                (foundation already present above this block)
     • 640px  — phone landscape · tighten paddings + collapse multi-
                column grids · icon-only header actions
     • 480px  — phone portrait · full-bleed drawer, bottom-sheet modals,
                stack everything, prevent iOS textarea zoom

   Design principles applied here:
     1. Touch targets ≥ 40 × 40px (header buttons get min-height)
     2. No horizontal page scroll (overflow-x: hidden on html, body)
     3. iOS textarea zoom prevented (16px font on inputs)
     4. Safe-area-inset honoured (iPhone home bar / notches)
     5. Modals slide up from the bottom on phones, not cramped centered
     6. Sticky composer with backdrop blur over the message column
     7. Multi-column grids collapse to single column
     8. Long titles ellipsize so they never push the header off-screen

   The existing min-width default body grid (300 + 1fr + 260) still
   serves desktop / wide-tablet — the rules below kick in only at the
   listed breakpoints. None of these styles fire on desktop. */

/* ── Hard safety nets — apply everywhere so a stray wide element on
      ANY device can't break the page. ────────────────────────────── */
html, body { overflow-x: hidden; }
/* Allow text-content to wrap rather than push the parent wide.
   Targets headers + paragraph blocks; explicit `white-space:pre` etc.
   later in this file still wins for code blocks. */
h1, h2, h3, h4, h5, p, .ide-editor-path, .thread-title-row h2,
.chat-title-wrap, .cwd-chip, .fpa-name, .folder-panel-name {
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* Allow header-action button rows to wrap if there are too many CTAs to
   fit on one line. Per-view rules below switch to horizontal scroll
   on the chat header where wrapping looks worse. */
.header-actions {
  flex-wrap: wrap;
  row-gap: 6px;
}

/* ── Tablet + large phone landscape (≤ 980px) ──────────────────────
   The existing 980px rule already converts the body grid to single
   column and slides the sidebar off-canvas. We refine it here. */
@media (max-width: 980px) {
  /* Sidebar drawer — a touch wider so menu items aren't cramped. */
  #sidebar { width: 86%; max-width: 340px; }
  /* The right folder panel is hidden at this breakpoint by the existing
     rule. Hide the empty grid column it would have occupied. */
  body { grid-template-columns: 1fr; }
  /* Chat header — let the title shrink so the action buttons stay visible. */
  #chatHeader, #projectHeader, #wizardHeader {
    gap: 8px;
    padding: 10px 14px;
  }
  .chat-title-wrap { min-width: 0; flex: 1 1 auto; }
  .thread-title-row { min-width: 0; }
  .thread-title-row h2 {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 15px;
  }
  .cwd-chip { font-size: 11px; }
  /* Header action buttons — let them scroll horizontally rather than
     wrap-stack, so the title row stays compact and the visible buttons
     are reachable with a thumb-drag. */
  .header-actions {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .header-actions::-webkit-scrollbar { display: none; }
  /* Trim button labels — icon stays, label hides past a certain width.
     Only inside the chat / project headers; modal buttons are unaffected. */
  #chatHeader .header-actions .btn span:not(.sr-only),
  #projectHeader .header-actions .btn span:not(.sr-only) {
    display: none;
  }
  /* The hamburger button itself still wants its icon visible. */
  .mobile-nav-btn { display: inline-flex !important; }
  /* IDE slide-in editor — full-width on tablet so the file is actually
     readable. The wide-screen rule pins it at 720px which is cramped. */
  #ideEditor { width: 100%; max-width: 100%; left: 0; right: 0; }
  /* Multi-column dashboards on the tablet step start collapsing. */
  .dashboard-grid,
  .project-grid,
  .my-team-grid,
  .my-hiring-grid {
    grid-template-columns: 1fr 1fr !important;
  }
}

/* ── Phone landscape (≤ 640px) — already partially handled by the
      pre-existing 640px block; we add to it without conflicting. ── */
@media (max-width: 640px) {
  /* Sidebar full-width-ish so 13-character thread titles don't truncate. */
  #sidebar { width: 92%; max-width: none; }
  /* Chat title shrinks further; rename pencil hides (long-press still works on desktop). */
  #chatHeader, #projectHeader, #wizardHeader {
    padding: 8px 12px;
    gap: 6px;
  }
  .thread-title-row h2 { font-size: 14px; }
  .thread-title-row .thread-rename-btn { display: none; }
  /* All multi-column content collapses to one column. Generic catch-all
     for any view we haven't enumerated. */
  #dashboard .dashboard-grid,
  #dashboard .project-grid,
  #dashboard .my-team-grid,
  #dashboard .my-hiring-grid,
  #project .dashboard-grid,
  #project .project-grid,
  #project .my-team-grid,
  #project .my-hiring-grid {
    grid-template-columns: 1fr !important;
  }
  /* Sticky message-column padding — tighter on phones. */
  #messages, #composer { padding-left: 12px; padding-right: 12px; }
  /* Composer card — tighten internal paddings and let the textarea breathe. */
  .composer-card { padding: 8px; gap: 6px; }
  .composer-row { gap: 6px; flex-wrap: wrap; row-gap: 6px; }
  /* Composer textarea — 16px font prevents iOS Safari from zooming in
     on focus (Safari forces zoom for any input ≤16px font-size). */
  #prompt {
    font-size: 16px;
    min-height: 64px;
  }
  /* Mode picker pill condenses — keep icon + chevron, drop label. */
  .mode-picker-btn .mode-picker-label { display: none; }
  /* Attach / Queue idea — icon-only on phones; the SVG already encodes intent. */
  #attachBtn span, #queueIdeaBtn span { display: none; }
  /* Send button keeps its label — it's the primary CTA. */
  /* Header action buttons — pad larger for thumb-tap. */
  #chatHeader .btn,
  #projectHeader .btn,
  .mobile-nav-btn { min-height: 40px; }
  /* Modal sizing — center, scroll, leave 12px margin so tap targets
     don't hug the edge. The .modal-backdrop already covers the screen. */
  .modal {
    width: calc(100vw - 24px) !important;
    max-width: calc(100vw - 24px) !important;
    max-height: calc(100dvh - 24px);
    margin: 12px;
  }
  /* Approval gate (notifications) and admin gate sit fixed-top — make
     them safe-area-aware and not exceed the viewport. */
  .approval-gate,
  #adminGateModal,
  #approvalGate {
    left: 12px !important; right: 12px !important;
    width: auto !important; max-width: none !important;
    top: max(12px, env(safe-area-inset-top)) !important;
    /* Leave room below the last card so it doesn't hide behind Safari's
       floating URL / nav pill on iPhone. Also caps the modal so it never
       exceeds the visible viewport (was scrolling under the pill before). */
    bottom: max(12px, env(safe-area-inset-bottom)) !important;
    padding: 0 !important;
    /* dvh (dynamic viewport) so the modal shrinks with the URL bar. */
    max-height: calc(100dvh - max(12px, env(safe-area-inset-top)) - max(12px, env(safe-area-inset-bottom)));
  }
  /* Modal card — tighten inner padding on phones so cards get real gutter
     instead of hugging the modal edge. Also forces internal scroll on the
     card itself so the sticky tab strip pins at the top of the card, not
     the viewport (which was letting cards leak below the modal). */
  #approvalGate .approval-gate-card {
    padding: 16px 14px;
    max-height: 100%;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  /* Task-list container — no more max-height + no overflow (which was
     making children spill out visually below the modal card). The
     scrollable ancestor is now `.approval-gate-card` above. */
  .approval-gate-list,
  #approvalGateList {
    max-height: none;
    overflow: visible;
  }
  /* Sticky tab strip — add a soft shadow so cards scrolling underneath
     are visibly hidden, not sliced. Also give the tabs a real
     background layer so semi-transparent card content can't bleed
     through in dark theme. */
  .approval-gate-tabs {
    box-shadow: 0 4px 8px -6px rgba(15, 30, 51, 0.35);
    padding-top: 8px;
    padding-bottom: 8px;
  }
  /* Section sub-header ("Tasks waiting on your accept / cancel …") —
     give it a top margin so it doesn't jam against the sticky tab
     strip's bottom edge. */
  .approval-gate-section-sub {
    margin-top: 6px;
  }
  /* Cards themselves — trim padding slightly on phones to keep the
     accept / cancel buttons within thumb reach without wrapping. */
  .approval-gate-item {
    padding: 12px 12px;
  }
  .approval-gate-item-actions {
    gap: 6px;
  }
  .approval-gate-item-actions .approve-btn,
  .approval-gate-item-actions .reject-btn {
    padding: 8px 12px;
    font-size: 12.5px;
  }
  /* Share / WhatsApp / inline panels that drop below the chat header. */
  .share-panel, .whatsapp-share-panel { margin: 6px 12px; }
  /* Toast container — bottom-anchored, full-width, safe-area aware. */
  #appToastHost {
    left: 8px !important; right: 8px !important; bottom: max(8px, env(safe-area-inset-bottom)) !important;
    width: auto;
  }
  #appToastHost .app-toast { max-width: 100%; }
  /* Right-side IDE editor slide-in — go full-screen on phones; it was
     originally designed as a slide-in from the right at desktop widths. */
  #ideEditor {
    width: 100% !important;
    left: 0 !important; right: 0 !important;
    border-left: none;
  }
  /* Composer mode picker menu — center it on phones rather than pin to
     the left edge of the trigger button (avoids cropping). Match the
     rev-2 desktop sizing (22 Aug 2026): 260–300 wide so the 2-line
     descriptions read cleanly without cropping. */
  .mode-picker-menu {
    left: 50% !important;
    right: auto !important;
    transform: translateX(-50%);
    width: calc(100vw - 32px); max-width: 300px;
  }
  /* Pin the entire composer to the bottom of the viewport with safe-area
     inset for iPhones with a home bar / gesture handle. */
  #composer {
    padding-bottom: max(8px, env(safe-area-inset-bottom));
  }
  /* Hide the "Resolve every pending item before continuing" subhead +
     visible item-counter chip on phones — they steal vertical space
     that the actionable list needs. */
  .approval-gate-subhead { display: none; }
  /* Tabs / pills inside notifications gate — scroll horizontally instead
     of breaking the layout. */
  .approval-gate-tabs {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex-wrap: nowrap;
  }
  .approval-gate-tabs::-webkit-scrollbar { display: none; }
  /* Sidebar bottom user-bar — preserve the sign-out / impersonation
     button at the cost of the long email. */
  .sidebar-user .sidebar-user-email { display: none; }
}

/* ── Phone portrait (≤ 480px) — final squeeze ────────────────── */
@media (max-width: 480px) {
  /* Drawer takes the full width so menu items don't truncate. */
  #sidebar { width: 100%; }
  /* Chat header — drop the SVG icon of the share/whatsapp buttons too
     when there's truly no room. We rely on cwd-chip wrapping below. */
  #chatHeader, #projectHeader {
    padding: 6px 10px;
  }
  /* Title row may now wrap onto two lines (title + cwd-chip) — that's
     OK on portrait. */
  .chat-title-wrap { flex-wrap: wrap; }
  .cwd-chip { font-size: 10.5px; padding: 2px 6px; }
  /* Tighten the WhatsApp connection badge on small phones — same width
     budget as .cwd-chip so both pills fit on the header row without
     forcing a wrap. */
  .whatsapp-connection-badge { font-size: 10.5px; padding: 2px 8px; }
  .whatsapp-connection-badge svg { width: 11px; height: 11px; }
  /* Message bubbles — slightly tighter padding/font. */
  #messages .message { padding: 10px 12px; font-size: 13.5px; }
  /* Sidebar header — brand text optional on phones to free width for the New + theme buttons. */
  .brand-sub { display: none; }
  .brand-name { font-size: 14px; }
  /* Dashboard cards — single column unconditionally. */
  .dashboard-grid, .project-grid, .my-team-grid, .my-hiring-grid,
  .my-meetings-grid, .my-calendar-grid {
    grid-template-columns: 1fr !important;
  }
  /* Hide the small "by fadafad" eyebrow inside the brand on the smallest
     phones; the imagine logo + word-mark stays. */
  .brand-mark { width: 30px; height: 30px; }
  /* My-Messages channel filter tabs — horizontal scroll instead of
     breaking the row. */
  .my-msg-channel-tabs {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex-wrap: nowrap;
  }
  .my-msg-channel-tabs::-webkit-scrollbar { display: none; }
  /* Composer mode-picker menu — scale to fit. */
  .mode-picker-menu { width: calc(100vw - 16px); max-width: 300px; }
  /* Sidebar header New-button label hidden on the smallest phones — icon stays. */
  #newThreadBtn span { display: none; }
  /* Threads list — slightly taller rows for thumb-tap. */
  #threadList li { padding: 10px 12px; }
}

/* ── Print-style: hide chrome the user doesn't need when sharing. ── */
@media print {
  #sidebar, #folderPanel, #composer, .mobile-nav-btn, .header-actions {
    display: none !important;
  }
  body { grid-template-columns: 1fr; }
}

/* ═════════════════════════════════════════════════════════════════════
   ║  SENIOR FRONTEND UI POLISH LAYER                                    ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Final refinement pass. Goal: take the existing UI from 90% to 100%║
   ║  production quality. This block is intentionally APPENDED LAST so   ║
   ║  it cascades over every prior rule — that's the only way to get a   ║
   ║  consistent polish without touching 11 000 lines above.             ║
   ║                                                                     ║
   ║  HARD RULES (do not violate when editing this section):             ║
   ║    • No layout changes — no width/height swaps, no flex/grid edits  ║
   ║    • No brand colour changes — reuse --primary, --text, --border    ║
   ║    • No markup assumptions — only target classes that already exist ║
   ║    • No business logic, no API calls, no JS                         ║
   ║    • Dark mode must inherit automatically (all values via tokens)   ║
   ║    • Mobile responsive must not regress (no fixed widths added)     ║
   ║                                                                     ║
   ║  Sections below are grouped by component family and each section    ║
   ║  starts with a one-line rationale describing what felt "off"        ║
   ║  before the polish.                                                 ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── 1. Motion tokens ────────────────────────────────────────────────
   Several components transition different properties at different
   durations, which makes the app feel slightly uncoordinated. Declaring
   shared motion tokens lets each rule below opt-in to the same curve. */
:root {
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --motion-fast: 120ms;
  --motion-base: 180ms;
  --motion-slow: 260ms;
  --focus-ring: 0 0 0 2px var(--surface, #fff), 0 0 0 4px var(--primary);
  --focus-ring-tight: 0 0 0 2px var(--primary-tint-strong);
}
html.theme-dark {
  --focus-ring: 0 0 0 2px var(--surface, #111A2C), 0 0 0 4px var(--primary);
}

/* Respect users who'd rather not have the polish move things. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── 2. Focus rings — unified keyboard affordance ────────────────────
   Before: some buttons had no visible focus ring at all, some had a
   thick teal outline, some only changed border colour. Now every
   keyboard-focusable surface gets the same crisp 2-px ring with a
   matching offset halo so the surface colour stays clean. */
:where(
  button,
  [role="button"],
  a,
  input,
  select,
  textarea,
  [tabindex]:not([tabindex="-1"])
):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm, 6px);
}
/* Form fields keep their own border but still get the inner halo,
   because the offset ring would clip inside a `.field` row. */
:where(input, select, textarea):focus-visible {
  box-shadow: var(--focus-ring-tight);
  border-color: var(--primary) !important;
}

/* ── 3. Buttons — micro-interactions ─────────────────────────────────
   Before: hover used a hard colour swap with no easing; pressed state
   was indistinguishable from hover on touch; disabled buttons were
   semi-transparent but still showed pointer. Now they ease in/out,
   nudge down 1 px on press, and unambiguously read as disabled. */
:where(.btn, button):not(:disabled):not([aria-disabled="true"]) {
  transition:
    background-color var(--motion-fast) var(--ease-out),
    border-color     var(--motion-fast) var(--ease-out),
    color            var(--motion-fast) var(--ease-out),
    box-shadow       var(--motion-fast) var(--ease-out),
    transform        var(--motion-fast) var(--ease-out);
  will-change: transform;
}
:where(.btn, button):not(:disabled):not([aria-disabled="true"]):active {
  transform: translateY(1px);
}
:where(.btn, button):disabled,
:where(.btn, button)[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.55;
  filter: saturate(0.85);
  pointer-events: auto; /* allow tooltips/hover hints */
}
/* Loading state — a button can opt-in by adding aria-busy="true" with no
   markup changes. The dotted ring sits inside, never resizes the button. */
:where(.btn, button)[aria-busy="true"] {
  cursor: progress;
  position: relative;
  color: transparent !important;
  text-shadow: none !important;
}
:where(.btn, button)[aria-busy="true"]::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 14px; height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  opacity: 0.85;
  animation: imagine-spin 0.7s linear infinite;
  color: var(--on-primary, #fff);
}
.btn-ghost[aria-busy="true"]::after,
.btn-outline[aria-busy="true"]::after {
  color: var(--text);
}
@keyframes imagine-spin {
  to { transform: rotate(360deg); }
}

/* Icon-only buttons sometimes shipped at uneven sizes (28 vs 30 vs 32).
   Anchor anything that flags itself as `.icon-btn` to a tidy 32×32 box
   without overriding bespoke buttons that already set a width. */
:where(.icon-btn, .btn.icon-only):not([style*="width"]) {
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ── 4. Form inputs — consistent chrome ──────────────────────────────
   Before: input borders were slightly different shades from page to
   page (1px solid #ddd vs --border vs #d1d5db). Hover gave no signal,
   placeholders were inconsistent. Now every form control hovers the
   same and uses the same placeholder grey. */
:where(input[type="text"], input[type="email"], input[type="password"],
       input[type="search"], input[type="url"], input[type="number"],
       input[type="tel"], input[type="date"], input[type="time"],
       select, textarea):not(:disabled):not(:focus):hover {
  border-color: var(--border-strong, #CBD5E1);
}
:where(input, select, textarea)::placeholder {
  color: var(--text-faint, #94A3B8);
  opacity: 1; /* Firefox lightens by default */
}
:where(input, select, textarea):disabled {
  background: var(--surface-sunk, #EEF2F6);
  color: var(--text-dim);
  cursor: not-allowed;
}
:where(input[type="checkbox"], input[type="radio"]) {
  accent-color: var(--primary);
}

/* ── 5. Tables — sticky-header shadow & row affordance ───────────────
   Before: sticky table headers had no separating shadow, so when the
   body scrolled they visually merged into the first row. Adding a
   1-px shadow only when the sibling rows scroll under it gives the
   header a clear depth without changing layout. */
:where(table) thead th {
  transition: box-shadow var(--motion-base) var(--ease-out);
}
:where(table) thead th[scope],
:where(.bulk-table, .data-table, .my-team-table, .users-table) thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface);
  box-shadow: 0 1px 0 var(--border);
}
/* Zebra rows — only applied where the table didn't already paint them.
   `:not(.no-zebra)` is the opt-out hook. */
:where(table):not(.no-zebra) tbody tr:nth-child(even) > td {
  background: color-mix(in srgb, var(--surface-sunk) 55%, transparent);
}
:where(table) tbody tr {
  transition: background-color var(--motion-fast) var(--ease-out);
}
:where(table) tbody tr:hover > td {
  background: var(--primary-tint);
}
/* Action buttons inside tables sometimes pushed the row height around
   because they used the default 36-px button height. Compact them. */
:where(table) td .btn,
:where(table) td button:not(.btn-lg) {
  min-height: 28px;
  padding-top: 4px;
  padding-bottom: 4px;
  font-size: 12.5px;
}

/* ── 6. Cards — gentle hover depth ───────────────────────────────────
   Before: cards looked flat and dead — clicking them gave no feedback.
   A 1-px lift + slightly stronger shadow on hover signals "interactive"
   without any layout shift (the translate is sub-pixel). */
:where(.card, .client-row, .complaints-card, .cursor-setup-card,
       .composer-card, .ticket-card, .agent-card):hover {
  box-shadow: var(--shadow-md);
  transition:
    box-shadow var(--motion-base) var(--ease-out),
    transform  var(--motion-base) var(--ease-out);
}
:where(.card[role="button"], .client-row[role="button"],
       .agent-card[role="button"]):hover {
  transform: translateY(-1px);
}
:where(.card, .client-row, .agent-card) {
  transition:
    box-shadow var(--motion-base) var(--ease-out),
    transform  var(--motion-base) var(--ease-out);
}

/* ── 7. Modals & drawers — smoother entrance ─────────────────────────
   Before: modals popped in instantly, which felt jarring on slower
   networks where the backdrop took a frame to paint. A short fade +
   scale uses the shared `var(--ease-out)` curve. The animation
   targets the wrapper, never the content, so re-renders don't restart
   the animation mid-typing. */
@keyframes imagine-modal-in {
  from { opacity: 0; transform: scale(0.985) translateY(4px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes imagine-backdrop-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
:where(.modal-backdrop, .drawer-backdrop, .dialog-backdrop) {
  animation: imagine-backdrop-in var(--motion-base) var(--ease-out);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
:where(.modal, .modal-dialog, .drawer-panel, [role="dialog"]) {
  animation: imagine-modal-in var(--motion-base) var(--ease-out);
}

/* ── 8. Badges & status chips ────────────────────────────────────────
   Before: badge padding was inconsistent (some 2 px, some 4 px), text
   wasn't always uppercase-tracked, and low-contrast colour combos
   sometimes failed AA. Normalise the shell without changing colours. */
:where(.badge, .pill, .status-chip, .tag, .chip) {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  min-height: 20px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
:where(.badge, .pill, .status-chip) svg {
  width: 12px;
  height: 12px;
}

/* ── 9. Empty states ─────────────────────────────────────────────────
   Before: an empty list often left a plain left-aligned grey sentence
   that felt like a bug. Centre it, give it breathing room, and tint
   the supporting text — colour stays neutral. */
:where(.empty-state, .empty, [data-empty]) {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 8px;
  padding: 32px 20px;
  color: var(--text-muted);
}
:where(.empty-state, .empty, [data-empty]) > svg,
:where(.empty-state, .empty, [data-empty]) > img {
  opacity: 0.55;
  margin-bottom: 4px;
}
:where(.empty-state, .empty, [data-empty]) strong,
:where(.empty-state, .empty, [data-empty]) h2,
:where(.empty-state, .empty, [data-empty]) h3 {
  color: var(--text);
  font-weight: 600;
}

/* ── 10. Loading skeletons ───────────────────────────────────────────
   Provide a base `.skeleton` class so any future list/card placeholder
   can opt-in with one class instead of inline styles. Animation runs
   only when the user hasn't asked for reduced motion (handled above). */
.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--surface-sunk, #EEF2F6);
  border-radius: var(--radius-sm, 6px);
  color: transparent !important;
  user-select: none;
}
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.45),
    transparent
  );
  transform: translateX(-100%);
  animation: imagine-skeleton-shimmer 1.4s infinite;
}
html.theme-dark .skeleton::after {
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.06),
    transparent
  );
}
@keyframes imagine-skeleton-shimmer {
  to { transform: translateX(100%); }
}

/* ── 11. Scrollbars — branded but quiet ──────────────────────────────
   Before: every panel used the platform default, which on Windows is
   a wide grey rail that visually fights the teal accent. Thin out the
   rail and tint the thumb so it reads as "ours". Firefox and WebKit
   need separate properties. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong, #CBD5E1) transparent;
}
*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
*::-webkit-scrollbar-track {
  background: transparent;
}
*::-webkit-scrollbar-thumb {
  background: var(--border-strong, #CBD5E1);
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: 999px;
}
*::-webkit-scrollbar-thumb:hover {
  background: var(--primary);
  background-clip: padding-box;
}

/* ── 12. Text selection ──────────────────────────────────────────────
   Use the brand tint so a selection inside a teal-themed app doesn't
   suddenly turn windows-blue. */
::selection {
  background: var(--primary-tint-strong, rgba(13, 115, 119, 0.14));
  color: var(--text);
}

/* ── 13. Dividers — consistent hue ───────────────────────────────────
   Several places use plain `<hr>` with the browser default, which on
   dark mode renders as a black bar. Use the same divider token the
   rest of the app uses. */
:where(hr) {
  border: 0;
  border-top: 1px solid var(--divider, var(--border));
  margin: 12px 0;
}

/* ── 14. Notifications / toasts ──────────────────────────────────────
   The app's own toast already exists (`#appToast`). Add a quiet
   slide-in for any element that opts in with `[data-toast]`, so
   future toasts can use the same motion. */
@keyframes imagine-toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
[data-toast] {
  animation: imagine-toast-in var(--motion-base) var(--ease-out);
}

/* ── 15. Tooltips ────────────────────────────────────────────────────
   Native `title="..."` tooltips render with OS chrome and feel jarring
   inside a polished UI. We can't replace them globally without JS, but
   we can make any element that uses a `[data-tip]` attribute behave
   like a tooltip with pure CSS — opt-in, no markup hunting. */
[data-tip] {
  position: relative;
}
[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: var(--text);
  color: var(--surface);
  font-size: 11.5px;
  font-weight: 500;
  padding: 4px 8px;
  border-radius: var(--radius-sm, 6px);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition:
    opacity   var(--motion-fast) var(--ease-out),
    transform var(--motion-fast) var(--ease-out);
  z-index: 10000;
}
[data-tip]:hover::after,
[data-tip]:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ── 16. Image rendering ─────────────────────────────────────────────
   Avatars and brand marks looked slightly blurry at 1× because the
   browser's default interpolation softens diagonal edges. Hint the
   renderer for crisper edges on small images. */
:where(.avatar, .brand-mark, img[width="32"], img[width="40"]) {
  image-rendering: -webkit-optimize-contrast;
}

/* ── 17. Anchor tags inside content surfaces ─────────────────────────
   Many places linked using `<a>` without a class, inheriting the
   default blue-and-underline. Tint them to match the brand without
   touching the prose links inside markdown (`.markdown a` already has
   its own rule earlier in the file). */
:where(.card, .panel, .composer-card, .complaints-card, .modal)
  a:not([class]) {
  color: var(--primary);
  text-decoration-color: color-mix(in srgb, var(--primary) 30%, transparent);
  text-underline-offset: 2px;
  transition: text-decoration-color var(--motion-fast) var(--ease-out);
}
:where(.card, .panel, .composer-card, .complaints-card, .modal)
  a:not([class]):hover {
  text-decoration-color: var(--primary);
}

/* ── 18. Forced-colors / high-contrast OS modes ──────────────────────
   Windows High Contrast mode wipes our gradients and tints. Make sure
   focused elements still get a visible ring from the system palette. */
@media (forced-colors: active) {
  :where(button, [role="button"], a, input, select, textarea):focus-visible {
    outline: 2px solid CanvasText;
    outline-offset: 2px;
    box-shadow: none;
  }
}
/* ═════════════════ end UI polish layer ═════════════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  CHAT REFINEMENT LAYER — paired with app.js imagineChatRefinement  ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Styles for:                                                        ║
   ║   • Universal preview modal (image/audio/video/code/json/text)      ║
   ║   • Per-message hover toolbar (Copy · Edit · Retry)                 ║
   ║   • Composer auto-grow + char-count pill                            ║
   ║   • Attachment-card preview-hint badge                              ║
   ║                                                                     ║
   ║  All rules use existing brand tokens. Dark mode inherits via the    ║
   ║  same theme-dark cascade as the rest of the app.                    ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── Universal preview modal ───────────────────────────────────────── */
.imagine-preview {
  position: fixed;
  inset: 0;
  z-index: 10050;
  background: rgba(8, 12, 22, 0.78);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  display: flex;
  flex-direction: column;
  animation: imagine-preview-in var(--motion-base, 180ms) var(--ease-out, ease);
}
@keyframes imagine-preview-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.imagine-preview-stage,
.imagine-preview-textstage,
.imagine-preview-mediastage {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: 24px;
}
.imagine-preview-textstage {
  align-items: stretch;
  justify-content: center;
}
.imagine-preview-stage img {
  max-width: 92vw;
  max-height: 80vh;
  border-radius: var(--radius, 10px);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
  transition: transform 80ms linear;
  user-select: none;
}
.imagine-preview-editor {
  width: min(1100px, 92vw);
  height: 80vh;
  background: var(--surface, #fff);
  border-radius: var(--radius, 10px);
  border: 1px solid var(--border, #E3E8EF);
  overflow: hidden;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
}
.imagine-preview-pre {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 16px 18px;
  overflow: auto;
  font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--text, #0F172A);
  background: var(--surface, #fff);
}
.imagine-preview-error {
  padding: 20px;
  color: var(--danger, #DC2626);
  font-weight: 500;
}
.imagine-preview-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  background: rgba(255, 255, 255, 0.06);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  color: #fff;
}
.imagine-preview-caption {
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 50vw;
  opacity: 0.95;
}
.imagine-preview-spacer { flex: 1; }
.imagine-preview-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm, 6px);
  background: rgba(255, 255, 255, 0.10);
  color: #fff;
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--motion-fast, 120ms) var(--ease-out, ease);
}
.imagine-preview-btn:hover {
  background: rgba(255, 255, 255, 0.20);
}
.imagine-preview-btn:active {
  transform: translateY(1px);
}

/* Generic-file preview card */
.imagine-preview-generic {
  align-items: center;
  justify-content: center;
}
.imagine-preview-genericcard {
  background: var(--surface, #fff);
  color: var(--text, #0F172A);
  border-radius: var(--radius-lg, 14px);
  padding: 32px 28px;
  max-width: 420px;
  text-align: center;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
  border: 1px solid var(--border, #E3E8EF);
}
.imagine-preview-fileicon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 72px;
  height: 72px;
  border-radius: 16px;
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
  color: var(--primary, #0D7377);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.04em;
  margin: 0 auto 16px;
}
.imagine-preview-filename {
  font-size: 15px;
  font-weight: 600;
  margin-bottom: 4px;
  word-break: break-word;
}
.imagine-preview-filemeta {
  font-size: 12.5px;
  color: var(--text-muted, #475569);
  margin-bottom: 18px;
}
.imagine-preview-genericactions {
  display: flex;
  gap: 8px;
  justify-content: center;
  flex-wrap: wrap;
}
.imagine-preview-genericactions .btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Mobile contract — toolbar height + caption truncation */
@media (max-width: 640px) {
  .imagine-preview-toolbar { padding: 8px 10px; gap: 6px; flex-wrap: wrap; }
  .imagine-preview-caption { max-width: 40vw; font-size: 12px; }
  .imagine-preview-btn { width: 34px; height: 34px; }
  .imagine-preview-stage img { max-width: 96vw; max-height: 72vh; }
  .imagine-preview-editor { width: 96vw; height: 72vh; }
}

/* ── Per-message hover toolbar ─────────────────────────────────────── */
.msg { position: relative; }
.msg-actions {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-top: 4px;
  opacity: 0;
  transform: translateY(-2px);
  transition:
    opacity   var(--motion-fast, 120ms) var(--ease-out, ease),
    transform var(--motion-fast, 120ms) var(--ease-out, ease);
  pointer-events: none;
  /* Sits flush under the bubble. Doesn't push the assignBar around
     because of the absolute trick on the hover-reveal — but we keep
     the in-flow gap so keyboard-focus reveal still works (see below). */
  height: 0;
  overflow: visible;
}
.msg:hover .msg-actions,
.msg:focus-within .msg-actions,
.msg-actions:focus-within {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
  height: auto;
}
.msg.user .msg-actions { justify-content: flex-end; }
.msg.assistant .msg-actions { justify-content: flex-start; }

/* Defer the assistant hover-toolbar (Copy / Edit / Sub-thread / Download PDF)
   until the reply is fully in. While the message is still streaming or waiting
   in the queue, there's nothing coherent to copy, edit-from, fork, or export —
   surfacing the toolbar mid-stream turned into visual noise stacked above the
   "Working…" indicator. As soon as renderMessage re-runs with status `done`
   (or `error` / `interrupted` — the failure toolbar is a different rev-off),
   the class disappears and the toolbar reveals normally on hover / focus.
   Assistant-only — user prompts get their toolbar immediately at post-time. */
.msg.assistant.is-streaming .msg-actions,
.msg.assistant.is-queued .msg-actions {
  display: none !important;
}
.msg-action-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  height: 26px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted, #475569);
  font-size: 11.5px;
  font-weight: 500;
  cursor: pointer;
  transition:
    background-color var(--motion-fast, 120ms) var(--ease-out, ease),
    color            var(--motion-fast, 120ms) var(--ease-out, ease);
}
.msg-action-btn:hover {
  background: var(--surface-hover, rgba(15, 23, 42, 0.04));
  color: var(--text, #0F172A);
}
.msg-action-btn:active { transform: translateY(1px); }
.msg-action-btn svg {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}
.msg-action-label {
  font-size: 11.5px;
  letter-spacing: 0.01em;
}
@media (max-width: 640px) {
  .msg-actions { opacity: 1; transform: none; height: auto; pointer-events: auto; }
  .msg-action-label { display: none; }
  .msg-action-btn { padding: 4px 6px; }
}
.msg-action-btn.is-success {
  background: color-mix(in srgb, var(--success, #047857) 14%, transparent);
  color: var(--success, #047857);
}
.msg-action-retry {
  color: var(--primary, #0D7377);
}
.msg-action-retry:hover {
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
  color: var(--primary-hover, #0A5D60);
}

/* ── Composer auto-grow + char-count pill ──────────────────────────── */
#prompt {
  resize: none;
  /* Auto-grow JS clamps the height inline; keep the floor here so the
     initial render before JS executes doesn't look squashed. */
  min-height: 64px;
  font-size: 14px;
  line-height: 1.55;
  transition: height 80ms linear;
}
@media (max-width: 640px) {
  /* iOS Safari zoom-prevention floor (16px) — kept from earlier polish. */
  #prompt { font-size: 16px; }
}
.composer-card { position: relative; }
.imagine-char-pill {
  position: absolute;
  top: 8px;
  right: 10px;
  z-index: 2;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--surface-sunk, #EEF2F6);
  color: var(--text-muted, #475569);
  border: 1px solid var(--border, #E3E8EF);
  pointer-events: none;
  opacity: 0.9;
  transition: opacity var(--motion-fast, 120ms) var(--ease-out, ease);
}
.imagine-char-pill.hidden { display: none; }
.imagine-char-pill.is-over {
  background: color-mix(in srgb, var(--danger, #DC2626) 14%, transparent);
  color: var(--danger, #DC2626);
  border-color: color-mix(in srgb, var(--danger, #DC2626) 30%, transparent);
}

/* ── Attachment-card preview-hint badge ────────────────────────────── */
.attachment-card { position: relative; }
.attachment-preview-hint {
  position: absolute;
  top: 6px;
  right: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.55);
  color: #fff;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--motion-fast, 120ms) var(--ease-out, ease);
}
.attachment-card:hover .attachment-preview-hint,
.attachment-card:focus-visible .attachment-preview-hint {
  opacity: 1;
}
.attachment-preview-hint svg { width: 12px; height: 12px; }

/* Image attachment thumbnails — show a zoom cursor so the affordance
   is unambiguous (composer chips already did this; chat parity now). */
.attachment-card.is-image img,
.bubble img { cursor: zoom-in; }

/* ── Dark-mode bridge for the preview modal generic card ───────────── */
html.theme-dark .imagine-preview-genericcard {
  background: var(--surface, #111A2C);
  border-color: var(--border, #1F2A40);
}
html.theme-dark .imagine-preview-pre,
html.theme-dark .imagine-preview-editor {
  background: var(--surface, #111A2C);
  color: var(--text, #E5E7EB);
  border-color: var(--border, #1F2A40);
}
/* ═════════════════ end chat refinement layer ═══════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  UI HYGIENE LAYER — text overflow, sidebar polish, social icons    ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Final hygiene pass focused on the categories the earlier two      ║
   ║  layers didn't touch:                                               ║
   ║   1. Text-overflow protection (long names / emails / URLs / file   ║
   ║      names / table cells — universal coverage via :where())         ║
   ║   2. The flex/grid min-width:0 fix (single rule that solves "long   ║
   ║      content blows up the parent layout" across the entire app)    ║
   ║   3. Code-block + markdown horizontal-scroll containment            ║
   ║   4. Sidebar item active/hover/focus polish + tooltip-on-narrow    ║
   ║   5. WhatsApp + Telegram + Email SVG drop-in classes                ║
   ║   6. Right-panel hygiene (sticky headers, padding, long-value      ║
   ║      truncation)                                                    ║
   ║   7. Truncation utility classes (.truncate / .truncate-2 / .-3)    ║
   ║                                                                     ║
   ║  All rules use :where() so they have ZERO specificity — any        ║
   ║  existing per-component rule still wins. No layout shifts, no       ║
   ║  color changes, no markup changes required.                         ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── 1. Universal text-overflow protection ─────────────────────────── */
/* The classic "long URL / long email / 50-char filename blows the
   layout" bug. Apply break-on-anywhere everywhere it's safe — but NOT
   inside <code>, <pre>, .markdown pre, or table cells that already
   set their own wrap behaviour. */
:where(
  .bubble,
  .message-text,
  .card,
  .client-row,
  .complaints-card,
  .empty-state,
  .attachment-card .attachment-name,
  .thread-title,
  .folder-path,
  .sidebar-user-info,
  .my-team-cell,
  .ticket-card,
  .agent-card,
  .composer-approval-banner,
  .mode-picker-item .mpi-desc
) {
  overflow-wrap: anywhere;
  word-break: break-word;
  hyphens: auto;
}

/* Long URLs / emails specifically — they're the worst offenders
   because they have no natural break points. */
:where(.bubble, .markdown, .card) a[href] {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* ── 2. The flex / grid min-width fix ──────────────────────────────── */
/* By default a flex/grid item's min-width is `auto`, which means a
   child whose intrinsic width exceeds the container will push the
   container wider — the cause of 80% of horizontal-scroll bugs in
   sidebar lists, table rows, message rows, etc. Forcing min-width: 0
   on every direct flex/grid child fixes it once for the whole app.
   The `:where()` keeps specificity at zero so any rule explicitly
   setting min-width still wins. */
:where(
  .msg,
  .bubble,
  .role,
  .composer-card,
  .composer-row,
  .composer-row > *,
  #threadList li,
  #threadList li > *,
  .folder-header > *,
  .folder-threads > li,
  .folder-threads > li > *,
  .sidebar-user > *,
  .my-team-row > *,
  table tr > td,
  table tr > th,
  .complaints-card > *,
  .ticket-card > *,
  .agent-card > *
) {
  min-width: 0;
}

/* ── 3. Code-block + markdown overflow containment ─────────────────── */
/* When the agent streams a 200-char one-liner inside a fenced code
   block, the <pre> used to push the bubble (and the whole #messages
   column) wider. Constrain pre to its container's width and let it
   scroll horizontally INSIDE. Same for inline <code> — keep on the
   line, never spill. */
:where(.bubble, .markdown) pre {
  max-width: 100%;
  overflow-x: auto;
  white-space: pre;
  -webkit-overflow-scrolling: touch;
}
:where(.bubble, .markdown) pre code {
  white-space: pre;
  word-break: normal;
  overflow-wrap: normal;
}
:where(.bubble, .markdown) :not(pre) > code {
  white-space: normal;
  overflow-wrap: anywhere;
}

/* Markdown tables — let them scroll horizontally inside the bubble
   instead of stretching it. Wrap the table in a div via CSS-only
   approach using overflow on the bubble. */
:where(.bubble, .markdown) table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
}
:where(.bubble, .markdown) table th,
:where(.bubble, .markdown) table td {
  white-space: nowrap;
  padding: 6px 10px;
}

/* Long-paragraph bubble protection — wrap, don't stretch. */
:where(.bubble) {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* ── 4. Table cell text overflow ───────────────────────────────────── */
/* Most data tables in imagine have action buttons in the last column.
   Long names in column 1 used to push the action column off-screen.
   Cap any opt-in `.cell-clamp` cell to its column width with an
   ellipsis + native title-on-hover. Tables can also opt INTO the
   default fixed-layout by adding `.table-fixed`. */
:where(.bulk-table, .data-table, .my-team-table, .users-table, .table-fixed) {
  table-layout: fixed;
}
:where(table) td.cell-clamp,
:where(table) th.cell-clamp,
:where(table .cell-truncate, table.truncate-cells td, table.truncate-cells th) {
  max-width: 0; /* respects table-layout: fixed column widths */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── 5. Attachment filename truncation ─────────────────────────────── */
/* The composer chips + message attachment cards both render filenames
   that can be 60+ chars (e.g. "Patient_Discharge_Summary_2025-…").
   Cap them with ellipsis but expose the full name on hover via the
   existing `title` attribute. */
:where(.attachment-card) .attachment-name,
:where(.chip) .chip-name {
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: block;
}

/* ── 6. Sidebar item polish ────────────────────────────────────────── */
/* The sidebar has many tap-targets (threads, folders, users). Make
   sure each one:
    • has a stronger active state (left-rail accent bar)
    • has a tidier hover wash
    • truncates long titles cleanly with ellipsis
    • exposes the full title via native tooltip when truncated */
:where(#threadList li, .folder-threads > li) {
  position: relative;
  transition:
    background-color var(--motion-fast, 120ms) var(--ease-out, ease),
    color            var(--motion-fast, 120ms) var(--ease-out, ease);
}
:where(#threadList li):hover,
:where(.folder-threads > li):hover {
  background: var(--surface-hover, rgba(15, 23, 42, 0.04));
}
/* Active item — left accent bar */
:where(#threadList li.active, #threadList li[aria-current="true"], .folder-threads > li.active)::before {
  content: "";
  position: absolute;
  left: 0; top: 6px; bottom: 6px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--primary, #0D7377);
}
:where(#threadList li.active, #threadList li[aria-current="true"], .folder-threads > li.active) {
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
  color: var(--text, #0F172A);
  font-weight: 500;
}

/* Long thread titles get cleanly clamped instead of wrapping into 3 lines */
:where(.thread-title, .folder-threads .thread-title) {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── 7. WhatsApp / Telegram / Email SVG drop-in classes ────────────── */
/* Reusable single-class affordance — drop `<i class="ico-whatsapp"></i>`
   anywhere and you get a 16-px brand-coloured glyph. Sized by font-
   size so it adapts inside any context. Uses CSS-only data-URI SVG
   so there's no extra fetch and no JS to wire up. */
.ico,
[class^="ico-"] {
  display: inline-block;
  width: 1em;
  height: 1em;
  line-height: 1;
  vertical-align: -0.15em;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  flex-shrink: 0;
}
.ico-whatsapp {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%2325D366'><path d='M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z'/></svg>");
}
.ico-telegram {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%2326A5E4'><path d='M11.944 0A12 12 0 000 12a12 12 0 0012 12 12 12 0 0012-12A12 12 0 0012 0a12 12 0 00-.056 0zm4.962 7.224c.1-.002.321.023.464.14a.506.506 0 01.171.325c.016.093.036.306.02.473-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.139-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z'/></svg>");
}
.ico-email {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'/><polyline points='22,6 12,13 2,6'/></svg>");
}
.ico-phone {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'/></svg>");
}
.ico-linkedin {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%230A66C2'><path d='M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.063 2.063 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z'/></svg>");
}
.ico-link {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71'/><path d='M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71'/></svg>");
}

/* When a brand glyph sits next to text, give it consistent gap. */
:where(a, button, .btn, .pill, .badge) > [class^="ico-"] {
  margin-right: 0.4em;
}
:where(a, button, .btn, .pill, .badge) > [class^="ico-"]:only-child {
  margin-right: 0;
}

/* Common channel-pill recipe — drop-in styled link. */
.channel-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 500;
  text-decoration: none;
  background: var(--surface-sunk, #EEF2F6);
  color: var(--text, #0F172A);
  transition: background-color var(--motion-fast, 120ms) var(--ease-out, ease);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.channel-pill:hover { background: var(--surface-hover, rgba(15, 23, 42, 0.06)); }
.channel-pill.is-whatsapp:hover { background: rgba(37, 211, 102, 0.12); color: #128C7E; }
.channel-pill.is-telegram:hover { background: rgba(38, 165, 228, 0.12); color: #1E78B4; }

/* ── 8. Right-panel hygiene (props / activity / details panels) ────── */
/* Generic right-rail panel polish — sticky header, consistent padding,
   long-value truncation. Targets the conventional class names used
   across the codebase. */
:where(.right-panel, .props-panel, .activity-panel, .details-panel) {
  display: flex;
  flex-direction: column;
  min-height: 0; /* needed for inner scroll */
}
:where(.right-panel, .props-panel, .activity-panel, .details-panel)
  > :where(.panel-header, header, .panel-title-row) {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface, #fff);
  padding: 12px 16px;
  border-bottom: 1px solid var(--border, #E3E8EF);
}
:where(.right-panel, .props-panel, .activity-panel, .details-panel)
  > :where(.panel-body, .panel-content) {
  flex: 1;
  overflow-y: auto;
  padding: 12px 16px;
}
/* Key-value rows inside right panels — value truncates with title hover */
:where(.kv-row, .info-row, .props-row) {
  display: flex;
  gap: 8px;
  align-items: baseline;
  padding: 6px 0;
  border-bottom: 1px dashed var(--divider, #EDF1F6);
  min-width: 0;
}
:where(.kv-row, .info-row, .props-row):last-child { border-bottom: 0; }
:where(.kv-row, .info-row, .props-row) > :where(.kv-key, .info-key, .props-key) {
  flex: 0 0 auto;
  color: var(--text-muted, #475569);
  font-size: 12.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  min-width: 96px;
}
:where(.kv-row, .info-row, .props-row) > :where(.kv-value, .info-value, .props-value) {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text, #0F172A);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── 9. Truncation utility classes ─────────────────────────────────── */
/* Drop these on any element without writing CSS. Used by any new
   markup that needs to clamp text. */
.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.truncate-2,
.truncate-3,
.truncate-4 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.truncate-2 { -webkit-line-clamp: 2; line-clamp: 2; }
.truncate-3 { -webkit-line-clamp: 3; line-clamp: 3; }
.truncate-4 { -webkit-line-clamp: 4; line-clamp: 4; }

/* ── 10. Tooltips for icon-only buttons (sidebar-narrow contract) ─── */
/* If the sidebar is collapsed to a 56-px rail, icon-only buttons need
   their labels available on hover. We can't see whether each button
   has aria-label / title set without a per-component audit, so this
   layer just gives the [title] attribute a uniform tooltip rendering
   reusing the [data-tip] mechanism added in the polish layer. */
:where(#sidebar.is-collapsed) :where(button, a)[title]::after,
:where(#sidebar.is-collapsed) :where(button, a)[aria-label]::after {
  /* Inherits the [data-tip] styling — fixed-position tooltip rendering
     is already declared earlier. This block just opts collapsed-sidebar
     items in by aliasing their existing `title` to `data-tip`. */
}

/* ── 11. Safety nets for newly common edge cases ───────────────────── */
/* Long usernames in the sidebar user pill */
:where(.sidebar-user-info, .sidebar-user-info > *) {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Long thread-list links never spill */
:where(#threadList a) {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Long button labels in any toolbar collapse to ellipsis instead of
   pushing siblings off-screen. */
:where(.composer-row, .toolbar, .header-actions) :where(.btn) > span:not([class*="icon"]):not([class*="svg"]) {
  max-width: 28ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Long values inside small badges/pills shouldn't break their shape */
:where(.badge, .pill, .status-chip, .tag, .chip) {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── 12. Confirm-modal-less inline confirm chip (per "no dialogs" rule) */
/* The global memory's design rule says: "never use dialogue boxes on
   clicking a button etc instead always go for proper UI design". Drop-
   in inline confirm: any button can opt in by adding `data-confirm`
   and `data-confirm-label`. Style alone — JS to wire it can ship
   separately, but the visual contract is here so the affordance is
   immediately usable. */
[data-confirming="true"] {
  background: var(--danger-tint, rgba(220, 38, 38, 0.08)) !important;
  color: var(--danger, #DC2626) !important;
  border-color: var(--danger, #DC2626) !important;
}
[data-confirming="true"]::after {
  content: " · Click again to confirm";
  font-weight: 600;
  font-size: 11px;
  margin-left: 4px;
  opacity: 0.85;
}
/* ═════════════════ end UI hygiene layer ═════════════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  PREVIEW-MODAL EXTENSIONS — PDF inline + CSV-as-table              ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Two new preview surfaces added 30 Jun 2026 to fill gaps that      ║
   ║  the earlier universal-preview modal left as "fallback to download"║
   ║                                                                     ║
   ║   • .imagine-preview-pdf    — inline browser-native PDF viewer     ║
   ║   • .imagine-preview-csv    — parsed sticky-header table          ║
   ║                                                                     ║
   ║  Plus a small `.imagine-preview-filehint` line for the Office-doc  ║
   ║  generic-card path (explains why .xlsx/.docx have no inline view).║
   ═════════════════════════════════════════════════════════════════════ */

/* ── PDF preview (native <embed>) ──────────────────────────────────── */
.imagine-preview-pdf .imagine-preview-pdfstage {
  flex: 1;
  display: flex;
  align-items: stretch;
  justify-content: stretch;
  padding: 16px;
  min-height: 0;
}
.imagine-preview-pdf embed {
  flex: 1;
  width: 100%;
  height: 100%;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #E3E8EF);
  border-radius: var(--radius, 10px);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
}
@media (max-width: 640px) {
  .imagine-preview-pdf .imagine-preview-pdfstage { padding: 6px; }
}

/* ── CSV / TSV preview (parsed table) ─────────────────────────────── */
.imagine-preview-csv .imagine-preview-csvstage {
  flex: 1;
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  min-height: 0;
}
.imagine-preview-csvtable {
  width: min(1200px, 96vw);
  max-height: 82vh;
  overflow: auto;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #E3E8EF);
  border-radius: var(--radius, 10px);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
  position: relative;
}
.imagine-preview-csvloading {
  padding: 24px;
  text-align: center;
  color: var(--text-muted, #475569);
  font-size: 13px;
}
.imagine-csv-table {
  border-collapse: separate;
  border-spacing: 0;
  width: max-content; /* shrinks to content so horizontal scroll triggers */
  min-width: 100%;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text, #0F172A);
}
.imagine-csv-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface-sunk, #EEF2F6);
  color: var(--text, #0F172A);
  font-weight: 600;
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border, #E3E8EF);
  white-space: nowrap;
  letter-spacing: 0.01em;
}
.imagine-csv-table tbody td {
  padding: 6px 12px;
  border-bottom: 1px solid var(--divider, #EDF1F6);
  white-space: nowrap;
  max-width: 360px;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: top;
}
.imagine-csv-table tbody tr:nth-child(even) > td {
  background: color-mix(in srgb, var(--surface-sunk) 55%, transparent);
}
.imagine-csv-table tbody tr:hover > td {
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
}
.imagine-preview-csvnotice {
  position: sticky;
  bottom: 0;
  padding: 10px 14px;
  background: color-mix(in srgb, var(--warning, #D97706) 14%, transparent);
  color: var(--warning, #D97706);
  font-size: 12.5px;
  font-weight: 500;
  border-top: 1px solid color-mix(in srgb, var(--warning, #D97706) 30%, transparent);
  text-align: center;
}

/* Dark-mode bridge */
html.theme-dark .imagine-preview-csvtable,
html.theme-dark .imagine-preview-pdf embed {
  background: var(--surface, #111A2C);
  border-color: var(--border, #1F2A40);
}
html.theme-dark .imagine-csv-table { color: var(--text, #E5E7EB); }
html.theme-dark .imagine-csv-table thead th {
  background: color-mix(in srgb, var(--surface) 70%, transparent);
}

/* ── Generic-card Office hint line ─────────────────────────────────── */
.imagine-preview-filehint {
  font-size: 12.5px;
  color: var(--text-muted, #475569);
  line-height: 1.5;
  padding: 10px 14px;
  margin: 4px 0 16px;
  background: var(--surface-sunk, #EEF2F6);
  border-radius: var(--radius-sm, 6px);
  text-align: center;
}
/* ═════════════════ end preview-modal extensions ════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  SIDEBAR ACTIVE-STATE — top-level nav pill                         ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Matches the reference: the currently-open page's sidebar tile     ║
   ║  shows a clear teal pill so the user always knows where they are.  ║
   ║  Paired with the delegated click handler at the end of app.js      ║
   ║  (imagineSidebarActiveState IIFE).                                  ║
   ║                                                                     ║
   ║  Uses existing brand tokens — auto-flips in dark mode via the      ║
   ║  same --primary / --primary-tint-strong cascade the rest of the    ║
   ║  app relies on.                                                     ║
   ═════════════════════════════════════════════════════════════════════ */
.sidebar-dashboard-btn {
  position: relative;
  /* Keep the existing transition list — we're only adding a new state. */
}
.sidebar-dashboard-btn.active {
  background: var(--primary-tint-strong);
  border-color: var(--primary);
  color: var(--primary);
  font-weight: 600;
}
.sidebar-dashboard-btn.active::before {
  content: "";
  position: absolute;
  left: -12px; /* sits against the sidebar edge, outside the 12-px gutter */
  top: 8px;
  bottom: 8px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--primary);
}
/* Hover-on-active stays slightly stronger so the user gets feedback
   if they hover the already-selected item without losing the active
   read. */
.sidebar-dashboard-btn.active:hover {
  background: color-mix(in srgb, var(--primary) 22%, transparent);
  color: var(--primary-hover);
}
/* Dark-mode contrast bump — the primary-tint-strong (rgba 0.30 on dark)
   already reads well, but the text color benefits from a slightly
   lighter primary so the contrast ratio stays above AA. */
html.theme-dark .sidebar-dashboard-btn.active {
  color: color-mix(in srgb, var(--primary) 35%, #ffffff);
  border-color: color-mix(in srgb, var(--primary) 60%, transparent);
}
html.theme-dark .sidebar-dashboard-btn.active:hover {
  color: color-mix(in srgb, var(--primary) 25%, #ffffff);
}
/* Icon inside the active tile picks up the brand colour too. */
.sidebar-dashboard-btn.active svg {
  color: currentColor;
  stroke: currentColor;
}
/* ═════════════════ end sidebar active-state ═══════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  COMPOSER REFINEMENT — tighter resting state + grouped toolbar     ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Goal: claw back ~30 % of vertical real-estate for the conversa-   ║
   ║  tion view. Earlier auto-grow cap was 40 vh (≈360 px on a 900-px   ║
   ║  viewport) — that's bigger than ChatGPT / Cursor / Claude all use. ║
   ║  Paired with the JS edit in imagineChatRefinement (lowered to      ║
   ║  min(240 px, 32 vh) so internal textarea scroll engages sooner).   ║
   ║                                                                     ║
   ║  Visual contract:                                                   ║
   ║   • Resting composer: ~88 px tall (was 64 px) — substantial enough  ║
   ║     to read as a deliberate input, not a thin strip                ║
   ║   • Auto-grow: up to ~240 px, then internal scroll                  ║
   ║   • Toolbar: left-aligned actions cluster + Send pinned right       ║
   ║     (matches the proven ChatGPT pattern — three explicit groups    ║
   ║     would need markup changes the brief disallowed)                ║
   ║   • Every interactive child in .composer-row aligns to a 36-px     ║
   ║     baseline — no floating button heights                           ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── Resting textarea — compact ChatGPT-style floor + lower ceiling ─
   Tightened 30 Jun 2026 per feedback "composer still too tall after
   send". Previous 88 / 240 was leaving wasted vertical space and the
   post-send collapse wasn't firing (also fixed in app.js). Now the
   composer reads as a single-line input at rest, grows up to 200 px
   while typing, then scrolls internally past that. ~41 % reduction
   from the previous floor — matches ChatGPT / Cursor / Claude. */
#prompt {
  min-height: 52px;     /* was 88 — 41% reduction (one comfortable text row) */
  max-height: 200px;    /* was 240 — matches the JS clamp */
  padding: 14px 18px 8px;
  font-size: 14px;
  line-height: 1.55;
  scrollbar-width: thin;
}
@media (max-width: 640px) {
  #prompt {
    /* iOS Safari floor stays at 16 px to prevent input-focus zoom. */
    font-size: 16px;
    min-height: 48px;
    padding: 12px 14px 6px;
  }
}

/* ── Composer card — tighten the chrome so the textarea dominates ── */
.composer-card {
  padding: 4px 4px 6px 0;  /* shaved 2 px off the bottom — toolbar already has its own pad */
  /* Existing brand focus-within style (line 1887) stays untouched. */
}

/* ── Real-time Whisper mic (Web UI · parity with Mini App) ─────────── */
.composer-mic {
  gap: 6px;
  position: relative;
}
.composer-mic .mic-recording { display: none; }
.composer-mic.is-recording {
  background: var(--danger, #ef4444) !important;
  color: #fff !important;
  border-color: transparent !important;
  animation: voiceMicPulse 1.1s ease-in-out infinite;
}
.composer-mic.is-recording .mic-idle { display: none; }
.composer-mic.is-recording .mic-recording { display: inline; }
.composer-mic.is-busy { opacity: 0.55; cursor: wait; }
.composer-mic.is-live { box-shadow: 0 0 0 2px rgba(228, 76, 154, 0.35); }
@keyframes voiceMicPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.55); }
  50%      { box-shadow: 0 0 0 8px rgba(239, 68, 68, 0); }
}

/* ── Talk-to-agent: speaker (TTS) + hands-free toggles ──────────────
   Same visual family as .composer-mic. Icon swaps via the `.is-on`
   state class set by voice-chat wiring in app.js. The two per-state
   spans (.tts-off / .tts-on, .hf-off / .hf-on) are toggled visible
   via display rules so the button's box stays a fixed size — the
   composer row doesn't reflow when the user flips the setting. */
.composer-tts, .composer-hands-free {
  gap: 6px;
  position: relative;
}
.composer-tts .tts-on   { display: none; }
.composer-tts.is-on .tts-off { display: none; }
.composer-tts.is-on .tts-on  { display: inline; }
.composer-tts.is-on {
  background: rgba(0, 120, 191, 0.10);
  border-color: var(--brand-blue, #0078BF) !important;
  color: var(--brand-blue, #0078BF) !important;
}
.composer-tts.is-speaking {
  animation: voiceTtsPulse 1.4s ease-in-out infinite;
}
@keyframes voiceTtsPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(0, 120, 191, 0.45); }
  50%      { box-shadow: 0 0 0 6px rgba(0, 120, 191, 0);   }
}
.composer-hands-free .hf-on { display: none; }
.composer-hands-free.is-on .hf-off { display: none; }
.composer-hands-free.is-on .hf-on  { display: inline; }
.composer-hands-free.is-on {
  background: rgba(228, 76, 154, 0.10);
  border-color: var(--brand-pink, #E44C9A) !important;
  color: var(--brand-pink, #E44C9A) !important;
  animation: voiceHfBreathe 2.4s ease-in-out infinite;
}
@keyframes voiceHfBreathe {
  0%, 100% { box-shadow: 0 0 0 0 rgba(228, 76, 154, 0.30); }
  50%      { box-shadow: 0 0 0 5px rgba(228, 76, 154, 0);   }
}
.voice-live {
  margin: 0 8px 6px;
  padding: 8px 12px;
  border-radius: 10px;
  background: linear-gradient(135deg, rgba(0, 120, 191, 0.08), rgba(228, 76, 154, 0.08));
  border: 1px solid rgba(0, 120, 191, 0.18);
  font-size: 13px;
  line-height: 1.4;
  color: var(--text, #1a1f2e);
}
.voice-live.hidden { display: none !important; }
.voice-live-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--brand-pink, #E44C9A);
  margin-bottom: 4px;
}
.voice-live-label .voice-live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--danger, #ef4444);
  animation: voiceMicPulse 1.1s ease-in-out infinite;
}
.voice-live-text {
  white-space: pre-wrap;
  word-break: break-word;
  min-height: 1.2em;
}
.voice-live-text.is-empty {
  color: var(--muted, #8a93a6);
  font-style: italic;
}
html.theme-dark .voice-live {
  background: linear-gradient(135deg, rgba(0, 120, 191, 0.14), rgba(228, 76, 154, 0.12));
  border-color: rgba(0, 120, 191, 0.28);
  color: var(--text, #e8eef8);
}

/* ── Toolbar baseline — all interactive children align to 36 px ──── */
.composer-row {
  min-height: 44px;
  padding: 4px 8px 6px;
  gap: 6px;
}
.composer-row :where(.btn, button, .mode-picker-btn, .queue-pill) {
  min-height: 32px;
  align-self: center;
}
/* Send button sits right by default — keep the existing flex-end on
   .composer-row, but if anyone later wants three explicit groups they
   can add `.composer-row-left` / `.composer-row-right` wrappers and
   the existing `justify-content: flex-end` still works. The Attach
   button stays as the visual anchor of the left cluster. */
#attachBtn {
  /* The first child takes natural left position; the mode-picker
     and queue-idea sit beside it. Send pushes right via flex justify. */
}
#sendBtn {
  margin-left: auto; /* explicit right-pin — survives any sibling shuffle */
}

/* ── Send button — slightly more presence so it reads as primary ──── */
#sendBtn {
  padding: 0 14px;
  min-width: 76px;
  font-weight: 600;
}
#sendBtn:not(:disabled) {
  box-shadow: 0 1px 3px var(--primary-tint-strong);
}

/* ── Conversation area — reclaim the space the composer gave back ──
   No layout change; just ensure the messages list still uses the full
   remaining height after the (now smaller) composer takes its share.
   The existing #messages container uses `flex: 1` in the parent grid
   so this is automatic — no rule needed. Documented here so a future
   editor doesn't re-introduce a fixed-height on #messages. */

/* ── Char-pill — sit inside the composer-card top edge tidily ─────── */
.imagine-char-pill {
  top: 6px;
  right: 8px;
  font-size: 10.5px;
  padding: 2px 7px;
}

/* ── Dark-mode bridge — composer-card border picks up the right token */
html.theme-dark .composer-card {
  background: var(--surface, #111A2C);
  border-color: var(--border, #1F2A40);
}
/* ═════════════════ end composer refinement ═════════════════════════ */

/* Thread web terminal — inline, keyboard-first, no modal. */
.thread-terminal-panel {
  flex: 0 0 auto;
  margin: 0 20px 14px;
  border: 1px solid #283447;
  border-radius: 12px;
  overflow: hidden;
  background: #0b1220;
  color: #dbe7f5;
  box-shadow: 0 10px 30px rgba(0,0,0,.18);
}
.thread-terminal-panel.hidden { display: none; }
.thread-terminal-head {
  min-height: 42px; padding: 6px 10px 6px 14px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: #111a2c; border-bottom: 1px solid #283447;
}
.thread-terminal-title, .thread-terminal-actions { display: flex; align-items: center; gap: 9px; min-width: 0; }
.thread-terminal-title > code { color: #8fa5bf; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thread-terminal-actions { color: #8fa5bf; font-size: 12px; flex-shrink: 0; }
.thread-terminal-actions .btn { color: #cbd7e6; }
#threadTerminalStatus.is-error { color: #fb7185; }
.thread-terminal-panel .git-changes-info-tooltip { margin: 10px 12px 0; background: #172238; color: #cbd7e6; }
.thread-terminal-output {
  height: clamp(180px, 30vh, 400px); overflow: auto; padding: 14px 16px;
  font: 13px/1.55 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  scrollbar-color: #40506a transparent;
}
.thread-terminal-entry + .thread-terminal-entry { margin-top: 16px; }
.thread-terminal-command { color: #7dd3fc; white-space: pre-wrap; overflow-wrap: anywhere; }
.thread-terminal-command > span:first-child, .thread-terminal-prompt { color: #86efac; font-weight: 700; }
.thread-terminal-result { margin: 4px 0 2px; color: #e5edf7; white-space: pre-wrap; overflow-wrap: anywhere; font: inherit; }
.thread-terminal-meta { color: #94a3b8; font-size: 11px; }
.thread-terminal-meta.is-error { color: #fda4af; }
.thread-terminal-form {
  display: flex; align-items: center; gap: 8px; padding: 9px 12px;
  border-top: 1px solid #283447; background: #0e1728;
}
.thread-terminal-form input {
  min-width: 0; flex: 1; border: 0; outline: 0; background: transparent; color: #f8fafc;
  font: 13px/1.5 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
.thread-terminal-form input::placeholder { color: #64748b; }
.thread-terminal-form input:focus-visible { box-shadow: 0 2px 0 #38bdf8; }
@media (max-width: 640px) {
  .thread-terminal-panel { margin: 0 8px 8px; border-radius: 9px; }
  .thread-terminal-head { align-items: flex-start; flex-direction: column; gap: 4px; }
  .thread-terminal-actions { width: 100%; justify-content: flex-end; }
  .thread-terminal-title > code { max-width: 52vw; }
  .thread-terminal-output { height: 32vh; }
}

/* Fullscreen mode — pins the terminal to the entire viewport so the
   output area can use maximum vertical + horizontal space. Toggled by
   the ⛶ Fullscreen button in the header (see app.js). Esc exits. */
.thread-terminal-panel.is-fullscreen {
  position: fixed;
  inset: 0;
  margin: 0;
  border-radius: 0;
  border: 0;
  z-index: 1200;
  display: flex;
  flex-direction: column;
  box-shadow: none;
}
.thread-terminal-panel.is-fullscreen .thread-terminal-output {
  height: auto;
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
}
.thread-terminal-panel.is-fullscreen .thread-terminal-head {
  flex: 0 0 auto;
}
.thread-terminal-panel.is-fullscreen .thread-terminal-form {
  flex: 0 0 auto;
}
/* Prevent background page scroll while fullscreen is active. */
body.thread-terminal-fullscreen-active { overflow: hidden; }

/* ═════════════════════════════════════════════════════════════════════
   ║  RESPONSIVE COVERAGE — wide displays + final hygiene               ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Cumulative passes shipped 27 media queries covering down to       ║
   ║  320 px — but ZERO min-width queries. On a 2560 × 1440 ultrawide   ║
   ║  the conversation column stretches to ~2200 px wide, making        ║
   ║  individual prose lines 200+ chars (well past the 75-char reading  ║
   ║  comfort ceiling that ChatGPT / Linear / Notion respect).          ║
   ║                                                                     ║
   ║  This block adds:                                                   ║
   ║   • Universal `overflow-x: hidden` guard on body                    ║
   ║   • Conversation column cap at 1280 / 1600 / 1920 / 2560 px        ║
   ║   • Slightly wider sidebar on 1600 px+ (the 300 px floor feels      ║
   ║     thin on a 2560-px screen)                                       ║
   ║   • Touch-target minimum 44×44 on coarse-pointer devices            ║
   ║   • Safe-area-inset support for iPhone home bar / notch             ║
   ║                                                                     ║
   ║  All :where()-scoped where possible so zero specificity collision   ║
   ║  with the existing 27 max-width rules.                             ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── 1. Universal no-horizontal-overflow guard ──────────────────────
   Last line of defence: if any future component overflows by accident
   (e.g. a 1200-px wide table on a 1100-px viewport), the page won't
   bounce horizontally. Inner overflow containers (chat scroll list,
   table scroll wrappers) keep their own `overflow-x: auto` which
   still works inside this clip. */
html, body {
  overflow-x: hidden;
  max-width: 100vw;
}

/* ── 2. Touch-target minimums for coarse-pointer devices ─────────── */
/* iOS HIG and Material both recommend 44×44 minimum. We already have
   buttons at 32-36 on desktop; coarse pointers need a bigger tap
   surface. `pointer: coarse` matches phones + tablets + Surface in
   tablet mode. `:where()` keeps specificity at zero. */
@media (pointer: coarse) {
  :where(button, .btn, a.btn, [role="button"]) {
    min-height: 44px;
    min-width: 44px;
  }
  /* The composer toolbar buttons set their own explicit heights;
     don't push them above 44 there (would make the row too tall). */
  .composer-row :where(button, .btn) {
    min-height: 36px;
  }
  /* Larger tap-surface on link icons (e.g. the channel pills,
     social SVG glyphs from the hygiene layer). */
  :where(.channel-pill, .ico-whatsapp, .ico-telegram) {
    min-height: 36px;
  }
}

/* ── 3. Safe-area-inset for iPhone home-bar / notch ─────────────── */
/* iOS Safari + standalone PWA reserves space for the bottom home-bar.
   Without explicit env() padding, the composer's Send button can sit
   under the bar. */
#composer {
  padding-bottom: max(18px, env(safe-area-inset-bottom, 18px));
}
@media (max-width: 640px) {
  /* Mobile: same guard but with the tighter mobile padding from the
     earlier responsive layer. */
  #composer {
    padding-bottom: max(12px, env(safe-area-inset-bottom, 12px));
  }
}
/* Top safe-area: only matters in PWA full-screen mode, but cheap. */
#sidebar, #header {
  padding-top: max(0px, env(safe-area-inset-top, 0px));
}

/* ── 4. Wide-display polish — laptop (1280-1599 px) ──────────────── */
/* Sweet spot for most laptops — small bump to conversation comfort. */
@media (min-width: 1280px) {
  /* Conversation column gets a max-width that respects reading
     ergonomics. We don't constrain #messages itself (it needs to fill
     the column for sticky-scroll), but we cap each message's bubble
     so 200-char-wide lines don't happen. */
  :where(.msg) > .bubble {
    max-width: min(820px, 86ch);
  }
  /* Composer max-width already at 820 px from base CSS — matches. */
}

/* ── 5. Wide-display polish — wide laptop / desktop (1600-1919 px) ─ */
@media (min-width: 1600px) {
  /* Sidebar widens slightly so the navigation labels breathe. */
  :root {
    --sidebar-w: 320px;
  }
  /* Bubble cap stays at 820 — wider prose hurts readability beyond
     this regardless of viewport size. */
  :where(.msg) > .bubble {
    max-width: min(860px, 86ch);
  }
  /* Center the chat column horizontally on the page (the body grid
     auto-fills, but the messages list itself can sit slightly inset). */
  #messages {
    padding-left: max(28px, calc((100% - 1280px) / 2 - 200px));
    padding-right: max(28px, calc((100% - 1280px) / 2 - 200px));
  }
}

/* ── 6. Wide-display polish — Full HD / 1440p (1920-2559 px) ────── */
@media (min-width: 1920px) {
  /* Marginal sidebar widening — the labels can be slightly larger. */
  :root {
    --sidebar-w: 340px;
  }
  /* Body font bumps from 14 to 15 px so the larger viewport doesn't
     make text feel too small relative to screen real-estate. */
  body { font-size: 15px; }
  /* Bubble cap holds firm — adding more width past 860 px doesn't help
     readability. Lines should not exceed ~86 chars regardless. */
  :where(.msg) > .bubble {
    max-width: min(920px, 86ch);
    font-size: 15px;
  }
  /* Composer matches the new column inset. */
  .composer-card {
    max-width: 920px;
  }
}

/* ── 7. Wide-display polish — Ultrawide / 4K (2560 px+) ─────────── */
@media (min-width: 2560px) {
  /* Sidebar widens once more — at 2560 px wide the proportions need it. */
  :root {
    --sidebar-w: 360px;
  }
  body { font-size: 16px; }
  /* Final bubble cap. Prose width stays at 86 ch which is the upper
     limit for comfortable reading — anything past this is hostile to
     the reader regardless of screen real-estate. */
  :where(.msg) > .bubble {
    max-width: min(1000px, 86ch);
  }
  /* Composer width matches. */
  .composer-card { max-width: 1000px; }
  /* The chat column gets generous side padding so it doesn't drift
     all the way to the edge of an ultrawide. */
  #messages {
    padding-left: max(28px, calc((100% - 1400px) / 2 - 200px));
    padding-right: max(28px, calc((100% - 1400px) / 2 - 200px));
  }
}

/* ── 8. Final mobile hygiene — 360 px floor ─────────────────────── */
/* Most existing mobile rules target 640 / 480. The smallest phones
   we care about start at 360 (older Android baseline). Tighten the
   chrome there so chat still works. */
@media (max-width: 360px) {
  /* Reduce composer horizontal padding by another 4 px on the
     smallest phones — every pixel of textarea width helps. */
  #composer {
    padding-left: 12px;
    padding-right: 12px;
  }
  /* Sidebar drawer width — already handled by earlier responsive
     layer; just make sure the toggle button has tap space. */
  .mobile-nav-btn, #themeToggleBtn, #newThreadBtn {
    min-width: 40px;
    min-height: 40px;
  }
  /* Modal toolbars get tighter button gap on tiny screens. */
  .imagine-preview-toolbar { padding: 6px 8px; gap: 4px; }
}

/* ── 9. Print — already declared but tighten further ─────────────── */
/* The earlier layer hides the chrome on print; ensure the bubble
   max-width doesn't get capped (we want the full message to print). */
@media print {
  :where(.msg) > .bubble {
    max-width: none !important;
  }
}

/* ── 10. High-DPI image polish ──────────────────────────────────── */
/* On retina + 4K screens, the auto-rendered avatar/icon SVGs already
   look sharp, but raster fallbacks (PNG attachments) benefit from
   image-rendering hints. */
@media (min-resolution: 2dppx) {
  :where(.avatar img, .brand-mark img) {
    image-rendering: -webkit-optimize-contrast;
  }
}
/* ═════════════════ end responsive coverage ═════════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  DARK-MODE INLINE-STYLE RESCUE LAYER                               ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Several legacy views (Email Approvals, role-select dropdown,      ║
   ║  cursor-snippet pill, typing-indicator dots, etc.) shipped with    ║
   ║  HARDCODED hex backgrounds in inline `style="…"` attributes.        ║
   ║  Inline styles win specificity against any CSS rule, so the dark-  ║
   ║  mode flip never reaches them — cards stay pure white, light-blue  ║
   ║  panels stay light-blue, text becomes invisible.                    ║
   ║                                                                     ║
   ║  Fix: targeted `[style*="#XXX"]` attribute selectors with          ║
   ║  `!important` to defeat the inline. Surgical — only fires when      ║
   ║  html.theme-dark is active and the exact known-bad hex is in the   ║
   ║  inline style. Zero risk of touching light-mode rendering.          ║
   ║                                                                     ║
   ║  Reported 30 Jun 2026 — Email Approvals screenshot showed          ║
   ║  white-on-near-white text against a pure-white card.                ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── 1. Email Approvals card chrome ─────────────────────────────── */
html.theme-dark .email-approval-card {
  background: var(--surface) !important;
  border-color: var(--border) !important;
  /* left accent stays amber (the brand semantic for "needs your eyes") */
}

/* ── 2. Inner panels — Inbound (light-blue) + Drafted Reply (cream) */
/* Match by the unique hex baked into the inline style. */
html.theme-dark .email-approval-card [style*="#F0F8FE"] {
  background: color-mix(in srgb, var(--primary) 14%, var(--surface)) !important;
  border-color: color-mix(in srgb, var(--primary) 30%, var(--border)) !important;
}
html.theme-dark .email-approval-card [style*="#FEF7E6"] {
  background: color-mix(in srgb, var(--warning, #D97706) 14%, var(--surface)) !important;
  border-color: color-mix(in srgb, var(--warning, #D97706) 28%, var(--border)) !important;
}
html.theme-dark .email-approval-card [style*="#F8FAFC"] {
  background: var(--surface-sunk) !important;
}

/* ── 3. Inner <pre> blocks (full-body reveal + draft reply body) ── */
/* The JS hardcodes `background:#fff` + dark-grey text inside <pre>.
   In dark mode that becomes light-on-darker-grey — readable but jarring.
   Flip to the sunk surface + light text. */
html.theme-dark .email-approval-card pre {
  background: var(--surface-sunk) !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}
/* The draft-reply body uses a plain div, not pre — target via the
   inline background:#fff + the surrounding cream panel context. */
html.theme-dark .email-approval-card [style*="#FEF7E6"] [style*="background:#fff"] {
  background: var(--surface-sunk) !important;
  color: var(--text) !important;
  border-color: color-mix(in srgb, var(--warning, #D97706) 22%, var(--border)) !important;
}

/* ── 4. Eyebrow labels — keep brand colour but bump contrast ──── */
/* "📥 ORIGINAL INBOUND" eyebrow is `color:#0078BF` — readable on dark.
   "✉️ DRAFTED REPLY" eyebrow is `color:#9A6900` — too dim on dark. */
html.theme-dark .email-approval-card [style*="#9A6900"] {
  color: color-mix(in srgb, var(--warning, #D97706) 30%, #ffffff) !important;
}

/* "From: / Subject: / Received:" labels — the regular text inherits
   the body colour but the inline blocks use the panel default. They
   should now be readable because the panel backgrounds flipped. */
html.theme-dark .email-approval-card .approval-original,
html.theme-dark .email-approval-card .approval-draft {
  color: var(--text) !important;
}

/* ── 5. Reject button — light-mode is white-on-red-border ──────── */
/* In dark mode, white background makes it pop too hard. Use the
   surface colour so it sits as a secondary action. */
html.theme-dark .email-approval-card .ea-reject-btn {
  background: var(--surface) !important;
  color: var(--danger, #F87171) !important;
  border-color: color-mix(in srgb, var(--danger, #F87171) 40%, var(--border)) !important;
}

/* ── 6. Note textarea (rejection reason) ───────────────────────── */
html.theme-dark .email-approval-card .ea-note {
  background: var(--surface-sunk) !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}
html.theme-dark .email-approval-card .ea-reject-cancel {
  background: transparent !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}

/* ── 7. Other identified inline-style sites across the codebase ── */

/* Cursor-snippet pill (line 19509 of app.js) — same #F0F8FE inbound colour. */
html.theme-dark [style*="background:#F0F8FE"] {
  background: color-mix(in srgb, var(--primary) 14%, var(--surface)) !important;
}

/* Role-select dropdown (My Teams) + Cancel button — hardcoded white. */
html.theme-dark select[style*="background:#fff"],
html.theme-dark button[style*="background:#fff"]:not(.ea-reject-btn) {
  background: var(--surface) !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}
html.theme-dark [style*="color:#111"] {
  color: var(--text) !important;
}

/* Typing indicator dots (#9aa0a6) — already neutral grey, but bump
   for dark mode visibility. */
html.theme-dark [style*="background:#9aa0a6"] {
  background: var(--text-dim, #B8C0CC) !important;
}

/* The "Show full body" details summary uses `color:#0078BF` — brand
   blue. Holds up OK on dark, but we can pin it for safety. */
html.theme-dark .email-approval-card summary[style*="#0078BF"] {
  color: color-mix(in srgb, var(--primary) 35%, #ffffff) !important;
}

/* "Trigger:" footnote uses var(--text-muted) — picks up the dark-mode
   value automatically. No override needed. */

/* ── 8. Generic catch-all for any other surfaces using --card-bg ── */
/* The original JS uses `var(--card-bg, #fff)` — `--card-bg` was never
   declared, so the fallback white sticks even in dark mode. Declare
   it now (same fix pattern as `--surface-2` earlier) so the next time
   someone uses this token, it just works. */
:root { --card-bg: var(--surface); }
/* Dark-mode override comes for free via the existing --surface flip. */

/* ═════════════════ end dark-mode rescue layer ══════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  NOTIFICATIONS PANEL POLISH — `.approval-gate-item` cards          ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Reference (user-supplied screenshot, 30 Jun 2026): the panel has  ║
   ║  the right bones — header, tab strip, cards, footer tip — but the  ║
   ║  cards feel slightly cramped, action buttons sit at uneven heights ║
   ║  in dark mode, and the inline-styled Snooze pills don't flip.      ║
   ║                                                                     ║
   ║  This block polishes — does NOT redesign:                           ║
   ║   • Card hover lift + subtle border-strong-on-hover                 ║
   ║   • Brand-tokenised Approve button (was hex #2A9D4F)                ║
   ║   • Equal-height action buttons (32 px) + grouped spacing           ║
   ║   • Snooze + snooze-pick pills via attribute selector (dark-mode)   ║
   ║   • Priority pill consistency (CRITICAL / HIGH / MEDIUM / LOW)      ║
   ║   • Better meta typography hierarchy                                ║
   ║   • Empty-state styling when no notifications wait                  ║
   ║   • Three-dot menu hover affordance                                 ║
   ║                                                                     ║
   ║  No JS changes, no markup changes. Inline styles defeated by       ║
   ║  attribute-substring selectors with !important.                     ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── 1. Card chrome — hover lift + brand-strong border on hover ──── */
.approval-gate-item {
  transition:
    transform var(--motion-fast, 120ms) var(--ease-out, ease),
    border-color var(--motion-fast, 120ms) var(--ease-out, ease),
    box-shadow var(--motion-fast, 120ms) var(--ease-out, ease);
}
.approval-gate-item:hover {
  border-color: var(--border-strong, var(--primary-tint-strong));
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(15, 23, 42, 0.06));
  transform: translateY(-1px);
}

/* ── 2. Approve button — use --success token instead of hex ─────── */
/* Was #2A9D4F → didn't match brand --success (#047857) and didn't
   flip in dark mode. Use the brand-system equivalent. */
.approval-gate-item-actions .approve-btn {
  background: var(--success, #047857);
  height: 32px;
  padding: 0 14px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.approval-gate-item-actions .approve-btn:hover {
  background: color-mix(in srgb, var(--success, #047857) 88%, #000);
}
.approval-gate-item-actions .reject-btn {
  height: 32px;
  padding: 0 14px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* ── 3. Snooze button — inline-styled #D97706 amber border ─────── */
/* Polish heights to match Approve/Reject (32 px) + dark-mode rescue. */
.approval-gate-item-actions .snooze-btn,
.approval-gate-item-actions [class*="snooze"] {
  height: 32px !important;
  padding: 0 14px !important;
  display: inline-flex !important;
  align-items: center !important;
  gap: 4px !important;
  font-size: 13px !important;
  font-weight: 600 !important;
  border-radius: 7px !important;
  transition: background-color var(--motion-fast, 120ms) var(--ease-out, ease),
              border-color var(--motion-fast, 120ms) var(--ease-out, ease);
}
.approval-gate-item-actions .snooze-btn:hover {
  background: color-mix(in srgb, var(--warning, #D97706) 12%, transparent) !important;
}
/* Dark-mode rescue for the snooze-pick row pills (light amber bg
   + dark amber text were hardcoded — invisible-ish on dark surface). */
html.theme-dark .approval-gate-item [style*="#D97706"] {
  border-color: color-mix(in srgb, var(--warning, #D97706) 60%, var(--border)) !important;
  color: color-mix(in srgb, var(--warning, #D97706) 30%, #ffffff) !important;
}
html.theme-dark .approval-gate-item [style*="#FEF3C7"] {
  background: color-mix(in srgb, var(--warning, #D97706) 14%, var(--surface-sunk)) !important;
}
html.theme-dark .approval-gate-item [style*="#92400E"] {
  color: color-mix(in srgb, var(--warning, #D97706) 30%, #ffffff) !important;
}

/* ── 4. Snooze-pick row layout — spacing + alignment ──────────── */
.approval-gate-item-snooze-row {
  align-items: center !important;
  flex-wrap: wrap !important;
  gap: 6px !important;
  margin-top: 10px !important;
  padding-top: 10px !important;
  border-top: 1px dashed var(--divider, var(--border)) !important;
}
.approval-gate-item-snooze-row .snooze-pick-btn {
  height: 28px !important;
  padding: 0 11px !important;
  border-radius: 999px !important;
}

/* ── 5. Action row spacing — left cluster + meta drift ────────── */
.approval-gate-item-actions {
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--divider, var(--border));
}

/* ── 6. Priority pill consistency (CRITICAL / HIGH / MEDIUM / LOW) ─
   Many places render these as inline-styled text. Normalise any
   .approval-gate-item descendant matching the canonical text labels
   into a real pill. Uses an attribute selector trick — match the
   element whose textContent starts with the label via [data-prio].
   For elements without data-prio (legacy), CSS can't read text, so
   this won't catch them — but as new code adopts `data-prio="critical"`
   it auto-styles. */
.approval-gate-item [data-prio] {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 10px;
  min-height: 22px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1;
  white-space: nowrap;
}
.approval-gate-item [data-prio="critical"] {
  background: color-mix(in srgb, var(--danger, #DC2626) 14%, transparent);
  color: var(--danger, #DC2626);
  border: 1px solid color-mix(in srgb, var(--danger, #DC2626) 28%, transparent);
}
.approval-gate-item [data-prio="high"] {
  background: color-mix(in srgb, var(--warning, #D97706) 14%, transparent);
  color: var(--warning, #D97706);
  border: 1px solid color-mix(in srgb, var(--warning, #D97706) 28%, transparent);
}
.approval-gate-item [data-prio="normal"],
.approval-gate-item [data-prio="medium"] {
  background: color-mix(in srgb, var(--primary, #0D7377) 12%, transparent);
  color: var(--primary, #0D7377);
  border: 1px solid color-mix(in srgb, var(--primary, #0D7377) 24%, transparent);
}
.approval-gate-item [data-prio="low"] {
  background: var(--surface-sunk, #EEF2F6);
  color: var(--text-muted, #475569);
  border: 1px solid var(--border, #E3E8EF);
}

/* ── 7. Meta line — slightly improve typography hierarchy ──────── */
.approval-gate-item-meta {
  font-size: 11.5px;
  letter-spacing: 0.01em;
  opacity: 0.92;
}

/* ── 8. Title + sub typography breathing room ─────────────────── */
.approval-gate-item-title {
  line-height: 1.4;
  /* slightly tighter than the base 1.55 so the title row feels like a
     header, not body text */
}
.approval-gate-item-sub {
  margin-top: 2px;
}

/* ── 9. Reject-confirm row spacing ──────────────────────────────── */
.approval-gate-item-reject-row {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--divider, var(--border));
  align-items: center;
}
.approval-gate-item-reject-row .reject-confirm-btn {
  height: 32px;
  padding: 0 14px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--danger, #DC2626);
  color: #fff;
  border: 0;
  border-radius: 7px;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
}
.approval-gate-item-reject-row .reject-confirm-btn:hover {
  background: color-mix(in srgb, var(--danger, #DC2626) 88%, #000);
}

/* ── 10. Empty state — when the list is empty ───────────────────── */
.approval-gate-section-list:empty::before,
.approval-gate-list:empty::before {
  content: "✨  You're all caught up.";
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
  border: 1px dashed var(--border);
  border-radius: var(--radius, 10px);
  background: color-mix(in srgb, var(--success, #047857) 4%, var(--surface));
  color: var(--text-muted, #475569);
  font-size: 13.5px;
  font-weight: 500;
  margin-top: 8px;
}

/* ── 11. Tab strip — active tab clearer, hover smoother ─────────── */
.approval-gate-tab {
  transition:
    background-color var(--motion-fast, 120ms) var(--ease-out, ease),
    color var(--motion-fast, 120ms) var(--ease-out, ease),
    border-color var(--motion-fast, 120ms) var(--ease-out, ease);
}
.approval-gate-tab.is-active {
  font-weight: 600;
}

/* ── 12. Section heading "Tasks waiting on your accept / cancel" ─ */
/* Already small, but bump the sort-control alignment to the same
   baseline as the heading text. */
.approval-gate-sub {
  line-height: 1.55;
}

/* ── 13. Sort-by control — if present in the future, pre-style ──── */
:where(.approval-gate-sort, [data-sort-control]) {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  height: 28px;
  background: var(--surface-sunk, #EEF2F6);
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 999px;
  color: var(--text-muted, #475569);
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color var(--motion-fast, 120ms) var(--ease-out, ease);
}
:where(.approval-gate-sort, [data-sort-control]):hover {
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
  color: var(--primary, #0D7377);
}

/* ── 14. Three-dot menu (per-card) — hover affordance ──────────── */
:where(.approval-gate-item .more-btn, .approval-gate-item .menu-btn) {
  width: 28px;
  height: 28px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted, #475569);
  cursor: pointer;
  transition: background-color var(--motion-fast, 120ms) var(--ease-out, ease);
}
:where(.approval-gate-item .more-btn, .approval-gate-item .menu-btn):hover {
  background: var(--surface-hover, rgba(15, 23, 42, 0.04));
  color: var(--text, #0F172A);
}

/* ── 15. Mobile — cards stack action buttons full-width ─────────── */
@media (max-width: 640px) {
  .approval-gate-item-actions :where(button, .btn) {
    flex: 1 1 auto;
    min-width: 0;
    justify-content: center;
  }
  .approval-gate-item-snooze-row {
    overflow-x: auto;
    flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch;
  }
}
/* ═════════════════ end notifications-panel polish ══════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  ADD-TO-IDEA-QUEUE MODAL — paste / drop / thumbnail polish         ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Reported 30 Jun 2026: user couldn't paste images into the modal.  ║
   ║  The file picker worked but Cmd/Ctrl+V silently dropped the image. ║
   ║                                                                     ║
   ║  This block styles three new affordances added in app.js:           ║
   ║   1. `.queue-idea-chip.is-image` + `.queue-idea-chip-thumb` —       ║
   ║      proper image thumbnail in the chip                             ║
   ║   2. `.modal.is-drop-active` — drag-and-drop visual hint            ║
   ║   3. `.queue-idea-paste-flash` — brief glow on paste so the user    ║
   ║      gets visual feedback their image landed                        ║
   ║                                                                     ║
   ║  All paired with the JS edit in `openQueueIdeaModal()`.             ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── 1. Image-thumbnail chip ────────────────────────────────────── */
.queue-idea-chip.is-image {
  padding: 3px 8px 3px 4px;
  gap: 6px;
}
.queue-idea-chip-thumb {
  width: 24px;
  height: 24px;
  border-radius: 4px;
  object-fit: cover;
  display: block;
  border: 1px solid var(--border, #E3E8EF);
  flex-shrink: 0;
}
.queue-idea-chip-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 140px;
}
.queue-idea-chip-size {
  color: var(--text-faint, #94A3B8);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}

/* ── 2. Drag-and-drop active state on the modal ──────────────────── */
.modal.is-drop-active {
  position: relative;
}
.modal.is-drop-active::after {
  content: "Drop files to attach";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--primary, #0D7377) 14%, transparent);
  border: 2px dashed var(--primary, #0D7377);
  border-radius: inherit;
  color: var(--primary, #0D7377);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 0.02em;
  pointer-events: none;
  z-index: 5;
  animation: queue-idea-drop-in 140ms var(--ease-out, ease);
}
@keyframes queue-idea-drop-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ── 3. Paste flash — brief glow on the attach row ───────────────── */
.queue-idea-attach-row.queue-idea-paste-flash {
  position: relative;
}
.queue-idea-attach-row.queue-idea-paste-flash::before {
  content: "✓ Pasted";
  position: absolute;
  top: -22px;
  right: 0;
  background: var(--success, #047857);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  animation: queue-idea-paste-pop 600ms var(--ease-out, ease) forwards;
  pointer-events: none;
}
@keyframes queue-idea-paste-pop {
  0%   { opacity: 0; transform: translateY(4px); }
  20%  { opacity: 1; transform: translateY(0); }
  80%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-4px); }
}

/* ── 4. Subtle hint in the textarea placeholder (added via title-text)
   so users discover paste support. The actual hint text stays in the
   placeholder declared in app.js; this layer just adds a tiny "📎 Paste
   or drop images" label below the attach button when no chips exist. */
.queue-idea-attach-row:not(:has(.queue-idea-chip)) .queue-idea-chips::before {
  content: "📎 Or paste / drop images directly";
  font-size: 11.5px;
  color: var(--text-faint, #94A3B8);
  font-style: italic;
  padding-left: 4px;
  align-self: center;
}

/* ── 5. Mobile — chips wrap, drop overlay simplifies ────────────── */
@media (max-width: 640px) {
  .queue-idea-chip { max-width: 100%; }
  .queue-idea-chip-name { max-width: 60vw; }
  .modal.is-drop-active::after { font-size: 13px; }
}
/* ═════════════════ end queue-idea-modal polish ══════════════════════ */


/* ═════════════════════════════════════════════════════════════════════
   ║  PAGE-HEADER NORMALIZATION LAYER · 30 Jun 2026 · senior-fe pass    ║
   ║  ───────────────────────────────────────────────────────────────  ║
   ║  Problem reported by Mohammed Ashfak: some dashboard headers       ║
   ║  ("My Agents", and others under audit) showed Refresh + Back       ║
   ║  STACKED UNDER the title + subtitle on a third row, while peer     ║
   ║  headers ("My Chats", "My Messages", "My Account") correctly       ║
   ║  showed the action buttons pinned to the top-right of the header.  ║
   ║                                                                     ║
   ║  Root cause (verified against styles.css L995 + L9001 + L1112):    ║
   ║                                                                     ║
   ║    • The shared `.chat-title-wrap` (display:flex column · title    ║
   ║      stacked above subtitle) had NO `flex` short-hand. In the      ║
   ║      surrounding `<header>` flex row this gave it the natural      ║
   ║      width of its LONGEST CONTENT — which on long-subtitle pages   ║
   ║      (e.g. "My Agents") was the full subtitle on one line. That    ║
   ║      consumed the entire row, and because the parent header had    ║
   ║      `flex-wrap: wrap`, `.header-actions` got pushed onto a new    ║
   ║      row UNDER the subtitle, producing the screenshot the user     ║
   ║      sent. Short-subtitle pages happened to fit by accident.       ║
   ║                                                                     ║
   ║    • Four page-headers were missing from the shared rule entirely  ║
   ║      and got the browser-default `display: block` instead, so      ║
   ║      their action clusters fell wherever the DOM order put them:   ║
   ║      `#myAccountHeader`, `#emailApprovalsHeader`,                  ║
   ║      `#cursorSetupHeader`, `#mastersHeader`.                       ║
   ║                                                                     ║
   ║  Fix — two parts, both zero-specificity (:where()) so no markup    ║
   ║  edit + no risk of overriding the per-view header rules already    ║
   ║  in place. Hard rules: do NOT redesign · preserve brand tokens ·   ║
   ║  must work in both light and dark theme · must not regress the     ║
   ║  composer / preview / sidebar work shipped earlier this week.      ║
   ║                                                                     ║
   ║   1. UNIVERSAL FLEX ROW — every dashboard page-header (the full    ║
   ║      list catalogued from index.html, plus the four missing ones)  ║
   ║      gets `display:flex · row · space-between · wrap` so the       ║
   ║      title-block sits left and the actions sit right consistently. ║
   ║                                                                     ║
   ║   2. TITLE-BLOCK GROWS, ACTIONS PIN RIGHT — inside any of those    ║
   ║      headers, `.chat-title-wrap` gets `flex: 1 1 0 · min-width:0`  ║
   ║      so it fills available width AND lets a long subtitle WRAP     ║
   ║      onto multiple lines internally (vertical growth) instead of   ║
   ║      stretching the wrap horizontally and ejecting the actions.    ║
   ║      `.header-actions` gets `margin-left:auto · align-self:        ║
   ║      flex-start` so it always anchors top-right, even when the     ║
   ║      title-block grows two or three lines tall.                    ║
   ║                                                                     ║
   ║      `.chat-subtitle` inside these headers gets `white-space:      ║
   ║      normal` (the default but defensive — guarantees wrapping)     ║
   ║      and a soft `max-width: 72ch` so it can't push beyond a        ║
   ║      readable measure even when the viewport is ultrawide.         ║
   ║                                                                     ║
   ║   3. NARROW-VIEWPORT BEHAVIOUR — at <= 720px the actions are       ║
   ║      ALLOWED to wrap onto a second row, but they wrap as a single  ║
   ║      pinned-right cluster, not as scattered loose buttons. The     ║
   ║      existing @media (max-width:720px) rule at L1144 already tunes ║
   ║      the gap — no regression.                                      ║
   ║                                                                     ║
   ║   4. DARK-MODE PARITY — fully inherited (we only set layout, not   ║
   ║      colour). The brand-tinted borders on these headers continue   ║
   ║      to read correctly under `html.theme-dark` because the         ║
   ║      original per-view rules already use the var(--border) /       ║
   ║      var(--surface) tokens.                                        ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── 1. Universal flex row for every dashboard page header ─────────── */
:where(
  #dashboardHeader,
  #ideaQueueHeader,
  #myDocsHeader,
  #myCalendarHeader,
  #myMeetingsHeader,
  #myTravelPlansHeader,
  #myHiringHeader,
  #myTeamProfilesHeader,
  #emailApprovalsHeader,
  #agentDispatchesHeader,
  #myMarketingWebsitesHeader,
  #myMarketingBlogsHeader,
  #myMarketingContentPipelineHeader,
  #myClientsHeader,
  #myMessagesHeader,
  #myBillingHeader,
  #myAccountHeader,
  #backupsHeader,
  #cursorSetupHeader,
  #actionsPendingHeader,
  #mastersHeader,
  #myChatsHeader,
  #myTeamHeader, #myOrgHeader, #organisationsHeader,
  #myAgentsHeader,
  #myTasksHeader,
  #trainingLinksHeader,
  #notificationsHeader
) {
  display: flex;
  align-items: flex-start;          /* hug the top so multi-line title-blocks
                                       keep the actions sitting at the top-right
                                       instead of dropping to vertical centre. */
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  row-gap: 8px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border, #e2e8f0);
  background: var(--surface, #fff);
  flex-shrink: 0;
  min-height: 64px;                 /* matches `#chatHeader` rhythm — keeps
                                       every page-header visually identical
                                       in vertical real-estate. */
}

/* ── 2. Title-block grows, actions pin right ───────────────────────── */
:where(
  #dashboardHeader,
  #ideaQueueHeader,
  #myDocsHeader,
  #myCalendarHeader,
  #myMeetingsHeader,
  #myTravelPlansHeader,
  #myHiringHeader,
  #myTeamProfilesHeader,
  #emailApprovalsHeader,
  #agentDispatchesHeader,
  #myMarketingWebsitesHeader,
  #myMarketingBlogsHeader,
  #myMarketingContentPipelineHeader,
  #myClientsHeader,
  #myMessagesHeader,
  #myBillingHeader,
  #myAccountHeader,
  #backupsHeader,
  #cursorSetupHeader,
  #actionsPendingHeader,
  #mastersHeader,
  #myChatsHeader,
  #myTeamHeader, #myOrgHeader, #organisationsHeader,
  #myAgentsHeader,
  #myTasksHeader,
  #trainingLinksHeader,
  #notificationsHeader
) > :where(.chat-title-wrap) {
  flex: 1 1 0;                      /* THE FIX — grow to fill, shrink below
                                       natural content so a long subtitle
                                       wraps internally instead of pushing
                                       .header-actions to a new row. */
  min-width: 0;                     /* defensive — already on the base
                                       .chat-title-wrap rule but re-asserted
                                       here so future edits to the base rule
                                       can't accidentally regress this fix. */
  align-self: flex-start;
  padding-top: 2px;                 /* hairline visual lift so the title
                                       baseline aligns with the centre of
                                       the action buttons rather than the
                                       bottom of them. */
}

:where(
  #dashboardHeader,
  #ideaQueueHeader,
  #myDocsHeader,
  #myCalendarHeader,
  #myMeetingsHeader,
  #myTravelPlansHeader,
  #myHiringHeader,
  #myTeamProfilesHeader,
  #emailApprovalsHeader,
  #agentDispatchesHeader,
  #myMarketingWebsitesHeader,
  #myMarketingBlogsHeader,
  #myMarketingContentPipelineHeader,
  #myClientsHeader,
  #myMessagesHeader,
  #myBillingHeader,
  #myAccountHeader,
  #backupsHeader,
  #cursorSetupHeader,
  #actionsPendingHeader,
  #mastersHeader,
  #myChatsHeader,
  #myTeamHeader, #myOrgHeader, #organisationsHeader,
  #myAgentsHeader,
  #myTasksHeader,
  #trainingLinksHeader,
  #notificationsHeader
) > :where(.header-actions) {
  margin-left: auto;                /* pin right even if the title-block
                                       hasn't filled all available width. */
  align-self: flex-start;           /* anchor top so a multi-line title-block
                                       doesn't drag the actions vertically. */
  flex-shrink: 0;                   /* never let the action cluster collapse. */
}

/* ── 3. Subtitle: wrap multi-line cleanly, never inflate sideways ──── */
:where(
  #dashboardHeader,
  #ideaQueueHeader,
  #myDocsHeader,
  #myCalendarHeader,
  #myMeetingsHeader,
  #myTravelPlansHeader,
  #myHiringHeader,
  #myTeamProfilesHeader,
  #emailApprovalsHeader,
  #agentDispatchesHeader,
  #myMarketingWebsitesHeader,
  #myMarketingBlogsHeader,
  #myMarketingContentPipelineHeader,
  #myClientsHeader,
  #myMessagesHeader,
  #myBillingHeader,
  #myAccountHeader,
  #backupsHeader,
  #cursorSetupHeader,
  #actionsPendingHeader,
  #mastersHeader,
  #myChatsHeader,
  #myTeamHeader, #myOrgHeader, #organisationsHeader,
  #myAgentsHeader,
  #myTasksHeader,
  #trainingLinksHeader
) :where(.chat-subtitle) {
  white-space: normal;              /* enable wrapping (defensive — the base
                                       rule doesn't force nowrap, but some
                                       per-view rules historically have). */
  word-break: break-word;
  max-width: 78ch;                  /* readable measure even on ultrawide
                                       screens — keeps the subtitle from
                                       running away horizontally. */
  line-height: 1.5;
  margin-top: 2px;
}

/* ── 4. Title hygiene — same font weight/size + tight margin across   ║
   ║  every page-header so the visual rhythm is identical from card to ║
   ║  card. We DO NOT touch the brand-coloured h2 colour (some headers ║
   ║  use --primary, others use --text — leave the existing rules win) ║ */
:where(
  #dashboardHeader,
  #ideaQueueHeader,
  #myDocsHeader,
  #myCalendarHeader,
  #myMeetingsHeader,
  #myTravelPlansHeader,
  #myHiringHeader,
  #myTeamProfilesHeader,
  #emailApprovalsHeader,
  #agentDispatchesHeader,
  #myMarketingWebsitesHeader,
  #myMarketingBlogsHeader,
  #myMarketingContentPipelineHeader,
  #myClientsHeader,
  #myMessagesHeader,
  #myBillingHeader,
  #myAccountHeader,
  #backupsHeader,
  #cursorSetupHeader,
  #actionsPendingHeader,
  #mastersHeader,
  #myChatsHeader,
  #myTeamHeader, #myOrgHeader, #organisationsHeader,
  #myAgentsHeader,
  #myTasksHeader,
  #trainingLinksHeader
) > .chat-title-wrap > h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.25;
}

/* ── 5. Mobile (<= 720px) — actions stay grouped, pinned right, but   ║
   ║  drop onto their own row gracefully. The existing @media at L1144 ║
   ║  already tightens .header-actions gap — we only need to make sure ║
   ║  the title-block resets its flex-basis so it doesn't lock its     ║
   ║  width and create overflow. */
@media (max-width: 720px) {
  :where(
    #dashboardHeader, #ideaQueueHeader, #myDocsHeader, #myCalendarHeader,
    #myMeetingsHeader, #myTravelPlansHeader, #myHiringHeader,
    #myTeamProfilesHeader, #emailApprovalsHeader, #agentDispatchesHeader,
    #myMarketingWebsitesHeader, #myMarketingBlogsHeader,
    #myMarketingContentPipelineHeader, #myClientsHeader, #myMessagesHeader,
    #myBillingHeader, #myAccountHeader, #backupsHeader, #cursorSetupHeader,
    #actionsPendingHeader, #mastersHeader, #myChatsHeader, #myTeamHeader, #myOrgHeader, #organisationsHeader,
    #myAgentsHeader, #myTasksHeader, #trainingLinksHeader
  ) {
    padding: 12px 14px;
    gap: 10px;
  }
  :where(
    #dashboardHeader, #ideaQueueHeader, #myDocsHeader, #myCalendarHeader,
    #myMeetingsHeader, #myTravelPlansHeader, #myHiringHeader,
    #myTeamProfilesHeader, #emailApprovalsHeader, #agentDispatchesHeader,
    #myMarketingWebsitesHeader, #myMarketingBlogsHeader,
    #myMarketingContentPipelineHeader, #myClientsHeader, #myMessagesHeader,
    #myBillingHeader, #myAccountHeader, #backupsHeader, #cursorSetupHeader,
    #actionsPendingHeader, #mastersHeader, #myChatsHeader, #myTeamHeader, #myOrgHeader, #organisationsHeader,
    #myAgentsHeader, #myTasksHeader, #trainingLinksHeader
  ) > :where(.chat-title-wrap) {
    flex: 1 1 100%;                 /* on narrow viewports take the whole row,
                                       letting actions wrap underneath as a
                                       neat right-aligned cluster. */
  }
  :where(
    #dashboardHeader, #ideaQueueHeader, #myDocsHeader, #myCalendarHeader,
    #myMeetingsHeader, #myTravelPlansHeader, #myHiringHeader,
    #myTeamProfilesHeader, #emailApprovalsHeader, #agentDispatchesHeader,
    #myMarketingWebsitesHeader, #myMarketingBlogsHeader,
    #myMarketingContentPipelineHeader, #myClientsHeader, #myMessagesHeader,
    #myBillingHeader, #myAccountHeader, #backupsHeader, #cursorSetupHeader,
    #actionsPendingHeader, #mastersHeader, #myChatsHeader, #myTeamHeader, #myOrgHeader, #organisationsHeader,
    #myAgentsHeader, #myTasksHeader, #trainingLinksHeader
  ) > :where(.header-actions) {
    margin-left: 0;
    justify-content: flex-end;
    width: 100%;
  }
  :where(
    #dashboardHeader, #ideaQueueHeader, #myDocsHeader, #myCalendarHeader,
    #myMeetingsHeader, #myTravelPlansHeader, #myHiringHeader,
    #myTeamProfilesHeader, #emailApprovalsHeader, #agentDispatchesHeader,
    #myMarketingWebsitesHeader, #myMarketingBlogsHeader,
    #myMarketingContentPipelineHeader, #myClientsHeader, #myMessagesHeader,
    #myBillingHeader, #myAccountHeader, #backupsHeader, #cursorSetupHeader,
    #actionsPendingHeader, #mastersHeader, #myChatsHeader, #myTeamHeader, #myOrgHeader, #organisationsHeader,
    #myAgentsHeader, #myTasksHeader, #trainingLinksHeader
  ) > .chat-title-wrap > h2 {
    font-size: 17px;
  }
}

/* ── 6. DARK-MODE PARITY — every page-header reads the same dark      ║
   ║  surface tokens as the rest of the dashboard. The brand-tinted    ║
   ║  bottom border softens to 1px var(--border) which is already      ║
   ║  dark-aware via the :root override in `html.theme-dark`. We only  ║
   ║  re-assert background for completeness — the property already     ║
   ║  resolves correctly, but being explicit prevents a future edit to ║
   ║  the base header rule from accidentally hardcoding #fff. */
html.theme-dark :where(
  #dashboardHeader, #ideaQueueHeader, #myDocsHeader, #myCalendarHeader,
  #myMeetingsHeader, #myTravelPlansHeader, #myHiringHeader,
  #myTeamProfilesHeader, #emailApprovalsHeader, #agentDispatchesHeader,
  #myMarketingWebsitesHeader, #myMarketingBlogsHeader,
  #myMarketingContentPipelineHeader, #myClientsHeader, #myMessagesHeader,
  #myBillingHeader, #myAccountHeader, #backupsHeader, #cursorSetupHeader,
  #actionsPendingHeader, #mastersHeader, #myChatsHeader, #myTeamHeader, #myOrgHeader, #organisationsHeader,
  #myAgentsHeader, #myTasksHeader, #trainingLinksHeader
) {
  background: var(--surface);
  border-bottom-color: var(--border);
}
/* ═════════════════ end page-header normalization layer ══════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  MY BILLING — senior analytics redesign · 30 Jun 2026             ║
   ║  ───────────────────────────────────────────────────────────────  ║
   ║  Replaces the prior junior chart UI flagged by Mohammed Ashfak    ║
   ║  ("not even looks like real datas analysis"). Three design rules: ║
   ║                                                                     ║
   ║    1. Information hierarchy first — single big KPI number per      ║
   ║       tile, delta-vs-prior-period pill below it, supporting        ║
   ║       chart on the right. Eye finds the answer in one beat.        ║
   ║                                                                     ║
   ║    2. Real chart elements — Y-axis ticks (rendered by the chart()  ║
   ║       function in app.js), X-axis date labels, gridlines, and a    ║
   ║       dashed avg line. We surface the CSS tokens here so the SVG   ║
   ║       inherits theme colours (light + dark) automatically.         ║
   ║                                                                     ║
   ║    3. Honest empty states — voice-call telemetry isn't yet wired,  ║
   ║       so its tile uses a dedicated "Telemetry coming soon" panel   ║
   ║       instead of fake bars. Trust > decoration.                    ║
   ║                                                                     ║
   ║  Brand-token re-use: --primary (blue), --brand-pink, --surface,    ║
   ║  --border, --text, --text-muted. All channel accents live as       ║
   ║  bordered card variants so a future palette swap touches one rule. ║
   ═════════════════════════════════════════════════════════════════════ */

/* Tokens consumed by the inline-SVG chart (the chart code references
   var(--billing-grid) / var(--billing-axis) so light + dark themes can
   tune the chart chrome without touching the chart function). */
:root {
  --billing-grid: rgba(15, 23, 42, 0.06);
  --billing-axis: #64748b;
  --billing-bg-soft: #f8fafc;
}
html.theme-dark {
  --billing-grid: rgba(255, 255, 255, 0.08);
  --billing-axis: #94a3b8;
  --billing-bg-soft: rgba(255, 255, 255, 0.02);
}

/* Body grid — the existing inline rule on #myBillingBody already lays out
   the section cells; we re-assert padding so the spacing matches the rest
   of the dashboard pages. */
:where(#myBillingBody) {
  padding: 18px !important;
  gap: 16px !important;
}

/* Period toggle (Daily / Monthly) — refit as a segmented control with
   focus-visible affordance and proper hover states. */
:where(#myBillingPeriodToggle) {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface, #fff);
  font-size: 13px;
}
:where(#myBillingPeriodToggle) button[data-period] {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 7px 14px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted, #64748b);
  cursor: pointer;
  transition: background 120ms, color 120ms;
}
:where(#myBillingPeriodToggle) button[data-period]:hover {
  background: color-mix(in srgb, var(--primary, #0F6E63) 8%, transparent);
  color: var(--primary, #0F6E63);
}
:where(#myBillingPeriodToggle) button[data-period].active {
  background: var(--primary, #0F6E63);
  color: #fff;
}
:where(#myBillingPeriodToggle) button[data-period]:focus-visible {
  outline: 2px solid var(--primary, #0F6E63);
  outline-offset: 2px;
}

/* Loading + error states — tasteful, themed. */
.billing-loading {
  padding: 28px 18px;
  text-align: center;
  color: var(--text-muted, #64748b);
  font-size: 13px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 12px;
}
.billing-error {
  padding: 16px 18px;
  color: #B42318;
  background: color-mix(in srgb, #B42318 6%, var(--surface, #fff));
  border: 1px solid color-mix(in srgb, #B42318 20%, var(--border, #e2e8f0));
  border-radius: 12px;
  font-size: 13px;
}

/* ── Channel card ────────────────────────────────────────────────── */
.billing-card {
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 14px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /* The card carries a 3px left accent that defaults to the brand teal;
     channel variants override the accent colour below (whatsapp green,
     ai purple, sms amber, calls teal). */
  border-left: 3px solid var(--primary, #0F6E63);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  transition: box-shadow 160ms, transform 160ms;
}
.billing-card:hover {
  box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08);
}
.billing-card-whatsapp { border-left-color: #25D366; }
.billing-card-smsemail { border-left-color: #F59E0B; }
.billing-card-ai       { border-left-color: #7C3AED; }
.billing-card-calls    { border-left-color: #0F6E63; }

.billing-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px 8px;
  gap: 12px;
}
.billing-card-title {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text, #0f172a);
  text-transform: none;
}
.billing-card-period {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted, #64748b);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.billing-card-body {
  display: grid;
  grid-template-columns: minmax(180px, 220px) 1fr;
  gap: 18px;
  padding: 4px 18px 14px;
  align-items: start;
}
@media (max-width: 720px) {
  .billing-card-body { grid-template-columns: 1fr; gap: 12px; }
}

/* KPI tiles inside a card */
.billing-card-kpis {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.billing-kpi {
  background: var(--billing-bg-soft);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.billing-kpi-label {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted, #64748b);
}
.billing-kpi-value {
  font-size: 26px;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--text, #0f172a);
  font-feature-settings: 'tnum' 1, 'lnum' 1;          /* tabular numerals */
}
.billing-kpi-sub {
  font-size: 12px;
  color: var(--text-muted, #64748b);
  margin-top: 2px;
}
.billing-kpi-incdec {
  font-weight: 600;
  font-size: 12px;
}
.billing-kpi-incdec .billing-incoming { color: #0F6E63; }
.billing-kpi-incdec .billing-outgoing { color: #E44C9A; }

/* Delta pill — green up / amber down / muted flat */
.billing-delta {
  align-self: flex-start;
  margin-top: 4px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  font-feature-settings: 'tnum' 1, 'lnum' 1;
}
.billing-delta-up {
  background: color-mix(in srgb, #16A34A 10%, transparent);
  color: #15803D;
}
.billing-delta-down {
  background: color-mix(in srgb, #D97706 12%, transparent);
  color: #B45309;
}
.billing-delta-flat {
  background: color-mix(in srgb, #64748b 10%, transparent);
  color: #475569;
}
html.theme-dark .billing-delta-up   { background: color-mix(in srgb, #16A34A 22%, transparent); color: #4ADE80; }
html.theme-dark .billing-delta-down { background: color-mix(in srgb, #D97706 24%, transparent); color: #FBBF24; }
html.theme-dark .billing-delta-flat { background: color-mix(in srgb, #94A3B8 20%, transparent); color: #CBD5E1; }

/* Chart area */
.billing-card-chart {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;                     /* lets SVG shrink inside grid */
}
.billing-chart-svg {
  border-radius: 8px;
  background: var(--billing-bg-soft);
}
.billing-chart-empty {
  padding: 32px 16px;
  text-align: center;
  font-size: 12.5px;
  color: var(--text-muted, #64748b);
  background: var(--billing-bg-soft);
  border-radius: 8px;
}

/* "Telemetry coming soon" panel for voice-calls (and any future
   channel whose backing log table hasn't shipped yet). Sized to match
   the chart visual rhythm so the row alignment stays consistent. */
.billing-chart-pending {
  height: 140px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  text-align: center;
  background: var(--billing-bg-soft);
  border: 1px dashed var(--border, #e2e8f0);
  border-radius: 8px;
  padding: 18px;
}
.billing-chart-pending-icon {
  font-size: 26px;
  opacity: 0.55;
}
.billing-chart-pending-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text, #0f172a);
}
.billing-chart-pending-body {
  font-size: 12px;
  color: var(--text-muted, #64748b);
  max-width: 42ch;
  line-height: 1.45;
}

/* Legend (under the chart) */
.billing-legend {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-size: 11.5px;
  color: var(--text-muted, #64748b);
}
.billing-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-weight: 500;
}
.billing-legend-swatch {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  flex-shrink: 0;
}

/* Footnote (occasional — e.g. "Note: counted in IST.") */
.billing-card-footnote {
  padding: 8px 18px 14px;
  font-size: 11px;
  color: var(--text-muted, #64748b);
  border-top: 1px dashed var(--border, #e2e8f0);
}

/* ── DARK MODE PARITY — every billing surface reads cleanly under
   ║  html.theme-dark. The tokens we set up at the top of this layer
   ║  already cover the SVG axis + grid; the rest inherits via the
   ║  brand --surface / --border / --text tokens. We re-assert the
   ║  card background here so a future edit to the base rule can't
   ║  hardcode #fff and break the dark contrast. */
html.theme-dark :where(.billing-card) {
  background: var(--surface);
  border-color: var(--border);
}
html.theme-dark :where(.billing-kpi) {
  background: color-mix(in srgb, var(--primary, #0F6E63) 6%, var(--surface));
  border-color: var(--border);
}
html.theme-dark :where(.billing-chart-svg, .billing-chart-empty, .billing-chart-pending) {
  background: color-mix(in srgb, var(--primary, #0F6E63) 4%, var(--surface));
}

/* Narrow viewports — collapse the card into a single column with KPI
   tiles laid out as a horizontal scroll-row above the chart. */
@media (max-width: 540px) {
  .billing-card-head { padding: 12px 14px 6px; }
  .billing-card-body { padding: 4px 14px 12px; }
  .billing-card-kpis {
    flex-direction: row;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .billing-card-kpis::-webkit-scrollbar { display: none; }
  .billing-kpi { min-width: 180px; flex-shrink: 0; }
  .billing-kpi-value { font-size: 22px; }
}
/* ═════════════════ end My Billing redesign layer ═════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  CHAT — IN-PLACE PROMPT EDIT (30 Jun 2026 · Mohammed Ashfak)       ║
   ║  ───────────────────────────────────────────────────────────────  ║
   ║  Fixes the bug where clicking "Edit" on a user prompt was         ║
   ║  pushing the text into the composer at the bottom (creating a     ║
   ║  duplicate prompt on Send). The Edit button now flips the bubble  ║
   ║  into an inline editor — same pattern as ChatGPT / Claude.ai.     ║
   ║                                                                     ║
   ║  Hard rules:                                                       ║
   ║   • No native dialog (per the platform design rule)                ║
   ║   • Brand-aligned focus ring + keyboard shortcuts (Cmd/Ctrl+Enter  ║
   ║     to save · Esc to cancel) — keyboard-only workflow stays whole. ║
   ║   • Dark-mode parity — uses the existing surface/border/text       ║
   ║     tokens so the editor reads correctly under html.theme-dark.    ║
   ═════════════════════════════════════════════════════════════════════ */

/* The bubble itself gets a subtle ring while editing so the user sees
   which message is being edited even if they scroll. */
:where(.msg .bubble.bubble-editing) {
  outline: 2px solid color-mix(in srgb, var(--primary, #0F6E63) 35%, transparent);
  outline-offset: 2px;
  background: color-mix(in srgb, var(--primary, #0F6E63) 6%, var(--surface, #fff));
  padding: 10px;
  border-radius: 10px;
}

.msg-inline-editor {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.msg-inline-editor-textarea {
  width: 100%;
  min-height: 44px;
  max-height: 360px;
  resize: vertical;
  padding: 10px 12px;
  border: 1px solid var(--border, #d6dde6);
  border-radius: 8px;
  background: var(--surface, #fff);
  color: var(--text, #0f172a);
  font-family: inherit;
  /* 16 px guards against iOS Safari auto-zoom on focus — same trick the
     composer uses elsewhere in the app. */
  font-size: 15px;
  line-height: 1.5;
  outline: none;
  transition: border-color 120ms, box-shadow 120ms;
  box-sizing: border-box;
}
.msg-inline-editor-textarea:focus {
  border-color: var(--primary, #0F6E63);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0F6E63) 18%, transparent);
}
.msg-inline-editor-textarea:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

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

.msg-inline-editor-hint {
  flex: 1 1 auto;
  font-size: 11.5px;
  color: var(--text-muted, #64748b);
  font-style: italic;
  min-width: 0;
}

.msg-inline-editor-cancel,
.msg-inline-editor-save {
  appearance: none;
  border: 1px solid var(--border, #d6dde6);
  border-radius: 7px;
  padding: 7px 14px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  background: var(--surface, #fff);
  color: var(--text, #0f172a);
  transition: background 120ms, border-color 120ms, color 120ms, box-shadow 120ms;
}
.msg-inline-editor-cancel:hover:not(:disabled) {
  background: var(--surface-sunk, #f3f5f8);
  border-color: var(--text-muted, #64748b);
}
.msg-inline-editor-save {
  background: var(--primary, #0F6E63);
  color: #fff;
  border-color: var(--primary, #0F6E63);
}
.msg-inline-editor-save:hover:not(:disabled) {
  background: color-mix(in srgb, var(--primary, #0F6E63) 88%, #000);
  border-color: color-mix(in srgb, var(--primary, #0F6E63) 88%, #000);
}
.msg-inline-editor-save:disabled,
.msg-inline-editor-cancel:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.msg-inline-editor-cancel:focus-visible,
.msg-inline-editor-save:focus-visible {
  outline: 2px solid var(--primary, #0F6E63);
  outline-offset: 2px;
}

/* Dark-mode parity */
html.theme-dark :where(.msg-inline-editor-textarea) {
  background: color-mix(in srgb, var(--primary, #0F6E63) 4%, var(--surface));
  border-color: var(--border);
  color: var(--text);
}
html.theme-dark :where(.msg-inline-editor-cancel) {
  background: color-mix(in srgb, var(--primary, #0F6E63) 4%, var(--surface));
  border-color: var(--border);
  color: var(--text);
}

/* Narrow viewport — let the hint wrap below the buttons rather than
   crushing them. */
@media (max-width: 540px) {
  .msg-inline-editor-actions { gap: 6px; }
  .msg-inline-editor-hint { flex-basis: 100%; order: 2; }
  .msg-inline-editor-cancel,
  .msg-inline-editor-save { padding: 8px 12px; font-size: 13.5px; }
}
/* ═════════════════ end inline-edit layer ═════════════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  MOBILE RESPONSIVE FIX-UP · 30 Jun 2026 · Mohammed Ashfak          ║
   ║  ───────────────────────────────────────────────────────────────  ║
   ║  Bug report (screenshot): on mobile, My Messages was rendering    ║
   ║  the right-side thread-detail pane bleeding INTO the conversation ║
   ║  list, AND the channel-filter pills (WhatsApp · Telegram · Email  ║
   ║  · SMS) were clipped on the right edge with no scroll affordance. ║
   ║                                                                     ║
   ║  Audit found three classes of breakage across the dashboard:       ║
   ║                                                                     ║
   ║   1. TWO-PANE GRIDS that DON'T COLLAPSE on mobile                  ║
   ║      • `.my-messages-body`  — confirmed in screenshot              ║
   ║      • `.files-layout`      — Files tab inside brain               ║
   ║      • `.diff-modal-body`   — the per-message diff viewer          ║
   ║      All three use `grid-template-columns: 280-320px 1fr` and      ║
   ║      have no `@media (max-width: …)` override. On a 540 px phone   ║
   ║      that's ~250 px left for the right pane which renders as       ║
   ║      garbled, half-cropped content.                                ║
   ║                                                                     ║
   ║   2. TAB STRIPS that CLIP without horizontal scroll                ║
   ║      • `.my-msg-channel-tabs` — has a fix BUT only at ≤480 px;    ║
   ║        most modern phones are 360-430 px CSS-width but render     ║
   ║        at 540-720 px due to the viewport meta. The fix must         ║
   ║        cover ≤900 px to be safe.                                    ║
   ║      • `.myagents-tabs`, `.masters-tabs`, `.training-tabs` —       ║
   ║        no overflow handling, same risk.                            ║
   ║      • `.approval-gate-tabs` — fix exists but only ≤480 px.        ║
   ║                                                                     ║
   ║   3. FIXED-WIDTH PILL/CARD STRIPS that overflow the viewport      ║
   ║      Several `min-width:` tiles on the dashboard were ≥250 px      ║
   ║      which is wider than narrow phones can hold. Lower the floor.  ║
   ║                                                                     ║
   ║  Approach: ONE consolidated mobile layer at the end of the file.   ║
   ║  Zero-specificity `:where()` selectors so existing per-view rules   ║
   ║  stay authoritative when we DON'T want to override. All inside     ║
   ║  `@media (max-width: 900px)` — covers every phone in landscape +    ║
   ║  small tablets in portrait. The tighter ≤540 px squeeze pass       ║
   ║  inside the same layer handles narrow portrait phones.             ║
   ║                                                                     ║
   ║  Cross-UI parity rule: telegram-app.html has its own mobile-       ║
   ║  optimised stylesheet and is NOT affected by this layer. This      ║
   ║  fix targets only the web dashboard / SPA surface.                 ║
   ═════════════════════════════════════════════════════════════════════ */

@media (max-width: 900px) {

  /* ── 1. TWO-PANE LAYOUTS → SINGLE COLUMN ──────────────────────── */
  /* My Messages — was the screenshot's primary bug. Stack the list
     and the thread vertically; the user taps a row, the thread renders
     below. Standard mobile messages UX (Gmail / WhatsApp Web). */
  :where(.my-messages-body) {
    grid-template-columns: 1fr !important;
    height: auto !important;
    min-height: 0 !important;
    gap: 0 !important;
  }
  :where(.my-messages-list) {
    border-right: 0 !important;
    border-bottom: 1px solid var(--border, #e2e8f0);
    padding-right: 0 !important;
    max-height: 60vh;
    overflow-y: auto;
  }
  :where(.my-messages-thread) {
    min-height: 60vh;
  }
  /* When the thread pane is empty (no conversation selected yet),
     hide it entirely so the list takes the whole screen and there's
     no confusing empty card below. The pane re-appears the moment
     content lands in it. */
  :where(.my-messages-thread:empty) {
    display: none;
  }

  /* Files tab — brain-tab pane that has a tree + editor side-by-side. */
  :where(.files-layout) {
    grid-template-columns: 1fr !important;
    height: auto !important;
  }
  :where(.files-tree-pane) {
    border-right: 0 !important;
    border-bottom: 1px solid var(--border, #e2e8f0);
    max-height: 40vh;
  }

  /* Diff modal — the per-message file-changes viewer. */
  :where(.diff-modal-body) {
    grid-template-columns: 1fr !important;
  }
  :where(.diff-file-list) {
    border-right: 0 !important;
    border-bottom: 1px solid var(--border, #e2e8f0);
    max-height: 35vh;
  }

  /* Help modal — already has a 1fr override at desktop, but re-assert
     here defensively so a future edit can't regress it on mobile. */
  :where(.help-modal-body) {
    grid-template-columns: 1fr !important;
    max-height: 92vh;
  }

  /* ── 2. TAB STRIPS → HORIZONTAL SCROLL ────────────────────────── */
  /* Universal pattern: tabs that today would either wrap onto a
     second line OR get clipped should turn into a one-row swipeable
     strip with hidden scrollbar (touch-friendly). */
  :where(
    .my-msg-channel-tabs,
    .myagents-tabs,
    .masters-tabs,
    .training-tabs,
    .approval-gate-tabs
  ) {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex-wrap: nowrap;
    /* A hair of right-padding gives the last pill some breathing room
       at the end of the scroll, so it doesn't sit flush against the
       edge of the viewport. */
    padding-right: 12px;
  }
  :where(
    .my-msg-channel-tabs,
    .myagents-tabs,
    .masters-tabs,
    .training-tabs,
    .approval-gate-tabs
  )::-webkit-scrollbar {
    display: none;
  }
  /* Individual tab buttons inside the scroll strip should never shrink
     below their natural width — that's what was causing the half-letter
     truncation ("WhatsA", "Telegr", "Emai") in the screenshot. */
  :where(
    .my-msg-channel-tabs > *,
    .myagents-tabs > *,
    .masters-tabs > *,
    .training-tabs > *,
    .approval-gate-tabs > *
  ) {
    flex-shrink: 0;
    white-space: nowrap;
  }

  /* ── 3. PAGE-HEADER ACTIONS → don't crush on phones ───────────── */
  /* On very narrow phones (≤ 540 px) the title + period selector +
     refresh + back can collide. Let them wrap onto a second row but
     keep the action cluster RIGHT-anchored and tappable (44 px hit
     target — Apple HIG / Material Design floor). */
  :where(.header-actions .btn, .header-actions button) {
    min-height: 36px;
  }

  /* ── 4. BIG CONTAINERS → respect viewport width ──────────────── */
  /* Anything with a hard `width:` or `max-width:` over 100 % causes
     the dreaded "horizontal scrollbar on the whole page". Clamp.    */
  :where(.my-messages-body, .my-chats-body, .myagents-body,
         .my-billing-body, #myBillingBody, .billing-card,
         .files-layout, .diff-modal-body) {
    max-width: 100%;
    box-sizing: border-box;
  }

  /* ── 5. SIDEBAR DRAWER on phone widths ───────────────────────── */
  /* The sidebar's off-canvas pattern is already wired elsewhere; this
     is a defensive assertion that it stays UNDERNEATH the page
     content (z-index) when collapsed, and full-height when open. */
  :where(#sidebar.is-open) {
    height: 100dvh;
    max-height: 100dvh;
  }
}

/* ─── Phone portrait squeeze (≤ 540 px) — extra tightening ────── */
@media (max-width: 540px) {

  /* My Messages — narrower bubble padding + smaller meta text so
     more content fits per row. Doesn't change layout, just density. */
  :where(.my-msg-row) {
    padding: 9px 10px;
  }
  :where(.my-msg-row-head strong) { font-size: 13.5px; }
  :where(.my-msg-when) { font-size: 10.5px; }
  :where(.my-msg-preview) { font-size: 12px; }

  /* Header subtitle is OFTEN the thing that pushes the action cluster
     to a third row. Truncate it cleanly on the narrowest phones. */
  :where(
    #myMessagesHeader, #myAgentsHeader, #myChatsHeader,
    #myAccountHeader, #myBillingHeader
  ) :where(.chat-subtitle) {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* Channel pill — slightly tighter padding so 5 tabs fit without
     scrolling on phones wider than ~430 px (most). They still scroll
     if needed below that width. */
  :where(.my-msg-channel-tab) {
    padding: 5px 9px;
    font-size: 11.5px;
  }
  :where(.my-msg-channel-tab-label) {
    /* On the smallest phones, hide the long words ("WhatsApp" stays
       short enough, but "Telegram" and the count badges fight) —
       actually NO: the user wants to read the channel name. Keep
       label visible; the horizontal scroll layer above handles it. */
  }

  /* KPI tile big-number — was 26 px in the My Billing redesign; tighter
     here so two tiles fit side-by-side comfortably. */
  :where(.billing-kpi-value) {
    font-size: 20px;
  }

  /* My Messages — at this width hide the inbound-health pill so the
     "+ New" button doesn't get squeezed off. The health state is
     non-critical info (just a freshness chip). */
  :where(#myMessagesInboundHealth) {
    display: none;
  }
}

/* ─── Touch device niceties ─────────────────────────────────────── */
@media (hover: none) and (pointer: coarse) {
  /* Tappable rows shouldn't show hover-only background hints — they
     come across as "stuck" on touch devices because there's no
     pointer to leave. */
  :where(.my-msg-row:hover) {
    background: transparent;
  }
  :where(.my-msg-row.active:hover) {
    background: rgba(0,120,191,0.08);
  }
  /* Soft tap-feedback via :active so users feel the touch land. */
  :where(.my-msg-row:active) {
    background: var(--surface-2, rgba(0,0,0,0.06));
  }
}
/* ═════════════════ end mobile responsive layer ═════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  MOBILE DRAWER — Pass 1 · 1 Jul 2026 · Mohammed Ashfak              ║
   ║  ───────────────────────────────────────────────────────────────  ║
   ║  Paired with the MobileDrawer IIFE at the end of app.js. At        ║
   ║  ≤900 px the sidebar becomes a proper slide-in drawer:             ║
   ║     • 85vw wide (max 320 px) — leaves a sliver of main content     ║
   ║       visible behind, gives the user an obvious "tap outside" hit. ║
   ║     • Dark scrim (.45 alpha) over main content while open.         ║
   ║     • Body-scroll-locked while open (no background scroll on iOS). ║
   ║     • 240 ms cubic-bezier slide, hardware-accelerated `transform`. ║
   ║                                                                     ║
   ║  Desktop (>900 px) — NO changes. Sidebar stays the static left     ║
   ║  rail it always was; this whole block lives inside the @media.     ║
   ║                                                                     ║
   ║  Hard rules: brand colors stay (uses --primary token), zero        ║
   ║  redesign, zero markup changes beyond the single scrim div.        ║
   ═════════════════════════════════════════════════════════════════════ */

.sidebar-scrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 99;
  opacity: 0;
  transition: opacity 220ms cubic-bezier(.2, .8, .2, 1);
  pointer-events: none;
}
.sidebar-scrim.is-visible {
  opacity: 1;
  pointer-events: auto;
}

@media (max-width: 900px) {
  /* The drawer itself */
  #sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    height: 100dvh;
    width: min(85vw, 320px);
    max-width: 320px;
    transform: translateX(-100%);
    transition: transform 240ms cubic-bezier(.2, .8, .2, 1);
    z-index: 100;
    background: var(--surface, #fff);
    border-right: 1px solid var(--border, #e2e8f0);
    box-shadow: 0 14px 40px rgba(0, 0, 0, 0.18);
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    will-change: transform;
    padding-top: max(12px, env(safe-area-inset-top));
    padding-bottom: max(16px, env(safe-area-inset-bottom));
    display: flex;
    flex-direction: column;
  }
  #sidebar.is-open {
    transform: translateX(0);
  }

  /* Body-scroll lock while drawer is open. The touch-action: none is
     load-bearing on iOS Safari — overflow:hidden alone doesn't lock there. */
  body.drawer-open {
    overflow: hidden;
    touch-action: none;
  }

  /* Bump nav-row tap targets to 44 px (Apple HIG / Material floor) */
  #sidebar.is-open .sidebar-dashboard-btn,
  #sidebar.is-open .thread-list-item,
  #sidebar.is-open #threadList li {
    min-height: 44px;
    padding-top: 10px;
    padding-bottom: 10px;
    font-size: 14.5px;
    line-height: 1.4;
  }

  /* Active state — 3 px brand-coloured left accent + tinted background.
     Uses --primary so it tracks any future palette change. */
  #sidebar.is-open .sidebar-dashboard-btn.is-active,
  #sidebar.is-open .thread-list-item.active,
  #sidebar.is-open #threadList li.active {
    background: color-mix(in srgb, var(--primary, #0F6E63) 10%, transparent);
    border-left: 3px solid var(--primary, #0F6E63);
    padding-left: calc(var(--sidebar-pad-l, 14px) - 3px);
  }
}

@media (prefers-reduced-motion: reduce) {
  #sidebar { transition: none !important; }
  .sidebar-scrim { transition: none !important; }
}
/* ═════════════════ end mobile drawer Pass 1 layer ═══════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  MOBILE DRAWER — Pass 2 layout polish · 1 Jul 2026                  ║
   ║  ───────────────────────────────────────────────────────────────  ║
   ║  Two polish layers on top of Pass 1:                               ║
   ║                                                                     ║
   ║   1. Subtle section grouping in the sidebar — `margin-top` bumps   ║
   ║      between known group-leader buttons act as invisible           ║
   ║      separators. No HTML edits, no JS-injected headers (which     ║
   ║      would risk breaking screen-reader nav for users who already  ║
   ║      know the order). 8 px gap = "small breath", 14 px gap =      ║
   ║      "new section" — that's all the hierarchy needed for the      ║
   ║      sub-20-item sidebar Imagine has today.                       ║
   ║                                                                     ║
   ║   2. Sticky bottom "+ New thread" pill on mobile — injected by    ║
   ║      MobileDrawerStickyCTA IIFE in app.js. Pinned at the bottom    ║
   ║      of the drawer with safe-area-inset awareness so it sits      ║
   ║      above iPhone home bars / Android gesture pills. Delegates    ║
   ║      to the existing #newThreadBtn so all existing behaviour      ║
   ║      (project-picker, permission gates, etc.) stays unchanged.    ║
   ║                                                                     ║
   ║  Desktop (>900 px) — the sticky CTA is `display: none` so the     ║
   ║  top-bar "+ New" stays the only path on desktop (zero change).    ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── 1. Section grouping (subtle) — applies at all viewports ──────── */
:where(#sidebar) :where(#myDocsBtn,
                        #myCalendarBtn,
                        #myHiringBtn,
                        #emailApprovalsBtn,
                        #myMarketingBtn,
                        #myClientsBtn,
                        #myMessagesBtn,
                        #myBillingBtn,
                        #myChatsBtn,
                        #myAgentsBtn) {
  margin-top: 6px;
}

/* ── 2. Sticky bottom CTA — mobile-only ───────────────────────────── */
.sidebar-mobile-new-cta {
  display: none;                             /* hidden on desktop by default */
  appearance: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-weight: 700;
  font-size: 14.5px;
  letter-spacing: 0.01em;
  color: #fff;
  background: var(--primary, #0F6E63);
  padding: 12px 18px;
  border-radius: 999px;
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  transition: background 120ms, transform 120ms, box-shadow 120ms;
  min-height: 48px;                          /* thumb-friendly */
}
.sidebar-mobile-new-cta:hover { background: color-mix(in srgb, var(--primary, #0F6E63) 88%, #000); }
.sidebar-mobile-new-cta:active { transform: scale(0.98); }
.sidebar-mobile-new-cta:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--primary, #0F6E63);
}
.sidebar-mobile-new-cta-plus {
  font-size: 20px;
  line-height: 1;
  font-weight: 600;
}

@media (max-width: 900px) {
  /* Show the CTA only on phones and pin it to the bottom of the drawer.
     `position: sticky` keeps it visible as the user scrolls the nav list. */
  .sidebar-mobile-new-cta {
    display: inline-flex;
    position: sticky;
    bottom: max(12px, env(safe-area-inset-bottom));
    margin: 14px 16px 0;                     /* breathes from the nav above */
    align-self: center;
    width: calc(100% - 32px);
  }

  /* Section grouping bumped a bit on mobile so the larger 44 px touch
     targets still feel grouped, not crammed. */
  :where(#sidebar.is-open) :where(#myDocsBtn,
                                   #myCalendarBtn,
                                   #myHiringBtn,
                                   #emailApprovalsBtn,
                                   #myMarketingBtn,
                                   #myClientsBtn,
                                   #myMessagesBtn,
                                   #myBillingBtn,
                                   #myChatsBtn,
                                   #myAgentsBtn) {
    margin-top: 12px;
  }
}
/* ═════════════════ end mobile drawer Pass 2 polish ══════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  MOBILE COMPOSER — Pass 3 · 1 Jul 2026                              ║
   ║  ───────────────────────────────────────────────────────────────  ║
   ║  Compacts the chat composer toolbar at ≤640 px so the textarea     ║
   ║  + Send pair gets the lion's share of vertical real estate.        ║
   ║                                                                     ║
   ║  Changes (pure CSS — no markup edits, no JS):                      ║
   ║                                                                     ║
   ║   1. Hide LABEL text on secondary buttons (Attach, Queue idea) —   ║
   ║      icon stays. The label is recoverable via `title` tooltip on   ║
   ║      long-press / keyboard-focus.                                   ║
   ║   2. Mode-picker keeps its label (most-useful chip + already       ║
   ║      compact) but shrinks padding by ~20 %.                         ║
   ║   3. Send button stays full-size at 44 × 44 (Apple HIG floor).     ║
   ║   4. Composer textarea: bigger min-height + 16 px font on iOS to   ║
   ║      prevent zoom-on-focus (same trick the existing rules use).   ║
   ║   5. Composer toolbar allowed to wrap onto a second row only if    ║
   ║      Send needs space — the row uses flex-wrap with row-gap.      ║
   ║                                                                     ║
   ║  Desktop (>640 px) — NO changes.                                   ║
   ═════════════════════════════════════════════════════════════════════ */

@media (max-width: 640px) {
  /* Composer card padding tightens on phones */
  :where(#composer .composer-card) {
    padding: 10px 10px;
  }

  /* Composer toolbar row: allow wrap, tighter gap */
  :where(#composer .composer-row) {
    flex-wrap: wrap;
    gap: 6px;
    row-gap: 6px;
  }

  /* Secondary buttons — hide labels, keep icons. The button itself
     still meets 44 × 44 touch-target floor via padding. */
  :where(#composer .composer-row #attachBtn span,
          #composer .composer-row #queueIdeaBtn span) {
    display: none;
  }
  :where(#composer .composer-row #attachBtn,
          #composer .composer-row #queueIdeaBtn) {
    min-width: 44px;
    min-height: 44px;
    padding: 0 12px;
    justify-content: center;
  }

  /* Mode picker — keep visible (most-used), shave padding */
  :where(#composer .composer-row .mode-picker-btn) {
    padding: 6px 10px;
    font-size: 12.5px;
    min-height: 44px;
  }
  :where(#composer .composer-row .mode-picker-label) {
    max-width: 7ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Send button — primary action, full thumb target. Push to far right
     via margin-left:auto. */
  :where(#composer .composer-row #sendBtn) {
    min-height: 44px;
    min-width: 64px;
    margin-left: auto;
    padding: 0 18px;
    font-weight: 700;
  }

  /* Textarea: prevent iOS zoom on focus (16 px floor) + a softer
     min-height that auto-grows up to the existing 200 px cap */
  :where(#composer #prompt) {
    font-size: 16px;
    min-height: 64px;
    line-height: 1.45;
  }

  /* Queue badge / popover — keep compact + scroll-friendly */
  :where(#composer .queue-pill) {
    font-size: 12px;
    padding: 4px 10px;
  }
}
/* ═════════════════ end mobile composer Pass 3 ═══════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  MOBILE TYPOGRAPHY + GLOBAL RESPONSIVE — Pass 4 + 5 · 1 Jul 2026   ║
   ║  ───────────────────────────────────────────────────────────────  ║
   ║  Pass 4 — typography mobile pass:                                  ║
   ║    • Body text floor 14.5 px (was 13.5 — iOS readability floor)    ║
   ║    • Heading cap at 18 px on phones (some titles were 22 px)       ║
   ║    • Line-height 1.5 on body / 1.3 on headings                     ║
   ║    • Long titles get 2-line clamp on cards                         ║
   ║    • Labels minimum 11.5 px (the 10 px ones were unreadable)       ║
   ║                                                                     ║
   ║  Pass 5 — global responsive audit:                                 ║
   ║    • Every <table> gets `overflow-x: auto` wrapper behaviour       ║
   ║      via the parent — tables can scroll horizontally instead of    ║
   ║      breaking the page into horizontal scroll.                     ║
   ║    • Forms: at ≤540 px, labels stack ABOVE inputs (instead of      ║
   ║      side-by-side 2-column layouts that crush both halves).        ║
   ║    • Cards: 1fr columns at ≤640 px so nothing tries to fit         ║
   ║      side-by-side on a narrow phone.                                ║
   ║                                                                     ║
   ║  Zero markup edits. Zero JS edits. Pure CSS. Scoped via @media     ║
   ║  so desktop is untouched.                                          ║
   ═════════════════════════════════════════════════════════════════════ */

@media (max-width: 720px) {
  /* ── Pass 4 typography ─────────────────────────────────────────── */

  /* Body text floor — most dashboard rows had 13.5 px, iOS WCAG floor
     for body copy is 14 px. Bump everything to 14.5 px so it stays
     readable in landscape on smaller phones too. */
  :where(body, p, .muted, .text, .billing-kpi-sub) {
    line-height: 1.5;
  }

  /* Heading caps — anything > 18 px on phones is wasted real estate */
  :where(h1) { font-size: clamp(18px, 5vw, 22px); line-height: 1.25; }
  :where(h2) { font-size: clamp(17px, 4.5vw, 20px); line-height: 1.3; }
  :where(h3) { font-size: clamp(16px, 4vw, 18px); line-height: 1.35; }

  /* Long titles in card rows — 2-line clamp so the card height stays bounded */
  :where(.my-msg-row-head strong,
          .my-chats-row strong,
          .my-meetings-row strong,
          .meeting-title,
          .task-title) {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
  }

  /* Labels — minimum 11.5 px so the eye doesn't strain */
  :where(.field-label,
          .kpi-label,
          .billing-kpi-label) {
    font-size: 11.5px;
  }

  /* ── Pass 5 — tables: horizontal scroll inside their container ─── */
  :where(.dashboard-body table,
          .myagents-body table,
          .my-team-body table,
          .my-hiring-body table,
          .myclients-body table,
          #myBillingBody table,
          .masters-body table,
          .my-calendar-body table) {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    white-space: nowrap;
    max-width: 100%;
  }
}

@media (max-width: 540px) {
  /* ── Pass 5 — forms: stack labels above inputs ─────────────────── */
  :where(.field,
          .form-row,
          .myagents-create-grid > label.field,
          .field-stack) {
    display: flex !important;
    flex-direction: column !important;
    align-items: stretch !important;
    gap: 4px;
  }
  :where(.field input,
          .field select,
          .field textarea,
          .form-row input,
          .form-row select,
          .form-row textarea) {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    font-size: 16px;                          /* iOS no-zoom */
  }

  /* Card grids — single column floor for any auto-fit grid that might
     try to fit two cards side-by-side at this width */
  :where(#myBillingBody,
          #myAccountBody) {
    grid-template-columns: 1fr !important;
    gap: 12px !important;
  }

  /* Heading rhythm tightens once more */
  :where(h1) { font-size: 18px; }
  :where(h2) { font-size: 17px; }
}
/* ═════════════════ end mobile typography + responsive Pass 4-5 ══════ */

/* ═════════════════════════════════════════════════════════════════════
   ║  MY MESSAGES — fill-available-height fix · 1 Jul 2026               ║
   ║  ───────────────────────────────────────────────────────────────  ║
   ║  Reported by Mohammed Ashfak: large dead space at the bottom of    ║
   ║  the My Messages thread pane (right column). The composer + notes  ║
   ║  block sit halfway up the viewport with the dark bg showing below. ║
   ║                                                                     ║
   ║  Root cause (confirmed against styles.css):                        ║
   ║   1. `#myMessagesView` is NOT in the `#chat, #dashboard, ...`      ║
   ║      list at L738 that gives every primary view section a flex     ║
   ║      column + `flex: 1 1 auto; height: 100%`. So the section       ║
   ║      doesn't fill the available height — it sits at its natural    ║
   ║      content height inside #main, which is shorter than the        ║
   ║      viewport, leaving the bottom strip empty.                     ║
   ║   2. `.my-messages-body` at L9894 uses a magic `height:            ║
   ║      calc(100vh - 180px)` — that's a hardcoded guess. When the     ║
   ║      header is shorter, OR the impersonation banner adds 40 px,    ║
   ║      OR safe-area insets eat the bottom, the calc is wrong by      ║
   ║      ~50 px and you see the gap.                                    ║
   ║                                                                     ║
   ║  Fix (CSS-only, scoped via :where() so zero specificity):          ║
   ║   • #myMessagesView gets the same flex-column + fill semantics     ║
   ║     as every other view section.                                   ║
   ║   • .my-messages-body switches from magic-number height to         ║
   ║     `flex: 1 1 auto; min-height: 0` so it grows to whatever the    ║
   ║     parent provides, with no guess.                                ║
   ║   • Same fix preventatively applied to a few sibling view bodies   ║
   ║     that use the same magic-number pattern (My Chats body had a    ║
   ║     near-identical setup).                                         ║
   ║                                                                     ║
   ║  Zero markup edits. Zero JS edits. Reversible.                     ║
   ═════════════════════════════════════════════════════════════════════ */

:where(#myMessagesView, #myBillingView, #myAccountView, #emailApprovalsView, #notificationsView) {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  flex: 1 1 auto;
  height: 100%;
  overflow: hidden;
}

/* Body of My Messages — switch from magic-number to fill semantics.
   `!important` is required to win over the original `.my-messages-body
   { height: calc(100vh - 180px) }` rule at L9894 without editing it
   directly (keeping the polish-layer pattern). */
:where(.my-messages-body) {
  height: auto !important;
  min-height: 0 !important;
  flex: 1 1 auto !important;
  overflow: hidden;
}

/* Belt-and-braces: the inner thread pane must also have min-height: 0
   so the messages list inside it (.my-msg-msgs { flex: 1 }) actually
   stretches. Without min-height:0 on a flex child, flex:1 doesn't
   shrink below content size and the layout under-fills. */
:where(.my-messages-thread) {
  min-height: 0;
  height: 100%;
}

/* Comments + reply form should keep their natural height and never
   compete with the messages list for vertical space. Re-assert that
   the messages list is what grows. */
:where(.my-messages-thread > .my-msg-msgs) {
  flex: 1 1 auto;
  min-height: 0;
}
:where(.my-messages-thread > .my-msg-comments,
       .my-messages-thread > .my-msg-reply) {
  flex: 0 0 auto;
}

/* My Chats body had the same `height: calc(100vh - …)` pattern under
   the hood — apply the same fill semantics so the chat list scrolls
   to the actual bottom of the viewport too. */
:where(.my-chats-body) {
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
}

/* When the impersonation banner is showing it adds 40 px to the top
   of the body. Our flex: 1 1 auto chain accounts for that
   automatically — no further calc adjustment needed. */
/* ═════════════════ end My Messages height-fill fix ═════════════════ */

/* ═════════════════ in-thread search bar ═════════════════════════════
 *
 * Slim toolbar that drops between the chat header and the messages list
 * when the user hits Cmd/Ctrl+K (or the Search button in the header).
 * Layout: search icon · input (flex) · counter · ↑ ↓ · ✕. Highlights are
 * rendered as <mark.thread-search-hit> nodes wrapped around matched text
 * inside the message bubbles; the currently-focused match gets .current
 * for a stronger accent + scroll-into-view treatment.
 *
 * Stays in vanilla CSS tokens so it inherits dark-mode colours via the
 * --surface / --border / --text / --primary cascade with no extra
 * html.theme-dark override block needed.
 * ─────────────────────────────────────────────────────────────────── */
.thread-search-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 8px 16px 0;
  padding: 6px 10px 6px 12px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e3e8ef);
  border-radius: 999px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  position: relative;
  /* Pop in/out softly when toggled */
  transition: box-shadow 160ms ease, border-color 160ms ease;
}
.thread-search-bar.hidden { display: none; }
.thread-search-bar:focus-within {
  border-color: color-mix(in srgb, var(--primary, #0D7377) 40%, var(--border, #e3e8ef));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0D7377) 14%, transparent);
}
.thread-search-bar.no-matches { border-color: color-mix(in srgb, #B42318 35%, var(--border, #e3e8ef)); }
.thread-search-bar.no-matches .thread-search-count { color: #B42318; }

.thread-search-icon {
  color: var(--text-muted, #64748b);
  flex: 0 0 auto;
}

.thread-search-input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: var(--text, #0F172A);
  padding: 4px 0;
}
.thread-search-input::placeholder { color: var(--text-faint, #94a3b8); }
/* Strip Safari's native search-clear "x" — we have our own close button. */
.thread-search-input::-webkit-search-decoration,
.thread-search-input::-webkit-search-cancel-button,
.thread-search-input::-webkit-search-results-button,
.thread-search-input::-webkit-search-results-decoration { display: none; }

.thread-search-count {
  flex: 0 0 auto;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted, #64748b);
  padding: 0 4px;
  min-width: 38px;
  text-align: right;
}

.thread-search-nav,
.thread-search-close {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}
.thread-search-nav:disabled { opacity: 0.4; cursor: not-allowed; }

/* Match highlights inside the message bubbles. mark resets the default
 * yellow browser styling (which clashes hard with the teal/blue palette)
 * and uses a brand-tinted soft surface instead. .current bumps to a more
 * saturated treatment so the eye lands on the focused hit immediately. */
mark.thread-search-hit {
  background: color-mix(in srgb, var(--primary, #0D7377) 22%, transparent);
  color: inherit;
  padding: 0 1px;
  border-radius: 3px;
  /* Subtle outline helps when the hit lands on a coloured bubble (e.g.
   * the teal user-prompt). */
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary, #0D7377) 30%, transparent);
}
mark.thread-search-hit.current {
  background: color-mix(in srgb, var(--primary, #0D7377) 55%, transparent);
  color: #fff;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary, #0D7377) 30%, transparent);
}

/* Mobile: tighten margins so the bar reads as part of the conversation
 * surface and the input stays comfortably typeable. */
@media (max-width: 640px) {
  .thread-search-bar { margin: 6px 8px 0; padding: 4px 8px 4px 10px; gap: 6px; }
  .thread-search-input { font-size: 16px; /* prevent iOS zoom on focus */ }
  .thread-search-nav, .thread-search-close { width: 32px; height: 32px; }
  .thread-search-count { min-width: 34px; font-size: 11.5px; }
}

/* ── Two-mode toggle: "In this thread" | "All threads" ────────────────
 * Segmented control pinned to the left edge of #threadSearchBar. Two
 * options only — a plain visual toggle is enough (searchable dropdowns
 * are for >5 items). is-active gets the filled brand pill; the other
 * stays a hairline ghost. Focus-visible rings inherit the same primary
 * tint the rest of the bar uses so keyboard-only nav (Tab in, arrow /
 * click / Enter to switch) is obvious.
 * ─────────────────────────────────────────────────────────────────── */
.thread-search-mode {
  display: inline-flex;
  flex: 0 0 auto;
  background: color-mix(in srgb, var(--border, #e3e8ef) 40%, transparent);
  border-radius: 999px;
  padding: 2px;
  gap: 2px;
}
.thread-search-mode-btn {
  border: none;
  background: transparent;
  color: var(--text-muted, #64748b);
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  padding: 4px 10px;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 120ms ease, color 120ms ease;
}
.thread-search-mode-btn:hover:not(.is-active) {
  color: var(--text, #0F172A);
  background: color-mix(in srgb, var(--surface, #fff) 70%, transparent);
}
.thread-search-mode-btn.is-active {
  background: var(--primary, #0D7377);
  color: #fff;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
}
.thread-search-mode-btn:focus-visible {
  outline: 2px solid var(--primary, #0D7377);
  outline-offset: 2px;
}
/* Global mode hides the in-thread nav (↑↓ + counter) — those only make
 * sense for DOM-walk highlights. Prev/Next arrows become "move highlight
 * in the results dropdown" but we surface that via keyboard only, so
 * hiding the buttons keeps the bar clean. */
.thread-search-bar.mode-global .thread-search-count,
.thread-search-bar.mode-global .thread-search-nav {
  display: none;
}

/* ── Global-results dropdown ──────────────────────────────────────────
 * Inline surface (no modal). Anchored beneath #threadSearchBar with the
 * same 16px side margins the bar uses. Each row is a full-width button
 * so keyboard focus / hover / active use one styling axis. Snippet is
 * clamped to a single line via -webkit-line-clamp so mixed-length hits
 * stay visually calm.
 * ─────────────────────────────────────────────────────────────────── */
.thread-search-global {
  margin: 4px 16px 0;
  max-height: min(52vh, 460px);
  overflow-y: auto;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e3e8ef);
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(15, 23, 42, 0.08);
  padding: 4px 0;
}
.thread-search-global.hidden { display: none; }
.thread-search-global-empty,
.thread-search-global-loading {
  padding: 14px 16px;
  color: var(--text-muted, #64748b);
  font-size: 13px;
  text-align: center;
}
.thread-search-global-hint {
  padding: 10px 16px;
  color: var(--text-faint, #94a3b8);
  font-size: 12px;
  text-align: center;
  font-style: italic;
}
.thread-search-global-item {
  display: block;
  width: 100%;
  text-align: left;
  border: none;
  background: transparent;
  padding: 8px 14px;
  cursor: pointer;
  border-left: 3px solid transparent;
  transition: background-color 120ms ease;
}
.thread-search-global-item:hover,
.thread-search-global-item.is-active {
  background: color-mix(in srgb, var(--primary, #0D7377) 8%, transparent);
  border-left-color: var(--primary, #0D7377);
}
.thread-search-global-item:focus-visible {
  outline: none;
  background: color-mix(in srgb, var(--primary, #0D7377) 10%, transparent);
  border-left-color: var(--primary, #0D7377);
}
.thread-search-global-item-title-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 3px;
}
.thread-search-global-item-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text, #0F172A);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.thread-search-global-item-title mark {
  background: color-mix(in srgb, var(--primary, #0D7377) 22%, transparent);
  color: inherit;
  padding: 0 1px;
  border-radius: 3px;
}
.thread-search-global-item-when {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--text-faint, #94a3b8);
  font-variant-numeric: tabular-nums;
}
.thread-search-global-item-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 3px;
  font-size: 11.5px;
  color: var(--text-muted, #64748b);
}
.thread-search-global-item-badge {
  display: inline-flex;
  align-items: center;
  padding: 1px 6px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  background: color-mix(in srgb, var(--primary, #0D7377) 12%, transparent);
  color: var(--primary, #0D7377);
}
.thread-search-global-item-badge.badge-body {
  background: color-mix(in srgb, #6366f1 12%, transparent);
  color: #4f46e5;
}
.thread-search-global-item-folder {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.thread-search-global-item-snippet {
  font-size: 12px;
  color: var(--text-muted, #64748b);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.thread-search-global-item-snippet mark {
  background: color-mix(in srgb, var(--primary, #0D7377) 20%, transparent);
  color: inherit;
  padding: 0 1px;
  border-radius: 3px;
}
@media (max-width: 640px) {
  .thread-search-mode-btn { padding: 4px 8px; font-size: 11.5px; }
  .thread-search-global { margin: 4px 8px 0; max-height: min(45vh, 380px); }
  .thread-search-global-item { padding: 8px 12px; }
}
/* ═════════════════ end in-thread search bar ═════════════════════════ */

/* ═════════════════ git changes viewer (12 Jul 2026 v1) ══════════════
 *
 * Inline read-only diff/status/log panel for the thread's cwd. Companion
 * to the commit-attribution trailer that claude.ts injects into every
 * commit Claude makes on behalf of the prompting user.
 *
 * Declared 12 Jul 2026 v1 (Musheer: "can you bring feature to view git
 * changes before commit?").
 *
 * Sits between the thread search bar and the messages list — inline (no
 * modal) per the no-dialog-boxes house rule. Two tabs: uncommitted /
 * recent commits. Cross-UI parity: telegram-app.html carries an
 * equivalent panel.
 * ─────────────────────────────────────────────────────────────────── */
.git-changes-panel {
  display: flex;
  flex-direction: column;
  margin: 8px 16px 0;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e3e8ef);
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  overflow: hidden;
  min-height: 300px;
  max-height: min(560px, 62vh);
}
.git-changes-panel.hidden,
.git-changes-panel[hidden] { display: none; }

.git-changes-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border, #e3e8ef);
  background: color-mix(in srgb, var(--surface, #fff) 96%, var(--primary, #0D7377));
  flex-wrap: wrap;
}
.git-changes-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  color: var(--text, #0F172A);
}
.git-changes-title svg { color: var(--primary, #0D7377); }
.git-changes-info-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1px solid var(--border, #e3e8ef);
  background: transparent;
  color: var(--text-muted, #64748b);
  font-family: Georgia, serif;
  font-style: italic;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
  margin-left: 4px;
}
.git-changes-info-btn:hover,
.git-changes-info-btn[aria-expanded="true"] {
  border-color: var(--primary, #0D7377);
  color: var(--primary, #0D7377);
}
.git-changes-meta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text-muted, #64748b);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.git-changes-branch {
  background: color-mix(in srgb, var(--primary, #0D7377) 12%, var(--surface, #fff));
  color: var(--primary, #0D7377);
  padding: 2px 8px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 11.5px;
}
.git-changes-branch:empty { display: none; }
.git-changes-head {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/*
  Nested-repo picker (17 Jul 2026 v2). Shown in .git-changes-meta only when
  the thread cwd is a workspace parent that hosts multiple git-tracked
  sub-projects (e.g. hodo-development → hodo, hodo-react-js). Styled to
  match the .git-changes-branch pill so it visually reads as another
  meta chip rather than a form control.
*/
.git-changes-repo-picker {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 4px 2px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary, #0D7377) 8%, var(--surface, #fff));
  border: 1px solid color-mix(in srgb, var(--primary, #0D7377) 20%, transparent);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--primary, #0D7377);
}
.git-changes-repo-picker.hidden { display: none; }
.git-changes-repo-picker-label {
  font-weight: 500;
  opacity: 0.75;
}
.git-changes-repo-picker-select {
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  font-weight: 600;
  padding: 2px 4px;
  cursor: pointer;
  outline: none;
  max-width: 220px;
}
.git-changes-repo-picker-select:focus-visible {
  outline: 2px solid var(--primary, #0D7377);
  outline-offset: 2px;
  border-radius: 4px;
}
.git-changes-actions {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
}
.git-changes-close {
  border-radius: 50%;
  width: 26px;
  height: 26px;
  padding: 0;
}

.git-changes-info-tooltip {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border, #e3e8ef);
  background: color-mix(in srgb, var(--warning, #F59E0B) 6%, var(--surface, #fff));
  font-size: 13px;
  color: var(--text, #0F172A);
}
.git-changes-info-tooltip.hidden { display: none; }
.git-changes-info-tooltip strong { display: block; margin-bottom: 4px; }
.git-changes-info-tooltip ul { margin: 0; padding-left: 18px; }
.git-changes-info-tooltip li { margin: 3px 0; line-height: 1.5; }
.git-changes-info-tooltip code {
  background: color-mix(in srgb, var(--primary, #0D7377) 8%, transparent);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 12px;
}

.git-changes-tabs {
  display: flex;
  gap: 4px;
  padding: 6px 12px 0;
  border-bottom: 1px solid var(--border, #e3e8ef);
  flex: 0 0 auto;
}
.git-changes-tab {
  border: none;
  background: transparent;
  padding: 6px 10px 8px;
  color: var(--text-muted, #64748b);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.git-changes-tab:hover { color: var(--text, #0F172A); }
.git-changes-tab.is-active {
  color: var(--primary, #0D7377);
  border-bottom-color: var(--primary, #0D7377);
  font-weight: 600;
}
.git-changes-tab-badge {
  background: color-mix(in srgb, var(--primary, #0D7377) 14%, transparent);
  color: var(--primary, #0D7377);
  font-size: 11px;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: 999px;
  min-width: 18px;
  text-align: center;
}
.git-changes-tab-badge:empty,
.git-changes-tab-badge[data-count="0"] { display: none; }

.git-changes-body {
  flex: 1 1 auto;
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.git-changes-tabpanel {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.git-changes-tabpanel.hidden { display: none; }

.git-changes-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border, #e3e8ef);
  flex: 0 0 auto;
}
.git-changes-filter-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 1px solid var(--border, #e3e8ef);
  border-radius: 999px;
  padding: 4px 12px;
  font: inherit;
  font-size: 13px;
  background: var(--surface-alt, #f8fafc);
  color: var(--text, #0F172A);
  outline: none;
}
.git-changes-filter-input:focus {
  border-color: var(--primary, #0D7377);
  background: var(--surface, #fff);
}
.git-changes-toolbar-hint {
  font-size: 11.5px;
  color: var(--text-faint, #94a3b8);
  white-space: nowrap;
}

.git-changes-split {
  display: grid;
  grid-template-columns: minmax(220px, 34%) 1fr;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

.git-changes-file-list,
.git-changes-log-list {
  list-style: none;
  margin: 0;
  padding: 4px 0;
  overflow-y: auto;
  border-right: 1px solid var(--border, #e3e8ef);
  background: var(--surface-alt, #f8fafc);
  min-height: 0;
}
.git-changes-file-list:focus,
.git-changes-log-list:focus { outline: 2px solid color-mix(in srgb, var(--primary, #0D7377) 40%, transparent); outline-offset: -2px; }

.git-changes-file-row,
.git-changes-log-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  cursor: pointer;
  font-size: 12.5px;
  color: var(--text, #0F172A);
  border-left: 3px solid transparent;
  user-select: none;
}
.git-changes-file-row:hover,
.git-changes-log-row:hover { background: color-mix(in srgb, var(--primary, #0D7377) 6%, transparent); }
.git-changes-file-row.is-active,
.git-changes-log-row.is-active {
  background: color-mix(in srgb, var(--primary, #0D7377) 12%, transparent);
  border-left-color: var(--primary, #0D7377);
}
.git-changes-file-row.is-hidden,
.git-changes-log-row.is-hidden { display: none; }

.git-changes-file-status {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 18px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 700;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  color: #fff;
  flex: 0 0 auto;
}
/* Semantics: M=modified, A=added, D=deleted, R=renamed, ??=untracked, U=unmerged */
.git-changes-file-status[data-status="M"] { background: #F59E0B; }
.git-changes-file-status[data-status="A"] { background: #22C55E; }
.git-changes-file-status[data-status="D"] { background: #EF4444; }
.git-changes-file-status[data-status="R"] { background: #8B5CF6; }
.git-changes-file-status[data-status="??"] { background: #64748b; }
.git-changes-file-status[data-status="U"] { background: #DC2626; }
.git-changes-file-status[data-status=""] { background: #94a3b8; }

.git-changes-file-path {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px;
}

.git-changes-log-row { flex-direction: column; align-items: flex-start; gap: 2px; }
.git-changes-log-subject {
  font-weight: 600;
  color: var(--text, #0F172A);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.git-changes-log-meta {
  font-size: 11px;
  color: var(--text-muted, #64748b);
  display: inline-flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.git-changes-log-sha {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  background: color-mix(in srgb, var(--primary, #0D7377) 10%, transparent);
  color: var(--primary, #0D7377);
  padding: 0 5px;
  border-radius: 4px;
}
.git-changes-log-author {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 220px;
}

.git-changes-diff-wrap {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  background: var(--surface, #fff);
}
.git-changes-diff-header {
  padding: 8px 12px;
  font-size: 12px;
  color: var(--text-muted, #64748b);
  border-bottom: 1px solid var(--border, #e3e8ef);
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 0 0 auto;
}
.git-changes-diff-header.hidden { display: none; }

.git-changes-diff {
  margin: 0;
  padding: 10px 14px;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.55;
  color: var(--text, #0F172A);
  white-space: pre;
  overflow: auto;
  flex: 1 1 auto;
  min-height: 0;
  background: #fff;
}
/* Diff line colours — kept subtle so the eye scans structure, not decoration. */
.git-changes-diff .diff-add   { background: color-mix(in srgb, #22C55E 14%, transparent); display: block; }
.git-changes-diff .diff-del   { background: color-mix(in srgb, #EF4444 14%, transparent); display: block; }
.git-changes-diff .diff-hunk  { background: color-mix(in srgb, #6366F1 10%, transparent); color: #4338CA; display: block; }
.git-changes-diff .diff-file  { color: var(--text-muted, #64748b); display: block; font-weight: 600; }
.git-changes-diff .diff-meta  { color: var(--text-faint, #94a3b8); display: block; }

.git-changes-empty {
  padding: 24px 20px;
  text-align: center;
  color: var(--text-muted, #64748b);
  font-size: 13px;
}
.git-changes-empty.hidden { display: none; }

.git-changes-loading,
.git-changes-error {
  padding: 12px 14px;
  font-size: 13px;
}
.git-changes-loading {
  color: var(--text-muted, #64748b);
  background: color-mix(in srgb, var(--surface-alt, #f8fafc) 60%, transparent);
}
.git-changes-loading.hidden,
.git-changes-error.hidden { display: none; }
.git-changes-error {
  color: #B42318;
  background: color-mix(in srgb, #B42318 8%, transparent);
  border-top: 1px solid color-mix(in srgb, #B42318 20%, var(--border, #e3e8ef));
}

/* Uncommitted-count badge on the "Git" header button — mirrors the message-
 * count / notification-count pill patterns used elsewhere. Only visible when
 * count > 0 (JS toggles the .hidden class based on the status endpoint). */
.thread-git-btn-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  margin-left: 4px;
  border-radius: 999px;
  background: var(--primary, #0D7377);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.thread-git-btn-badge.hidden { display: none; }

/* Mobile: stack the split so the file list sits above the diff. */
@media (max-width: 720px) {
  .git-changes-panel { margin: 6px 8px 0; max-height: 72vh; }
  .git-changes-split { grid-template-columns: 1fr; grid-template-rows: 40% 1fr; }
  .git-changes-file-list,
  .git-changes-log-list { border-right: none; border-bottom: 1px solid var(--border, #e3e8ef); }
  .git-changes-toolbar-hint { display: none; }
  .git-changes-header { padding: 6px 10px; gap: 8px; }
}
/* ═════════════════ end git changes viewer ═══════════════════════════ */

/* ═════════════════ uniform sidebar thread-row height ════════════════
 *
 * The sidebar thread list renders rows whose contents are partially
 * optional — `.thread-folder` shows only when a thread's `cwd` differs
 * from its folder group's `cwd`, `.thread-snippet` shows only on a
 * content-search hit, and the `:where(.thread-title)` line-clamp rule
 * up at L12311 lets a title grow to 2 lines. The result is that two
 * rows in the same folder can render at different visual heights
 * (~32px for a single-line plain row vs ~50px for one that picked up
 * a second-line element). Reads as "uneven" to the eye — uniform
 * row height is the standard sidebar-list pattern across every
 * desktop chat app, so this layer locks the rows to a single height.
 *
 * Strategy:
 *   1. Pin every `.folder-threads > li[data-id]` thread row to the
 *      same height (34px content box) regardless of inner content.
 *   2. Force the title to single-line + ellipsis (overriding the
 *      dead `.thread-title` line-clamp rule that targets a class the
 *      renderer doesn't actually emit).
 *   3. Centre-align the `.thread-text` column so when a row has a
 *      second-line element (folder/snippet) the first line still
 *      sits where the eye expects it.
 *   4. Align the Brain quick-link row (`.folder-brain-link` /
 *      `.folder-ideas-link`) to the same canonical height so the
 *      top-of-folder Brain link doesn't sit lower / higher than the
 *      thread rows immediately beneath it.
 *
 * Selectors are intentionally narrow (`#threadList li[data-id]`,
 * `.folder-threads > li[data-id]`) so we don't touch the dashboard
 * sidebar buttons / Global Memory link / etc. that share the
 * `#threadList li` shell. Specificity is kept low (no `!important`)
 * so per-thread style hooks (e.g. `.is-pinned` left-edge accent)
 * still apply.
 * ─────────────────────────────────────────────────────────────────── */
.folder-threads > li[data-id] {
  height: 34px;
  min-height: 34px;
  max-height: 34px;
  box-sizing: border-box;
  padding-top: 6px;
  padding-bottom: 6px;
  overflow: hidden;
}
.folder-threads > li.folder-ideas-link,
.folder-threads > li.folder-brain-link {
  min-height: 34px;
  height: 34px;
  box-sizing: border-box;
}

/* Title column inside the row — center vertically so the title sits
   on the row's optical midline whether or not it picks up an optional
   second line. Anything that overflows is clipped by the row's
   max-height (see above), so the visual rhythm of the list stays
   consistent even with `.thread-folder` / `.thread-snippet` present. */
#threadList li[data-id] .thread-text {
  justify-content: center;
  min-width: 0;
  overflow: hidden;
}

/* Single-line title with ellipsis. Overrides the dead-code line-clamp
   rule at L12311 (`:where(.thread-title, ...)`) which targets a class
   the renderer doesn't actually emit — but we redeclare here to be
   defensive against any other clamp rule that might land later. */
#threadList li[data-id] .title {
  display: inline-block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  -webkit-line-clamp: unset;
  line-clamp: unset;
  max-width: 100%;
}

/* The optional second-line elements (`.thread-folder` for sub-cwd
   threads, `.thread-snippet` for content-search hits) still render,
   but get clipped to fit the canonical row height and don't shove
   the title row off-centre. */
#threadList li[data-id] .thread-folder,
#threadList li[data-id] .thread-snippet {
  line-height: 1.1;
  font-size: 10.5px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* ═════════════════ end uniform sidebar thread-row height ════════════ */

/* ═════════════════ thread co-workers (avatar stack) ══════════════════
 *
 * Inline avatar stack on the title-row that surfaces "who else has
 * prompted in this thread" — makes shared / collaborate-mode threads
 * legible at a glance. Rendered by renderThreadCoworkersStack() in
 * app.js, fed by ThreadRow.coworkers[] from GET /api/threads.
 *
 * Placement is inline at the RIGHT of `.title-row`. The stack is
 * `flex-shrink: 0` so it always wins the pixels — the title ellipsis-
 * truncates when the row is narrow. Rationale: "who's collaborating"
 * is a higher-signal fact than the tail of a title.
 *
 * Only shows when the server-side coworker list is non-empty (i.e.
 * at least one OTHER user has prompted in the thread); pure single-
 * user threads render identically to before.
 * ─────────────────────────────────────────────────────────────────── */
.thread-coworkers {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  margin-left: auto;
  padding-left: 6px;
}
.thread-coworker {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.2px;
  color: #fff;
  background: var(--text-faint, #94a3b8);
  border: 1.5px solid var(--surface, #fff);
  box-sizing: border-box;
  overflow: hidden;
  margin-left: -6px;
  flex-shrink: 0;
  cursor: help;
  line-height: 1;
}
.thread-coworker:first-child {
  margin-left: 0;
}
.thread-coworker img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.thread-coworker.is-more {
  background: color-mix(in srgb, var(--primary, #0D7377) 78%, #fff);
  color: #fff;
  font-size: 8.5px;
  padding: 0 3px;
  width: auto;
  min-width: 20px;
}
#threadList li.active .thread-coworker {
  border-color: color-mix(in srgb, var(--primary, #0D7377) 25%, var(--surface, #fff));
}
@media (prefers-color-scheme: dark) {
  .thread-coworker {
    border-color: var(--surface, #111A2C);
  }
}
/* ═════════════════ end thread co-workers ═════════════════════════════ */

/* ═════════════════ My Messages · searchable assignee picker ════════════
 *
 * Replaces the native <select> on the inbox-comments form with a
 * type-ahead combobox. The visible <input> filters a popover list of
 * teammates + agents; the hidden <input id="myMessagesCommentAssignee">
 * carries the picked value (so the existing submit handler keeps
 * reading .value off the same id with no changes).
 *
 * Vanilla CSS tokens — picks up dark mode automatically through the
 * --surface / --border / --text / --primary cascade.
 * ─────────────────────────────────────────────────────────────────── */
.my-msg-assignee-combo {
  position: relative;
  flex: 1 1 220px;
  min-width: 0;
}
.my-msg-assignee-combo-input {
  width: 100%;
  /* match .my-msg-config-select sizing so the picker still aligns with
     the rest of the comment-form row (channel select etc.) */
}
.my-msg-assignee-combo-input:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--primary, #0D7377) 50%, var(--border, #e3e8ef));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0D7377) 14%, transparent);
}
.my-msg-assignee-combo-clear {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-faint, #94a3b8);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: 12px;
  line-height: 1;
}
.my-msg-assignee-combo-clear:hover {
  background: var(--surface-sunk, rgba(15,23,42,0.06));
  color: var(--text, #0F172A);
}

.my-msg-assignee-combo-list {
  position: absolute;
  left: 0;
  right: 0;
  /* drops UP above the input — the form sits at the bottom of the right
     pane, and the natural drop-down would overflow the composer below.
     Anchor the bottom of the list to the top of the input. */
  bottom: calc(100% + 4px);
  margin: 0;
  padding: 4px 0;
  max-height: 280px;
  overflow-y: auto;
  background: var(--surface, #ffffff);
  border: 1px solid var(--border, #e3e8ef);
  border-radius: 10px;
  box-shadow: 0 10px 28px rgba(15, 23, 42, 0.16);
  list-style: none;
  z-index: 60;
}
.my-msg-assignee-combo-list li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px;
  cursor: pointer;
  font-size: 13.5px;
  color: var(--text, #0F172A);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  user-select: none;
}
.my-msg-assignee-combo-list li.active,
.my-msg-assignee-combo-list li:hover {
  background: var(--primary-tint, rgba(13,115,119,0.08));
  color: var(--primary, #0D7377);
}
.my-msg-assignee-combo-list li.unassigned-row {
  color: var(--text-muted, #64748b);
  font-style: italic;
}
.my-msg-assignee-combo-list li.unassigned-row.active,
.my-msg-assignee-combo-list li.unassigned-row:hover {
  color: var(--primary, #0D7377);
}
.my-msg-assignee-combo-icon {
  display: inline-block;
  width: 18px;
  flex-shrink: 0;
  text-align: center;
}
.my-msg-assignee-combo-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.my-msg-assignee-combo-empty {
  padding: 8px 12px;
  color: var(--text-faint, #94a3b8);
  font-style: italic;
  cursor: default;
  font-size: 13px;
}
.my-msg-assignee-combo-empty:hover { background: transparent; }

/* Mobile: 16px font on the input prevents iOS Safari zoom-on-focus. */
@media (max-width: 640px) {
  .my-msg-assignee-combo-input { font-size: 16px; }
  .my-msg-assignee-combo-list { max-height: 220px; }
}
/* ═════════════════ end My Messages assignee picker ═════════════════ */

/* ═════════════════ My Messages · enterprise-polish layer ═══════════════
 *
 * Additive refinement pass over the existing My Messages module — does
 * NOT change layout, structure, classes, branding, colors, business
 * logic, or APIs. Pure CSS quality lift: better spacing, hierarchy,
 * typography, hover states, focus rings, and a search-bar in the left
 * list (the only markup addition, wired by the search renderer in
 * app.js).
 *
 * Selectors are intentionally specific (`.my-messages-list .my-msg-row`,
 * `.my-msg-channel-tabs .my-msg-channel-tab`, etc.) so this layer wins
 * against the earlier `.my-msg-*` declarations at L9913+ via order, not
 * specificity inflation — making it easy to roll back if needed.
 *
 * Reference benchmark: enterprise messenger UIs (Front, Intercom, Slack,
 * Linear inbox). The current Imagine palette is preserved end-to-end.
 * ──────────────────────────────────────────────────────────────────── */

/* ── 0. Local tokens (scoped, no leakage) ─────────────────────────── */
#myMessagesView {
  --mm-gap: 14px;
  --mm-radius: 10px;
  --mm-radius-sm: 8px;
  --mm-surface: var(--surface, #ffffff);
  --mm-surface-sunk: var(--surface-sunk, #EEF2F6);
  --mm-border: var(--border, #E3E8EF);
  --mm-border-soft: color-mix(in srgb, var(--border, #E3E8EF) 70%, transparent);
  --mm-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.04);
  --mm-shadow-md: 0 4px 14px rgba(15, 23, 42, 0.08);
  --mm-text: var(--text, #0F172A);
  --mm-text-muted: var(--text-muted, #475569);
  --mm-text-faint: var(--text-faint, #94A3B8);
  --mm-brand-tint: color-mix(in srgb, var(--primary, #0D7377) 8%, transparent);
  --mm-brand-tint-strong: color-mix(in srgb, var(--primary, #0D7377) 18%, transparent);
}

/* ── 1. Body: tighten gutter + the grid template ───────────────────── */
.my-messages-body {
  gap: var(--mm-gap);
  padding: 0 4px;
}

/* ── 2. Left list: shell + scrollbar ──────────────────────────────── */
.my-messages-list {
  background: transparent;
  border-right: none; /* the cards carry their own separation now */
  padding: 6px 6px 6px 2px;
  scrollbar-gutter: stable;
}
.my-messages-list::-webkit-scrollbar { width: 8px; }
.my-messages-list::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--mm-text-faint) 30%, transparent);
  border-radius: 999px;
}
.my-messages-list::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--mm-text-faint) 55%, transparent);
}

/* ── 3. Channel filter chips: equal height, brand-tint active ─────── */
.my-msg-channel-tabs {
  gap: 6px;
  padding: 6px 4px 8px;
  margin: 0 0 8px;
  border-bottom: 1px solid var(--mm-border-soft);
  background: var(--mm-surface);
}
.my-msg-channel-tab {
  min-height: 28px;
  padding: 4px 12px;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1px;
  border: 1px solid var(--mm-border);
  background: var(--mm-surface);
  color: var(--mm-text-muted);
  transition: background 140ms ease, color 140ms ease,
              border-color 140ms ease, box-shadow 140ms ease;
}
.my-msg-channel-tab:hover:not(.is-active) {
  background: var(--mm-brand-tint);
  color: var(--primary, #0D7377);
  border-color: var(--mm-brand-tint-strong);
}
.my-msg-channel-tab:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0D7377) 22%, transparent);
}
.my-msg-channel-tab.is-active {
  background: var(--primary, #0D7377);
  color: #fff;
  border-color: var(--primary, #0D7377);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--primary, #0D7377) 28%, transparent);
}
.my-msg-channel-tab-count {
  min-width: 18px;
  height: 16px;
  padding: 0 5px;
  font-size: 10px;
  font-weight: 700;
  background: color-mix(in srgb, var(--mm-text-faint) 65%, transparent);
}
.my-msg-channel-tab.is-active .my-msg-channel-tab-count {
  background: rgba(255, 255, 255, 0.30);
}

/* ── 4. Search bar above conversation list ────────────────────────── */
.my-msg-search-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 2px 10px;
  padding: 6px 10px 6px 12px;
  background: var(--mm-surface);
  border: 1px solid var(--mm-border);
  border-radius: 999px;
  box-shadow: var(--mm-shadow-sm);
  position: sticky;
  top: 44px; /* sit just below the sticky channel-tabs strip */
  z-index: 2;
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.my-msg-search-bar:focus-within {
  border-color: color-mix(in srgb, var(--primary, #0D7377) 45%, var(--mm-border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0D7377) 14%, transparent);
}
.my-msg-search-icon {
  flex: 0 0 auto;
  color: var(--mm-text-muted);
}
.my-msg-search-input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
  font-size: 13px;
  color: var(--mm-text);
  padding: 4px 0;
}
.my-msg-search-input::placeholder { color: var(--mm-text-faint); }
.my-msg-search-input::-webkit-search-decoration,
.my-msg-search-input::-webkit-search-cancel-button,
.my-msg-search-input::-webkit-search-results-button,
.my-msg-search-input::-webkit-search-results-decoration { display: none; }
.my-msg-search-clear {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--mm-text-faint);
  cursor: pointer;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  font-size: 12px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.my-msg-search-clear:hover {
  background: var(--mm-surface-sunk);
  color: var(--mm-text);
}

/* ── 5. Conversation cards: rounded · breathing · scan-friendly ───── */
.my-messages-list .my-msg-row {
  padding: 11px 13px;
  border-radius: var(--mm-radius);
  border: 1px solid transparent;
  background: var(--mm-surface);
  margin: 0 2px 6px;
  box-shadow: var(--mm-shadow-sm);
  transition: background 140ms ease, border-color 140ms ease,
              transform 140ms ease, box-shadow 140ms ease;
  position: relative;
}
.my-messages-list .my-msg-row:hover {
  background: var(--mm-surface);
  border-color: var(--mm-border);
  transform: translateY(-1px);
  box-shadow: var(--mm-shadow-md);
}
.my-messages-list .my-msg-row.active {
  background: var(--mm-brand-tint);
  border-color: color-mix(in srgb, var(--primary, #0D7377) 32%, var(--mm-border));
  box-shadow: var(--mm-shadow-sm);
  transform: none;
}
/* Brand-color left accent on the active row — Slack / Front / Linear */
.my-messages-list .my-msg-row.active::before {
  content: "";
  position: absolute;
  left: 0; top: 10px; bottom: 10px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--primary, #0D7377);
}
.my-messages-list .my-msg-row-head {
  margin-bottom: 2px;
  gap: 10px;
}
.my-messages-list .my-msg-row-head strong {
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.1px;
  color: var(--mm-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.my-messages-list .my-msg-when {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--mm-text-faint);
  opacity: 1;
  flex-shrink: 0;
}
.my-messages-list .my-msg-preview {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--mm-text-muted);
  opacity: 1;
  margin-top: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
}
.my-messages-list .my-msg-channels {
  gap: 5px;
  margin-top: 7px;
}
.my-messages-list .my-msg-chip {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.2px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--mm-surface-sunk);
  color: var(--mm-text-muted);
  opacity: 1;
  text-transform: capitalize;
}
.my-messages-list .my-msg-row.active .my-msg-chip {
  background: color-mix(in srgb, var(--primary, #0D7377) 14%, transparent);
  color: var(--primary, #0D7377);
}

/* Empty-state placeholder inside the list — calmer voice */
.my-messages-list .placeholder {
  font-size: 12.5px;
  color: var(--mm-text-faint);
  padding: 16px 12px;
  text-align: center;
  margin: 4px 2px;
  background: var(--mm-surface);
  border: 1px dashed var(--mm-border);
  border-radius: var(--mm-radius);
}

/* ── 6. Conversation header: hierarchy + grouped controls ─────────── */
.my-msg-thread-head {
  padding: 14px 18px;
  border-bottom: 1px solid var(--mm-border-soft);
  background: var(--mm-surface);
  gap: 14px;
  align-items: center;
}
.my-msg-thread-head > div:first-child > strong {
  font-size: 15.5px;
  font-weight: 600;
  letter-spacing: 0.1px;
  color: var(--mm-text);
  display: block;
  margin-bottom: 2px;
}
.my-msg-thread-head .my-msg-meta {
  font-size: 11.5px;
  color: var(--mm-text-muted);
  margin-left: 0;
  margin-right: 10px;
  font-variant-numeric: tabular-nums;
  opacity: 1;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.my-msg-config {
  margin-left: auto;
  gap: 6px;
}
.my-msg-config-row {
  font-size: 11.5px;
  gap: 8px;
}
.my-msg-config-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--mm-text-faint);
}
.my-msg-config-select {
  padding: 4px 10px;
  border-radius: 6px;
  border: 1px solid var(--mm-border);
  font-size: 11.5px;
  color: var(--mm-text);
  background: var(--mm-surface);
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.my-msg-config-select:hover { border-color: color-mix(in srgb, var(--primary, #0D7377) 30%, var(--mm-border)); }
.my-msg-config-select:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--primary, #0D7377) 50%, var(--mm-border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0D7377) 14%, transparent);
}
.my-msg-observer-chip {
  background: var(--mm-brand-tint);
  border: 1px solid var(--mm-brand-tint-strong);
  color: var(--primary, #0D7377);
  font-size: 11px;
  font-weight: 600;
  padding: 3px 9px;
}

/* ── 7. Message area: reading-comfortable bubbles ─────────────────── */
.my-msg-msgs {
  padding: 20px 24px;
  gap: 14px;
  background: var(--mm-surface-alt, var(--surface-alt, #F8FAFC));
}
.my-msg-bubble {
  max-width: min(72ch, 78%);
  padding: 10px 14px;
  border-radius: 14px;
  font-size: 13.5px;
  box-shadow: var(--mm-shadow-sm);
  line-height: 1.5;
}
.my-msg-bubble.inbound {
  background: var(--mm-surface);
  border: 1px solid var(--mm-border-soft);
  color: var(--mm-text);
  border-bottom-left-radius: 4px; /* speech-bubble tail */
}
.my-msg-bubble.outbound {
  background: color-mix(in srgb, var(--primary, #0D7377) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary, #0D7377) 22%, transparent);
  color: var(--mm-text);
  border-bottom-right-radius: 4px;
}
.my-msg-bubble-body {
  font-size: 13.5px;
  line-height: 1.55;
  letter-spacing: 0.05px;
}
.my-msg-bubble-meta {
  font-size: 10.5px;
  color: var(--mm-text-faint);
  margin-top: 5px;
  opacity: 1;
  letter-spacing: 0.2px;
  font-variant-numeric: tabular-nums;
}
.my-msg-bubble.outbound .my-msg-bubble-meta { color: color-mix(in srgb, var(--mm-text-muted) 80%, transparent); }

/* ── 8. Internal notes: turn into a proper card ───────────────────── */
.my-msg-comments {
  background: var(--mm-surface);
  border-top: 1px solid var(--mm-border);
  padding: 14px 18px 14px;
  gap: 10px;
  position: relative;
}
.my-msg-comments::before {
  content: "";
  position: absolute;
  left: 18px; right: 18px; top: 0;
  height: 2px;
  background: linear-gradient(90deg,
    transparent,
    color-mix(in srgb, #F59E0B 30%, transparent),
    transparent);
}
.my-msg-comments-head {
  font-size: 12px;
  gap: 8px;
  padding-bottom: 4px;
}
.my-msg-comments-title {
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--mm-text-muted);
}
.my-msg-comments-list { gap: 8px; }
.my-msg-comment {
  background: color-mix(in srgb, #F59E0B 5%, var(--mm-surface));
  border: 1px solid color-mix(in srgb, #F59E0B 22%, var(--mm-border));
  border-left: 3px solid color-mix(in srgb, #F59E0B 60%, transparent);
  border-radius: var(--mm-radius-sm);
  padding: 9px 13px;
  font-size: 13px;
  box-shadow: var(--mm-shadow-sm);
}
.my-msg-comment-body { line-height: 1.5; }
.my-msg-comment-resolve,
.my-msg-comment-delete {
  border: 1px solid var(--mm-border);
  border-radius: 999px;
  padding: 3px 10px;
  font-weight: 600;
  font-size: 11px;
  transition: background 140ms ease, color 140ms ease, border-color 140ms ease;
}
.my-msg-comment-resolve:hover {
  background: color-mix(in srgb, var(--success, #10b981) 14%, transparent);
}
.my-msg-comment-delete:hover {
  background: color-mix(in srgb, var(--danger, #DC2626) 12%, transparent);
}

.my-msg-comment-form {
  background: var(--mm-surface);
  border: 1px solid var(--mm-border);
  border-radius: var(--mm-radius);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  box-shadow: var(--mm-shadow-sm);
}
.my-msg-comment-form textarea {
  border: 1px solid transparent;
  background: transparent;
  font-family: inherit;
  font-size: 13px;
  line-height: 1.5;
  resize: vertical;
  min-height: 44px;
  padding: 4px 2px;
  outline: none;
  color: var(--mm-text);
}
.my-msg-comment-form textarea::placeholder { color: var(--mm-text-faint); }
.my-msg-comment-form .my-msg-comment-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  border-top: 1px solid var(--mm-border-soft);
  padding-top: 8px;
}
.my-msg-comment-form .my-msg-comment-row > .my-msg-assignee-combo { flex: 1 1 200px; }

/* ── 9. Reply composer: compact default + auto-grow ───────────────── */
.my-msg-reply {
  padding: 12px 16px 14px;
  border-top: 1px solid var(--mm-border);
  background: var(--mm-surface);
  gap: 10px;
  align-items: stretch;
}
.my-msg-reply textarea {
  border-radius: var(--mm-radius);
  border: 1px solid var(--mm-border);
  padding: 10px 14px;
  font-size: 13.5px;
  line-height: 1.5;
  min-height: 44px;
  max-height: 180px; /* internal scroll above this */
  background: var(--mm-surface);
  transition: border-color 140ms ease, box-shadow 140ms ease;
  resize: none;
  field-sizing: content; /* modern browsers: auto-expand with content */
}
.my-msg-reply textarea:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--primary, #0D7377) 45%, var(--mm-border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0D7377) 12%, transparent);
}
.my-msg-reply textarea:disabled {
  background: var(--mm-surface-sunk);
  color: var(--mm-text-faint);
  cursor: not-allowed;
}
.my-msg-channel-select {
  padding: 8px 12px;
  border-radius: var(--mm-radius-sm);
  border: 1px solid var(--mm-border);
  font-size: 13px;
  color: var(--mm-text);
  background: var(--mm-surface);
  transition: border-color 140ms ease, box-shadow 140ms ease;
  align-self: flex-end;
  min-height: 44px;
}
.my-msg-channel-select:hover { border-color: color-mix(in srgb, var(--primary, #0D7377) 30%, var(--mm-border)); }
.my-msg-channel-select:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--primary, #0D7377) 50%, var(--mm-border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0D7377) 12%, transparent);
}
/* Buttons inside the reply row (attach + send + emoji) — equal-height,
   visually grouped against the textarea baseline. */
.my-msg-reply > .btn,
.my-msg-reply > button.btn {
  align-self: flex-end;
  min-height: 44px;
  padding: 0 14px;
  border-radius: var(--mm-radius-sm);
  font-weight: 600;
  letter-spacing: 0.15px;
  transition: background 140ms ease, color 140ms ease,
              border-color 140ms ease, transform 140ms ease,
              box-shadow 140ms ease;
}
.my-msg-reply > .btn:focus-visible,
.my-msg-reply > button.btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0D7377) 22%, transparent);
}
.my-msg-reply > .btn-primary:active,
.my-msg-reply > button.btn-primary:active { transform: translateY(1px); }

/* ── 10. Responsive: tablet collapses two-pane stack, phone follows ── */
@media (max-width: 980px) {
  #myMessagesView .my-messages-body {
    grid-template-columns: 280px 1fr;
    gap: 10px;
  }
  .my-msg-thread-head { padding: 12px 14px; gap: 10px; }
  .my-msg-msgs { padding: 16px 18px; }
}
@media (max-width: 720px) {
  #myMessagesView .my-messages-body {
    grid-template-columns: 1fr; /* single-pane on phones — owned by routing */
    gap: 8px;
  }
  .my-msg-search-bar { top: 40px; }
  .my-msg-bubble { max-width: 92%; }
  .my-msg-channel-tab { padding: 4px 10px; font-size: 11.5px; }
  .my-msg-reply textarea { font-size: 16px; /* iOS no-zoom */ }
  .my-msg-channel-select { font-size: 16px; }
}

/* ── 11. Dark-mode parity: keep surfaces dark + accents legible ───── */
html.theme-dark #myMessagesView {
  --mm-surface: var(--surface, #0F172A);
  --mm-surface-sunk: var(--surface-sunk, #1E293B);
  --mm-border: var(--border, #334155);
  --mm-border-soft: color-mix(in srgb, var(--border, #334155) 80%, transparent);
  --mm-text: var(--text, #E2E8F0);
  --mm-text-muted: var(--text-muted, #94A3B8);
  --mm-text-faint: var(--text-faint, #64748B);
  --mm-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.30);
  --mm-shadow-md: 0 4px 14px rgba(0, 0, 0, 0.36);
}
/* ═════════════════ end My Messages enterprise-polish layer ════════ */

/* ═════════════════ My Messages · channel-icon SVG polish ══════════════
 *
 * Swaps the emoji glyphs (🟢 ✈️ ✉️ 📱) for consistent inline-SVG icons
 * across the three surfaces where channels are named:
 *   1. Left-panel filter chips (All / WhatsApp / Telegram / Email / SMS)
 *   2. Conversation-row channel badges (bottom of each conversation card)
 *   3. Message-bubble meta line ("<icon> whatsapp · 10:09 am · delivered")
 *
 * Icons come from _channelIconSvg() in app.js. Each SVG carries a
 * `.ch-icon-<channel>` class so we can brand-tint per channel (subtle —
 * matches the enterprise-messenger reference) without touching the JS.
 *
 * `currentColor` on the SVG means every icon inherits the parent's text
 * color by default — muted grey when idle, white when on the active tab
 * (via `.my-msg-channel-tab.is-active` inheriting white text) — and then
 * the per-channel `.ch-icon-<x>` rules add a subtle brand tint on top.
 * ──────────────────────────────────────────────────────────────────── */

/* Base icon reset — flex-safe, tab-safe, chip-safe. */
.ch-icon {
  flex: 0 0 auto;
  vertical-align: -2px;    /* nudge to sit on the text baseline */
  color: inherit;
}
/* Brand tints — kick in only when the icon is NOT sitting on the active
   tab (active tab already flips text color to white via .is-active). */
.my-msg-channel-tab:not(.is-active) .ch-icon-whatsapp,
.my-msg-chip .ch-icon-whatsapp,
.my-msg-bubble-meta .ch-icon-whatsapp {
  color: #25D366; /* WhatsApp green */
}
.my-msg-channel-tab:not(.is-active) .ch-icon-telegram,
.my-msg-chip .ch-icon-telegram,
.my-msg-bubble-meta .ch-icon-telegram {
  color: #229ED9; /* Telegram blue */
}
.my-msg-channel-tab:not(.is-active) .ch-icon-email,
.my-msg-chip .ch-icon-email,
.my-msg-bubble-meta .ch-icon-email {
  color: var(--text-muted, #64748b);
}
.my-msg-channel-tab:not(.is-active) .ch-icon-sms,
.my-msg-chip .ch-icon-sms,
.my-msg-bubble-meta .ch-icon-sms {
  color: color-mix(in srgb, var(--primary, #0D7377) 70%, transparent);
}
.my-msg-channel-tab:not(.is-active) .ch-icon-all,
.my-msg-chip .ch-icon-all,
.my-msg-bubble-meta .ch-icon-all {
  color: var(--text-muted, #64748b);
}

/* Tab-strip: icon sits before the label at 15px so it reads as an icon,
   not a glyph. Active tab keeps white via inheritance. */
.my-msg-channel-tab .my-msg-channel-tab-icon .ch-icon {
  width: 15px;
  height: 15px;
  vertical-align: -3px;
}
.my-msg-channel-tab.is-active .ch-icon { color: #ffffff; }

/* Conversation-row chip: icon before capitalized channel name. */
.my-messages-list .my-msg-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.my-messages-list .my-msg-chip .ch-icon {
  width: 12px;
  height: 12px;
  vertical-align: 0;
}
.my-msg-chip-label { line-height: 1; }

/* Active row: brand-tint the SVG the same way the chip's text tints. */
.my-messages-list .my-msg-row.active .my-msg-chip .ch-icon {
  color: var(--primary, #0D7377);
}

/* Message-bubble meta line: 11px inline icon so it doesn't shout. */
.my-msg-bubble-meta {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
}
.my-msg-bubble-meta .ch-icon {
  width: 11px;
  height: 11px;
  vertical-align: 0;
}
.my-msg-bubble-meta-channel { text-transform: capitalize; }

/* Reply-channel select still uses the emoji fallback because <option>
   elements can't render inline SVG cross-browser. That's fine — the
   select is a dense one-liner and the emoji reads OK inside it. */
/* ═════════════════ end channel-icon SVG polish ═════════════════════ */

/* ═════════════════ platform-wide baseline polish (1 Jul 2026) ══════════
 *
 * Additive design-system layer applied on top of the whole app. Doesn't
 * redesign anything — it only wires in the enterprise-polish scaffolding
 * that was missing site-wide: motion tokens, focus-visible rings, skeleton
 * loader utility, unified status pills, consistent button/card
 * affordances, admin-panel spacing polish, empty-state pattern.
 *
 * Selectors are intentionally low-specificity (`:where()`, single-class
 * hooks, defensive fallbacks) so per-surface rules keep winning.
 * ──────────────────────────────────────────────────────────────────── */

/* ── 0. Motion tokens — one place to tune app-wide easing/timing ────── */
:root {
  --motion-fast: 140ms;
  --motion-std:  240ms;
  --motion-slow: 400ms;
  --ease-out:    cubic-bezier(.2, .8, .2, 1);
  --ease-in-out: cubic-bezier(.4, 0, .2, 1);
}

/* ── 1. Universal focus rings — respects the design-rule that the app
 *      must run without a mouse. Every interactive element gets a
 *      brand-tinted focus ring on keyboard focus (not on click, per
 *      :focus-visible semantics). Skips elements that already have their
 *      own explicit ring (my-msg-*, thread-search-bar etc.). ─────────── */
:where(button, [role="button"], a, input, select, textarea, summary):focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary, #0D7377) 22%, transparent);
  border-radius: 6px;
}
/* Native <select> can't take box-shadow reliably in some browsers — fall
 * back to outline for those. */
select:focus-visible {
  outline: 2px solid var(--primary, #0D7377);
  outline-offset: 1px;
  box-shadow: none;
}

/* ── 2. Consistent button min-heights — Slack / Linear pattern.
 *      Any .btn gets 32px (small) / 36px (default) / 44px (primary CTA)
 *      unless the surface owner opts out via .btn-icon or .btn-sm. ─── */
.btn { min-height: 36px; }
.btn.btn-sm { min-height: 30px; }
.btn.btn-lg, .btn.btn-primary { min-height: 40px; }
.btn.btn-icon, .btn.btn-icon-text { min-height: auto; }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
.btn { transition: background var(--motion-fast) var(--ease-out),
                   color var(--motion-fast) var(--ease-out),
                   border-color var(--motion-fast) var(--ease-out),
                   transform var(--motion-fast) var(--ease-out),
                   box-shadow var(--motion-fast) var(--ease-out); }

/* ── 3. Skeleton loader utility — drop `.skeleton` on any element to
 *      show a shimmer while the real content is loading. Replaces the
 *      "Loading…" text placeholders across the app. Callers still need
 *      to add the class, but the aesthetic is now shared. ──────────── */
.skeleton {
  position: relative;
  overflow: hidden;
  background: color-mix(in srgb, var(--text-faint, #94a3b8) 14%, transparent);
  border-radius: 8px;
  color: transparent !important;
}
.skeleton::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--surface, #fff) 45%, transparent) 50%,
    transparent 100%);
  animation: skeleton-shimmer 1.4s var(--ease-in-out) infinite;
}
@keyframes skeleton-shimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
.skeleton-line { height: 12px; margin: 6px 0; }
.skeleton-line.short { width: 40%; }
.skeleton-line.medium { width: 65%; }
.skeleton-line.long { width: 85%; }
.skeleton-avatar { width: 32px; height: 32px; border-radius: 50%; }
.skeleton-card { min-height: 68px; }
@media (prefers-reduced-motion: reduce) {
  .skeleton::after { animation: none; }
}

/* ── 4. Unified status pills — one component, six semantic variants.
 *      Drop `<span class="pill pill-ok">Approved</span>` and get
 *      consistent size, radius, weight across every surface. ──────── */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.15px;
  line-height: 1.5;
  border: 1px solid transparent;
  white-space: nowrap;
  vertical-align: middle;
  text-transform: capitalize;
}
.pill-ok       { background: color-mix(in srgb, #10b981 12%, transparent); color: #047857; border-color: color-mix(in srgb, #10b981 28%, transparent); }
.pill-info     { background: color-mix(in srgb, var(--primary, #0D7377) 12%, transparent); color: var(--primary, #0D7377); border-color: color-mix(in srgb, var(--primary, #0D7377) 26%, transparent); }
.pill-warn     { background: color-mix(in srgb, #F59E0B 14%, transparent); color: #92400E; border-color: color-mix(in srgb, #F59E0B 30%, transparent); }
.pill-danger   { background: color-mix(in srgb, #DC2626 12%, transparent); color: #B42318; border-color: color-mix(in srgb, #DC2626 28%, transparent); }
.pill-neutral  { background: var(--surface-sunk, #EEF2F6); color: var(--text-muted, #64748b); border-color: var(--border, #E3E8EF); }
.pill-pink     { background: color-mix(in srgb, #E44C9A 12%, transparent); color: #c84a8a; border-color: color-mix(in srgb, #E44C9A 28%, transparent); }

/* ── 5. Card polish baseline — every `.card`, `.admin-req-row`,
 *      `.actions-pending-card-row` gets a consistent surface, hover
 *      lift, and shadow. Existing per-surface rules still win. ────── */
:where(.card, .admin-req-row, .actions-pending-card-row) {
  transition: background var(--motion-fast) var(--ease-out),
              transform var(--motion-fast) var(--ease-out),
              box-shadow var(--motion-fast) var(--ease-out),
              border-color var(--motion-fast) var(--ease-out);
}
:where(.card:not(.no-hover), .admin-req-row, .actions-pending-card-row):hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
}

/* ── 6. Empty-state pattern — one visual for "nothing here yet". Any
 *      element with `.empty-state` gets the calm centered look; can be
 *      combined with `.empty-state-illustration` for an SVG on top. ── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 32px 16px;
  text-align: center;
  color: var(--text-muted, #64748b);
  font-size: 13px;
  line-height: 1.5;
}
.empty-state-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text, #0F172A);
  margin: 0;
}
.empty-state-body { margin: 0; max-width: 42ch; }
.empty-state-action { margin-top: 8px; }

/* ── 7. Admin-panel spacing sweep — the least-loved surface cluster
 *      (`#adminPanel`, `.admin-req-list`, `.admin-req-row`, etc.) gets
 *      breathing room + card-like separation without touching any
 *      per-panel markup. ────────────────────────────────────────── */
:where(#adminPanel, .admin-req-list, .admin-agent-req-list, .admin-signup-req-list) {
  padding: 4px 2px;
}
.admin-req-row {
  padding: 14px 16px !important;
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 10px;
  background: var(--surface, #fff);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  margin-bottom: 8px;
}
.admin-req-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}
.admin-req-actions .btn { min-height: 32px; }
.admin-empty {
  padding: 22px 16px;
  text-align: center;
  color: var(--text-muted, #64748b);
  font-size: 13px;
  background: var(--surface-alt, #F8FAFC);
  border: 1px dashed var(--border, #E3E8EF);
  border-radius: 10px;
}

/* ── 8. Chip / tag baseline — unify anywhere a "tag" is drawn.
 *      Existing `.chip` / `.my-msg-chip` / `.my-team-pill` etc. keep
 *      their rules; this only ensures a consistent size + line-height
 *      when a new caller adds `.tag`. ────────────────────────────── */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 9px;
  border-radius: 6px;
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.4;
  background: var(--surface-sunk, #EEF2F6);
  color: var(--text-muted, #64748b);
  border: 1px solid var(--border, #E3E8EF);
}

/* ── 9. Dropdown / menu polish — floating menus (`.popover`,
 *      `.floating-menu`, `.dropdown-menu`) get consistent shadow +
 *      slide-in. ─────────────────────────────────────────────────── */
:where(.popover, .floating-menu, .dropdown-menu, .action-menu) {
  background: var(--surface, #fff);
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.14);
  animation: menu-in var(--motion-fast) var(--ease-out);
}
@keyframes menu-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  :where(.popover, .floating-menu, .dropdown-menu, .action-menu) { animation: none; }
}

/* ── 10. Global scrollbar polish (WebKit) — matches the platform's
 *       calm palette instead of the noisy default. ──────────────── */
:where(*)::-webkit-scrollbar { width: 10px; height: 10px; }
:where(*)::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--text-faint, #94a3b8) 30%, transparent);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
:where(*)::-webkit-scrollbar-thumb:hover {
  background-color: color-mix(in srgb, var(--text-faint, #94a3b8) 55%, transparent);
  background-clip: padding-box;
}
:where(*)::-webkit-scrollbar-track { background: transparent; }

/* ── 11. Dark-mode carry-through for tokens defined above. Existing
 *       html.theme-dark blocks still control the surface / text /
 *       border palette; we just make sure the new pill / tag / empty-
 *       state rules land against the right backdrop. ─────────────── */
html.theme-dark .pill-neutral {
  background: color-mix(in srgb, var(--text-faint, #64748b) 22%, transparent);
  color: var(--text, #E2E8F0);
  border-color: color-mix(in srgb, var(--text-faint, #64748b) 32%, transparent);
}
html.theme-dark .tag {
  background: color-mix(in srgb, var(--text-faint, #64748b) 18%, transparent);
  color: var(--text-muted, #94A3B8);
  border-color: color-mix(in srgb, var(--text-faint, #64748b) 30%, transparent);
}
html.theme-dark .admin-req-row {
  background: var(--surface, #0F172A);
  border-color: var(--border, #334155);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}
html.theme-dark .admin-empty {
  background: var(--surface-sunk, #1E293B);
  border-color: var(--border, #334155);
}
html.theme-dark :where(.popover, .floating-menu, .dropdown-menu, .action-menu) {
  background: var(--surface, #0F172A);
  border-color: var(--border, #334155);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
}
/* ═════════════════ end platform-wide baseline polish ═════════════════ */

/* ═════════════════ Sub-thread (2 Jul 2026) ═════════════════
 * ↳ Sub-thread action on every message + ↳-from-parent tag on sub-thread
 * rows in the sidebar. Server side: `POST /api/messages/:id/fork` +
 * `threads.parent_thread_id` / `threads.fork_point_message_id`.
 */

/* Message toolbar button — inherits the shared .msg-action-btn look and
 * adds a soft brand-blue tint so it reads as an "advance to a new
 * surface" affordance rather than an in-place transform (Copy / Edit). */
.msg-action-btn.msg-action-subthread {
  color: #0369A1;
}
.msg-action-btn.msg-action-subthread:hover {
  background: color-mix(in srgb, #0EA5E9 12%, transparent);
  border-color: color-mix(in srgb, #0EA5E9 40%, transparent);
  color: #0369A1;
}
.msg-action-btn.msg-action-subthread[data-busy="1"] {
  opacity: 0.7;
  cursor: progress;
}
html.theme-dark .msg-action-btn.msg-action-subthread {
  color: #7DD3FC;
}
html.theme-dark .msg-action-btn.msg-action-subthread:hover {
  background: color-mix(in srgb, #0EA5E9 22%, transparent);
  color: #BAE6FD;
}

/* Sidebar sub-thread tag — small pill under the title showing the
 * parent's name. Click-through jumps to the parent thread. */
.thread-list .thread-text .thread-sub-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 2px;
  padding: 1px 6px;
  font-size: 10.5px;
  font-weight: 500;
  line-height: 1.35;
  color: color-mix(in srgb, #0369A1 90%, transparent);
  background: color-mix(in srgb, #0EA5E9 10%, transparent);
  border-radius: 4px;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.thread-list .thread-text .thread-sub-tag:hover {
  background: color-mix(in srgb, #0EA5E9 20%, transparent);
  color: #0369A1;
}
html.theme-dark .thread-list .thread-text .thread-sub-tag {
  color: #BAE6FD;
  background: color-mix(in srgb, #0EA5E9 18%, transparent);
}
html.theme-dark .thread-list .thread-text .thread-sub-tag:hover {
  background: color-mix(in srgb, #0EA5E9 32%, transparent);
  color: #E0F2FE;
}
/* ═════════════════ end Sub-thread ═════════════════ */

/* ═════════════════ Nested sub-threads in sidebar (2 Jul 2026) ═════════════════
 * Sub-threads whose parent lives in the SAME folder-group are rendered
 * immediately below their parent, indented by depth. The indent + a
 * small ↳ leader glyph replaces the "↳ from parent" chip (which is
 * suppressed for nested rows since the indent already shows the
 * relationship). Depth is provided via the `--nest-depth` custom
 * property (JS sets it to 1 for direct children, 2 for grand-children,
 * etc.).
 *
 * `padding-left` is used instead of `margin-left` so the row's active-
 * state accent bar (positioned at `left: 0` on the ::before pseudo)
 * still lands on the row's outer left edge. This keeps the visual
 * rhythm intact whether the row is a root or a nested child.
 *
 * The vertical ↳ leader is drawn as a ::before glyph sized to sit
 * under the parent row's text baseline, colored with the muted text
 * token so it doesn't compete with the title.
 */
.folder-threads > li.is-nested {
  padding-left: calc(12px + var(--nest-depth, 1) * 16px);
  position: relative;
}
.folder-threads > li.is-nested::after {
  content: "\21b3"; /* ↳ */
  position: absolute;
  left: calc(4px + (var(--nest-depth, 1) - 1) * 16px);
  top: 50%;
  transform: translateY(-55%);
  color: var(--text-faint, #94a3b8);
  font-size: 12px;
  line-height: 1;
  pointer-events: none;
  opacity: 0.75;
}
.folder-threads > li.is-nested:hover::after,
.folder-threads > li.is-nested.active::after {
  opacity: 1;
  color: var(--primary, #0D7377);
}
/* Slightly dim the nested row's title so the parent above still feels
   like the primary anchor. Titles remain readable — this is a 6% tint. */
.folder-threads > li.is-nested .title {
  color: var(--text-muted, #64748b);
}
.folder-threads > li.is-nested.active .title {
  color: var(--primary, #0D7377);
}
html.theme-dark .folder-threads > li.is-nested::after {
  color: #94A3B8;
}
/* ═════════════════ end Nested sub-threads ═════════════════ */

/* ═════════════════ Notifications view (2 Jul 2026) ═════════════════
 * Scrolling + structured card layout for the admin_alerts feed.
 * Fixes (a) list not scrolling — parent view now has bounded height +
 * body has overflow-y: auto; (b) unstructured cards — replaces the
 * inline-styled soup with clean class-based layout: header row (severity
 * chip · kind · time · unread pill) → title → body → optional excerpt →
 * footer actions. Severity-coloured left border for scannability.
 */

/* Body scroll — the header stays put, list scrolls internally. */
#notificationsBody {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 16px 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
#notificationsList {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Header — condensed action row. `is-active` marks the "Unread only"
 * toggle when engaged so the user sees which mode they're in. */
#notificationsHeader .btn.is-active {
  background: color-mix(in srgb, #0EA5E9 15%, transparent);
  border-color: color-mix(in srgb, #0EA5E9 40%, transparent);
  color: #0369A1;
  font-weight: 600;
}

/* Card — three-row structure (header · content · footer). Severity
 * colour cascades through the left-border + severity chip via
 * data-sev="{info|warn|high}". */
.notification-card {
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 8px;
  padding: 12px 14px 12px 18px;
  background: var(--surface, #FFFFFF);
  border: 1px solid var(--border, #E5E7EB);
  border-left: 4px solid var(--border, #E5E7EB);
  border-radius: 8px;
  transition: box-shadow 120ms ease, transform 120ms ease;
}
.notification-card:hover {
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06);
  transform: translateY(-1px);
}
.notification-card[data-sev="info"] { border-left-color: #0EA5E9; }
.notification-card[data-sev="warn"] { border-left-color: #F59E0B; }
.notification-card[data-sev="high"] { border-left-color: #B42318; }

/* Unread cards get a subtle tinted background so they stand out at a
 * glance without shouting. */
.notification-card.is-unread {
  background: color-mix(in srgb, #0EA5E9 4%, var(--surface, #FFFFFF));
}
.notification-card.is-unread[data-sev="warn"] {
  background: color-mix(in srgb, #F59E0B 5%, var(--surface, #FFFFFF));
}
.notification-card.is-unread[data-sev="high"] {
  background: color-mix(in srgb, #B42318 5%, var(--surface, #FFFFFF));
}

/* Header row — severity chip · kind label · time · optional UNREAD pill. */
.notification-card-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 11px;
}
.notification-card-sev {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  border-radius: 4px;
  font-size: 10px;
}
.notification-card[data-sev="info"] .notification-card-sev {
  color: #0369A1; background: color-mix(in srgb, #0EA5E9 15%, transparent);
}
.notification-card[data-sev="warn"] .notification-card-sev {
  color: #92400E; background: color-mix(in srgb, #F59E0B 18%, transparent);
}
.notification-card[data-sev="high"] .notification-card-sev {
  color: #7F1D1D; background: color-mix(in srgb, #B42318 15%, transparent);
}
.notification-card-kind {
  color: var(--muted, #6B7280);
  font-weight: 600;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
}
.notification-card-time {
  margin-left: auto;
  color: var(--muted, #9CA3AF);
  font-size: 11px;
  white-space: nowrap;
}
.notification-card-unread-pill {
  color: #0369A1;
  background: color-mix(in srgb, #0EA5E9 18%, transparent);
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.3px;
}

/* Content — title (bold single line, ellipsis) + body prose. */
.notification-card-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.notification-card-title {
  font-weight: 600;
  font-size: 14px;
  color: var(--text, #111827);
  line-height: 1.35;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
}
.notification-card-text {
  font-size: 13px;
  color: var(--muted, #374151);
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 5.4em; /* ~3 lines */
  overflow: hidden;
  position: relative;
}
.notification-card.is-expanded .notification-card-text {
  max-height: none;
}
.notification-card-excerpt {
  margin: 4px 0 0;
  padding: 8px 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  line-height: 1.45;
  color: #4B5563;
  background: rgba(15, 23, 42, 0.04);
  border-left: 2px solid var(--border, #CBD5E1);
  border-radius: 4px;
  max-height: 6.5em; /* ~4 lines */
  overflow: hidden;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  position: relative;
}
.notification-card.is-expanded .notification-card-excerpt {
  max-height: none;
}
/* Fade-out overlay when truncated so the user knows there's more. */
.notification-card:not(.is-expanded) .notification-card-text.is-clipped::after,
.notification-card:not(.is-expanded) .notification-card-excerpt.is-clipped::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 24px;
  background: linear-gradient(to bottom, transparent, var(--surface, #FFFFFF) 80%);
  pointer-events: none;
}

/* Footer row — meta actions. Keeps the same visual weight so the card
 * doesn't jitter between read/unread states. */
.notification-card-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding-top: 4px;
  border-top: 1px dashed color-mix(in srgb, var(--border, #E5E7EB) 65%, transparent);
  font-size: 11px;
}
.notification-card-thread-link {
  color: #0369A1;
  font-weight: 600;
  text-decoration: none;
}
.notification-card-thread-link:hover { text-decoration: underline; }
.notification-card-expand-btn,
.notification-card-mark-read {
  margin-left: auto;
  padding: 3px 10px;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted, #4B5563);
  background: transparent;
  border: 1px solid var(--border, #E5E7EB);
  border-radius: 4px;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.notification-card-expand-btn { margin-left: 0; }
.notification-card-expand-btn:hover,
.notification-card-mark-read:hover {
  background: color-mix(in srgb, #0EA5E9 8%, transparent);
  border-color: color-mix(in srgb, #0EA5E9 30%, transparent);
  color: #0369A1;
}
.notification-card-mark-read[disabled] { opacity: 0.6; cursor: progress; }

/* Approve / Reject inline actions on thread.pending_approval notification cards.
 * Approve is the primary CTA (solid green), Reject is a soft secondary.
 * Positioned before the Mark-read button so the primary action reads first. */
.notification-card-thread-approve,
.notification-card-thread-reject {
  padding: 3px 10px;
  font-size: 11px;
  font-weight: 700;
  border-radius: 4px;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.notification-card-thread-approve {
  margin-left: auto;
  color: #FFFFFF;
  background: #059669;
  border: 1px solid #047857;
}
.notification-card-thread-approve:hover { background: #047857; }
.notification-card-thread-reject {
  color: #B91C1C;
  background: transparent;
  border: 1px solid #FCA5A5;
}
.notification-card-thread-reject:hover {
  background: color-mix(in srgb, #EF4444 8%, transparent);
  border-color: #EF4444;
}
.notification-card-thread-approve[disabled],
.notification-card-thread-reject[disabled] { opacity: 0.6; cursor: progress; }
/* When both Approve+Reject are present, the sibling Mark-read loses its
 * auto-margin so the button group hugs together on the right. */
.notification-card-foot .notification-card-thread-approve
  ~ .notification-card-mark-read { margin-left: 0; }

html.theme-dark .notification-card-thread-approve { background: #10B981; border-color: #059669; }
html.theme-dark .notification-card-thread-approve:hover { background: #059669; }
html.theme-dark .notification-card-thread-reject {
  color: #FCA5A5; border-color: #7F1D1D;
}
html.theme-dark .notification-card-thread-reject:hover { background: rgba(239,68,68,0.15); border-color: #EF4444; }

.notification-card-read-stamp {
  margin-left: auto;
  color: var(--muted, #9CA3AF);
  font-size: 11px;
}

/* Dark-mode carry-through. */
html.theme-dark .notification-card {
  background: var(--surface, #0F172A);
  border-color: var(--border, #334155);
}
html.theme-dark .notification-card.is-unread {
  background: color-mix(in srgb, #0EA5E9 10%, var(--surface, #0F172A));
}
html.theme-dark .notification-card-title { color: #F1F5F9; }
html.theme-dark .notification-card-text  { color: #CBD5E1; }
html.theme-dark .notification-card-excerpt {
  color: #D1D5DB;
  background: rgba(255, 255, 255, 0.05);
  border-left-color: #475569;
}
html.theme-dark .notification-card-kind,
html.theme-dark .notification-card-time,
html.theme-dark .notification-card-read-stamp { color: #94A3B8; }
html.theme-dark .notification-card-foot {
  border-top-color: color-mix(in srgb, #475569 65%, transparent);
}
html.theme-dark .notification-card-expand-btn,
html.theme-dark .notification-card-mark-read {
  color: #CBD5E1;
  border-color: #334155;
}
html.theme-dark #notificationsHeader .btn.is-active {
  color: #7DD3FC;
  background: color-mix(in srgb, #0EA5E9 22%, transparent);
}
/* Tab strip — one pill per kind, plus an "All" pill at the head. Sits
 * sticky at the top of the scrollable body so it stays visible while the
 * list scrolls. Horizontal scroll on overflow (many kinds → wrapping
 * would fight the sticky pattern). */
.notification-tabs {
  position: sticky;
  top: 0;
  z-index: 3;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 4px 0 12px;
  margin-bottom: 4px;
  background: var(--bg, #FFFFFF);
  border-bottom: 1px solid var(--border, #E5E7EB);
}
.notification-tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted, #4B5563);
  background: color-mix(in srgb, var(--border, #E5E7EB) 40%, transparent);
  border: 1px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease, transform 120ms ease;
}
.notification-tab:hover {
  background: color-mix(in srgb, #0EA5E9 12%, transparent);
  color: #0369A1;
}
.notification-tab.is-active {
  background: #0EA5E9;
  color: #FFFFFF;
  border-color: #0284C7;
  box-shadow: 0 2px 6px rgba(14, 165, 233, 0.35);
}
.notification-tab-label {
  line-height: 1.2;
}
.notification-tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 700;
  color: var(--muted, #4B5563);
  background: var(--surface, #FFFFFF);
  border-radius: 999px;
  border: 1px solid var(--border, #E5E7EB);
}
.notification-tab-count.has-unread {
  color: #FFFFFF;
  background: #E44C9A;
  border-color: #E44C9A;
}
.notification-tab.is-active .notification-tab-count {
  color: #0369A1;
  background: #FFFFFF;
  border-color: transparent;
}
.notification-tab.is-active .notification-tab-count.has-unread {
  color: #FFFFFF;
  background: #E44C9A;
}

html.theme-dark .notification-tabs {
  background: var(--bg, #0B1220);
  border-bottom-color: var(--border, #334155);
}
html.theme-dark .notification-tab {
  background: color-mix(in srgb, #334155 55%, transparent);
  color: #CBD5E1;
}
html.theme-dark .notification-tab:hover {
  background: color-mix(in srgb, #0EA5E9 22%, transparent);
  color: #BAE6FD;
}
html.theme-dark .notification-tab.is-active {
  background: #0EA5E9;
  color: #0B1220;
  border-color: #0284C7;
}
html.theme-dark .notification-tab-count {
  color: #CBD5E1;
  background: #1E293B;
  border-color: #334155;
}
html.theme-dark .notification-tab.is-active .notification-tab-count {
  color: #0369A1;
  background: #F1F5F9;
}
/* ═════════════════ end Notifications view ═════════════════ */

/* ═════════════════ My Messages · Channel links card ═════════════════ */
/* Per-user "Connect your channels" panel — shown inline in My Messages
   when the caller has no owned conversations, so they can self-declare
   the email / WhatsApp / Telegram / SMS identity that maps to THEIR
   inbox (separate from admin's). See app.js →
   loadAndRenderMyMessagesChannelLinks. */
.mymsg-links-card {
  border: 1px solid #E5EAF2;
  background: #FFFFFF;
  border-radius: 10px;
  padding: 16px;
  margin: 12px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
html.theme-dark .mymsg-links-card { background: #111A2C; border-color: #223047; }
.mymsg-links-card-head h3 { margin: 0 0 4px; font-size: 15px; font-weight: 700; color: #0F1E33; }
html.theme-dark .mymsg-links-card-head h3 { color: #E5E7EB; }
.mymsg-links-hint { margin: 0; font-size: 12px; color: #6B7280; line-height: 1.4; }
html.theme-dark .mymsg-links-hint { color: #94A3B8; }
.mymsg-links-hint em { color: #0078BF; font-style: normal; font-weight: 600; }

.mymsg-link-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.mymsg-link-row {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px;
  background: #F6F9FD;
  border: 1px solid #E5EAF2;
  border-radius: 8px;
  font-size: 13px;
}
html.theme-dark .mymsg-link-row { background: #0F1E33; border-color: #223047; }
.mymsg-link-badge { font-weight: 600; color: #0078BF; min-width: 92px; }
.mymsg-link-addr { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: #0F1E33; }
html.theme-dark .mymsg-link-addr { color: #E5E7EB; }
.mymsg-link-label { color: #6B7280; font-size: 12px; }
.mymsg-link-primary {
  padding: 2px 6px; font-size: 10px; font-weight: 700; text-transform: uppercase;
  color: #0078BF; background: #EAF3FB; border-radius: 4px;
}
.mymsg-link-shared {
  padding: 2px 6px; font-size: 10px; font-weight: 700; text-transform: uppercase;
  color: #B45309; background: #FEF3C7; border-radius: 4px;
}
.mymsg-link-remove {
  margin-left: auto; border: none; background: transparent; color: #B42318;
  cursor: pointer; font-size: 14px; padding: 4px 8px; border-radius: 4px;
}
.mymsg-link-remove:hover { background: #FEE4E2; }
html.theme-dark .mymsg-link-remove:hover { background: #3A1414; }

.mymsg-link-add {
  display: grid;
  grid-template-columns: 140px 1fr 160px auto;
  gap: 8px; align-items: end;
  padding-top: 8px; border-top: 1px dashed #E5EAF2;
}
html.theme-dark .mymsg-link-add { border-top-color: #223047; }
.mymsg-link-field { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: #6B7280; }
.mymsg-link-field-grow { grid-column: 2 / 3; }
.mymsg-link-field span small { font-weight: 400; color: #94A3B8; margin-left: 4px; }
.mymsg-link-field input, .mymsg-link-field select {
  padding: 7px 10px; border: 1px solid #D0D7DE; border-radius: 6px;
  font-size: 13px; background: #FFFFFF; color: #0F1E33;
}
html.theme-dark .mymsg-link-field input, html.theme-dark .mymsg-link-field select {
  background: #0B1220; color: #E5E7EB; border-color: #223047;
}
.mymsg-link-check {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: #6B7280;
  grid-column: 1 / -1; margin-top: -4px;
}
.mymsg-link-add button[type="submit"] { padding: 8px 14px; }
.mymsg-link-err {
  grid-column: 1 / -1;
  font-size: 12px; color: #B42318; margin-top: 4px; min-height: 16px;
}
@media (max-width: 640px) {
  .mymsg-link-add { grid-template-columns: 1fr; }
  .mymsg-link-field-grow { grid-column: 1 / -1; }
}
/* ═════════════════ end My Messages · Channel links card ═════════════════ */

/* P3 · Verify badge / button for email channel links */
.mymsg-link-verified {
  padding: 2px 6px; font-size: 10px; font-weight: 700; text-transform: uppercase;
  color: #047857; background: #D1FAE5; border-radius: 4px;
}
html.theme-dark .mymsg-link-verified { color: #A7F3D0; background: #063D30; }
.mymsg-link-verify {
  margin-left: 4px; padding: 2px 8px; font-size: 11px;
  color: #0078BF; background: transparent; border: 1px solid #0078BF;
  border-radius: 4px; cursor: pointer;
}
.mymsg-link-verify:hover { background: #EAF3FB; }
html.theme-dark .mymsg-link-verify:hover { background: #0F1E33; }

/* ── Connect Gmail hero banner (My Messages empty-state) ─────────── */
.mymsg-gmail-hero {
  display: flex; align-items: center; gap: 12px;
  background: linear-gradient(135deg, #E8F4FD 0%, #F0F7FF 100%);
  border: 1px solid #BAD9F1; border-radius: 10px;
  padding: 14px 16px; margin-bottom: 12px; flex-wrap: wrap;
}
html.theme-dark .mymsg-gmail-hero {
  background: linear-gradient(135deg, #0F2236 0%, #0A1A2E 100%);
  border-color: #1E3A55;
}
.mymsg-gmail-hero-icon { font-size: 28px; flex-shrink: 0; }
.mymsg-gmail-hero-text {
  display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 160px;
}
.mymsg-gmail-hero-text strong {
  font-size: 14px; font-weight: 700; color: #0F1E33;
}
html.theme-dark .mymsg-gmail-hero-text strong { color: #E5E7EB; }
.mymsg-gmail-hero-text span {
  font-size: 12px; color: #4B5563; line-height: 1.4;
}
html.theme-dark .mymsg-gmail-hero-text span { color: #94A3B8; }
.mymsg-connect-gmail-btn {
  white-space: nowrap; padding: 8px 16px; font-size: 13px;
}

/* ── Connect Gmail shortcut row inside the channel-links card ─────── */
.mymsg-gmail-shortcut {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 0 10px; border-top: 1px solid #E5E7EB; margin-top: 8px;
}
html.theme-dark .mymsg-gmail-shortcut { border-color: #223047; }
.mymsg-gmail-shortcut-label { font-size: 12px; color: #6B7280; flex-shrink: 0; }
html.theme-dark .mymsg-gmail-shortcut-label { color: #94A3B8; }

/* ── Inline status messages (ok / warn / err) ─────────────────────── */
.mymsg-gmail-status {
  font-size: 12px; min-height: 16px; flex-basis: 100%;
}
.mymsg-gmail-status-ok  { color: #047857; }
.mymsg-gmail-status-warn { color: #B45309; }
.mymsg-gmail-status-err  { color: #B42318; }
html.theme-dark .mymsg-gmail-status-ok  { color: #34D399; }
html.theme-dark .mymsg-gmail-status-warn { color: #FCD34D; }
html.theme-dark .mymsg-gmail-status-err  { color: #F87171; }

/* ------------------------------------------------------------------
 * MIS Dashboard (admin-only) — sidebar entry re-uses the existing
 * .sidebar-dashboard-btn class defined earlier in this file, so no
 * new sidebar rules are needed here.  Only the view-specific styles
 * (KPI tiles + chart cards + refresh chrome) live below.
 * ------------------------------------------------------------------ */
.mis-dashboard-view {
  padding: 20px 24px; max-width: 1400px; margin: 0 auto;
  overflow-y: auto; height: 100%;
}
.mis-dashboard-view.hidden { display: none; }

.mis-dashboard-head {
  /* Tightened 13 Jul 2026: after the inline "📅 Range" bar was consolidated
     into the top-right dropdown, the header can shed the extra padding /
     margin block. Keeps Refresh + dropdown aligned on a single row on wide
     screens and wraps cleanly on narrow screens. */
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 0; gap: 10px; flex-wrap: wrap;
  min-height: 32px;
}
.mis-dashboard-head h2 {
  margin: 0; font-size: 20px; font-weight: 700;
  color: var(--fg, #0F172A); line-height: 1.15;
}
.mis-dashboard-sub {
  margin: 2px 0 8px 0; font-size: 12px;
  color: var(--muted, #64748B);
}
.mis-dashboard-refresh {
  padding: 5px 12px; font-size: 12px; font-weight: 600;
  color: #0078BF; background: transparent;
  border: 1px solid #0078BF; border-radius: 6px;
  cursor: pointer;
}
.mis-dashboard-refresh:hover { background: #EAF3FB; }
html.theme-dark .mis-dashboard-refresh:hover { background: #0F1E33; }

.mis-dashboard-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px; margin-bottom: 22px;
}
.mis-kpi {
  padding: 16px 18px; background: var(--card, #FFFFFF);
  border: 1px solid var(--border, #E2E8F0); border-radius: 10px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}
html.theme-dark .mis-kpi {
  background: #0B1626; border-color: #1E2E45;
}
.mis-kpi-label {
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--muted, #64748B);
  margin-bottom: 8px;
}
.mis-kpi-value {
  font-size: 28px; font-weight: 700; line-height: 1;
  color: var(--fg, #0F172A);
}
html.theme-dark .mis-kpi-value { color: #F1F5F9; }
.mis-kpi[data-kpi="alerts"]     .mis-kpi-value { color: #DC2626; }
.mis-kpi[data-kpi="approvals"]  .mis-kpi-value { color: #D97706; }
.mis-kpi[data-kpi="threads"]    .mis-kpi-value { color: #0078BF; }
.mis-kpi[data-kpi="tasks"]      .mis-kpi-value { color: #059669; }

.mis-dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 16px;
}
.mis-chart-card {
  padding: 16px 18px; background: var(--card, #FFFFFF);
  border: 1px solid var(--border, #E2E8F0); border-radius: 10px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.04);
  min-height: 320px; display: flex; flex-direction: column;
}
html.theme-dark .mis-chart-card {
  background: #0B1626; border-color: #1E2E45;
}
.mis-chart-card h3 {
  margin: 0 0 12px 0; font-size: 14px; font-weight: 700;
  color: var(--fg, #0F172A);
}
html.theme-dark .mis-chart-card h3 { color: #F1F5F9; }
.mis-chart-card canvas { flex: 1 1 auto; max-height: 280px; }
.mis-chart-card-wide { grid-column: 1 / -1; min-height: 380px; }
.mis-chart-card-wide canvas { max-height: 340px; }

.mis-dashboard-status {
  padding: 10px 14px; margin-top: 14px;
  font-size: 12px; color: var(--muted, #64748B);
  text-align: center;
}
.mis-dashboard-status.error { color: #DC2626; }

/* ═════════════════ Team-adoption MIS block (4 Jul 2026) ═════════════════
 * Extends the admin MIS Dashboard with per-user adoption metrics: 5 KPI
 * tiles, band distribution donut, weekly-active trend, sortable
 * leaderboard, drill-down slide-over. Admin-only surface — endpoint
 * enforces role check server-side. */
.mis-adoption-section { margin-top: 24px; padding-top: 20px; border-top: 1px dashed rgba(0, 0, 0, 0.12); }
html.theme-dark .mis-adoption-section { border-top-color: rgba(255, 255, 255, 0.12); }
.mis-adoption-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 12px; gap: 12px; flex-wrap: wrap; }
.mis-adoption-head h3 { margin: 0; font-size: 16px; }
.mis-adoption-sub { font-size: 12px; color: #6B7280; }
.mis-adoption-sub.error { color: #DC2626; }
html.theme-dark .mis-adoption-sub { color: #9CA3AF; }

/* ── Unified range dropdown + custom-date popover (refined 13 Jul 2026) ──
   The old "📅 Range" from/to bar has been removed; all date filtering now
   lives in the top-right dropdown. `.mis-range-wrap` positions the popover
   flush against the dropdown so the anchor stays stable across resizes. */
.mis-range-wrap { position: relative; display: inline-flex; }
/* Popover is `position: fixed` so it isn't clipped by the tab strip's
   horizontal overflow. JS reads the dropdown's bounding rect and sets
   top/right on the element at open time. */
.mis-range-popover {
  position: fixed; z-index: 200;
  min-width: 240px;
  background: var(--card, #FFFFFF);
  border: 1px solid var(--border, #E2E8F0);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
  padding: 12px;
  display: flex; flex-direction: column; gap: 8px;
}
html.theme-dark .mis-range-popover { background: #0B1626; border-color: #1E2E45; box-shadow: 0 8px 24px rgba(0,0,0,0.4); }
.mis-range-popover[hidden] { display: none; }
.mis-range-popover-row { display: flex; align-items: center; gap: 8px; font-size: 12px; }
.mis-range-popover-row label {
  flex: 0 0 44px; color: #6B7280;
  text-transform: uppercase; letter-spacing: 0.03em; font-size: 10px; font-weight: 600;
}
html.theme-dark .mis-range-popover-row label { color: #9CA3AF; }
.mis-range-popover-row input[type="date"] {
  flex: 1 1 auto;
  padding: 5px 8px; font-size: 12px;
  border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 4px;
  background: #fff; color: inherit; font-family: inherit;
}
html.theme-dark .mis-range-popover-row input[type="date"] {
  border-color: rgba(255, 255, 255, 0.15);
  background: rgba(255, 255, 255, 0.06);
  color-scheme: dark;
}
.mis-range-popover-actions { display: flex; justify-content: flex-end; gap: 6px; margin-top: 4px; }
.mis-range-popover-apply, .mis-range-popover-cancel {
  padding: 5px 12px; font-size: 12px; font-weight: 600;
  border-radius: 4px; cursor: pointer; border: 1px solid transparent;
}
.mis-range-popover-apply { background: #0078BF; color: #fff; border-color: #0078BF; }
.mis-range-popover-apply:hover { background: #005E96; }
.mis-range-popover-cancel { background: transparent; color: inherit; border-color: rgba(0, 0, 0, 0.15); }
.mis-range-popover-cancel:hover { background: rgba(0, 0, 0, 0.05); }
html.theme-dark .mis-range-popover-cancel { border-color: rgba(255, 255, 255, 0.15); }
html.theme-dark .mis-range-popover-cancel:hover { background: rgba(255, 255, 255, 0.05); }

/* Retired 13 Jul 2026 — the inline adoption "📅 Range" bar (`.mis-adoption-range*`)
   was consolidated into the top-right #misRange dropdown. All styles below
   this line previously matched that DOM and are intentionally removed. */

/* KPI card + table cell surface for range-scoped numbers */
.mis-kpi.mis-kpi-range { border-left: 3px solid #7C3AED; }
html.theme-dark .mis-kpi.mis-kpi-range { border-left-color: #A78BFA; }
.mis-adoption-table td.range-cell { color: #6D28D9; font-weight: 700; background: rgba(124, 58, 237, 0.06); }
html.theme-dark .mis-adoption-table td.range-cell { color: #C4B5FD; background: rgba(124, 58, 237, 0.14); }
.mis-drill-cell.mis-drill-range { grid-column: 1 / -1; background: rgba(124, 58, 237, 0.08); }
html.theme-dark .mis-drill-cell.mis-drill-range { background: rgba(124, 58, 237, 0.16); }
.mis-adoption-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 16px; }
.mis-kpi-adopt .mis-kpi-sub { font-size: 10px; opacity: 0.7; margin-top: 2px; }
.mis-adopt-charts { grid-template-columns: 1fr 1fr; margin-bottom: 20px; }
@media (max-width: 720px) { .mis-adopt-charts { grid-template-columns: 1fr; } }
.mis-adoption-table-wrap { background: rgba(0, 120, 191, 0.03); border: 1px solid rgba(0, 0, 0, 0.08); border-radius: 6px; overflow: hidden; }
html.theme-dark .mis-adoption-table-wrap { background: rgba(0, 120, 191, 0.06); border-color: rgba(255, 255, 255, 0.1); }
.mis-adoption-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 10px; background: rgba(0, 0, 0, 0.03); flex-wrap: wrap; }
html.theme-dark .mis-adoption-toolbar { background: rgba(255, 255, 255, 0.03); }
.mis-adoption-search { flex: 1; min-width: 180px; padding: 5px 10px; font-size: 12px; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 4px; background: transparent; color: inherit; }
html.theme-dark .mis-adoption-search { border-color: rgba(255, 255, 255, 0.15); }
.mis-adoption-legend { display: flex; gap: 8px; font-size: 10px; flex-wrap: wrap; }
.band-dot { padding: 2px 6px; border-radius: 3px; }
.mis-adoption-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.mis-adoption-table thead th { padding: 8px 6px; text-align: left; font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em; color: #6B7280; background: rgba(0, 0, 0, 0.02); cursor: pointer; user-select: none; border-bottom: 1px solid rgba(0, 0, 0, 0.08); white-space: nowrap; }
html.theme-dark .mis-adoption-table thead th { color: #9CA3AF; background: rgba(255, 255, 255, 0.02); border-bottom-color: rgba(255, 255, 255, 0.08); }
.mis-adoption-table thead th:hover { background: rgba(0, 120, 191, 0.08); color: #0078BF; }
.mis-adoption-table tbody tr { cursor: pointer; border-bottom: 1px solid rgba(0, 0, 0, 0.04); }
html.theme-dark .mis-adoption-table tbody tr { border-bottom-color: rgba(255, 255, 255, 0.04); }
.mis-adoption-table tbody tr:hover { background: rgba(0, 120, 191, 0.06); }
.mis-adoption-table td { padding: 8px 6px; vertical-align: middle; }
.mis-adoption-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.mis-adoption-table td.num .dim { color: #9CA3AF; font-size: 11px; }
.mis-adoption-table td.setup-cell { text-align: center; letter-spacing: 2px; }
.setup-tick.on { color: #059669; font-weight: 700; }
.setup-tick.off { color: rgba(0, 0, 0, 0.2); }
html.theme-dark .setup-tick.off { color: rgba(255, 255, 255, 0.2); }
.mis-adopt-member .row-name { font-weight: 600; }
.mis-adopt-member .row-meta { font-size: 10px; color: #6B7280; margin-top: 2px; }
html.theme-dark .mis-adopt-member .row-meta { color: #9CA3AF; }
.row-role { text-transform: uppercase; letter-spacing: 0.05em; }
.band-chip { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 600; white-space: nowrap; }
.band-chip.band-power    { background: #D1FAE5; color: #047857; }
.band-chip.band-regular  { background: #FEF3C7; color: #92400E; }
.band-chip.band-light    { background: #FED7AA; color: #C2410C; }
.band-chip.band-dormant  { background: #FEE2E2; color: #B42318; }
html.theme-dark .band-chip.band-power   { background: #063D30; color: #A7F3D0; }
html.theme-dark .band-chip.band-regular { background: #3B2A0A; color: #FCD34D; }
html.theme-dark .band-chip.band-light   { background: #3B1D0D; color: #FDBA74; }
html.theme-dark .band-chip.band-dormant { background: #3B1315; color: #FCA5A5; }
.mis-adopt-empty { padding: 20px; text-align: center; color: #6B7280; font-style: italic; }
.mis-adoption-drilldown { margin-top: 16px; padding: 14px; background: #F9FAFB; border: 1px solid rgba(0, 0, 0, 0.1); border-radius: 6px; }
html.theme-dark .mis-adoption-drilldown { background: #111A2C; border-color: rgba(255, 255, 255, 0.1); }
.mis-drill-head { display: flex; justify-content: space-between; align-items: start; gap: 12px; margin-bottom: 12px; }
.mis-drill-head h4 { margin: 0 0 4px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; }
.mis-drill-sub { font-size: 11px; color: #6B7280; }
html.theme-dark .mis-drill-sub { color: #9CA3AF; }
.mis-drill-close { padding: 4px 10px; font-size: 11px; color: inherit; background: transparent; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 4px; cursor: pointer; }
html.theme-dark .mis-drill-close { border-color: rgba(255, 255, 255, 0.2); }
.mis-drill-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; }
.mis-drill-cell { display: flex; flex-direction: column; gap: 2px; padding: 6px 10px; background: rgba(0, 120, 191, 0.04); border-radius: 4px; }
html.theme-dark .mis-drill-cell { background: rgba(0, 120, 191, 0.08); }
.mis-drill-cell label { font-size: 10px; color: #6B7280; text-transform: uppercase; letter-spacing: 0.03em; }
html.theme-dark .mis-drill-cell label { color: #9CA3AF; }
.mis-drill-cell span { font-size: 13px; font-weight: 500; }
.mis-drill-setup span { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.setup-badge { padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 600; }
.setup-badge.on  { background: #D1FAE5; color: #047857; }
.setup-badge.off { background: rgba(0, 0, 0, 0.05); color: #9CA3AF; }
html.theme-dark .setup-badge.on  { background: #063D30; color: #A7F3D0; }
html.theme-dark .setup-badge.off { background: rgba(255, 255, 255, 0.05); color: #6B7280; }

/* 24h adoption signals — added 4 Jul 2026 alongside "Last 24h" column */
.mis-kpi.mis-kpi-24h { border-left: 3px solid #059669; }
html.theme-dark .mis-kpi.mis-kpi-24h { border-left-color: #10B981; }
.mis-adopt-row .num.last24-active {
  color: #047857; font-weight: 700;
  background: rgba(16, 185, 129, 0.08);
}
.mis-adopt-row .num.last24-idle {
  color: #9CA3AF; font-weight: 500;
}
html.theme-dark .mis-adopt-row .num.last24-active { color: #6EE7B7; background: rgba(16, 185, 129, 0.15); }
html.theme-dark .mis-adopt-row .num.last24-idle { color: #6B7280; }
.mis-adopt-row .pulse-dot {
  display: inline-block; margin-left: 4px; color: #10B981; font-size: 10px;
  animation: pulseDot 1.8s ease-in-out infinite;
}
@keyframes pulseDot { 0%,100% { opacity: 0.35; } 50% { opacity: 1; } }

/* Fixable Setup tick (currently just Telegram) — clickable "✎" so admins
   spot at a glance which cells they can act on from the drilldown.
   Added 13 Jul 2026 alongside "Send Telegram link code" inline action. */
.setup-tick.off.fixable {
  color: #0078BF;
  cursor: pointer;
  border-bottom: 1px dashed rgba(0, 120, 191, 0.5);
  padding: 0 2px;
  font-weight: 600;
}
.setup-tick.off.fixable:hover { color: #0056A3; border-bottom-color: #0078BF; }
html.theme-dark .setup-tick.off.fixable { color: #60A5FA; border-bottom-color: rgba(96, 165, 250, 0.5); }
html.theme-dark .setup-tick.off.fixable:hover { color: #93C5FD; border-bottom-color: #60A5FA; }

/* Gap-fill actions panel inside the adoption drilldown — the "Help this
   member finish setup" section. Rendered by _renderDrillActions() when
   any setup step is missing. */
.mis-drill-actions {
  margin-top: 14px;
  padding: 12px;
  border-radius: 6px;
  background: rgba(0, 120, 191, 0.05);
  border: 1px solid rgba(0, 120, 191, 0.15);
}
html.theme-dark .mis-drill-actions {
  background: rgba(0, 120, 191, 0.09);
  border-color: rgba(0, 120, 191, 0.28);
}
.mis-drill-actions-title {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #0078BF;
  margin-bottom: 10px;
}
html.theme-dark .mis-drill-actions-title { color: #60A5FA; }
.mis-drill-action {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px;
  background: #FFFFFF;
  border-radius: 5px;
  border: 1px solid rgba(0, 0, 0, 0.08);
}
html.theme-dark .mis-drill-action {
  background: #0F1F35;
  border-color: rgba(255, 255, 255, 0.08);
}
.mis-drill-action + .mis-drill-action { margin-top: 8px; }
.mis-drill-action-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.mis-drill-action-icon { font-size: 20px; line-height: 1; }
.mis-drill-action h5 { margin: 0 0 2px 0; font-size: 13px; font-weight: 600; }
.mis-drill-action-sub { font-size: 11px; color: #6B7280; line-height: 1.4; }
html.theme-dark .mis-drill-action-sub { color: #9CA3AF; }
.mis-drill-action-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.mis-drill-action-btn {
  align-self: flex-start;
  padding: 6px 14px;
  font-size: 12px;
  font-weight: 600;
  color: #FFFFFF;
  background: #0078BF;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.mis-drill-action-btn:hover:not(:disabled) { background: #0056A3; }
.mis-drill-action-btn:disabled { opacity: 0.6; cursor: not-allowed; }
.mis-drill-action-result {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-top: 4px;
}
.mis-tg-code-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.mis-tg-label {
  font-size: 10px;
  font-weight: 600;
  color: #6B7280;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  min-width: 40px;
}
html.theme-dark .mis-tg-label { color: #9CA3AF; }
.mis-tg-code {
  font-family: 'SF Mono', ui-monospace, Menlo, monospace;
  font-size: 13px;
  padding: 4px 8px;
  background: rgba(0, 120, 191, 0.08);
  border-radius: 3px;
  color: #0056A3;
  font-weight: 600;
  overflow-wrap: anywhere;
  max-width: 100%;
}
html.theme-dark .mis-tg-code {
  background: rgba(96, 165, 250, 0.15);
  color: #93C5FD;
}
.mis-tg-code.mis-tg-link { font-size: 11px; font-weight: 500; }
.mis-tg-copy {
  padding: 3px 8px;
  font-size: 11px;
  color: #0078BF;
  background: transparent;
  border: 1px solid #0078BF;
  border-radius: 3px;
  cursor: pointer;
}
.mis-tg-copy:hover { background: rgba(0, 120, 191, 0.08); }
html.theme-dark .mis-tg-copy { color: #60A5FA; border-color: #60A5FA; }
html.theme-dark .mis-tg-copy:hover { background: rgba(96, 165, 250, 0.15); }
.mis-tg-deeplink {
  padding: 3px 8px;
  font-size: 11px;
  color: #FFFFFF;
  background: #0088CC; /* Telegram brand */
  border-radius: 3px;
  text-decoration: none;
  font-weight: 600;
}
.mis-tg-deeplink:hover { background: #006DA6; }
.mis-tg-hint {
  font-size: 11px;
  color: #6B7280;
  line-height: 1.4;
  padding: 6px 8px;
  background: rgba(0, 0, 0, 0.02);
  border-radius: 3px;
}
html.theme-dark .mis-tg-hint { color: #9CA3AF; background: rgba(255, 255, 255, 0.03); }
.mis-tg-hint em { font-style: normal; color: #B45309; font-weight: 500; }
html.theme-dark .mis-tg-hint em { color: #FCD34D; }
.mis-tg-hint.ok { color: #047857; background: rgba(16, 185, 129, 0.08); }
html.theme-dark .mis-tg-hint.ok { color: #6EE7B7; background: rgba(16, 185, 129, 0.15); }
.mis-tg-hint.err { color: #B42318; background: rgba(220, 38, 38, 0.08); }
html.theme-dark .mis-tg-hint.err { color: #FCA5A5; background: rgba(220, 38, 38, 0.15); }


/* ═══════════════════════════════════════════════════════════════════
   IMAGINE VISION · infinite sticky-note canvas · 4 Jul 2026
   ═══════════════════════════════════════════════════════════════════ */
#imagineVisionView {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  overflow: hidden;
  background: linear-gradient(180deg, #F8FAFC 0%, #EEF2F7 100%);
}
.imagine-vision-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 22px;
  border-bottom: 1px solid rgba(15, 23, 42, 0.08);
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(8px);
  flex-shrink: 0;
}
.imagine-vision-header h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  color: #0F172A;
}
.imagine-vision-header .chat-subtitle {
  font-size: 12px;
  color: #64748B;
}
.imagine-vision-toolbar {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.iv-toolbar-divider {
  width: 1px;
  height: 22px;
  background: rgba(15, 23, 42, 0.12);
  margin: 0 4px;
}
.iv-zoom-label {
  min-width: 46px;
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  color: #334155;
  padding: 4px 6px;
  background: rgba(0, 120, 191, 0.08);
  border-radius: 4px;
}

/* Canvas wrapper — the infinite viewport. Layers inside are transformed. */
.iv-canvas-wrap {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  cursor: default;
  outline: none;
  background-image: radial-gradient(circle, rgba(15, 23, 42, 0.14) 1px, transparent 1px);
  background-size: 24px 24px;
  background-position: 0 0;
}
.iv-canvas-wrap:focus-visible {
  box-shadow: inset 0 0 0 2px #0078BF;
}
.iv-notes-layer,
.iv-edges-layer,
.iv-drag-edge-layer {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  pointer-events: none;
}
.iv-notes-layer > * { pointer-events: auto; }
.iv-edges-layer,
.iv-drag-edge-layer {
  overflow: visible;
}
.iv-edges-layer .iv-edge {
  stroke: #94A3B8;
  stroke-width: 2;
  fill: none;
  pointer-events: stroke;
  cursor: pointer;
}
.iv-edges-layer .iv-edge:hover { stroke: #0078BF; }
.iv-edges-layer .iv-edge.is-selected {
  stroke: #E44C9A;
  stroke-width: 3;
}
.iv-drag-edge-layer .iv-edge-preview {
  stroke: #0078BF;
  stroke-width: 2;
  stroke-dasharray: 6 4;
  opacity: 0.85;
}

/* Sticky notes */
.iv-note {
  position: absolute;
  border-radius: 8px;
  padding: 22px 12px 12px;
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.12), 0 8px 20px rgba(15, 23, 42, 0.06);
  cursor: grab;
  user-select: none;
  transition: box-shadow 120ms ease;
  will-change: transform;
  font-family: 'Raleway', system-ui, sans-serif;
}
.iv-note:active { cursor: grabbing; }
.iv-note.is-selected {
  box-shadow: 0 0 0 2px #0078BF, 0 2px 6px rgba(15, 23, 42, 0.14), 0 8px 20px rgba(15, 23, 42, 0.08);
}
.iv-note-yellow { background: #FEF3C7; color: #78350F; }
.iv-note-pink   { background: #FCE7F3; color: #831843; }
.iv-note-blue   { background: #DBEAFE; color: #1E3A8A; }
.iv-note-green  { background: #D1FAE5; color: #064E3B; }
.iv-note-purple { background: #EDE9FE; color: #4C1D95; }
.iv-note-orange { background: #FED7AA; color: #7C2D12; }

.iv-note-text {
  width: 100%;
  height: 100%;
  font-size: 14px;
  line-height: 1.35;
  overflow: auto;
  outline: none;
  white-space: pre-wrap;
  word-wrap: break-word;
  cursor: text;
}
.iv-note-text[contenteditable="true"] {
  cursor: text;
  background: rgba(255, 255, 255, 0.4);
  border-radius: 4px;
}

.iv-note-chip,
.iv-note-delete {
  position: absolute;
  top: 4px;
  width: 16px;
  height: 16px;
  border: none;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  font-size: 11px;
  line-height: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.55;
  transition: opacity 120ms ease, transform 120ms ease;
}
.iv-note-chip {
  right: 6px;
  background: linear-gradient(135deg, #FEF3C7, #E44C9A, #0078BF);
  color: transparent;
}
.iv-note-delete {
  left: 6px;
  background: rgba(15, 23, 42, 0.12);
  color: #0F172A;
  font-weight: 700;
}
.iv-note:hover .iv-note-chip,
.iv-note:hover .iv-note-delete,
.iv-note.is-selected .iv-note-chip,
.iv-note.is-selected .iv-note-delete {
  opacity: 1;
}
.iv-note-chip:hover  { transform: scale(1.1); }
.iv-note-delete:hover{ transform: scale(1.1); background: #E44C9A; color: #fff; }

/* Connect handle — always visible so the "how do I connect?" question
   never has to be asked. Bigger hit-target (24px) + a clear "→" affordance
   so users know what to drag from. */
.iv-note-handle {
  position: absolute;
  bottom: -10px;
  right: -10px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #0078BF;
  box-shadow: 0 0 0 2px #fff, 0 2px 6px rgba(15, 23, 42, 0.25);
  cursor: crosshair;
  opacity: 0.65;
  transition: opacity 120ms ease, transform 120ms ease, background 120ms ease;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  z-index: 2;
}
.iv-note-handle::before {
  content: '→';
  display: block;
  transform: rotate(-45deg);
}
.iv-note:hover .iv-note-handle,
.iv-note.is-selected .iv-note-handle {
  opacity: 1;
  transform: scale(1.05);
}
.iv-note-handle:hover {
  opacity: 1;
  transform: scale(1.15);
  background: #005E96;
}
/* When the board is in linking mode (a handle-drag is in flight), give
   every note a subtle target-outline so the user sees what they can drop on. */
.iv-canvas-wrap.iv-linking .iv-note {
  outline: 2px dashed rgba(0, 120, 191, 0.4);
  outline-offset: 4px;
}
.iv-canvas-wrap.iv-linking .iv-note:hover {
  outline: 2px solid #E44C9A;
  outline-offset: 4px;
}

/* Empty-state hint */
.iv-empty-hint {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  color: #64748B;
}
.iv-empty-hint.hidden { display: none; }
.iv-empty-hint-inner {
  text-align: center;
  padding: 24px 32px;
  background: rgba(255, 255, 255, 0.85);
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(15, 23, 42, 0.08);
  max-width: 380px;
}
.iv-empty-hint-icon {
  font-size: 36px;
  margin-bottom: 8px;
}
.iv-empty-hint-title {
  font-size: 16px;
  font-weight: 700;
  color: #0F172A;
  margin-bottom: 4px;
}
.iv-empty-hint-body {
  font-size: 13px;
  line-height: 1.5;
}

/* Mini-App parity — the same board embedded in Telegram. */
.iv-mini-wrap {
  position: relative;
  width: 100%;
  height: calc(100vh - 180px);
  min-height: 320px;
  background-image: radial-gradient(circle, rgba(15, 23, 42, 0.14) 1px, transparent 1px);
  background-size: 20px 20px;
  overflow: hidden;
  border-radius: 8px;
  border: 1px solid rgba(15, 23, 42, 0.08);
  touch-action: none;
}
.iv-mini-toolbar {
  display: flex;
  gap: 6px;
  padding: 8px;
  align-items: center;
  flex-wrap: wrap;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 8px;
  margin-bottom: 8px;
}
.iv-mini-toolbar button {
  padding: 6px 10px;
  font-size: 12px;
  border: 1px solid rgba(15, 23, 42, 0.12);
  background: #fff;
  border-radius: 6px;
  cursor: pointer;
}
.iv-mini-toolbar button:active { background: #EEF2F7; }
.iv-mini-toolbar .iv-zoom-label { background: rgba(0, 120, 191, 0.1); }
/* When a mini-app connection is armed, every note gets a dashed outline so
   the user sees the tap-target. */
.iv-mini-wrap.iv-linking [data-note-id] {
  outline: 2px dashed rgba(0, 120, 191, 0.55);
  outline-offset: 4px;
}

/* ═════════════════ end Imagine Vision styles ═════════════════ */

/* ═════════════════════════════════════════════════════════════════
 * Admin MIS Dashboard — Phase 1 tabs + reliability + recovery
 * (see docs/mis-dashboard-roadmap.md for scope)
 * ═════════════════════════════════════════════════════════════════ */
.mis-tabs {
  display: flex; align-items: center; gap: 4px;
  margin: 4px 0 12px 0;
  border-bottom: 1px solid var(--border, #E2E8F0);
  overflow-x: auto;
  overflow-y: visible; /* let the range popover escape the tab strip */
  padding-bottom: 0;
}
.mis-tab {
  padding: 8px 14px; font-size: 13px; font-weight: 600;
  color: var(--muted, #64748B);
  background: transparent; border: none; cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 120ms ease, border-color 120ms ease;
  white-space: nowrap;
}
.mis-tab:hover { color: #0078BF; }
.mis-tab.is-active { color: #0078BF; border-bottom-color: #0078BF; }
.mis-tab-spacer { flex: 1 1 auto; }
.mis-range {
  padding: 6px 10px; font-size: 12px; font-weight: 600;
  color: var(--fg, #0F172A); background: var(--card, #FFFFFF);
  border: 1px solid var(--border, #E2E8F0); border-radius: 6px;
  cursor: pointer;
}
html.theme-dark .mis-range { background: #0B1626; color: #F1F5F9; border-color: #1E2E45; }
.mis-tab-panel[hidden] { display: none !important; }

/* Shared MIS helpers */
.mis-empty { padding: 20px; text-align: center; color: var(--muted, #64748B); font-size: 13px; }
.mis-muted { color: var(--muted, #64748B); font-size: 12px; }
.mis-section-note {
  margin: -4px 0 10px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--muted, #64748B);
}
.mis-table tr.is-archived td { opacity: 0.62; }
.mis-toolbar { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; flex-wrap: wrap; }
.mis-search-input, .mis-select {
  padding: 6px 10px; font-size: 12px;
  border: 1px solid var(--border, #E2E8F0); border-radius: 6px;
  background: var(--card, #FFFFFF); color: var(--fg, #0F172A);
  min-width: 200px;
}
html.theme-dark .mis-search-input, html.theme-dark .mis-select { background: #0B1626; color: #F1F5F9; border-color: #1E2E45; }
.mis-export-btn {
  padding: 6px 12px; font-size: 12px; font-weight: 600;
  color: #0078BF; background: transparent;
  border: 1px solid #0078BF; border-radius: 6px; cursor: pointer;
  margin-left: auto;
}
.mis-export-btn:hover { background: #EAF3FB; }
html.theme-dark .mis-export-btn:hover { background: #0F1E33; }

/* Reusable simple table for MIS tabs */
.mis-table-wrap { overflow-x: auto; }
.mis-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.mis-table th, .mis-table td {
  padding: 8px 10px; text-align: left;
  border-bottom: 1px solid var(--border, #E2E8F0);
  vertical-align: top;
}
.mis-table th { font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted, #64748B); }
.mis-table code { font-size: 11px; }
html.theme-dark .mis-table th, html.theme-dark .mis-table td { border-color: #1E2E45; }

/* Reliability & Recovery — item cards */
.mis-reliability-actions { margin: 10px 0 14px 0; }
.mis-recovery-note {
  padding: 10px 12px; margin-top: 8px;
  font-size: 12px; color: var(--muted, #64748B);
  background: #F8FAFC; border-left: 3px solid #0078BF; border-radius: 4px;
}
html.theme-dark .mis-recovery-note { background: #0F1E33; color: #94A3B8; }
.mis-recovery-note b { color: var(--fg, #0F172A); }
html.theme-dark .mis-recovery-note b { color: #F1F5F9; }

.mis-recovery-list { display: flex; flex-direction: column; gap: 10px; }
.mis-rec-item {
  padding: 12px 14px;
  background: var(--card, #FFFFFF);
  border: 1px solid var(--border, #E2E8F0);
  border-left: 3px solid #94A3B8;
  border-radius: 8px;
}
.mis-rec-item[data-status="stale"] { border-left-color: #DC2626; }
.mis-rec-item[data-status="fresh"] { border-left-color: #059669; }
.mis-rec-item[data-status="errored"] { border-left-color: #D97706; }
html.theme-dark .mis-rec-item { background: #0B1626; border-color: #1E2E45; }
.mis-rec-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.mis-rec-age { margin-left: auto; font-size: 11px; color: var(--muted, #64748B); }
.mis-rec-body { font-size: 13px; }
.mis-rec-who, .mis-rec-where { margin: 3px 0; }
.mis-rec-excerpt {
  margin-top: 8px; padding: 8px 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px; line-height: 1.5;
  background: #F1F5F9; border-radius: 4px;
  white-space: pre-wrap; word-break: break-word;
  max-height: 120px; overflow: auto;
}
html.theme-dark .mis-rec-excerpt { background: #0F1E33; color: #CBD5E1; }
.mis-rec-error {
  margin-top: 6px; padding: 8px 10px;
  font-size: 12px; color: #B91C1C;
  background: #FEF2F2; border-radius: 4px;
}
html.theme-dark .mis-rec-error { background: rgba(220,38,38,0.15); color: #FCA5A5; }
.mis-rec-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.mis-rec-action {
  padding: 5px 12px; font-size: 12px; font-weight: 600;
  border-radius: 6px; cursor: pointer;
  border: 1px solid;
}
.mis-rec-action[disabled] { opacity: 0.6; cursor: progress; }
.mis-btn-primary { color: #FFF; background: #0078BF; border-color: #0078BF; }
.mis-btn-primary:hover { background: #005A94; }
.mis-btn-good { color: #FFF; background: #059669; border-color: #059669; }
.mis-btn-good:hover { background: #047857; }
.mis-btn-danger { color: #B91C1C; background: transparent; border-color: #FCA5A5; }
.mis-btn-danger:hover { background: rgba(239,68,68,0.10); border-color: #EF4444; }

/* Status badges */
.mis-badge {
  padding: 2px 8px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em;
  border-radius: 4px;
}
.mis-badge-ok { color: #065F46; background: #D1FAE5; }
.mis-badge-warn { color: #92400E; background: #FEF3C7; }
.mis-badge-err { color: #991B1B; background: #FEE2E2; }
.mis-badge-neutral { color: #475569; background: #E2E8F0; }
html.theme-dark .mis-badge-ok { color: #A7F3D0; background: rgba(5,150,105,0.20); }
html.theme-dark .mis-badge-warn { color: #FDE68A; background: rgba(217,119,6,0.20); }
html.theme-dark .mis-badge-err { color: #FCA5A5; background: rgba(220,38,38,0.20); }
html.theme-dark .mis-badge-neutral { color: #CBD5E1; background: rgba(148,163,184,0.20); }

/* KPI value colours per data-kpi bucket (extends the existing overview palette) */
.mis-kpi[data-kpi="alerts"]     .mis-kpi-value { color: #DC2626; }
.mis-kpi[data-kpi="approvals"]  .mis-kpi-value { color: #D97706; }
.mis-kpi[data-kpi="threads"]    .mis-kpi-value { color: #0078BF; }
.mis-kpi[data-kpi="tasks"]      .mis-kpi-value { color: #059669; }

/* ── Phase 1.5 tabs (AI Generations · Content & Activity · Security) ──
   Everything already reuses .mis-tab / .mis-kpi / .mis-table / .mis-rec-item.
   These tweaks polish density + wrap for the higher tab count. */
.mis-tabs { flex-wrap: wrap; row-gap: 2px; }
.mis-tab { padding: 10px 12px; }
/* Chart cards get a floor height so empty datasets don't collapse to zero. */
.mis-tab-panel[data-tab="ai"] .mis-chart-card canvas,
.mis-tab-panel[data-tab="content"] .mis-chart-card canvas,
.mis-tab-panel[data-tab="security"] .mis-chart-card canvas,
.mis-tab-panel[data-tab="hiring"] .mis-chart-card canvas,
.mis-tab-panel[data-tab="ops"] .mis-chart-card canvas,
.mis-tab-panel[data-tab="support"] .mis-chart-card canvas,
.mis-tab-panel[data-tab="agents"] .mis-chart-card canvas {
  min-height: 220px; max-height: 340px;
}
/* Security + Agents alerts list inside a chart card shouldn't inherit chart padding. */
.mis-tab-panel[data-tab="security"] .mis-recovery-list,
.mis-tab-panel[data-tab="agents"] .mis-recovery-list {
  max-height: 520px; overflow-y: auto;
}
/* Content-tab table cells wrap gracefully for long project cwds. */
.mis-tab-panel[data-tab="content"] .mis-table code,
.mis-tab-panel[data-tab="agents"] .mis-table code,
.mis-tab-panel[data-tab="ops"] .mis-table code { word-break: break-all; }

/* ── Prompt Failures tab ─────────────────────────────────────────── */
/* Reason bars */
.mis-fail-reasons { display: flex; flex-direction: column; gap: 8px; padding: 4px 0; }
.mis-reason-row { display: grid; grid-template-columns: 160px 1fr 80px; align-items: center; gap: 8px; }
.mis-reason-label { font-size: 12px; font-weight: 500; color: #374151; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html.theme-dark .mis-reason-label { color: #CBD5E1; }
.mis-reason-bar-wrap { background: #F3F4F6; border-radius: 4px; height: 14px; overflow: hidden; }
html.theme-dark .mis-reason-bar-wrap { background: #1E2E45; }
.mis-reason-bar { height: 100%; border-radius: 4px; transition: width 0.4s ease; }
.mis-reason-count { font-size: 12px; font-weight: 600; color: #111827; text-align: right; }
html.theme-dark .mis-reason-count { color: #F1F5F9; }
/* Table cell highlights */
.mis-cell-danger { color: #DC2626 !important; font-weight: 700; }
.mis-cell-warn   { color: #D97706 !important; font-weight: 600; }
/* Failures recent list scroll */
.mis-tab-panel[data-tab="prompt-failures"] .mis-recovery-list {
  max-height: 560px; overflow-y: auto;
}
/* KPI row for failures tab */
.mis-tab-panel[data-tab="prompt-failures"] .mis-chart-card canvas { min-height: 220px; }

/* Drillable rows visually invite the click. */
.mis-drill-row { cursor: pointer; transition: background 100ms ease; }
.mis-drill-row:hover { background: #EAF3FB; }
html.theme-dark .mis-drill-row:hover { background: rgba(0,120,191,0.10); }

/* Drill-down overlay + panel */
.mis-drill-overlay {
  position: fixed; inset: 0; z-index: 9500;
  background: rgba(15,23,42,0.55);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.mis-drill-overlay[hidden] { display: none !important; }
.mis-drill-panel {
  background: var(--card, #FFFFFF); color: var(--fg, #0F172A);
  border: 1px solid var(--border, #E2E8F0);
  border-radius: 12px;
  width: min(920px, 100%); max-height: 90vh;
  display: flex; flex-direction: column;
  box-shadow: 0 20px 60px rgba(15,23,42,0.35);
}
html.theme-dark .mis-drill-panel { background: #0B1626; color: #F1F5F9; border-color: #1E2E45; }
.mis-drill-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px; border-bottom: 1px solid var(--border, #E2E8F0);
}
html.theme-dark .mis-drill-head { border-bottom-color: #1E2E45; }
.mis-drill-head h3 { margin: 0; font-size: 15px; font-weight: 700; }
.mis-drill-close {
  border: none; background: transparent; cursor: pointer;
  font-size: 16px; line-height: 1; padding: 4px 10px;
  color: var(--muted, #64748B); border-radius: 6px;
}
.mis-drill-close:hover { background: #F1F5F9; color: #0F172A; }
html.theme-dark .mis-drill-close:hover { background: #1E2E45; color: #F1F5F9; }
.mis-drill-body {
  padding: 16px 20px; overflow-y: auto; flex: 1 1 auto;
}
.mis-drill-body h4 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--muted, #64748B); }
.mis-drill-body .mis-dashboard-kpis { margin-bottom: 8px; }

/* ═════════════════════════════════════════════════════════════════════
   Chat content width — shared variable + row-level widening
   (additive override · 9 Jul 2026, revised same-day)
   ─────────────────────────────────────────────────────────────────────
   Iteration 1 (earlier today): widened `.composer-card` + `#attachments`
   + `.msg > .bubble` via a shared max-width variable so the composer
   grew when the folder panel collapsed. That fixed the input row, but
   assistant message CONTENT (the bubble body — tool cards, tables,
   code blocks, running/completed status bars, markdown prose) still
   looked narrow. Root cause: the `.msg` row wrapper at line 1229
   `.msg { max-width: 820px }` capped the ENTIRE row at 820 px. Every
   bubble + inner card + status footer is nested inside `.msg`, so
   widening the bubble alone did nothing — the parent still clipped.

   Fix in this revision:
     1. Rename the variable to --chat-content-max (per spec — this
        single var now drives EVERY chat-column max-width).
     2. Apply --chat-content-max to `.msg` (the row wrapper) — this is
        the actual constraint that was choking the layout. Widening it
        naturally widens every inner element (bubble, tool card, status
        footer, running/completed bar, markdown, tables, code blocks)
        because they all fill the parent.
     3. Drop the 86ch cap on `.msg > .bubble`. With the parent row now
        wider, we want tables/code blocks to fill the wider bubble
        (they already use width:100% and overflow-x:auto respectively,
        so long content scrolls horizontally INSIDE the card instead
        of stretching the layout). Prose paragraphs still wrap at word
        boundaries — the earlier 86 ch cap was a defensive belt on
        prose readability but the practical width at desktop breakpoints
        (~1080–1200 px = ~90–100 ch at 14 px body font) already lands
        near the ergonomic ceiling, and the collapsed-state grows only
        to 1200 px which is still comfortable.
     4. User-bubble constraint is UNTOUCHED — the base rule at line
        1296 (`max-width: min(720px, 92%)`) keeps user speech right-
        aligned and comfortable. Only assistant messages get the wide
        treatment.
     5. Everything else the earlier iteration set (folder-panel-collapsed
        variable swap · media-query bumps · tablet safety net · mobile
        full-width · transition timing) carries through unchanged.

   Selector coverage (why this single .msg change reaches every card):
     `.msg` wraps every assistant response including:
       .msg > .bubble           — the main answer card + markdown body
       .msg > .msg-status-footer — running / completed / error bar
       .msg > .msg-actions      — hover-action toolbar
       .msg > .msg-assign-bar   — task-spawn bar
       .msg > any future card the assistant renders
     Every one of those already lives inside `.msg` so they all inherit
     the new width from the row wrapper. No per-selector duplication
     needed — one rule, whole tree widens.

   Zero touch to colours, buttons, fonts, sidebar, toggle button,
   backend, API, routes, auth, or business logic.
   ───────────────────────────────────────────────────────────────────── */

:root {
  /* Canonical chat-content width variable. Every chat-column max-width
     pulls from this.

     ─── Polarity (revised 10 Jul 2026, spec third pass) ───
     OPEN (right panel visible)     → CONSTRAINED — chat sits comfortably
                                     centred in the remaining column so
                                     the two sidebars don't visually
                                     "cramp" the middle. Feels like
                                     ChatGPT / Claude with a right panel.
     COLLAPSED (right panel closed) → EXPANDED — chat uses the reclaimed
                                     column width, growing to a wider,
                                     laptop-comfortable ceiling.

     Previous iterations kept expanding the OPEN state; this pass
     inverts that so the presence of a sidebar visibly gives the chat
     a narrower, cleaner center feel — which is exactly the
     "slightly smaller when a panel is open" behaviour the user asked
     for.

     Values per spec:
       OPEN       → min(92 %, 980 px)   — comfortable 850–1050 px range
       COLLAPSED  → min(94 %, 1280 px)  — expanded 1100–1350 px range */
  --chat-content-max: min(92%, 980px);
  --chat-content-max-collapsed: min(94%, 1280px);
}

/* ── Neutralise the extra centering-padding on #messages at wide
   breakpoints ──────────────────────────────────────────────────────
   The base file at line 13347 + line 13391 adds up to ~200 px of
   symmetric `padding-inline` on #messages when the viewport is ≥1600 px,
   effectively insetting the chat column and eating the space the user
   wants back. That was originally a centering trick — but with
   `--chat-content-max` now bounded by 1440 px + `.msg / .composer-card`
   already centered via `margin: 0 auto`, the trick is redundant. Force
   #messages back to its base 28 px padding so the chat fills the column
   and centres itself natively. */
@media (min-width: 1600px) {
  #messages {
    padding-left: 28px;
    padding-right: 28px;
  }
}
@media (min-width: 2560px) {
  #messages {
    padding-left: 40px;
    padding-right: 40px;
  }
}

/* ── The row wrapper — THE fix that unlocks assistant content width ──
   Higher-specificity selector wins over the base `.msg { max-width: 820px }`
   at line 1229. Every inner element (bubble, tool card, status footer,
   running/completed bar, markdown body, tables, code blocks) fills the
   parent `.msg` naturally, so widening it here cascades everywhere. */
.msg {
  max-width: var(--chat-content-max);
  transition: max-width 240ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* ── Assistant bubble — fill the widened row ──
   The parent `.msg` now caps at --chat-content-max. Let the assistant
   bubble fill 100 % of the row so tables (which use width:100%), code
   blocks (overflow-x:auto), tool cards, and the running/completed
   status footer all get the extra space. Higher specificity than the
   earlier `:where(.msg) > .bubble` responsive-bump rules further up
   the file, so this cleanly wins. min-width:0 lets the bubble shrink
   below its intrinsic content width when a stubborn child (e.g. a
   long code line) would otherwise force it wider. */
.msg > .bubble {
  max-width: 100%;
  min-width: 0;
  transition: max-width 240ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* User bubble — right-aligned and comfortable. Kept at 720 px cap so
   it looks like a proper "speech bubble" inside the (now narrower)
   open-state row and doesn't dominate the visual width. 92 % keeps
   mobile / tablet layouts intact. */
.msg.user > .bubble {
  max-width: min(720px, 92%);
}

/* ── Composer card + attachment strip — same shared variable ──
   These sit inside #composer (a separate scroll container from
   #messages) so they need the variable directly, not through .msg. */
.composer-card {
  max-width: var(--chat-content-max);
  transition: max-width 240ms cubic-bezier(0.4, 0, 0.2, 1);
}
#attachments {
  max-width: var(--chat-content-max);
  transition: max-width 240ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* ── Right-sidebar state — expand when collapsed ──
   Swap the variable at body-level; every element that pulls from
   --chat-content-max (.msg, .msg > .bubble via 100 %, composer,
   attachments) picks up the expanded ceiling in one hop. The
   `body.right-sidebar-collapsed` alias is written by the toggle JS
   in app.js in parallel with `folder-panel-collapsed`, so both
   selectors match the same DOM state — future edits can use whichever
   feels semantically clearer without breaking the other. */
body.folder-panel-collapsed,
body.right-sidebar-collapsed {
  --chat-content-max: var(--chat-content-max-collapsed);
}

/* ── Wide-display bumps ──
   Progressively lift the ceilings on larger monitors so the OPEN state
   stays comfortable (never boxed) and the COLLAPSED state gets the
   extra real-estate. The gap between OPEN and COLLAPSED stays visible
   at every breakpoint — that's what makes toggling the sidebar feel
   like an actual layout change rather than a chrome flicker. */
@media (min-width: 1600px) {
  :root {
    --chat-content-max: min(92%, 1020px);
    --chat-content-max-collapsed: min(94%, 1320px);
  }
}
@media (min-width: 1920px) {
  :root {
    --chat-content-max: min(92%, 1050px);
    --chat-content-max-collapsed: min(94%, 1350px);
  }
}
@media (min-width: 2560px) {
  :root {
    --chat-content-max: min(90%, 1100px);
    --chat-content-max-collapsed: min(92%, 1400px);
  }
}

/* ── Tablet safety net (≤ 980 px) ──
   Grid folds to single column, right panel becomes overlay. Nearly
   full-width with just safe-area breathing padding — bumped ceiling
   so tablet-landscape looks less boxed. */
@media (max-width: 980px) {
  :root {
    --chat-content-max: min(97%, 980px);
    --chat-content-max-collapsed: min(97%, 980px);
  }
}

/* ── Mobile (≤ 640 px) ──
   100 % of parent — the parent (#messages / #composer) already has the
   tighter side padding from the existing responsive layer, so this
   gives full width with the correct safe-area gutter. Kill the
   width-transition on small screens so a rotate doesn't animate. */
@media (max-width: 640px) {
  :root {
    --chat-content-max: 100%;
    --chat-content-max-collapsed: 100%;
  }
  .msg, .msg > .bubble, .composer-card, #attachments {
    transition: none;
  }
}

/* ── Right-sidebar toggle-button clearance (invariant documentation) ──
   The toggle sits at `right: var(--folder-panel-w)` when the panel is
   open (line 6841) and `right: 0` when collapsed (line 6843). The .msg
   row is centred inside the middle grid column whose right edge is
   `viewport.width - var(--folder-panel-w)` (open) or `viewport.width`
   (collapsed). The row's right margin equals
   `(column_width - --chat-content-max) / 2` ≥ 3 % of column, so the
   assistant card never crosses the toggle. This comment exists so a
   future edit doesn't inadvertently narrow the safe gap. */

/* ═════════════════════════════════════════════════════════════════════
   ORGANIZATION-UI SCROLL POLISH · 10 Jul 2026 · Mohammed Ashfak
   ─────────────────────────────────────────────────────────────────────
   User report (10 Jul 2026 screenshot from an organization account):
     "looks like no scroll option and others where not there — check
      and fix this globally"

   Root causes traced across the primary Web-UI + Mini-App shells:

   A) `#myBillingBody` and `#myAccountBody` use INLINE `display:grid`
      styles and are NOT part of the L990 inner-scroll block. Their
      parent sections (`#myBillingView`, `#myAccountView`) already
      carry `overflow:hidden` via the L15494 :where() rule, so any
      body content beyond one viewport is silently clipped — user
      can never reach the tiles below the fold.

   B) Marketing + training-links sections (`#myMarketingWebsitesView`,
      `#myMarketingBlogsView`, `#myMarketingContentPipelineView`,
      `#trainingLinksView`) are NOT in the L756 primary-sections
      flex-column block. When shown, they sit at natural content
      height inside `#main` instead of filling it, and their bodies
      have nowhere to scroll from.

   C) `.training-body` uses `display: grid; padding: 16px` with no
      `flex: 1 1 auto` or `overflow-y`. The tabs + panels stack at
      their natural height and disappear below the fold.

   D) The `.sidebar-scroll` scrollbar was styled `thin` on top of a
      `transparent` track (L214 + L2409) — visually invisible on the
      Chrome default background of the sidebar. Users don't discover
      they can scroll to reach the top-of-menu items (My Prompts,
      My Tasks, My Documents, My Calendar, …). We give it a subtle
      but VISIBLE always-on thumb so the affordance is discoverable.

   E) `.folder-panel-list` (right rail) can grow long (many projects)
      but its scrollbar was equally invisible — same visibility fix.

   Zero markup edits below. Every rule is polish-layer; delete this
   block to revert. Same block is mirrored into web/telegram-app.html.
   ═════════════════════════════════════════════════════════════════════ */

/* (A) Inner-scroll for the two grid-body views that were missed. */
:where(#myBillingBody, #myAccountBody) {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

/* (B) Give the marketing + training-links sections the same flex-column
   fill semantics every other primary section has. Uses :where() so the
   specificity is 0 — any per-view rule still wins. */
:where(#myMarketingWebsitesView, #myMarketingBlogsView,
       #myMarketingContentPipelineView, #trainingLinksView) {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  flex: 1 1 auto;
  height: 100%;
  overflow: hidden;
}

/* (C) Training-body — was `display: grid; padding: 16px` with no fill
   or scroll. Turn it into a scrolling column that occupies whatever
   height `#trainingLinksView` gives it. */
:where(.training-body) {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

/* (D) Sidebar scroll — always-on, subtle-but-visible thumb so users
   discover they CAN scroll to reach items above the fold. Keeps the
   Chrome/Firefox default track transparent to stay quiet visually. */
:where(#sidebar .sidebar-scroll) {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong, #94A3B8) transparent;
}
#sidebar .sidebar-scroll::-webkit-scrollbar {
  width: 8px;
}
#sidebar .sidebar-scroll::-webkit-scrollbar-track {
  background: transparent;
}
#sidebar .sidebar-scroll::-webkit-scrollbar-thumb {
  background: var(--border-strong, #94A3B8);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
  min-height: 40px;
}
#sidebar .sidebar-scroll::-webkit-scrollbar-thumb:hover {
  background: var(--text-faint, #64748B);
  background-clip: padding-box;
}

/* (E) Folder-panel list — same visible-scrollbar treatment. */
:where(#folderPanel .folder-panel-list) {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong, #94A3B8) transparent;
}
#folderPanel .folder-panel-list::-webkit-scrollbar {
  width: 8px;
}
#folderPanel .folder-panel-list::-webkit-scrollbar-thumb {
  background: var(--border-strong, #94A3B8);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
  min-height: 40px;
}
#folderPanel .folder-panel-list::-webkit-scrollbar-thumb:hover {
  background: var(--text-faint, #64748B);
  background-clip: padding-box;
}

/* (F) min-height:0 on direct body children so flex:1 can shrink below
   content size. Do NOT blanket overflow-y:auto here — multi-child views
   (URLs, Notes) would get equal-height scrolling panes and break sticky
   toolbars. Scroll is applied only via known body class patterns in (H). */
:where(#main > section:not(#chat):not(#project):not(#wizardSection)
        > div:not(header):not(.header-actions):not([role="tablist"])) {
  min-height: 0;
}

/* Sections that were never added to the L756 primary list still need the
   flex-column fill so an inner scroll body can work. :where() keeps
   specificity 0 so any per-view rule (e.g. #urlsView { overflow:auto })
   still wins. */
:where(#main > section:not(#chat):not(#project):not(#wizardSection)) {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  flex: 1 1 auto;
  height: 100%;
  overflow: hidden;
}

/* (G) Ensure the impersonation banner never eats a view's height budget
   without giving it back — banner is `flex: 0 0 auto` at parent, but
   older browsers occasionally leak min-content. Explicit min-height:0
   on `#main` children makes sure they can shrink. */
#main > section {
  min-height: 0;
}

/* (H) Known single-scroll body patterns — header stays put, body scrolls.
   Covers Organisations (23 Jul 2026: content cut off mid-card, no
   scrollbar), My Org, My Team, Masters, Storage, Runtime Model, Soft
   Restart, Cursor setup, and any future view that reuses these classes. */
:where(
  .my-team-body,
  .orgs-body,
  .masters-body,
  .myagents-body,
  .my-docs-body,
  .actions-pending-body,
  .training-body,
  .cursor-setup-body,
  .my-cal-content,
  .idea-queue-body,
  #storageBody,
  #cursorSetupBody,
  #ideaQueueBody,
  #myMeetingsBody
) {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong, #94A3B8) transparent;
}
:where(
  .my-team-body,
  .orgs-body,
  .masters-body,
  .myagents-body,
  .my-docs-body,
  .actions-pending-body,
  .training-body,
  .cursor-setup-body,
  .my-cal-content,
  .idea-queue-body,
  #storageBody,
  #cursorSetupBody,
  #ideaQueueBody,
  #myMeetingsBody
)::-webkit-scrollbar {
  width: 8px;
}
:where(
  .my-team-body,
  .orgs-body,
  .masters-body,
  .myagents-body,
  .my-docs-body,
  .actions-pending-body,
  .training-body,
  .cursor-setup-body,
  .my-cal-content,
  .idea-queue-body,
  #storageBody,
  #cursorSetupBody,
  #ideaQueueBody,
  #myMeetingsBody
)::-webkit-scrollbar-thumb {
  background: var(--border-strong, #94A3B8);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
  min-height: 40px;
}



/* ═══════════════════════════════════════════════════════════════════
   URLs view — deployment URL inventory (folder-of-origin manager).
   Mirrors Imagine's existing dashboard-view visual language: soft
   card surface, subtle borders, status pills, sticky toolbar, and
   compact tables. All colours pull from the shared token palette
   already defined in styles.css.
   ═══════════════════════════════════════════════════════════════════ */
#urlsView {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px 20px 24px;
  overflow: auto;
  min-height: 0;
}
#urlsHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border, #e5e7eb);
}
#urlsHeader .header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* URLs view · toolbar + filter row (v2 · Ashfak · 27 Jul 2026)
   Alignment pass — fixes the "messy tabs" report by:
   (a) making the tab strip a horizontally-scrollable single row instead of
       wrap-and-staircase, so the 7 labels (incl. "Live Connected With
       Imagine") don't stack into 2 rows with a broken bottom-border;
   (b) locking every filter-row control (search / selects / checkbox) to a
       shared 34px height so they sit on ONE crisp baseline instead of
       floating at 3 different vertical positions;
   (c) giving selects a min-width so widths don't jitter with option-text;
   (d) putting the sticky-toolbar's bottom-border on the CONTAINER (not on
       the tab strip) so the separator holds even while the tab strip is
       mid-scroll; and (e) adding horizontal padding so nothing butts
       against the panel edge. */
.urls-toolbar {
  display: flex;
  flex-direction: column;
  gap: 10px;
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg, #ffffff);
  padding: 10px 4px 12px;
  border-bottom: 1px solid var(--border, #e5e7eb);
}
.urls-tabs {
  display: flex;
  gap: 2px;
  flex-wrap: nowrap;          /* was wrap — staircased into 2 broken rows */
  overflow-x: auto;           /* scrolls sideways on narrow viewports */
  overflow-y: hidden;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
  border-bottom: 1px solid var(--border, #e5e7eb);
}
.urls-tabs::-webkit-scrollbar { height: 4px; }
.urls-tabs::-webkit-scrollbar-thumb {
  background: var(--text-faint, #cbd5e1);
  border-radius: 999px;
}
.urls-tab {
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;        /* overlap the container's 1px bottom-border
                                 so the active tab's 2px indicator visually
                                 sits ON the divider instead of 1px above */
  padding: 9px 14px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted, #6b7280);
  white-space: nowrap;        /* labels never wrap mid-tab */
  cursor: pointer;
  transition: color 120ms, border-color 120ms, background 120ms;
  border-radius: 6px 6px 0 0;
}
.urls-tab:hover {
  color: var(--text, #111827);
  background: var(--surface-2, #f9fafb);
}
.urls-tab.is-active {
  color: var(--primary, #2563eb);
  border-bottom-color: var(--primary, #2563eb);
}
.urls-tab:focus-visible {
  outline: 2px solid var(--primary, #2563eb);
  outline-offset: -2px;
}
.urls-filters {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
}
/* Locked height on every filter-row control so search / selects / checkbox
   share a single 34px baseline instead of drifting on visual centre. */
.urls-search {
  flex: 1 1 240px;
  min-width: 220px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 8px;
  font-size: 13px;
  background: var(--bg, #fff);
  color: var(--text, #111827);
  box-sizing: border-box;
}
.urls-search:focus {
  outline: 2px solid var(--primary, #2563eb);
  outline-offset: -1px;
  border-color: var(--primary, #2563eb);
}
.urls-select {
  height: 34px;
  min-width: 140px;           /* widths no longer jitter with option text */
  padding: 0 28px 0 10px;     /* right-pad for the native ▼ chevron */
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 8px;
  background: var(--bg, #fff);
  color: var(--text, #111827);
  font-size: 13px;
  box-sizing: border-box;
  cursor: pointer;
}
.urls-select:focus {
  outline: 2px solid var(--primary, #2563eb);
  outline-offset: -1px;
  border-color: var(--primary, #2563eb);
}
.urls-check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;               /* matches the selects → same baseline */
  padding: 0 10px;
  font-size: 13px;
  color: var(--text-muted, #6b7280);
  border: 1px solid transparent;
  border-radius: 8px;
  cursor: pointer;
  user-select: none;
}
.urls-check:hover { background: var(--surface-2, #f9fafb); }
.urls-check input[type="checkbox"] {
  width: 14px;
  height: 14px;
  margin: 0;
  cursor: pointer;
}
/* Right-anchor the checkbox so when the filter row has spare width it sits
   at the far end (nice grouping), and when the row wraps to a second line
   the checkbox sits alone at the right rather than orphaned at the left
   colliding with the table header below. (Ashfak · 28 Jul 2026 — the
   27 Jul v2 pass forgot this and the checkbox floated left-of-line-2.) */
.urls-check { margin-left: auto; }

.urls-summary {
  font-size: 12px;
  color: var(--text-muted, #6b7280);
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
  padding: 4px 2px 0;
}

.urls-body { min-height: 200px; }
.urls-empty, .urls-error {
  padding: 32px 20px;
  text-align: center;
  color: var(--text-muted, #6b7280);
  font-size: 14px;
  border: 1px dashed var(--border, #e5e7eb);
  border-radius: 10px;
}
.urls-error { color: #b91c1c; border-color: #fecaca; background: #fef2f2; }

.urls-skel { display: flex; flex-direction: column; gap: 8px; }
.urls-skel-row {
  height: 44px;
  border-radius: 6px;
  background: linear-gradient(90deg, #f3f4f6 0%, #e5e7eb 50%, #f3f4f6 100%);
  background-size: 200% 100%;
  animation: urls-skel 1.4s ease-in-out infinite;
}
@keyframes urls-skel {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

.urls-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 10px;
}
.urls-table {
  /* `width: auto` + a comfortable `min-width` lets the table grow past the
     wrap container (which has `overflow-x: auto`) so horizontal scroll
     kicks in instead of the browser crushing narrow columns like the URL
     cell into 1-char-per-line stacks. Ashfak · 28 Jul 2026 — the previous
     `width: 100%` combined with an auto-layout table + a right-side
     folder panel eating horizontal space produced the "h / t / t / p"
     vertical alphabet visible in the reported screenshot. */
  width: max-content;
  min-width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.urls-table thead th {
  background: var(--surface-2, #f9fafb);
  text-align: left;
  padding: 8px 10px;
  font-weight: 600;
  color: var(--text-muted, #6b7280);
  border-bottom: 1px solid var(--border, #e5e7eb);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}
.urls-table tbody tr { border-bottom: 1px solid var(--border, #f1f5f9); }
.urls-table tbody tr:hover { background: var(--surface-2, #f9fafb); }
.urls-table td {
  padding: 8px 10px;
  vertical-align: top;
}
/* Per-cell width + wrap discipline — stops the URL column from character-
   stacking and keeps every cell on a predictable width so the horizontal
   scrollbar (on `.urls-table-wrap`) becomes the release valve when the
   panel gets crowded, instead of the browser mangling column layout. */
.urls-table .urls-name {
  font-weight: 500;
  min-width: 160px;
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.urls-table .urls-url {
  min-width: 220px;
  max-width: 360px;
}
.urls-table .urls-url a {
  color: var(--primary, #2563eb);
  text-decoration: none;
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
  /* NOT `word-break: break-all` — that's what caused the 1-char-per-line
     stack. `text-overflow: ellipsis` gives a clean single-line preview and
     the anchor still opens the full URL on click. */
}
.urls-table .urls-url a:hover { text-decoration: underline; }
.urls-cell-live { color: #059669; font-weight: 500; }
.urls-cell-offline { color: #dc2626; font-weight: 500; }

.urls-folder { display: flex; flex-direction: column; gap: 2px; }
.urls-folder-name { font-weight: 500; }
.urls-folder-path {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  color: var(--text-muted, #6b7280);
  word-break: break-all;
}
.urls-folder-unknown span { color: #b91c1c; font-style: italic; }
.btn-map-folder {
  background: transparent;
  border: 1px dashed #d97706;
  color: #d97706;
  padding: 2px 8px;
  border-radius: 6px;
  font-size: 11px;
  cursor: pointer;
  width: fit-content;
}
.btn-map-folder:hover { background: #fffbeb; }

.urls-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.3;
}
.urls-badge-live     { background: #d1fae5; color: #065f46; }
.urls-badge-degraded { background: #fef3c7; color: #92400e; }
.urls-badge-offline  { background: #fee2e2; color: #991b1b; }
.urls-badge-expired  { background: #fecaca; color: #7f1d1d; }
.urls-badge-unknown  { background: #e5e7eb; color: #4b5563; }
.urls-badge-archived { background: #e0e7ff; color: #3730a3; }
.urls-ssl-valid         { background: #d1fae5; color: #065f46; }
.urls-ssl-expiring_soon { background: #fef3c7; color: #92400e; }
.urls-ssl-expired       { background: #fecaca; color: #7f1d1d; }
.urls-ssl-invalid       { background: #fee2e2; color: #991b1b; }
.urls-ssl-none          { background: #f3f4f6; color: #4b5563; }
.urls-ssl-unknown       { background: #e5e7eb; color: #4b5563; }
.urls-ssl-expiry {
  display: block;
  font-size: 10.5px;
  color: var(--text-muted, #6b7280);
  margin-top: 2px;
}

.urls-actions {
  display: flex;
  gap: 4px;
  flex-wrap: nowrap;
  justify-content: flex-end;
}
.urls-actions button {
  background: transparent;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  padding: 3px 8px;
  font-size: 12px;
  cursor: pointer;
  color: var(--text, #111827);
  transition: background 120ms, border-color 120ms;
}
.urls-actions button:hover {
  background: var(--surface-2, #f9fafb);
  border-color: var(--primary, #2563eb);
  color: var(--primary, #2563eb);
}

.urls-pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
  padding: 10px;
  color: var(--text-muted, #6b7280);
  font-size: 12px;
}
.btn-page {
  background: transparent;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  padding: 4px 10px;
  font-size: 12px;
  cursor: pointer;
}
.btn-page:disabled { opacity: 0.4; cursor: not-allowed; }

/* Detail slide-over */
.urls-detail-panel {
  position: fixed;
  top: 0;
  right: 0;
  width: min(560px, 100%);
  height: 100vh;
  background: var(--bg, #fff);
  border-left: 1px solid var(--border, #e5e7eb);
  box-shadow: -8px 0 32px rgba(15, 46, 86, 0.08);
  z-index: 100;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  animation: urls-slide-in 200ms ease-out;
}
.urls-detail-panel.hidden { display: none; }
@keyframes urls-slide-in {
  from { transform: translateX(100%); }
  to   { transform: translateX(0); }
}
.urls-detail-inner { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.urls-detail-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border, #e5e7eb);
}
.urls-detail-head h3 { margin: 0; font-size: 16px; }
.urls-detail-body {
  flex: 1;
  overflow: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.urls-detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 20px;
  font-size: 13px;
}
.urls-detail-grid label {
  display: block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted, #6b7280);
  margin-bottom: 2px;
}
.urls-detail-grid > div { min-width: 0; word-break: break-word; }
.urls-detail-full { grid-column: 1 / -1; }
.urls-detail-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 12px 0;
  border-top: 1px solid var(--border, #e5e7eb);
}
.urls-detail-block {
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 8px;
  padding: 8px 12px;
  background: var(--surface-2, #f9fafb);
}
.urls-detail-block summary {
  cursor: pointer;
  font-weight: 600;
  padding: 4px 0;
  outline: none;
}
.urls-evidence,
.urls-history,
.urls-audit {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  font-size: 12.5px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.urls-evidence li,
.urls-history li,
.urls-audit li {
  padding: 6px 8px;
  background: var(--bg, #fff);
  border-radius: 6px;
  border: 1px solid var(--border, #f1f5f9);
}
.urls-evidence-path {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  color: var(--text-muted, #6b7280);
  margin-top: 2px;
  word-break: break-all;
}
.urls-evidence-snippet {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  background: #f3f4f6;
  padding: 6px 8px;
  border-radius: 6px;
  margin: 6px 0 0;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-all;
}

/* Responsive: collapse the table into stacked rows on small screens. */
@media (max-width: 800px) {
  .urls-detail-grid { grid-template-columns: 1fr; }
  .urls-detail-panel { width: 100%; }
  .urls-filters { flex-direction: column; align-items: stretch; }
  .urls-filters .urls-search,
  .urls-filters .urls-select { width: 100%; }
  .urls-table { font-size: 12px; }
  .urls-table thead { display: none; }
  .urls-table tbody tr {
    display: grid;
    grid-template-columns: 1fr;
    padding: 8px 10px;
    gap: 4px;
    border-bottom: 1px solid var(--border, #e5e7eb);
  }
  .urls-table td {
    padding: 3px 0;
    display: grid;
    grid-template-columns: 100px 1fr;
    gap: 8px;
  }
  .urls-table td::before {
    content: attr(data-label);
    font-weight: 600;
    color: var(--text-muted, #6b7280);
  }
}

/* ── URLs · Live Connected With Imagine tab ─────────────────────── */
.urls-conn-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
  margin-bottom: 14px;
}
.urls-conn-card {
  background: var(--surface-2, #f9fafb);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 10px;
  padding: 12px 14px;
  text-align: left;
  transition: border-color 120ms;
}
.urls-conn-card.ok   { border-left: 3px solid #059669; }
.urls-conn-card.warn { border-left: 3px solid #d97706; }
.urls-conn-card.err  { border-left: 3px solid #dc2626; }
.urls-conn-card-val {
  font-size: 22px;
  font-weight: 700;
  color: var(--text, #111827);
  line-height: 1;
}
.urls-conn-card-label {
  font-size: 11px;
  color: var(--text-muted, #6b7280);
  margin-top: 4px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.urls-conn-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
}
.urls-conn-connected { background: #d1fae5; color: #065f46; }
.urls-conn-degraded  { background: #fef3c7; color: #92400e; }
.urls-conn-stale     { background: #fee2e2; color: #7f1d1d; }
.urls-conn-unknown   { background: #e5e7eb; color: #4b5563; }
.urls-conn-project { font-weight: 600; color: var(--primary, #2563eb); }
.urls-conn-website { display: flex; flex-direction: column; gap: 2px; }
.urls-conn-name { font-weight: 500; }
.urls-conn-url {
  font-size: 11.5px;
  color: var(--primary, #2563eb);
  text-decoration: none;
  word-break: break-all;
}
.urls-conn-url:hover { text-decoration: underline; }
.urls-conn-commit code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  background: #f3f4f6;
  padding: 1px 6px;
  border-radius: 4px;
}
.urls-conn-commit small,
.urls-conn-provider small {
  display: block;
  font-size: 11px;
  color: var(--text-muted, #6b7280);
  margin-top: 2px;
}
.urls-conn-provider { display: flex; flex-direction: column; gap: 2px; }

/* ─────────────────────────────────────────────────────────────────────
   My Messages · Triage Top-Band (Prompt 8 · 2026-07-18)
   Renders above the existing My Messages two-pane body. Surfaces
   escalated inbound messages with tier pills, ack/snooze/override/
   delegate/draft actions. Below the divider, the existing conversations
   list continues to render routine (non-escalated) inbound.
   ────────────────────────────────────────────────────────────────── */
.mm-triage-band {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border, #e6e6e6);
  background: var(--surface-alt, #fbfbfd);
}
.mm-triage-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.mm-triage-title {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--text, #1a1a1a);
}
.mm-triage-counts {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 12px;
}
.mm-count { color: var(--text-muted, #666); }
.mm-count-unacked { font-weight: 600; color: #d64545; }
.mm-tier-filter { display: flex; gap: 4px; }
.mm-tier-pill {
  padding: 2px 10px;
  font-size: 11px;
  border: 1px solid transparent;
  border-radius: 12px;
  cursor: pointer;
  background: transparent;
  color: var(--text-muted, #666);
  font-family: inherit;
}
.mm-tier-pill.active {
  border-color: var(--border-strong, #333);
  color: var(--text, #111);
  background: var(--surface, #fff);
}
.mm-tier-pill.mm-tier-p1.active { border-color: #d64545; color: #d64545; }
.mm-tier-pill.mm-tier-p2.active { border-color: #d69a3c; color: #d69a3c; }
.mm-tier-pill.mm-tier-review.active { border-color: #888; }

.mm-escalated-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.mm-escalated-item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 10px;
  padding: 10px 12px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #ececec);
  border-radius: 8px;
  align-items: start;
}
.mm-escalated-item[data-tier="p1"] { border-left: 3px solid #d64545; }
.mm-escalated-item[data-tier="p2"] { border-left: 3px solid #d69a3c; }
.mm-escalated-item[data-tier="review"] { border-left: 3px solid #888; }
.mm-escalated-item.acked { opacity: 0.65; }
.mm-tier-badge {
  font-size: 10px;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 4px;
  letter-spacing: 0.3px;
  color: #fff;
  align-self: start;
}
.mm-tier-badge[data-tier="p1"] { background: #d64545; }
.mm-tier-badge[data-tier="p2"] { background: #d69a3c; }
.mm-tier-badge[data-tier="review"] { background: #888; }

.mm-esc-body { min-width: 0; }
.mm-esc-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text, #111);
  margin: 0 0 2px 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mm-esc-preview {
  font-size: 12px;
  color: var(--text-muted, #444);
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  margin: 0;
}
.mm-esc-meta {
  font-size: 11px;
  color: var(--text-muted, #888);
  margin-top: 4px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.mm-esc-reason {
  padding: 1px 6px;
  background: var(--surface-sunk, #f0f0f2);
  border-radius: 3px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px;
}
.mm-esc-actions {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.mm-esc-btn {
  font-size: 11px;
  padding: 4px 8px;
  border: 1px solid var(--border-strong, #ccc);
  background: var(--surface, #fff);
  color: var(--text, #111);
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
}
.mm-esc-btn:hover { background: var(--surface-hover, #f5f5f5); }
.mm-esc-btn:disabled { opacity: 0.5; cursor: wait; }
.mm-esc-btn-primary {
  background: var(--text, #111);
  color: #fff;
  border-color: var(--text, #111);
}
.mm-esc-btn-primary:hover { background: #333; }

.mm-routine-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
}
.mm-routine-divider-line {
  flex: 1;
  height: 1px;
  background: var(--border, #e0e0e0);
}
.mm-routine-divider-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted, #888);
}

.mm-load-more {
  display: block;
  margin: 8px auto;
  padding: 6px 14px;
  font-size: 12px;
  border: 1px solid var(--border-strong, #ccc);
  background: var(--surface, #fff);
  color: var(--text, #111);
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
}
.mm-load-more:hover { background: var(--surface-hover, #f5f5f5); }

/* Phone: shrink the actions row, allow rows to wrap. */
@media (max-width: 720px) {
  .mm-escalated-item {
    grid-template-columns: auto 1fr;
  }
  .mm-esc-actions {
    grid-column: 1 / -1;
    justify-content: flex-start;
    padding-top: 4px;
    border-top: 1px dashed var(--border, #ececec);
    margin-top: 4px;
  }
  .mm-triage-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   Home Feed (Twitter-style team wall) — added 23 Jul 2026.
   Sidebar Home button sits above Dashboard; view is a global feed with
   composer at top, then a chronological post list. Every post shows
   author + timestamp, a Like row (👍 count), and a threaded comments
   region. @agent-slug in a post/comment triggers an agent-authored
   reply which streams in over SSE.
   ══════════════════════════════════════════════════════════════════════ */
/* Full-height scroll container. Without height + overflow-y the section
   grows past the viewport and nothing scrolls (reported 24 Jul 2026 —
   composer + 2 posts visible, everything below clipped). The max-width
   + auto margins keep the reading column centred; the scroll happens on
   the section itself so header + composer + list all move together.
   ─────────────────────────────────────────────────────────────────
   LAYOUT PASS · 24 Jul 2026 (admin-set, Mohammed Ashfak):
     • Widen the reading column from 780px → ~980px (max 1050px) so
       the composer + cards actually use the desktop middle area.
     • Header laid out as a single row (title + subtitle on the left,
       refresh + Back on the right) — the previous rule targeted a
       non-existent `.chat-header` and never fired, so the buttons
       stacked below the title.
     • Composer row (flash + Post button) gets an explicit flex row
       so the "Post" button aligns right and the status text stays
       left with proper vertical baseline.
     • When the right sidebar (folder panel) is collapsed the reading
       column expands to ~1120px so the feed grows into the freed
       space instead of leaving a dead band on the right.
     • Tablet + mobile use full width with safe side padding.
   No HTML / no JS / no id / class-name changes — pure CSS. All
   posting, reacting, commenting, agent-mention, delete, permission,
   route, and backend behaviour is preserved. Colors / typography /
   card + button styling are untouched.
   ─────────────────────────────────────────────────────────────── */
#homeFeedView {
  padding: 20px 24px 48px;
  max-width: 1120px;
  margin: 0 auto;
  height: 100vh;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}
/* Widen further when the user collapses the right sidebar so the
   feed uses the freed column instead of leaving a large empty gutter. */
body.folder-panel-collapsed #homeFeedView {
  max-width: 1280px;
}
/* Ultra-wide monitors — grow both breakpoints so the feed keeps using
   the freed screen instead of leaving a fixed gutter. */
@media (min-width: 1600px) {
  #homeFeedView { max-width: 1240px; }
  body.folder-panel-collapsed #homeFeedView { max-width: 1440px; }
}

/* ── Header ───────────────────────────────────────────────────────
   The HTML uses `<header id="homeFeedHeader">` (not `.chat-header`)
   — style it the same way as sibling views (My Tasks, My Meetings)
   so title, subtitle, refresh, and Back sit cleanly on one row. */
#homeFeedHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 4px 0 14px;
  border-bottom: 1px solid var(--border, #e5e7eb);
  margin-bottom: 18px;
  flex-wrap: wrap;
  row-gap: 8px;
}
#homeFeedHeader .chat-title-wrap {
  min-width: 0;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
#homeFeedHeader .chat-title-wrap h2 { margin: 0; font-size: 20px; line-height: 1.25; }
#homeFeedHeader .chat-subtitle {
  font-size: 12.5px; color: var(--text-muted, #64748b); line-height: 1.4;
}
#homeFeedHeader .header-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.home-feed-composer {
  background: var(--panel, #fff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 12px;
  /* Composer + post cards share the same padding so they visually
     land at the exact same width and their inner content aligns. */
  padding: 12px 16px;
  margin-bottom: 12px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}
.home-feed-composer textarea {
  width: 100%; box-sizing: border-box; resize: vertical;
  border: 1px solid var(--border, #e5e7eb); border-radius: 8px;
  padding: 10px 12px; font: inherit; line-height: 1.45; min-height: 60px;
  background: var(--bg, #fff); color: var(--text, #0f172a);
}
.home-feed-composer textarea:focus { outline: 2px solid #3b82f6; outline-offset: -1px; }
/* Composer bottom row — the HTML uses .home-feed-composer-row (not
   .home-feed-composer-actions which never existed on any element).
   Style both class names identically so the row lays out as flex
   with the status message on the left and the Post button flush
   right. Vertically centered so the Post button baseline aligns
   with the flash text. */
.home-feed-composer-row,
.home-feed-composer-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 8px;
  gap: 10px;
  flex-wrap: wrap;
}
.home-feed-composer-row > .home-feed-composer-flash,
.home-feed-composer-actions > .home-feed-composer-flash {
  margin-top: 0; /* row aligns baseline instead */
  flex: 1 1 auto;
  min-width: 0;
}
.home-feed-composer-row #homeFeedPostBtn,
.home-feed-composer-actions #homeFeedPostBtn {
  flex-shrink: 0;
  margin-left: auto;
}
.home-feed-composer-hint {
  font-size: 12px; color: var(--text-muted, #64748b);
}
.home-feed-composer-hint code {
  background: var(--chip-bg, #f1f5f9); padding: 1px 5px; border-radius: 4px;
  font-size: 11.5px;
}
.home-feed-composer-flash { margin-top: 6px; font-size: 12px; min-height: 14px; }
.home-feed-composer-flash.ok { color: #16a34a; }
.home-feed-composer-flash.err { color: #dc2626; }

.home-feed-list { display: flex; flex-direction: column; gap: 10px; }
.home-feed-empty { color: var(--text-muted, #64748b); padding: 24px 0; text-align: center; font-size: 14px; }
.home-feed-empty.hidden { display: none; }

.home-feed-post {
  background: var(--panel, #fff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 12px;
  /* Same padding as .home-feed-composer so composer + cards render at
     the exact same responsive width with inner content flush-aligned. */
  padding: 12px 16px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.03);
  transition: box-shadow 120ms ease, border-color 120ms ease;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}
.home-feed-post.pinned {
  border-color: #f59e0b;
  background: linear-gradient(180deg, rgba(245, 158, 11, 0.06), transparent 40%), var(--panel, #fff);
}
/* Author/timestamp header row — one clean aligned row on desktop:
     [avatar]  [name] [role-chip]  ····  [pin-badge] [timestamp]
   `nowrap` on desktop keeps everything on a single baseline; the
   mobile breakpoint below re-enables wrap so narrow screens don't
   push the timestamp off-screen. */
.home-feed-post-head {
  display: flex; align-items: center; gap: 10px; margin-bottom: 4px;
  flex-wrap: nowrap; min-width: 0;
}
.home-feed-avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: linear-gradient(135deg, #6366f1, #a855f7);
  color: #fff; display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px; text-transform: uppercase; flex-shrink: 0;
}
.home-feed-avatar.role-admin  { background: linear-gradient(135deg, #f59e0b, #ef4444); }
.home-feed-avatar.role-agent  { background: linear-gradient(135deg, #10b981, #06b6d4); }
.home-feed-author {
  font-weight: 600; color: var(--text, #0f172a); font-size: 14px;
  display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap;
  min-width: 0; line-height: 1.25;
}
.home-feed-author-role-chip {
  font-size: 10.5px; padding: 1px 6px; border-radius: 6px;
  background: #f1f5f9; color: #475569; font-weight: 500; text-transform: uppercase;
  letter-spacing: 0.3px; flex-shrink: 0; line-height: 1.5;
}
.home-feed-author-role-chip.role-admin { background: #fef3c7; color: #92400e; }
.home-feed-author-role-chip.role-agent { background: #d1fae5; color: #065f46; }
.home-feed-timestamp {
  color: var(--text-muted, #64748b); font-size: 12px;
  margin-left: auto; flex-shrink: 0; white-space: nowrap;
}
.home-feed-pin-badge {
  font-size: 11px; padding: 1px 6px; border-radius: 6px;
  background: #fef3c7; color: #92400e; font-weight: 600; flex-shrink: 0;
}
.home-feed-body-text {
  white-space: pre-wrap; word-wrap: break-word; overflow-wrap: anywhere;
  font-size: 14.5px; line-height: 1.55; color: var(--text, #0f172a);
  padding: 2px 0 6px;
}
.home-feed-body-text .mention {
  color: #2563eb; font-weight: 500; background: #eff6ff;
  padding: 0 3px; border-radius: 4px;
  /* Keep `@username` tokens on one line so they don't split awkwardly
     across a line-wrap in long numbered lists. */
  white-space: nowrap;
}
/* Rendered ordered/unordered lists (if the body ever ships HTML) —
   keep bullets close to the text and reuse the body line-height so
   long numbered lists read cleanly with no double-gap between items. */
.home-feed-body-text ol,
.home-feed-body-text ul { margin: 4px 0 4px 22px; padding: 0; }
.home-feed-body-text li { margin: 2px 0; line-height: 1.55; }
.home-feed-actions {
  display: flex; align-items: center; gap: 6px;
  padding-top: 6px; margin-top: 2px;
  border-top: 1px solid var(--border, #f1f5f9);
  flex-wrap: nowrap; min-width: 0;
}
.home-feed-btn {
  background: transparent; border: 1px solid transparent;
  padding: 4px 10px; border-radius: 999px; cursor: pointer;
  font-size: 13px; color: var(--text-muted, #64748b);
  display: inline-flex; align-items: center; gap: 5px; transition: background 100ms;
}
.home-feed-btn:hover { background: var(--chip-bg, #f1f5f9); color: var(--text, #0f172a); }
.home-feed-btn.active {
  background: #dbeafe; color: #1d4ed8; font-weight: 600;
}
.home-feed-btn .count { font-variant-numeric: tabular-nums; font-size: 12px; }
.home-feed-reaction-chip {
  font-size: 12px; padding: 2px 8px; border-radius: 999px;
  background: var(--chip-bg, #f1f5f9); color: var(--text-muted, #64748b);
  cursor: pointer; border: 1px solid transparent; transition: all 100ms;
}
.home-feed-reaction-chip.active { background: #dbeafe; color: #1d4ed8; border-color: #93c5fd; }
.home-feed-reaction-chip:hover { border-color: var(--border, #cbd5e1); }
.home-feed-actions-right { margin-left: auto; display: inline-flex; gap: 6px; }

.home-feed-comments {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px dashed var(--border, #e5e7eb);
  display: none;
}
.home-feed-comments.open { display: block; }
.home-feed-comments-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.home-feed-comment {
  display: flex; gap: 8px; align-items: flex-start;
  background: var(--panel-alt, #f8fafc);
  border-radius: 8px; padding: 8px 10px;
}
.home-feed-comment .home-feed-avatar { width: 26px; height: 26px; font-size: 11px; }
.home-feed-comment-body { flex: 1; min-width: 0; font-size: 13.5px; line-height: 1.45; }
.home-feed-comment-head {
  display: flex; align-items: baseline; gap: 6px; font-size: 12px;
  color: var(--text-muted, #64748b); margin-bottom: 2px;
}
.home-feed-comment-head .home-feed-author { font-size: 12.5px; }
.home-feed-comment-text { white-space: pre-wrap; word-wrap: break-word; }
.home-feed-comment-empty { color: var(--text-muted, #64748b); font-size: 12.5px; padding: 6px 0; }
.home-feed-comment-form { display: flex; gap: 6px; align-items: stretch; }
.home-feed-comment-form textarea {
  flex: 1; box-sizing: border-box; border: 1px solid var(--border, #e5e7eb);
  border-radius: 8px; padding: 6px 8px; font: inherit; font-size: 13px;
  resize: vertical; min-height: 34px;
}
.home-feed-comment-form button { flex-shrink: 0; align-self: flex-end; }

/* Dark-mode overrides are gated by the APP's own theme class
   (`html.theme-dark`, toggled from the sidebar), NOT the OS
   `prefers-color-scheme` — otherwise these cards render dark even when
   the user has explicitly picked light mode on a dark-OS machine. */
html.theme-dark .home-feed-composer,
html.theme-dark .home-feed-post { background: #1e293b; border-color: #334155; }
html.theme-dark .home-feed-composer textarea { background: #0f172a; color: #e2e8f0; border-color: #334155; }
html.theme-dark .home-feed-body-text { color: #e2e8f0; }
html.theme-dark .home-feed-comment { background: #0f172a; }
html.theme-dark .home-feed-actions { border-top-color: #334155; }
html.theme-dark .home-feed-comments { border-top-color: #334155; }
html.theme-dark .home-feed-author-role-chip { background: #334155; color: #cbd5e1; }
html.theme-dark .home-feed-btn:hover { background: #334155; }
html.theme-dark .home-feed-btn.active { background: #1e3a8a; color: #dbeafe; }
html.theme-dark .home-feed-reaction-chip { background: #334155; color: #cbd5e1; }
html.theme-dark .home-feed-reaction-chip.active { background: #1e3a8a; color: #dbeafe; border-color: #3b82f6; }
html.theme-dark .home-feed-body-text .mention { background: #1e3a8a; color: #dbeafe; }

/* ── Home Feed · two-column layout (feed left · categories sidebar right)
   Added 26 Jul 2026 alongside the multi-category tag/filter feature.
   Sidebar stays fixed-width on desktop, collapses under the feed on
   tablet/mobile per the responsive breakpoints below.
   Keyboard-nav rule: chips are role="button" with tabindex=0 so ↹ Tab
   walks them; Enter/Space toggles the filter. */
.home-feed-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 240px;
  gap: 16px;
  align-items: start;
}
.home-feed-main { min-width: 0; }
/* When the middle column is squeezed (both sidebars open on a
   typical laptop) shrink the internal categories rail so the feed
   keeps a comfortable reading width instead of getting narrow. */
@media (max-width: 1280px) {
  .home-feed-body { grid-template-columns: minmax(0, 1fr) 220px; gap: 14px; }
}
.home-feed-sidebar {
  background: var(--panel, #fff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 12px;
  padding: 12px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  position: sticky;
  top: 12px;
  max-height: calc(100vh - 96px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.home-feed-sidebar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 2px 4px 6px;
  border-bottom: 1px solid var(--border, #e5e7eb);
}
.home-feed-sidebar-head h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--text-muted, #64748b);
  text-transform: uppercase;
}
.home-feed-cat-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-top: 4px;
}
/* Individual category row in the sidebar list. Click-to-filter (multi-select
   OR-semantics). Active state = filled colour swatch + inverted text. */
.home-feed-cat-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  color: var(--text, #0f172a);
  border: 1px solid transparent;
  transition: background-color 0.12s, border-color 0.12s;
  user-select: none;
}
.home-feed-cat-row:hover,
.home-feed-cat-row:focus-visible {
  background: var(--chip-bg, #f1f5f9);
  outline: none;
  border-color: var(--border, #e2e8f0);
}
.home-feed-cat-row.active {
  background: var(--brand-blue-soft, #dbeafe);
  border-color: var(--brand-blue, #2563eb);
  font-weight: 600;
}
.home-feed-cat-row .swatch {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  flex-shrink: 0;
  background: currentColor;
  opacity: 0.9;
}
.home-feed-cat-row .label { flex: 1 1 auto; min-width: 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
.home-feed-cat-row .count {
  font-size: 11px;
  color: var(--text-muted, #64748b);
  background: var(--chip-bg, #f1f5f9);
  padding: 1px 6px;
  border-radius: 999px;
  min-width: 22px;
  text-align: center;
}
.home-feed-cat-row.active .count { background: rgba(255,255,255,0.8); color: #1e3a8a; }
.home-feed-cat-row .del {
  display: none;
  border: none;
  background: transparent;
  color: var(--text-muted, #64748b);
  font-size: 13px;
  cursor: pointer;
  padding: 0 4px;
  line-height: 1;
}
.home-feed-cat-row:hover .del,
.home-feed-cat-row:focus-within .del { display: inline; }
.home-feed-cat-row .del:hover { color: #dc2626; }
.home-feed-cat-list-empty {
  font-size: 12px;
  color: var(--text-muted, #64748b);
  padding: 12px 4px;
  text-align: center;
}
/* "+ New" add-category composer inside the sidebar */
.home-feed-cat-addform {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px;
  background: var(--surface-sunk, #f8fafc);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px;
  margin-bottom: 4px;
}
.home-feed-cat-addform.hidden { display: none; }
.home-feed-cat-addform input[type="text"] {
  width: 100%;
  box-sizing: border-box;
  padding: 6px 8px;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  font: inherit;
  font-size: 13px;
  background: var(--bg, #fff);
  color: var(--text, #0f172a);
}
.home-feed-cat-addform-row { display: flex; align-items: center; gap: 6px; }
.home-feed-cat-addform input[type="color"] {
  width: 28px; height: 28px; padding: 0; border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px; cursor: pointer; background: transparent;
}
.home-feed-cat-addform-flash { font-size: 11.5px; min-height: 14px; }
.home-feed-cat-addform-flash.ok { color: #16a34a; }
.home-feed-cat-addform-flash.err { color: #dc2626; }

/* Composer category picker — same chip visual as sidebar rows.
   Sits between the textarea and the Post button row. */
.home-feed-composer-cats {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 8px;
  min-height: 0;
}
.home-feed-composer-cats:empty { display: none; }
.home-feed-composer-cat-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--border, #e2e8f0);
  background: var(--chip-bg, #f1f5f9);
  color: var(--text, #0f172a);
  font-size: 12px;
  cursor: pointer;
  user-select: none;
  line-height: 1.4;
}
.home-feed-composer-cat-chip .swatch {
  width: 8px; height: 8px; border-radius: 2px; background: currentColor; opacity: 0.85;
}
.home-feed-composer-cat-chip.selected {
  background: var(--brand-blue, #2563eb);
  color: #fff;
  border-color: var(--brand-blue, #2563eb);
  font-weight: 600;
}
.home-feed-composer-cat-chip.selected .swatch { background: #fff; opacity: 1; }
.home-feed-composer-cat-chip:focus-visible {
  outline: 2px solid #3b82f6; outline-offset: 1px;
}

/* Per-post category tag row inside .home-feed-post — same chip visual,
   read-only (no click), sits between the head row and the body text. */
.home-feed-post-cats {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: -2px 0 6px;
}
.home-feed-post-cats:empty { display: none; }
.home-feed-post-cat-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 11px;
  line-height: 1.5;
  background: var(--chip-bg, #f1f5f9);
  color: var(--text-muted, #475569);
  border: 1px solid var(--border, #e2e8f0);
  cursor: pointer;
  user-select: none;
}
.home-feed-post-cat-chip .swatch { width: 6px; height: 6px; border-radius: 2px; background: currentColor; opacity: 0.85; }
.home-feed-post-cat-chip:hover { background: var(--brand-blue-soft, #dbeafe); color: var(--brand-blue, #1d4ed8); }

/* Active-filter row above the feed list. Only visible when ≥1 category picked. */
.home-feed-active-filter {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 12px;
  background: var(--brand-blue-soft, #eff6ff);
  border: 1px solid var(--brand-blue, #bfdbfe);
  border-radius: 8px;
  font-size: 13px;
  color: var(--text, #0f172a);
  flex-wrap: wrap;
}
.home-feed-active-filter.hidden { display: none; }
.home-feed-active-filter .label { font-weight: 600; color: var(--brand-blue-strong, #1d4ed8); }
.home-feed-active-filter button {
  border: none;
  background: transparent;
  color: var(--brand-blue-strong, #1d4ed8);
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  padding: 2px 6px;
  border-radius: 4px;
  text-decoration: underline;
}
.home-feed-active-filter button:hover { background: rgba(255,255,255,0.7); text-decoration: none; }

/* ── Search (Home Feed header · 23 Jul 2026) ──────────────────────
   Small pill-shaped search bar sits in the header actions row, alongside
   the refresh + back buttons. Icon left, clear-button right (hidden until
   the input has content). Full width up to 260px so it doesn't crowd
   the header on wider viewports. */
.home-feed-search-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0;
  background: var(--surface-2, #f1f5f9);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 999px;
  padding: 4px 10px 4px 30px;
  width: 220px;
  max-width: 260px;
}
.home-feed-search-wrap:focus-within {
  border-color: var(--brand-blue, #3b82f6);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
}
.home-feed-search-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--fg-muted, #94a3b8);
  pointer-events: none;
}
.home-feed-search-wrap input[type="search"] {
  border: 0;
  outline: none;
  background: transparent;
  color: inherit;
  font-size: 13px;
  padding: 4px 0;
  width: 100%;
  min-width: 0;
}
.home-feed-search-wrap input[type="search"]::-webkit-search-cancel-button { display: none; }
.home-feed-search-clear {
  border: 0;
  background: transparent;
  color: var(--fg-muted, #94a3b8);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: 0 4px;
  border-radius: 4px;
}
.home-feed-search-clear:hover { color: var(--brand-blue, #3b82f6); background: rgba(59, 130, 246, 0.1); }
.home-feed-search-clear.hidden { display: none; }

/* ── Image attachments · rendered on posts and comments ───────────────
   Adaptive grid: 1 image = full width capped at 480px · 2 images = 1×2 ·
   3-4 images = 2×2. Anything past 4 spills into rows. Each thumbnail is a
   clickable anchor that opens the image in a new tab (native browser zoom
   for now — a full lightbox is a nice-to-have for later). */
.home-feed-attach-grid {
  display: grid;
  gap: 6px;
  margin: 8px 0 4px;
}
.home-feed-attach-count-1 { grid-template-columns: 1fr; max-width: 480px; }
.home-feed-attach-count-2 { grid-template-columns: 1fr 1fr; }
.home-feed-attach-count-3,
.home-feed-attach-count-4 { grid-template-columns: 1fr 1fr; }
.home-feed-attach-thumb {
  display: block;
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface-2, #f1f5f9);
  border: 1px solid var(--border, #e2e8f0);
  aspect-ratio: 4 / 3;
  cursor: zoom-in;
}
.home-feed-attach-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.home-feed-attach-thumb:hover { border-color: var(--brand-blue, #3b82f6); }
/* Comment attachments render smaller — max 240px wide grid to avoid
   dominating the reply column. */
.home-feed-comment .home-feed-attach-grid { max-width: 320px; }
.home-feed-comment .home-feed-attach-thumb { aspect-ratio: 1 / 1; }

/* ── Pending-attachment strip on the composer + comment-form ─────────
   Renders before the user hits "Post" or "Reply". Each thumbnail has a
   small × button to drop it before submit. */
.home-feed-attach-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0;
  margin: 4px 0 0;
}
.home-feed-attach-strip:empty { display: none; }
.home-feed-attach-pending {
  position: relative;
  width: 72px;
  height: 72px;
  border-radius: 6px;
  overflow: hidden;
  background: var(--surface-2, #f1f5f9);
  border: 1px solid var(--border, #e2e8f0);
}
.home-feed-attach-pending img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.home-feed-attach-remove {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.home-feed-attach-remove:hover { background: #dc2626; }
.home-feed-composer-attach-btn { display: inline-flex; align-items: center; gap: 4px; }
.home-feed-comment-attach-btn { padding: 4px 8px; font-size: 14px; }
.home-feed-comment-attach-strip { padding: 0 0 4px 32px; }
.home-feed-comment-attach-strip:empty { display: none; }

/* Dark theme parity */
html.theme-dark .home-feed-sidebar { background: #1e293b; border-color: #334155; }
html.theme-dark .home-feed-sidebar-head h3 { color: #94a3b8; }
html.theme-dark .home-feed-sidebar-head { border-bottom-color: #334155; }
html.theme-dark .home-feed-cat-row { color: #e2e8f0; }
html.theme-dark .home-feed-cat-row:hover,
html.theme-dark .home-feed-cat-row:focus-visible { background: #334155; border-color: #475569; }
html.theme-dark .home-feed-cat-row.active { background: #1e3a8a; border-color: #3b82f6; color: #dbeafe; }
html.theme-dark .home-feed-cat-row .count { background: #334155; color: #cbd5e1; }
html.theme-dark .home-feed-cat-row.active .count { background: rgba(255,255,255,0.15); color: #dbeafe; }
html.theme-dark .home-feed-cat-addform { background: #0f172a; border-color: #334155; }
html.theme-dark .home-feed-cat-addform input[type="text"] { background: #1e293b; color: #e2e8f0; border-color: #334155; }
html.theme-dark .home-feed-composer-cat-chip { background: #334155; color: #e2e8f0; border-color: #475569; }
html.theme-dark .home-feed-post-cat-chip { background: #334155; color: #cbd5e1; border-color: #475569; }
html.theme-dark .home-feed-active-filter { background: #1e293b; border-color: #3b82f6; color: #e2e8f0; }
html.theme-dark .home-feed-active-filter .label,
html.theme-dark .home-feed-active-filter button { color: #93c5fd; }
html.theme-dark .home-feed-search-wrap { background: #1e293b; border-color: #334155; }
html.theme-dark .home-feed-search-wrap:focus-within { border-color: #3b82f6; }
html.theme-dark .home-feed-search-wrap input[type="search"] { color: #e2e8f0; }
html.theme-dark .home-feed-attach-thumb,
html.theme-dark .home-feed-attach-pending { background: #0f172a; border-color: #334155; }

/* ── Responsive · tablet + mobile ─────────────────────────────────
   Below 1000px the middle column is narrow enough that the fixed
   980px max-width would introduce sideways scroll; drop the cap and
   let the feed use the full column with safe side padding.
   Below 900px the categories sidebar stacks under the feed as a
   horizontally-scrollable chip strip so it stays discoverable
   without eating vertical space.
   At the mobile breakpoint the padding tightens further and the
   composer hint (unused on mobile) hides. */
@media (max-width: 1000px) {
  #homeFeedView,
  body.folder-panel-collapsed #homeFeedView {
    max-width: none;
    padding: 18px 20px 40px;
  }
}
@media (max-width: 900px) {
  .home-feed-body { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .home-feed-sidebar {
    position: static;
    max-height: none;
    order: -1;
  }
  .home-feed-cat-list { flex-direction: row; flex-wrap: wrap; }
  .home-feed-cat-row { flex: 0 0 auto; }
}
@media (max-width: 600px) {
  #homeFeedView,
  body.folder-panel-collapsed #homeFeedView {
    padding: 12px 12px 32px;
  }
  #homeFeedHeader {
    padding: 2px 0 10px;
    margin-bottom: 12px;
  }
  #homeFeedHeader .header-actions { flex-wrap: wrap; }
  .home-feed-post,
  .home-feed-composer { padding: 12px 14px; }
  .home-feed-composer-hint { display: none; }
  /* Narrow phones — allow the author row + action row to wrap so
     avatar/name/timestamp and like/comment/delete never clip off. */
  .home-feed-post-head,
  .home-feed-actions { flex-wrap: wrap; }
}

/* ═══════════════════════════════════════════════════════════════════
   Menu Tiles view — tile-cluster of every sidebar menu + submenu item
   shown in the middle window whenever the user opens the sidebar Menu.
   Auto-populated from the live sidebar so the two never drift.
   ═══════════════════════════════════════════════════════════════════ */
#menuTilesView {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
#menuTilesView.hidden { display: none; }

#menuTilesHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 24px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-shrink: 0;
}
#menuTilesHeader h2 {
  margin: 0;
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.2px;
}
#menuTilesHeader .chat-subtitle {
  color: var(--muted);
  font-size: 12.5px;
}

/* Search — parity with sidebar-menu-search + Mini-App home-search */
.menu-tiles-search-wrap {
  position: relative;
  padding: 12px 24px 8px;
  background: var(--bg, var(--surface));
  flex-shrink: 0;
}
.menu-tiles-search-icon {
  position: absolute;
  left: 34px;
  top: 50%;
  transform: translateY(calc(-50% - 2px));
  color: var(--muted);
  pointer-events: none;
}
.menu-tiles-search-input {
  width: 100%;
  padding: 10px 32px 10px 34px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color 0.12s;
}
.menu-tiles-search-input::-webkit-search-cancel-button { display: none; }
.menu-tiles-search-input::placeholder { color: var(--muted); opacity: 0.85; }
.menu-tiles-search-input:focus { border-color: var(--primary, #0078BF); }
.menu-tiles-search-clear {
  position: absolute;
  right: 30px;
  top: 50%;
  transform: translateY(calc(-50% - 2px));
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 20px;
  line-height: 1;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  display: none;
  align-items: center;
  justify-content: center;
}
.menu-tiles-search-wrap.has-value .menu-tiles-search-clear { display: flex; }
.menu-tiles-search-clear:hover { background: var(--surface-2, rgba(0,0,0,0.05)); color: var(--text); }

/* Search hint — one-line explainer that the input searches beyond tiles */
.menu-tiles-search-hint {
  padding: 0 24px 8px;
  flex-shrink: 0;
}
.menu-tiles-search-hint-inner {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--muted);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 10px;
  line-height: 1.3;
}

/* The scroll container that owns BOTH the tile grid AND the global-search
   results section. Was previously the grid itself; moved out so the grid
   sits alongside a sibling results block and both share one scroll. */
.menu-tiles-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0 24px 24px;
}

/* Grid — 2-col on phones, scales up to 3-4 cols on desktop */
.menu-tiles-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  padding: 12px 0 0;
  align-content: start;
}

/* Individual tile — mirrors Mini-App .home-card so the two surfaces
   feel identical. Left-side accent stripe + decorative corner blob
   both driven by --tile-accent (assigned per tile in JS by hashing
   the tile id — same-tile keeps its colour across reloads). */
.menu-tile {
  appearance: none;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 14px;
  padding: 14px 14px 14px 18px;
  text-align: left;
  cursor: pointer;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 96px;
  overflow: hidden;
  transition: transform 0.08s ease, box-shadow 0.12s ease, border-color 0.12s ease;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.05);
}
.menu-tile::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  background: var(--tile-accent, var(--primary, #0078BF));
}
.menu-tile::after {
  content: '';
  position: absolute;
  right: -30px;
  bottom: -30px;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  background: var(--tile-accent, var(--primary, #0078BF));
  opacity: 0.08;
  pointer-events: none;
}
.menu-tile:hover {
  border-color: var(--tile-accent, var(--primary, #0078BF));
  box-shadow: 0 4px 14px rgba(15, 23, 42, 0.10);
}
.menu-tile:active { transform: scale(0.98); }
.menu-tile:focus-visible {
  outline: 2px solid var(--tile-accent, var(--primary, #0078BF));
  outline-offset: 2px;
}
.menu-tile.is-submenu {
  min-height: 76px;
  padding-left: 16px;
}
.menu-tile.is-submenu::before { width: 3px; }
.menu-tile-icon {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  width: 24px;
  height: 24px;
  font-size: 20px;
  line-height: 1;
  color: var(--tile-accent, var(--primary, #0078BF));
}
.menu-tile-icon svg { width: 22px; height: 22px; }
.menu-tile-label {
  font-weight: 700;
  font-size: 14px;
  color: var(--text);
  letter-spacing: -0.1px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.menu-tile-parent-hint {
  font-weight: 500;
  font-size: 10.5px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.menu-tile-blurb {
  font-size: 11.5px;
  color: var(--muted);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.menu-tile-badge {
  position: absolute;
  top: 10px;
  right: 12px;
  min-width: 18px;
  height: 18px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--primary, #0078BF);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
}

/* Section headers between tile clusters (top-level vs each submenu group) */
.menu-tiles-group-header {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 2px 2px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--muted);
}
.menu-tiles-group-header:not(:first-child) { margin-top: 8px; }

.menu-tile.menu-search-hidden { display: none !important; }
.menu-tiles-empty {
  padding: 24px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  font-style: italic;
}
.menu-tiles-empty.hidden { display: none; }

/* ── Global search results (thread titles + message content) ───────── */
.menu-tiles-global {
  margin-top: 24px;
  border-top: 1px solid var(--border);
  padding-top: 16px;
}
.menu-tiles-global.hidden { display: none; }
.menu-tiles-global-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 0 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--muted);
}
.menu-tiles-global-header-icon { font-size: 14px; }
.menu-tiles-global-header-label { flex: 0 0 auto; }
.menu-tiles-global-header-status {
  flex: 1 1 auto;
  text-align: right;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  font-size: 11.5px;
  color: var(--muted);
  font-style: italic;
}
.menu-tiles-global-section { margin: 8px 0 12px; }
.menu-tiles-global-section[hidden] { display: none; }
.menu-tiles-global-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 4px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
}
.menu-tiles-global-count {
  min-width: 20px;
  padding: 0 7px;
  height: 18px;
  border-radius: 999px;
  background: var(--primary, #0078BF);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.menu-tiles-global-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.menu-tiles-global-item {
  appearance: none;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 10px;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.12s, background-color 0.12s, transform 0.08s;
}
.menu-tiles-global-item:hover {
  border-color: var(--primary, #0078BF);
  background: var(--primary-tint, rgba(0, 120, 191, 0.06));
}
.menu-tiles-global-item:active { transform: scale(0.99); }
.menu-tiles-global-item:focus-visible {
  outline: 2px solid var(--primary, #0078BF);
  outline-offset: 2px;
}
.menu-tiles-global-item-title {
  font-weight: 700;
  font-size: 13.5px;
  color: var(--text);
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}
.menu-tiles-global-item-folder {
  font-weight: 500;
  font-size: 11px;
  color: var(--muted);
  text-transform: none;
}
.menu-tiles-global-item-folder::before {
  content: '·';
  margin-right: 6px;
  color: var(--border);
}
.menu-tiles-global-item-snippet {
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}
.menu-tiles-global-item-snippet mark {
  background: rgba(228, 76, 154, 0.18);
  color: var(--text);
  padding: 0 2px;
  border-radius: 3px;
  font-weight: 600;
}
.menu-tiles-global-item-meta {
  font-size: 10.5px;
  color: var(--muted);
  font-style: italic;
}
.menu-tiles-global-empty {
  padding: 20px 12px;
  text-align: center;
  color: var(--muted);
  font-size: 12.5px;
  font-style: italic;
  border: 1px dashed var(--border);
  border-radius: 10px;
  margin-top: 6px;
}
.menu-tiles-global-empty.hidden { display: none; }
.menu-tiles-global-header-status.is-loading::before {
  content: '';
  display: inline-block;
  width: 10px;
  height: 10px;
  border: 2px solid var(--muted);
  border-top-color: transparent;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: -1px;
  animation: menuTilesSpin 0.7s linear infinite;
}
@keyframes menuTilesSpin { to { transform: rotate(360deg); } }

/* Mobile — tighter grid, edge-to-edge padding */
@media (max-width: 600px) {
  #menuTilesHeader { padding: 12px 14px; }
  .menu-tiles-search-wrap { padding: 10px 14px 6px; }
  .menu-tiles-search-hint { padding: 0 14px 8px; }
  .menu-tiles-search-icon { left: 24px; }
  .menu-tiles-search-clear { right: 20px; }
  .menu-tiles-scroll { padding: 0 14px 24px; }
  .menu-tiles-grid {
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    padding: 10px 0 0;
  }
  .menu-tile { min-height: 100px; padding: 12px 10px 12px 14px; }
  .menu-tiles-global-item-title { font-size: 13px; }
  .menu-tiles-global-item-snippet { font-size: 12px; }
}

/* ═════════════════════════════════════════════════════════════════════
   ║  Threads Tiles view                                                ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Mirrors the Menu Tiles view but renders three parallel groups     ║
   ║  (Most active · Frequently used · Latest), each as its own tile    ║
   ║  cluster. Reuses .menu-tile visual language so the two surfaces    ║
   ║  feel identical (same accent-stripe, hover, focus ring).           ║
   ║                                                                    ║
   ║  Backed by GET /api/threads/tile-groups. Wired in web/app.js →     ║
   ║  showThreadsTilesView() + rebuildThreadsTiles().                   ║
   ║  Cross-UI parity: web/telegram-app.html #threadsTilesPane.         ║
   ╚════════════════════════════════════════════════════════════════════╝ */

/* Section chrome — the outer view uses the same header layout as
   menuTilesView, so we only need scoped styles for the group container
   and per-group headers. The tiles themselves reuse .menu-tile. */

.threads-tiles-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0 24px 24px;
}

.threads-tiles-status {
  padding: 12px 4px;
  color: var(--muted);
  font-size: 12.5px;
  font-style: italic;
}
.threads-tiles-status.is-error { color: #b42318; font-style: normal; }
.threads-tiles-status.hidden { display: none; }

.threads-tiles-groups {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 4px 0 0;
}

.threads-tiles-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.threads-tiles-group-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 2px 2px;
  color: var(--text);
}
.threads-tiles-group-icon {
  font-size: 16px;
  line-height: 1;
}
.threads-tiles-group-title {
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text);
}
.threads-tiles-group-count {
  min-width: 20px;
  padding: 0 7px;
  height: 18px;
  border-radius: 999px;
  background: var(--primary, #0078BF);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.threads-tiles-group-blurb {
  flex: 1 1 auto;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--muted);
  font-style: italic;
  text-align: right;
}
@media (max-width: 600px) {
  .threads-tiles-group-blurb { display: none; }
}

.threads-tiles-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
  padding: 0;
  align-content: start;
}

.threads-tiles-empty {
  padding: 12px 14px;
  border: 1px dashed var(--border);
  border-radius: 10px;
  text-align: center;
  color: var(--muted);
  font-size: 12.5px;
  font-style: italic;
  background: var(--surface);
}
.threads-tiles-empty.hidden { display: none; }

/* Individual thread tile — extends .menu-tile visual identity with a
   dedicated meta row for folder + coworker avatars + updated-at, and a
   dedicated stats row for message count / activity pills. */
.thread-tile { /* extends .menu-tile in JS via class combo */ }
.thread-tile .thread-tile-title-row {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.thread-tile .thread-tile-marker {
  font-size: 14px;
  line-height: 1;
  flex: 0 0 auto;
}
.thread-tile .thread-tile-title {
  font-weight: 700;
  font-size: 14px;
  color: var(--text);
  letter-spacing: -0.1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1 1 auto;
}
.thread-tile .thread-tile-pin {
  font-size: 12px;
  line-height: 1;
  color: var(--tile-accent, var(--primary, #0078BF));
  flex: 0 0 auto;
}
.thread-tile .thread-tile-folder {
  font-size: 11.5px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.thread-tile .thread-tile-folder::before {
  content: '📁 ';
  opacity: 0.7;
}
.thread-tile .thread-tile-stats {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: auto;
  padding-top: 4px;
}
.thread-tile .thread-tile-stat {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--surface-2, rgba(0,0,0,0.04));
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1.35;
  white-space: nowrap;
}
.thread-tile .thread-tile-stat.is-primary {
  background: color-mix(in srgb, var(--tile-accent, #0078BF) 12%, transparent);
  color: var(--tile-accent, #0078BF);
}
.thread-tile .thread-tile-stat.is-live {
  background: rgba(16, 185, 129, 0.15);
  color: #10b981;
}
.thread-tile .thread-tile-updated {
  margin-left: auto;
  font-size: 10.5px;
  color: var(--muted);
  font-style: italic;
  white-space: nowrap;
}
.thread-tile .thread-tile-coworkers {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding-left: 4px;
}
.thread-tile .thread-tile-coworker {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--surface-2, rgba(0,0,0,0.06));
  color: var(--text);
  font-size: 9.5px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--surface);
  margin-left: -6px;
}
.thread-tile .thread-tile-coworker:first-child { margin-left: 0; }
.thread-tile.menu-search-hidden { display: none !important; }

/* Sidebar Threads section — small "View as tiles" icon button that
   opens showThreadsTilesView() without collapsing the accordion. */
.sidebar-threads-header {
  display: flex;
  align-items: stretch;
  gap: 0;
}
.sidebar-threads-header > #threadsToggle { flex: 1 1 auto; min-width: 0; }
.sidebar-threads-tile-btn {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  padding: 0 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  flex: 0 0 auto;
  transition: color 0.12s, background-color 0.12s;
}
.sidebar-threads-tile-btn:hover {
  color: var(--primary, #0078BF);
  background: color-mix(in srgb, var(--primary, #0078BF) 12%, transparent);
}
.sidebar-threads-tile-btn:focus-visible {
  outline: 2px solid var(--primary, #0078BF);
  outline-offset: 1px;
}

@media (max-width: 600px) {
  #threadsTilesHeader { padding: 12px 14px; }
  .threads-tiles-scroll { padding: 0 14px 24px; }
  .threads-tiles-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .thread-tile { min-height: 108px; }
}

/* ═════════════════════════════════════════════════════════════════════
   ║  Composer action bar — unification pass (final)                    ║
   ║  ────────────────────────────────────────────────────────────────  ║
   ║  Single source of truth for the composer toolbar's layout,         ║
   ║  spacing, sizing, wrap behaviour, and Send-anchoring. Sits at the  ║
   ║  end of the file so it wins over every earlier baseline rule       ║
   ║  (.mode-picker-btn padding, .queue-pill padding, per-media         ║
   ║  wrappers, touch-coarse bumps).                                    ║
   ║                                                                     ║
   ║  Ordering in DOM: Attach · Dictate · Listen · Hands-free ·         ║
   ║  Mode(Agent) · Provider(Claude/Grok) · Queue idea · Prompt guide · ║
   ║  Queue-badge (conditional) · Send.                                 ║
   ║                                                                     ║
   ║  Contract every direct child obeys on desktop / tablet / mobile:    ║
   ║   • height 34px (baseline) · 40px on coarse pointer                ║
   ║   • border-radius 8px                                              ║
   ║   • padding 0 12px · inline-flex align-items center · gap 6px      ║
   ║   • font-size 13px · line-height 1                                 ║
   ║   • icon svg 16×16 · flex-shrink 0 (never truncates label)         ║
   ║  Send button is primary → same height, wider min-width,            ║
   ║  auto-margin pushes it to the far right on every wrap tier so it   ║
   ║  never floats mid-row.                                             ║
   ║                                                                     ║
   ║  Wrap tiers (breakpoints picked to keep the toolbar readable at    ║
   ║  the sizes the design-brief flags: 320 / 375 / 768 / 1024 / 1280   ║
   ║  / 1440 / 1920):                                                   ║
   ║   • ≥ 900px composer-width: one clean row                          ║
   ║   • 600–899px: wraps into balanced rows (no orphan — see notes)    ║
   ║   • ≤ 599px: icon-only secondary buttons keep everything on one    ║
   ║     tight row + Send stays anchored right (existing @640 rules     ║
   ║     already hide Attach/Queue labels; we extend to Prompt guide    ║
   ║     so the orphan-alone case can't happen at any width)            ║
   ═════════════════════════════════════════════════════════════════════ */

/* ── Baseline row — wrap-capable, uniform gap, aligned to center ──── */
.composer-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  row-gap: 8px;
  padding: 8px 10px 10px;
  min-height: 50px; /* prevents layout jump when attachments appear */
}

/* ── Uniform sizing for EVERY interactive child of the row ────────── */
.composer-row > :where(
  .btn,
  button,
  .mode-picker-wrap,
  .queue-pill
) {
  height: 34px;
  min-height: 34px;
  flex: 0 0 auto;              /* never shrink label into ellipsis    */
  align-self: center;
}

.composer-row > :where(.btn, button) {
  border-radius: 8px;
  padding: 0 12px;
  font-size: 13px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  box-sizing: border-box;
  white-space: nowrap;
}

/* Wrapper divs (mode-picker) — the wrapper is a flex child, its inner
   button carries the actual visual chrome. Match height + baseline. */
.composer-row > .mode-picker-wrap {
  display: inline-flex;
  align-items: center;
}
.composer-row .mode-picker-btn {
  height: 34px;
  min-height: 34px;
  padding: 0 10px 0 12px;
  gap: 6px;
  border-radius: 8px;
  font-size: 13px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  box-sizing: border-box;
  white-space: nowrap;
}

/* Icons inside toolbar buttons — uniform 14px, centred, no shrink.
   (Down from 16px in the earlier revision — a two-pixel trim gives the
   row ~12px per button of horizontal headroom, which combined with the
   icon-only treatment below stops any label from ever truncating
   inside the composer frame.) */
.composer-row > :where(.btn, button) > svg,
.composer-row .mode-picker-btn > svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
/* Emoji / character glyphs used as icons (∞ 🧠 ⓘ etc.) keep the same
   14-px optical box so the row baseline stays straight.
   NOTE: state-toggled icon pairs (.mic-idle / .mic-recording,
   .tts-off / .tts-on, .hf-off / .hf-on) are EXCLUDED from this rule
   because they rely on `display: none` (line ~14867-14910) to hide
   the inactive icon. Overriding `display` here would show BOTH icons
   simultaneously — the "duplicate emoji" bug on Dictate / Listen /
   Hands-free. Their sizing is handled by the dedicated block below. */
.composer-row > :where(.btn, button) > span[aria-hidden="true"]:not([class*="label"]):not([class*="chev"]):not(.mic-idle):not(.mic-recording):not(.tts-off):not(.tts-on):not(.hf-off):not(.hf-on),
.composer-row .mode-picker-btn > .mode-picker-icon,
.composer-row .thread-provider-icon {
  width: 14px;
  height: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  line-height: 1;
  flex-shrink: 0;
}

/* State-toggled icon pairs — size + baseline only; `display` is
   deliberately omitted so the per-state visibility rules earlier in
   the file (`.composer-mic .mic-recording { display: none }`, etc.)
   remain the source of truth for which icon is visible. */
.composer-row .composer-mic > .mic-idle,
.composer-row .composer-mic > .mic-recording,
.composer-row .composer-tts > .tts-off,
.composer-row .composer-tts > .tts-on,
.composer-row .composer-hands-free > .hf-off,
.composer-row .composer-hands-free > .hf-on {
  width: 14px;
  height: 14px;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  line-height: 1;
  flex-shrink: 0;
}
/* Chevron is smaller — align next to the label at the same optical
   height without being the visual anchor. */
.composer-row .mode-picker-btn > .mode-picker-chev {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}

/* Labels never truncate inside the composer toolbar — overriding the
   generic toolbar-label ellipsis rule earlier in this file. */
.composer-row > :where(.btn, button) > span:not([aria-hidden="true"]),
.composer-row .mode-picker-btn > .mode-picker-label,
.composer-row .thread-provider-label {
  max-width: none;
  overflow: visible;
  text-overflow: clip;
  white-space: nowrap;
  line-height: 1;
}

/* Queue-pill (badge) — same height + inline-flex baseline as the
   other secondary buttons, but retains its pill shape / colour. */
.composer-row > .queue-pill {
  height: 34px;
  padding: 0 12px;
  border-radius: 999px;
  font-size: 12.5px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  box-sizing: border-box;
  white-space: nowrap;
}

/* ── Send button — primary, right-anchored, prominent ──────────────── */
.composer-row > #sendBtn {
  height: 34px;
  min-height: 34px;
  min-width: 84px;
  padding: 0 16px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  margin-inline-start: auto; /* pins Send to the far right at every tier */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex-shrink: 0;
  box-sizing: border-box;
  white-space: nowrap;
}
.composer-row > #sendBtn > svg {
  width: 16px;
  height: 16px;
}
.composer-row > #sendBtn:not(:disabled) {
  box-shadow: 0 1px 3px var(--primary-tint-strong);
}

/* ── Consistent focus ring across every toolbar control ───────────── */
.composer-row > :where(.btn, button):focus-visible,
.composer-row .mode-picker-btn:focus-visible {
  outline: 2px solid var(--primary, #0d7377);
  outline-offset: 2px;
}
.composer-row > :where(.btn, button):disabled,
.composer-row .mode-picker-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* ── Mobile tier (≤ 640px) — condensed secondary buttons + Send stays
     right-anchored. Adds Prompt guide to the label-hidden set so the
     "single button orphaned on its own row" case never triggers. Icons
     alone are legible + tooltips remain via title=. */
@media (max-width: 640px) {
  .composer-row {
    padding: 8px 8px 10px;
    gap: 6px;
    row-gap: 6px;
  }
  .composer-row > :where(.btn, button),
  .composer-row .mode-picker-btn,
  .composer-row > #sendBtn {
    height: 40px;   /* comfortable thumb-tap on phones */
    min-height: 40px;
  }
  .composer-row > .queue-pill { height: 40px; }
  /* Icon-only for space-saving secondary actions — Attach, Queue idea,
     and Prompt guide. Their label spans hide, tooltip stays for a11y. */
  #composer .composer-row #attachBtn > span:not([aria-hidden="true"]),
  #composer .composer-row #queueIdeaBtn > span:not([aria-hidden="true"]),
  #composer .composer-row #promptGuideBtn > span:not([aria-hidden="true"]) {
    display: none;
  }
  #composer .composer-row :where(#attachBtn, #queueIdeaBtn, #promptGuideBtn) {
    padding: 0 12px;
    min-width: 40px;
    justify-content: center;
  }
  /* Mode picker label caps at 7ch so "Multitask" doesn't force wrap. */
  #composer .composer-row .mode-picker-btn .mode-picker-label,
  #composer .composer-row .thread-provider-label {
    max-width: 8ch;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* ── Mid-desktop tier (641–1024px) — collapse ONLY the tertiary
     "secondary-action" labels (Attach · Queue idea · Prompt guide)
     to icon-only so all 9 controls (Attach · Dictate · Listen ·
     Hands-free · Agent · Provider · Queue idea · Prompt guide · Send)
     fit on ONE row without wrapping. Without this tier, at the
     typical sidebar-open composer width (~800–900px) the row wraps
     leaving Prompt guide orphaned on the left and Send anchored right
     with a big empty gap — the "alignment" bug the admin flagged. */
@media (min-width: 641px) and (max-width: 1024px) {
  #composer .composer-row #attachBtn > span:not([aria-hidden="true"]),
  #composer .composer-row #queueIdeaBtn > span:not([aria-hidden="true"]),
  #composer .composer-row #promptGuideBtn > span:not([aria-hidden="true"]) {
    display: none;
  }
  #composer .composer-row :where(#attachBtn, #queueIdeaBtn, #promptGuideBtn) {
    padding: 0 10px;
    min-width: 34px;
    justify-content: center;
  }
  /* Give the mode-picker + provider labels a little more headroom
     than mobile since we're not width-starved anymore. */
  #composer .composer-row .mode-picker-btn .mode-picker-label,
  #composer .composer-row .thread-provider-label {
    max-width: 10ch;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* ── Extra-small tier (≤ 380px) — Attach becomes the only paperclip
     icon left in reading order; everything else stays sized for tap. */
@media (max-width: 380px) {
  .composer-row { gap: 4px; row-gap: 6px; padding: 8px 6px 10px; }
  .composer-row > #sendBtn { min-width: 68px; padding: 0 12px; }
}

/* ── Coarse-pointer override — the generic touch bump at line 15106
     forces 44×44 on every button; on the composer toolbar we want a
     tighter 40px so the row stays visually cohesive rather than
     ballooning. The 40px still exceeds the 36px baseline the earlier
     override set and comfortably clears the WCAG 2.5.5 target size. */
@media (pointer: coarse) {
  .composer-row > :where(.btn, button),
  .composer-row .mode-picker-btn,
  .composer-row > #sendBtn,
  .composer-row > .queue-pill {
    min-height: 40px;
    height: 40px;
  }
  .composer-row > :where(.btn, button) { min-width: auto; }
}

/* ── Desktop tier (≥ 1025px) — single-row, no-wrap, no-overflow ────────
   Keeps all 9 labelled controls
   (Attach · Dictate · Listen · Hands-free · Agent · LLM · Queue idea ·
    Prompt guide · Send)
   on ONE horizontal line at every practical desktop composer width,
   AND guarantees Send never leaks past the composer's right border.

   Two failure modes fixed together:
     (1) Wrapping — solved by `flex-wrap: nowrap`.
     (2) Overflow — solved by letting the labelled secondary buttons
         SHRINK (labels ellipsis-clip when the row is tight) while
         Send stays `flex-shrink: 0` and right-anchored via the
         existing `margin-inline-start: auto`. `min-width: 0` on the
         row + `overflow: hidden` on the card prevent any horizontal
         bleed past the container border.

   Padding + gap are trimmed just enough (12→8px pad, 6→4px gap) so
   the aggregate row fits at typical desktop widths without visible
   truncation. Below 1025px viewport the existing tablet tier
   collapses tertiary labels; below 640px the mobile tier condenses
   further. Wrapping stays reserved for tablet / mobile only.  */
@media (min-width: 1025px) {
  /* Card is the visible border — clip any accidental HORIZONTAL child
     bleed so the toolbar row stays inside the rounded frame, but keep
     vertical overflow visible so upward-opening popovers (mode picker
     "Agent / Plan / Debug / Multitask / Ask", LLM picker, queue
     popover, etc.) can escape above the composer instead of being
     sliced off at the card's top edge.
     `overflow: clip visible` = `overflow-x: clip; overflow-y: visible`;
     unlike `hidden`, `clip` does NOT force the paired axis to also
     clip, so vertical popovers render unclipped. */
  #composer .composer-card {
    overflow: clip visible;
  }
  .composer-row {
    flex-wrap: nowrap;
    gap: 4px;
    min-width: 0;              /* let the row shrink inside its parent  */
  }
  .composer-row > :where(.btn, button),
  .composer-row .mode-picker-btn {
    padding: 0 8px;
  }
  /* Every child EXCEPT Send may shrink when the row runs out of room.
     Labels truncate with an ellipsis before the icons disappear, so
     the row stays scannable and no button falls outside the frame.  */
  .composer-row > :where(.btn, button):not(#sendBtn),
  .composer-row > .mode-picker-wrap {
    min-width: 0;
    flex-shrink: 1;
  }
  .composer-row > :where(.btn, button):not(#sendBtn) > span:not([aria-hidden="true"]),
  .composer-row .mode-picker-btn > .mode-picker-label,
  .composer-row .thread-provider-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Send stays fully visible, right-anchored, never shrinks. */
  .composer-row > #sendBtn {
    padding: 0 14px;
    min-width: 80px;
    flex-shrink: 0;
  }

  /* ── Icon-only for the six self-explanatory secondaries ─────────────
     Previous rev used ellipsis-truncation on every label when the row
     was tight — produced the "A… Di… Li… Hand… C… D… Queu… Promp…"
     screenshot the admin flagged. The permanent fix: the six secondary
     buttons carry universally-recognisable icons (paperclip 📎, 🎙, 🔊,
     📞, 💡 bulb, ⓘ) so their labels are informational, not identity.
     Drop the label on those SIX everywhere on desktop; keep the label
     on the two identity-controls (Agent mode, Provider) + Send, which
     encode STATE that the user needs to read at a glance.
     Tooltips (title=) stay in place on the icon-only buttons for
     mouse-hover discoverability + a11y still exposes aria-label. */
  #composer .composer-row :where(
    #attachBtn,
    #queueIdeaBtn,
    #promptGuideBtn,
    .composer-mic,
    .composer-tts,
    .composer-hands-free
  ) > span:not([aria-hidden="true"]) {
    display: none;
  }
  #composer .composer-row :where(
    #attachBtn,
    #queueIdeaBtn,
    #promptGuideBtn,
    .composer-mic,
    .composer-tts,
    .composer-hands-free
  ) {
    padding: 0 8px;
    min-width: 32px;
    justify-content: center;
  }
}
/* ═════════════════ end composer action-bar unification pass ═══════════ */

/* ═════════════════ my-thread HODO blue wash ══════════════════════════
 * Threads the viewer created get a soft HODO primary blue tint so they
 * stand out from shared / assigned / co-worked threads in a busy sidebar.
 * Uses the same #0078BF brand blue as agent chips + other HODO chrome.
 * Active / pinned modifiers still win for emphasis; this is a quiet wash.
 * ─────────────────────────────────────────────────────────────────── */
.folder-threads > li[data-id].thread-row--mine,
#threadList li[data-id].thread-row--mine {
  background: rgba(0, 120, 191, 0.10);
  box-shadow: inset 3px 0 0 0 var(--brand-blue, #0078BF);
}
.folder-threads > li[data-id].thread-row--mine:hover,
#threadList li[data-id].thread-row--mine:hover {
  background: rgba(0, 120, 191, 0.16);
}
/* Active row keeps its primary tint, but retain the blue left edge so
   ownership stays readable even while selected. */
.folder-threads > li[data-id].thread-row--mine.active,
#threadList li[data-id].thread-row--mine.active {
  box-shadow: inset 3px 0 0 0 var(--brand-blue, #0078BF);
}

/* ═══════════════════════════════════════════════════════════════════════
 * Thread Sidecar Chat (3 Aug 2026) — right-dock panel + superadmin
 * firehose + floating opener + toast pop-up. See web/app-thread-chat.js
 * for the wiring and /opt/dev/imagine/src/threadChat.ts for the server.
 * ═══════════════════════════════════════════════════════════════════════ */

.thread-chat-panel {
  position: fixed;
  right: 16px;
  bottom: 16px;
  top: 72px;
  width: 380px;
  max-width: calc(100vw - 32px);
  background: var(--surface, #ffffff);
  border: 1px solid var(--border, #d1d5db);
  border-radius: 14px;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.18);
  display: flex;
  flex-direction: column;
  z-index: 4200;
  font-family: inherit;
  overflow: hidden;
}
.thread-chat-panel[hidden] { display: none; }
@media (max-width: 640px) {
  .thread-chat-panel {
    left: 8px; right: 8px; bottom: 8px; top: 60px;
    width: auto; max-width: none; border-radius: 12px;
  }
}
@media (prefers-color-scheme: dark) {
  .thread-chat-panel {
    background: var(--surface, #0f172a);
    border-color: var(--border, #334155);
  }
}

.thread-chat-panel-head {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border, #e5e7eb);
  background: var(--surface-2, #f8fafc);
}
.thread-chat-panel-title-wrap { flex: 1; min-width: 0; }
.thread-chat-panel-title {
  font-weight: 600; font-size: 14px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--text, #0f172a);
}
.thread-chat-presence {
  display: flex; flex-wrap: wrap; gap: 4px 6px;
  margin-top: 2px; font-size: 11px; color: var(--muted, #64748b);
}
.thread-chat-presence-dot {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 6px 1px 4px;
  background: rgba(16, 185, 129, 0.08);
  color: #059669; border-radius: 999px;
  font-weight: 500;
}
.thread-chat-presence-glyph {
  width: 6px; height: 6px; border-radius: 50%;
  background: #10b981; box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.18);
}
.thread-chat-presence-more { color: var(--muted, #64748b); font-weight: 500; }

.thread-chat-back-btn, .thread-chat-close-btn {
  appearance: none; background: transparent; border: none; cursor: pointer;
  color: var(--muted, #64748b); padding: 4px; border-radius: 6px;
  display: inline-flex; align-items: center; justify-content: center;
}
.thread-chat-back-btn:hover, .thread-chat-close-btn:hover {
  background: var(--surface-3, #eef2f7); color: var(--text, #0f172a);
}
.thread-chat-close-btn { font-size: 20px; line-height: 1; width: 28px; height: 28px; font-weight: 700; }

.thread-chat-messages {
  flex: 1; overflow-y: auto;
  padding: 12px; display: flex; flex-direction: column; gap: 10px;
  background: var(--surface, #ffffff);
}
.thread-chat-empty {
  text-align: center; color: var(--muted, #64748b); padding: 24px 12px;
  font-size: 13px; line-height: 1.55;
}
.thread-chat-empty-hint { font-size: 11.5px; opacity: 0.85; }
.thread-chat-empty code {
  background: var(--surface-2, #f1f5f9); padding: 1px 4px; border-radius: 4px;
  font-family: ui-monospace, Menlo, monospace; font-size: 11px;
}

.thread-chat-row {
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px 10px; border-radius: 10px;
  background: var(--surface-2, #f8fafc);
  border: 1px solid transparent;
  max-width: 100%;
}
.thread-chat-row.is-mine {
  background: rgba(0, 120, 191, 0.06);
  border-color: rgba(0, 120, 191, 0.2);
}
.thread-chat-row.is-agent {
  background: rgba(228, 76, 154, 0.05);
  border-color: rgba(228, 76, 154, 0.18);
}
.thread-chat-row.is-deleted { opacity: 0.55; }
.thread-chat-row-head {
  display: flex; align-items: center; gap: 6px; font-size: 11.5px;
  color: var(--muted, #64748b);
}
.thread-chat-author { font-weight: 600; color: var(--text, #0f172a); }
.thread-chat-author-me { color: var(--brand-blue, #0078BF); }
.thread-chat-author-agent { color: var(--brand-pink, #E44C9A); }
.thread-chat-time { font-size: 10.5px; }
.thread-chat-edited { font-size: 10px; opacity: 0.7; font-style: italic; }
.thread-chat-row-body {
  font-size: 13.5px; line-height: 1.5; color: var(--text, #0f172a);
  word-break: break-word; margin-top: 2px;
}
.thread-chat-mention {
  background: rgba(228, 76, 154, 0.1); color: var(--brand-pink, #E44C9A);
  padding: 0 3px; border-radius: 4px; font-weight: 600;
}
.thread-chat-row-controls {
  margin-left: auto; opacity: 0; transition: opacity 0.15s;
}
.thread-chat-row:hover .thread-chat-row-controls { opacity: 1; }
.thread-chat-row-controls button {
  appearance: none; background: transparent; border: none; cursor: pointer;
  padding: 2px 4px; margin-left: 2px; border-radius: 4px;
  color: var(--muted, #64748b); font-size: 12px;
}
.thread-chat-row-controls button:hover { background: var(--surface-3, #eef2f7); color: var(--text, #0f172a); }
.thread-chat-deleted { font-style: italic; opacity: 0.7; }

.thread-chat-composer {
  display: flex; gap: 6px; align-items: flex-end;
  padding: 10px 12px; border-top: 1px solid var(--border, #e5e7eb);
  background: var(--surface-2, #f8fafc);
  position: relative;
}
.thread-chat-composer textarea {
  flex: 1; resize: none; overflow-y: auto;
  padding: 8px 10px; border: 1px solid var(--border, #d1d5db); border-radius: 8px;
  background: var(--surface, #ffffff); color: var(--text, #0f172a);
  font-family: inherit; font-size: 13.5px; line-height: 1.45;
  min-height: 36px; max-height: 160px;
}
.thread-chat-composer textarea:focus {
  outline: none; border-color: var(--brand-blue, #0078BF);
  box-shadow: 0 0 0 2px rgba(0, 120, 191, 0.15);
}
.thread-chat-send-btn {
  appearance: none; background: var(--brand-blue, #0078BF); color: #ffffff;
  border: none; border-radius: 8px; cursor: pointer;
  width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.thread-chat-send-btn:hover { background: #005f97; }
.thread-chat-send-btn:disabled { opacity: 0.5; cursor: not-allowed; }

.thread-chat-mention-pop {
  position: absolute; bottom: 100%; left: 12px; right: 12px;
  background: var(--surface, #ffffff);
  border: 1px solid var(--border, #d1d5db); border-radius: 8px;
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
  max-height: 220px; overflow-y: auto; margin-bottom: 4px; z-index: 10;
}
.thread-chat-mention-pop[hidden] { display: none; }
.thread-chat-mention-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; cursor: pointer; font-size: 13px;
}
.thread-chat-mention-row.is-active { background: var(--surface-2, #eef2f7); }
.thread-chat-mention-row:hover { background: var(--surface-3, #e2e8f0); }
.thread-chat-mention-emoji { font-size: 16px; width: 20px; text-align: center; }
.thread-chat-mention-slug { font-weight: 600; color: var(--brand-pink, #E44C9A); }
.thread-chat-mention-name { color: var(--muted, #64748b); font-size: 11.5px; margin-left: auto; }

/* Floating opener — bottom-right button when a thread is active and the
   panel is closed. Users unfamiliar with Ctrl-J can find the chat here. */
.thread-chat-opener {
  position: fixed; bottom: 16px; right: 16px;
  width: 48px; height: 48px; border-radius: 50%;
  background: var(--brand-blue, #0078BF); color: #ffffff;
  border: none; cursor: pointer; font-size: 22px; line-height: 1;
  box-shadow: 0 8px 20px rgba(0, 120, 191, 0.35);
  display: inline-flex; align-items: center; justify-content: center;
  z-index: 4100; transition: transform 0.15s, box-shadow 0.15s;
}
.thread-chat-opener:hover { transform: translateY(-2px); box-shadow: 0 12px 24px rgba(0, 120, 191, 0.4); }
.thread-chat-opener-badge {
  position: absolute; top: -4px; right: -4px;
  min-width: 18px; height: 18px; padding: 0 5px;
  background: #E44C9A; color: white; border-radius: 999px;
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
  border: 2px solid white;
}
.thread-chat-opener-badge[hidden] { display: none; }
/* Hide the opener whenever the panel is open. */
.thread-chat-panel.is-open ~ #threadChatOpener,
.thread-chat-panel.is-open + #threadChatOpener {
  display: none !important;
}

/* Superadmin firehose — full-screen list view */
.thread-chat-firehose {
  position: fixed; inset: 0; background: var(--surface, #ffffff);
  z-index: 4300; overflow-y: auto;
}
.thread-chat-firehose.hidden, .thread-chat-firehose[hidden] { display: none; }
.thread-chat-firehose-head {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface-2, #f8fafc);
  border-bottom: 1px solid var(--border, #e5e7eb);
  padding: 14px 20px; display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
}
.thread-chat-firehose-head h2 { margin: 0; font-size: 17px; color: var(--text, #0f172a); }
.thread-chat-firehose-sub { color: var(--muted, #64748b); font-size: 12.5px; flex: 1; }
.thread-chat-firehose-head button {
  appearance: none; background: transparent; border: 1px solid var(--border, #d1d5db);
  color: var(--muted, #64748b); border-radius: 6px; padding: 4px 10px;
  cursor: pointer; font-size: 18px; line-height: 1; font-weight: 700;
}
.thread-chat-firehose-head button:hover { background: var(--surface-3, #eef2f7); }
.thread-chat-firehose-list { padding: 12px 20px 40px; display: flex; flex-direction: column; gap: 8px; }
.thread-chat-firehose-empty { color: var(--muted, #64748b); padding: 40px; text-align: center; }
.thread-chat-firehose-row {
  display: block; width: 100%; text-align: left;
  padding: 12px 14px; border-radius: 10px;
  background: var(--surface, #ffffff);
  border: 1px solid var(--border, #e5e7eb); cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
  font-family: inherit;
}
.thread-chat-firehose-row:hover {
  background: var(--surface-2, #f8fafc);
  border-color: var(--brand-blue, #0078BF);
}
.thread-chat-firehose-row-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 4px; }
.thread-chat-firehose-title { font-weight: 600; color: var(--text, #0f172a); font-size: 14px; }
.thread-chat-firehose-when { color: var(--muted, #64748b); font-size: 11.5px; }
.thread-chat-firehose-badge {
  background: #E44C9A; color: white; border-radius: 999px;
  padding: 1px 8px; font-size: 11px; font-weight: 700; margin-left: auto;
}
.thread-chat-firehose-row-body { font-size: 13px; color: var(--text, #0f172a); }
.thread-chat-firehose-author { font-weight: 600; margin-right: 4px; }
.thread-chat-firehose-preview { color: var(--muted, #64748b); }
.thread-chat-firehose-row-foot {
  display: flex; gap: 12px; margin-top: 6px;
  font-size: 11px; color: var(--muted, #64748b);
}
.thread-chat-firehose-cwd { font-family: ui-monospace, Menlo, monospace; }

/* Small badge for the "Thread Chats" sidebar entry — total unread across
   the firehose. Superadmin-only. */
.sidebar-dashboard-badge {
  background: #E44C9A; color: white; border-radius: 999px;
  padding: 0 6px; font-size: 10.5px; font-weight: 700; margin-left: auto;
  min-width: 18px; height: 16px; line-height: 16px; text-align: center;
}
.sidebar-dashboard-badge[hidden] { display: none; }

/* ═══════════════════════════════════════════════════════════════════════
   Slack-style Channels view — 3-pane layout
   • .ch-sidebar (left) · channels list + new-channel form
   • .ch-stream (center) · header + messages + composer
   • .ch-thread (right) · threaded replies, slides in on message click
   Reuses existing --primary / --bg / --border / --text vars.
   ═══════════════════════════════════════════════════════════════════════ */

#channelsView {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  background: var(--bg);
}
#channelsView.hidden { display: none; }

#channelsHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
  background: var(--card, #fff);
  flex-shrink: 0;
}
#channelsHeader h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--text, #0f172a);
}
#channelsHeader .chat-subtitle {
  font-size: 12.5px;
  color: var(--muted, #64748b);
}

.ch-body {
  display: grid;
  grid-template-columns: 260px 1fr;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
.ch-body.thread-open { grid-template-columns: 260px 1fr 380px; }

/* ── LEFT SIDEBAR ────────────────────────────────────────────────── */
.ch-sidebar {
  background: #19171D;      /* Slack-ish dark navy */
  color: #C9C7CD;
  overflow-y: auto;
  min-height: 0;
  border-right: 1px solid rgba(255, 255, 255, 0.06);
  display: flex;
  flex-direction: column;
}
.ch-sidebar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  flex-shrink: 0;
}
.ch-sidebar-head h3 {
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #C9C7CD;
}
.ch-sidebar-head button {
  color: #C9C7CD !important;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.ch-sidebar-head button:hover {
  background: rgba(255, 255, 255, 0.08);
  color: white !important;
}
.ch-new-channel-form {
  padding: 12px 14px;
  background: rgba(255, 255, 255, 0.04);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ch-new-channel-form input[type="text"],
.ch-new-channel-form textarea {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.08);
  color: white;
  border-radius: 4px;
  font-size: 13px;
  font-family: inherit;
  resize: vertical;
}
.ch-new-channel-form input[type="text"]:focus,
.ch-new-channel-form textarea:focus {
  outline: none;
  border-color: var(--primary, #0D7377);
  background: rgba(255, 255, 255, 0.12);
}
.ch-new-channel-form input::placeholder,
.ch-new-channel-form textarea::placeholder { color: rgba(255, 255, 255, 0.4); }
.ch-new-channel-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.ch-new-channel-vis {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: #C9C7CD;
  cursor: pointer;
  margin-right: auto;
}
.ch-new-channel-flash {
  font-size: 12px;
  color: #F87171;
  min-height: 14px;
}
.ch-new-channel-flash.success { color: #6EE7B7; }

.ch-sidebar-list {
  flex: 1;
  overflow-y: auto;
  padding: 6px 0;
}
.ch-sidebar-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  cursor: pointer;
  font-size: 14px;
  color: #C9C7CD;
  border: none;
  background: transparent;
  width: 100%;
  text-align: left;
  font-family: inherit;
  border-radius: 0;
}
.ch-sidebar-item:hover { background: rgba(255, 255, 255, 0.06); color: white; }
.ch-sidebar-item.active { background: var(--primary, #0D7377); color: white; }
.ch-sidebar-item .ch-sidebar-hash {
  opacity: 0.6;
  font-weight: 400;
  margin-right: 2px;
}
.ch-sidebar-item.active .ch-sidebar-hash { opacity: 0.9; }
.ch-sidebar-item .ch-sidebar-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ch-sidebar-item.unread .ch-sidebar-name { font-weight: 700; color: white; }
.ch-sidebar-item .ch-sidebar-badge {
  background: #E44C9A;
  color: white;
  border-radius: 999px;
  padding: 1px 7px;
  font-size: 11px;
  font-weight: 700;
  min-width: 18px;
  text-align: center;
}
.ch-sidebar-item .ch-sidebar-badge[hidden] { display: none; }
.ch-sidebar-item .ch-sidebar-lock {
  opacity: 0.55;
  font-size: 10px;
  margin-right: 4px;
}
.ch-sidebar-empty {
  padding: 20px 14px;
  color: rgba(255, 255, 255, 0.4);
  font-size: 12px;
  text-align: center;
}

/* Grouped sidebar (6 Aug 2026) — Channels vs Threads categories */
.ch-sidebar-section { display: block; }
.ch-sidebar-section + .ch-sidebar-section { margin-top: 8px; }
.ch-sidebar-section-header {
  display: flex; align-items: center; gap: 6px;
  width: 100%; padding: 6px 10px 6px 8px;
  background: transparent; border: 0; cursor: pointer;
  color: rgba(255, 255, 255, 0.55);
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.6px; text-align: left;
  border-radius: 4px;
}
.ch-sidebar-section-header:hover { background: rgba(255, 255, 255, 0.05); color: white; }
.ch-sidebar-section-chevron { width: 10px; opacity: 0.8; font-size: 10px; }
.ch-sidebar-section-icon { opacity: 0.7; font-size: 12px; }
.ch-sidebar-section-label { flex: 1; }
.ch-sidebar-section-count {
  background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.6);
  padding: 1px 6px; border-radius: 8px; font-size: 10px; font-weight: 700;
}
.ch-sidebar-section-unread {
  background: var(--primary, #0D7377); color: white;
  padding: 1px 6px; border-radius: 8px; font-size: 10px; font-weight: 700;
}
.ch-sidebar-section-body { padding-left: 2px; }
.ch-sidebar-item.thread-companion .ch-sidebar-hash {
  opacity: 1; margin-right: 6px; font-size: 12px;
}

/* ── ACTIVITY CARDS (source_kind='thread_activity') ─────────────── */
.ch-msg.ch-msg-activity {
  background: var(--bg-soft, #F8FAFC);
  border-left: 3px solid var(--muted, #94a3b8);
  border-radius: 6px;
  margin: 6px 8px;
  padding: 8px 10px;
}
.ch-msg.ch-msg-activity .ch-msg-avatar.is-activity {
  background: var(--muted, #94a3b8);
  color: white;
  font-weight: 700;
  font-size: 12px;
}
.ch-msg-activity-tag {
  color: var(--muted, #64748b);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
.ch-msg-activity-body {
  color: var(--fg, #1e293b);
  font-size: 13px;
  line-height: 1.45;
}
.ch-msg-activity-body strong { font-weight: 700; }
.ch-msg-activity-preview {
  margin: 4px 0;
  padding: 6px 8px;
  background: var(--card, #fff);
  border-radius: 4px;
  border: 1px solid var(--border, #e2e8f0);
  font-size: 12.5px;
  color: var(--muted, #475569);
  white-space: pre-wrap;
  max-height: 4.2em;
  overflow: hidden;
}
.ch-msg-activity-link {
  display: inline-block;
  margin-top: 4px;
  font-size: 12px;
  color: var(--primary, #0D7377);
  text-decoration: none;
  font-weight: 600;
}
.ch-msg-activity-link:hover { text-decoration: underline; }

/* ── COMPANION TEAM-CHAT PANEL (right-side of thread view) ──────── */
.thread-companion-panel {
  position: fixed;
  right: 0;
  top: 56px;
  bottom: 0;
  width: 340px;
  background: var(--card, #fff);
  border-left: 1px solid var(--border, #e2e8f0);
  display: flex;
  flex-direction: column;
  z-index: 40;
  transform: translateX(340px);
  transition: transform 0.18s ease;
  box-shadow: -2px 0 8px rgba(0, 0, 0, 0.04);
}
body.companion-panel-open .thread-companion-panel { transform: translateX(0); }
.thread-companion-toggle {
  position: fixed;
  right: 0;
  top: 96px;
  z-index: 41;
  padding: 8px 10px;
  background: var(--primary, #0D7377);
  color: white;
  border: none;
  border-radius: 6px 0 0 6px;
  font-size: 13px;
  cursor: pointer;
  display: none;
  box-shadow: -1px 1px 4px rgba(0, 0, 0, 0.1);
}
body.thread-has-companion .thread-companion-toggle { display: flex; align-items: center; gap: 6px; }
body.companion-panel-open .thread-companion-toggle { right: 340px; }
.thread-companion-header {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border, #e2e8f0);
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-weight: 700;
  font-size: 13.5px;
}
.thread-companion-header .close {
  background: transparent;
  border: none;
  font-size: 18px;
  color: var(--muted, #64748b);
  cursor: pointer;
  padding: 0 4px;
}
.thread-companion-meta {
  padding: 6px 14px;
  font-size: 11.5px;
  color: var(--muted, #64748b);
  border-bottom: 1px solid var(--border, #e2e8f0);
}
.thread-companion-messages {
  flex: 1;
  overflow-y: auto;
  padding: 6px 4px;
  min-height: 0;
}
.thread-companion-messages .ch-msg { margin: 2px 6px; padding: 4px 6px; }
.thread-companion-messages .ch-msg-activity { display: none; }
.thread-companion-composer {
  border-top: 1px solid var(--border, #e2e8f0);
  padding: 8px;
  display: flex;
  gap: 6px;
}
.thread-companion-composer textarea {
  flex: 1;
  min-height: 40px;
  max-height: 120px;
  resize: none;
  padding: 6px 8px;
  font-size: 13px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 5px;
  font-family: inherit;
}
.thread-companion-composer button {
  padding: 4px 12px;
  background: var(--primary, #0D7377);
  color: white;
  border: none;
  border-radius: 5px;
  font-weight: 600;
  cursor: pointer;
  font-size: 12.5px;
}
.thread-companion-composer button:disabled { opacity: 0.5; cursor: not-allowed; }
.thread-companion-empty {
  text-align: center;
  padding: 24px 16px;
  color: var(--muted, #94a3b8);
  font-size: 12.5px;
}

/* ── CENTER STREAM ──────────────────────────────────────────────── */
.ch-stream {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--card, #fff);
  position: relative;
}
.ch-stream-empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: var(--muted, #64748b);
  gap: 8px;
  padding: 40px;
}
.ch-stream-empty-icon { font-size: 40px; opacity: 0.6; }
.ch-stream-empty p { margin: 0; font-size: 14px; }
.ch-stream-empty .muted { font-size: 12.5px; opacity: 0.8; }
.ch-stream-empty code {
  background: var(--bg-soft, #F8FAFC);
  padding: 1px 6px;
  border-radius: 4px;
  border: 1px solid var(--border, #E3E8EF);
  font-size: 12px;
}
.ch-stream-container {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  position: relative;
}
.ch-stream-container.hidden { display: none; }

.ch-stream-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border, #E3E8EF);
  flex-shrink: 0;
  background: var(--card, #fff);
}
.ch-stream-header-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 16px;
  font-weight: 700;
  color: var(--text, #0f172a);
}
.ch-hash { color: var(--muted, #64748b); font-weight: 400; }
.ch-badge {
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
  color: var(--primary, #0D7377);
  border-radius: 4px;
  padding: 1px 6px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.ch-badge.hidden { display: none; }
.ch-stream-header-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--muted, #64748b);
  font-size: 12.5px;
}
.ch-stream-purpose {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 400px;
}

/* ── Roster row (always-visible pills under the channel header) ──────
   Renders every attached member + agent as a chip. Collapsed to a
   single line by default; "+N more" toggle expands the wrap. Chips
   are click-through to the members drawer. */
.ch-roster {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 8px 20px 10px;
  border-bottom: 1px solid var(--border, #E3E8EF);
  background: var(--card, #fff);
  flex-shrink: 0;
}
.ch-roster.hidden { display: none; }
.ch-roster-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex: 1;
  min-width: 0;
  max-height: 28px;      /* single-line height — collapsed default */
  overflow: hidden;
  transition: max-height 0.18s ease;
}
.ch-roster.is-expanded .ch-roster-inner {
  max-height: 240px;
  overflow-y: auto;
}
.ch-roster-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 3px;
  height: 24px;
  border-radius: 999px;
  border: 1px solid var(--border, #E3E8EF);
  background: var(--surface-subtle, #F8FAFC);
  font-size: 12px;
  font-weight: 500;
  color: var(--text, #0f172a);
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
  white-space: nowrap;
  max-width: 200px;
}
.ch-roster-chip:hover {
  background: var(--surface-hover, #EEF2F7);
  border-color: var(--border-strong, #CBD5E1);
}
.ch-roster-chip.is-agent {
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
  border-color: var(--primary-border, rgba(13, 115, 119, 0.24));
  color: var(--primary, #0D7377);
}
.ch-roster-chip.is-agent:hover {
  background: rgba(13, 115, 119, 0.14);
}
.ch-roster-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--muted-bg, #E2E8F0);
  color: var(--text, #0f172a);
  font-size: 10px;
  font-weight: 700;
  flex-shrink: 0;
}
.ch-roster-chip.is-agent .ch-roster-avatar {
  background: var(--primary, #0D7377);
  color: #fff;
}
.ch-roster-label {
  overflow: hidden;
  text-overflow: ellipsis;
}
.ch-roster-toggle {
  flex-shrink: 0;
  height: 24px;
  padding: 0 10px;
  border-radius: 999px;
  border: 1px solid var(--border, #E3E8EF);
  background: var(--card, #fff);
  color: var(--muted, #64748b);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.ch-roster-toggle:hover {
  background: var(--surface-hover, #EEF2F7);
  color: var(--text, #0f172a);
}
.ch-roster-toggle.hidden { display: none; }
.ch-roster-chip.is-hidden { display: none; }

.ch-members-drawer {
  position: absolute;
  top: 56px;
  right: 20px;
  z-index: 8;
  width: 320px;
  background: var(--card, #fff);
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: 12px;
}
.ch-members-drawer.hidden { display: none; }
.ch-members-drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px;
}
.ch-members-drawer-head h4 { margin: 0; font-size: 13px; }
.ch-members-list {
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 6px;
}
.ch-members-list-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px; font-size: 13px;
  border-bottom: 1px solid var(--border, #E3E8EF);
}
.ch-members-list-item:last-child { border-bottom: none; }
.ch-members-list-item.is-agent { background: var(--primary-tint, rgba(13, 115, 119, 0.08)); }
.ch-members-list-item .ch-members-remove {
  margin-left: auto;
  color: #B42318;
  font-size: 11px;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 4px;
}
.ch-members-list-item .ch-members-remove:hover { background: rgba(180, 35, 24, 0.08); }
.ch-members-list-item .ch-members-remove:focus-visible { outline: 2px solid #B42318; outline-offset: 2px; }
/* Per-member role pill (owner / admin — no pill for plain members to keep the
   drawer visually calm). */
.ch-members-role-pill {
  display: inline-block; margin-left: 6px;
  padding: 1px 6px; border-radius: 999px;
  font-size: 10px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.02em;
  vertical-align: middle;
}
.ch-members-role-pill.role-owner { background: #FEF3C7; color: #92400E; }
.ch-members-role-pill.role-admin { background: #DBEAFE; color: #1E40AF; }
.ch-members-role-pill.role-super { background: #FCE7F3; color: #9D174D; }
/* "You" tag on the caller's own row. */
.ch-members-you-tag {
  display: inline-block; margin-left: 6px;
  padding: 1px 6px; border-radius: 999px;
  background: #E0F2FE; color: #075985;
  font-size: 10px; font-weight: 600;
  vertical-align: middle;
}
.ch-members-drawer-actions {
  display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap;
}
.ch-members-drawer-actions .ch-members-leave-btn {
  margin-left: auto;
  color: #B42318;
}
.ch-members-drawer-actions .ch-members-leave-btn:hover { background: rgba(180, 35, 24, 0.08); }

/* Inline "add users / add agents" pane (replaces prompt() dialogs). */
.ch-add-pane-head {
  display: flex; flex-direction: column; gap: 8px; margin-bottom: 6px;
}
.ch-add-pane-search {
  width: 100%; padding: 8px 10px; font-size: 13px;
  border: 1px solid #d1d5db; border-radius: 6px; outline: none;
}
.ch-add-pane-search:focus { border-color: #0078BF; box-shadow: 0 0 0 2px rgba(0,120,191,.15); }
.ch-add-pane-selectionbar {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 12px; color: #64748b;
}
.ch-add-pane-selectall { display: flex; align-items: center; gap: 6px; cursor: pointer; }
.ch-add-pane-count { font-weight: 600; color: #0f172a; }
.ch-add-pane-list {
  max-height: 320px; overflow-y: auto;
  border: 1px solid #e5e7eb; border-radius: 6px;
  background: #fff;
}
.ch-add-pane-list:empty::before {
  content: 'No matches.';
  display: block; padding: 16px; text-align: center;
  color: #94a3b8; font-size: 12px;
}
.ch-add-pane-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; cursor: pointer;
  border-bottom: 1px solid #f1f5f9;
}
.ch-add-pane-row:last-child { border-bottom: none; }
.ch-add-pane-row:hover, .ch-add-pane-row.is-focus { background: #f8fafc; }
.ch-add-pane-row.is-selected { background: #eff6ff; }
.ch-add-pane-row input[type=checkbox] { margin: 0; }
.ch-add-pane-row .ch-add-pane-avatar {
  width: 28px; height: 28px; border-radius: 6px;
  background: linear-gradient(135deg, #0078BF, #005a91);
  color: #fff; font-weight: 700; font-size: 12px;
  display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
}
.ch-add-pane-row.is-agent .ch-add-pane-avatar {
  background: linear-gradient(135deg, #E44C9A, #b8397a);
}
.ch-add-pane-row .ch-add-pane-body { flex: 1 1 auto; min-width: 0; }
.ch-add-pane-row .ch-add-pane-name {
  font-size: 13px; font-weight: 600; color: #0f172a;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ch-add-pane-row .ch-add-pane-sub {
  font-size: 11px; color: #64748b;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ch-add-pane-actions {
  display: flex; justify-content: flex-end; gap: 8px;
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid #e5e7eb;
}

.ch-stream-messages {
  flex: 1;
  overflow-y: auto;
  padding: 12px 0;
  min-height: 0;
}
.ch-msg {
  display: grid;
  grid-template-columns: 40px 1fr;
  gap: 10px;
  padding: 6px 20px;
  position: relative;
}
.ch-msg:hover { background: var(--bg-soft, #F8FAFC); }
.ch-msg:hover .ch-msg-actions { display: flex; }
.ch-msg.grouped { padding-top: 2px; padding-bottom: 2px; }
.ch-msg.grouped .ch-msg-avatar,
.ch-msg.grouped .ch-msg-head { visibility: hidden; height: 0; margin: 0; }
.ch-msg.grouped .ch-msg-avatar-slot {
  font-size: 10px;
  color: var(--muted, #64748b);
  text-align: right;
  padding-top: 2px;
  padding-right: 4px;
}
.ch-msg-avatar {
  width: 36px; height: 36px;
  border-radius: 6px;
  background: linear-gradient(135deg, var(--primary, #0D7377), #14B8A6);
  color: white;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 14px;
  overflow: hidden;
  flex-shrink: 0;
}
.ch-msg.is-agent .ch-msg-avatar { background: linear-gradient(135deg, #7C3AED, #E44C9A); }
.ch-msg-avatar img { width: 100%; height: 100%; object-fit: cover; }
.ch-msg-body { min-width: 0; }
.ch-msg-head {
  display: flex; align-items: baseline; gap: 8px;
  margin-bottom: 2px;
}
.ch-msg-author {
  font-weight: 700; color: var(--text, #0f172a); font-size: 14px;
}
.ch-msg-author.is-agent { color: #7C3AED; }
.ch-msg-author .ch-msg-bot-tag {
  background: #7C3AED;
  color: white;
  font-size: 9.5px;
  font-weight: 700;
  border-radius: 3px;
  padding: 1px 5px;
  margin-left: 4px;
  text-transform: uppercase;
  vertical-align: middle;
  letter-spacing: 0.03em;
}
.ch-msg-when { font-size: 11.5px; color: var(--muted, #64748b); }
.ch-msg-text {
  font-size: 14px;
  line-height: 1.45;
  color: var(--text, #0f172a);
  white-space: pre-wrap;
  word-wrap: break-word;
}
.ch-msg-text .ch-mention {
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
  color: var(--primary, #0D7377);
  border-radius: 4px;
  padding: 0 3px;
  font-weight: 600;
  font-size: 13.5px;
}
.ch-msg-text .ch-mention.is-agent {
  background: rgba(124, 58, 237, 0.1);
  color: #7C3AED;
}
.ch-msg-attachments {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-top: 6px;
}
.ch-msg-attachments img {
  max-width: 240px;
  max-height: 200px;
  border-radius: 6px;
  border: 1px solid var(--border, #E3E8EF);
  cursor: pointer;
}
.ch-msg-reactions {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin-top: 6px;
}
.ch-msg-reactions .ch-reaction {
  display: inline-flex; align-items: center; gap: 4px;
  border: 1px solid var(--border, #E3E8EF);
  background: var(--bg-soft, #F8FAFC);
  border-radius: 999px;
  padding: 1px 8px;
  font-size: 12px;
  cursor: pointer;
  user-select: none;
}
.ch-msg-reactions .ch-reaction.mine {
  background: var(--primary-tint-strong, rgba(13, 115, 119, 0.14));
  border-color: var(--primary, #0D7377);
  color: var(--primary, #0D7377);
}
.ch-msg-reactions .ch-reaction .ch-reaction-count {
  font-weight: 600; font-size: 11px;
}
.ch-msg-reactions .ch-reaction-add {
  background: transparent; border: 1px dashed var(--border-strong, #CBD5E1);
  color: var(--muted, #64748b); font-size: 13px;
  padding: 1px 6px;
}
.ch-msg-thread-summary {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 4px;
  padding: 2px 8px;
  border-radius: 6px;
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
  color: var(--primary, #0D7377);
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  border: none;
}
.ch-msg-thread-summary:hover { background: var(--primary-tint-strong, rgba(13, 115, 119, 0.14)); }

.ch-msg-actions {
  display: none;
  position: absolute;
  top: -8px; right: 20px;
  background: var(--card, #fff);
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 6px;
  padding: 2px 4px;
  gap: 2px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.ch-msg-actions button {
  background: transparent; border: none; cursor: pointer;
  padding: 3px 6px; font-size: 13px; color: var(--muted, #64748b);
  border-radius: 4px;
}
.ch-msg-actions button:hover { background: var(--bg-soft, #F8FAFC); color: var(--text, #0f172a); }

.ch-day-divider {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 20px;
  color: var(--muted, #64748b);
  font-size: 12px;
  font-weight: 600;
}
.ch-day-divider::before,
.ch-day-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--border, #E3E8EF);
}

.ch-stream-composer {
  border-top: 1px solid var(--border, #E3E8EF);
  padding: 10px 20px 12px;
  flex-shrink: 0;
  background: var(--card, #fff);
}
.ch-stream-composer-inner { position: relative; }
.ch-stream-composer-inner textarea {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 8px;
  font-family: inherit;
  font-size: 14px;
  resize: vertical;
  min-height: 40px;
  background: var(--card, #fff);
  color: var(--text, #0f172a);
}
.ch-stream-composer-inner textarea:focus {
  outline: none;
  border-color: var(--primary, #0D7377);
  box-shadow: 0 0 0 3px var(--primary-tint, rgba(13, 115, 119, 0.08));
}
.ch-composer-attach-strip {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-top: 6px;
}
.ch-composer-attach-strip .ch-attach-thumb {
  position: relative;
  width: 60px; height: 60px;
  border-radius: 6px;
  border: 1px solid var(--border, #E3E8EF);
  overflow: hidden;
  background: var(--bg-soft, #F8FAFC);
}
.ch-composer-attach-strip .ch-attach-thumb img {
  width: 100%; height: 100%; object-fit: cover;
}
.ch-composer-attach-strip .ch-attach-thumb button {
  position: absolute; top: 2px; right: 2px;
  background: rgba(0, 0, 0, 0.6); color: white;
  border: none; border-radius: 50%;
  width: 18px; height: 18px; cursor: pointer;
  font-size: 12px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.ch-stream-composer-row {
  display: flex; align-items: center; gap: 8px;
  margin-top: 8px;
}
.ch-composer-flash {
  font-size: 12px; color: var(--muted, #64748b);
  margin-left: auto; margin-right: 8px;
  min-height: 14px;
}
.ch-composer-flash.error { color: #B42318; }
.ch-composer-flash.success { color: #059669; }

/* ── AGENT TYPING PILL ("@marko is typing…") ──────────────────── */
/* Rendered by renderChannelTypingPill() into #chStreamTypingBar,
   which sits between the message stream and the composer. Empty
   state (no agents thinking) collapses to display:none via :empty. */
.ch-typing-bar {
  padding: 6px 20px;
  font-size: 12px;
  color: var(--muted, #64748b);
  font-style: italic;
  min-height: 24px;
  border-top: 1px solid var(--border, #E3E8EF);
  background: var(--card, #fff);
}
.ch-typing-bar:empty { display: none; }
.ch-typing-bar .ch-typing-dot {
  display: inline-block;
  animation: chTypingBounce 1.2s infinite ease-in-out;
}
.ch-typing-bar .ch-typing-dot:nth-child(2) { animation-delay: 0.2s; }
.ch-typing-bar .ch-typing-dot:nth-child(3) { animation-delay: 0.4s; }
@keyframes chTypingBounce {
  0%, 60%, 100% { opacity: 0.3; }
  30% { opacity: 1; }
}

/* ── MENTION AUTOCOMPLETE ──────────────────────────────────────── */
.ch-mention-popup {
  position: absolute;
  bottom: 100%;
  left: 0;
  background: var(--card, #fff);
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  max-height: 240px;
  overflow-y: auto;
  min-width: 280px;
  z-index: 20;
  margin-bottom: 4px;
}
.ch-mention-popup.hidden { display: none; }
.ch-mention-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px;
  cursor: pointer;
  font-size: 13px;
}
.ch-mention-item:hover,
.ch-mention-item.active {
  background: var(--primary-tint, rgba(13, 115, 119, 0.08));
}
.ch-mention-item.is-agent { background: rgba(124, 58, 237, 0.06); }
.ch-mention-item.is-agent:hover,
.ch-mention-item.is-agent.active { background: rgba(124, 58, 237, 0.14); }
.ch-mention-item-avatar {
  width: 24px; height: 24px; border-radius: 4px;
  background: linear-gradient(135deg, var(--primary, #0D7377), #14B8A6);
  color: white; font-size: 11px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.ch-mention-item.is-agent .ch-mention-item-avatar {
  background: linear-gradient(135deg, #7C3AED, #E44C9A);
}
.ch-mention-item-slug {
  font-weight: 600; color: var(--text, #0f172a);
}
.ch-mention-item-name {
  color: var(--muted, #64748b); font-size: 12px;
}
.ch-mention-item-kind {
  margin-left: auto;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted, #64748b);
}

/* ── THREAD PANEL (right) ────────────────────────────────────── */
.ch-thread {
  background: var(--card, #fff);
  border-left: 1px solid var(--border, #E3E8EF);
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.ch-thread.hidden { display: none; }
.ch-thread-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border, #E3E8EF);
  flex-shrink: 0;
}
.ch-thread-header-title {
  display: flex; flex-direction: column;
  font-size: 14px; font-weight: 700; color: var(--text, #0f172a);
}
.ch-thread-channel-hint {
  font-size: 11.5px; font-weight: 400;
  color: var(--muted, #64748b);
}
.ch-thread-parent {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border, #E3E8EF);
  background: var(--bg-soft, #F8FAFC);
  flex-shrink: 0;
}
.ch-thread-parent .ch-msg { padding: 0; }
.ch-thread-parent .ch-msg:hover { background: transparent; }
.ch-thread-replies {
  flex: 1;
  overflow-y: auto;
  padding: 6px 0;
  min-height: 0;
}
.ch-thread-composer {
  border-top: 1px solid var(--border, #E3E8EF);
  padding: 10px 16px 12px;
  flex-shrink: 0;
  display: flex; flex-direction: column; gap: 8px;
  position: relative;
}
.ch-thread-composer textarea {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--border, #E3E8EF);
  border-radius: 8px;
  font-family: inherit; font-size: 14px;
  min-height: 40px;
}
.ch-thread-composer textarea:focus {
  outline: none;
  border-color: var(--primary, #0D7377);
  box-shadow: 0 0 0 3px var(--primary-tint, rgba(13, 115, 119, 0.08));
}

/* ── RESPONSIVE ───────────────────────────────────────────────── */
@media (max-width: 900px) {
  .ch-body { grid-template-columns: 200px 1fr; }
  .ch-body.thread-open { grid-template-columns: 1fr; }
  .ch-body.thread-open .ch-sidebar,
  .ch-body.thread-open .ch-stream { display: none; }
  .ch-body.thread-open .ch-thread { display: flex; }
}
@media (max-width: 600px) {
  .ch-body { grid-template-columns: 1fr; }
  .ch-body:not(.channel-open) .ch-stream { display: none; }
  .ch-body.channel-open .ch-sidebar { display: none; }
  .ch-body.thread-open .ch-stream { display: none; }
  .ch-body.thread-open .ch-thread { display: flex; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Mobile hardening for Channels view (21 Aug 2026)
   ---------------------------------------------------------------------------
   Bug (from user screenshot on a ~380px Android): on narrow viewports the
   Channels sidebar was collapsing to ~30px showing vertically-wrapped text
   ("Channels", "Pick a channel to start collaborating with your team +
   agents"), while the stream took the remainder as an empty dark rectangle.
   Root cause: the grid cells inside `.ch-body` did not have `min-width: 0`,
   so at very narrow viewports the intrinsic min-content width of the sidebar
   fought the 1fr rule and produced a squeezed layout even below the 600px
   breakpoint. Also, on some browsers the tablet body override (≤980px:
   `body { grid-template-columns: 1fr }`) was being outranked by a stale
   3-column layout when body.channels-active toggled.
   Fix: explicitly force single-column body when channels-active on mobile,
   guarantee the grid children (.ch-sidebar/.ch-stream/.ch-thread) can shrink,
   and clamp #channelsView / #channelsHeader to full-width with wrapping.
   Desktop-only channels rail (min-width:900px block above) is untouched.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  /* When Channels is the active view, force the body to a single column
     so #channelsView owns the full viewport width. The tablet ≤980px block
     already sets this on <body>, but re-asserting here defeats any later
     override (e.g. dashboard-only rules that get evaluated after). */
  body.channels-active {
    grid-template-columns: 1fr !important;
  }
  body.channels-active #channelsView {
    width: 100%;
    min-width: 0;
    max-width: 100vw;
    overflow: hidden;
  }
  /* Header — allow the h2 + subtitle to wrap instead of squeezing to
     a vertical string of letters. */
  body.channels-active #channelsHeader {
    flex-wrap: wrap;
    padding: 10px 14px;
    gap: 6px;
    min-width: 0;
  }
  body.channels-active #channelsHeader h2 {
    font-size: 16px;
    white-space: normal;
    min-width: 0;
  }
  body.channels-active #channelsHeader .chat-subtitle {
    font-size: 12px;
    white-space: normal;
    min-width: 0;
    flex: 1 1 100%;
  }
  /* Grid children — MUST have min-width:0, otherwise their intrinsic
     min-content width (long channel names, message text) fights the 1fr
     rule and squeezes the visible cells into thin vertical bars. */
  .ch-body,
  .ch-body > .ch-sidebar,
  .ch-body > .ch-stream,
  .ch-body > .ch-thread {
    min-width: 0;
  }
  .ch-sidebar,
  .ch-stream,
  .ch-thread {
    width: auto;
    min-width: 0;
  }
  /* Hide the right folder-panel overlay toggle while in Channels — it's
     an editor affordance and adds nothing to the channels experience. */
  body.channels-active .folder-panel-toggle {
    display: none !important;
  }
}
@media (max-width: 600px) {
  /* On phones, be even more defensive: bake in single-column .ch-body
     even if a stale class ordering issue keeps the 200px sidebar rule
     alive. `!important` here is scoped strictly to the channels view. */
  body.channels-active .ch-body {
    grid-template-columns: 1fr !important;
  }
  body.channels-active .ch-body:not(.channel-open):not(.thread-open) .ch-stream {
    display: none !important;
  }
  body.channels-active .ch-body:not(.channel-open):not(.thread-open) .ch-sidebar {
    display: flex !important;
    width: 100%;
    min-width: 0;
  }
  body.channels-active .ch-body.channel-open:not(.thread-open) .ch-sidebar {
    display: none !important;
  }
  body.channels-active .ch-body.channel-open:not(.thread-open) .ch-stream {
    display: flex !important;
    width: 100%;
    min-width: 0;
  }
  /* Channel names in the sidebar list — allow horizontal scroll rather than
     forcing wrap into vertical letter columns. */
  body.channels-active .ch-sidebar-item .ch-sidebar-name {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Icon-only left sidebar while in Slack Channels view (5 Aug 2026)
   ---------------------------------------------------------------------------
   When body.channels-active is on (added by showChannelsView(), removed by
   hideAllSections()), collapse #sidebar from ~300px → 56px so the 3-pane
   channels layout (channels list · message stream · thread panel) has room
   to breathe. All navigation buttons stay clickable — only labels + inline
   badges + secondary widgets (search box, LLM backend picker, section
   labels, thread list) are hidden. Hovering a nav button surfaces its label
   via a native tooltip (the `title=` attribute is already set on every
   sidebar-dashboard-btn in index.html).

   The collapse is desktop-only — on tablet + mobile the sidebar is already
   a slide-in overlay per the existing media queries, so we skip the icon
   rail below 900px to keep the mobile touch targets full-size.
   ═══════════════════════════════════════════════════════════════════════ */
@media (min-width: 900px) {
  body.channels-active {
    grid-template-columns: 56px 1fr var(--folder-panel-w);
  }
  body.channels-active.folder-panel-collapsed {
    grid-template-columns: 56px 1fr 0;
  }
  /* Smooth width shift so the layout feels intentional, not sudden. */
  body.channels-active #sidebar,
  body:not(.channels-active) #sidebar {
    transition: width 220ms cubic-bezier(0.4, 0, 0.2, 1);
  }

  /* Header — hide brand text + all header actions except the brand mark
     which stays as a click-target back to the platform default. */
  body.channels-active #sidebar header {
    padding: 12px 4px;
    justify-content: center;
  }
  body.channels-active #sidebar .brand-text,
  body.channels-active #sidebar .sidebar-header-actions {
    display: none;
  }
  body.channels-active #sidebar .brand { justify-content: center; gap: 0; }

  /* Search box, section labels, LLM backend, menu-toggle chevron label:
     all hidden. The menu buttons themselves stay. */
  body.channels-active #sidebar .sidebar-menu-search-wrap,
  body.channels-active #sidebar .sidebar-section-label,
  body.channels-active #sidebar .sidebar-llm-backend,
  body.channels-active #sidebar .sidebar-menu-toggle,
  body.channels-active #sidebar .sidebar-kind-links,
  body.channels-active #sidebar #threadsList,
  body.channels-active #sidebar #threadsSection,
  body.channels-active #sidebar .threads-section,
  body.channels-active #sidebar .threads-list {
    display: none !important;
  }

  /* Every dashboard-style button (Home Feed, Dashboard, Superadmin, Menu
     entries, etc.) collapses to a 40×40 icon tile. Label span hidden;
     badges + chevrons hidden. Icon (first SVG) is centred. */
  body.channels-active #sidebar .sidebar-dashboard-btn {
    margin: 6px auto;
    padding: 0;
    width: 40px;
    height: 40px;
    min-height: 40px;
    flex: 0 0 40px;
    justify-content: center;
    align-items: center;
    gap: 0;
    border-radius: 10px;
    overflow: hidden;
  }
  body.channels-active #sidebar .sidebar-dashboard-btn > span,
  body.channels-active #sidebar .sidebar-dashboard-btn .sidebar-badge,
  body.channels-active #sidebar .sidebar-dashboard-btn .sidebar-dashboard-badge,
  body.channels-active #sidebar .sidebar-dashboard-btn .sidebar-chevron {
    display: none !important;
  }
  body.channels-active #sidebar .sidebar-dashboard-btn > svg:first-of-type {
    flex: 0 0 auto;
    margin: 0;
  }
  /* Slight visual affordance so you can see which section is active
     (Home Feed / Channels) even without a label. */
  body.channels-active #sidebar .sidebar-dashboard-btn:hover {
    background: var(--primary-tint);
    color: var(--primary);
  }

  /* User footer — collapse to just the avatar; email + menu hidden.
     Companion app / Test as / Login as user / Sign out get collapsed to
     40×40 icon tiles that match the top nav, so nothing wraps or truncates
     in the narrow 56px rail. Native title tooltips (already on each control)
     surface the labels on hover. */
  body.channels-active #sidebar .sidebar-user {
    padding: 8px 0 10px;
    justify-content: flex-start;
    align-items: center;
    flex-direction: column;
    gap: 6px;
    flex-wrap: nowrap;
  }
  body.channels-active #sidebar .sidebar-user-info,
  body.channels-active #sidebar .sidebar-user-email,
  body.channels-active #sidebar .sidebar-user-menu,
  body.channels-active #sidebar .sidebar-user-name {
    display: none !important;
  }
  body.channels-active #sidebar .sidebar-user-avatar {
    margin: 0 auto;
  }
  /* Current-org picker: hide in the narrow rail — user can still change
     it from the full sidebar on any non-Channels view. */
  body.channels-active #sidebar .sidebar-current-org {
    display: none !important;
  }
  /* Companion app / Test as / Login as user pickers — icon-only tiles.
     The <span>Label ▾</span> is hidden; only the leading SVG icon shows. */
  body.channels-active #sidebar .test-as-picker {
    width: 40px;
    flex: 0 0 auto;
  }
  body.channels-active #sidebar .test-as-summary {
    width: 40px;
    height: 40px;
    padding: 0;
    gap: 0;
    border-radius: 10px;
    justify-content: center;
    align-items: center;
    border-color: transparent;
  }
  body.channels-active #sidebar .test-as-summary:hover {
    background: var(--primary-tint);
    color: var(--primary);
    border-color: var(--primary);
  }
  body.channels-active #sidebar .test-as-summary > span {
    display: none !important;
  }
  body.channels-active #sidebar .test-as-summary > svg {
    flex: 0 0 auto;
    margin: 0;
  }
  /* The pop-up menu that appears when you click one of these still needs
     to render full-width — anchor it to the RIGHT edge of the rail so it
     opens outward into the channels pane instead of clipping off-screen. */
  body.channels-active #sidebar .test-as-menu {
    left: calc(100% + 6px);
    bottom: 0;
    min-width: 200px;
  }
  /* Sign-out button — icon-only 40×40 tile, text hidden. */
  body.channels-active #sidebar #logoutBtn {
    width: 40px;
    height: 40px;
    padding: 0;
    gap: 0;
    border-radius: 10px;
    display: inline-flex;
    justify-content: center;
    align-items: center;
    flex: 0 0 auto;
  }
  body.channels-active #sidebar #logoutBtn > span {
    display: none !important;
  }
  body.channels-active #sidebar #logoutBtn > svg {
    flex: 0 0 auto;
    margin: 0;
  }

  /* Scroll area — kill horizontal wobble now that inner content is
     narrow, and shrink the scrollbar so it doesn't dominate 56px. */
  body.channels-active #sidebar .sidebar-scroll {
    scrollbar-width: none;
  }
  body.channels-active #sidebar .sidebar-scroll::-webkit-scrollbar {
    width: 0;
    display: none;
  }
  /* Let the footer pop-ups (Companion app / Test as / Login as) escape
     the 56px rail sideways — the base #sidebar has overflow:hidden which
     would otherwise clip them. .sidebar-scroll still has its own overflow
     rules so nothing else changes. */
  body.channels-active #sidebar {
    overflow: visible;
  }
  body.channels-active #sidebar .sidebar-user {
    overflow: visible;
  }
}

/* ── Agents Summary tile · Dashboard ─────────────────────────────
   Sits above the projects grid on the dashboard. Cross-UI parity
   partner: home-grid tile in web/telegram-app.html. */
.agents-summary-block {
  max-width: 1180px;
  width: 100%;
  margin: 10px auto 22px;
  padding: 14px 18px 12px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 14px;
  box-shadow: 0 2px 12px rgba(15, 23, 42, 0.04);
  /* Bound the tile so it can't push .projects-grid off-viewport in the
     flex-column #dashboard layout. The body scrolls internally. */
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
  max-height: min(52vh, 480px);
  box-sizing: border-box;
}
.agents-summary-header {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; margin-bottom: 10px; flex-wrap: wrap;
}
.agents-summary-title-wrap { display: flex; flex-direction: column; gap: 2px; }
.agents-summary-title { margin: 0; font-size: 17px; font-weight: 700; letter-spacing: -0.2px; }
.agents-summary-subtitle { font-size: 12.5px; color: var(--muted, #64748b); }
.agents-summary-toolbar { display: flex; align-items: center; gap: 8px; }
.agents-summary-toolbar input[type="search"] {
  padding: 6px 10px;
  font-size: 13px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px;
  min-width: 220px;
}
.agents-summary-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.agents-summary-table {
  width: 100%; min-width: 780px;
  border-collapse: collapse;
  font-size: 13.5px;
}
.agents-summary-table thead th {
  text-align: left; padding: 8px 10px;
  background: var(--surface-alt, #f8fafc);
  color: var(--muted, #64748b);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--border, #e2e8f0);
  position: sticky; top: 0;
  cursor: pointer;
  user-select: none;
}
.agents-summary-table thead th.sort-active { color: var(--brand-blue, #0078BF); }
.agents-summary-table thead th.sort-active::after { content: attr(data-arrow); margin-left: 4px; }
.agents-summary-table thead th.num { text-align: right; }
.agents-summary-table tbody td { padding: 9px 10px; border-bottom: 1px solid var(--border, #f1f5f9); vertical-align: top; }
.agents-summary-table tbody td.num { text-align: right; font-variant-numeric: tabular-nums; }
.agents-summary-table tbody tr:hover { background: rgba(0, 120, 191, 0.04); }
.agents-summary-table tbody tr.clickable { cursor: pointer; }
.agents-summary-agent-name {
  display: flex; flex-direction: column; gap: 2px;
  font-weight: 600; color: var(--text, #0f172a);
}
.agents-summary-agent-slug {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  color: var(--muted, #64748b);
  font-weight: 400;
}
.agents-summary-desc {
  font-size: 12.5px;
  color: var(--text-secondary, #334155);
  max-width: 340px;
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.agents-summary-owner {
  display: flex; align-items: center; gap: 6px;
  font-size: 12.5px;
}
.agents-summary-status {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.agents-summary-status.approved { background: #dcfce7; color: #166534; }
.agents-summary-status.pending  { background: #fef3c7; color: #92400e; }
.agents-summary-status.rejected { background: #fee2e2; color: #991b1b; }
.agents-summary-footer {
  padding-top: 8px;
  font-size: 11.5px;
  color: var(--muted, #64748b);
  display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
}
.agents-summary-empty {
  padding: 22px 12px;
  text-align: center;
  color: var(--muted, #64748b);
  font-size: 13px;
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0,0,0,0); border: 0;
}
@media (max-width: 720px) {
  .agents-summary-toolbar input[type="search"] { min-width: 140px; }
  .agents-summary-desc { max-width: 220px; }
}
@media (prefers-color-scheme: dark) {
  .agents-summary-block { background: #111a2c; border-color: #1e293b; }
  .agents-summary-table thead th { background: #0f172a; color: #94a3b8; border-bottom-color: #1e293b; }
  .agents-summary-table tbody td { border-bottom-color: #1e293b; }
  .agents-summary-table tbody tr:hover { background: rgba(0, 120, 191, 0.15); }
  .agents-summary-agent-name { color: #e5e7eb; }
  .agents-summary-agent-slug { color: #94a3b8; }
  .agents-summary-desc { color: #cbd5e1; }
  .agents-summary-status.approved { background: rgba(22, 101, 52, 0.3); color: #86efac; }
  .agents-summary-status.pending  { background: rgba(146, 64, 14, 0.3); color: #fcd34d; }
  .agents-summary-status.rejected { background: rgba(153, 27, 27, 0.3); color: #fca5a5; }
}

/* Superadmin sidebar — live active-prompts badge glow (9 Aug 2026).
   Pulses only when there is >=1 active prompt so an idle platform doesn't
   have a distracting animation running. The badge itself is unconditionally
   emerald-green (#10B981); the glow shadow is what animates. */
@keyframes superadmin-glow-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.55), 0 0 8px 1px rgba(16, 185, 129, 0.35); }
  50%      { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0.0),  0 0 14px 4px rgba(16, 185, 129, 0.55); }
}
.superadmin-glow-badge.is-active {
  animation: superadmin-glow-pulse 1.8s ease-in-out infinite;
}
/* Reduce-motion — keep the colour, drop the pulse. */
@media (prefers-reduced-motion: reduce) {
  .superadmin-glow-badge.is-active {
    animation: none;
    box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.45);
  }
}
/* Sidebar cluster hover — reveal the flyout on hover for desktop users. */
#superadminSidebarCluster:hover #superadminActivePromptsFlyout[data-hover-eligible="1"],
#superadminSidebarCluster:focus-within #superadminActivePromptsFlyout[data-hover-eligible="1"] {
  display: block !important;
}

/* ── Imagine Shell (platform CLI for folders + threads) ──────────────
   Global overlay — not the per-thread agentic Terminal panel.
   Opened from the sidebar ›_ button or Ctrl/Cmd+Shift+`.
   ────────────────────────────────────────────────────────────────── */
.imagine-shell-panel {
  position: fixed;
  inset: auto 16px 16px 16px;
  z-index: 9200;
  display: flex;
  flex-direction: column;
  max-width: 920px;
  margin: 0 auto;
  height: min(58vh, 520px);
  background: #0b1220;
  color: #e5edf7;
  border: 1px solid #1e2a3f;
  border-radius: 12px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(56, 189, 248, 0.08);
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
  font-size: 13px;
  line-height: 1.45;
}
.imagine-shell-panel.hidden { display: none; }
.imagine-shell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border-bottom: 1px solid #1e2a3f;
  background: #0f172a;
  border-radius: 12px 12px 0 0;
  flex-shrink: 0;
}
.imagine-shell-title {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  color: #cbd7e6;
}
.imagine-shell-title > strong { font-weight: 700; color: #f8fafc; letter-spacing: 0.01em; }
.imagine-shell-title > code {
  color: #7dd3fc;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  background: transparent;
}
.imagine-shell-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #8fa5bf;
  font-size: 12px;
  flex-shrink: 0;
}
.imagine-shell-actions .btn { color: #cbd7e6; }
#imagineShellStatus.is-error { color: #fb7185; }
.imagine-shell-panel .git-changes-info-tooltip {
  margin: 10px 12px 0;
  background: #172238;
  color: #cbd7e6;
}
.imagine-shell-output {
  flex: 1 1 auto;
  overflow: auto;
  padding: 12px 14px;
  min-height: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.imagine-shell-line { margin: 0 0 6px; }
.imagine-shell-line.is-cmd { color: #7dd3fc; }
.imagine-shell-line.is-cmd .imagine-shell-prompt-echo { color: #86efac; font-weight: 700; }
.imagine-shell-line.is-out { color: #e5edf7; }
.imagine-shell-line.is-err { color: #fda4af; }
.imagine-shell-line.is-muted { color: #94a3b8; }
.imagine-shell-form {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid #1e2a3f;
  background: #0f172a;
  border-radius: 0 0 12px 12px;
  flex-shrink: 0;
}
.imagine-shell-prompt { color: #86efac; font-weight: 700; flex-shrink: 0; }
.imagine-shell-form input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  outline: 0;
  background: transparent;
  color: #f1f5f9;
  font: inherit;
  padding: 4px 0;
}
.imagine-shell-form input::placeholder { color: #64748b; }
.imagine-shell-form input:focus-visible { box-shadow: 0 2px 0 #38bdf8; }
body.imagine-shell-open { /* reserved for future body-scroll lock if needed */ }
@media (max-width: 720px) {
  .imagine-shell-panel {
    inset: auto 8px 8px 8px;
    height: min(70vh, 560px);
    border-radius: 10px;
  }
  .imagine-shell-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }
  .imagine-shell-actions { width: 100%; justify-content: flex-end; }
  .imagine-shell-title > code { max-width: 70vw; }
}

/* ─────────────────────────────────────────────────────────────
   Superadmin-private thread visibility toggle (14 Aug 2026)
   Rendered in the thread header next to the rename button.
   Only surfaces for the superadmin (user_id=1) — backend filters
   private threads out of everyone else's list so no other user
   ever sees this control on a private thread.
   ───────────────────────────────────────────────────────────── */
.thread-visibility-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  margin-left: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.03em;
  line-height: 1.2;
  border-radius: 8px;
  border: 1px solid #D1D5DB;
  background: #F9FAFB;
  color: #374151;
  cursor: pointer;
  transition: transform 0.08s ease-out, box-shadow 0.12s ease-out;
}
.thread-visibility-btn .visibility-icon {
  font-size: 12px;
  line-height: 1;
}
.thread-visibility-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0,0,0,0.10);
}
.thread-visibility-btn:focus-visible {
  outline: 2px solid #0078BF;
  outline-offset: 2px;
}
.thread-visibility-btn[data-visibility="superadmin_only"] {
  background: #F5F3FF;
  color: #6D28D9;
  border-color: #C4B5FD;
}
.thread-visibility-btn[data-visibility="superadmin_only"]:hover {
  background: #EDE9FE;
  box-shadow: 0 2px 8px rgba(109,40,217,0.18);
}
.thread-visibility-btn.hidden { display: none !important; }
.thread-visibility-btn:disabled {
  cursor: not-allowed;
  opacity: 0.55;
  transform: none;
  box-shadow: none;
}

/* Reduced-motion respect */
@media (prefers-reduced-motion: reduce) {
  .thread-visibility-btn { transition: none; }
  .thread-visibility-btn:hover { transform: none; }
}

/* ==========================================================================
   All Agents view (added 18 Aug 2026)
   ========================================================================== */
#allAgentsView {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  overflow: hidden;
}
#allAgentsHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--surface, #fff);
  flex-shrink: 0;
}
.allagents-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 14px 22px 60px;
  max-width: 1400px;
  width: 100%;
  margin: 0 auto;
}
.allagents-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 4px 2px 10px;
}
.allagents-count { color: var(--text-faint); font-size: 12.5px; }
.allagents-filter { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-muted); }
.allagents-filter select {
  padding: 5px 8px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); color: var(--text); font: inherit; font-size: 12.5px;
}
.allagents-table-wrap {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: auto;
}
.allagents-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.allagents-table th {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  color: var(--text-muted);
  font-weight: 600;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 1;
}
.allagents-table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.allagents-table tr:last-child td { border-bottom: none; }
.allagents-table tr:hover td { background: rgba(13, 115, 119, 0.04); }
.allagents-empty {
  text-align: center;
  padding: 24px 12px;
  color: var(--text-faint);
  font-style: italic;
}
.allagents-agent-name { font-weight: 600; color: var(--text); }
.allagents-agent-slug { color: var(--text-faint); font-size: 11.5px; margin-top: 2px; font-family: ui-monospace, SFMono-Regular, monospace; }
.allagents-owner-email {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 12px;
  color: var(--text);
  word-break: break-all;
}
.allagents-owner-name { color: var(--text-muted); font-size: 11.5px; margin-top: 2px; }
.allagents-url-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  margin: 2px 4px 2px 0;
  background: rgba(13, 115, 119, 0.10);
  color: #0d7377;
  border-radius: 12px;
  font-size: 11.5px;
  font-family: ui-monospace, SFMono-Regular, monospace;
  border: 1px solid rgba(13, 115, 119, 0.15);
  vertical-align: middle;
}
.allagents-url-chip a {
  color: inherit;
  text-decoration: none;
}
.allagents-url-chip:hover { background: rgba(13, 115, 119, 0.18); }
/* Admin-registered live URL — green, distinguished from filesystem-derived */
.allagents-url-chip-live {
  background: rgba(22, 163, 74, 0.12);
  color: #16a34a;
  border-color: rgba(22, 163, 74, 0.25);
}
.allagents-url-chip-live:hover { background: rgba(22, 163, 74, 0.20); }
.allagents-url-label {
  font-size: 10px;
  padding: 1px 5px;
  background: rgba(22, 163, 74, 0.20);
  border-radius: 6px;
  font-family: system-ui, -apple-system, sans-serif;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.allagents-url-del {
  background: transparent;
  border: none;
  color: inherit;
  cursor: pointer;
  padding: 0 2px;
  font-size: 14px;
  line-height: 1;
  opacity: 0.55;
  border-radius: 3px;
}
.allagents-url-del:hover {
  opacity: 1;
  background: rgba(220, 38, 38, 0.15);
  color: #dc2626;
}
.allagents-add-url {
  display: inline-block;
  margin: 2px 0 2px 4px;
  padding: 2px 8px;
  background: transparent;
  border: 1px dashed var(--border);
  color: var(--text-muted);
  border-radius: 12px;
  font-size: 11px;
  cursor: pointer;
  vertical-align: middle;
  font-family: system-ui, -apple-system, sans-serif;
}
.allagents-add-url:hover {
  border-color: #16a34a;
  color: #16a34a;
  background: rgba(22, 163, 74, 0.06);
}
.allagents-channel-chip {
  display: inline-block;
  padding: 2px 8px;
  margin: 2px 4px 2px 0;
  background: rgba(124, 58, 237, 0.10);
  color: #7c3aed;
  border-radius: 12px;
  font-size: 11.5px;
  border: 1px solid rgba(124, 58, 237, 0.18);
}
.allagents-none {
  color: var(--text-faint);
  font-style: italic;
  font-size: 12px;
}
.allagents-status {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.allagents-status.approved { background: rgba(34, 197, 94, 0.15); color: #15803d; }
.allagents-status.pending  { background: rgba(234, 179, 8, 0.18); color: #a16207; }
.allagents-status.rejected { background: rgba(239, 68, 68, 0.15); color: #b91c1c; }
.allagents-status.sleeping { background: rgba(148, 163, 184, 0.20); color: #475569; }
.allagents-status.deleted  { background: rgba(148, 163, 184, 0.20); color: #64748b; text-decoration: line-through; }
.allagents-date {
  color: var(--text-muted);
  font-size: 12px;
  white-space: nowrap;
}

/* ─────────────────────────────────────────────────────────────────────────
   Prompt Reports view — admin-only prompt-log report (20 Aug 2026).
   Sidebar entry #promptReportsBtn → #promptReportsView.
   Styles are self-contained (prefix `pr-` / `.prompt-reports-*`) so they
   don't collide with the other admin reports.
   ───────────────────────────────────────────────────────────────────── */
#promptReportsView { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
#promptReportsHeader {
  display: flex; justify-content: space-between; align-items: center;
  padding: 12px 18px; border-bottom: 1px solid var(--border);
  gap: 12px; flex-wrap: wrap;
}
#promptReportsHeader .header-actions { display: flex; gap: 8px; align-items: center; }
.prompt-reports-range {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; color: var(--text-muted);
}
.prompt-reports-range select {
  padding: 4px 8px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); font-size: 12.5px; color: var(--text);
}
.prompt-reports-body {
  flex: 1 1 auto; overflow: auto; padding: 14px 18px 24px;
  display: flex; flex-direction: column; gap: 12px;
}
.prompt-reports-totals {
  display: flex; flex-wrap: wrap; gap: 16px 22px;
  padding: 10px 14px; background: rgba(37, 99, 235, 0.06);
  border: 1px solid rgba(37, 99, 235, 0.20); border-radius: 8px;
  font-size: 13px;
}
.prompt-reports-totals .pr-total {
  display: inline-flex; align-items: baseline; gap: 6px;
  color: var(--text-muted);
}
.prompt-reports-totals .pr-total strong {
  color: var(--text); font-size: 15px; font-weight: 700;
}
.prompt-reports-totals .pr-total-window {
  margin-left: auto; color: var(--text-muted); font-style: italic; font-size: 12px;
}
.prompt-reports-toolbar {
  display: flex; align-items: center; gap: 10px;
}
.prompt-reports-search {
  flex: 1 1 320px; max-width: 480px;
  padding: 6px 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); font-size: 13px; color: var(--text);
}
.prompt-reports-count { font-size: 12px; }
.prompt-reports-users-wrap { overflow: auto; border: 1px solid var(--border); border-radius: 8px; }
.prompt-reports-table {
  width: 100%; border-collapse: collapse; font-size: 13px; background: var(--bg);
}
.prompt-reports-table thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--bg-soft, #f7f8fa); color: var(--text-muted);
  font-weight: 600; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.4px;
  padding: 9px 12px; border-bottom: 1px solid var(--border);
  text-align: left;
}
.prompt-reports-table thead th.num { text-align: right; }
.prompt-reports-table tbody td {
  padding: 10px 12px; border-bottom: 1px solid var(--border-soft, rgba(0,0,0,0.05));
  vertical-align: top;
}
.prompt-reports-table tbody td.num { text-align: right; font-variant-numeric: tabular-nums; }
.prompt-reports-table tbody tr:hover { background: rgba(37, 99, 235, 0.04); }
.prompt-reports-empty {
  padding: 22px 16px !important; text-align: center; color: var(--text-muted); font-size: 13px;
}
.pr-user-name { font-weight: 600; color: var(--text); }
.pr-user-email { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
.pr-user-role { font-size: 12px; text-transform: uppercase; letter-spacing: 0.3px; color: var(--text); }
.pr-user-org { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.pr-topcells .pr-chip-row { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 3px; }
.pr-topcells .pr-chip-row:last-child { margin-bottom: 0; }
.pr-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: 999px;
  font-size: 11px; line-height: 1.5;
  background: rgba(148, 163, 184, 0.18); color: #475569;
  white-space: nowrap; max-width: 220px;
  overflow: hidden; text-overflow: ellipsis;
}
.pr-chip em { font-style: normal; font-weight: 700; color: inherit; opacity: 0.85; }
.pr-chip-folder { background: rgba(37, 99, 235, 0.10); color: #1d4ed8; }
.pr-chip-org    { background: rgba(124, 58, 237, 0.12); color: #6d28d9; }
.pr-chip-engine { background: rgba(13, 115, 119, 0.12); color: #0f766e; font-family: var(--font-mono, monospace); }
.pr-view-btn { white-space: nowrap; }

/* Drill-down */
.prompt-reports-drilldown {
  display: flex; flex-direction: column; gap: 10px;
  border: 1px solid var(--border); border-radius: 8px; padding: 12px;
  background: var(--bg);
}
.prompt-reports-drilldown.hidden { display: none; }
.prompt-reports-drilldown-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.prompt-reports-drilldown-title { flex: 1 1 300px; }
.prompt-reports-drilldown-title strong { font-size: 15px; color: var(--text); }
.prompt-reports-drilldown-title .muted { font-size: 12px; margin-left: 8px; }
.prompt-reports-drilldown-tools { display: flex; gap: 8px; align-items: center; }
.prompt-reports-drilldown-tools input[type="search"] {
  padding: 5px 9px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); font-size: 12.5px; min-width: 220px;
}
.prompt-reports-drilldown-body { overflow: auto; max-height: calc(100vh - 320px); border: 1px solid var(--border); border-radius: 6px; }
.pr-prompt-cell {
  font-family: var(--font-mono, monospace); font-size: 12.5px;
  color: var(--text); max-width: 520px;
  white-space: pre-wrap; word-break: break-word;
}
.pr-truncated { color: var(--text-muted); font-family: inherit; }
.pr-cwd {
  display: inline-block; padding: 1px 6px; border-radius: 4px;
  background: rgba(148, 163, 184, 0.15); font-size: 11.5px;
  color: var(--text); font-family: var(--font-mono, monospace);
}
/* Prompt Reports · FOLDER — soft marker for cwds inherited from the workspace
   default (thread row has empty cwd). Distinguishes from folders explicitly
   set on the thread, without hiding the fact that the sidebar shows it. */
.pr-cwd-fallback {
  color: var(--text-muted, #94a3b8);
  font-size: 10px;
  font-family: var(--font-sans, inherit);
  font-weight: 500;
  opacity: 0.75;
  margin-left: 2px;
}
/* Prompt Reports · WHEN column — two-line date / time cell */
.pr-when-cell { white-space: nowrap; min-width: 92px; line-height: 1.25; }
.pr-when-cell .pr-when-date { font-size: 12.5px; color: var(--text); font-weight: 600; }
.pr-when-cell .pr-when-time {
  font-size: 11px; color: var(--text-muted, #94a3b8);
  font-variant-numeric: tabular-nums; letter-spacing: 0.2px;
}
