/* AGiXT Desktop sidebar styles
 * Layout, dark theme tuned for an always-on-top sidebar.
 * Activity/subactivity rendering mirrors the AGiXT web client conventions
 * (parent group with collapsible children, accent colors per type).
 */

/* Theme tokens.
 *
 * Dark is the default (lives on :root). Light is opt-in via
 * `<html data-theme="light">` which app.js sets on boot from the user's
 * saved preference (system / light / dark). When set to system we
 * reflect the OS `prefers-color-scheme` and live-update on changes.
 *
 * Server-delivered desktop extensions reuse these CSS variables, so
 * flipping the attribute on <html> recolors them automatically without
 * extension-side code. The few host rules that hardcoded
 * `rgba(255,255,255,…)` (scrollbar thumb, sidenav muted state, code
 * background, etc.) are explicitly overridden in the light block below
 * so the popover doesn't read as "mostly light with a few dark scars."
 */
:root,
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: rgba(15, 17, 24, 0.96);
  --panel: rgba(20, 24, 36, 0.92);
  --panel-2: rgba(28, 32, 46, 0.92);
  --panel-hover: rgba(36, 41, 56, 0.92);
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.16);
  --border-muted: rgba(255, 255, 255, 0.05);
  --text: #e6e8ee;
  --text-dim: #a1a7b5;
  --text-faint: #6f7585;
  --accent: #6b7bff;
  --accent-2: #9a6cff;
  --accent-soft: rgba(107, 123, 255, 0.18);
  /* Third accent — used for small details that benefit from a
     distinct blue (link hover, sort arrow, info badge, spinner ring).
     Headings/titles inherit --text instead. */
  --accent-blue: #5b8eff;
  /* User bubble shares --accent so it visually matches the rest of
     the accent surfaces (send button, audio play / progress / volume,
     1x-2x-3x toggle, etc.). One color across every "blue" surface. */
  --user-bubble: var(--accent);
  --assistant-bubble: rgba(36, 41, 56, 0.95);
  --activity: rgba(60, 80, 130, 0.30);
  --activity-thought: rgba(120, 90, 200, 0.22);
  --activity-error: rgba(220, 60, 80, 0.25);
  --activity-warn: rgba(220, 160, 60, 0.20);
  --activity-info: rgba(60, 140, 220, 0.20);
  --code-bg: rgba(255, 255, 255, 0.08);
  --code-block-bg: rgba(0, 0, 0, 0.4);
  --scrollbar-thumb: rgba(255, 255, 255, 0.12);
  --scrollbar-thumb-hover: rgba(255, 255, 255, 0.22);
  --sidenav-icon: rgba(255, 255, 255, 0.55);
  --sidenav-icon-active: #fff;
  --sidenav-hover-bg: rgba(255, 255, 255, 0.04);
  --modal-backdrop: rgba(0, 0, 0, 0.55);
  --radius: 12px;
  --radius-sm: 8px;
  --shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* "Dark" — modeled on VSCode Dark Modern. Neutral grayscale chrome (no
 * blue tint) with the brand accent kept intact. This is the default dark
 * variant the app resolves to from `system`; the deep-navy theme below
 * (`data-theme="dark"`, labeled "Dark Blue" in settings) is an explicit
 * opt-in for users who want the saturated blue palette. The internal
 * value stays `gray` so existing saved preferences keep working. */
:root[data-theme="gray"] {
  color-scheme: dark;
  --bg: #1f1f1f;
  --panel: #181818;
  --panel-2: #2a2a2a;
  --panel-hover: #2f2f2f;
  --border: rgba(255, 255, 255, 0.09);
  --border-strong: rgba(255, 255, 255, 0.18);
  --border-muted: rgba(255, 255, 255, 0.05);
  --text: #cccccc;
  --text-dim: #9d9d9d;
  --text-faint: #6e6e6e;
  /* Muted blue accent that sits naturally on the neutral gray chrome.
     Far less saturated than the dark theme's blue-purple — that one
     bloomed against #1f1f1f. Carries every accent surface (send btn,
     play/volume/progress in audible, 1x-2x-3x toggle, user bubble).
     Darkened further so the user bubble + send button don't shout
     against the muted gray surfaces. */
  --accent: #3d6a93;
  --accent-2: #9a6cff;
  --accent-soft: rgba(61, 106, 147, 0.20);
  --accent-blue: #355c81;
  --user-bubble: var(--accent);
  --assistant-bubble: #2a2a2a;
  --activity: rgba(60, 80, 130, 0.22);
  --activity-thought: rgba(120, 90, 200, 0.18);
  --activity-error: rgba(220, 60, 80, 0.22);
  --activity-warn: rgba(220, 160, 60, 0.18);
  --activity-info: rgba(60, 140, 220, 0.18);
  --code-bg: rgba(255, 255, 255, 0.06);
  --code-block-bg: #181818;
  --scrollbar-thumb: rgba(255, 255, 255, 0.15);
  --scrollbar-thumb-hover: rgba(255, 255, 255, 0.25);
  --sidenav-icon: rgba(255, 255, 255, 0.55);
  --sidenav-icon-active: #ffffff;
  --sidenav-hover-bg: rgba(255, 255, 255, 0.04);
  --modal-backdrop: rgba(0, 0, 0, 0.55);
  --shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f5f6fa;
  --panel: #ffffff;
  --panel-2: #eef0f5;
  --panel-hover: #e3e6ee;
  --border: rgba(15, 17, 24, 0.10);
  --border-strong: rgba(15, 17, 24, 0.20);
  --border-muted: rgba(15, 17, 24, 0.05);
  --text: #1a1d27;
  --text-dim: #565d6e;
  --text-faint: #8a90a0;
  --accent: #4f5dd1;
  --accent-2: #7a4dff;
  --accent-soft: rgba(79, 93, 209, 0.14);
  /* Darker blue so it stays readable against the white panel
     backgrounds without bloom. Same hue family as GitHub's link blue. */
  --accent-blue: #1f6feb;
  --user-bubble: var(--accent);
  --assistant-bubble: #ffffff;
  --activity: rgba(60, 80, 130, 0.08);
  --activity-thought: rgba(120, 90, 200, 0.10);
  --activity-error: rgba(220, 60, 80, 0.10);
  --activity-warn: rgba(220, 160, 60, 0.12);
  --activity-info: rgba(60, 140, 220, 0.10);
  --code-bg: rgba(15, 17, 24, 0.06);
  --code-block-bg: #f1f3f8;
  --scrollbar-thumb: rgba(15, 17, 24, 0.18);
  --scrollbar-thumb-hover: rgba(15, 17, 24, 0.32);
  --sidenav-icon: rgba(15, 17, 24, 0.55);
  --sidenav-icon-active: #1a1d27;
  --sidenav-hover-bg: rgba(15, 17, 24, 0.05);
  --modal-backdrop: rgba(15, 17, 24, 0.40);
  --shadow: 0 12px 32px rgba(15, 17, 24, 0.12);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  font-family: var(--font);
  color: var(--text);
  background: transparent;
  overflow: hidden;
  /* Hard-clip at the window border. Any internal area that needs
   * scrolling (chat log, auth fields when small) handles its own
   * overflow inside the popover — never the body, otherwise we'd get
   * a chrome scrollbar that looks awful. */
}

/* ---------- Tray-anchored popover ----------
 *
 * The window is shown/hidden as a unit at the OS level. The `.dock-panel`
 * fills the whole window — borders + shadow give it the visual identity
 * of a Discord/Slack-style menu popover.
 */

.dock-panel {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow);
  overflow: hidden;
}

/* Borderless windows don't get OS-native resize edges, so we render
 * our own grip corners. Tauri 2 ships with built-in resize behavior
 * for elements with the `data-tauri-resize-*` attributes. */
.resize-handle {
  position: fixed;
  width: 16px;
  height: 16px;
  z-index: 1000;
  cursor: nwse-resize;
}
.resize-handle-br {
  bottom: 0;
  right: 0;
  cursor: se-resize;
  background: linear-gradient(135deg,
    transparent 0%, transparent 55%,
    rgba(255,255,255,0.12) 55%, rgba(255,255,255,0.12) 60%,
    transparent 60%, transparent 70%,
    rgba(255,255,255,0.18) 70%, rgba(255,255,255,0.18) 75%,
    transparent 75%, transparent 85%,
    rgba(255,255,255,0.24) 85%, rgba(255,255,255,0.24) 90%,
    transparent 90%);
  border-bottom-right-radius: 14px;
}
.resize-handle-bl {
  bottom: 0;
  left: 0;
  cursor: sw-resize;
  background: linear-gradient(225deg,
    transparent 0%, transparent 55%,
    rgba(255,255,255,0.12) 55%, rgba(255,255,255,0.12) 60%,
    transparent 60%, transparent 70%,
    rgba(255,255,255,0.18) 70%, rgba(255,255,255,0.18) 75%,
    transparent 75%, transparent 85%,
    rgba(255,255,255,0.24) 85%, rgba(255,255,255,0.24) 90%,
    transparent 90%);
  border-bottom-left-radius: 14px;
}
.resize-handle:hover {
  background-color: rgba(255,255,255,0.06);
}

/* Topbar */

.topbar {
  display: flex;
  align-items: stretch;
  gap: 8px;
  /* Top padding grows to cover a device status bar / notch when one is
     reported via env(safe-area-inset-top); on desktop the inset is 0 so
     the original 8px still applies. Without this the brand mark gets
     clipped under the system status bar on Android/iOS. */
  padding: max(8px, env(safe-area-inset-top)) 10px 8px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  /* Anchor for the agent/convo popovers — they use top: 100% to drop
     down below the topbar. Without `relative` they fall through to the
     dock-panel and land at the bottom of the window. */
  position: relative;
}

.brand {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.brand-mark {
  width: 32px;
  height: 32px;
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex-shrink: 0;
  position: relative;
}
.brand-mark img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
/* When no SVG is available we fall back to a gradient tile + initials. */
.brand-mark.fallback {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff;
  font-weight: 800;
  font-size: 12px;
  letter-spacing: 0.5px;
}
.brand-mark.fallback img {
  display: none;
}
.brand-mark.fallback::after {
  content: attr(data-fallback);
}

/* Connection-state dot, overlaid on the logo. Hidden when connected so
   the topbar stays clean; only shows when there's a problem. */
.brand-conn {
  position: absolute;
  bottom: -2px;
  right: -2px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #ffd591;
  border: 1.5px solid var(--panel);
  display: block;
}
.brand-conn.connected { display: none; }
.brand-conn.error { background: #ff6b7a; }

/* Two stacked rows on the right side of the topbar. The agent chip and
   icon buttons share the top row; the conversation chip + new-conv
   button share the bottom row. The stack flexes against the logo so
   long agent or conversation names get the available width.

   `position: relative` is the anchor for the agent / convo popover
   menus inside; their `top: calc(100% + 4px)` lands at the bottom of
   the stack regardless of whether the stack lives in `.topbar` (popover
   mode) or has been relocated into the chat pane (window mode). */
.topbar-stack {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 auto;
  min-width: 0;
  position: relative;
}

body.auth-mode .topbar-stack {
  display: none;
}

/* When the landing iframe is showing, give it the full panel — the
   landing has its own header + branding, so the desktop topbar would
   just be redundant chrome above it. The Tauri drag region is still
   served by the iframe via window-level pointer events. */
body.auth-mode:has(#landing-screen:not([hidden])) .topbar {
  display: none;
}

/* Window mode: hide the global topbar (the OS title bar provides the
   drag region + close, and the brand identity), and slot the agent /
   conversation chips into the top of the chat pane via the
   `topbar-stack--in-chat` class added by app.js. Saves the ~76px of
   vertical chrome the topbar used to claim. */
body.window-mode:not(.auth-mode) .topbar {
  display: none;
}
.topbar-stack--in-chat {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  flex: 0 0 auto;
}
/* Popovers anchored to the in-chat stack drop down INTO the chat
   surface — make sure they layer above the messages list. */
.topbar-stack--in-chat .popover-menu {
  z-index: 60;
}
.topbar-row {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}
.topbar-row > .chip-btn { flex: 1 1 auto; min-width: 0; }

.icon-btn {
  width: 28px;
  height: 28px;
  border-radius: 6px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-dim);
  font-size: 16px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  line-height: 1;
}
.icon-btn:hover { background: var(--panel-2); color: var(--text); }
.icon-btn[aria-pressed="true"] { background: var(--accent); color: #fff; }

/* Chip-style switchers — agent + conversation, hosted in the topbar. */

.chip-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 10px;
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 500;
  cursor: pointer;
  /* In the topbar both chips share a single flex track with the action
     buttons. Allow them to shrink so long agent/conversation names get
     ellipsised instead of pushing the row over the window width. */
  flex: 1 1 0;
  min-width: 0;
  max-width: 100%;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.chip-btn-icon {
  flex-shrink: 0;
  color: var(--text-faint);
}
.chip-btn:hover { background: var(--panel); border-color: var(--border-strong); }
.chip-btn[aria-expanded="true"] { background: var(--panel); border-color: var(--accent); }
.chip-btn-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  min-width: 0;
  text-align: left;
}

.popover-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 8px;
  right: 8px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: 50;
  max-height: 380px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.popover-menu[hidden] { display: none; }
.popover-menu-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--text-faint);
  padding: 8px 10px 4px;
}
.popover-menu-search {
  padding: 8px 8px 4px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  position: sticky;
  top: 0;
  z-index: 1;
}
.popover-menu-search input {
  width: 100%;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 6px 9px;
  font-family: inherit;
  font-size: 12px;
  box-sizing: border-box;
}
.popover-menu-search input:focus {
  outline: 1px solid var(--accent);
  border-color: var(--accent);
}
.popover-menu-list {
  overflow-y: auto;
  flex: 1;
  padding: 2px 4px 6px;
}
.popover-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 6px;
  cursor: pointer;
  border: none;
  background: transparent;
  width: 100%;
  text-align: left;
  font-family: inherit;
  font-size: 12px;
  color: var(--text);
}
.popover-menu-item:hover { background: var(--panel-2); }
.popover-menu-item.is-selected { color: var(--text); }
.popover-menu-item.is-selected .popover-menu-check { color: #5dd28f; }
.popover-menu-check {
  width: 14px;
  flex-shrink: 0;
  color: transparent;
}
.popover-menu-item .agent-name { font-weight: 600; }
.popover-menu-item .agent-company {
  color: var(--text-faint);
  font-size: 11px;
  margin-left: 4px;
}
.popover-menu-footer {
  border-top: 1px solid var(--border);
  padding: 4px;
}
.popover-menu-action {
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  padding: 8px;
  font-family: inherit;
  font-size: 12px;
  color: var(--accent);
  cursor: pointer;
  border-radius: 6px;
}
.popover-menu-action:hover { background: var(--panel-2); }
.convo-meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}
.convo-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 500;
}
.convo-time {
  font-size: 10.5px;
  color: var(--text-faint);
}

/* Chat scroll area */

.chat {
  flex: 1;
  overflow-y: auto;
  padding: 14px 12px;
  /* Flex column + `margin-top: auto` on `.messages` (below) anchors a
     short conversation to the bottom of the scroller so the latest
     activity sits just above the composer instead of floating at the
     top of an empty pane. When content grows past the visible height
     the auto-margin collapses and ordinary scrolling resumes. */
  display: flex;
  flex-direction: column;
  /* `scroll-behavior: smooth` was here but it animates *user* scroll
     wheel events too, which makes the scrollbar feel sluggish when
     the user is just trying to skim the conversation. Programmatic
     scrolls (auto-scroll-to-bottom in chat.js) set scrollTop directly
     and don't need a CSS smooth — they're already instant. */
  /* CSS scroll anchoring keeps the visible content pinned when chat
     content reflows (e.g. when the chat pane width changes from a
     resize-handle drag or a layout transition into window mode). */
  overflow-anchor: auto;
}

.empty-state {
  text-align: center;
  color: var(--text-dim);
  margin-top: 60px;
  padding: 0 16px;
}
.empty-state-icon { font-size: 32px; margin-bottom: 8px; }
.empty-state-title { font-size: 16px; font-weight: 600; color: var(--text); margin-bottom: 6px; }
.empty-state-body { font-size: 13px; line-height: 1.5; }

.messages { display: flex; flex-direction: column; gap: 10px; margin-top: auto; }

/* Message bubble */

.message { display: flex; flex-direction: column; max-width: 100%; }
.message-row { display: flex; gap: 8px; align-items: flex-end; }
.message-user { align-items: flex-end; }
.message-user .message-row { justify-content: flex-end; }
.message-assistant .message-row { justify-content: flex-start; }

/* Timestamp pinned to the bubble's bottom edge. Hidden until the user
   hovers the message row. The full date sits in the title attribute. */
.message-ts {
  font-size: 10px;
  color: var(--text-faint);
  white-space: nowrap;
  flex-shrink: 0;
  padding-bottom: 4px;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.message-row:hover .message-ts { opacity: 1; }

.bubble {
  border-radius: var(--radius);
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.5;
  max-width: 92%;
  word-wrap: break-word;
  overflow-wrap: anywhere;
}
.message-user .bubble {
  background: var(--user-bubble);
  color: #fff;
  border-bottom-right-radius: 4px;
}
.message-assistant .bubble {
  background: var(--assistant-bubble);
  border: 1px solid var(--border);
  border-bottom-left-radius: 4px;
}

.message-meta {
  font-size: 10px;
  color: var(--text-faint);
  margin-top: 2px;
  padding: 0 4px;
}

/* Activity groups */

.activity {
  background: var(--activity);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin: 4px 0;
  overflow: hidden;
  font-size: 12px;
}
.activity[data-type="thought"] { background: var(--activity-thought); }
.activity[data-type="error"]   { background: var(--activity-error); }
.activity[data-type="warn"]    { background: var(--activity-warn); }
.activity[data-type="info"]    { background: var(--activity-info); }

.activity-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  cursor: pointer;
  user-select: none;
  color: var(--text-dim);
}
.activity-head .chev { transition: transform 0.15s ease; }
.activity[aria-expanded="true"] .activity-head .chev { transform: rotate(90deg); }
.activity-title { flex: 1; font-weight: 500; color: var(--text); }
.activity-elapsed {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  white-space: nowrap;
  flex: 0 0 auto;
}
.activity-elapsed:empty { display: none; }
.activity-spinner {
  width: 10px; height: 10px; border-radius: 50%;
  border: 2px solid var(--text-faint);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
  display: none;
}
.activity[data-running="true"] .activity-spinner { display: inline-block; }

.activity-body {
  padding: 0 10px 8px 28px;
  display: none;
  border-top: 1px solid var(--border);
  margin-top: 4px;
  padding-top: 6px;
  font-size: 11.5px;
  color: var(--text-dim);
}
.activity[aria-expanded="true"] .activity-body { display: block; }

.tool-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--text-dim);
  margin: 4px 0 4px;
  align-self: flex-start;
}
.tool-chip-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--text-faint);
  flex-shrink: 0;
}
.tool-chip.pending .tool-chip-dot {
  background: var(--accent);
  animation: pulse 1.2s ease-in-out infinite;
}
.tool-chip.ok .tool-chip-dot { background: #5dd28f; }
.tool-chip.error { color: #ff8a96; border-color: rgba(255,138,150,0.3); }
.tool-chip.error .tool-chip-dot { background: #ff8a96; }

.subactivity {
  display: flex;
  gap: 8px;
  padding: 6px 0;
  align-items: flex-start;
}
.subactivity + .subactivity { border-top: 1px dashed var(--border); }
.subactivity .sub-icon {
  flex: 0 0 auto;
  width: 16px;
  text-align: center;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-faint);
  user-select: none;
}
.subactivity .sub-content {
  flex: 1 1 auto;
  min-width: 0;
}
.subactivity .sub-content .md { font-size: 11.5px; line-height: 1.45; }

.subactivity[data-tag="THOUGHT"]     .sub-icon { color: #c4b3ff; }
.subactivity[data-tag="THOUGHT"]     .sub-content { color: #c4b3ff; }
.subactivity[data-tag="ERROR"]       .sub-icon,
.subactivity[data-tag="ERROR"]       .sub-content { color: #ff8a96; }
.subactivity[data-tag="WARNING"]     .sub-icon,
.subactivity[data-tag="WARNING"]     .sub-content { color: #ffd591; }
.subactivity[data-tag="INFO"]        .sub-icon { color: #8bc7ff; }
.subactivity[data-tag="CLIENT_TOOL"] .sub-icon { color: #9ee0a3; }
.subactivity[data-tag="REMOTE"]      .sub-icon { color: #74c2ff; }
.subactivity[data-tag="DIAGRAM"]     .sub-icon { color: #d8a3ff; }
.subactivity[data-tag="EXECUTION"]   .sub-icon { color: #ffc36b; }

/* Tool-call group: one collapsed line per tool call ("Called <name>")
 * that, when expanded, reveals the request payload + every follow-up
 * subactivity (REMOTE queue, REMOTE complete, received result, uploads). */
details.sub-tool-group {
  margin: 4px 0;
}
details.sub-tool-group > summary.sub-tool-group-summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--text-dim);
  padding: 3px 8px;
  border-radius: 5px;
  border: 1px solid transparent;
  background: rgba(158, 224, 163, 0.04);
}
details.sub-tool-group > summary.sub-tool-group-summary::-webkit-details-marker { display: none; }
details.sub-tool-group > summary.sub-tool-group-summary::before {
  content: '▸';
  display: inline-block;
  width: 10px;
  font-size: 10px;
  color: #9ee0a3;
  transition: transform 0.15s ease;
}
details.sub-tool-group[open] > summary.sub-tool-group-summary::before {
  transform: rotate(90deg);
}
details.sub-tool-group > summary.sub-tool-group-summary:hover {
  border-color: rgba(158, 224, 163, 0.25);
  background: rgba(158, 224, 163, 0.08);
}
.sub-tool-group-body {
  margin-top: 6px;
  padding: 6px 8px;
  border-left: 2px solid rgba(158, 224, 163, 0.2);
  margin-left: 6px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* CLIENT_TOOL — collapsed by default, expands on click */
details.sub-tool {
  margin: 0;
}
details.sub-tool > summary.sub-tool-summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--text-dim);
  padding: 2px 6px;
  border-radius: 4px;
  border: 1px solid transparent;
}
details.sub-tool > summary.sub-tool-summary::-webkit-details-marker { display: none; }
details.sub-tool > summary.sub-tool-summary::before {
  content: '▸';
  display: inline-block;
  width: 10px;
  font-size: 10px;
  color: var(--text-faint);
  transition: transform 0.15s ease;
}
details.sub-tool[open] > summary.sub-tool-summary::before { transform: rotate(90deg); }
details.sub-tool > summary.sub-tool-summary:hover {
  border-color: var(--border);
  background: rgba(255, 255, 255, 0.03);
}
.sub-tool-name {
  font-family: var(--mono);
  font-size: 11px;
  color: #9ee0a3;
  background: rgba(158, 224, 163, 0.08);
  padding: 1px 6px;
  border-radius: 4px;
}
.sub-tool-pre {
  margin: 6px 0 0;
  font-family: var(--mono);
  font-size: 10.5px;
  background: rgba(0, 0, 0, 0.35);
  padding: 6px 8px;
  border-radius: 5px;
  overflow-x: auto;
  white-space: pre;
  color: var(--text-dim);
}

/* EXECUTION — first line is the disclosure summary, body holds json args /
 * code / command output behind a click so the chat isn't a wall of tool I/O. */
details.sub-exec {
  margin: 0;
  width: 100%;
  min-width: 0;
}
details.sub-exec > summary.sub-exec-summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--text-dim);
  padding: 2px 6px;
  border-radius: 4px;
  border: 1px solid transparent;
  max-width: 100%;
}
details.sub-exec > summary.sub-exec-summary::-webkit-details-marker { display: none; }
details.sub-exec > summary.sub-exec-summary::before {
  content: '▸';
  display: inline-block;
  width: 10px;
  font-size: 10px;
  color: #ffc36b;
  transition: transform 0.15s ease;
  flex: 0 0 auto;
}
details.sub-exec[open] > summary.sub-exec-summary::before { transform: rotate(90deg); }
details.sub-exec > summary.sub-exec-summary:hover {
  border-color: rgba(255, 195, 107, 0.25);
  background: rgba(255, 195, 107, 0.06);
}
.sub-exec-title {
  display: inline;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sub-exec-title p { margin: 0; display: inline; }
.sub-exec-body {
  margin-top: 6px;
  padding: 6px 8px;
  border-left: 2px solid rgba(255, 195, 107, 0.2);
  margin-left: 6px;
  font-size: 11.5px;
  line-height: 1.45;
}
.sub-exec-body pre {
  background: rgba(0, 0, 0, 0.35);
  padding: 6px 8px;
  border-radius: 5px;
  overflow-x: auto;
}
.codex-events {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.codex-step .sub-exec-summary {
  background: rgba(158, 224, 163, 0.04);
}
.codex-step .sub-exec-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.codex-response {
  border-top: 1px dashed var(--border);
  margin-top: 4px;
  padding-top: 6px;
}

/* REMOTE / command result terminal block */
.sub-remote {
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}
.sub-remote-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding: 4px 8px;
  background: rgba(116, 194, 255, 0.08);
  font-size: 11px;
}
.sub-remote-name {
  font-family: var(--mono);
  color: #74c2ff;
}
.sub-remote-exit {
  font-family: var(--mono);
  font-size: 10.5px;
  padding: 1px 6px;
  border-radius: 999px;
}
.sub-remote-exit.ok  { color: #5dd28f; background: rgba(93, 210, 143, 0.12); }
.sub-remote-exit.err { color: #ff8a96; background: rgba(255, 138, 150, 0.15); }
.sub-remote-out, .sub-remote-err {
  margin: 0;
  padding: 6px 8px;
  font-family: var(--mono);
  font-size: 10.5px;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-all;
  background: rgba(0, 0, 0, 0.35);
  color: var(--text);
}
.sub-remote-err { color: #ff8a96; }

/* Markdown content inside bubbles */

.md p { margin: 0 0 8px; }
.md p:last-child { margin-bottom: 0; }
/* Chapter / section titles in agent responses inherit the body text
   color (--text), which reads as white on dark/gray and as near-black
   on light. Earlier we colored these with --accent-blue, but on the
   gray theme that bloomed against the muted chrome — the user
   preferred a plain bold heading. --accent-blue is still available
   for small accents (links, sort arrows, info badges). */
.md h1, .md h2, .md h3, .md h4, .md h5, .md h6 {
  margin: 14px 0 6px;
  line-height: 1.25;
}
.md h1 { font-size: 19px; font-weight: 700; }
.md h2 { font-size: 16px; font-weight: 700; }
.md h3 { font-size: 14px; font-weight: 600; }
.md h4, .md h5, .md h6 { font-size: 13px; font-weight: 600; }
.md > h1:first-child,
.md > h2:first-child,
.md > h3:first-child,
.md > h4:first-child { margin-top: 0; }
/* Bubble text is white (or whatever the accent's foreground reads as);
   force markdown links inside it to inherit so they don't drop to the
   global --accent color and lose contrast on the bubble background. */
.message-user .md a { color: inherit; }
.md code {
  font-family: var(--mono);
  font-size: 12px;
  background: var(--code-bg);
  padding: 1px 4px;
  border-radius: 4px;
}
.md pre {
  background: var(--code-block-bg);
  padding: 8px 10px;
  border-radius: 6px;
  overflow-x: auto;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.4;
  margin: 6px 0;
}
.md pre code { background: transparent; padding: 0; }
.md a { color: var(--accent); text-decoration: none; }
.md a:hover { text-decoration: underline; }
.md ul, .md ol { padding-left: 22px; margin: 6px 0; }
.md li { margin: 2px 0; }
.md img, .md video {
  max-width: 100%;
  height: auto;
  border-radius: 8px;
  margin: 6px 0;
  display: block;
}
.md video { background: #000; }
.md audio { width: 100%; margin: 6px 0; }
.md table { border-collapse: collapse; margin: 6px 0; font-size: 11.5px; }
.md th, .md td { border: 1px solid var(--border); padding: 4px 6px; text-align: left; }
.md blockquote {
  margin: 6px 0;
  padding: 4px 10px;
  border-left: 3px solid var(--accent);
  color: var(--text-dim);
}
.md hr { border: none; border-top: 1px solid var(--border); margin: 10px 0; }

/* Composer */

.composer {
  background: var(--panel);
  padding: 6px 10px;
  /* No top border — keeps the composer continuous with the sidenav at
     the bottom-left corner so they read as one control surface
     framing the chat content. */
}
.composer-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.composer-input {
  flex: 1;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 7px 10px;
  font-family: inherit;
  font-size: 13px;
  line-height: 1.4;
  resize: none;
  min-height: 32px;
  max-height: 160px;
}
.composer-input:focus { outline: 1px solid var(--accent); border-color: var(--accent); }
/* Composer buttons share a footprint with the sidenav buttons so the
   "control surface" reads uniformly across the left rail and the
   bottom bar. Same 32×32, same 8px corners, same border-less hover
   highlight (already inherited from `.icon-btn:hover`). */
.composer-row .icon-btn,
.composer-row .send-btn {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
}
.composer-row .icon-btn {
  border-radius: 8px;
  border: none;
}
.send-btn {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  border: none;
  background: var(--accent);
  color: #fff;
  font-size: 15px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s ease;
}
.send-btn:hover { background: var(--accent-2); }
.send-btn:disabled { opacity: 0.5; cursor: not-allowed; }
/* Send/stop swap. The `display: flex` on .send-btn would normally
   override the HTML `hidden` attribute (UA `display: none`), so without
   this both buttons render side-by-side. Defer to [hidden] explicitly. */
.send-btn[hidden] { display: none; }
/* Stop button shares the send-btn footprint (already covered by the
   .composer-row .send-btn rule) but reads as a destructive action. */
.send-btn.stop-btn { background: #e34555; }
.send-btn.stop-btn:hover { background: #c83a48; }
.send-btn.stop-btn svg { display: block; }
.composer-status {
  font-size: 11px;
  color: var(--text-faint);
  margin-top: 2px;
  min-height: 0;
}
.composer-status:empty { display: none; }
.composer-status.error { color: #ff8a96; }

/* Attachments tray sits above the composer row. Chips show the file's
   basename with the full path on hover, and an × to drop it before
   sending. The selected files are local-only — they get cleared after
   the message goes out.
   The [hidden] override is load-bearing: without it the `display: flex`
   would override the HTML hidden attribute and the empty tray would
   keep reserving margin above the composer. */
.attachments {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 6px;
}
.attachments[hidden] { display: none; }
.attachment-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 4px 2px 10px;
  font-size: 11px;
  color: var(--text);
  max-width: 100%;
}
.attachment-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 240px;
}
.attachment-remove {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-faint);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.attachment-remove:hover { background: var(--border); color: var(--text); }
.attach-btn { color: var(--text-dim); }
.attach-btn:hover { color: var(--text); }

/* Mic button — tap to record, tap again to stop+transcribe+send. The
   data-state attribute toggles which inner glyph is visible. */
.mic-btn { color: var(--text-dim); position: relative; }
.mic-btn:hover { color: var(--text); }
.mic-btn .mic-icon-idle,
.mic-btn .mic-icon-recording,
.mic-btn .mic-icon-busy { display: none; }
.mic-btn[data-state="idle"] .mic-icon-idle { display: inline-block; }
.mic-btn[data-state="recording"] {
  color: #fff;
  background: #e34555;
  border-color: #e34555;
}
.mic-btn[data-state="recording"] .mic-icon-recording {
  display: inline-block;
  width: 10px;
  height: 10px;
  background: #fff;
  border-radius: 2px;
  animation: mic-pulse 1.2s ease-in-out infinite;
}
.mic-btn[data-state="busy"] .mic-icon-busy {
  display: inline-block;
  animation: spin 0.8s linear infinite;
}
@keyframes mic-pulse {
  0%, 100% { transform: scale(1);   opacity: 1; }
  50%      { transform: scale(0.7); opacity: 0.7; }
}
.composer-status.speaking { color: #5dd28f; }

/* Child role shell: keep the chat available, but make voice the primary
   action and remove administrative/navigation affordances. */
body.child-mode .topbar-stack > .topbar-row:first-child,
body.child-mode #btn-agent-training,
body.child-mode #btn-share,
body.child-mode #btn-delete-conversation,
body.child-mode .sidenav-btn[data-view]:not([data-view="chat"]):not([data-view="xtschool"]):not([data-view^="xtschool_"]):not([data-view="audible"]),
body.child-mode .sidenav-more-btn,
body.child-mode .sidenav-more-popover,
/* The "Put your agent to work" suggestion strip above the composer doesn't
   belong in the kid surface — kids talk to AGiXT through the mic, not
   through agent-management prompt builders. */
body.child-mode #prompt-guidance {
  display: none !important;
}
body.child-mode .composer {
  padding: 12px 16px 14px;
}
body.child-mode .attachments,
body.child-mode #btn-attach,
body.child-mode #btn-workspace,
body.child-mode #composer-input,
body.child-mode #btn-send {
  display: none !important;
}
body.child-mode .composer-row {
  justify-content: center;
}
body.child-mode #btn-mic {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.22);
}
body.child-mode #btn-mic:hover:not(:disabled) {
  background: var(--accent-2);
}
body.child-mode #btn-mic:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
}
body.child-mode #btn-mic svg {
  width: 28px;
  height: 28px;
}
body.child-mode #btn-mic .mic-icon-recording {
  width: 18px;
  height: 18px;
}
body.child-mode .composer-status {
  margin-top: 8px;
  text-align: center;
  font-size: 12px;
}

/* Auth screen */

.auth-screen {
  flex: 1;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 12px 14px 18px;
  min-height: 0;
}
.auth-screen[hidden] { display: none; }

/* Landing screen — pre-auth marketing page hosted in an iframe so the
   brand's CSS stays isolated from the desktop client's tokens. The
   floating "Sign in" pill in the top-right is rendered by the host
   (not the iframe) so it works even if a brand forgets to add an
   auth CTA. */
.landing-screen {
  flex: 1;
  display: flex;
  position: relative;
  min-height: 0;
  background: var(--bg);
}
.landing-screen[hidden] { display: none; }
.landing-screen iframe {
  flex: 1;
  width: 100%;
  height: 100%;
  border: 0;
  background: var(--bg);
}
.chat-screen {
  flex: 1;
  display: flex;
  flex-direction: row;
  min-height: 0;
}
.chat-screen[hidden] { display: none; }

/* Trial / billing lifecycle banner — appears at the top of the dock-panel
   (directly under the topbar) so it spans the full window width and is
   visually unmissable, instead of being squeezed into the chat column. */
.trial-banner {
  flex: 0 0 auto;
  width: 100%;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid color-mix(in srgb, #ffb774 34%, var(--border));
  background:
    linear-gradient(90deg,
      color-mix(in srgb, #ffb774 16%, var(--panel)),
      color-mix(in srgb, var(--panel) 92%, #5dd28f 8%));
  color: var(--text);
}
.trial-banner-icon {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #ffcf8a;
  background: color-mix(in srgb, #ffb774 18%, var(--panel-2));
  border: 1px solid color-mix(in srgb, #ffb774 24%, var(--border));
}
.trial-banner-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.trial-banner-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.trial-banner-copy {
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-dim);
}
.trial-banner-actions {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.trial-banner-btn,
.trial-banner-primary,
.trial-banner-close {
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--border);
  font: inherit;
  font-size: 12px;
  font-weight: 650;
  cursor: pointer;
}
.trial-banner-btn {
  padding: 0 12px;
  background: var(--panel-2);
  color: var(--text);
}
.trial-banner-primary {
  padding: 0 13px;
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.trial-banner-close {
  width: 32px;
  padding: 0;
  background: transparent;
  color: var(--text-dim);
}
.trial-banner-btn:hover,
.trial-banner-close:hover {
  background: var(--panel-hover);
  color: var(--text);
}
.trial-banner-primary:hover { filter: brightness(1.07); }
.trial-banner-info {
  border-bottom-color: color-mix(in srgb, #8bc7ff 34%, var(--border));
  background:
    linear-gradient(90deg,
      color-mix(in srgb, #8bc7ff 14%, var(--panel)),
      color-mix(in srgb, var(--panel) 92%, #5dd28f 8%));
}
.trial-banner-info .trial-banner-icon {
  color: #8bc7ff;
  background: color-mix(in srgb, #8bc7ff 18%, var(--panel-2));
  border-color: color-mix(in srgb, #8bc7ff 24%, var(--border));
}
.trial-banner-bad {
  border-bottom-color: color-mix(in srgb, #ff8a96 36%, var(--border));
  background:
    linear-gradient(90deg,
      color-mix(in srgb, #ff8a96 14%, var(--panel)),
      color-mix(in srgb, var(--panel) 92%, #ffb774 8%));
}
.trial-banner-bad .trial-banner-icon {
  color: #ff8a96;
  background: color-mix(in srgb, #ff8a96 18%, var(--panel-2));
  border-color: color-mix(in srgb, #ff8a96 24%, var(--border));
}

@media (max-width: 760px) {
  .trial-banner {
    grid-template-columns: auto minmax(0, 1fr);
  }
  .trial-banner-actions {
    grid-column: 1 / -1;
    justify-content: flex-start;
  }
}

/* Right-hand pane that hosts the active view's content. The sidenav
   sits to its left and we want this column to shrink/grow to fill the
   remaining width. min-width:0 lets the inner chat scroller behave
   correctly inside the flex row. */
.chat-screen-main {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  position: relative;
}

/* One pane per registered section. Active pane fills the column; all
   others are display:none via [hidden]. Each pane manages its own
   internal layout (chat: scroller + composer; future sections can
   render whatever fits). */
.view-pane {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}
.view-pane[hidden] { display: none; }
/* Server-delivered extension pages get a default scroll container so
   they don't bleed past the dock-panel; extensions can still set their
   own overflow on their root if they need fixed footers/etc. */
.view-pane.view-pane-extension {
  overflow: auto;
}
/* Framed layout (manifest opt-in: `"layout": "framed"`). The host
   draws a thin header strip — same color as the topbar + sidenav so
   the chrome reads as one continuous band across the top of the
   window — with the manifest label as the title and a flex actions
   slot the extension can populate via `ctx.headerActionsEl` /
   `ctx.setHeaderActions(...)`. The body below it is where the
   extension mounts its content; it owns its own scroll so the header
   stays pinned. Switching from `view-pane.view-pane-extension`'s
   default `overflow: auto` to `overflow: hidden` here is what makes
   that pinning work. */
/* `:not([hidden])` is load-bearing: without it the `display: flex`
   below outranks `.view-pane[hidden] { display: none }` (specificity
   30 vs 11) and every framed pane renders simultaneously, stacking
   their headers down the chat-screen-main column. */
.view-pane.view-pane-extension.is-framed:not([hidden]) {
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.ext-pane-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
  min-height: 0;
  /* Stacking context — needed so absolutely-positioned dropdowns
     anchored inside the header (e.g. the machines column picker)
     paint OVER the body's content. Without it the body, being a
     later sibling, paints over header descendants. */
  position: relative;
  z-index: 2;
}
.ext-pane-title {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
  margin: 0;
  flex: 0 0 auto;
  color: var(--text);
}
.ext-pane-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
  /* Push actions to the right by default — extensions typically put
     a refresh icon, search input, and column picker here. */
  justify-content: flex-end;
}
.ext-pane-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  /* Flex column so extensions can rely on `height: 100%` / `flex: 1`
     children resolving against a definite parent. The list view in
     machines uses `min-height: 100%` (single child grows to fill +
     content beyond scrolls); the detail / remote views use
     `height: 100%` with their OWN inner overflow:auto on the detail
     body — that pattern needs the parent to be a flex container with
     a definite height, otherwise the child collapses. */
  display: flex;
  flex-direction: column;
}

/* Host-side polish overlay — improves the default look-and-feel of
   server-delivered extensions without touching their own scoped CSS.
   Hover lift on action buttons, accent focus ring on inputs/selects,
   slightly heavier card presence with subtle inner highlight on the
   top edge. Each rule targets the common class shapes the extensions
   use (`*-table`, `*-card`, `*-primary`, `*-secondary`, `*-search`,
   `*-tab`, etc.) so they pick the polish up without per-page edits. */
.view-pane-extension button {
  transition: background 0.14s ease, color 0.14s ease, border-color 0.14s ease, transform 0.08s ease, box-shadow 0.14s ease;
}
.view-pane-extension button:active:not(:disabled) {
  transform: translateY(0.5px);
}
.view-pane-extension button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.view-pane-extension input:focus,
.view-pane-extension select:focus,
.view-pane-extension textarea:focus {
  outline: none;
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 3px rgba(107, 123, 255, 0.18) !important;
}
.view-pane-extension input[type="search"],
.view-pane-extension input[type="text"],
.view-pane-extension input[type="email"],
.view-pane-extension input[type="password"],
.view-pane-extension select,
.view-pane-extension textarea {
  font-family: var(--font);
}
/* Bump card presence — extensions use varied class prefixes
   (mx-card, co-card, ct-card, …); target every outer `-card` class
   without bleeding into their `-card-*` subelements.

   The previous selector `[class*="-card"]` matched any class string
   containing "-card" anywhere, which silently also matched
   `mx-card-head`, `mx-card-title`, `mx-card-body`, `co-card-content`,
   etc. Each match drew a 1px inset top-highlight, producing visible
   hairlines next to card titles (the "lines in the table headers"
   bug reported on /machines).

   The two-clause selector below restricts the match to classes that
   either *end* with `-card` (the only class on the element) OR are
   followed by a space (one of multiple classes on the element).
   `mx-card-head` matches neither, so nested subelements no longer
   pick up the polish. */
.view-pane-extension [class$="-card"],
.view-pane-extension [class*="-card "] {
  position: relative;
}
.view-pane-extension [class$="-card"]::before,
.view-pane-extension [class*="-card "]::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
/* Table wrapper polish — soft shadow on the rounded box. */
.view-pane-extension [class*="-table-wrap"] {
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.02), 0 4px 18px rgba(0, 0, 0, 0.22);
}
/* Active filter pill gets a subtle accent glow. */
.view-pane-extension [class*="-tab"].is-active {
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 0 0 1px var(--accent) inset;
}
/* Primary action buttons — accent glow on hover so the call-to-action
   reads stronger than the secondary buttons next to it. */
.view-pane-extension [class*="-primary"] {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 0 rgba(255, 255, 255, 0.1) inset;
}
.view-pane-extension [class*="-primary"]:hover:not(:disabled) {
  filter: brightness(1.08);
  box-shadow: 0 2px 6px rgba(107, 123, 255, 0.32), 0 1px 0 rgba(255, 255, 255, 0.12) inset;
}
/* Page title spacing tweak — more breathing room above the table. */
.view-pane-extension h2[class*="-title"] {
  font-feature-settings: "ss01", "ss02", "cv11";
}
/* Make code/mono cells slightly more visible against the bg. */
.view-pane-extension code {
  letter-spacing: 0.005em;
}

/* Slicker page-header structure — push search inputs to the right
   edge so the title + action buttons cluster on the left, and give
   each header more breathing room. Targets the common class shapes
   (`*-title-row`, `*-search`, `*-tabs`) so every extension picks the
   spacing up without per-page edits. */
.view-pane-extension [class*="-title-row"] {
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  row-gap: 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
  margin-bottom: 4px;
}
.view-pane-extension [class*="-title-row"] > [class*="-search"] {
  margin-left: auto;
}
.view-pane-extension [class*="-title-row"] > h2[class*="-title"] {
  margin-right: 8px;  /* small visual gap between title text and the
                         action buttons that follow */
}
/* Filter-tab row — extra top space so it isn't visually fused to the
   action buttons above it. */
.view-pane-extension [class*="-tabs"] {
  padding-top: 4px;
}

/* Server-registered sidenav buttons either render a built-in
   monochrome SVG (resolved from the icon registry by name) or fall
   back to text/emoji. Sized to match the static chat + settings SVG
   icons so the rail reads as one coherent control surface. */
.sidenav-btn-icon {
  font-size: 18px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.sidenav-btn-icon svg {
  display: block;
  width: 20px;
  height: 20px;
}

/* Workspace-open layout — chat pane stays visible alongside the
   workspace editor. `.chat-screen-main` flips to a row, the chat pane
   takes a fixed slim column, and `#workspace-screen` (mounted as a
   sibling by workspace.js) fills the rest. */
/* Window-mode: the popover has been promoted to a real OS window.
   The chat pane stays alongside any extension/workspace content via
   `body.with-content-pane`; when chat is the only thing showing, it
   fills the whole width. */
body.window-mode .chat-screen-main {
  flex-direction: row;
}
body.window-mode .view-pane[data-view="chat"] {
  flex: 1 1 auto;
  min-width: 0;
}
body.window-mode.with-content-pane .view-pane[data-view="chat"] {
  flex: 0 0 var(--chat-pane-width, 340px);
  min-width: 0;
  border-right: 1px solid var(--border);
}
body.window-mode.chat-collapsed .view-pane[data-view="chat"] {
  display: none;
}
body.window-mode .dock-panel {
  border-radius: 0;
  border: 0;
  box-shadow: none;
}
body.window-mode .resize-handle {
  display: none;
}

/* Drag handle between chat pane and content area. Hidden in popover
   mode and in chat-only window mode (no content next to chat).
   Doubles as the collapse-chat affordance via a chevron button. */
.chat-resize-handle {
  display: none;
  flex: 0 0 4px;
  background: transparent;
  cursor: col-resize;
  position: relative;
  user-select: none;
  margin-left: -1px;
  z-index: 2;
}
body.window-mode.with-content-pane .chat-resize-handle {
  display: flex;
  align-items: center;
  justify-content: center;
}
.chat-resize-handle:hover,
.chat-resize-handle.is-dragging {
  background: rgba(107, 123, 255, 0.35);
}
/* Stacked handle controls — expand (fill window) above, collapse
   (hide chat) below. Centered on the seam; revealed on hover/focus. */
.chat-handle-actions {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.chat-expand-btn,
.chat-collapse-btn {
  width: 18px;
  height: 36px;
  padding: 0;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text-dim);
  border-radius: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.12s ease, color 0.12s ease, background 0.12s ease;
}
.chat-resize-handle:hover .chat-expand-btn,
.chat-resize-handle:hover .chat-collapse-btn,
.chat-expand-btn:focus-visible,
.chat-collapse-btn:focus-visible {
  opacity: 1;
}
.chat-expand-btn:hover,
.chat-collapse-btn:hover {
  color: var(--text);
  background: var(--panel);
}

/* Expanded — chat fills the whole content area, the content pane
   (extension or workspace) is hidden. The sidenav icons remain the
   way back to whatever page was open. Mutually exclusive with the
   collapsed state. */
body.window-mode.chat-expanded.with-content-pane .view-pane[data-view="chat"] {
  flex: 1 1 auto;
  border-right: 0;
}
body.window-mode.chat-expanded.with-content-pane .chat-screen-main > .view-pane:not([data-view="chat"]),
body.window-mode.chat-expanded.with-content-pane .chat-screen-main > #workspace-screen {
  display: none;
}
body.window-mode.chat-expanded .chat-resize-handle {
  display: none;
}

/* Collapsed re-expand strip — replaces the chat pane when collapsed. */
.chat-collapsed-strip {
  display: none;
  flex: 0 0 28px;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding: 10px 0;
  gap: 8px;
  background: var(--panel);
  border-right: 1px solid var(--border);
  cursor: pointer;
  color: var(--text-dim);
  font-family: inherit;
  border-top: 0;
  border-bottom: 0;
  border-left: 0;
}
.chat-collapsed-strip:hover {
  background: var(--panel-2);
  color: var(--text);
}
body.window-mode.chat-collapsed .chat-collapsed-strip {
  display: flex;
}
body.window-mode.chat-collapsed .chat-resize-handle {
  display: none;
}
.chat-collapsed-strip-label {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.7;
}

/* ---------- Mobile portrait: one surface at a time --------------------
   On a phone in portrait the 340px chat-beside-content split is too
   cramped, so we collapse to a single active surface. app.js stamps
   `body.mobile-portrait` from a matchMedia listener
   (`(orientation: portrait) and (max-width: 820px)`); desktop and
   landscape never get the class, so every rule below is inert there
   and the split experience is unchanged.

   Behaviour: picking a sidenav section shows that page full-width with
   the agent chat collapsed to the existing pop-open "Chat" strip. Tap
   the strip and chat slides up as a full-screen overlay over the page;
   the Back bar returns to the page. This reuses the exact
   collapse/strip machinery the desktop split already has — the only
   difference is chat overlays the page instead of taking a side
   column. */

/* Chat open over a content page: cover the whole content area instead
   of taking a fixed side column. `.chat-screen-main` is
   position:relative, so inset:0 fills it (the sidenav is its sibling
   and stays put). The page stays mounted underneath. When collapsed,
   the existing `body.window-mode.chat-collapsed
   .view-pane[data-view="chat"] { display:none }` rule plus the strip
   still apply unchanged. */
body.mobile-portrait.window-mode.with-content-pane:not(.chat-collapsed) .view-pane[data-view="chat"] {
  position: absolute;
  inset: 0;
  z-index: 40;
  flex: none;
  width: 100%;
  border-right: 0;
  background: var(--bg);
}

/* No seam to drag when only one surface shows at a time. */
body.mobile-portrait.window-mode .chat-resize-handle {
  display: none;
}

/* The pop-open "Chat" affordance keeps the exact same look it has when
   collapsed on desktop (the vertical edge strip) so it reads as part
   of the app rather than a bolted-on mobile control. The only mobile
   concessions: a slightly wider touch target and a raised z-index so
   it always stays tappable above page content. Once each page flexes
   to mobile (no horizontal overflow) the strip is no longer buried, so
   no special positioning is needed — it stays the inline left-edge
   column it is on desktop. */
body.mobile-portrait.window-mode.chat-collapsed .chat-collapsed-strip {
  flex-basis: 38px;
  z-index: 60;
}

/* ---- Status bar / notch / home-indicator (mobile only) -------------
   In window mode the global `.topbar` (which carried the
   env(safe-area-inset-top) padding) is hidden, so without this the
   chat/content surface renders under the device status bar and its
   top row of controls can't be tapped. Inset the whole app shell by
   the reported safe areas; on desktop every env() is 0 so this is a
   no-op. Scoped away from auth-mode because the auth/landing screens
   keep their own topbar inset. */
body.window-mode:not(.auth-mode) .dock-panel {
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}

/* ---- Team chat: columns → slide-over drawers (mobile portrait) -----
   The Discord-style layout is four side-by-side columns
   (company rail 56px · channel list 220px · content · member list
   220px). On a phone that crushes the message surface to a sliver.
   Keep the thin company rail inline, but float the channel + member
   lists as absolute drawers over the content so the conversation
   always gets the full width. The existing
   `.tc-channels-collapsed` / `.tc-members-collapsed` rules
   (display:none) still close them; team-chat.js drives those classes
   from a transient mobile state so a phone session never overwrites
   the desktop collapse preference. */
body.mobile-portrait .view-pane-team-chat .tc-body { position: relative; }
body.mobile-portrait .view-pane-team-chat .tc-content {
  flex: 1 1 auto;
  min-width: 0;
}
body.mobile-portrait .view-pane-team-chat .tc-channel-list,
body.mobile-portrait .view-pane-team-chat .tc-member-list {
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 8;
  width: min(80vw, 300px);
  box-shadow: 0 0 34px rgba(0, 0, 0, 0.45);
}
body.mobile-portrait .view-pane-team-chat .tc-channel-list {
  left: 56px; /* docked just right of the 56px company rail */
}
body.mobile-portrait .view-pane-team-chat .tc-member-list {
  right: 0;
}

/* ===== Mobile portrait: make every page flex ========================
   The panes were designed for a wide desktop split; on a phone their
   fixed multi-column layouts overflow, producing window-level
   side-scrollbars and truncated content. These rules (all gated on
   body.mobile-portrait, so desktop/landscape are untouched) clip the
   page, turn list+detail layouts into single-surface drawers, and let
   genuinely-wide content (tables, code) scroll inside its own box
   instead of widening the whole app. */

/* Nothing produces a window-level horizontal scrollbar or bleeds over
   the chat strip — every pane clips and scrolls internally. */
body.mobile-portrait .chat-screen-main { overflow: hidden; }

/* Tables are the #1 side-scroll culprit. Scroll them inside their own
   wrapper rather than widening the page — covers the app's own
   *-table-wrap convention and server-delivered extensions. */
body.mobile-portrait [class*="-table-wrap"],
body.mobile-portrait [class*="-table-scroll"],
body.mobile-portrait .view-pane-extension [class*="table"] {
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Header / toolbar rows wrap instead of overflowing; tab strips that
   can't wrap (segmented controls) scroll horizontally. */
body.mobile-portrait .cn-header,
body.mobile-portrait .pl-header,
body.mobile-portrait .as-header,
body.mobile-portrait .as-panel-toolbar,
body.mobile-portrait .view-pane-extension [class*="-title-row"],
body.mobile-portrait .view-pane-extension [class*="-toolbar"] {
  flex-wrap: wrap;
  row-gap: 8px;
}
body.mobile-portrait .cn-scope-tabs,
body.mobile-portrait .pl-scope-tabs,
body.mobile-portrait .us-tabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Workspace: the Files tree becomes a right-side slide-over drawer so
   the editor always gets the full width (same pattern as team chat).
   The collapsed 28px re-expand strip is untouched — it's already thin
   enough and is the affordance to reopen the drawer. */
body.mobile-portrait .wk-body { position: relative; }
body.mobile-portrait .wk-sidebar {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 8;
  width: min(82vw, 300px);
  box-shadow: 0 0 34px rgba(0, 0, 0, 0.45);
}
body.mobile-portrait .wk-sidebar-resize { display: none; }

/* List+editor panes (chains, prompts) already stack via their own
   ≤720px viewport media query; guarantee the list spans full width and
   the editor can shrink so neither forces a side-scroll on a phone. */
body.mobile-portrait .cn-list,
body.mobile-portrait .pl-list {
  width: 100%;
  max-width: 100%;
}
body.mobile-portrait .cn-editor,
body.mobile-portrait .pl-editor,
body.mobile-portrait .cn-step-body,
body.mobile-portrait .pl-edit-grid {
  min-width: 0;
}

/* Inputs / title wrappers that hard-pin a min-width wider than a phone
   would otherwise blow out their row. */
body.mobile-portrait .as-search-wrap,
body.mobile-portrait .cn-editor-titlewrap,
body.mobile-portrait .pl-editor-titlewrap {
  min-width: 0;
}

/* Generic server-extension safety. Their CSS is delivered, not editable
   here, so clamp media/code/tables to the viewport and let wide blocks
   scroll internally; flow rows wrap rather than overflow. */
body.mobile-portrait .view-pane-extension { overflow: auto; }
body.mobile-portrait .view-pane-extension img,
body.mobile-portrait .view-pane-extension pre,
body.mobile-portrait .view-pane-extension table,
body.mobile-portrait .view-pane-extension video {
  max-width: 100%;
}
body.mobile-portrait .view-pane-extension pre {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
body.mobile-portrait .view-pane-extension [class*="-row"],
body.mobile-portrait .view-pane-extension [class*="-actions"],
body.mobile-portrait .view-pane-extension [class*="-filters"] {
  flex-wrap: wrap;
}

/* Back bar — present only while the chat overlay is up on a phone.
   `order:-1` floats it above the agent/conversation stack that app.js
   relocates in as the chat pane's first child in window mode. */
.chat-mobile-back {
  display: none;
}
body.mobile-portrait.window-mode.with-content-pane:not(.chat-collapsed) .chat-mobile-back {
  order: -1;
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  width: 100%;
  padding: 11px 14px;
  background: var(--panel);
  border: 0;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
body.mobile-portrait.window-mode.with-content-pane:not(.chat-collapsed) .chat-mobile-back:hover {
  background: var(--panel-2);
}
body.mobile-portrait.window-mode.with-content-pane:not(.chat-collapsed) .chat-mobile-back:active {
  background: var(--panel-2);
  transform: translateY(0.5px);
}

/* VSCode-style activity bar. Top group lists sections (Chat, …); bottom
   group is reserved for pinned actions (currently just app settings).
   New sections are added by dropping a `.sidenav-btn[data-view=…]` into
   `.sidenav-top` and a matching `.view-pane[data-view=…]` into
   `.chat-screen-main`. */
.sidenav {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 44px;
  padding: 8px 0;
  gap: 2px;
  background: var(--panel);
  /* No right border — the panel/bg colour difference is enough of a
     seam, and the lack of a line lets the sidenav read as part of the
     same "control surface" as the composer below. */
}
.sidenav-top,
.sidenav-bottom {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  align-items: center;
}
/* `min-height: 0` lets the top group shrink below its natural content
   size when the window is short — without it the flex item floors at
   `min-height: auto` (content size) and pushes the bottom group
   off-screen. `overflow: hidden` clips any tail buttons before the JS
   overflow pass swaps them into the "···" popover, and is what makes
   `scrollHeight > clientHeight` observable so the reflow can detect
   the overflow in the first place. */
.sidenav-top {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
.sidenav-bottom { flex: 0 0 auto; }

/* Brand mark slot at the top of the sidenav. Decorative — chat is
   always present in the application, so the brand replaces what used
   to be a redundant Chat nav button. */
.sidenav-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  margin-bottom: 6px;
  flex-shrink: 0;
}
.sidenav-brand .brand-mark {
  width: 28px;
  height: 28px;
}
.sidenav-btn {
  width: 32px;
  height: 32px;
  /* Pin the row height — without this, when `.sidenav-top` is squeezed
     (min-height: 0 lets it shrink below content size), flex-shrink
     defaults to 1 and the browser compresses each button down to its
     min-content size (~20px from the inner SVG). That made the icons
     read as smashed together and also fooled the overflow reflow into
     measuring shrunken row heights, so it thought every button fit and
     never invoked the "···" popover. The brand already pins itself the
     same way (.sidenav-brand has flex-shrink: 0). */
  flex-shrink: 0;
  border-radius: 8px;
  border: none;
  background: transparent;
  /* VSCode activity-bar treatment: muted gray by default, full
     contrast on hover/active. Icons inherit `currentColor` from the SVG. */
  color: var(--sidenav-icon);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  position: relative;
  transition: color 0.14s ease, background 0.14s ease;
}
.sidenav-btn:hover {
  color: var(--sidenav-icon-active);
  background: var(--sidenav-hover-bg);
}
.sidenav-btn:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 1px;
}
.sidenav-btn.is-active {
  color: var(--sidenav-icon-active);
  background: transparent;
}
/* VSCode-style accent rail running along the left edge of the active
   button. -4px from the button left = flush with the sidenav's left
   edge (button is 32px in 40px sidenav, centered, so 4px each side). */
.sidenav-btn.is-active::before {
  content: "";
  position: absolute;
  left: -4px;
  top: 4px;
  bottom: 4px;
  width: 2px;
  border-radius: 0 2px 2px 0;
  background: var(--accent);
}
/* Instant CSS tooltip — replaces the 1.5s browser-default `title`
   delay with VSCode's "appears immediately on hover" feel. */
.sidenav-btn[data-tooltip] { /* anchor for ::after */ }
.sidenav-btn[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  left: calc(100% + 8px);
  top: 50%;
  transform: translateY(-50%);
  padding: 4px 8px;
  border-radius: 4px;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border-strong);
  font-size: 11px;
  font-weight: 500;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform-origin: left center;
  transition: opacity 0.08s ease;
  z-index: 50;
  box-shadow: 0 4px 14px rgba(0,0,0,0.35);
}
.sidenav-btn:hover[data-tooltip]::after,
.sidenav-btn:focus-visible[data-tooltip]::after {
  opacity: 1;
}
/* Hide the native browser tooltip on these buttons so we don't get
   the double-flash of CSS tooltip + system tooltip after the delay. */
.sidenav .sidenav-btn[title] { /* keep the attribute for a11y */ }
/* Drag-sort affordances — only middle-group buttons (non-chat,
   non-admin-slot) are draggable, and only `.sidenav-top` listens for
   reordering. The is-dragging button fades; the drop target shows a
   thin accent rail above or below it via box-shadow (the ::before
   pseudo-element is already in use for the active-state rail). */
.sidenav-btn.is-dragging {
  opacity: 0.35;
  cursor: grabbing;
}
.sidenav-btn.is-drop-above,
.sidenav-more-row.is-drop-above {
  box-shadow: inset 0 2px 0 var(--accent);
}
.sidenav-btn.is-drop-below,
.sidenav-more-row.is-drop-below {
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* Overflow handling — when the sidenav can't fit every middle-group
   button, the tail items get `is-overflow-hidden` (display:none) and a
   `.sidenav-more-btn` appears as the last visible row. Clicking the
   More button opens a `.sidenav-more-popover` listing the hidden items;
   each row activates that view on click and can be dragged into the
   visible rail to pin it. */
.sidenav-btn.is-overflow-hidden {
  display: none;
}
.sidenav-more-btn .more-dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  margin: 0 1px;
}
.sidenav-more-btn[aria-expanded="true"] {
  color: var(--sidenav-icon-active);
  background: var(--sidenav-hover-bg);
}
.sidenav-more-btn.has-active-hidden::after {
  /* small dot in the corner indicating an active view is hiding */
  /* `::after` is already used by [data-tooltip], so use a separate
     dot element rendered via a child instead — see .more-active-dot. */
}
.more-active-dot {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  pointer-events: none;
}

.sidenav-more-popover {
  position: fixed;
  z-index: 60;
  min-width: 180px;
  max-width: 280px;
  max-height: 70vh;
  overflow-y: auto;
  padding: 4px;
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0,0,0,0.4);
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.sidenav-more-popover[hidden] { display: none; }
.sidenav-more-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  border-radius: 6px;
  border: none;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  user-select: none;
  width: 100%;
}
.sidenav-more-row:hover,
.sidenav-more-row:focus-visible {
  background: var(--sidenav-hover-bg);
  outline: none;
}
.sidenav-more-row.is-active {
  color: var(--sidenav-icon-active);
}
.sidenav-more-row.is-active::before {
  content: "";
  width: 2px;
  align-self: stretch;
  border-radius: 0 2px 2px 0;
  background: var(--accent);
  margin-left: -8px;
  margin-right: 2px;
}
.sidenav-more-row.is-dragging {
  opacity: 0.35;
  cursor: grabbing;
}
.sidenav-more-row .more-row-icon {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--sidenav-icon);
}
.sidenav-more-row.is-active .more-row-icon {
  color: var(--sidenav-icon-active);
}
.sidenav-more-row .more-row-label {
  flex: 1 1 auto;
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Notification dot — used by the bottom gear when an action (e.g. a
   downloaded desktop update) is waiting for the user. Subtle so it
   doesn't compete with other UI. */
.sidenav-btn.has-pending::after {
  content: "";
  position: absolute;
  top: 4px;
  right: 4px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--panel);
}

.auth-card {
  width: 100%;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.auth-tabs {
  display: flex;
  gap: 4px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 3px;
  margin-bottom: 6px;
}
.auth-tab {
  flex: 1;
  background: transparent;
  border: none;
  color: var(--text-dim);
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.2px;
}
.auth-tab[aria-selected="true"] {
  background: var(--accent);
  color: #fff;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--text-dim);
}
.field[hidden],
.auth-pane[hidden],
.auth-row[hidden] { display: none !important; }
.field-label {
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-size: 10px;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: 6px;
}
.field-meta {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  font-size: 10px;
  color: var(--text-faint);
  opacity: 0.7;
}
.field-hint {
  font-size: 11px;
  color: var(--text-faint);
  margin-top: 2px;
}
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.field input[type="email"],
.field input[type="text"],
.field input[type="password"],
.field input[type="url"],
.field select,
.field textarea {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  font-family: inherit;
  font-size: 12px;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: 1px solid var(--accent);
  border-color: var(--accent);
}
/* Native <select> renders its closed face with the OS chrome by
   default (white in light, dark in some themes) regardless of our
   CSS. Strip the appearance and paint a chevron with currentColor so
   the closed widget reads as part of the theme. The dropdown popup
   itself is still drawn by the OS, but `color-scheme` on :root
   already aligns it with the active theme. */
.field select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  /* Pad on the right so the chevron has room. */
  padding-right: 28px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 9px center;
  cursor: pointer;
}
.field select::-ms-expand { display: none; }
.field.readonly input,
.field input:read-only {
  opacity: 0.7;
  cursor: default;
}

.auth-pane { display: flex; flex-direction: column; gap: 10px; }
.auth-pane[hidden] { display: none; }

.auth-invite {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 10px;
  align-items: flex-start;
  border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border));
  background:
    linear-gradient(
      135deg,
      color-mix(in srgb, var(--accent) 16%, var(--panel)) 0%,
      color-mix(in srgb, var(--accent) 6%, var(--panel)) 100%
    );
  border-radius: 10px;
  padding: 11px 12px 12px 12px;
  margin-bottom: 10px;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent) inset,
    0 4px 14px -8px color-mix(in srgb, var(--accent) 60%, transparent);
  animation: auth-invite-in 220ms ease-out;
}
.auth-invite::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  bottom: 8px;
  width: 3px;
  background: var(--accent);
  border-radius: 0 2px 2px 0;
}
.auth-invite[hidden] { display: none; }
.auth-invite-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 22%, var(--panel-2));
  color: var(--accent);
  flex: 0 0 auto;
  margin-top: 1px;
}
.auth-invite-main {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.auth-invite-title {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: 0.2px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.auth-invite-title::after {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);
  animation: auth-invite-pulse 1.8s ease-in-out infinite;
}
.auth-invite-body {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.45;
}
.auth-invite-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 4px;
}
.auth-invite-meta[hidden] { display: none; }
.auth-invite-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 18%, var(--panel-2));
  border: 1px solid color-mix(in srgb, var(--accent) 32%, var(--border));
  border-radius: 999px;
  padding: 2px 8px 2px 6px;
  max-width: 100%;
}
.auth-invite-chip[hidden] { display: none; }
.auth-invite-chip svg { opacity: 0.85; flex: 0 0 auto; }
.auth-invite-chip-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 180px;
}
.auth-invite-dismiss {
  appearance: none;
  background: transparent;
  border: none;
  color: var(--text-faint);
  padding: 4px;
  border-radius: 6px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  transition: background 120ms ease, color 120ms ease;
}
.auth-invite-dismiss:hover {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--text);
}
.auth-invite-dismiss:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.auth-invite-warn {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-top: 6px;
  padding: 6px 8px;
  font-size: 11px;
  line-height: 1.4;
  color: #ffb774;
  background: color-mix(in srgb, #ffb774 12%, transparent);
  border: 1px solid color-mix(in srgb, #ffb774 30%, transparent);
  border-radius: 6px;
}
.auth-invite-warn[hidden] { display: none; }
.auth-invite-warn::before {
  content: "!";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: color-mix(in srgb, #ffb774 28%, transparent);
  color: #ffb774;
  font-weight: 800;
  font-size: 10px;
  margin-top: 1px;
}

.auth-invite-actions {
  display: flex;
  gap: 6px;
  margin-top: 8px;
  flex-wrap: wrap;
}
.auth-invite-actions[hidden] { display: none; }
.auth-invite-accept,
.auth-invite-decline {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.2px;
  padding: 5px 11px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease, transform 80ms ease;
}
.auth-invite-accept {
  color: #fff;
  background: var(--accent);
  border: 1px solid var(--accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18), 0 4px 12px -6px var(--accent);
}
.auth-invite-accept:hover { filter: brightness(1.08); }
.auth-invite-accept:active { transform: translateY(0.5px); }
.auth-invite-decline {
  color: var(--text-dim);
  background: transparent;
  border: 1px solid var(--border);
}
.auth-invite-decline:hover {
  color: var(--text);
  background: var(--panel-2);
  border-color: color-mix(in srgb, var(--text-faint) 50%, var(--border));
}
@keyframes auth-invite-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes auth-invite-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}
@media (prefers-reduced-motion: reduce) {
  .auth-invite { animation: none; }
  .auth-invite-title::after { animation: none; }
}

.auth-cta {
  width: 100%;
  padding: 10px 12px;
  font-size: 13px;
}

.auth-row { display: flex; flex-direction: column; gap: 8px; }

.auth-divider {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--text-faint);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin: 4px 0;
}
.auth-divider::before, .auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.btn-ghost {
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border);
}
.btn-ghost:hover { background: var(--panel-2); color: var(--text); }
.btn-secondary {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
}
.btn-secondary:hover { background: var(--panel); }

.oauth-buttons {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.btn-oauth {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 500;
  text-align: left;
}
.btn-oauth:hover { background: var(--panel); border-color: var(--border-strong); }
.oauth-icon {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  /* Real provider mark SVGs are colored on their own; we just frame
   * them in a neutral background so light marks (Apple, GitHub) stay
   * visible against the panel. */
  background: rgba(255, 255, 255, 0.04);
}
.oauth-icon img,
.oauth-icon svg {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  border-radius: 4px;
}
.oauth-icon.fallback {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff;
  font-weight: 700;
  font-size: 11px;
  border-radius: 50%;
}

/* "Local" mode pane: localhost:7437 status + one-click installer.
   Lives between the URL fields and the login/register panes. The
   pane itself is hidden unless the user picks the "Local" service. */
.local-pane {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.local-pane[hidden] { display: none; }
.local-status {
  font-size: 12px;
  color: var(--text-dim);
  display: flex;
  align-items: center;
  gap: 6px;
}
.local-status::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-faint);
  flex-shrink: 0;
}
.local-status.ok { color: var(--text); }
.local-status.ok::before { background: #22c55e; }
.local-status.warn::before { background: #eab308; }
.local-status.error { color: #ef4444; }
.local-status.error::before { background: #ef4444; }
.local-status.info::before { background: var(--accent); }

.local-row { display: flex; align-items: center; gap: 8px; }
.local-row[hidden] { display: none; }
.local-row-stack { flex-direction: column; align-items: stretch; }

.local-hw-summary {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11.5px;
  color: var(--text-dim);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
}
.local-hw-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}
.local-hw-label {
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-size: 10px;
  color: var(--text-faint);
  flex-shrink: 0;
}
.local-hw-value {
  text-align: right;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text);
  word-break: break-all;
}
.local-hw-note {
  margin-top: 4px;
  padding-top: 6px;
  border-top: 1px dashed var(--border);
  font-size: 11px;
  line-height: 1.45;
  color: var(--text-faint);
}

.local-install-progress {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.local-install-log {
  background: #0b0d10;
  color: #d1d5db;
  font-family: var(--mono);
  font-size: 10.5px;
  line-height: 1.45;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  max-height: 220px;
  overflow-y: auto;
  white-space: pre-wrap;
  word-break: break-word;
}
.local-log-line { margin: 0; }
.local-log-phase { color: #93c5fd; font-weight: 600; }
.local-log-stderr { color: #fca5a5; }
.local-log-ok { color: #86efac; font-weight: 600; }
.local-log-err { color: #fca5a5; font-weight: 600; }

.auth-status {
  font-size: 11.5px;
  color: var(--text-faint);
  min-height: 16px;
  padding: 4px 2px;
  transition: color 120ms ease;
}
.auth-status:empty { padding: 0; min-height: 0; }
.auth-status.error,
.auth-status.success,
.auth-status.info {
  padding: 7px 10px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 6px;
  line-height: 1.4;
}
.auth-status.error::before,
.auth-status.success::before,
.auth-status.info::before {
  content: "";
  flex: 0 0 auto;
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.auth-status.error {
  color: #ff8a96;
  background: color-mix(in srgb, #ff8a96 12%, transparent);
  border: 1px solid color-mix(in srgb, #ff8a96 28%, transparent);
}
.auth-status.success {
  color: #5dd28f;
  background: color-mix(in srgb, #5dd28f 12%, transparent);
  border: 1px solid color-mix(in srgb, #5dd28f 28%, transparent);
}
.auth-status.info {
  color: #8bc7ff;
  background: color-mix(in srgb, #8bc7ff 12%, transparent);
  border: 1px solid color-mix(in srgb, #8bc7ff 28%, transparent);
}

.settings-user {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 7px 9px;
  font-size: 12px;
  color: var(--text);
}

/* Modal (Settings) */

.modal {
  position: fixed; inset: 0;
  background: var(--modal-backdrop);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 16px;
}
.modal.open { display: flex; }
.modal-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  width: 100%;
  max-width: 360px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: var(--shadow);
}
.share-modal-card {
  max-width: 540px;
  border-radius: 12px;
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.45), 0 1px 0 rgba(255, 255, 255, 0.06) inset;
  animation: share-modal-pop 0.18s cubic-bezier(.2, .9, .3, 1.2);
}
@keyframes share-modal-pop {
  from { transform: scale(0.96) translateY(8px); opacity: 0; }
  to { transform: scale(1) translateY(0); opacity: 1; }
}
.modal-close {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  font: inherit;
  font-size: 16px;
  line-height: 1;
  border-radius: 6px;
  transition: background 0.12s, color 0.12s;
}
.modal-close:hover { color: var(--text); background: var(--panel-2); }
.share-modal-card .modal-header {
  padding: 16px 18px;
  background: var(--panel);
}
.share-modal-card .modal-header h2 {
  font-size: 15px;
  font-weight: 700;
}
.share-modal-sub {
  margin: 4px 0 0;
  color: var(--text-faint);
  font-size: 12px;
  line-height: 1.45;
}
.share-modal-body { padding: 18px; gap: 14px; }
.share-modal-body select,
.share-modal-body input[type="email"],
.share-modal-body input[type="text"],
.share-modal-body input[type="datetime-local"] {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 9px 11px;
  font-family: inherit;
  font-size: 13px;
  transition: border-color 0.14s, box-shadow 0.14s;
}
.share-modal-body select:focus,
.share-modal-body input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(107, 123, 255, 0.18);
}
.share-modal-body select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 32px;
  cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23a1a7b5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 10px 10px;
}
.share-modal-body .field { gap: 6px; }
.share-modal-body .field > span:first-child {
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
}
.share-modal-body .field.check {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
}
.share-modal-body .field.check span {
  text-transform: none;
  letter-spacing: 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  padding-top: 0;
}
.share-modal-body .field.check input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
}
.share-modal-body input[readonly] {
  user-select: all;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--accent-blue);
  background: var(--panel);
}
.share-modal-body .settings-status {
  font-size: 12px;
  min-height: 16px;
  padding: 0 2px;
}
.share-modal-body .settings-status.success { color: #9ce0b3; }
.share-modal-body .settings-status.error { color: #ff8a96; }
.share-modal-body .field-actions {
  margin-top: 4px;
  padding-top: 12px;
  border-top: 1px solid var(--border-muted);
}
.share-modal-card .btn {
  border-radius: 8px;
  padding: 9px 14px;
  font-size: 12.5px;
  transition: filter 0.14s, background 0.14s, transform 0.08s;
}
.share-modal-card .btn:active { transform: translateY(0.5px); }
.share-modal-card .btn-primary {
  box-shadow: 0 1px 2px rgba(0,0,0,0.25), 0 1px 0 rgba(255,255,255,0.08) inset;
}
.share-modal-card .btn-primary:hover {
  filter: brightness(1.08);
  background: var(--accent);
  box-shadow: 0 2px 6px rgba(107, 123, 255, 0.32), 0 1px 0 rgba(255,255,255,0.12) inset;
}
.share-modal-card .btn:not(.btn-primary):not(.btn-danger) {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
}
.share-modal-card .btn:not(.btn-primary):not(.btn-danger):hover {
  background: var(--panel-hover);
}
.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}
.modal-header h2 { margin: 0; font-size: 14px; }
.modal-body { padding: 14px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }

/* Session overlay — blocking screen for billing/server-issue/auth events.
   Renders centered above all chrome and dims the rest of the app. */
.session-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--modal-backdrop);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.18s ease;
}
.session-overlay.is-open { opacity: 1; }
.session-overlay-card {
  width: min(440px, 100%);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 28px 26px;
  text-align: center;
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.45), 0 1px 0 rgba(255, 255, 255, 0.06) inset;
  transform: scale(0.96) translateY(8px);
  opacity: 0;
  animation: session-pop 0.22s 0.04s cubic-bezier(.2, .9, .3, 1.2) forwards;
}
@keyframes session-pop {
  to { transform: scale(1) translateY(0); opacity: 1; }
}
.session-overlay-icon {
  width: 64px;
  height: 64px;
  margin: 0 auto 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
}
.session-overlay[data-kind="payment"] .session-overlay-icon {
  background: rgba(232, 167, 68, 0.18);
  color: #ffd28a;
}
.session-overlay[data-kind="server-issue"] .session-overlay-icon {
  background: rgba(220, 60, 80, 0.18);
  color: #ff8a96;
}
.session-overlay[data-kind="auth"] .session-overlay-icon {
  background: rgba(91, 142, 255, 0.18);
  color: var(--accent-blue);
}
.session-overlay-title {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}
.session-overlay-body {
  margin: 0 0 8px;
  color: var(--text-dim);
  font-size: 13.5px;
  line-height: 1.55;
}
.session-overlay-hint {
  margin: 0 0 20px;
  color: var(--text-faint);
  font-size: 12px;
  line-height: 1.5;
}
.session-overlay-actions {
  display: flex;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
}
.session-overlay-btn,
.session-overlay-primary {
  height: 38px;
  padding: 0 18px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  border-radius: 10px;
  border: 1px solid var(--border);
  cursor: pointer;
  transition: background 0.14s, filter 0.14s, transform 0.08s, box-shadow 0.14s;
}
.session-overlay-btn {
  background: var(--panel-2);
  color: var(--text);
}
.session-overlay-btn:hover { background: var(--panel-hover); }
.session-overlay-primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.08) inset;
}
.session-overlay-primary:hover {
  filter: brightness(1.08);
  box-shadow: 0 2px 6px rgba(107, 123, 255, 0.32), 0 1px 0 rgba(255, 255, 255, 0.12) inset;
}
.session-overlay-btn:active,
.session-overlay-primary:active { transform: translateY(0.5px); }

.ext-load-error {
  margin: 16px;
  padding: 14px 16px;
  border: 1px solid rgba(220, 60, 80, 0.45);
  border-radius: var(--radius-sm);
  background: rgba(220, 60, 80, 0.14);
  color: #ffb4ba;
  font-size: 13px;
  line-height: 1.45;
}
.ext-load-error strong {
  display: block;
  color: var(--text);
  font-size: 14px;
  margin-bottom: 4px;
}
.ext-load-error p {
  margin: 0;
  color: #ffb4ba;
  overflow-wrap: anywhere;
}

.field { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--text-dim); }
.field input[type="url"], .field input[type="text"], .field textarea {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 7px 9px;
  font-family: inherit;
  font-size: 12px;
}
.field textarea { resize: vertical; font-family: var(--mono); font-size: 11px; }
.field code { font-family: var(--mono); font-size: 11px; background: var(--code-bg); padding: 1px 4px; border-radius: 3px; }
.field.check {
  flex-direction: row; align-items: flex-start; gap: 8px;
  cursor: pointer;
}
.field.check span { line-height: 1.4; padding-top: 1px; }
.sudo-session-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.sudo-session-row input {
  flex: 1;
  min-width: 0;
}
.sudo-session-row .btn {
  white-space: nowrap;
}
.sudo-session-actions {
  justify-content: space-between;
  align-items: center;
}
.sudo-session-status {
  min-width: 0;
  color: var(--text-faint);
  font-size: 11px;
  line-height: 1.35;
  text-align: right;
}
.sudo-session-status.error { color: #ff8a96; }
.sudo-session-status.success { color: #5dd28f; }
.field-actions { display: flex; justify-content: space-between; gap: 8px; margin-top: 6px; }

.btn {
  border: none;
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-2); }
.btn-danger { background: transparent; color: #ff8a96; border: 1px solid #ff8a96; }
.btn-danger:hover { background: rgba(255, 138, 150, 0.12); }

.settings-status { font-size: 11px; color: var(--text-faint); min-height: 14px; }
.settings-status.error { color: #ff8a96; }
.settings-status.success { color: #5dd28f; }

/* ---------- User Settings pane ---------- */
/* Side pane that hosts App / Account / Settings / Developer / Billing /
 * Companies / Teams. Reuses the agent-settings (.as-*) tokens for cards,
 * inputs, and toasts so the two settings panes feel like siblings. */

.view-pane-user-settings {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--bg);
}
.view-pane-user-settings[hidden] { display: none; }

.us-header {
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  padding: 0 16px;
  flex-shrink: 0;
}
.us-tabs {
  display: flex;
  gap: 0;
  flex-wrap: wrap;
  align-items: stretch;
  overflow-x: auto;
}
.us-tab {
  appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  padding: 11px 14px;
  cursor: pointer;
  transition: color 0.12s ease, border-color 0.12s ease;
  white-space: nowrap;
}
.us-tab:hover { color: var(--text); }
.us-tab.is-active {
  color: var(--text);
  border-bottom-color: var(--accent);
}
.us-tab[hidden] { display: none; }

.us-main {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  position: relative;
}
.us-panel {
  display: none;
  padding: 18px 22px 28px;
  flex-direction: column;
  gap: 14px;
  /* No max-width: settings sections should span the full width of the
     view-pane container so wide tables (members, tokens, webhooks) get
     room to breathe rather than being pinned at 720px. */
  width: 100%;
}
.us-panel.is-active { display: flex; }
.us-panel[hidden] { display: none !important; }

.us-section {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.us-section-title {
  font-size: 13.5px;
  font-weight: 650;
  margin: 0;
  letter-spacing: 0.1px;
}
.us-section-blurb {
  font-size: 12px;
  color: var(--text-dim);
  margin: 0;
  line-height: 1.45;
}
.us-section-row {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}
.us-section-row.between { justify-content: space-between; }
.us-section-row.end { justify-content: flex-end; }
.us-section-row.column { flex-direction: column; align-items: stretch; }

.us-plan-picker {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.us-billing-intervals {
  display: inline-flex;
  align-self: flex-start;
  gap: 6px;
  padding: 4px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2);
}
.us-billing-interval-btn {
  height: 30px;
  border-radius: 7px;
}
.us-plan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 10px;
}
.us-plan-card {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel-2);
}
.us-plan-card.is-current {
  border-color: color-mix(in srgb, #5dd28f 36%, var(--border));
  background: color-mix(in srgb, #5dd28f 8%, var(--panel-2));
}
.us-plan-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}
.us-plan-title {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
}
.us-plan-description {
  margin: 3px 0 0;
  color: var(--text-dim);
  font-size: 12px;
  line-height: 1.4;
}
.us-plan-price {
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.us-plan-price-amount {
  font-size: 24px;
  line-height: 1;
  font-weight: 750;
  color: var(--text);
}
.us-plan-price-interval {
  font-size: 12px;
  color: var(--text-dim);
}
.us-plan-limits {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
.us-plan-features {
  margin: 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--text-dim);
  font-size: 12px;
  line-height: 1.4;
}
.us-plan-card > .btn {
  margin-top: auto;
  align-self: flex-start;
}

/* Pending payment banner — shown in the Billing tab after the user
   opens an external Stripe checkout. Variants:
   - info    (blue)    → checkout opened, waiting on completion
   - warn    (amber)   → more than ~10 minutes elapsed, payment may have
                         been cancelled or abandoned
   - success (green)   → token balance went up, payment landed
*/
.us-payment-banner {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  margin-bottom: 8px;
}
.us-payment-banner-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: var(--panel);
  color: var(--text-dim);
  flex: 0 0 auto;
  margin-top: 1px;
}
.us-payment-banner-body { flex: 1; min-width: 0; }
.us-payment-banner-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.us-payment-banner-msg {
  font-size: 12.5px;
  color: var(--text-dim);
  line-height: 1.5;
  margin-top: 3px;
}
.us-payment-banner-actions {
  display: flex;
  gap: 6px;
  margin-top: 9px;
  flex-wrap: wrap;
}
.us-payment-banner-info {
  border-color: color-mix(in srgb, #8bc7ff 30%, var(--border));
  background: color-mix(in srgb, #8bc7ff 8%, var(--panel-2));
}
.us-payment-banner-info .us-payment-banner-icon {
  color: #8bc7ff;
  background: color-mix(in srgb, #8bc7ff 22%, var(--panel));
}
.us-payment-banner-warn {
  border-color: color-mix(in srgb, #ffb774 30%, var(--border));
  background: color-mix(in srgb, #ffb774 10%, var(--panel-2));
}
.us-payment-banner-warn .us-payment-banner-icon {
  color: #ffb774;
  background: color-mix(in srgb, #ffb774 22%, var(--panel));
}
.us-payment-banner-success {
  border-color: color-mix(in srgb, #5dd28f 32%, var(--border));
  background: color-mix(in srgb, #5dd28f 10%, var(--panel-2));
}
.us-payment-banner-success .us-payment-banner-icon {
  color: #5dd28f;
  background: color-mix(in srgb, #5dd28f 22%, var(--panel));
}
.us-payment-banner-bad {
  border-color: color-mix(in srgb, #ff8a96 32%, var(--border));
  background: color-mix(in srgb, #ff8a96 10%, var(--panel-2));
}
.us-payment-banner-bad .us-payment-banner-icon {
  color: #ff8a96;
  background: color-mix(in srgb, #ff8a96 22%, var(--panel));
}
.us-warning-list {
  margin: 4px 0 0;
  padding-left: 18px;
}
.us-warning-list li + li { margin-top: 3px; }

.us-grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
@media (max-width: 520px) {
  .us-grid-2 { grid-template-columns: 1fr; }
}

.us-input,
.us-textarea,
.us-select {
  width: 100%;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  font-family: inherit;
  font-size: 12.5px;
  box-sizing: border-box;
}
.us-input:focus,
.us-textarea:focus,
.us-select:focus {
  outline: 1px solid var(--accent);
  border-color: var(--accent);
}
.us-textarea { resize: vertical; min-height: 70px; font-family: inherit; }
.us-select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 28px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 9px center;
  cursor: pointer;
}

.us-label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--text-dim);
  flex: 1;
  min-width: 0;
}
.us-label-text {
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-size: 10px;
  color: var(--text-faint);
}
.us-hint {
  font-size: 11px;
  color: var(--text-faint);
  margin: 0;
  line-height: 1.4;
}
.us-hint.error { color: #ff8a96; }
.us-hint.success { color: #5dd28f; }

.us-check {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  cursor: pointer;
  font-size: 12.5px;
  color: var(--text);
  line-height: 1.4;
}
.us-check input[type="checkbox"] { accent-color: var(--accent); margin-top: 2px; }

.us-range-row {
  display: flex;
  gap: 10px;
  align-items: center;
}
.us-range {
  flex: 1;
  min-width: 120px;
  accent-color: var(--accent);
}

.us-row-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.us-list-item {
  display: flex;
  gap: 10px;
  align-items: center;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  flex-wrap: wrap;
}
.us-list-item-grow { flex: 1; min-width: 0; }
.us-list-item-title {
  font-size: 13px;
  font-weight: 600;
  margin: 0;
  word-break: break-word;
}
.us-list-item-meta {
  font-size: 11.5px;
  color: var(--text-dim);
  margin: 2px 0 0;
}
.us-list-item-actions {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-shrink: 0;
}

.us-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text-dim);
}
.us-badge.primary { background: var(--accent-soft); border-color: rgba(107, 123, 255, 0.45); color: var(--accent); }
.us-badge.success { background: rgba(94, 210, 143, 0.18); border-color: rgba(94, 210, 143, 0.4); color: #5dd28f; }
.us-badge.warn { background: rgba(220, 160, 60, 0.18); border-color: rgba(220, 160, 60, 0.4); color: #e5b86a; }
.us-badge.danger { background: rgba(255, 138, 150, 0.18); border-color: rgba(255, 138, 150, 0.4); color: #ff8a96; }

.us-toast {
  position: absolute;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--panel-2);
  color: var(--text);
  padding: 9px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow);
  font-size: 12.5px;
  max-width: 480px;
  z-index: 50;
  pointer-events: none;
}
.us-toast.success { border-color: rgba(94, 210, 143, 0.5); }
.us-toast.error { border-color: rgba(255, 138, 150, 0.55); }

.us-empty {
  padding: 28px 0;
  text-align: center;
  color: var(--text-faint);
  font-size: 12.5px;
}

.us-status-line {
  font-size: 11.5px;
  color: var(--text-faint);
  min-height: 14px;
}
.us-status-line.error { color: #ff8a96; }
.us-status-line.success { color: #5dd28f; }

.us-divider {
  height: 1px;
  background: var(--border);
  margin: 4px 0;
}

.us-section-danger {
  border-color: rgba(255, 138, 150, 0.4);
}
.us-section-danger .us-section-title { color: #ff8a96; }

.us-progress-track {
  width: 100%;
  height: 6px;
  background: var(--panel-2);
  border-radius: 3px;
  overflow: hidden;
}
.us-progress-fill {
  height: 100%;
  background: var(--accent);
  transition: width 0.2s ease;
}
.us-progress-fill.warn { background: #e5b86a; }
.us-progress-fill.danger { background: #ff8a96; }

.us-kv-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 12px;
  font-size: 12px;
}
.us-kv-grid dt {
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-size: 10px;
  color: var(--text-faint);
  align-self: center;
}
.us-kv-grid dd {
  margin: 0;
  color: var(--text);
  word-break: break-word;
}

.us-mono {
  font-family: var(--mono);
  font-size: 11px;
  background: var(--code-bg);
  padding: 2px 6px;
  border-radius: 3px;
  color: var(--text);
}

.us-scope-list {
  max-height: 220px;
  overflow-y: auto;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.us-scope-cat {
  font-weight: 600;
  font-size: 11.5px;
  margin: 6px 0 2px;
  text-transform: capitalize;
}
.us-scope-cat:first-child { margin-top: 0; }
.us-scope-row {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  padding-left: 8px;
}
.us-scope-row code {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--accent-blue);
}
.us-scope-row-desc { font-size: 10.5px; color: var(--text-faint); }

/* Notifications tab — per-category cards with action toggles. Mirrors
 * the web app's /user/settings notification cards but scaled for the
 * tighter side-pane footprint. */
.us-notif-categories {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.us-notif-categories.is-master-off {
  opacity: 0.5;
  pointer-events: none;
}
.us-notif-group-header {
  margin: 12px 2px 2px;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--text-faint);
}
.us-notif-card {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.us-notif-card.is-disabled .us-notif-card-meta { opacity: 0.7; }
.us-notif-card-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
}
.us-notif-card-meta { display: flex; flex-direction: column; gap: 2px; }
.us-notif-card-title {
  margin: 0;
  font-weight: 600;
  font-size: 13px;
  color: var(--text);
}
.us-notif-card-desc {
  margin: 0;
  font-size: 11.5px;
  color: var(--text-faint);
}
.us-notif-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 4px 16px;
  padding-top: 4px;
  border-top: 1px solid var(--border);
}
.us-notif-action {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 12px;
  color: var(--text-faint);
  padding: 4px 0;
  gap: 8px;
  cursor: pointer;
}
.us-notif-action:hover { color: var(--text); }
.us-notif-save-bar {
  position: sticky;
  bottom: 8px;
  margin-top: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: var(--panel);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
.us-notif-save-msg {
  flex: 1;
  font-size: 12.5px;
  color: var(--text);
}

/* Glasses tab — hide all settings sections (Focus & presence, Behavior,
 * Dashboard, Display Fit, Test and Save) until the user actually has
 * G1 glasses connected. `settingsContainer.hidden = true` already does
 * the work; we just style the offline hint so it sits at panel width. */
.g1-settings-container { display: flex; flex-direction: column; gap: 16px; }
.g1-settings-container[hidden] { display: none; }

/* Super Admin "Companies" filter row — keeps the search box stretchy and
 * the four selects sized to their content so they line up on a single row
 * and only wrap to a new line when the panel actually runs out of width. */
.us-admin-filters .us-input {
  width: auto;
  flex: 2 1 220px;
  min-width: 0;
}
.us-admin-filters .us-select {
  width: auto;
  flex: 0 1 auto;
  min-width: 0;
}

/* User-settings modal: overlay dialog used by the Super Admin and Custom
 * Roles editors. Mirrors the web app's edit/invite dialogs but scaled
 * for the side pane. Activates by appending to document.body. */
.us-modal-backdrop {
  position: fixed;
  inset: 0;
  background: var(--modal-backdrop);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: 16px;
}
.us-modal-card {
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  width: 100%;
  max-width: 560px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: var(--shadow);
}
.us-modal-card.wide { max-width: 720px; }
.us-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.us-modal-header h3 {
  margin: 0;
  font-size: 13.5px;
  font-weight: 650;
  letter-spacing: 0.1px;
}
.us-modal-header p {
  margin: 4px 0 0;
  font-size: 11.5px;
  color: var(--text-dim);
}
.us-modal-close {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-dim);
  font-size: 18px;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  cursor: pointer;
  line-height: 1;
}
.us-modal-close:hover { background: var(--panel-2); color: var(--text); }
.us-modal-body {
  padding: 14px 16px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.us-modal-footer {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
  flex-wrap: wrap;
}

/* Invite-results list (after multi-email invite send). */
.us-invite-results {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 200px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.us-invite-result {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 11.5px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.us-invite-result:last-child { border-bottom: 0; }
.us-invite-result.success { background: rgba(94, 210, 143, 0.08); }
.us-invite-result.error { background: rgba(255, 138, 150, 0.08); }
.us-invite-result-head {
  display: flex;
  gap: 6px;
  align-items: center;
}
.us-invite-result-msg { color: var(--text-dim); padding-left: 18px; word-break: break-word; }
.us-invite-result-msg.error { color: #ff8a96; }
.us-invite-result-link {
  display: flex;
  gap: 6px;
  align-items: center;
  padding-left: 18px;
}
.us-invite-result-link a {
  color: var(--accent);
  font-size: 11px;
  word-break: break-all;
  text-decoration: none;
}
.us-invite-result-link a:hover { text-decoration: underline; }

/* Bulk-select row checkboxes on the members list. */
.us-list-item.is-selected {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.us-bulk-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: var(--accent-soft);
  border: 1px solid rgba(107, 123, 255, 0.45);
  border-radius: var(--radius-sm);
  font-size: 12px;
  flex-wrap: wrap;
}
.us-bulk-bar-count {
  font-weight: 600;
  color: var(--accent);
  flex: 1;
  min-width: 0;
}

/* Status badges used in the invitations list. */
.us-badge.muted { background: var(--panel-2); border-color: var(--border); color: var(--text-dim); }

/* Inline action button row used in member rows so the role select plus
 * Remove plus custom-roles button line up cleanly even on narrow panes. */
.us-row-actions {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* Custom-roles list inside the manage-roles modal. */
.us-role-card {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  flex-wrap: wrap;
}
.us-role-card.inactive { opacity: 0.6; }
.us-role-card-grow { flex: 1; min-width: 0; }
.us-role-card-title { font-size: 12.5px; font-weight: 600; margin: 0; }
.us-role-card-desc { font-size: 11px; color: var(--text-dim); margin: 4px 0 0; }
.us-role-card-scopes {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 6px;
}
.us-role-card-scopes code {
  font-family: var(--mono);
  font-size: 10.5px;
  background: var(--code-bg);
  color: var(--accent-blue);
  padding: 1px 6px;
  border-radius: 3px;
}
.us-role-card-actions {
  display: flex;
  gap: 4px;
  align-items: center;
  flex-shrink: 0;
}

/* Sticky bulk-action bar so it stays visible while the user scrolls a
 * long member list. Tooltip context: scroll container is `.us-main`. */
.us-bulk-bar {
  position: sticky;
  top: 0;
  z-index: 4;
}

/* Compact chip-style button used on member rows for the "+ Custom role"
 * affordance. Inline-stylable buttons across the codebase use .btn
 * variants — this one is small enough to need its own class. */
.us-chip-btn {
  appearance: none;
  border: 1px dashed var(--border-strong);
  background: transparent;
  color: var(--text-dim);
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  padding: 1px 8px;
  line-height: 1.5;
  cursor: pointer;
  font-family: inherit;
}
.us-chip-btn:hover:not(:disabled) {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-soft);
}
.us-chip-btn:disabled { opacity: 0.5; cursor: default; }

/* Search/filter bar above member or invitation lists. */
.us-filter-bar {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.us-filter-bar .us-input { flex: 1; min-width: 160px; }

/* Stat pills shown next to a section title — e.g. "5 Admins · 12 Users".
 * Decorative but useful for quick at-a-glance team composition. */
.us-stat-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.us-stat-pill {
  font-size: 10.5px;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text-dim);
}
.us-stat-pill.accent { background: var(--accent-soft); border-color: rgba(107, 123, 255, 0.45); color: var(--accent); }

.us-child-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
}
.us-child-control-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel-2);
}
.us-child-card-head,
.us-child-rule-head {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  align-items: flex-start;
}
.us-child-card-title {
  font-size: 13px;
  font-weight: 700;
  margin: 0;
}
.us-child-rules {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 10px;
}
.us-child-rule {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--panel);
  min-width: 0;
}
.us-child-rule-grid {
  display: grid;
  grid-template-columns: minmax(86px, 0.8fr) repeat(3, minmax(92px, 1fr));
  gap: 8px;
  align-items: end;
}
.us-child-free-days {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.us-child-days {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
.us-child-day {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 24px;
  padding: 2px 7px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  font-size: 10.5px;
  color: var(--text-dim);
  cursor: pointer;
}
.us-child-day input {
  margin: 0;
  accent-color: var(--accent);
}
.us-child-day:has(input:checked) {
  color: var(--accent);
  border-color: rgba(107, 123, 255, 0.45);
  background: var(--accent-soft);
}
.us-child-override {
  display: grid;
  grid-template-columns: minmax(130px, 0.8fr) minmax(180px, 1fr) minmax(220px, auto);
  gap: 8px;
  align-items: end;
}
@media (max-width: 740px) {
  .us-child-rule-grid,
  .us-child-override {
    grid-template-columns: 1fr;
  }
}

/* Themed confirm dialog message styling. */
.us-confirm-message {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
  margin: 0;
}

/* Member details modal — small grid layout that mirrors the web's
 * /team/[id] page. Each field is a label + display/edit control. */
.us-detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
@media (max-width: 520px) {
  .us-detail-grid { grid-template-columns: 1fr; }
}
.us-detail-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.us-detail-field-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-faint);
}
.us-detail-field-value {
  font-size: 12.5px;
  color: var(--text);
  padding: 8px 10px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  border-radius: var(--radius-sm);
  min-height: 20px;
  word-break: break-word;
}
.us-detail-field-value.readonly { color: var(--text-dim); }

/* Member custom-role chips (read-only display on member row). */
.us-custom-role-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10.5px;
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(107, 123, 255, 0.18);
  color: var(--accent);
  border: 1px solid rgba(107, 123, 255, 0.4);
  margin-right: 4px;
}
.us-custom-role-chip button {
  appearance: none;
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
  font-size: 12px;
  padding: 0 2px;
  line-height: 1;
}
.us-custom-role-chip button:hover { color: #ff8a96; }

/* Scrollbar */

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover); }

@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* Custom right-click context menu (replaces the webkit2gtk default,
   which exposed Inspect Element and other dev affordances we don't want
   shipped to users). */
.ctx-menu {
  position: fixed;
  z-index: 1000;
  min-width: 160px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  padding: 4px;
  font-size: 12px;
  user-select: none;
  -webkit-user-select: none;
}
.ctx-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  color: var(--text);
  padding: 6px 10px;
  border-radius: 4px;
  cursor: pointer;
  font-family: inherit;
  font-size: inherit;
}
.ctx-menu-item:hover:not(:disabled) { background: var(--panel-2); }
.ctx-menu-item:disabled {
  color: var(--text-faint);
  cursor: default;
}
.ctx-menu-sep {
  height: 1px;
  background: var(--border);
  margin: 4px 2px;
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.cursor-blink::after {
  content: "▍";
  margin-left: 1px;
  animation: pulse 0.9s ease-in-out infinite;
  color: var(--accent);
}

/* ─────────────────────────────────────────────────────────────────────────
 * Team chat (Discord-style group chat) pane.
 * Lives in the chat-screen-main content slot like extensions/chains/etc.
 * The agent chat pane stays alongside on the side via with-content-pane.
 * Three sub-columns within the pane:
 *   .tc-company-rail  — fixed 56px vertical icon strip (companies + DMs)
 *   .tc-channel-list  — collapsible channel/DM list (-> .tc-channels-collapsed)
 *   .tc-content       — main message surface (header + scroller + composer)
 *   .tc-member-list   — collapsible member list (-> .tc-members-collapsed)
 * ─────────────────────────────────────────────────────────────────────── */

.view-pane-team-chat {
  background: var(--bg);
  overflow: hidden;
}
.tc-body {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: row;
  align-items: stretch;
}

/* Company switcher rail (left). Mirrors GroupRail.tsx in style — round
   icons with active indicator pill on the left edge, vertical list. */
.tc-company-rail {
  flex: 0 0 56px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 10px 0;
  background: var(--panel);
  border-right: 1px solid var(--border);
  overflow-y: auto;
}
.tc-company,
.tc-company-private {
  position: relative;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 12px;
  cursor: pointer;
  background: var(--panel-2);
  color: var(--text-dim);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 0;
  transition: border-radius 0.18s ease, background 0.18s ease, color 0.18s ease;
}
.tc-company:hover,
.tc-company-private:hover {
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
}
.tc-company.is-active,
.tc-company-private.is-active {
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
}
.tc-company.is-active::before,
.tc-company-private.is-active::before {
  content: "";
  position: absolute;
  left: -8px;
  top: 50%;
  transform: translateY(-50%);
  width: 4px;
  height: 28px;
  border-radius: 0 4px 4px 0;
  background: var(--text);
}
.tc-company-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}
.tc-company-initials {
  font-size: 13px;
  font-weight: 600;
}
.tc-company-sep {
  width: 28px;
  height: 2px;
  background: var(--border);
  border-radius: 1px;
  margin: 2px 0;
  flex-shrink: 0;
}
.tc-company-list {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 100%;
}
.tc-company-badge {
  position: absolute;
  right: -2px;
  bottom: -2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: #ef4444;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Channel / DM list (collapsible). */
.tc-channel-list {
  flex: 0 0 220px;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-right: 1px solid var(--border);
  min-width: 0;
}
.tc-channel-header {
  flex: 0 0 auto;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 10px;
  border-bottom: 1px solid var(--border);
  gap: 6px;
}
.tc-channel-header-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-channel-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 6px 4px;
}
.tc-channel-empty {
  padding: 12px 10px;
  color: var(--text-dim);
  font-size: 12px;
  text-align: center;
}
.tc-channel-category {
  padding: 10px 8px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.tc-channel-row {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 5px 8px;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: var(--text-dim);
  font-size: 13px;
  cursor: pointer;
  text-align: left;
}
.tc-channel-row:hover {
  background: var(--panel-2);
  color: var(--text);
}
.tc-channel-row.is-active {
  background: var(--panel-2);
  color: var(--text);
  font-weight: 600;
}
.tc-channel-row.has-unread {
  color: var(--text);
  font-weight: 600;
}
.tc-channel-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
}
.tc-channel-row.is-active .tc-channel-icon,
.tc-channel-row.has-unread .tc-channel-icon {
  color: var(--text);
}
.tc-channel-name {
  flex: 1 1 auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-channel-unread {
  flex-shrink: 0;
  min-width: 18px;
  height: 16px;
  padding: 0 5px;
  background: #ef4444;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tc-channel-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

/* Collapsed-state re-expand strip — same vocabulary the chains pane
   uses for its list (.cn-list-collapsed). Wraps the whole channel list
   so user clicks anywhere to reopen. */
.tc-channels-collapsed .tc-channel-list { display: none; }
.tc-channel-collapsed {
  display: none;
  flex: 0 0 22px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 0;
  background: var(--panel);
  border-right: 1px solid var(--border);
  color: var(--text-dim);
  border: 0;
  cursor: pointer;
}
.tc-channels-collapsed .tc-channel-collapsed { display: flex; }
.tc-channel-collapsed:hover { color: var(--text); background: var(--panel-2); }
.tc-channel-collapsed-label {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Content area (channel header + messages + composer). */
.tc-content {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
}
.tc-content-header {
  flex: 0 0 auto;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  gap: 10px;
}
.tc-content-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-content-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}
.tc-content-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.tc-messages-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 14px 16px;
  position: relative;
}
.tc-messages-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  font-size: 13px;
  text-align: center;
  padding: 20px;
  pointer-events: none;
}
/* The CSS `display: flex` above outranks the user-agent `[hidden] {
   display: none }` rule, so the empty placeholder stayed visible even
   when the message list was populated. Re-assert hidden here so the
   toggle in renderMessages() actually takes effect. */
.tc-messages-empty[hidden] { display: none !important; }
.tc-messages {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.tc-message {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.tc-message-avatar {
  flex: 0 0 36px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--panel-2);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
}
.tc-message.is-agent .tc-message-avatar {
  background: var(--accent);
  color: #fff;
}
.tc-message-main {
  flex: 1 1 auto;
  min-width: 0;
}
.tc-message-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 2px;
}
.tc-message-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.tc-message-ts {
  font-size: 11px;
  color: var(--text-dim);
}
.tc-message-body {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text);
  word-wrap: break-word;
  overflow-wrap: break-word;
}
.tc-message-body p { margin: 0 0 6px; }
.tc-message-body p:last-child { margin-bottom: 0; }

/* Composer. */
.tc-composer {
  position: relative; /* anchor for the absolutely-positioned GIF popover */
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 6px;
  padding: 10px 12px;
  border-top: 1px solid var(--border);
  background: var(--panel);
}
.tc-composer-input {
  flex: 1 1 auto;
  min-height: 36px;
  max-height: 132px;
  resize: none;
  font-family: inherit;
  font-size: 13.5px;
  line-height: 1.4;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  outline: none;
}
.tc-composer-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(107, 123, 255, 0.18);
}
.tc-send-btn {
  flex: 0 0 auto;
  height: 36px;
  min-width: 40px;
  border: 0;
  border-radius: 6px;
  background: var(--accent);
  color: #fff;
  font-size: 16px;
  cursor: pointer;
  padding: 0 10px;
}
.tc-send-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.tc-composer-status {
  padding: 4px 14px 6px;
  font-size: 11px;
  color: var(--text-dim);
  background: var(--panel);
}
.tc-composer-status.is-error { color: #ff8a96; }
.tc-composer-status:empty { display: none; }

/* Typing indicator — a thin line ABOVE the composer, mirroring the
   web's chat-input ("X is typing..."): 11px, muted, gently pulsing,
   only present while someone is actually typing (hidden otherwise so
   it doesn't reserve a permanent blank strip). Send feedback is shown
   via the textarea placeholder instead, so nothing toggles here on a
   normal send and the composer never jumps. */
.tc-typing-indicator {
  padding: 2px 14px;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-dim);
  background: var(--panel);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  animation: tc-typing-pulse 1.6s ease-in-out infinite;
}
.tc-typing-indicator[hidden] { display: none; }
@keyframes tc-typing-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}

/* Member list (collapsible + resizable when open). Width is JS-driven
   via --tc-member-width (persisted to localStorage); mirrors the
   workspace Files sidebar / chat-pane resize idiom. */
.tc-member-list {
  flex: 0 0 var(--tc-member-width, 200px);
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-left: 1px solid var(--border);
  min-width: 0;
}
/* Drag seam between the message surface and the member list. */
.tc-member-resize {
  flex: 0 0 5px;
  cursor: col-resize;
  background: var(--border);
  position: relative;
  z-index: 2;
  user-select: none;
}
.tc-member-resize::before {
  /* Invisible padded hit target so the thin seam is easy to grab. */
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: -4px;
  right: -4px;
}
.tc-member-resize:hover,
.tc-member-resize.is-dragging { background: var(--accent); }
.tc-members-collapsed .tc-member-list,
.tc-members-collapsed .tc-member-resize { display: none; }
/* The seam is a desktop affordance only — on mobile the member list
   is an absolute slide-over drawer (see mobile-portrait rules). */
body.mobile-portrait .view-pane-team-chat .tc-member-resize { display: none; }
.tc-member-header {
  flex: 0 0 auto;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 10px;
  border-bottom: 1px solid var(--border);
}
.tc-member-header-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.tc-member-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 6px 4px;
}
.tc-member-empty {
  padding: 12px 10px;
  color: var(--text-dim);
  font-size: 12px;
  text-align: center;
}
.tc-member-section {
  padding: 10px 8px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.tc-member-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  border-radius: 5px;
}
.tc-member-row:hover { background: var(--panel-2); }
.tc-member-avatar {
  flex: 0 0 28px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--panel-2);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 600;
}
.tc-member-row.is-agent .tc-member-avatar {
  background: var(--accent);
  color: #fff;
}
.tc-member-main {
  flex: 1 1 auto;
  min-width: 0;
}
.tc-member-name {
  font-size: 13px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-member-row.is-agent .tc-member-name { color: var(--accent); }
.tc-member-sub {
  font-size: 10px;
  color: var(--text-dim);
}

/* Shared icon button for tc-* headers. */
.tc-icon-btn {
  background: transparent;
  color: var(--text-dim);
  border: 0;
  width: 26px;
  height: 26px;
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
}
.tc-icon-btn:hover {
  background: var(--panel-2);
  color: var(--text);
}

/* Toast — bottom-center status overlay (success / error) consistent
   with the other pane toasts (.cn-toast, .as-toast, .us-toast). */
.tc-toast {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  padding: 10px 16px;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
  z-index: 50;
}
.tc-toast.is-error {
  background: #4a1f1f;
  color: #ff8a96;
  border-color: #663030;
}

/* ─────────────────────────────────────────────────────────────────────────
 * Team-chat additions: avatars, reply cards, OG previews, attachments,
 * emoji autocomplete, GIF picker, modal dialogs, context menus.
 * Lives below the main team-chat block so it overrides the basic styles
 * where needed.
 * ─────────────────────────────────────────────────────────────── */

/* Composite avatar: <img> stacks on top, initials underneath, swap to
   bot icon for agents. Single positioning context so the gravatar 404
   fallback reveals the initials seamlessly. */
.tc-avatar {
  position: relative;
  flex-shrink: 0;
  border-radius: 50%;
  overflow: hidden;
  background: var(--panel-2);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
  user-select: none;
}
.tc-avatar.is-agent {
  background: var(--accent);
  color: #fff;
}
.tc-avatar-initials {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 0;
}
.tc-avatar-img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Override the placeholder .tc-message-avatar block since we render
   .tc-avatar inside the message wrapper now. */
.tc-message-avatar { display: none; }

/* Channel header: action row sits to the right of the title. */
.tc-channel-header-actions {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}

/* Reply card — appears above the message body when the message is a
   reply. Curved connector line + hover state to suggest the click
   scrolls to the original. */
.tc-reply-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px 4px 18px;
  margin-bottom: 4px;
  background: var(--panel-2);
  border-left: 2px solid var(--accent);
  border-radius: 4px;
  font-size: 12px;
  color: var(--text-dim);
  cursor: pointer;
  max-width: 100%;
  overflow: hidden;
}
.tc-reply-card:hover { background: rgba(107, 123, 255, 0.08); }
.tc-reply-author {
  color: var(--text);
  font-weight: 600;
  flex-shrink: 0;
  white-space: nowrap;
}
.tc-reply-preview {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-dim);
}
.tc-reply-connector { display: none; }
.tc-message-flash {
  animation: tc-message-flash-anim 1.4s ease;
}
@keyframes tc-message-flash-anim {
  0%, 100% { background: transparent; }
  20%, 60% { background: rgba(107, 123, 255, 0.16); }
}

/* OG previews — small inline cards below the message body. */
.tc-og-previews {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* Generic OG card. The web's LinkPreview.tsx flips to flex-column
   the moment there's an image — so a GitHub repo / news article /
   landing page with an og:image gets the big "image on top, text
   below" treatment, not a small thumbnail. Text-only links keep a
   compact horizontal layout. */
.tc-og-card {
  display: flex;
  flex-direction: column;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  text-decoration: none;
  color: var(--text);
  max-width: 520px;
  overflow: hidden;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.tc-og-card:hover {
  background: var(--panel);
  border-color: var(--accent);
}
.tc-og-card-media .tc-og-image,
.tc-og-card-media .tc-og-video {
  display: block;
  width: 100%;
  height: auto;
  max-height: 360px;
  object-fit: contain;
  background: #000;
  border-radius: 3px 3px 0 0;
}
.tc-og-video { background: #000; }
.tc-og-meta {
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.tc-og-site {
  font-size: 11px;
  color: var(--text-dim);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.tc-og-site-icon { display: inline-flex; opacity: 0.7; }
.tc-og-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.tc-og-card:hover .tc-og-title { text-decoration: underline; }
.tc-og-desc {
  font-size: 12.5px;
  color: var(--text-dim);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Twitter / X-specific card — Discord-style rich tweet embed.
   Blue left rail in Twitter's brand color, X logo + site name in the
   header, then author / handle on its own line, the tweet text, and
   the media (image or video) at the bottom. Maps 1:1 to the web's
   LinkPreview.tsx isTwitter branch. */
.tc-og-card-twitter {
  border-left-color: #1d9bf0;
  padding: 8px 12px 10px;
  gap: 0;
}
.tc-og-card-twitter .tc-og-tw-head {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-dim);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  letter-spacing: 0.02em;
}
.tc-og-tw-logo { color: var(--text); display: inline-flex; }
.tc-og-tw-author { margin-top: 4px; }
.tc-og-tw-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
}
.tc-og-card-twitter:hover .tc-og-tw-name { text-decoration: underline; }
.tc-og-tw-handle {
  font-size: 12px;
  color: var(--text-dim);
}
.tc-og-tw-text {
  font-size: 13.5px;
  color: var(--text);
  line-height: 1.4;
  margin-top: 4px;
  white-space: pre-wrap;
  word-wrap: break-word;
}
.tc-og-tw-image,
.tc-og-tw-video {
  display: block;
  width: 100%;
  height: auto;
  max-height: 360px;
  object-fit: cover;
  border-radius: 6px;
  margin-top: 8px;
  background: #000;
}

/* Pinned badge in message head. */
.tc-message-pinned {
  font-size: 11px;
  margin-left: 4px;
}

/* Attachments tray above the composer. */
.tc-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 6px 12px;
  background: var(--panel-2);
  border-top: 1px solid var(--border);
}
.tc-attachments[hidden] { display: none; }
.tc-attach-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 4px 8px;
  font-size: 12px;
  color: var(--text);
  max-width: 200px;
}
.tc-attach-thumb {
  width: 28px;
  height: 28px;
  object-fit: cover;
  border-radius: 3px;
}
.tc-attach-icon { font-size: 16px; }
.tc-attach-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 130px;
}
.tc-attach-remove {
  background: transparent;
  border: 0;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 14px;
  padding: 0;
  line-height: 1;
}
.tc-attach-remove:hover { color: var(--text); }

/* Composer action buttons (paperclip, GIF) — sized to match the existing
   icon buttons in the rest of the chat surface. */
.tc-composer-action {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  margin-top: 2px;
}
.tc-gif-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

/* Reply chip displayed above the composer when a reply is queued. */
.tc-reply-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  background: var(--panel-2);
  border-top: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  font-size: 12px;
}
.tc-reply-chip-label {
  color: var(--text);
  font-weight: 600;
  flex-shrink: 0;
}
.tc-reply-chip-preview {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-dim);
}
.tc-reply-chip-close {
  background: transparent;
  border: 0;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  padding: 0 4px;
}
.tc-reply-chip-close:hover { color: var(--text); }

/* Drop zone visual indicator. */
.tc-messages-scroll.tc-dropzone-active {
  outline: 2px dashed var(--accent);
  outline-offset: -8px;
  background: rgba(107, 123, 255, 0.05);
}

/* Emoji autocomplete popover. */
.tc-emoji-popover {
  position: absolute;
  bottom: 100%;
  left: 8px;
  margin-bottom: 4px;
  width: 240px;
  max-height: 260px;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
  z-index: 30;
}
.tc-emoji-popover[hidden] { display: none; }
.tc-emoji-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 10px;
  border: 0;
  background: transparent;
  color: var(--text);
  font-size: 12px;
  cursor: pointer;
  text-align: left;
}
.tc-emoji-row:hover,
.tc-emoji-row.is-active { background: var(--panel-2); }
.tc-emoji-glyph { font-size: 16px; }
.tc-emoji-code { color: var(--text-dim); }

/* GIF picker popover. */
.tc-gif-popover {
  position: absolute;
  bottom: 100%;
  right: 8px;
  margin-bottom: 4px;
  width: 340px;
  max-height: 380px;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
  padding: 8px;
  z-index: 30;
}
.tc-gif-popover[hidden] { display: none; }
.tc-gif-search {
  flex: 0 0 auto;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 13px;
  padding: 6px 10px;
  border-radius: 4px;
  margin-bottom: 6px;
}
.tc-gif-search:focus {
  border-color: var(--accent);
  outline: none;
}
.tc-gif-grid {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  overflow-y: auto;
  min-height: 200px;
}
.tc-gif-status {
  grid-column: 1 / -1;
  padding: 24px;
  text-align: center;
  color: var(--text-dim);
  font-size: 12px;
}
.tc-gif-cell {
  border: 0;
  background: var(--panel-2);
  cursor: pointer;
  padding: 0;
  overflow: hidden;
  border-radius: 4px;
}
.tc-gif-cell img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.tc-gif-cell:hover { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Context menu (team-chat scoped). Uses the same vocabulary as ctx-menu
   but with distinct class so we can override per-section appearance. */
.tc-ctxmenu {
  position: fixed;
  min-width: 200px;
  max-width: 280px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
  padding: 4px;
  z-index: 200;
}
.tc-ctxmenu[hidden] { display: none; }
.tc-ctxmenu-head {
  padding: 4px 10px 6px;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.tc-ctxmenu-sep {
  height: 1px;
  background: var(--border);
  margin: 4px 2px;
}
.tc-ctxmenu-item {
  display: block;
  width: 100%;
  padding: 6px 10px;
  background: transparent;
  border: 0;
  color: var(--text);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  border-radius: 4px;
  font-family: inherit;
}
.tc-ctxmenu-item:hover:not(.is-disabled) { background: var(--panel-2); }
.tc-ctxmenu-item.is-disabled,
.tc-ctxmenu-item:disabled {
  color: var(--text-faint, var(--text-dim));
  cursor: default;
  opacity: 0.5;
}
.tc-ctxmenu-item.is-danger { color: #ff8a96; }
.tc-ctxmenu-item.is-danger:hover:not(.is-disabled) {
  background: rgba(255, 138, 150, 0.12);
  color: #ff8a96;
}

/* Modal dialog (create/edit channel). */
.tc-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 150;
}
.tc-modal {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
  min-width: 360px;
  max-width: 460px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.tc-modal-header {
  padding: 12px 16px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  border-bottom: 1px solid var(--border);
}
.tc-modal-body {
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.tc-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 10px 16px;
  border-top: 1px solid var(--border);
  background: var(--panel-2);
}
.tc-form-label {
  font-size: 12px;
  color: var(--text-dim);
  margin-top: 6px;
}
.tc-form-input {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 4px;
  padding: 6px 10px;
  font-size: 13px;
  font-family: inherit;
}
.tc-form-input:focus {
  border-color: var(--accent);
  outline: none;
}
.tc-form-check {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  font-size: 13px;
  color: var(--text);
}
.tc-btn {
  padding: 6px 14px;
  border-radius: 4px;
  border: 1px solid transparent;
  font-size: 13px;
  cursor: pointer;
  font-family: inherit;
}
.tc-btn-primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.tc-btn-primary:hover { filter: brightness(1.08); }
.tc-btn-primary:disabled { opacity: 0.6; cursor: not-allowed; }
.tc-btn-secondary {
  background: transparent;
  color: var(--text);
  border-color: var(--border);
}
.tc-btn-secondary:hover { background: var(--panel-2); }

/* ─────────────────────────────────────────────────────────────────────────
 * Round 2 parity additions: active pill, presence dots, role icons,
 * member search, hover toolbar, reactions strip, edit mode, modal tabs.
 * ─────────────────────────────────────────────────────────────── */

/* Active indicator pill on the company rail — Discord-style white bar
   anchored to the left edge of the active server icon, growing on hover. */
.tc-company { position: relative; }
.tc-company-pill {
  position: absolute;
  left: -10px;
  top: 50%;
  transform: translateY(-50%);
  width: 4px;
  height: 0;
  border-radius: 0 4px 4px 0;
  background: var(--text);
  transition: height 200ms ease;
  pointer-events: none;
}
.tc-company.is-active .tc-company-pill { height: 28px; }
.tc-company:hover .tc-company-pill { height: 16px; }
.tc-company.is-active:hover .tc-company-pill { height: 28px; }

/* "Add server" button at the bottom of the rail. */
.tc-company-add {
  background: var(--panel-2);
  color: var(--text-dim);
}
.tc-company-add:hover { background: #10b981; color: #fff; }

/* Channel category — turn it into a button when categories are
   collapsible. */
.tc-channel-category-btn {
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
  padding: 10px 8px 4px;
  background: transparent;
  border: 0;
  color: var(--text-dim);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  text-align: left;
}
.tc-channel-category-btn:hover { color: var(--text); }
.tc-channel-cat-chev {
  flex: 0 0 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tc-channel-cat-label {
  flex: 1 1 auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-channel-cat-unread {
  flex-shrink: 0;
  min-width: 16px;
  height: 14px;
  padding: 0 4px;
  background: #ef4444;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  border-radius: 7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Loading state for the channel list. */
.tc-channel-empty.tc-loading {
  animation: tc-pulse 1.6s ease-in-out infinite;
}
@keyframes tc-pulse { 0%, 100% { opacity: 0.6; } 50% { opacity: 1; } }

/* Bell-off icon for muted channels. */
.tc-channel-muted {
  display: inline-flex;
  margin-left: auto;
  margin-right: 2px;
  color: var(--text-dim);
  opacity: 0.6;
}

/* Threads nested under their parent channel. */
.tc-channel-thread {
  padding-left: 22px;
  font-size: 12px;
}

/* Member-list extras: search bar, presence dots, role icons. */
.tc-member-header-actions {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}
.tc-member-search {
  flex: 0 0 auto;
  padding: 6px 8px 4px;
}
.tc-member-search input {
  width: 100%;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 12px;
  border-radius: 4px;
  padding: 5px 8px;
  outline: none;
}
.tc-member-search input:focus {
  border-color: var(--accent);
}
.tc-member-avatar-wrap {
  position: relative;
  flex: 0 0 28px;
  /* The avatar img inside .tc-avatar carries z-index: 1 (so it stacks
     over the initials fallback). Without an explicit z-index here the
     presence dot — a SIBLING of .tc-avatar — would lose to the avatar
     img in stacking order and disappear behind it. Lift the wrap into
     its own stacking context so the dot can render on top. */
  z-index: 0;
  isolation: isolate;
}
.tc-presence-dot {
  position: absolute;
  bottom: -2px;
  right: -2px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: rgba(140, 145, 160, 0.5);
  border: 2px solid var(--panel);
  box-sizing: content-box;
  z-index: 2;
}
.tc-presence-dot.is-online { background: #10b981; }
.tc-member-name-row {
  display: flex;
  align-items: center;
  gap: 4px;
}
.tc-member-role-icon {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}
.tc-member-name.is-observer {
  color: var(--text-dim);
}
.tc-member-status {
  font-size: 10px;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-style: italic;
}
.tc-member-extra { opacity: 0.85; }

/* Hover toolbar above each message — pinned to the message's top-right,
   only fully visible on hover. */
.tc-message {
  position: relative;
  /* `content-visibility: auto` (set below for scroll perf) silently
     applies PAINT containment to every on-screen row, not just size
     containment for off-screen ones. Paint containment clips anything
     outside this border box, so the hover toolbar must live entirely
     INSIDE the message — no negative `top` / upward transform, or its
     top edge (the reaction buttons) gets sheared off. The toolbar is
     right-aligned and opaque; it floats over the top-right corner on
     hover (Slack/Discord-style) while the header text stays at left,
     so a tight top padding is enough — no big reserved band. */
  padding-top: 6px;
}
.tc-msg-toolbar {
  position: absolute;
  /* Sits fully within the reserved top sliver above — no upward
     transform, so paint containment from content-visibility:auto
     can't clip the reaction buttons at the top. */
  top: 2px;
  right: 8px;
  display: flex;
  align-items: center;
  gap: 1px;
  padding: 2px 4px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s ease;
  z-index: 4;
}
.tc-message:hover .tc-msg-toolbar {
  opacity: 1;
  pointer-events: auto;
}
.tc-msg-toolbar-btn {
  border: 0;
  background: transparent;
  color: var(--text);
  font-size: 14px;
  padding: 4px 6px;
  cursor: pointer;
  border-radius: 4px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tc-msg-toolbar-btn:hover { background: var(--panel-2); }
.tc-msg-toolbar-sep {
  width: 1px;
  height: 16px;
  background: var(--border);
  margin: 0 2px;
}

/* Reactions strip — rendered below the message body. */
.tc-reactions-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 6px;
}
.tc-reaction-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  color: var(--text);
  font-size: 12px;
  cursor: pointer;
}
.tc-reaction-pill:hover { background: var(--panel); border-color: var(--accent); }
.tc-reaction-pill.is-mine {
  background: rgba(107, 123, 255, 0.15);
  border-color: var(--accent);
}
.tc-reaction-emoji { line-height: 1; }
.tc-reaction-count { font-size: 11px; color: var(--text-dim); }

/* Optimistically-rendered message awaiting its server echo — shown
   immediately on send, dimmed slightly until the real record arrives
   and replaces it. Keeps "press send" feeling instant. */
.tc-message.tc-msg-pending { opacity: 0.55; }

/* "(edited)" label */
.tc-message-edited {
  font-size: 10px;
  color: var(--text-dim);
  margin-left: 4px;
  font-style: italic;
}

/* Inline edit mode. */
.tc-edit-wrap {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.tc-edit-textarea {
  width: 100%;
  resize: vertical;
  min-height: 60px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font-family: inherit;
  font-size: 13.5px;
  padding: 8px 10px;
  outline: none;
}
.tc-edit-textarea:focus { border-color: var(--accent); }
.tc-edit-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.tc-edit-hint {
  flex: 1 1 auto;
  font-size: 11px;
  color: var(--text-dim);
}

/* Modal tabbed-picker UI. */
.tc-modal-desc {
  font-size: 12px;
  color: var(--text-dim);
  margin-bottom: 8px;
}
.tc-tabbar {
  display: flex;
  align-items: stretch;
  gap: 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 8px;
}
.tc-tab {
  flex: 1 1 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--text-dim);
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
}
.tc-tab:hover { color: var(--text); }
.tc-tab.is-active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.tc-tab-icon { display: inline-flex; }
.tc-tab-panels {
  max-height: 360px;
  overflow-y: auto;
  margin-top: 4px;
}
.tc-modal-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.tc-modal-list-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  color: var(--text);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: 4px;
}
.tc-modal-list-row:hover { background: var(--panel-2); }
.tc-modal-list-meta { flex: 1 1 auto; min-width: 0; }
.tc-modal-list-name {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-modal-list-sub {
  font-size: 11px;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-modal-list-cta {
  flex: 0 0 auto;
  font-size: 12px;
  color: var(--accent);
  font-weight: 600;
}
.tc-modal-empty {
  padding: 20px;
  text-align: center;
  color: var(--text-dim);
  font-size: 13px;
}

/* ─────────────────────────────────────────────────────────────────────────
 * Round 3 parity additions: spoilers, code-block toolbar, image
 * lightbox, composer syntax overlay, agent-grouped DM list.
 * ─────────────────────────────────────────────────────────────── */

/* Spoiler — body covered until clicked. */
.md-spoiler {
  display: inline-block;
  background: var(--panel-2);
  color: var(--panel-2);
  border-radius: 4px;
  padding: 0 4px;
  cursor: pointer;
  user-select: none;
  transition: background 0.15s ease, color 0.15s ease;
}
.md-spoiler:hover { background: var(--border); }
.md-spoiler .md-spoiler-inner { visibility: hidden; }
.md-spoiler.is-revealed {
  background: var(--panel-2);
  color: var(--text);
  cursor: text;
  user-select: text;
}
.md-spoiler.is-revealed .md-spoiler-inner { visibility: visible; }

/* Fenced code block with a header toolbar. */
.md-codeblock {
  background: var(--code-bg, var(--panel-2));
  border: 1px solid var(--border);
  border-radius: 6px;
  margin: 6px 0;
  overflow: hidden;
}
.md-codeblock-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 8px;
  background: rgba(255, 255, 255, 0.03);
  border-bottom: 1px solid var(--border);
  font-size: 11px;
}
.md-codeblock-lang {
  color: var(--text-dim);
  font-family: var(--mono, monospace);
  text-transform: lowercase;
  letter-spacing: 0.04em;
}
.md-codeblock-actions {
  display: flex;
  align-items: center;
  gap: 2px;
}
.md-codeblock-btn {
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-dim);
  font-size: 11px;
  font-family: inherit;
  padding: 2px 8px;
  border-radius: 4px;
  cursor: pointer;
}
.md-codeblock-btn:hover {
  background: var(--panel);
  color: var(--text);
  border-color: var(--border);
}
.md-codeblock-pre {
  margin: 0;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  border-radius: 0;
  overflow-x: auto;
  font-family: var(--mono, monospace);
  font-size: 12.5px;
  line-height: 1.45;
}
.md-codeblock-pre code {
  background: transparent;
  padding: 0;
  border-radius: 0;
  color: var(--text);
}

/* Click-to-expand image. */
.tc-message-image {
  max-width: 100%;
  max-height: 320px;
  border-radius: 6px;
  display: block;
  margin: 4px 0;
}

/* Image lightbox overlay. */
.tc-lightbox-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.85);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 300;
  cursor: zoom-out;
}
.tc-lightbox-img {
  max-width: 92vw;
  max-height: 92vh;
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.6);
}
.tc-lightbox-close,
.tc-lightbox-dl {
  position: absolute;
  top: 16px;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 22px;
  line-height: 1;
  padding: 0;
}
.tc-lightbox-close { right: 16px; }
.tc-lightbox-dl { right: 60px; }
.tc-lightbox-close:hover,
.tc-lightbox-dl:hover { background: rgba(0, 0, 0, 0.85); }

/* Live composer overlay — sits behind the textarea and carries the
   formatting preview. The textarea is transparent text + visible
   caret so the user sees the styled overlay underneath. */
.tc-composer-input-wrap {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: stretch;
  min-width: 0;
}
.tc-composer-overlay {
  position: absolute;
  inset: 0;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 13.5px;
  line-height: 1.4;
  white-space: pre-wrap;
  word-wrap: break-word;
  overflow-wrap: break-word;
  overflow-y: hidden;
  color: transparent;
  pointer-events: none;
  z-index: 1;
  border: 1px solid transparent;
  border-radius: 6px;
  box-sizing: border-box;
}
.tc-composer-input-wrap .tc-composer-input {
  position: relative;
  z-index: 2;
  background: transparent;
  color: transparent;
  caret-color: var(--text);
  width: 100%;
}
/* Make the textarea text visible too — we COULD keep it transparent
   like Discord and rely on the overlay, but in a webview the overlay
   may not always line up perfectly across font fallbacks. Showing
   both means the text is always readable; the overlay just adds the
   colored markers / weight on top. The overlay's own colors shine
   through where they're solid (mention/code/spoiler chips). */
.tc-composer-input-wrap .tc-composer-input { color: var(--text); }
.tc-composer-overlay .tc-cm-plain { color: transparent; }
.tc-composer-overlay .tc-cm-bold { color: transparent; font-weight: 700; }
.tc-composer-overlay .tc-cm-bold-open { color: var(--text-dim); font-weight: 700; }
.tc-composer-overlay .tc-cm-italic { color: transparent; font-style: italic; }
.tc-composer-overlay .tc-cm-italic-open { color: var(--text-dim); font-style: italic; }
.tc-composer-overlay .tc-cm-underline { color: transparent; text-decoration: underline; }
.tc-composer-overlay .tc-cm-underline-open { color: var(--text-dim); text-decoration: underline; }
.tc-composer-overlay .tc-cm-strike { color: transparent; text-decoration: line-through; }
.tc-composer-overlay .tc-cm-strike-open { color: var(--text-dim); text-decoration: line-through; }
.tc-composer-overlay .tc-cm-code,
.tc-composer-overlay .tc-cm-code-open {
  background: var(--panel);
  color: transparent;
  border-radius: 3px;
  font-family: var(--mono, monospace);
}
.tc-composer-overlay .tc-cm-spoiler,
.tc-composer-overlay .tc-cm-spoiler-open {
  background: var(--text-dim);
  color: transparent;
  border-radius: 3px;
}
.tc-composer-overlay .tc-cm-mention {
  background: rgba(107, 123, 255, 0.18);
  color: transparent;
  border-radius: 3px;
}
/* When the overlay paints a "chip" (code/spoiler/mention) we want the
   underlying textarea text to disappear so we don't get double text.
   Easiest approach: only "chip" spans get visible backgrounds; the
   textarea text on top reads against the chip background. */
.tc-composer-input-wrap .tc-composer-input { caret-color: var(--text); }

/* Agent-grouped DM rows. */
.tc-agent-node {
  display: flex;
  align-items: center;
  gap: 2px;
  width: 100%;
  padding: 5px 6px;
  border-radius: 5px;
  color: var(--text-dim);
}
.tc-agent-node:hover { background: var(--panel-2); color: var(--text); }
.tc-agent-node.is-active {
  background: var(--panel-2);
  color: var(--text);
}
.tc-agent-node.has-unread { color: var(--text); font-weight: 600; }
.tc-agent-chev {
  background: transparent;
  border: 0;
  color: var(--text-dim);
  cursor: pointer;
  padding: 2px 4px;
  border-radius: 3px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 120ms ease;
}
.tc-agent-chev:hover { color: var(--text); }
.tc-agent-chev.is-expanded { transform: rotate(90deg); }
.tc-agent-main {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  border: 0;
  color: inherit;
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  text-align: left;
  padding: 2px;
}
.tc-agent-name {
  flex: 1 1 auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-agent-count {
  font-size: 10px;
  color: var(--text-dim);
  background: var(--panel);
  border-radius: 8px;
  padding: 0 6px;
  flex-shrink: 0;
}
.tc-agent-child {
  padding-left: 26px;
  font-size: 12px;
}

/* ─────────────────────────────────────────────────────────────────────────
 * Round 4 parity additions: mention chips, context-menu reaction row +
 * icons, GIF auto-stop, channel drag-reorder, OG skeleton.
 * ─────────────────────────────────────────────────────────────── */

/* Mention chip — Discord-style accent pill with click + hover state. */
.md-mention {
  display: inline;
  background: rgba(107, 123, 255, 0.22);
  color: var(--text);
  padding: 0 4px;
  border-radius: 3px;
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.12s ease;
}
.md-mention:hover {
  background: rgba(107, 123, 255, 0.38);
}
.md-mention:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.md-mention-agent {
  background: rgba(16, 185, 129, 0.22);
}
.md-mention-agent:hover {
  background: rgba(16, 185, 129, 0.4);
}

/* Context-menu inline reaction row (single horizontal strip). */
.tc-ctxmenu-row {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 2px;
  padding: 4px 6px;
}
.tc-ctxmenu-row-btn {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-radius: 4px;
  font-size: 16px;
  cursor: pointer;
  line-height: 1;
  padding: 0;
}
.tc-ctxmenu-row-btn:hover {
  background: var(--panel-2);
}

/* Context-menu items grow a leading icon slot so they read like the
   web's `<Icon className="mr-2 h-4 w-4" /> Label` layout. */
.tc-ctxmenu-item {
  display: flex;
  align-items: center;
  gap: 8px;
}
.tc-ctxmenu-icon {
  flex: 0 0 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
}
.tc-ctxmenu-item:hover:not(.is-disabled) .tc-ctxmenu-icon {
  color: var(--text);
}
.tc-ctxmenu-item.is-danger .tc-ctxmenu-icon { color: #ff8a96; }
.tc-ctxmenu-label {
  flex: 1 1 auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* GIF auto-stop player. */
.tc-gif-wrap {
  position: relative;
  display: inline-block;
  border-radius: 6px;
  overflow: hidden;
}
.tc-gif-img {
  display: block;
}
.tc-gif-wrap.is-paused-fallback .tc-gif-img {
  filter: brightness(0.55) saturate(0.65);
}
.tc-gif-overlay {
  position: absolute;
  top: 8px;
  left: 8px;
  width: 30px;
  height: 30px;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.75);
  color: #fff;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
}
.tc-gif-wrap:hover .tc-gif-overlay,
.tc-gif-overlay.is-paused {
  display: flex;
}
.tc-gif-wrap::after {
  content: "GIF";
  position: absolute;
  bottom: 6px;
  left: 6px;
  background: rgba(0, 0, 0, 0.7);
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  padding: 1px 5px;
  border-radius: 3px;
  letter-spacing: 0.04em;
  pointer-events: none;
}

/* Channel drag-and-drop indicators. */
.tc-channel-row[draggable="true"] {
  cursor: grab;
}
.tc-channel-row.is-dragging {
  opacity: 0.5;
}
.tc-channel-row.is-drop-above {
  box-shadow: inset 0 2px 0 var(--accent);
}
.tc-channel-row.is-drop-below {
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* OG preview skeleton. */
.tc-og-skel { pointer-events: none; }
.tc-og-skel-img {
  flex: 0 0 80px;
  width: 80px;
  height: 80px;
  background: var(--panel);
  border-radius: 3px;
  animation: tc-skel-pulse 1.4s ease-in-out infinite;
}
.tc-og-skel-bar {
  height: 12px;
  background: var(--panel);
  border-radius: 4px;
  margin: 4px 0;
  animation: tc-skel-pulse 1.4s ease-in-out infinite;
}
.tc-og-skel-bar-sm {
  width: 40%;
  height: 9px;
}
@keyframes tc-skel-pulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}

/* Round 5: scroll-perf isolation + icon-only code-block buttons. */

/* `contain: content` tells the engine that the message is a leaf — its
   layout, paint, and size never affect siblings. Combined with the
   IntersectionObserver-based lazy mount in team-chat.js this keeps
   200-message channels smooth to scroll. content-visibility:auto
   skips paint for off-screen rows entirely; the contain-intrinsic-size
   gives the scroller a stable height estimate so the scrollbar
   doesn't jitter. */
.tc-message {
  /* Layout + style only — `paint` containment would CLIP everything
     outside the message's content box, including the hover toolbar
     that lives at top: -10px above the message. Dropping `paint`
     keeps layout-isolation perf without losing the toolbar.
     content-visibility:auto applies its own paint containment ONLY
     while the row is off-screen, which is exactly what we want. */
  contain: layout style;
  content-visibility: auto;
  contain-intrinsic-size: auto 80px;
}
/* The scroll container can keep strict containment — its children
   (.tc-message) handle their own isolation. */
.tc-messages-scroll {
  contain: strict;
  overflow-anchor: auto;
}

/* Icon-only code-block buttons — match the compact toolbar in
   CodeBlock.tsx (icon, no label). */
.md-codeblock-btn {
  width: 26px;
  height: 22px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.md-codeblock-btn.is-copied {
  background: rgba(16, 185, 129, 0.1);
  border-color: rgba(16, 185, 129, 0.35);
}

/* Round 6: block spoiler, emoji picker popover, thread chip. */

/* Block spoiler — wraps a full block render. Hidden until clicked,
   then content visibility returns to normal so the nested code block
   keeps its toolbar / formatting. */
.md-spoiler-block {
  display: block;
  margin: 6px 0;
  padding: 6px 8px;
  cursor: pointer;
  user-select: none;
  background: var(--panel-2);
  color: transparent; /* hides text content underneath */
  border-radius: 6px;
  border: 1px solid var(--border);
}
.md-spoiler-block .md-spoiler-inner {
  visibility: hidden;
}
.md-spoiler-block.is-revealed {
  color: var(--text);
  cursor: text;
  user-select: text;
}
.md-spoiler-block.is-revealed .md-spoiler-inner { visibility: visible; }
/* When revealed, child code blocks need to "escape" the dimmed
   spoiler background, so the codeblock chrome paints over it cleanly. */
.md-spoiler-block.is-revealed .md-codeblock {
  background: var(--code-bg, var(--panel-2));
  border-color: var(--border);
}

/* Full emoji picker popover. */
.tc-emoji-picker {
  position: fixed;
  width: 320px;
  height: 360px;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.55);
  padding: 8px;
  z-index: 250;
}
.tc-emoji-picker-search {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 4px;
  padding: 6px 10px;
  font-size: 13px;
  margin-bottom: 6px;
  outline: none;
}
.tc-emoji-picker-search:focus { border-color: var(--accent); }
.tc-emoji-picker-grid {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 2px;
  overflow-y: auto;
  align-content: start;
}
.tc-emoji-picker-cell {
  width: 100%;
  aspect-ratio: 1;
  background: transparent;
  border: 0;
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  border-radius: 4px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tc-emoji-picker-cell:hover { background: var(--panel-2); }
.tc-emoji-picker-empty {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--text-dim);
  padding: 24px 12px;
  font-size: 12px;
}

/* Thread chip — small button below a message that opens the thread. */
.tc-thread-chip {
  margin-top: 6px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--accent);
  font-size: 12px;
  cursor: pointer;
  font-family: inherit;
}
.tc-thread-chip:hover {
  background: rgba(107, 123, 255, 0.08);
  border-color: var(--accent);
}
.tc-thread-chip-icon {
  display: inline-flex;
  align-items: center;
  color: var(--accent);
}
.tc-thread-chip-label { color: var(--text); font-weight: 600; }
.tc-thread-chip-ts { color: var(--text-dim); }
.tc-thread-chip-cta { color: var(--accent); margin-left: auto; }

/* Round 7: threads-count badge on the header button + threads panel.
   The earlier OG card variants were folded into the main card block
   above (now image-on-top by default whenever an image is present). */

/* Threads-count badge stamped onto the threads-toggle icon button. */
.tc-icon-btn { position: relative; }
.tc-icon-btn-count {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 14px;
  height: 14px;
  padding: 0 4px;
  border-radius: 7px;
  background: var(--accent);
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
  pointer-events: none;
}

/* Threads panel popover (anchored under the threads-toggle button). */
.tc-threads-panel {
  position: fixed;
  width: 320px;
  max-height: 420px;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.5);
  z-index: 220;
}
.tc-threads-panel-head {
  padding: 8px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  border-bottom: 1px solid var(--border);
}
.tc-threads-panel-scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 4px;
}
.tc-threads-panel-empty {
  padding: 16px;
  text-align: center;
  color: var(--text-dim);
  font-size: 12px;
}
.tc-threads-panel-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 10px;
  background: transparent;
  border: 0;
  color: var(--text);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: 4px;
}
.tc-threads-panel-row:hover { background: var(--panel-2); }
.tc-threads-panel-icon { color: var(--accent); flex: 0 0 14px;
                         display: inline-flex; align-items: center; }
.tc-threads-panel-meta { flex: 1 1 auto; min-width: 0; }
.tc-threads-panel-name {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-threads-panel-sub {
  font-size: 11px;
  color: var(--text-dim);
}

/* Round 11: composer emoji + mic buttons + mic state indicators. */

/* Mic button — three visual states (idle / recording / busy) driven
   by data-state, matching the agent chat's mic styling in the side
   pane so the two feel native to the same app. */
#tc-mic-btn {
  position: relative;
}
#tc-mic-btn .tc-mic-icon-idle,
#tc-mic-btn .tc-mic-icon-recording,
#tc-mic-btn .tc-mic-icon-busy {
  display: none;
  pointer-events: none;
}
#tc-mic-btn[data-state="idle"] .tc-mic-icon-idle { display: inline-block; }
#tc-mic-btn[data-state="recording"] .tc-mic-icon-recording { display: inline-block; }
#tc-mic-btn[data-state="busy"] .tc-mic-icon-busy {
  display: inline-block;
  animation: tc-mic-spin 0.9s linear infinite;
}
#tc-mic-btn[data-state="recording"] {
  background: rgba(239, 68, 68, 0.18);
  color: #ef4444;
}
.tc-mic-icon-recording {
  width: 12px;
  height: 12px;
  border-radius: 2px;
  background: #ef4444;
  animation: tc-mic-pulse 1.1s ease-in-out infinite;
}
@keyframes tc-mic-spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }
@keyframes tc-mic-pulse {
  0%, 100% { opacity: 0.85; transform: scale(1); }
  50%      { opacity: 1; transform: scale(1.15); }
}

/* ------------------------------------------------------------------ */
/* Prompt Guidance bar — vanilla-JS port of the web's                  */
/* ResourceGuidanceCard. Pinned to the bottom of the chat pane,        */
/* between #chat-scroll and .composer, swapping its suggestions to     */
/* match the active content page (see prompt-guidance.js).             */
/* ------------------------------------------------------------------ */
.prompt-guidance {
  flex: 0 0 auto;
  background: var(--panel);
  border-top: 1px solid var(--border);
  padding: 8px 12px 6px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.prompt-guidance[hidden] { display: none; }
.pg-bar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.pg-bar-titlewrap {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.pg-bar-spark { color: var(--accent); font-size: 12px; line-height: 1; }
.pg-bar-title {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pg-bar-toggle {
  flex: 0 0 auto;
  border: none;
  background: transparent;
  color: var(--text-faint);
  font: inherit;
  font-size: 11px;
  cursor: pointer;
  padding: 2px 4px;
  border-radius: var(--radius-sm);
}
.pg-bar-toggle:hover { color: var(--text); background: var(--panel-2); }
.pg-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  /* Show up to two rows of suggestions; anything beyond scrolls
     vertically. `scrollbar-gutter: stable` reserves the scrollbar
     track so it never sits on top of the chips. */
  max-height: calc(2 * 31px + 6px);
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-gutter: stable;
}
.pg-chips::-webkit-scrollbar { width: 6px; }
.pg-chips::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 3px;
}
.prompt-guidance.is-collapsed .pg-chips { display: none; }
.pg-chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 280px;
  padding: 6px 10px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.pg-chip:hover {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--text);
}
.pg-chip-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pg-chip-badge {
  flex: 0 0 auto;
  color: var(--accent);
  font-size: 11px;
  line-height: 1;
}

/* Builder modal — reuses .modal / .modal-card / .modal-header /
   .modal-body / .modal-close / .btn from the shared design system. */
.prompt-guidance-modal .modal-card { max-width: 520px; }
.pg-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pg-field-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
}
.pg-field-desc {
  font-size: 11px;
  color: var(--text-faint);
}
.pg-input {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  padding: 7px 9px;
  width: 100%;
  box-sizing: border-box;
}
.pg-input:focus {
  outline: none;
  border-color: var(--accent);
}
textarea.pg-input { resize: vertical; min-height: 56px; }
.pg-preview {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-dim);
  font-size: 12px;
  line-height: 1.45;
  padding: 8px 10px;
  max-height: 140px;
  overflow-y: auto;
  white-space: pre-wrap;
}
.pg-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: wrap;
}
.pg-actions .btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ─── Even Realities G1 glasses settings ─────────────────────────────────
   Visual language ported from the Flutter mobile app's GlassesSettingsPage:
   a gradient hero card with status chips, an adaptive "Live connection"
   card whose action set changes based on supported/scanning/connected/
   has-saved state, and per-glass battery rows with color-graded fills.

   Anything reused across the user-settings panel keeps its `.us-*` prefix;
   anything specific to the glasses pane uses the `.g1-*` prefix so the
   selectors don't leak into other tabs.
*/
.g1-hero {
  position: relative;
  border-radius: 18px;
  padding: 20px 22px 22px;
  color: #fff;
  overflow: hidden;
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--accent) 92%, #1a1f3a) 0%,
      color-mix(in srgb, var(--accent-2, #9a6cff) 88%, #1a1f3a) 100%);
  box-shadow: 0 8px 24px rgba(20, 22, 50, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.g1-hero::after {
  /* subtle radial highlight, top-right */
  content: "";
  position: absolute;
  inset: -40% -20% auto auto;
  width: 70%;
  aspect-ratio: 1;
  background: radial-gradient(closest-side, rgba(255, 255, 255, 0.18), transparent 70%);
  pointer-events: none;
}
.g1-hero-row {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  position: relative;
  z-index: 1;
}
.g1-hero-icon {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.16);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  line-height: 1;
}
.g1-hero-title-wrap { flex: 1; min-width: 0; }
.g1-hero-title {
  font-size: 17px;
  font-weight: 700;
  margin: 0 0 4px;
  letter-spacing: 0.1px;
}
.g1-hero-sub {
  font-size: 12.5px;
  line-height: 1.45;
  margin: 0;
  color: rgba(255, 255, 255, 0.85);
}
.g1-hero-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
  position: relative;
  z-index: 1;
}
.g1-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.g1-chip-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  display: inline-block;
}
.g1-chip.connected {
  background: rgba(94, 210, 143, 0.32);
  border-color: rgba(94, 210, 143, 0.55);
  color: #d6f4e2;
}
.g1-chip.disconnected {
  background: rgba(255, 138, 150, 0.28);
  border-color: rgba(255, 138, 150, 0.5);
  color: #ffd9de;
}
.g1-chip.scanning {
  background: rgba(229, 184, 106, 0.3);
  border-color: rgba(229, 184, 106, 0.5);
  color: #ffe8c2;
}
.g1-chip-icon { font-size: 13px; line-height: 1; }

/* Status banner inside the "Live connection" card. Colored to match the
   current state so glance-readers can tell at a stride whether the glasses
   are paired without scanning the body copy. */
.g1-status-banner {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 14px 16px;
  border-radius: 14px;
  border: 1px solid var(--border);
  background: var(--panel-2);
}
.g1-status-banner-icon {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  flex: 0 0 auto;
}
.g1-status-banner-text { flex: 1; min-width: 0; }
.g1-status-banner-title {
  font-size: 13px;
  font-weight: 650;
  margin: 0;
  line-height: 1.3;
}
.g1-status-banner-body {
  font-size: 11.5px;
  color: var(--text-dim);
  margin: 3px 0 0;
  line-height: 1.45;
  word-break: break-word;
}
.g1-status-banner.connected {
  border-color: rgba(94, 210, 143, 0.45);
  background: rgba(94, 210, 143, 0.10);
}
.g1-status-banner.connected .g1-status-banner-icon {
  background: rgba(94, 210, 143, 0.22);
  color: #5dd28f;
}
.g1-status-banner.connected .g1-status-banner-title { color: #5dd28f; }
.g1-status-banner.disconnected .g1-status-banner-icon {
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-dim);
}
.g1-status-banner.scanning {
  border-color: rgba(229, 184, 106, 0.4);
  background: rgba(229, 184, 106, 0.08);
}
.g1-status-banner.scanning .g1-status-banner-icon {
  background: rgba(229, 184, 106, 0.2);
  color: #e5b86a;
}
.g1-status-banner.scanning .g1-status-banner-title { color: #e5b86a; }
.g1-status-banner.error {
  border-color: rgba(255, 138, 150, 0.45);
  background: rgba(255, 138, 150, 0.08);
}
.g1-status-banner.error .g1-status-banner-icon {
  background: rgba(255, 138, 150, 0.22);
  color: #ff8a96;
}
.g1-status-banner.error .g1-status-banner-title { color: #ff8a96; }

.g1-spinner {
  width: 16px;
  height: 16px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: g1-spin 0.85s linear infinite;
  display: inline-block;
}
@keyframes g1-spin { to { transform: rotate(360deg); } }

/* Action row under the status banner. The set of buttons rendered is state-
   dependent — see `renderGlassesActions()` in user-settings.js. */
.g1-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.g1-actions.center { justify-content: center; }
.g1-actions .btn { flex: 0 0 auto; }
.g1-actions .btn.full { flex: 1 1 100%; }

/* Per-glass battery row, shown only when connected. The bar's fill width
   is set inline; its color tier comes from .level-* classes mirroring
   the mobile app's _getBatteryColor() thresholds. */
.g1-batt-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
@media (max-width: 520px) {
  .g1-batt-grid { grid-template-columns: 1fr; }
}
.g1-batt {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.g1-batt-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.g1-batt-label {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-dim);
}
.g1-batt-pct {
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
}
.g1-batt-meta {
  font-size: 11px;
  color: var(--text-faint);
  min-height: 14px;
}
.g1-batt-bar {
  width: 100%;
  height: 6px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 3px;
  overflow: hidden;
}
.g1-batt-bar-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.3s ease, background-color 0.3s ease;
}
.g1-batt.level-excellent .g1-batt-pct,
.g1-batt.level-excellent .g1-batt-bar-fill { color: #5dd28f; background-color: #5dd28f; }
.g1-batt.level-good .g1-batt-pct,
.g1-batt.level-good .g1-batt-bar-fill { color: #66bb6a; background-color: #66bb6a; }
.g1-batt.level-fair .g1-batt-pct,
.g1-batt.level-fair .g1-batt-bar-fill { color: #6b9eff; background-color: #6b9eff; }
.g1-batt.level-low .g1-batt-pct,
.g1-batt.level-low .g1-batt-bar-fill { color: #ffb774; background-color: #ffb774; }
.g1-batt.level-critical .g1-batt-pct,
.g1-batt.level-critical .g1-batt-bar-fill { color: #ff8a96; background-color: #ff8a96; }
/* The fill width comes from inline style; color is set via .level-* above
   on the parent so both percentage text and bar share the tier color. */

/* Focus & presence toggle row. Uses a custom switch since the desktop
   side has no shared toggle component — the existing .us-check is a
   plain checkbox, which doesn't read as a presence affordance. */
.g1-toggle-row {
  display: flex;
  align-items: center;
  gap: 16px;
  justify-content: space-between;
}
.g1-toggle-text { flex: 1; min-width: 0; }
.g1-toggle-title {
  font-size: 13px;
  font-weight: 600;
  margin: 0 0 3px;
}
.g1-toggle-sub {
  font-size: 11.5px;
  color: var(--text-dim);
  margin: 0;
  line-height: 1.45;
}
.g1-switch {
  position: relative;
  width: 42px;
  height: 24px;
  flex: 0 0 auto;
  cursor: pointer;
  display: inline-block;
}
.g1-switch input {
  appearance: none;
  -webkit-appearance: none;
  position: absolute;
  inset: 0;
  margin: 0;
  cursor: pointer;
  opacity: 0;
  width: 100%;
  height: 100%;
}
.g1-switch-track {
  position: absolute;
  inset: 0;
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.g1-switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  background: var(--text);
  border-radius: 50%;
  transition: transform 0.18s ease, background 0.18s ease;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}
.g1-switch input:checked ~ .g1-switch-track {
  background: var(--accent);
  border-color: var(--accent);
}
.g1-switch input:checked ~ .g1-switch-thumb {
  transform: translateX(18px);
  background: #fff;
}
.g1-switch input:focus-visible ~ .g1-switch-track {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Inline callout note used inside cards (e.g. silent-mode explainer). */
.g1-note {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 14px;
  font-size: 11.5px;
  color: var(--text-dim);
  line-height: 1.5;
}

/* ─── Super Admin tab ─────────────────────────────────────────────── */

/* Stats grid replaces the small `.us-stat-pill` inline chips with
   tile-sized cards for the dashboard at the top of the tab. */
.us-panel[data-us-panel="superadmin"] .us-stat-pills {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
}
.us-panel[data-us-panel="superadmin"] .us-stat-pill {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 8px);
  color: var(--text);
  text-align: left;
}
.us-stat-pill-value {
  font-size: 22px;
  font-weight: 600;
  color: var(--text);
}
.us-stat-pill-label {
  font-size: 11px;
  color: var(--text-dim);
}

/* A list row that contains a header row + collapsible user list. */
.us-list-item-wrap {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.us-list-item-wrap:last-child {
  border-bottom: 0;
}
