/* styles.css — white-label assistant UI.
 *
 * Theming is 100% CSS custom properties. Two full palettes (light + dark) are
 * defined below; the effective theme is chosen by:
 *   - no [data-theme] on <html>  → follow the OS (prefers-color-scheme)
 *   - [data-theme="light"|"dark"] → hard override (persisted toggle wins both ways)
 *
 * The ONLY tenant-specific values are --accent / --accent-strong, which app.js
 * sets at runtime from window.__TENANT__.branding. Everything else is neutral, so
 * no company name / logo / colour is ever hardcoded here.
 */

/* ---------- palette: light (default) ---------- */
:root {
  --bg: #ffffff;
  --bg-elev: #f7f7f8;
  --bg-input: #ffffff;
  --bg-sidebar: #f7f7f8;
  --border: #e3e3e6;
  --border-strong: #cfcfd4;
  --text: #1f2023;
  --text-dim: #6b6d76;
  --text-faint: #9a9ba4;

  /* tenant accent — overwritten by app.js; these are safe neutral defaults */
  --accent: #10a37f;
  --accent-strong: #0e8e6e;
  --accent-hover: color-mix(in srgb, var(--accent) 88%, #000);
  --on-accent: #ffffff;

  --user-bubble: var(--accent);
  --user-text: var(--on-accent);
  --assistant-bubble: #f2f2f4;
  --assistant-text: #1f2023;
  --think-bg: #f0f4f8;
  --think-border: #dbe4ee;
  --danger: #c0392b;
  --danger-bg: #fdecea;
  --ok: #1a8f5c;
  --warn: #b45309;

  --shadow: 0 1px 3px rgba(0, 0, 0, .08), 0 4px 20px rgba(0, 0, 0, .05);
  --shadow-pop: 0 8px 30px rgba(0, 0, 0, .16);
  --radius: 14px;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* ---------- palette: dark ---------- */
/* Applied when the OS is dark AND the user hasn't forced light. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #1a1a1d;
    --bg-elev: #232327;
    --bg-input: #2a2a2f;
    --bg-sidebar: #202024;
    --border: #34343a;
    --border-strong: #45454d;
    --text: #ececf1;
    --text-dim: #9a9ba4;
    --text-faint: #6f7079;

    --accent-hover: color-mix(in srgb, var(--accent) 82%, #fff);
    --assistant-bubble: #2a2a2f;
    --assistant-text: #ececf1;
    --think-bg: #24272d;
    --think-border: #363b44;
    --danger: #ff6b5e;
    --danger-bg: #3a2422;
    --ok: #4ade80;
    --warn: #fbbf24;

    --shadow: 0 1px 3px rgba(0, 0, 0, .3), 0 4px 24px rgba(0, 0, 0, .35);
    --shadow-pop: 0 8px 34px rgba(0, 0, 0, .55);
  }
}
/* Hard override to dark regardless of OS (persisted toggle). */
:root[data-theme="dark"] {
  --bg: #1a1a1d;
  --bg-elev: #232327;
  --bg-input: #2a2a2f;
  --bg-sidebar: #202024;
  --border: #34343a;
  --border-strong: #45454d;
  --text: #ececf1;
  --text-dim: #9a9ba4;
  --text-faint: #6f7079;
  --accent-hover: color-mix(in srgb, var(--accent) 82%, #fff);
  --assistant-bubble: #2a2a2f;
  --assistant-text: #ececf1;
  --think-bg: #24272d;
  --think-border: #363b44;
  --danger: #ff6b5e;
  --danger-bg: #3a2422;
  --ok: #4ade80;
  --warn: #fbbf24;
  --shadow: 0 1px 3px rgba(0, 0, 0, .3), 0 4px 24px rgba(0, 0, 0, .35);
  --shadow-pop: 0 8px 34px rgba(0, 0, 0, .55);
}

/* ---------- base ---------- */
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  font-family: var(--sans);
  background: var(--bg);
  color: var(--text);
  height: 100dvh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}
.hidden { display: none !important; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
button { font-family: inherit; }

/* ---------- generic buttons ---------- */
.btn {
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: 9px;
  padding: 7px 12px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background .12s, border-color .12s, transform .05s;
}
.btn:hover { background: var(--bg-elev); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn.icon { padding: 7px; }
.btn svg { width: 16px; height: 16px; display: block; }
.btn.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.btn.primary:hover { background: var(--accent-hover); }
.btn.primary:disabled { opacity: .55; cursor: default; }

/* ================================================================
   LOGIN SCREEN
   ================================================================ */
.login {
  height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px;
  background:
    radial-gradient(1200px 600px at 50% -10%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 60%),
    var(--bg);
}
.login-card {
  width: 100%;
  max-width: 400px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: var(--shadow);
  padding: 32px 28px;
  text-align: center;
}
.login-logo { height: 44px; width: auto; max-width: 220px; margin: 0 auto 18px; display: block; object-fit: contain; }
.login-card h1 { font-size: 20px; margin: 0 0 6px; font-weight: 700; letter-spacing: -.01em; }
.login-card .sub { font-size: 14px; color: var(--text-dim); line-height: 1.5; margin: 0 0 22px; }
.login form { display: flex; flex-direction: column; gap: 12px; text-align: left; }
.text-input {
  font-family: var(--sans);
  font-size: 15px;
  padding: 12px 14px;
  border: 1px solid var(--border-strong);
  border-radius: 11px;
  background: var(--bg-input);
  color: var(--text);
  outline: none;
  width: 100%;
}
.text-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
}
.login .btn.primary { justify-content: center; padding: 12px; font-size: 15px; border-radius: 11px; }
.login-msg {
  margin-top: 16px;
  font-size: 13.5px;
  line-height: 1.5;
  padding: 12px 14px;
  border-radius: 11px;
  text-align: left;
}
.login-msg.ok { background: var(--think-bg); border: 1px solid var(--think-border); color: var(--text); }
.login-msg.err { background: var(--danger-bg); border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent); color: var(--danger); }
.login-msg a { color: var(--accent); word-break: break-all; }

/* ================================================================
   APP SHELL
   ================================================================ */
.app { display: flex; flex-direction: column; height: 100dvh; }

/* ---- header ---- */
header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-elev);
  flex-shrink: 0;
  min-height: 54px;
}
.brand { display: flex; align-items: center; gap: 9px; min-width: 0; }
.brand-logo { height: calc(26px * var(--logo-scale, 1)); width: auto; max-width: calc(150px * var(--logo-scale, 1)); object-fit: contain; display: block; }
.brand-name { font-weight: 700; font-size: 15.5px; letter-spacing: -.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.model-pill {
  font-size: 11.5px;
  font-family: var(--mono);
  color: var(--text-dim);
  background: var(--bg);
  border: 1px solid var(--border);
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
}
/* The build (version · deploy date) inside the model pill. Dimmer than the model name —
   it answers "which build is this?", which matters at a glance far less than what you are
   talking to. Dropped at the existing 860px breakpoint (where the header already starts
   getting tight) so it stops adding width well before the 620px rule hides the pill
   outright; the pill's title attribute still carries it at every size. */
.model-pill .build-info { opacity: .62; }
header .spacer { flex: 1; }

/* icon-only header buttons */
.iconbtn {
  width: 36px; height: 36px;
  border-radius: 9px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  display: grid; place-items: center;
  transition: background .12s, color .12s, border-color .12s, transform .05s;
  flex-shrink: 0;
}
.iconbtn:hover { background: color-mix(in srgb, var(--text) 8%, transparent); color: var(--text); }
.iconbtn:active { transform: translateY(1px); }
.iconbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.iconbtn svg { width: 19px; height: 19px; }

/* language selector */
.lang-select {
  font-family: var(--sans);
  font-size: 13px;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: 9px;
  padding: 7px 8px;
  cursor: pointer;
  outline: none;
}
.lang-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.verify-select {
  font-family: var(--sans); font-size: 13px; color: var(--text); background: var(--bg);
  border: 1px solid var(--border-strong); border-radius: 9px; padding: 7px 8px; cursor: pointer; outline: none;
  transition: background .12s, border-color .12s, color .12s;
}
.verify-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Verification costs a second model pass on every answer, so leaving it on by accident
   is expensive and easy to do — "on" has to read as on at a glance, not just as one of
   three near-identical dropdown labels. Colour + weight carry it (the label itself still
   says quick/thorough, so this is never colour-alone). */
.verify-select.on {
  font-weight: 650;
  color: var(--accent-strong);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, var(--bg));
}
.verify-select.on.thorough {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 55%, transparent);
  background: color-mix(in srgb, var(--warn) 14%, var(--bg));
}

/* thinking toggle */
.toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
}
.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle .track {
  width: 34px; height: 20px; border-radius: 999px;
  background: var(--border-strong);
  position: relative; transition: background .15s;
  flex-shrink: 0;
}
.toggle .track::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%;
  background: #fff; transition: transform .15s;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .3);
}
.toggle input:checked + .track { background: var(--accent); }
.toggle input:checked + .track::after { transform: translateX(14px); }
.toggle input:focus-visible + .track { outline: 2px solid var(--accent); outline-offset: 2px; }

/* account menu */
.menu-wrap { position: relative; }
.avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--accent); color: var(--on-accent);
  border: none; cursor: pointer;
  display: grid; place-items: center;
  font-weight: 600; font-size: 13px;
  transition: transform .05s, filter .12s;
}
.avatar:hover { filter: brightness(1.06); }
.avatar:active { transform: translateY(1px); }
.avatar:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.menu {
  position: absolute; right: 0; top: calc(100% + 8px);
  /* wide enough that a normal work email (…@linguardlabs.com ≈ 230px incl. padding)
     sits on one line; capped so a very long one still can't exceed a phone screen. */
  min-width: 268px;
  max-width: calc(100vw - 20px);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-pop);
  padding: 8px;
  z-index: 40;
}
.menu .who { padding: 8px 10px 10px; border-bottom: 1px solid var(--border); margin-bottom: 6px; }
/* overflow-wrap (not break-all): only break a genuinely too-long address, and at the
   edge rather than mid-word, so a normal email never wraps. */
.menu .who .em { font-size: 13px; font-weight: 600; overflow-wrap: anywhere; }
.menu .who .role { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
.menu-item {
  display: flex; align-items: center; gap: 9px;
  width: 100%; text-align: left;
  background: transparent; border: none; cursor: pointer;
  padding: 9px 10px; border-radius: 8px;
  font-size: 13.5px; color: var(--text);
}
.menu-item:hover { background: var(--bg-elev); }
.menu-item svg { width: 16px; height: 16px; color: var(--text-dim); }

/* ---- body: sidebar + chat column ---- */
.body { flex: 1; display: flex; min-height: 0; position: relative; }

/* sidebar */
.sidebar {
  width: 268px;
  flex-shrink: 0;
  background: var(--bg-sidebar);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  min-height: 0;
  transition: margin-left .2s ease;
}
/* Sidebar is shown when the app has .sidebar-open (set per screen width at boot,
   flipped by the header toggle). Hidden = slid out by a negative margin. */
.app:not(.sidebar-open) .sidebar { margin-left: -268px; }
.sidebar-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 12px 8px;
}
.sidebar-head .ttl { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); }
.new-chat-btn {
  display: flex; align-items: center; gap: 8px;
  margin: 4px 10px 8px;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 11px;
  background: var(--bg);
  color: var(--text);
  font-size: 14px; font-weight: 500;
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.new-chat-btn:hover { background: var(--bg-elev); border-color: var(--accent); }
.new-chat-btn svg { width: 17px; height: 17px; }
/* both lists share one scroll area; conversations sit on top, council sessions below */
.sidebar-lists { flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
.conv-list { padding: 4px 8px 12px; }
.conv-empty { color: var(--text-dim); font-size: 13px; padding: 14px 12px; text-align: center; }
/* Model picker + reasoning-effort select. Both reuse `.lang-select` for shape so the
   header keeps one control idiom; only the widths differ, because a model id is longer
   than a language name and an effort label is shorter. The effort select is tinted when
   reasoning is ON, for the same reason `.verify-select` is: it costs tokens on every
   answer, and three near-identical dropdown labels don't read as on/off at a glance.
   The label still names the level, so it is never colour-alone. */
.model-select { max-width: 168px; }
.effort-select { max-width: 150px; }
.effort-select.on {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
  color: var(--accent);
}

/* Kind badge beside the timestamp in the sidebar. Only rendered when the tenant HAS
   council (see renderSidebar) — with one kind of thread there is nothing to distinguish
   and a "Chat" stamp on every row is pure noise. Council carries the accent because it is
   the exceptional one; chat is left plain so the common case stays quiet. */
.ckind {
  margin-left: 6px; padding: 1px 5px; border-radius: 4px;
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  border: 1px solid var(--border); color: var(--text-dim); vertical-align: 1px;
}
.ckind.council {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.conv {
  display: flex; align-items: center; gap: 6px;
  padding: 9px 10px; border-radius: 9px;
  cursor: pointer; position: relative;
  color: var(--text);
}
.conv:hover { background: color-mix(in srgb, var(--text) 6%, transparent); }
.conv.active { background: color-mix(in srgb, var(--accent) 15%, transparent); }
.conv .cmeta { flex: 1; min-width: 0; }
.conv .ctitle { font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.conv .ctime { font-size: 11px; color: var(--text-dim); margin-top: 1px; }
.conv .cdel {
  border: none; background: transparent; color: var(--text-dim);
  cursor: pointer; padding: 4px; border-radius: 6px; flex-shrink: 0;
  opacity: 0; transition: opacity .12s, background .12s, color .12s;
}
.conv:hover .cdel, .conv.active .cdel { opacity: 1; }
.conv .cdel:hover { background: var(--danger-bg); color: var(--danger); }
.conv .cdel svg { width: 15px; height: 15px; display: block; }

/* chat column */
.chat { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; }

main {
  flex: 1;
  overflow-y: auto;
  scroll-behavior: smooth;
}
.messages {
  max-width: 1080px;
  margin: 0 auto;
  padding: 24px 20px 8px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

/* empty state */
.empty {
  text-align: center;
  color: var(--text-dim);
  margin: 14vh auto;
  max-width: 480px;
  padding: 0 20px;
}
.empty .glyph {
  width: 52px; height: 52px; margin: 0 auto 16px;
  border-radius: 15px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
}
.empty .glyph svg { width: 28px; height: 28px; }
.empty h1 { font-size: 22px; margin: 0 0 8px; color: var(--text); font-weight: 700; }
.empty p { font-size: 14.5px; line-height: 1.55; margin: 6px 0; }

/* ---- message rows ---- */
.row { display: flex; }
.row.user { justify-content: flex-end; }
.row.assistant { justify-content: flex-start; }

.bubble {
  max-width: 88%;
  padding: 11px 15px;
  border-radius: var(--radius);
  line-height: 1.55;
  font-size: 15px;
  white-space: pre-wrap;
  word-wrap: break-word;
  overflow-wrap: anywhere;
}
.row.user .bubble {
  background: var(--user-bubble);
  color: var(--user-text);
  border-bottom-right-radius: 4px;
}
.row.assistant .bubble {
  background: var(--assistant-bubble);
  color: var(--assistant-text);
  border-bottom-left-radius: 4px;
}
.bubble.error {
  background: var(--danger-bg);
  color: var(--danger);
  border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
}

/* rendered markdown inside the assistant bubble */
.bubble.md { white-space: normal; }
.bubble.md > *:first-child { margin-top: 0; }
.bubble.md > *:last-child { margin-bottom: 0; }
.bubble.md p { margin: 0 0 10px; }
.bubble.md h1, .bubble.md h2, .bubble.md h3,
.bubble.md h4, .bubble.md h5, .bubble.md h6 { margin: 16px 0 8px; line-height: 1.3; font-weight: 700; }
.bubble.md h1 { font-size: 1.4em; } .bubble.md h2 { font-size: 1.25em; }
.bubble.md h3 { font-size: 1.12em; } .bubble.md h4 { font-size: 1em; }
.bubble.md ul, .bubble.md ol { margin: 4px 0 10px; padding-left: 1.4em; }
.bubble.md li { margin: 3px 0; }
.bubble.md li > p { margin: 0; }
.bubble.md a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.bubble.md hr { border: none; border-top: 1px solid var(--border); margin: 14px 0; }
.bubble.md img { max-width: 100%; border-radius: 8px; }
.bubble.md code {
  font-family: var(--mono); font-size: .88em;
  background: color-mix(in srgb, var(--text) 8%, transparent);
  padding: .12em .4em; border-radius: 5px;
}
.bubble.md pre {
  background: color-mix(in srgb, var(--text) 8%, transparent);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  overflow-x: auto;
  margin: 0 0 10px;
}
.bubble.md pre code { background: none; padding: 0; font-size: .85em; line-height: 1.45; }
.bubble.md blockquote {
  margin: 0 0 10px; padding: 2px 0 2px 12px;
  border-left: 3px solid var(--border-strong); color: var(--text-dim);
}
.bubble.md table {
  border-collapse: collapse; margin: 0 0 10px; font-size: .92em;
  display: block; max-width: 100%; overflow-x: auto;
}
.bubble.md th, .bubble.md td { border: 1px solid var(--border-strong); padding: 5px 9px; text-align: left; }
.bubble.md th { background: color-mix(in srgb, var(--text) 6%, transparent); font-weight: 600; }
.bubble.md .katex-display { overflow-x: auto; overflow-y: hidden; padding: 2px 0; margin: 8px 0; }
.bubble.md .katex { font-size: 1.02em; }

/* attachments shown in the user bubble */
.u-atts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.u-atts img { width: 130px; max-width: 42vw; border-radius: 8px; display: block; }
.u-atts .u-file {
  font-size: 12px; background: rgba(255, 255, 255, .18); color: var(--user-text);
  padding: 4px 8px; border-radius: 7px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}

/* assistant wrapper (thinking + bubble + stats + actions stack) */
.assistant-wrap { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; max-width: 88%; }

.stats { font-size: 11px; color: var(--text-dim); font-variant-numeric: tabular-nums; padding: 1px 4px; min-height: 13px; }

/* per-message action row */
.msg-actions { display: flex; gap: 4px; padding: 2px 2px 0; flex-wrap: wrap; }
.act {
  display: inline-flex; align-items: center; gap: 5px;
  border: none; background: transparent;
  color: var(--text-dim); cursor: pointer;
  font-size: 12px; padding: 4px 7px; border-radius: 7px;
  transition: background .12s, color .12s;
}
.act:hover { background: color-mix(in srgb, var(--text) 8%, transparent); color: var(--text); }
.act:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.act svg { width: 14px; height: 14px; }
.act.on { color: var(--accent); }

/* thinking area */
details.think {
  width: 100%;
  background: var(--think-bg);
  border: 1px solid var(--think-border);
  border-radius: 10px;
  font-size: 13px;
  color: var(--text-dim);
  overflow: hidden;
}
details.think summary {
  cursor: pointer; padding: 8px 12px; list-style: none;
  display: flex; align-items: center; gap: 7px; font-weight: 500; user-select: none;
}
details.think summary::-webkit-details-marker { display: none; }
details.think summary .chev { transition: transform .15s; width: 13px; height: 13px; }
details.think[open] summary .chev { transform: rotate(90deg); }
details.think .think-body {
  padding: 0 12px 10px 30px;
  white-space: pre-wrap;
  font-size: 12.5px; line-height: 1.5;
  color: var(--text-dim);
  max-height: 240px; overflow-y: auto;
}
/* while live it's a small scrolling window */
.thinking-live .think-body { max-height: 150px; }
.thinking-live .think-dots::after { content: ""; animation: dots 1.4s steps(4, end) infinite; }
@keyframes dots { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } 100% { content: ""; } }

.cursor::after {
  content: "▋"; display: inline-block; margin-left: 1px;
  animation: blink 1s steps(2, start) infinite; color: var(--accent); font-weight: 400;
}
@keyframes blink { to { visibility: hidden; } }

/* afterthoughts — the model's second-pass self-review, shown under the answer and
   clearly set apart from it (accent rule + inset). */
.afterthoughts {
  margin-top: 10px;
  padding: 8px 12px 8px 13px;
  border-left: 3px solid var(--accent);
  background: var(--think-bg);
  border-radius: 0 8px 8px 0;
}
.afterthoughts .after-head {
  display: flex; align-items: center; gap: 7px;
  font-size: 12px; font-weight: 600; letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--accent-strong);
}
.afterthoughts .after-head svg { width: 14px; height: 14px; }
.afterthoughts .after-body {
  margin-top: 5px;
  font-size: 13.5px; line-height: 1.55;
  color: var(--text-dim);
}
.afterthoughts .after-body > :first-child { margin-top: 0; }
.afterthoughts .after-body > :last-child { margin-bottom: 0; }
.after-dots::after { content: ""; animation: dots 1.4s steps(4, end) infinite; }

/* curated — the single-pass answer was rewritten for consistency; a small marker that
   folds open to reveal the original text. Subtler than the thinking panel. */
details.curated {
  width: 100%;
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-dim);
}
details.curated summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 9px; border-radius: 999px;
  background: var(--think-bg); border: 1px solid var(--think-border);
  font-weight: 600; letter-spacing: .01em; user-select: none;
  color: var(--accent-strong);
}
details.curated summary::-webkit-details-marker { display: none; }
details.curated summary .chev { transition: transform .15s; width: 12px; height: 12px; }
details.curated[open] summary .chev { transform: rotate(90deg); }
details.curated summary .cur-ico { width: 13px; height: 13px; }
details.curated .cur-body {
  margin-top: 6px;
  padding: 8px 12px;
  border-left: 3px solid var(--think-border);
  background: var(--think-bg);
  border-radius: 0 8px 8px 0;
  white-space: pre-wrap;
  font-size: 12.5px; line-height: 1.5;
  color: var(--text-dim);
  max-height: 320px; overflow-y: auto;
}
.cur-dots::after { content: ""; animation: dots 1.4s steps(4, end) infinite; }

/* ======================= council mode ======================= */
/* header mode switch (Chat / Council) */
.mode-switch {
  display: inline-flex; margin-left: 12px;
  border: 1px solid var(--border); border-radius: 999px; overflow: hidden;
  background: var(--bg-elev);
}
.mode-seg {
  border: 0; background: transparent; cursor: pointer;
  padding: 5px 14px; font-size: 13px; font-weight: 600; color: var(--text-dim);
}
.mode-seg.on { background: var(--accent); color: #fff; }

/* Labs off → hide the advanced composer controls (their effect is also suppressed at send
   time in app.js). The Labs switch lives in the account menu, tenant-gated. */
body.labs-off #wristwatchToggleWrap,
body.labs-off #afterToggleWrap,
body.labs-off #curativeToggleWrap,
body.labs-off #nudgeToggleWrap,
body.labs-off #verifySelect { display: none !important; }
.menu-item .menu-state { margin-left: auto; color: var(--accent); font-weight: 700; font-size: 13px; }

/* Labs "on" pill in the header — an accent call-to-action; clicking turns Labs off. */

/* in council mode, hide the chat-only composer controls + toggles (attach stays: the
   council can read documents too) */
body.mode-council #thinkToggleWrap,
body.mode-council #afterToggleWrap,
body.mode-council #curativeToggleWrap,
body.mode-council #sourceBtn { display: none !important; }

/* member picker bar above the composer */
.council-bar { display: none; }
body.mode-council .council-bar {
  display: flex; flex-wrap: wrap; gap: 7px;
  max-width: 1080px; margin: 0 auto 8px; padding: 0 2px;
}
.preset-btn {
  border: 1px solid var(--border); background: var(--bg-elev); color: var(--text-dim);
  border-radius: 999px; padding: 5px 12px; font-size: 13px; font-weight: 500; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
}
.preset-btn::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  border: 1.5px solid currentColor; opacity: .5;
}
.preset-btn.on {
  border-color: var(--accent); color: var(--accent-strong);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.preset-btn.on::before { background: var(--accent); border-color: var(--accent); opacity: 1; }
.preset-manage { font-weight: 600; }

/* chair presentation toggle — a small segmented control, right-aligned in the council bar */
.council-style {
  display: inline-flex; margin-left: auto; align-self: center;
  border: 1px solid var(--border); border-radius: 999px; background: var(--bg-elev);
  overflow: hidden;
}
.cs-seg {
  border: 0; background: transparent; color: var(--text-dim); cursor: pointer;
  padding: 5px 12px; font-size: 12.5px; font-weight: 500; white-space: nowrap;
}
.cs-seg.on {
  background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent-strong);
  font-weight: 600;
}
/* chair editor: the style picker (which chairman prompt to edit) */
.cm-chair-picker {
  display: inline-flex; margin: 0 0 10px;
  border: 1px solid var(--border); border-radius: 999px; background: var(--bg-elev); overflow: hidden;
}

/* a council turn: member panels in a row, chair below */
.council-wrap { width: 100%; max-width: 100%; }
.council-panels {
  display: grid; gap: 12px; margin-bottom: 12px;
  grid-auto-columns: minmax(260px, 1fr); grid-auto-flow: column;
  overflow-x: auto; padding-bottom: 4px;
}
.council-panel {
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg-elev); display: flex; flex-direction: column; min-width: 0;
}
.cp-head {
  display: flex; align-items: center; gap: 7px;
  padding: 8px 12px; border-bottom: 1px solid var(--border);
  font-size: 12.5px; font-weight: 700; letter-spacing: .01em; color: var(--accent-strong);
}
.cp-dots::after { content: ""; animation: dots 1.4s steps(4, end) infinite; }
.cp-body {
  padding: 10px 12px; font-size: 13.5px; line-height: 1.55; overflow-wrap: anywhere;
  max-height: 460px; overflow-y: auto;
}
.cp-body > :first-child { margin-top: 0; }
.cp-body > :last-child { margin-bottom: 0; }
.council-panel.failed .cp-body { color: var(--text-dim); font-style: italic; }

/* chairman panel, full width below the members */
.council-chair {
  border: 1px solid var(--accent); border-radius: 12px;
  background: color-mix(in srgb, var(--accent) 6%, var(--bg-elev));
}
.cc-head {
  display: flex; align-items: center; gap: 7px;
  padding: 9px 14px; border-bottom: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  font-size: 13px; font-weight: 700; color: var(--accent-strong);
}
.cc-head svg { width: 15px; height: 15px; }
.cc-dots::after { content: ""; animation: dots 1.4s steps(4, end) infinite; }
.cc-body { padding: 12px 14px; font-size: 14px; line-height: 1.6; }
.cc-body > :first-child { margin-top: 0; }
.cc-body > :last-child { margin-bottom: 0; }

/* on narrow screens the members stack instead of scrolling sideways */
@media (max-width: 720px) {
  .council-panels { grid-auto-flow: row; grid-auto-columns: auto; }
}

/* ---- council manager dialog ---- */
.council-kd { max-width: 640px; }
.cm-tabs { display: flex; gap: 4px; margin: 4px 0 12px; border-bottom: 1px solid var(--border); }
.cm-tab {
  border: 0; background: transparent; cursor: pointer;
  padding: 8px 14px; font-size: 13.5px; font-weight: 600; color: var(--text-dim);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.cm-tab.on { color: var(--accent-strong); border-bottom-color: var(--accent); }
.cm-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.cm-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; border: 1px solid var(--border); border-radius: 9px; background: var(--bg-elev);
}
.cm-name { flex: 1; font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: 8px; }
.cm-tag {
  font-size: 11px; font-weight: 600; color: var(--text-dim);
  border: 1px solid var(--border); border-radius: 999px; padding: 1px 7px;
}
.cm-acts { display: flex; gap: 6px; }
.cm-add { width: 100%; }
.cm-prompt {
  width: 100%; min-height: 200px; resize: vertical;
  border: 1px solid var(--border); border-radius: 10px; background: var(--bg-input);
  color: var(--text); padding: 10px 12px; font: inherit; font-size: 13.5px; line-height: 1.5;
}
.cm-chair-text { min-height: 300px; font-family: ui-monospace, monospace; font-size: 12.5px; }
.cm-editor { max-width: 560px; }
.cm-editor .text-input { width: 100%; margin-bottom: 10px; }
.cm-foot { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.cm-msg { font-size: 12.5px; color: var(--text-dim); }
.cm-badge {
  font-size: 12px; font-weight: 600; color: var(--text-dim);
  border: 1px solid var(--border); border-radius: 999px; padding: 2px 9px;
}
.cm-badge.custom { color: var(--accent-strong); border-color: var(--accent); }
.cm-editor-back { z-index: 60; }

/* ---- composer ---- */
footer {
  flex-shrink: 0;
  border-top: 1px solid var(--border);
  background: var(--bg-elev);
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
}
.composer {
  max-width: 1080px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: var(--bg-input);
  border: 1px solid var(--border-strong);
  border-radius: 16px;
  padding: 8px;
  box-shadow: var(--shadow);
  transition: border-color .12s;
}
.composer:focus-within { border-color: var(--accent); }
.composer-row { display: flex; align-items: flex-end; gap: 6px; }

/* attachment chips */
.chips { display: flex; flex-wrap: wrap; gap: 8px; padding: 2px 2px 0; }
.chips:empty { display: none; }
.chip {
  display: flex; align-items: center; gap: 7px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 9px; padding: 4px 6px; font-size: 12px; max-width: 240px;
}
.chip img { width: 34px; height: 34px; object-fit: cover; border-radius: 6px; flex-shrink: 0; }
.chip .cico { width: 26px; height: 26px; display: grid; place-items: center; flex-shrink: 0; color: var(--text-dim); }
.chip .cmeta2 { display: flex; flex-direction: column; min-width: 0; }
.chip .cname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
.chip .csub { color: var(--text-dim); font-size: 10.5px; }
.chip .csub.err { color: var(--danger); }
.chip .rm {
  border: none; background: transparent; color: var(--text-dim); cursor: pointer;
  font-size: 15px; line-height: 1; padding: 2px 4px; border-radius: 5px; flex-shrink: 0;
}
.chip .rm:hover { background: var(--danger-bg); color: var(--danger); }

/* round composer icon buttons */
.composer-btn {
  flex-shrink: 0;
  width: 38px; height: 38px;
  border-radius: 10px;
  border: none;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  display: grid; place-items: center;
  transition: background .12s, color .12s, transform .05s;
}
.composer-btn:hover { background: color-mix(in srgb, var(--text) 8%, transparent); color: var(--text); }
.composer-btn:active { transform: translateY(1px); }
.composer-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.composer-btn svg { width: 20px; height: 20px; }
.composer-btn.recording { color: var(--danger); background: var(--danger-bg); animation: pulse 1.3s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }

.composer textarea {
  flex: 1;
  border: none;
  background: transparent;
  resize: none;
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  color: var(--text);
  max-height: 200px;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 8px 2px;
  outline: none;
}
.composer textarea::placeholder { color: var(--text-dim); }

.send-btn {
  flex-shrink: 0;
  width: 38px; height: 38px;
  border-radius: 10px;
  border: none;
  background: var(--accent);
  color: var(--on-accent);
  cursor: pointer;
  display: grid; place-items: center;
  transition: background .12s, transform .05s, opacity .12s;
}
.send-btn:hover { background: var(--accent-hover); }
.send-btn:active { transform: translateY(1px); }
.send-btn:disabled { opacity: .4; cursor: not-allowed; }
.send-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.send-btn svg { width: 19px; height: 19px; }
.send-btn.stop { background: var(--danger); }
.send-btn.stop:hover { background: color-mix(in srgb, var(--danger) 85%, #000); }

.composer-note {
  max-width: 820px; margin: 6px auto 0; font-size: 12px; text-align: center; color: var(--danger);
}
.composer-note[hidden] { display: none; }
.hint { max-width: 820px; margin: 6px auto 0; font-size: 11px; color: var(--text-faint); text-align: center; }

/* ---- toast ---- */
.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  background: var(--text); color: var(--bg);
  font-size: 13px; padding: 9px 15px; border-radius: 10px;
  box-shadow: var(--shadow-pop); z-index: 60;
  opacity: 0; pointer-events: none; transition: opacity .18s, transform .18s;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(-4px); }

/* ---- responsive ---- */
.sidebar-scrim { display: none; }
@media (max-width: 860px) {
  /* the build sits inside the model pill, so it must stop adding header width here —
     the pill itself survives down to 620px (see .model-pill .build-info) */
  .model-pill .build-info { display: none; }
  /* on narrow screens the sidebar floats over the chat as a slide-in overlay */
  .sidebar {
    position: fixed; top: 54px; left: 0; bottom: 0; z-index: 30;
    box-shadow: var(--shadow-pop);
  }
  /* dim + capture taps behind the open sidebar (below the header at top:54px) */
  .app.sidebar-open .sidebar-scrim {
    display: block; position: fixed; top: 54px; inset-inline: 0; bottom: 0;
    z-index: 25; background: rgba(0, 0, 0, .42);
    -webkit-tap-highlight-color: transparent;
  }
}
@media (max-width: 620px) {
  .model-pill { display: none; }
  .toggle .lbl { display: none; }
  .brand-name { display: none; }
  .bubble, .assistant-wrap { max-width: 92%; }
  .messages { padding-top: 16px; }
  header { padding-inline: 10px; gap: 6px; }
  .lang-select { max-width: 116px; }
  /* keep content clear of the iOS home indicator */
  footer { padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
}

/* ---- inline TTS player (read-aloud) ---- */
.tts-player {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 6px 0 2px;
  padding: 6px 8px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 12px;
  max-width: 100%;
}
.tts-player audio {
  height: 34px;
  flex: 1;
  min-width: 0;
  max-width: 360px;
}
.tts-dl,
.tts-close {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text-dim);
  cursor: pointer;
  text-decoration: none;
}
.tts-dl svg { width: 16px; height: 16px; }
.tts-dl:hover,
.tts-close:hover { color: var(--accent); border-color: var(--accent); }
.tts-close { font-size: 14px; line-height: 1; }

/* ---- translate language menu ---- */
.tr-menu {
  position: fixed;
  z-index: 60;
  min-width: 190px;
  padding: 5px;
  background: var(--bg-input);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-pop);
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.tr-head {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 6px 10px 4px;
}
.tr-item {
  text-align: left;
  border: none;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
}
.tr-item:hover { background: var(--bg-elev); color: var(--accent); }

/* Brand logos are dark-on-transparent (designed for light backgrounds). In dark
   mode, sit them on a small white chip so they stay legible. box-sizing keeps the
   header/login height stable. */
.brand-logo, .login-logo { box-sizing: border-box; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-logo {
    background: #fff; border-radius: 7px; padding: 3px 7px;
  }
  :root:not([data-theme="light"]) .login-logo {
    background: #fff; border-radius: 10px; padding: 8px 12px;
  }
}
:root[data-theme="dark"] .brand-logo {
  background: #fff; border-radius: 7px; padding: 3px 7px;
}
:root[data-theme="dark"] .login-logo {
  background: #fff; border-radius: 10px; padding: 8px 12px;
}

/* TTS speed toggle (subtle, text button in the player) */
.tts-speed {
  flex-shrink: 0;
  min-width: 34px; height: 30px;
  padding: 0 6px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text-dim);
  font: 600 12px var(--sans);
  cursor: pointer;
}
.tts-speed:hover { color: var(--accent); border-color: var(--accent); }
/* mic transcribing state */
.composer-btn.busy { opacity: .6; pointer-events: none; }

/* knowledge-source (pack) selector in the composer */
.composer-btn.active { color: var(--on-accent); background: var(--accent); }
.composer-btn.active:hover { background: var(--accent-hover); }
.composer-btn .src-label {
  font: 600 12px var(--sans);
  max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.composer-btn .src-label:empty { display: none; }
#sourceBtn { width: auto; gap: 5px; padding: 0 9px; }
/* selected row in the translate / source menus */
.tr-item.on { color: var(--accent); font-weight: 600; }

/* login: 6-digit code entry */
.code-input {
  text-align: center;
  font-size: 24px;
  font-weight: 700;
  letter-spacing: .35em;
  font-family: var(--mono);
  padding-left: .35em;   /* balance the trailing letter-spacing */
}
#codeForm { display: flex; flex-direction: column; gap: 12px; }
#codeForm .btn { justify-content: center; padding: 12px; font-size: 15px; border-radius: 11px; }

/* "Read with vision" OCR control in the attachment chip */
.ocr-btn {
  margin-top: 3px;
  align-self: flex-start;
  font: 600 11px var(--sans);
  color: var(--on-accent);
  background: var(--accent);
  border: none;
  border-radius: 7px;
  padding: 3px 8px;
  cursor: pointer;
}
.ocr-btn:hover { background: var(--accent-hover); }

/* knowledge management dialog */
.tr-manage { border-top: 1px solid var(--bd, var(--border)); margin-top: 3px; color: var(--accent); font-weight: 600; }
.kd-back { position: fixed; inset: 0; background: rgba(0,0,0,.45); display: grid; place-items: center; z-index: 80; padding: 16px; }
.kd { width: 100%; max-width: 560px; max-height: 86vh; overflow: auto; background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 16px; box-shadow: var(--shadow-pop); padding: 18px 20px; }
.kd-head { display: flex; align-items: center; justify-content: space-between; }
.kd-head b { font-size: 16px; }
.kd-x { border: none; background: transparent; font-size: 22px; line-height: 1; color: var(--text-dim); cursor: pointer; }
.kd-hint { font-size: 12.5px; color: var(--text-dim); margin: 4px 0 14px; line-height: 1.45; }
.kd-add { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.kd-add .kd-file { flex: 1 1 180px; font-size: 12.5px; }
.kd-add .kd-name { flex: 1 1 140px; padding: 8px 10px; }
/* ---- personality ("soul") dialog: same shell as .kd, with an editor body ---- */
.soul-kd { max-width: 620px; }
.soul-text { width: 100%; min-height: 320px; resize: vertical; padding: 12px 13px;
  border: 1px solid var(--border); border-radius: 12px; background: var(--bg-elev); color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; line-height: 1.55; }
.soul-text:focus { outline: 2px solid var(--accent); outline-offset: -2px; border-color: var(--accent); }
.soul-text::placeholder { color: var(--text-dim); opacity: .55; }
.soul-foot { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.soul-foot .soul-sp { flex: 1; }
.soul-msg, .soul-chars { font-size: 12px; color: var(--text-dim); }
.soul-chars.over { color: var(--danger); font-weight: 600; }
.soul-tip { margin: 12px 0 0; }
@media (max-width: 720px) { .soul-text { min-height: 220px; } }

.kd-status { min-height: 16px; font-size: 12.5px; margin: 8px 0; }
.kd-status.ok { color: var(--ok); } .kd-status.err { color: var(--danger); } .kd-status.busy { color: var(--text-dim); }
.kd-list { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }
.kd-empty { color: var(--text-faint); font-size: 13px; padding: 12px 0; text-align: center; }

/* MCP "Connections" dialog */
.mcp-add .mcp-in-name { flex: 1 1 120px; padding: 8px 10px; }
.mcp-add .mcp-in-url { flex: 2 1 220px; padding: 8px 10px; }
.mcp-add .mcp-auth { flex: 0 0 auto; padding: 8px 10px; }
.mcp-add .mcp-in-tok { flex: 1 1 140px; padding: 8px 10px; }
.kd-shead { font-size: 11px; font-weight: 700; color: var(--text-faint); text-transform: uppercase; letter-spacing: .06em; margin: 14px 0 4px; }
.kd-shead:first-child { margin-top: 4px; }
.mcp-badge { font-size: 10.5px; font-weight: 600; padding: 1px 8px; border-radius: 999px; vertical-align: middle; white-space: nowrap; }
.mcp-badge.b-ok { background: color-mix(in srgb, var(--ok) 16%, transparent); color: var(--ok); }
.mcp-badge.b-shared { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); }
.mcp-badge.b-pend { background: #fff4e0; color: #b26a00; }
.mcp-badge.b-err { background: var(--danger-bg); color: var(--danger); }
.kd-row { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 11px; }
.kd-info { flex: 1; min-width: 0; }
.kd-name2 { font-weight: 600; font-size: 14px; }
.kd-meta { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
.kd-warn { color: var(--warn, #b26a00); font-weight: 600; font-size: 11px; }
.kd-actions { display: flex; gap: 6px; flex-shrink: 0; }
.kd-btn { font-size: 12px; padding: 5px 10px; border: 1px solid var(--border-strong); background: var(--bg); border-radius: 8px; cursor: pointer; color: var(--text); }
.kd-btn:hover { background: var(--bg-elev); }
.kd-del:hover { color: var(--danger); border-color: var(--danger); }
.kd-share { border: 1px solid var(--border); border-radius: 11px; padding: 12px; margin: 2px 0 6px; background: var(--bg-elev); }
.kd-share-h { font-size: 12px; font-weight: 600; margin-bottom: 8px; }
.kd-users { display: flex; flex-direction: column; gap: 4px; max-height: 180px; overflow: auto; margin-bottom: 10px; }
.kd-user { display: flex; align-items: center; gap: 8px; font-size: 13px; padding: 3px 2px; cursor: pointer; }

/* ---- tool activity ("Reading example.com…") ---------------------------------
   One row per tool call, above the answer bubble. Stays after the answer so the
   source of a fetched claim is attributable. */
.toolacts { display: flex; flex-direction: column; gap: 4px; margin: 0 0 8px; }
.toolact { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text-dim);
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 8px; padding: 5px 10px; align-self: flex-start; }
.toolact-spin { width: 12px; text-align: center; font-size: 11px; line-height: 1; }
.toolact.pending .toolact-spin { border: 1.6px solid var(--border); border-top-color: var(--accent);
  border-radius: 50%; height: 12px; animation: toolspin .7s linear infinite; }
.toolact.ok .toolact-spin { color: var(--ok); } .toolact.err .toolact-spin { color: var(--danger); }
.toolact.err { color: var(--danger); }
@keyframes toolspin { to { transform: rotate(360deg); } }
/* Elapsed seconds on a tool call that is taking its time. A fetch_url has a 15s read
   timeout and the model may take several rounds, so "Reading gov.uk…" can sit there for a
   minute — with no clock it is indistinguishable from a hang. */
.toolact-age { font-variant-numeric: tabular-nums; opacity: .65; }

/* The bubble before the first token. Something has to move: a request that spends 40s in
   a web fetch before it says anything otherwise renders as an empty grey box, which is
   exactly what "why is it frozen?" looks like. */
.bubble.waiting { display: flex; align-items: center; gap: 5px; min-height: 20px; }
.bubble.waiting::after { content: ""; }
.wait-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-dim);
  opacity: .35; animation: waitpulse 1.2s ease-in-out infinite; }
.wait-dot:nth-child(2) { animation-delay: .18s; }
.wait-dot:nth-child(3) { animation-delay: .36s; }
@keyframes waitpulse { 0%, 80%, 100% { opacity: .25; transform: translateY(0); }
                       40% { opacity: .9; transform: translateY(-2px); } }

/* verification status — sits between the answer and its stats */
.verify { display: flex; align-items: flex-start; gap: 7px; font-size: 12.5px; align-self: flex-start;
  border-radius: 8px; padding: 5px 10px; margin-top: 2px; border: 1px solid var(--border); }
.verify-spin { width: 12px; height: 12px; flex: none; margin-top: 1px; border: 1.6px solid var(--border);
  border-top-color: var(--accent); border-radius: 50%; animation: toolspin .7s linear infinite; }
.verify-ico { width: 14px; flex: none; text-align: center; font-weight: 700; }
.verify-txt { line-height: 1.4; }
.verify.checking { color: var(--text-dim); background: var(--bg-elev); }
.verify.ok { color: var(--ok); background: color-mix(in srgb, var(--ok) 10%, transparent); border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.verify.flagged { color: var(--danger); background: color-mix(in srgb, var(--danger) 8%, transparent); border-color: color-mix(in srgb, var(--danger) 35%, transparent); }
.verify.muted { color: var(--text-dim); background: var(--bg-elev); }

/* ---- nudge chip ----
   A nudge changed the answer, so the user is told — but the ANSWER is what matters, so
   this is deliberately the quietest marker in the message: dim text, no fill, no accent,
   one small hand. It sits with the stats, not next to the answer. While the nudge pass
   runs it pulses; a false positive (model declined) removes it entirely. */
.nudge-chip {
  display: inline-flex; align-items: center; gap: 5px; align-self: flex-start;
  font-size: 11px; color: var(--text-dim); padding: 1px 4px; line-height: 1.5;
  cursor: help; user-select: none;
}
.nudge-chip svg { width: 12px; height: 12px; flex: none; opacity: .8; }
.nudge-chip.working { opacity: .75; animation: nudgepulse 1.3s ease-in-out infinite; }
@keyframes nudgepulse { 0%, 100% { opacity: .45; } 50% { opacity: .9; } }
@media (prefers-reduced-motion: reduce) { .nudge-chip.working { animation: none; } }

/* ---- save-state feedback (Personality dialog) ----
   Rest = neutral outline; edited = accent (there's something to save); saved = green. */
.btn.save-dirty { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.btn.save-dirty:hover { background: var(--accent-hover); }
.btn.save-done { background: var(--ok); color: #fff; border-color: var(--ok); }
.btn.save-done:hover { background: var(--ok); }

/* ---- mermaid diagrams -------------------------------------------------------
   Rendered from ```mermaid blocks in an assistant answer (see renderMermaid).
   A wide diagram scrolls inside its own box rather than stretching the bubble. */
.mermaid-wrap {
  margin: 10px 0;
  padding: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  text-align: center;
}
.mermaid-wrap svg { max-width: 100%; height: auto; display: inline-block; }
/* A diagram the model wrote wrong: keep the source visible, flag it quietly. */
.mermaid-bad { border-left: 3px solid var(--danger); }

/* ---- code blocks: header bar + copy, and syntax colours ---------------------
   The palette is ours, not an hljs stock theme: this file's contract is that
   theming is 100% CSS custom properties, and two stock themes would mean loading
   and swapping a second stylesheet on every theme toggle. */
:root {
  --hl-kw:   #a626a4;   /* keyword / built-in   */
  --hl-str:  #50a14f;   /* strings              */
  --hl-num:  #b76b01;   /* numbers, literals    */
  --hl-com:  #9a9ba4;   /* comments             */
  --hl-fn:   #4078f2;   /* function / title     */
  --hl-var:  #e45649;   /* variable / attribute */
  --hl-type: #986801;   /* class / type         */
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --hl-kw: #c678dd; --hl-str: #98c379; --hl-num: #d19a66; --hl-com: #6f7079;
    --hl-fn: #61afef; --hl-var: #e06c75; --hl-type: #e5c07b;
  }
}
:root[data-theme="dark"] {
  --hl-kw: #c678dd; --hl-str: #98c379; --hl-num: #d19a66; --hl-com: #6f7079;
  --hl-fn: #61afef; --hl-var: #e06c75; --hl-type: #e5c07b;
}

.codewrap {
  margin: 0 0 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;                 /* keeps the bar's corners with the pre's */
  background: color-mix(in srgb, var(--text) 8%, transparent);
}
.codebar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 4px 6px 4px 12px;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--text) 4%, transparent);
}
.codelang {
  font-family: var(--mono); font-size: 11px; color: var(--text-dim);
  text-transform: lowercase; letter-spacing: .02em;
}
.codecopy {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--sans); font-size: 11.5px; color: var(--text-dim);
  background: transparent; border: 1px solid transparent; border-radius: 7px;
  padding: 3px 7px; cursor: pointer;
}
.codecopy:hover { background: var(--bg); color: var(--text); border-color: var(--border); }
.codecopy svg { width: 13px; height: 13px; }
.codecopy.done { color: var(--ok); }
/* The pre now lives inside .codewrap, which owns the frame and the background.
   Must out-specify `.bubble.md pre` above (0-2-1) or the pre keeps its own 8% tint
   ON TOP of the wrap's 8% — ~15% grey and a doubled border. */
.bubble.md .codewrap pre { margin: 0; border: none; border-radius: 0; background: transparent; }

/* hljs tokens */
.hljs-comment, .hljs-quote { color: var(--hl-com); font-style: italic; }
.hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-section, .hljs-doctag,
.hljs-name, .hljs-strong { color: var(--hl-kw); }
.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta .hljs-string { color: var(--hl-str); }
.hljs-number, .hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id { color: var(--hl-num); }
.hljs-title, .hljs-title.function_, .hljs-built_in { color: var(--hl-fn); }
.hljs-variable, .hljs-template-variable, .hljs-attr, .hljs-selector-attr, .hljs-deletion { color: var(--hl-var); }
.hljs-type, .hljs-class .hljs-title, .hljs-title.class_, .hljs-params { color: var(--hl-type); }
.hljs-emphasis { font-style: italic; }

/* ---- download chip for an assistant-produced file (e.g. a spreadsheet) ---- */
.filechip {
  display: inline-flex; align-items: center; gap: 8px;
  margin: 8px 0 0; padding: 8px 12px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-elev); color: var(--text);
  font-size: 13px; font-weight: 500; text-decoration: none;
  align-self: flex-start; max-width: 100%;
}
.filechip:hover { border-color: var(--accent); background: var(--bg); }
.filechip svg { width: 18px; height: 18px; color: var(--accent); flex: none; }
.filechip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.assistant-wrap.files-only { padding-top: 0; }

/* ======================================================   Voice mode — full-screen hands-free conversation
   -------------------------------------------------------------
   A cover, not a dialog: while it's open the mic is live and the page behind is
   irrelevant, so it takes the whole viewport (100dvh + safe-area inset, same as the
   chat shell) rather than floating in the middle of it.

   The orb is driven by ONE custom property, --lvl (0..1), which app.js writes from
   the rAF meter — the mic while you speak, the answer's audio while it plays. Colour
   comes from [data-state] so phase and level are independent; nothing here needs to
   know which is which.
   ============================================================= */
.voice {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column;
  height: 100dvh;
  padding: 0 16px calc(16px + env(safe-area-inset-bottom));
  background: var(--bg);
  color: var(--text);
}
body.voice-open { overflow: hidden; }

.voice-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: calc(14px + env(safe-area-inset-top)) 0 6px;
  flex: none;
}
.voice-badge {
  font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-faint);
}
.voice-x {
  display: grid; place-items: center; width: 36px; height: 36px;
  border: none; border-radius: 50%; background: transparent;
  color: var(--text-dim); cursor: pointer;
}
.voice-x:hover { background: var(--bg-elev); color: var(--text); }
.voice-x svg { width: 20px; height: 20px; }

.voice-stage {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 22px; text-align: center;
}

/* ---- the orb ---- */
.voice-orb {
  --lvl: 0;
  position: relative; flex: none;
  width: 168px; height: 168px;
  display: grid; place-items: center;
}
.voice-core {
  width: 96px; height: 96px; border-radius: 50%;
  background: radial-gradient(circle at 34% 30%,
              color-mix(in srgb, var(--accent) 55%, #fff), var(--accent) 62%,
              var(--accent-strong));
  box-shadow: 0 0 calc(18px + 46px * var(--lvl))
              color-mix(in srgb, var(--accent) calc(28% + 42% * var(--lvl)), transparent);
  /* the level term is what makes it feel connected to the room */
  transform: scale(calc(1 + .30 * var(--lvl)));
  transition: transform .07s linear, box-shadow .12s linear, background .3s ease;
}
.voice-ring {
  position: absolute; border-radius: 50%;
  border: 1.5px solid color-mix(in srgb, var(--accent) 34%, transparent);
  opacity: calc(.20 + .65 * var(--lvl));
  transition: opacity .12s linear, transform .07s linear, border-color .3s ease;
}
.voice-ring.r1 { width: 124px; height: 124px; transform: scale(calc(1 + .18 * var(--lvl))); }
.voice-ring.r2 { width: 150px; height: 150px; transform: scale(calc(1 + .12 * var(--lvl))); }
.voice-ring.r3 { width: 168px; height: 168px; transform: scale(calc(1 + .07 * var(--lvl))); }

/* Phase colours. Only the hue changes — size stays owned by --lvl. */
.voice-orb[data-state="thinking"] .voice-core,
.voice-orb[data-state="transcribing"] .voice-core { animation: voice-breathe 1.5s ease-in-out infinite; }
.voice-orb[data-state="muted"] .voice-core,
.voice-orb[data-state="interrupted"] .voice-core {
  background: radial-gradient(circle at 34% 30%, var(--text-faint), var(--text-dim));
  box-shadow: none;
}
.voice-orb[data-state="muted"] .voice-ring,
.voice-orb[data-state="interrupted"] .voice-ring { border-color: var(--border-strong); opacity: .3; }
.voice-orb[data-state="speaking"] .voice-ring { border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
@keyframes voice-breathe {
  0%, 100% { opacity: .55; transform: scale(.94); }
  50%      { opacity: 1;   transform: scale(1.04); }
}
@media (prefers-reduced-motion: reduce) {
  .voice-core, .voice-ring { transition: none; }
  .voice-orb[data-state="thinking"] .voice-core,
  .voice-orb[data-state="transcribing"] .voice-core { animation: none; }
}

.voice-status { font-size: 17px; font-weight: 600; color: var(--text); min-height: 24px; }
.voice-caption {
  width: min(640px, 100%); max-height: 34vh; overflow-y: auto;
  display: flex; flex-direction: column; gap: 10px;
  font-size: 15px; line-height: 1.55; text-align: left;
}
.voice-caption:empty { display: none; }
.vc-you {
  align-self: flex-end; max-width: 88%;
  padding: 9px 13px; border-radius: 16px 16px 4px 16px;
  background: var(--user-bubble); color: var(--user-text);
}
.vc-bot { align-self: flex-start; max-width: 96%; color: var(--text-dim); }

/* ---- controls ---- */
.voice-bar {
  flex: none; display: flex; gap: 10px; justify-content: center; flex-wrap: wrap;
  padding-top: 8px;
}
.voice-act {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 18px; min-height: 44px;      /* comfortable tap target on mobile */
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--bg-elev); color: var(--text);
  font-family: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
}
.voice-act:hover:not(:disabled) { border-color: var(--border-strong); background: var(--bg); }
.voice-act:disabled { opacity: .4; cursor: default; }
.voice-act svg { width: 18px; height: 18px; flex: none; }
.voice-act.off { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); }
.voice-act.end {
  background: var(--danger); border-color: var(--danger); color: #fff;
}
.voice-act.end:hover { background: color-mix(in srgb, var(--danger) 86%, #000); border-color: transparent; }

.voice-hint {
  flex: none; padding-top: 12px; text-align: center;
  font-size: 12.5px; color: var(--text-faint);
}

@media (max-width: 480px) {
  .voice-orb { width: 140px; height: 140px; }
  .voice-core { width: 84px; height: 84px; }
  .voice-ring.r1 { width: 106px; height: 106px; }
  .voice-ring.r2 { width: 126px; height: 126px; }
  .voice-ring.r3 { width: 140px; height: 140px; }
  .voice-act { padding: 11px 14px; font-size: 13px; }
  .voice-caption { max-height: 28vh; }
}
/* ---- export an answer to PDF: clone into .print-root, print only that -------------------
   Triggered by the Download → PDF action (body gets .printing); a plain Cmd/Ctrl-P is
   unaffected. The exporter forces data-theme=light first, so this prints dark-on-white. */
.print-root { display: none; }
.cc-actions { margin-top: 10px; }
@media print {
  body.printing > *:not(.print-root) { display: none !important; }
  body.printing .print-root { display: block; }
  .print-root { max-width: 100%; padding: 0; color: var(--text); }
  .print-root .act, .print-root .msg-actions, .print-root .codecopy { display: none !important; }
  .print-root pre, .print-root .council-panel, .print-root img { break-inside: avoid; }
  @page { margin: 16mm 15mm; }
}

/* =============================================================
   Header overflow sheet — the per-turn controls on a phone
   -------------------------------------------------------------
   app.js MOVES the real controls in here below 620px (syncHeaderOverflow); this file
   only has to make them read as a list rather than a toolbar. Note the label rule: the
   ≤620px block above hides `.toggle .lbl` to save room in the bar, which is exactly
   wrong once the control is in a sheet — a bare switch with no name is unusable.
   ============================================================= */
.chat-opts {
  position: absolute; top: calc(100% + 6px); right: 10px; z-index: 50;
  width: min(280px, calc(100vw - 20px));
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 12px; box-shadow: var(--shadow-pop);
  padding: 6px;
}
header { position: relative; }              /* anchor for the sheet */
.chat-opts-head {
  font-size: 11.5px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-faint); padding: 6px 8px 8px;
}
.chat-opts-body { display: flex; flex-direction: column; gap: 2px; }
/* Each moved control becomes a full-width row. */
.chat-opts-body > * { width: 100%; }
.chat-opts-body .toggle {
  display: flex; flex-direction: row-reverse; justify-content: space-between;
  align-items: center; gap: 10px;
  padding: 9px 8px; border-radius: 8px; min-height: 40px;   /* comfortable tap target */
  font-size: 14px; color: var(--text);
}
.chat-opts-body .toggle:hover { background: var(--bg); }
.chat-opts-body .toggle .lbl { display: inline !important; }   /* see note above */
.chat-opts-body .lang-select,
.chat-opts-body .verify-select {
  max-width: 100%; margin: 4px 0; height: 40px;
}
/* A control the tenant doesn't have stays hidden — `.hidden` travels with the node. */

@media (max-width: 620px) {
  /* The Chat/Council switch is primary navigation so it stays in the bar, but it had no
     narrow rule at all and cost ~140px of a 390px viewport. */
  .mode-switch { margin-left: 6px; }
  .mode-seg { padding: 5px 10px; font-size: 12px; }
  /* The Labs "on" pill goes entirely on a phone. Even icon-only it costs ~44px with its
     gap, and after the controls moved into the sheet the bar came to ~388px against a
     390px viewport — no margin for a 375px handset. Labs stays reachable in the account
     menu (which shows its state), and its toggles are now in the sheet, so the pill is
     the most expendable thing in the row. */
}

/* Per-pass cost under each council member and the chairman. The numbers come from the
   server (member_usage / chair_usage) because members run in parallel on one connection.

   Sized to match the Copy/Download buttons (`.act`, 12px) rather than picked
   independently: the chairman's sits IN that same row, so anything else would make one
   line of footer chrome render at two sizes. It stays below the panel body text (13.5px)
   — this is a footnote about the answer, not part of it. */
.cp-stats, .cc-stats {
  font-size: 12px; color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.cp-stats { padding: 0 12px 10px; }
/* Fallback position — only reached if the actions bar is never built (an errored or
   interrupted turn); a finished chair answer moves this into .cc-actions below. */
.cc-stats { padding: 0 14px 12px; }
/* Beside Copy and Download: the row owns the padding, so drop the block padding and just
   sit on the buttons' baseline. `flex: 1` takes the leftover width so a long stats string
   wraps within the row instead of pushing the row wider. */
.cc-actions .cc-stats { padding: 0; flex: 1; align-self: center; }
.cp-stats:empty, .cc-stats:empty { display: none; }

/* Council thinking. A member's working, streamed live into a fixed-height box inside its
   panel — a few lines that scroll rather than a block that grows, because five members
   each reasoning at length would push the chairman (the output people actually want) off
   the bottom of a long scroll. Same reasoning as the height-capped panels themselves.
   Dimmer and smaller than the submission: it is how the member got there, not what it
   said. `.collapsed` is the restored-from-history state — shorter still, since old
   working is something you go looking for rather than re-read. */
.cp-think, .cc-think {
  max-height: 84px; overflow-y: auto; overscroll-behavior: contain;
  margin: 0 12px 8px; padding: 6px 8px;
  border-left: 2px solid color-mix(in srgb, var(--accent) 35%, transparent);
  background: color-mix(in srgb, var(--text) 4%, transparent);
  border-radius: 0 6px 6px 0;
  font-size: 11.5px; line-height: 1.45; color: var(--text-dim);
  white-space: pre-wrap; word-break: break-word;
}
.cc-think { margin: 0 14px 10px; max-height: 96px; }
.cp-think.collapsed, .cc-think.collapsed { max-height: 44px; }
.cp-think[hidden], .cc-think[hidden] { display: none; }

/* The Labs switch: one control, at the top of the panel whose contents it decides.
   Separated by a rule because it is a different KIND of thing from the rows below — it
   governs which of them exist. Never hidden by `body.labs-off`: it is what turns that
   off. */
.chat-opts-labs {
  margin: 0 0 6px; padding: 6px 8px; border-radius: 8px;
  border-bottom: 1px solid var(--border); border-radius: 0;
}
.chat-opts-labs:hover { background: var(--bg); }
.chat-opts-labs.hidden { display: none; }

/* "Email me the result", armed. It promises something that happens after you have closed
   the tab, so the armed state has to be legible at a glance — a pressed-looking button,
   not a tint you'd miss. It disarms itself on send: one question, one email. */
.composer-btn.on {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
