/*
 * antchat chat UI stylesheet — hand-written, no Tailwind/node build.
 *
 * Look & feel target a familiar ChatGPT / LibreChat experience for users
 * migrating off the LibreChat-based deployment: a quiet sidebar of past
 * conversations, a centred reading column of message turns (assistant = plain
 * full-width text with an avatar; user = a right-aligned rounded bubble), and a
 * floating rounded composer pinned at the bottom.
 *
 * Theming: a light palette is the default; dark is applied automatically from
 * the OS via `prefers-color-scheme`, and a header toggle can pin either theme
 * (persisted in localStorage, read by the inline bootstrap in layout.templ).
 * Both modes are pure CSS-variable swaps — every rule below reads the tokens,
 * none hard-code a colour.
 *
 * Design tokens are CSS custom properties adapted from LibreChat's Tailwind
 * theme (color/spacing scale, layout structure) under its MIT license; see
 * /NOTICE. No LibreChat CSS, components, or brand assets are copied — only the
 * token values and the sidebar/chat-pane layout pattern. EU residency
 * (DECISIONS §11): this file is vendored and served from the binary; no CDN.
 */

/* ============================================================= *
 *  Design tokens — light (default)                              *
 * ============================================================= */
:root {
  /* surfaces */
  --c-bg: #ffffff;               /* chat pane background           */
  --c-surface: #ffffff;          /* cards, composer, top bar       */
  --c-surface-alt: #f4f4f5;      /* subtle panels / system bubbles */
  --c-sidebar: #f9f9f9;          /* conversation rail              */
  --c-sidebar-fg: #2d2d35;
  --c-sidebar-muted: #8e8ea0;
  --c-sidebar-hover: #ececec;
  --c-sidebar-active: #e4e4e7;

  /* message surfaces */
  --c-assistant-bg: transparent; /* assistant = plain reading text */
  --c-user-bubble: #f4f4f5;      /* user bubble fill               */
  --c-user-bubble-fg: #18181b;

  /* avatars */
  --c-avatar-assistant: #10a37f; /* ChatGPT-ish teal               */
  --c-avatar-user: #5436da;      /* indigo                         */
  --c-avatar-fg: #ffffff;

  /* text */
  --c-text: #0d0d12;
  --c-text-muted: #6e6e80;

  /* accent / state */
  --c-accent: #10a37f;
  --c-accent-hover: #0e9070;
  --c-accent-fg: #ffffff;
  --c-border: #e5e5e8;
  --c-border-strong: #d4d4d8;
  --c-danger: #ef4146;
  --c-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
  --c-shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.12);

  /* conversation flag palette (shared light/dark — vivid enough for both) */
  --flag-red: #e5484d;
  --flag-orange: #f5a623;
  --flag-yellow: #f2c200;
  --flag-green: #30a46c;
  --flag-blue: #3b82f6;
  --flag-purple: #8b5cf6;

  /* spacing scale */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.25rem;
  --sp-6: 1.5rem;
  --sp-8: 2rem;

  /* radius + type + layout */
  --radius: 0.75rem;
  --radius-sm: 0.5rem;
  --radius-pill: 1.5rem;
  --fs-sm: 0.8125rem;
  --fs-base: 0.9375rem;
  --fs-lg: 1.125rem;
  --fs-xl: 1.375rem;
  --sidebar-w: 16rem;
  --content-w: 56rem;
}

/* ============================================================= *
 *  Dark palette — auto via OS, unless a light override is pinned *
 * ============================================================= */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --c-bg: #212121;
    --c-surface: #2f2f2f;
    --c-surface-alt: #343541;
    --c-sidebar: #171717;
    --c-sidebar-fg: #ececf1;
    --c-sidebar-muted: #8e8ea0;
    --c-sidebar-hover: #262626;
    --c-sidebar-active: #2f2f2f;

    --c-assistant-bg: transparent;
    --c-user-bubble: #2f2f2f;
    --c-user-bubble-fg: #ececf1;

    --c-avatar-assistant: #10a37f;
    --c-avatar-user: #7b5cff;
    --c-avatar-fg: #ffffff;

    --c-text: #ececf1;
    --c-text-muted: #b4b4c0;

    --c-accent: #10a37f;
    --c-accent-hover: #1abe93;
    --c-accent-fg: #ffffff;
    --c-border: #3a3a3a;
    --c-border-strong: #4a4a4a;
    --c-danger: #ff6b6f;
    --c-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
    --c-shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.5);
  }
}

/* Dark pinned explicitly (header toggle), regardless of OS preference. */
:root[data-theme="dark"] {
  --c-bg: #212121;
  --c-surface: #2f2f2f;
  --c-surface-alt: #343541;
  --c-sidebar: #171717;
  --c-sidebar-fg: #ececf1;
  --c-sidebar-muted: #8e8ea0;
  --c-sidebar-hover: #262626;
  --c-sidebar-active: #2f2f2f;

  --c-assistant-bg: transparent;
  --c-user-bubble: #2f2f2f;
  --c-user-bubble-fg: #ececf1;

  --c-avatar-assistant: #10a37f;
  --c-avatar-user: #7b5cff;
  --c-avatar-fg: #ffffff;

  --c-text: #ececf1;
  --c-text-muted: #b4b4c0;

  --c-accent: #10a37f;
  --c-accent-hover: #1abe93;
  --c-accent-fg: #ffffff;
  --c-border: #3a3a3a;
  --c-border-strong: #4a4a4a;
  --c-danger: #ff6b6f;
  --c-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
  --c-shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.5);
}

/* ============================================================= *
 *  Base                                                          *
 * ============================================================= */
* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  font-family: "Söhne", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: var(--fs-base);
  line-height: 1.55;
  color: var(--c-text);
  background: var(--c-bg);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--c-accent); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--c-border-strong); border-radius: 6px; }
::-webkit-scrollbar-thumb:hover { background: var(--c-text-muted); }
::-webkit-scrollbar-track { background: transparent; }

/* ---- app shell: fixed sidebar + flexible main column ---- */
.app-shell { display: flex; height: 100vh; overflow: hidden; }

/* Drag handle between the rail and the main column: a thin invisible strip
 * (widened hit area) sitting on the sidebar's border, col-resize cursor. The
 * width itself is driven by --sidebar-w, written to localStorage by ui.js. */
.sidebar-resizer {
  flex: 0 0 auto;
  width: 6px;
  margin-left: -3px;
  cursor: col-resize;
  background: transparent;
  position: relative;
  z-index: 5;
  transition: background 0.12s ease;
}
.sidebar-resizer:hover,
.sidebar-resizer:focus-visible,
.sidebar-resizer[data-dragging="true"] { background: var(--c-avatar-user); outline: none; }

/* Backdrop + hamburger are inert until the narrow-screen media query below. */
.nav-backdrop { display: none; }
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  margin-right: var(--sp-2);
  border: 1px solid var(--c-border);
  border-radius: 0.5rem;
  background: var(--c-surface);
  color: var(--c-text);
  font-size: var(--fs-lg);
  line-height: 1;
  cursor: pointer;
}
.nav-toggle:hover { background: var(--c-surface-alt); }

/* ============================================================= *
 *  Sidebar                                                       *
 * ============================================================= */
.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--c-sidebar);
  color: var(--c-sidebar-fg);
  border-right: 1px solid var(--c-border);
  display: flex;
  flex-direction: column;
  padding: var(--sp-3);
  overflow: hidden;
}
.sidebar-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2) var(--sp-3);
}
.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex: 1 1 auto;
  min-width: 0;
  color: var(--c-sidebar-fg);
  font-weight: 700;
  font-size: var(--fs-lg);
  letter-spacing: -0.01em;
  text-decoration: none;
}
.brand-logo {
  width: 1.5rem;
  height: 1.5rem;
  flex: none;
  object-fit: contain;
}
/* antconvert launcher (top-left, antchat-new#65): a compact icon button next to
   the brand. Muted until hovered, matching the sidebar's quiet chrome. */
.brand-tool {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--radius-sm, 6px);
  color: var(--c-sidebar-fg-muted, var(--c-sidebar-fg));
  font-size: var(--fs-lg);
  line-height: 1;
  text-decoration: none;
  opacity: 0.75;
}
.brand-tool:hover {
  background: var(--c-sidebar-hover, rgba(127, 127, 127, 0.15));
  opacity: 1;
}

.conv-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow-y: auto;
  flex: 1 1 auto;
  margin-top: var(--sp-2);
}
.conv-empty {
  color: var(--c-sidebar-muted);
  font-size: var(--fs-sm);
  padding: var(--sp-3) var(--sp-2);
}
.conv-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  color: var(--c-sidebar-fg);
  transition: background 0.12s ease;
}
.conv-item:hover { background: var(--c-sidebar-hover); }
.conv-item-active { background: var(--c-sidebar-active); }
.conv-item-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}
.conv-item-title {
  font-size: var(--fs-sm);
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.conv-item-agent {
  font-size: 0.6875rem;
  color: var(--c-sidebar-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Per-row agent avatar (issue #49). Mirrors the picker card placeholder: a
   small circular image, or the teal→indigo gradient when the agent has no
   avatar bytes (or a non-conforming URI). object-fit keeps PNGs square. */
.conv-item-avatar {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  object-fit: cover;
}
.conv-item-avatar-empty {
  background: linear-gradient(135deg, var(--c-avatar-assistant), var(--c-avatar-user));
}
img.conv-item-avatar { background: var(--c-surface); }

/* Per-row colour-flag dot (transparent until a flag is set). */
.conv-flag {
  flex: none;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
}
.conv-flag-none { box-shadow: inset 0 0 0 1px var(--c-border-strong); opacity: 0.45; }
.conv-flag-red { background: var(--flag-red); }
.conv-flag-orange { background: var(--flag-orange); }
.conv-flag-yellow { background: var(--flag-yellow); }
.conv-flag-green { background: var(--flag-green); }
.conv-flag-blue { background: var(--flag-blue); }
.conv-flag-purple { background: var(--flag-purple); }

/* "⋯" per-row actions trigger (revealed on hover/focus-within). */
.conv-actions-btn {
  flex: none;
  border: none;
  background: transparent;
  color: var(--c-sidebar-muted);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 2px 4px;
  border-radius: var(--radius-sm);
  opacity: 0;
  transition: opacity 0.12s ease, background 0.12s ease;
}
.conv-item:hover .conv-actions-btn,
.conv-item:focus-within .conv-actions-btn { opacity: 1; }
.conv-actions-btn:hover { background: var(--c-sidebar-active); color: var(--c-sidebar-fg); }

/* Pinned / Ostatní group headers in the list. */
.conv-group-label {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--c-sidebar-muted);
  padding: var(--sp-3) var(--sp-2) var(--sp-1);
}

/* Eshop-style facet filter bar above the conversation list. */
.conv-filter {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-1);
  margin-top: var(--sp-2);
  border-bottom: 1px solid var(--c-border);
}
.filter-flags { display: flex; align-items: center; gap: var(--sp-1); }
/* Flag chips are radios (single-select + active highlight are native CSS): the
   <label> is the click target, the input is visually hidden, the swatch is the
   coloured dot (the .conv-flag-* class provides its fill / the "Vše" outline). */
.filter-flag { display: inline-flex; cursor: pointer; line-height: 0; }
.filter-flag-input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.filter-flag-swatch {
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  border: 2px solid transparent;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
}
.filter-flag-input:checked + .filter-flag-swatch { border-color: var(--c-sidebar-fg); }
.filter-flag-input:focus-visible + .filter-flag-swatch {
  outline: 2px solid var(--c-accent);
  outline-offset: 1px;
}
.filter-agent {
  flex: 1 1 6rem;
  min-width: 0;
  font-size: var(--fs-sm);
  padding: 4px 6px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--c-border);
  background: var(--c-surface);
  color: var(--c-text);
}

/* "Spravovat štítky" trigger — a small icon button after the colour chips that
 * opens the tag-management modal (issue #46). */
.filter-tags {
  width: 1.25rem;
  height: 1.25rem;
  margin-left: var(--sp-1);
  padding: 0;
  border: none;
  background: transparent;
  color: var(--c-sidebar-muted);
  cursor: pointer;
  font-size: var(--fs-sm);
  line-height: 1;
}
.filter-tags:hover { color: var(--c-sidebar-fg); }

/* Tag-management modal: a centred overlay listing the colour flags with a text
 * field each, so the user can name a colour (issue #46). Hidden until ui.js
 * shows it. */
.tag-modal[hidden] { display: none; }
.tag-modal {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
}
.tag-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
}
.tag-modal-panel {
  position: relative;
  width: min(28rem, calc(100vw - 2rem));
  max-height: calc(100vh - 4rem);
  overflow-y: auto;
  padding: var(--sp-5);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
  color: var(--c-text);
  box-shadow: var(--c-shadow-lg);
}
.tag-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}
.tag-modal-title { margin: 0; font-size: var(--fs-lg); }
.tag-modal-close {
  border: none;
  background: transparent;
  color: var(--c-text-muted);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 var(--sp-1);
}
.tag-modal-close:hover { color: var(--c-text); }
.tag-modal-sub { margin: var(--sp-2) 0 var(--sp-4); color: var(--c-text-muted); font-size: var(--fs-sm); }
.tag-modal-rows { display: flex; flex-direction: column; gap: var(--sp-3); }
.tag-row { display: flex; align-items: center; gap: var(--sp-3); }
.tag-row .conv-flag { flex: none; width: 0.875rem; height: 0.875rem; }
.tag-row-input {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-base);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: var(--c-text);
}
.tag-row-input:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }

/* Floating per-conversation actions menu (pin + flag), one per row; ui.js opens
   and positions it (position:fixed, to escape the scrolled list's clipping). */
.conv-actions-menu[hidden] { display: none; } /* class display:flex would override the UA [hidden] rule */
.conv-actions-menu {
  position: fixed;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 9rem;
  padding: var(--sp-2);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--c-shadow-lg);
}
.conv-action {
  border: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
  font-size: var(--fs-sm);
  color: var(--c-text);
  padding: var(--sp-2);
  border-radius: var(--radius-sm);
}
.conv-action:hover { background: var(--c-surface-alt); }
.conv-action-flags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  padding: var(--sp-2);
}
.conv-action-flag {
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  border: 2px solid transparent;
  padding: 0;
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
}
.conv-action-flag-active { border-color: var(--c-text); }

/* ============================================================= *
 *  Main column + top bar                                         *
 * ============================================================= */
.main-col { flex: 1 1 auto; display: flex; flex-direction: column; min-width: 0; }

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  background: color-mix(in srgb, var(--c-bg) 85%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--c-border);
}
.topbar-tenant { display: flex; align-items: baseline; gap: var(--sp-2); min-width: 0; }
.topbar-tenant-label { font-size: var(--fs-sm); color: var(--c-text-muted); }
.topbar-tenant-value { font-weight: 600; }
.topbar-actions { display: flex; align-items: center; gap: var(--sp-3); }
.topbar-switch {
  font-size: var(--fs-sm);
  color: var(--c-accent);
  text-decoration: none;
}
.topbar-switch:hover { text-decoration: underline; }

/* theme toggle: a single icon that swaps with the active theme */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--c-border);
  border-radius: 999px;
  background: var(--c-surface);
  color: var(--c-text);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.theme-toggle:hover { background: var(--c-surface-alt); border-color: var(--c-border-strong); }
.theme-toggle .ico-dark { display: none; }
.theme-toggle .ico-light { display: inline; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .ico-light { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .ico-dark { display: inline; }
}
:root[data-theme="dark"] .theme-toggle .ico-light { display: none; }
:root[data-theme="dark"] .theme-toggle .ico-dark { display: inline; }
:root[data-theme="light"] .theme-toggle .ico-light { display: inline; }
:root[data-theme="light"] .theme-toggle .ico-dark { display: none; }

/* ============================================================= *
 *  Chat pane                                                     *
 * ============================================================= */
.chat-main { flex: 1 1 auto; min-height: 0; display: flex; }
.chat { flex: 1 1 auto; display: flex; flex-direction: column; min-width: 0; position: relative; }

/* floating scroll-to-bottom chip: shown while auto-scroll is paused */
.scroll-to-bottom {
  position: absolute;
  bottom: 5.5rem; /* above the composer */
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  background: var(--c-accent);
  color: var(--c-accent-fg);
  border: none;
  border-radius: 1.5rem;
  padding: 0.375rem 0.875rem;
  font-size: var(--fs-sm);
  line-height: 1.4;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  white-space: nowrap;
}
.scroll-to-bottom:hover { filter: brightness(1.1); }
.scroll-to-bottom[hidden] { display: none; }

/* large hero naming the active assistant (LibreChat-style), first item in the
   scroll column so a new conversation reads as a clear greeting */
.chat-title {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-8) 0 var(--sp-4);
  text-align: center;
}
.chat-title-avatar {
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  flex: none;
  object-fit: cover;
  background: linear-gradient(135deg, var(--c-avatar-assistant), var(--c-avatar-user));
  box-shadow: var(--c-shadow);
}
/* Real avatar bytes: drop the placeholder gradient so it never bleeds through a
   transparent PNG margin behind the image (same fix as the card avatar). */
img.chat-title-avatar { background: var(--c-surface); }
.chat-title-name { margin: 0; font-size: 1.75rem; font-weight: 700; letter-spacing: -0.01em; }

/* shared button look (new-chat, send, login, picker) */
.newconv-btn, .login-btn, .picker-option {
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--c-accent);
  color: var(--c-accent-fg);
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease;
}
.newconv-btn:hover, .login-btn:hover, .picker-option:hover { background: var(--c-accent-hover); }

/* sidebar New-chat is a link to the home assistant picker */
.newconv-link {
  display: block;
  margin: 0 var(--sp-2) var(--sp-3);
  width: calc(100% - 2 * var(--sp-2));
  text-align: center;
  text-decoration: none;
}

/* sidebar "Procházet agenty": a secondary (un-filled) link below New-chat that
 * opens the read-only agent catalog (/agents, issue #35). */
.browse-link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  margin: calc(-1 * var(--sp-1)) var(--sp-2) var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-pill);
  color: var(--c-sidebar-fg);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: none;
  transition: background 0.12s ease;
}
.browse-link:hover { background: var(--c-sidebar-hover); }
.browse-link-ico { font-size: 1.05rem; line-height: 1; }
/* Folder icon in the sidebar archive link: render as monochrome to match the
   text-only look of the other browse-links (Agents uses ⌕, Archive uses 📁). */
.browse-link-archive .browse-link-ico { filter: grayscale(1); }

/* new-chat landing: assistant picker (the defining choice in antchat) */
.newchat {
  flex: 1 1 auto;
  overflow-y: auto;
  /* Full-width scroll container so the scrollbar sits at the page's right edge,
   * not beside the centred column (matches .chat-history). The picker content
   * stays centred via symmetric horizontal padding that collapses to a small
   * gutter on narrow screens — NOT via max-width + margin:auto, which would make
   * the narrow column itself the scroller and park the scrollbar in the middle. */
  scrollbar-gutter: stable;
  display: flex;
  flex-direction: column;
  /* stretch (not center) so a category with a single agent left-aligns its card
   * instead of centring it; the head keeps its own centred alignment below. */
  align-items: stretch;
  gap: var(--sp-6);
  width: 100%;
  padding: var(--sp-8) max(var(--sp-4), calc((100% - var(--content-w)) / 2));
}
.newchat-head { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); text-align: center; }
/* New-chat hero before an assistant is chosen: the Datamero ant (transparent,
   adapts to the page bg). Once an assistant is picked the conversation hero
   (.chat-title-avatar) carries the assistant's own image — task #49. */
.newchat-logo { width: 5rem; height: 5rem; flex: none; object-fit: contain; }
.newchat-title { margin: 0; font-size: 1.75rem; font-weight: 700; letter-spacing: -0.01em; }
.newchat-sub { margin: 0; color: var(--c-text-muted); }

.agent-category { width: 100%; display: flex; flex-direction: column; gap: var(--sp-3); }

/* Category groups read as separate via a hairline divider between consecutive
 * groups (issue #44) — just a leading line, no box, so the agent cards keep
 * their own contrast against the page. Scoped to [data-category] so the
 * headerless flat-grid fallback (no categories) gets no stray line. */
.agent-category[data-category] + .agent-category[data-category] {
  border-top: 1px solid var(--c-border);
  padding-top: var(--sp-4);
}

/* The always-expanded "frequently used" shortcut row above the collapsible
 * categories: same grid as a category, a plain (non-clickable) heading. */
.agent-frequent { width: 100%; display: flex; flex-direction: column; gap: var(--sp-3); }
.agent-frequent-name,
.agent-category-name {
  font-size: 1.05rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--c-text-muted);
}
/* Bolder category label so each group header reads as a clear section title
 * (issue #44) — weight only, same size. */
.agent-category-name { font-weight: 700; color: var(--c-text); }
.agent-frequent-name { margin: var(--sp-2) 0; }

/* Collapsible category header: a full-width button toggling the grid below it.
 * Default-collapsed; picker.js restores the per-browser expanded set and flips
 * aria-expanded + the body's [hidden]. */
.agent-category-toggle {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  margin: var(--sp-2) 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  text-align: left;
}
.agent-category-toggle .agent-category-name { margin: 0; }
/* A caret that points right when collapsed and rotates down when expanded. */
.agent-category-caret {
  flex: none;
  width: 0;
  height: 0;
  border-top: 0.3rem solid transparent;
  border-bottom: 0.3rem solid transparent;
  border-left: 0.4rem solid var(--c-text-muted);
  transition: transform 0.12s ease;
}
.agent-category-toggle[aria-expanded="true"] .agent-category-caret { transform: rotate(90deg); }
.agent-category-count {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--c-text-muted);
  text-transform: none;
  letter-spacing: 0;
}
/* A class selector (.agent-grid) would otherwise win over the UA [hidden] rule
 * and keep the collapsed grid visible — re-assert display:none explicitly. */
.agent-grid[hidden] { display: none; }

.agent-grid {
  display: grid;
  /* two columns at the reading width (half the content each), collapsing to one
   * on a narrow viewport (media query below). */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* The avatar badge overflows each card by 1.5rem up and left, so the gaps must
   * clear it: the row gap (>1.5rem) keeps a lower row's avatar off the card
   * above; the column gap (>1.5rem) keeps the right column's left-overflowing
   * avatar out of the left card. Both are larger than before for more vertical
   * breathing room between agents. */
  gap: 2.75rem 2rem;
  /* room at the top/left edges so the first row's and the left column's
   * overflowing avatars are not clipped by the category header or the page. */
  padding: 1.75rem 0 0 1.75rem;
  width: 100%;
}
.agent-card {
  position: relative;
  display: block;
  width: 100%;
  text-align: left;
  /* The avatar is a large badge overflowing the top-left corner (below): the
   * left padding clears the part of it that dips back into the card so the name
   * never sits under it; the top padding drops the text to the avatar's middle.
   * The right padding clears the pin toggle (top-right: right 0.5rem + width
   * 1.75rem ≈ 2.25rem) so a long name's first line never runs under it (antchat#28). */
  padding: var(--sp-4) 2.6rem var(--sp-4) 2.85rem;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
  color: var(--c-text);
  cursor: pointer;
  text-decoration: none;
  overflow: visible;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.agent-card:hover { border-color: var(--c-border-strong); box-shadow: var(--c-shadow); }
/* A large avatar badge overflowing the card's top-left corner (the "overlay"
   look): more than half of it sits outside the card rectangle, the rest dips in
   over the top-left. The surface-coloured ring makes it read as floating onto
   the page/gutter. The gradient is the empty-state placeholder; the <img>
   variant clears it (img rule below) so a transparent avatar margin shows the
   surface, not the gradient. object-fit: cover crops the normalized ~8% margin. */
.agent-card-avatar {
  position: absolute;
  top: -1.5rem;
  left: -1.5rem;
  width: 4rem;
  height: 4rem;
  border-radius: 50%;
  object-fit: cover;
  background: linear-gradient(135deg, var(--c-avatar-assistant), var(--c-avatar-user));
  box-shadow: 0 0 0 3px var(--c-surface);
}
/* Real avatar bytes: drop the placeholder gradient so it never bleeds through a
   transparent PNG margin behind the image (it would otherwise show under it). */
img.agent-card-avatar { background: var(--c-surface); }
.agent-card-body { display: flex; flex-direction: column; gap: 4px; width: 100%; min-width: 0; }
/* Wrap a long agent name (or a long unbroken token) instead of letting it
 * overflow the card — the card is overflow:visible, so without this a long name
 * spills past the edge and is clipped/overlaps the neighbouring column (antchat#28). */
.agent-card-name { font-weight: 600; overflow-wrap: anywhere; }
.agent-card-desc {
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  /* clamp long descriptions to three lines with an ellipsis so a verbose agent
   * cannot blow the card up to an enormous height. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Per-user agent pin (issue #35). The wrapper is the grid child now (the card +
 * its corner pin toggle); it must keep overflow visible so the card's avatar
 * badge can still dip outside the top-left corner. */
.agent-card-wrap { position: relative; width: 100%; }
/* The pin toggle sits in the card's top-right corner (the avatar overflows the
 * top-LEFT, so they never collide). Always visible for discoverability and
 * keyboard/Playwright reach; muted when unpinned, accent-filled when pinned. */
.agent-pin {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--c-text-muted);
  cursor: pointer;
  opacity: 0.65;
  transition: opacity 0.12s ease, color 0.12s ease, background-color 0.12s ease, border-color 0.12s ease;
}
.agent-pin:hover,
.agent-pin:focus-visible {
  opacity: 1;
  color: var(--c-text);
  background: var(--c-surface);
  border-color: var(--c-border-strong);
  outline: none;
}
.agent-pin.is-pinned {
  color: var(--c-accent);
  opacity: 1;
}
.agent-pin.is-pinned:hover,
.agent-pin.is-pinned:focus-visible {
  color: var(--c-accent-hover);
}
.agent-pin-icon { display: block; }

/* scrolling message history, centred reading column */
.chat-history {
  flex: 1 1 auto;
  overflow-y: auto;
  /* full-width scroll container so the scrollbar sits at the page's right edge,
     not beside the centred column; messages stay centred via symmetric padding
     that collapses to a small gutter on narrow screens. */
  scrollbar-gutter: stable;
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
  width: 100%;
  padding: var(--sp-6) max(var(--sp-4), calc((100% - var(--content-w)) / 2)) var(--sp-8);
}

/* ---- messages: assistant = plain text + avatar; user = right bubble ---- */
.bubble {
  display: flex;
  flex-direction: column;
  max-width: 100%;
  border: 0;
  background: var(--c-assistant-bg);
  padding: 0;
}
.bubble-user { align-items: flex-end; }
.bubble-assistant, .bubble-system, .bubble-tool { align-items: stretch; }

/* role line = avatar + the author's display name (assistant / user name,
   server-rendered into the element text and matched by the SSE stream) */
.bubble-role {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--c-text);
}
.bubble-role::before {
  content: "";
  width: 2rem;
  height: 2rem;
  flex: none;
  border-radius: 50%;
  background: var(--c-avatar-assistant);
}
.bubble-user .bubble-role { flex-direction: row-reverse; }
.bubble-user .bubble-role::before { background: var(--c-avatar-user); }
/* assistant avatar uses the brand gradient unless --agent-avatar is set on the
   bubble (by the template for reloaded messages, or by sse.js for live streams),
   in which case it shows the real agent image. */
.bubble-assistant .bubble-role::before {
  background-color: transparent;
  background-image: var(--agent-avatar, linear-gradient(135deg, var(--c-avatar-assistant), var(--c-avatar-user)));
  background-size: cover;
  background-position: center;
}
.bubble-system .bubble-role::before { background: var(--c-text-muted); }
.bubble-tool .bubble-role::before { background: var(--c-text-muted); }

.bubble-body {
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.6;
  color: var(--c-text);
}
/* assistant body aligns under the avatar; a little inset reads as a thread */
.bubble-assistant .bubble-body,
.bubble-assistant .bubble-tools,
.bubble-assistant .bubble-thinking,
.bubble-assistant .bubble-typing,
.bubble-assistant .bubble-artifacts { padding-left: calc(2rem + var(--sp-2)); }

/* the assistant answer is rendered markdown (block elements), not raw text */
.bubble-assistant .bubble-body { white-space: normal; }

/* user content is a compact rounded bubble on the right */
.bubble-user .bubble-body {
  background: var(--c-user-bubble);
  color: var(--c-user-bubble-fg);
  border-radius: var(--radius-pill);
  padding: var(--sp-3) var(--sp-4);
  max-width: 85%;
}

.bubble-system .bubble-body, .bubble-tool .bubble-body {
  background: var(--c-surface-alt);
  border-radius: var(--radius);
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-sm);
}

.bubble-tools { margin-top: var(--sp-2); display: flex; flex-direction: column; gap: var(--sp-1); }
.tool-status { font-size: var(--fs-sm); color: var(--c-text-muted); font-style: italic; }
.bubble-artifacts { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); }
.artifact-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  align-self: flex-start;
  color: var(--c-text);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: none;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  transition: border-color 0.12s ease;
}
.artifact-link::before { content: "📄"; }
.artifact-link:hover { border-color: var(--c-border-strong); }

/* conversation-level artifact panel (reload path): the generated-file links a
   live turn streamed into its bubble, re-rendered once at the end of history */
.conversation-artifacts { margin-top: var(--sp-5); padding-left: calc(2rem + var(--sp-2)); }
.conversation-artifacts-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--c-text-muted);
  margin-bottom: var(--sp-2);
}
.run-error { color: var(--c-danger); font-size: var(--fs-sm); margin-top: var(--sp-2); }

/* ---- typing indicator (animated dots, GPT-style) ---- */
.bubble-typing { display: flex; gap: 0.3rem; align-items: center; padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
.bubble-typing[hidden] { display: none; }
.bubble-typing span {
  width: 0.45rem; height: 0.45rem; border-radius: 50%;
  background: var(--c-text-muted); opacity: 0.4;
  animation: antchat-blink 1.2s infinite ease-in-out both;
}
.bubble-typing span:nth-child(2) { animation-delay: 0.2s; }
.bubble-typing span:nth-child(3) { animation-delay: 0.4s; }
@keyframes antchat-blink { 0%, 80%, 100% { opacity: 0.25; transform: scale(0.85); } 40% { opacity: 0.9; transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .bubble-typing span { animation: none; opacity: 0.6; } }

/* ---- collapsible reasoning ("thinking") block ---- */
.bubble-thinking { margin-top: var(--sp-1); margin-bottom: var(--sp-1); }
.bubble-thinking[hidden] { display: none; }
.bubble-thinking-summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm); color: var(--c-text-muted);
  padding: var(--sp-1) 0; user-select: none;
}
.bubble-thinking-summary::-webkit-details-marker { display: none; }
.bubble-thinking-summary::before {
  content: "▸"; display: inline-block; transition: transform 0.12s ease; font-size: 0.7em;
}
.bubble-thinking[open] .bubble-thinking-summary::before { transform: rotate(90deg); }
.bubble-thinking-body {
  margin-top: var(--sp-1);
  border-left: 2px solid var(--c-border-strong);
  padding: var(--sp-1) 0 var(--sp-1) var(--sp-3);
  font-size: var(--fs-sm); color: var(--c-text-muted); line-height: 1.55;
}
/* While the model is actively reasoning, the body is a fixed-height "flow"
   window (like ChatGPT/Claude): the latest lines stream through and auto-scroll
   inside it, older lines fade out at the top — so a long chain-of-thought never
   floods the page and the user can still reach the composer. Once thinking ends
   the cap is dropped (class removed), so re-opening the block shows it in full. */
.bubble-thinking.is-streaming .bubble-thinking-body {
  max-height: 7.5em;
  overflow-y: auto;
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 1.75em);
  mask-image: linear-gradient(to bottom, transparent 0, #000 1.75em);
}
.bubble-thinking.is-streaming .bubble-thinking-body::-webkit-scrollbar { display: none; }

/* ---- collapsible tool-call rows ---- */
.bubble-tool { font-size: var(--fs-sm); }
.bubble-tool-summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  color: var(--c-text-muted); padding: var(--sp-1) 0; user-select: none;
}
.bubble-tool-summary::-webkit-details-marker { display: none; }
.bubble-tool-summary::before { content: "🔧"; font-size: 0.85em; }
.bubble-tool-body {
  margin-top: var(--sp-1); margin-left: var(--sp-3);
  border-left: 2px solid var(--c-border); padding-left: var(--sp-3);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8em; color: var(--c-text-muted); white-space: pre-wrap; word-break: break-word;
}
.bubble-tool-result { margin-top: var(--sp-1); color: var(--c-text); font-family: inherit; }

/* ---- markdown inside the assistant answer ---- */
.bubble-assistant .bubble-body > :first-child { margin-top: 0; }
.bubble-assistant .bubble-body > :last-child { margin-bottom: 0; }
.bubble-assistant .bubble-body p { margin: 0 0 var(--sp-3); line-height: 1.6; }
.bubble-assistant .bubble-body ul,
.bubble-assistant .bubble-body ol { margin: 0 0 var(--sp-3); padding-left: var(--sp-6); }
.bubble-assistant .bubble-body li { margin: var(--sp-1) 0; line-height: 1.55; }
.bubble-assistant .bubble-body h1,
.bubble-assistant .bubble-body h2,
.bubble-assistant .bubble-body h3,
.bubble-assistant .bubble-body h4 { margin: var(--sp-4) 0 var(--sp-2); line-height: 1.3; font-weight: 600; }
.bubble-assistant .bubble-body h1 { font-size: var(--fs-lg); }
.bubble-assistant .bubble-body h2 { font-size: var(--fs-base); }
.bubble-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.875em; background: var(--c-surface-alt);
  padding: 0.1em 0.35em; border-radius: var(--radius-sm);
}
.bubble-body .md-pre {
  background: var(--c-surface-alt); border: 1px solid var(--c-border);
  border-radius: var(--radius-sm); padding: var(--sp-3);
  overflow-x: auto; margin: 0 0 var(--sp-3);
}
.bubble-body .md-pre code { background: none; padding: 0; font-size: 0.85em; }
.bubble-body a { color: var(--c-accent); text-decoration: underline; }

/* ============================================================= *
 *  Markdown extras — code badge/copy, syntax tokens, tables,    *
 *  blockquotes (issues #116 #117 #118 #125). Shared by the      *
 *  assistant answer (.bubble-body) and the archive preview      *
 *  drawer (.preview-bubble-text), so selectors are container-   *
 *  agnostic where the markup is identical.                      *
 * ============================================================= */

/* Syntax-highlight token palette — theme-aware, derived from the
   existing colour tokens so it tracks the light/dark toggle. */
:root {
  --tok-keyword: #8250df;
  --tok-string: #0a7d33;
  --tok-number: #b35900;
  --tok-comment: #6e7781;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --tok-keyword: #c792ea;
    --tok-string: #7ee787;
    --tok-number: #ffab70;
    --tok-comment: #8b949e;
  }
}
:root[data-theme="dark"] {
  --tok-keyword: #c792ea;
  --tok-string: #7ee787;
  --tok-number: #ffab70;
  --tok-comment: #8b949e;
}

/* The <pre> becomes a positioning context for the language badge and the
   copy button; extra top padding leaves room for them. */
.md-pre { position: relative; padding-top: var(--sp-5); }
.md-pre .tok-keyword { color: var(--tok-keyword); }
.md-pre .tok-string { color: var(--tok-string); }
.md-pre .tok-number { color: var(--tok-number); }
.md-pre .tok-comment { color: var(--tok-comment); font-style: italic; }

/* Language badge (#117): rendered from data-lang via CSS so no markup is
   injected; sits in the top-left, uppercased and muted. */
.md-pre[data-lang]::before {
  content: attr(data-lang);
  position: absolute;
  top: var(--sp-1); left: var(--sp-3);
  font-size: 0.65rem; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--c-text-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  pointer-events: none;
}

/* Copy button (#116): top-right, subtle until hover/focus. */
.md-copy {
  position: absolute;
  top: var(--sp-1); right: var(--sp-2);
  padding: 0.1em 0.5em;
  font-size: 0.7rem; line-height: 1.5;
  color: var(--c-text-muted);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 0.12s ease, color 0.12s ease;
}
.md-pre:hover .md-copy,
.md-copy:focus-visible { opacity: 1; }
.md-copy:hover { color: var(--c-text); border-color: var(--c-border-strong); }
.md-copy.is-copied { color: var(--c-accent); border-color: var(--c-accent); opacity: 1; }

/* Tables (#118): bordered, padded, theme-aware, horizontal scroll on overflow. */
.md-table-wrap { overflow-x: auto; margin: 0 0 var(--sp-3); }
.md-table {
  border-collapse: collapse;
  width: auto; max-width: 100%;
  font-size: 0.9em;
}
.md-table th, .md-table td {
  border: 1px solid var(--c-border);
  padding: var(--sp-1) var(--sp-3);
  text-align: left; vertical-align: top;
}
.md-table th { background: var(--c-surface-alt); font-weight: 600; }
.md-table tbody tr:nth-child(even) td { background: var(--c-surface-alt); }

/* Blockquote (#125): left rule + muted indented text. */
.md-blockquote {
  margin: 0 0 var(--sp-3);
  padding: var(--sp-1) var(--sp-4);
  border-left: 3px solid var(--c-border-strong);
  color: var(--c-text-muted);
}
.md-blockquote > :first-child { margin-top: 0; }
.md-blockquote > :last-child { margin-bottom: 0; }

/* Strikethrough (#126) inherits the default <del> styling; no rule needed. */

/* ============================================================= *
 *  Composer — floating rounded box, ChatGPT-style                *
 * ============================================================= */
.composer-wrap {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  width: min(var(--content-w), 100% - 2rem);
  margin: 0 auto var(--sp-6);
}
.composer {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
  width: 100%;
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-2);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--c-shadow);
}
.composer:focus-within { border-color: var(--c-border-strong); box-shadow: var(--c-shadow-lg); }

/* Attach (paperclip) button — mirrors the send button geometry but stays
 * surface-toned so it reads as secondary. */
.composer-attach {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--c-text-muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s ease, color 0.12s ease;
}
.composer-attach::after { content: "+"; font-size: 1.5rem; font-weight: 400; line-height: 1; }
.composer-attach:hover { background: var(--c-surface-sunken, rgba(0,0,0,0.05)); color: var(--c-text); }

/* Pending-attachment chips, shown above the composer pill before send. */
.composer-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: 0 var(--sp-2);
}
.composer-attachments[hidden] { display: none; }
.composer-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  max-width: 18rem;
  padding: var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-3);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm);
  color: var(--c-text);
}
.composer-chip.is-uploading { opacity: 0.6; }
.composer-chip.is-failed { border-color: var(--c-danger); color: var(--c-danger); }
.composer-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.composer-chip-remove {
  flex: none;
  border: 0;
  background: transparent;
  color: var(--c-text-muted);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 0 0.15rem;
}
.composer-chip-remove:hover { color: var(--c-text); }

/* Attachment line on a sent user bubble. */
.bubble-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}
.bubble-attachment {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm);
}
.composer-input {
  flex: 1 1 auto;
  resize: none;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--c-text);
  font: inherit;
  line-height: 1.5;
  padding: var(--sp-2) 0;
  max-height: 12rem;
}
.composer-input::placeholder { color: var(--c-text-muted); }
.composer-send {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--c-accent);
  color: var(--c-accent-fg);
  font-size: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s ease;
}
.composer-send::after { content: "↑"; font-size: 1.15rem; font-weight: 700; line-height: 1; }
.composer-send:hover { background: var(--c-accent-hover); }
.composer-send[hidden] { display: none; }
.composer-send:disabled { opacity: 0.5; cursor: default; }
.composer-input:disabled { opacity: 0.6; cursor: default; }

/* Stop button (#112): replaces the send button while a turn streams. Danger-
 * toned with a square glyph so it reads unambiguously as "stop". */
.composer-stop {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--c-danger);
  color: #fff;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s ease;
}
.composer-stop::after { content: "■"; font-size: 0.85rem; line-height: 1; }
.composer-stop:hover { filter: brightness(0.92); }
.composer-stop[hidden] { display: none; }

/* Per-message footer (#124/#120/#143): a relative timestamp and, on assistant
 * bubbles, the copy + regenerate icon actions. */
.bubble-foot {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  margin-top: var(--sp-1);
}
.bubble-foot .bubble-time { margin-right: var(--sp-2); }
.bubble-user .bubble-foot { justify-content: flex-end; }
.bubble-time { font-size: var(--fs-sm); color: var(--c-text-muted); }
.bubble-time:empty { display: none; }

/* Footer action icons (GPT-style, #143/#120): borderless ghost icon buttons that
 * sit quietly under each answer and brighten on bubble hover / focus. The glyph
 * is an inline stroke SVG inheriting currentColor. */
.bubble-act {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--c-text-muted);
  border-radius: var(--radius-sm);
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 0.12s ease, background 0.12s ease, color 0.12s ease;
}
.bubble-act svg { width: 1rem; height: 1rem; display: block; }
.bubble:hover .bubble-act,
.bubble-act:focus-visible { opacity: 1; }
.bubble-act:hover { background: var(--c-surface-sunken, rgba(0,0,0,0.05)); color: var(--c-text); }
.bubble-copy.is-copied { color: var(--c-accent); opacity: 1; }

/* Inline message editor (edit-and-resubmit, #152): a textarea + Odeslat/Zrušit
 * that replaces a user bubble's body while editing. Themed vars only, so it is
 * legible in both light and dark. */
.bubble-edit-form { display: flex; flex-direction: column; gap: var(--sp-2); width: min(40rem, 100%); }
.bubble-edit-input {
  width: 100%;
  min-height: 3rem;
  resize: vertical;
  padding: var(--sp-2) var(--sp-3);
  font: inherit;
  color: var(--c-text);
  background: var(--c-surface);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
}
.bubble-edit-input:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }
.bubble-edit-actions { display: flex; gap: var(--sp-2); justify-content: flex-end; }
.bubble-edit-save,
.bubble-edit-cancel {
  padding: var(--sp-1) var(--sp-3);
  font: inherit;
  border-radius: var(--radius-sm);
  cursor: pointer;
  border: 1px solid var(--c-border-strong);
}
.bubble-edit-save { background: var(--c-accent); color: var(--c-accent-fg); border-color: var(--c-accent); }
.bubble-edit-save:hover { background: var(--c-accent-hover); border-color: var(--c-accent-hover); }
.bubble-edit-cancel { background: var(--c-surface); color: var(--c-text); }
.bubble-edit-cancel:hover { background: var(--c-surface-sunken, rgba(0,0,0,0.05)); }

/* Copy is shown on every assistant bubble (any past answer is copyable).
 * Regenerate is rendered on every assistant bubble but only revealed on the most
 * recent one, so the user only ever regenerates the latest answer (#120). The
 * "last assistant" bubble is marked explicitly (.bubble-assistant-last, stamped
 * server-side and moved by sse.js on a streamed finish) rather than via
 * :last-of-type, which mis-targets when a trailing non-assistant element (the
 * conversation-artifacts panel, a tool/system bubble) follows the last answer. */
.bubble-regen { display: none; }
.bubble-assistant-last .bubble-regen { display: inline-flex; }

/* Tool-result truncation toggle (#130). */
.tool-result-toggle {
  display: block;
  margin-top: var(--sp-1);
  border: 0;
  background: transparent;
  color: var(--c-accent);
  font-size: var(--fs-sm);
  cursor: pointer;
  padding: 0;
}
.tool-result-toggle:hover { text-decoration: underline; }

/* Budget-error billing link (#131): an actionable link inside the RUN_ERROR
 * banner. Inherits the danger tone but stays clearly a link. */
.run-error-link { color: var(--c-danger); font-weight: 600; text-decoration: underline; }

/* ============================================================= *
 *  Bare shell (login / picker)                                   *
 * ============================================================= */
.bare-shell {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-6);
}
.bare-theme-toggle { position: absolute; top: var(--sp-5); right: var(--sp-5); }
.login-card, .picker-card {
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--c-shadow-lg);
  padding: var(--sp-8);
  text-align: center;
  width: 22rem;
}
.login-title, .picker-title { margin: 0 0 var(--sp-2); font-size: var(--fs-xl); letter-spacing: -0.01em; }
.login-sub, .picker-sub { color: var(--c-text-muted); font-size: var(--fs-sm); margin: 0 0 var(--sp-6); }
.login-btn { display: inline-block; text-decoration: none; padding: var(--sp-3) var(--sp-6); font-size: var(--fs-base); }
.picker-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.picker-form { margin: 0; }
.picker-option {
  width: 100%;
  background: var(--c-surface);
  color: var(--c-text);
  border: 1px solid var(--c-border);
  padding: var(--sp-3) var(--sp-4);
}
.picker-option:hover { background: var(--c-surface-alt); border-color: var(--c-border-strong); }
.picker-option-active { border-color: var(--c-accent); outline: 1px solid var(--c-accent); }

/* ============================================================= *
 *  Sidebar profile menu (bottom) — CSS-only <details> popup      *
 * ============================================================= */
.profile {
  position: relative;
  margin-top: auto;            /* pin to the bottom of the sidebar */
  border-top: 1px solid var(--c-border);
  padding-top: var(--sp-2);
}
.profile-trigger {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  list-style: none;            /* hide the default disclosure triangle */
  color: var(--c-sidebar-fg);
}
.profile-trigger::-webkit-details-marker { display: none; }
.profile-trigger:hover { background: var(--c-sidebar-hover); }
.profile-avatar {
  width: 1.75rem;
  height: 1.75rem;
  flex: none;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--c-avatar-user), var(--c-avatar-assistant));
}
.profile-name {
  flex: 1 1 auto;
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.profile-caret { color: var(--c-sidebar-muted); font-size: var(--fs-sm); }
.profile[open] .profile-caret { transform: rotate(180deg); }

.profile-menu {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + var(--sp-1));
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--c-shadow-lg);
  padding: var(--sp-2);
  display: flex;
  flex-direction: column;
  gap: 2px;
  z-index: 20;
}
.profile-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-2) var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--c-border);
  margin-bottom: var(--sp-1);
}
.profile-meta-label { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--c-text-muted); }
.profile-meta-value { font-size: var(--fs-sm); color: var(--c-text); word-break: break-word; }
.profile-badge {
  align-self: flex-start;
  margin-top: var(--sp-1);
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--c-accent);
  background: color-mix(in srgb, var(--c-accent) 14%, transparent);
  padding: 1px var(--sp-2);
  border-radius: 999px;
}
.profile-logout { margin: 0; }
.profile-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--sp-2) var(--sp-2);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--c-text);
  font: inherit;
  font-size: var(--fs-sm);
  text-decoration: none;
  cursor: pointer;
}
.profile-item:hover { background: var(--c-surface-alt); }
.profile-item-danger { color: var(--c-danger); }

/* ============================================================= *
 *  Responsive — collapse the rail on narrow screens              *
 * ============================================================= */
@media (max-width: 48rem) {
  /* The rail collapses; a "☰" toggle re-opens it as a fixed overlay over a
   * dismissable backdrop (click-away or Escape closes it; navigation reloads
   * the page, which resets the state). The drag resizer is meaningless here. */
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: min(20rem, 85vw);
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    z-index: 40;
    box-shadow: 0 0 2rem rgba(0, 0, 0, 0.3);
  }
  .app-shell.nav-open .sidebar { transform: translateX(0); }
  .app-shell.nav-open .nav-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 30;
  }
  .sidebar-resizer { display: none; }
  .nav-toggle { display: inline-flex; }
  .chat-history { padding-inline: var(--sp-3); }
  /* the two-column agent picker is too tight on a phone; stack to one column. */
  .agent-grid { grid-template-columns: 1fr; }
}

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

/* --- embedded antbill billing widget (ADR-0020) -----------------------------
   The billingui island (.antbill-billingui) reads generic host tokens
   (--bg/--fg/--muted/--border/--accent) with its own fallbacks. Alias antchat's
   palette onto them on the widget root so the embedded card matches the active
   theme (light/dark) without billingui knowing antchat's variable names. */
.billing-page {
  max-width: 48rem;
  margin: 0 auto;
  padding: var(--sp-6) var(--sp-4);
}
.billing-title {
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--c-text);
  margin: 0 0 var(--sp-5);
}
.antbill-billingui {
  --bg: var(--c-surface);
  --fg: var(--c-text);
  --muted: var(--c-text-muted);
  --border: var(--c-border);
  --accent: var(--c-accent);
}

/* --- embedded antconvert convert widget (ADR-0021) --------------------------
   The convertui island (.antconvert-convertui) reads the same generic host
   tokens (--bg/--fg/--muted/--border/--accent) with its own fallbacks. Alias
   antchat's palette onto them on the widget root so the embedded card matches
   the active theme (light/dark) — without this the widget's fallbacks render it
   white. Mirrors the .antbill-billingui block above. */
.antconvert-convertui {
  --bg: var(--c-surface);
  --fg: var(--c-text);
  --muted: var(--c-text-muted);
  --border: var(--c-border);
  --accent: var(--c-accent);
}
.billing-notice {
  border: 1px solid var(--c-border);
  border-radius: 0.5rem;
  background: var(--c-surface-alt);
  color: var(--c-text-muted);
  padding: var(--sp-6);
  text-align: center;
}
.billing-relogin {
  display: inline-block;
  margin-top: var(--sp-4);
  padding: var(--sp-2) var(--sp-4);
  border-radius: 0.5rem;
  background: var(--c-accent);
  color: var(--c-accent-fg);
  text-decoration: none;
}
.billing-relogin:hover { background: var(--c-accent-hover); }

/* ── Archive page ────────────────────────────────────────────────────────── */
.archive-page { padding: var(--sp-8); max-width: 64rem; }
.archive-head { margin-bottom: var(--sp-6); }
.archive-title { font-size: 1.25rem; font-weight: 600; margin-bottom: var(--sp-2); }
.archive-sub { color: var(--c-text-muted); font-size: 0.875rem; }
.archive-list { display: flex; flex-direction: column; gap: var(--sp-2); }
.archived-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--c-border);
  border-radius: 0.5rem;
  background: var(--c-surface);
}
.archived-item-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  text-decoration: none;
  color: inherit;
  cursor: pointer;
}
.archived-item-body:hover .archived-item-title { color: var(--c-accent); }
.archived-item-title {
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Date row: smaller, muted, italic to visually separate from the title */
.archived-item-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  font-size: 0.75rem;
  font-style: italic;
  color: var(--c-text-muted);
}
/* Deletion date gets an amber warning tone */
.archived-item-deletes {
  color: #b45309;
  font-style: italic;
}
:root[data-theme="dark"] .archived-item-deletes { color: #fbbf24; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .archived-item-deletes { color: #fbbf24; }
}
.archived-item-actions { display: flex; gap: var(--sp-2); flex-shrink: 0; }
.archived-action {
  padding: var(--sp-1) var(--sp-3);
  border-radius: 0.375rem;
  border: 1px solid var(--c-border);
  background: transparent;
  color: var(--c-text-muted);
  font-size: 0.8125rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.archived-action:hover { background: var(--c-surface-alt); color: var(--c-text); }
.archived-action-restore:hover { border-color: var(--c-accent); color: var(--c-accent); }
.archived-action-delete:hover { border-color: #ef4444; color: #ef4444; }

/* ── Conversation preview drawer ─────────────────────────────────────────── */
/* The drawer is shown/hidden purely via CSS: when #conv-preview is non-empty
   it slides in; when its innerHTML is cleared (close button / scrim click)
   it slides back out. No JS event-listeners needed beyond the inline onclick. */
.conv-preview {
  position: fixed;
  top: 0;
  right: 0;
  height: 100vh;
  width: min(520px, 100vw);
  background: var(--c-surface);
  border-left: 1px solid var(--c-border);
  box-shadow: -4px 0 32px rgba(0,0,0,0.12);
  transform: translateX(100%);
  transition: transform 0.25s ease;
  z-index: 300;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
#conv-preview:not(:empty) { transform: translateX(0); }

.conv-preview-scrim {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.25);
  z-index: 299;
  cursor: default;
}
#conv-preview:not(:empty) ~ .conv-preview-scrim { display: block; }

.preview-head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--c-border);
  flex-shrink: 0;
}
.preview-title-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.preview-title { font-weight: 600; font-size: 1rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.preview-agent { font-size: 0.75rem; color: var(--c-text-muted); }
.preview-close {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 0.375rem;
  border: none;
  background: transparent;
  color: var(--c-text-muted);
  font-size: 1.1rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.preview-close:hover { background: var(--c-surface-alt); color: var(--c-text); }

.preview-messages {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-4) var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.preview-empty { color: var(--c-text-muted); font-size: 0.875rem; }
.preview-bubble { display: flex; flex-direction: column; gap: var(--sp-1); }
.preview-bubble--user { align-items: flex-end; }
.preview-bubble--assistant { align-items: flex-start; }
.preview-bubble-author { font-size: 0.7rem; font-weight: 600; color: var(--c-text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
.preview-bubble-text {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.55;
  max-width: 88%;
  white-space: pre-wrap;
  word-break: break-word;
}
.preview-bubble--user .preview-bubble-text {
  background: var(--c-user-bubble);
  color: var(--c-user-bubble-fg);
  padding: var(--sp-2) var(--sp-3);
  border-radius: 1rem 1rem 0.25rem 1rem;
}
.preview-bubble--assistant .preview-bubble-text {
  background: transparent;
  color: var(--c-text);
}
/* Markdown re-rendered client-side inside the assistant preview bubble (#114):
   the drawer is not .bubble-body, so give the same block styling the chat pane
   has. The container-agnostic .md-* rules (badge, copy, table, blockquote) above
   already apply; these add the pieces that were .bubble-body-scoped. */
.preview-bubble--assistant .preview-bubble-text { white-space: normal; }
.preview-bubble--assistant .preview-bubble-text p { margin: 0 0 var(--sp-2); }
.preview-bubble--assistant .preview-bubble-text > :first-child { margin-top: 0; }
.preview-bubble--assistant .preview-bubble-text > :last-child { margin-bottom: 0; }
.preview-bubble--assistant .preview-bubble-text ul,
.preview-bubble--assistant .preview-bubble-text ol { margin: 0 0 var(--sp-2); padding-left: var(--sp-6); }
.preview-bubble--assistant .preview-bubble-text code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em; background: var(--c-surface-alt);
  padding: 0.1em 0.35em; border-radius: var(--radius-sm);
}
.preview-bubble--assistant .preview-bubble-text .md-pre {
  background: var(--c-surface-alt); border: 1px solid var(--c-border);
  border-radius: var(--radius-sm); padding: var(--sp-3) var(--sp-3) var(--sp-3);
  padding-top: var(--sp-5); overflow-x: auto; margin: 0 0 var(--sp-2);
}
.preview-bubble--assistant .preview-bubble-text .md-pre code {
  background: none; padding: 0;
}
.preview-bubble--assistant .preview-bubble-text a { color: var(--c-accent); text-decoration: underline; }

/* ============================================================= *
 *  Sidebar search (antchat-new#129)                             *
 * ============================================================= */
/* Full-text search box at the top of the facet bar; styled to sit in the
 * sidebar rail and match the tag-row inputs. */
.conv-search {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-sm);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: var(--c-text);
}
.conv-search::placeholder { color: var(--c-sidebar-muted); }
.conv-search:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }

/* ============================================================= *
 *  Sidebar pagination — "Načíst více" (antchat-new#122)         *
 * ============================================================= */
.conv-load-more {
  display: block;
  width: calc(100% - 2 * var(--sp-2));
  margin: var(--sp-2);
  padding: var(--sp-2);
  font-size: var(--fs-sm);
  text-align: center;
  cursor: pointer;
  color: var(--c-sidebar-fg);
  background: transparent;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
}
.conv-load-more:hover { background: var(--c-sidebar-hover); }
.conv-load-more:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }

/* ============================================================= *
 *  Inline rename edit-in-place (antchat-new#115)                *
 * ============================================================= */
/* The edit input sits inline in the row; when editing it replaces the title
 * link + agent tag visually. ui.js toggles [hidden] and the .conv-item-editing
 * class on the row. */
.conv-item-edit[hidden] { display: none; }
.conv-item-edit {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-sm);
  padding: 2px var(--sp-2);
  border: 1px solid var(--c-accent);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: var(--c-text);
}
.conv-item-edit:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }
/* While editing, hide the title link + actions trigger so only the input shows. */
.conv-item-editing .conv-item-main,
.conv-item-editing .conv-actions-btn { display: none; }

/* ============================================================= *
 *  Toast notifications (antchat-new#119)                        *
 * ============================================================= */
/* Fixed bottom-right stack; ui.js appends a .toast per message and removes it
 * after a short delay. Toasts slide/fade in via the .toast-show modifier. */
.toast-stack {
  position: fixed;
  right: var(--sp-4);
  bottom: var(--sp-4);
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  max-width: min(22rem, calc(100vw - 2rem));
  pointer-events: none;
}
.toast {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  color: #fff;
  background: #b91c1c;
  box-shadow: var(--c-shadow-lg);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease;
  pointer-events: auto;
}
.toast-show { opacity: 1; transform: translateY(0); }
.toast-error { background: #b91c1c; }
.toast-success { background: var(--c-accent); }

/* ============================================================= *
 *  Confirm modal — delete confirmation (antchat-new#115)        *
 * ============================================================= */
.confirm-modal[hidden] { display: none; }
.confirm-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
}
.confirm-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
}
.confirm-modal-panel {
  position: relative;
  width: min(24rem, calc(100vw - 2rem));
  padding: var(--sp-5);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
  color: var(--c-text);
  box-shadow: var(--c-shadow-lg);
}
.confirm-modal-title { margin: 0 0 var(--sp-2); font-size: var(--fs-lg); }
.confirm-modal-text { margin: 0 0 var(--sp-4); color: var(--c-text-muted); font-size: var(--fs-sm); line-height: 1.5; }
.confirm-modal-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); }
.confirm-modal-btn {
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-sm);
  border-radius: var(--radius-sm);
  cursor: pointer;
  border: 1px solid var(--c-border);
}
.confirm-modal-cancel { background: transparent; color: var(--c-text); }
.confirm-modal-cancel:hover { background: var(--c-surface-alt); }
.confirm-modal-ok { background: #b91c1c; border-color: #b91c1c; color: #fff; }
.confirm-modal-ok:hover { background: #a31616; }
.confirm-modal-btn:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }

/* ---------- user settings: communication-style persona (issue #142) ---------- */
.settings {
  max-width: 42rem;
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.settings-title { font-size: var(--fs-xl); font-weight: 600; }
.settings-intro { color: var(--c-text-muted); font-size: var(--fs-sm); line-height: 1.5; }
.persona-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-top: var(--sp-2);
}
.persona-field { display: flex; flex-direction: column; gap: var(--sp-1); }
.persona-label { font-weight: 500; font-size: var(--fs-sm); }
.persona-input {
  padding: var(--sp-2);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  background: var(--c-surface);
  color: var(--c-text);
  font: inherit;
}
.persona-textarea { resize: vertical; min-height: 4.5rem; }
.persona-save {
  align-self: flex-start;
  padding: var(--sp-2) var(--sp-4);
  border: none;
  border-radius: var(--radius-sm);
  background: var(--c-accent);
  color: #fff;
  font-weight: 600;
  cursor: pointer;
}
.persona-save:hover { filter: brightness(1.05); }
.persona-note { font-size: var(--fs-sm); padding: var(--sp-1) var(--sp-2); border-radius: var(--radius-sm); }
.persona-note-ok { color: var(--flag-green); }
.persona-note-err { color: var(--flag-red); }
