:root {
  --bg: #1a1a2e;
  --surface: #16213e;
  --surface2: #0f3460;
  --accent: #e94560;
  --text: #e0e0e0;
  --muted: #888;
  --own: #0f3460;
  --oth: #1e1e3a;
  --ai: #1a3a1a;
  --success: #2a5a2a;
  --danger: #5a1a1a;
  /* Read-receipt tick palette: a calm forward progression. Red is reserved
     exclusively for `failed` so a read receipt never reads as an alert. */
  --tick-delivered: #3ec370;
  --tick-read: #4da3ff;
  --tick-failed: #f87171;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

a { color: #7ab8ff; }
a:hover { color: #aad4ff; }
a.btn, a.btn:hover { color: white; }

body {
  font-family: system-ui, sans-serif;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  overflow-x: hidden;
}
body > main { margin: 10px; }
@media (min-width: 720px) {
  body > main { flex: 1 0 auto;  }
  body { display: flex; flex-direction: column; }
  body > .site-footer { flex-shrink: 0; }
}

nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  padding: 0.6rem 1.25rem;
  background: var(--surface);
  border-bottom: 1px solid var(--surface2);
  max-width: 100vw;
  overflow-x: clip;
}
body.dev-mode > nav {
  background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
  border-bottom: 2px solid #e94560;
}
body > nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
}
body { padding-top: 3.2rem; }
@media (max-width: 720px) {
  body > nav { position: static; }
  body { padding-top: 0; }
}
.nav-brand {
  font-weight: 700;
  font-size: 1.2rem;
  color: var(--accent) !important;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.nav-brand-icon { display: none; }
@media (max-width: 720px) {
  .nav-brand-icon { display: inline-block; }
  .nav-brand-text { display: none; }
}
.nav-primary, .nav-utility {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.nav-primary { margin-left: 0.75rem; }
.nav-utility { margin-left: auto; flex-shrink: 1; min-width: 0; gap: 0.5rem; flex-wrap: wrap; }

nav a { color: var(--text); text-decoration: none; }
nav a:hover { color: var(--accent); }
nav a.nav-active { color: var(--accent); font-weight: 600; border-bottom: 2px solid var(--accent); padding-bottom: 2px; }
nav a.nav-warn { color: #f0c040; }
nav a.nav-warn:hover { color: #ffe080; }
/* Single-contact nav link with new unseen activity — accent + a dot cue. */
nav a.nav-unread { color: var(--accent); font-weight: 600; }
nav a.nav-unread::after { content: "●"; margin-left: 4px; font-size: 0.6em; vertical-align: middle; color: var(--accent); }
/* Numeric badge appended to a nav item — e.g. filtered listings count. */
.nav-badge {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.05rem 0.4rem;
  background: var(--surface2);
  color: var(--muted);
  border-radius: 999px;
  font-size: 0.75em;
  font-weight: 500;
  vertical-align: middle;
}
nav a.nav-active .nav-badge { background: var(--accent); color: #fff; }
.nav-user {
  color: var(--muted);
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nav-user-avatar { padding: 0; line-height: 0; }
.nav-user-avatar img {
  width: 32px; height: 32px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--surface2);
  background: var(--surface);
  transition: border-color 0.12s ease;
}
.nav-user-avatar:hover img { border-color: var(--accent); }
.nav-user-avatar.nav-active img { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.nav-user-avatar.nav-active { border-bottom: none; padding-bottom: 0; }
/* Profile / sign-in glyph: always visible (both desktop + mobile).
   The 👤 is the ONLY visual when there's no avatar image — hiding it
   on desktop left the link as a zero-width invisible element. Lighter
   background than --surface2 so it stands out on the dark nav bar. */
.nav-user-glyph {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 1.2rem; width: 34px; height: 34px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.15);
  transition: background .15s, border-color .15s;
}
.nav-user:hover .nav-user-glyph {
  background: var(--accent); border-color: var(--accent);
}
.nav-locale {
  background: var(--surface2);
  color: var(--fg, var(--text));
  border: 1px solid var(--surface2);
  border-radius: 4px;
  padding: 3px 5px;
  cursor: pointer;
  max-width: 210px;
}
.nav-locale:focus { outline: 1px solid var(--accent); border-color: var(--accent); }
.unit-picker {
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--surface2, #ddd);
  border-radius: 4px;
  background: var(--surface, #fff);
  color: var(--text, #222);
  cursor: pointer;
}
.unit-picker:focus { outline: 1px solid var(--accent); border-color: var(--accent); }
.nav-prefs-wrap {
  display: flex; align-items: stretch; gap: 0;
}
.nav-prefs-group {
  display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap;
  border: 1px solid var(--surface2); border-radius: 6px 0 0 6px;
  padding: 0.2rem 0.4rem;
}
.nav-prefs-pin {
  margin-left: -1px;
  background: var(--surface2); border: 1px solid var(--surface2);
  color: var(--text); cursor: pointer;
  font-size: 0.9rem; font-weight: 600;
  padding: 0.35rem 0.45rem; line-height: 1;
  border-radius: 0 6px 6px 0;
  transition: background .15s, color .15s, border-color .15s;
}
.nav-prefs-pin:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.nav-prefs-group[style*="none"] + .nav-prefs-pin { border-radius: 6px; }
.nav-prefs-pin .eye-icon { display: block; }
.profile-prefs-group {
  position: relative;
  border: 1px solid var(--surface2); border-radius: 8px;
  padding: 0.8rem 1rem; margin-bottom: 0.7rem;
}
.profile-prefs-row {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.6rem;
  padding: 0.6rem 0.8rem;
}
.profile-pref-item {
  display: flex; flex-direction: column; gap: 0.15rem;
}
.profile-pref-item .field-label { color: var(--muted); margin: 0; }
.profile-pref-item .profile-field-with-badge { display: flex; align-items: center; gap: 0.25rem; }
.profile-prefs-row .btn-subtle {
  background: var(--surface2); color: var(--muted); border: 1px solid var(--surface2);
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; line-height: 1;
  border-radius: 4px; cursor: pointer; transition: background .15s, color .15s;
}
.profile-prefs-row .btn-subtle:hover { background: var(--accent); color: #fff; }
.profile-prefs-to-nav {
  position: absolute; top: 0.4rem; right: 0.4rem;
}
.ts-en { color: var(--muted); margin-left: 0.35em; }
.locale-item, .locale-opt {
  display: inline-flex; align-items: center; gap: 0.35em;
  white-space: nowrap;
}
/* Space between the flag glyph and the language name. The `gap` above
   handles flex layouts, but TomSelect's dropdown containers sometimes
   override `display` on the option wrapper; a hard right margin makes
   the spacing robust regardless. */
.locale-flag {
  display: inline-block;
  margin-right: 0.35em;
}

/* Currency picker row. Desktop = icon + localized name + SYMBOL (e.g.
   "🇭🇺 magyar forint Ft"); the 3-letter code is tooltip-only, so .cur-code is
   hidden. .cur-sym mirrors the locale picker's muted hint. Mobile (below)
   swaps to the compact "CODE (SYMBOL)" form. */
.cur-code { display: none; }
.cur-sym { color: var(--muted); margin-left: 0.4em; }
/* No distinct symbol (symbol == code, e.g. CHF): never show a redundant sym. */
.cur-nosym .cur-sym { display: none; }

/* The nav chip is intentionally narrow — the dropdown must be wider so
   the endonym + translated hint fit. TomSelect wraps the <select> in
   `.ts-wrapper` and hangs the dropdown after it; we widen it and pin it
   to the RIGHT edge of the wrapper so it doesn't overflow the viewport
   on nav-right layouts. */
.ts-wrapper.nav-locale {
  position: relative;                 /* anchor for the absolute dropdown */
}
.ts-wrapper.nav-locale .ts-dropdown,
.ts-wrapper.currency-picker .ts-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 260px;
  width: max-content;
  max-width: min(90vw, 340px);
  z-index: 100;
}
/* In the nav the chip sits at the right edge — open the dropdown leftward so
   it stays on-screen. (The Profile-page picker is not under <nav>, so it keeps
   the default left-aligned dropdown and doesn't run off the left edge.) */
nav .ts-wrapper.nav-locale .ts-dropdown {
  left: auto;
  right: 0;
}
.ts-wrapper.nav-locale .ts-dropdown .locale-opt,
.ts-wrapper.nav-locale .ts-dropdown .locale-item { white-space: nowrap; }
/* Force a single-column list — TomSelect's default `flex-wrap: wrap`
   layout turns wider dropdowns into a grid, but here we want a plain
   vertical list. */
.ts-wrapper.nav-locale .ts-dropdown .ts-dropdown-content {
  display: block;
  max-height: 60vh;
  overflow-y: auto;
}
.ts-wrapper.nav-locale .ts-dropdown .option { display: block; }
/* Currency dropdown options: block-level FLEX so the gap between icon / name /
   symbol applies (the generic `.option { display:block }` above would otherwise
   collapse the flex gap to zero, leaving only the symbol's margin). Scoped to
   the currency picker so the language picker's option layout is untouched. */
.ts-wrapper.currency-picker .ts-dropdown .option {
  display: flex; align-items: center; gap: 0.35em;
}

/* Single-select pickers (model / language / currency / timezone / any searchable
   <select>): CLOSED shows only the selected item — hide the inline input so it
   doesn't wrap onto a second row or leave a stray box. OPEN keeps the selected
   item VISIBLE beside a search field that grows to fill the control. The vendor
   sheet forces `.ts-control>input{display:inline-block!important}`, hence !important. */
.ts-wrapper.single:not(.dropdown-active) .ts-control > input {
  display: none !important;
}
.ts-wrapper.single.dropdown-active .ts-control > input {
  display: inline-block !important;
  flex: 1 1 auto !important; width: auto !important; min-width: 8ch !important;
  box-sizing: border-box;
}
/* The vendor reserves ~2.25rem of right padding for the dropdown chevron, but
   hides that chevron (background:transparent) while the field is open — leaving a
   big empty gap after the search box. Reclaim it when open so there's no dead
   space; the CLOSED state keeps its padding + chevron untouched. */
.ts-wrapper.single.dropdown-active .ts-control { padding-right: 0.75rem !important; }

/* Model picker capability icons (text 💬 + image 🖼️). */
.cap { display: inline-block; margin-right: 2px; line-height: 1; }
.cap-off { opacity: 0.25; }
.model-cap-legend .cap { margin-right: 1px; margin-left: 6px; }
.model-cap-legend .cap:first-child { margin-left: 0; }
.model-opt, .model-item { display: flex; align-items: center; gap: 6px; }
.model-opt .model-name, .model-item .model-name { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.model-opt .model-id, .model-item .model-id { flex: 0 0 auto; opacity: 0.55; }
.model-item .model-id { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40ch; }
.model-latest .model-name { color: var(--accent); font-weight: 600; }
.optgroup-header.optgroup-latest { color: var(--accent); }
/* Inline per-1M price next to the ⓘ in the model picker (option + selected
   item). Compact, muted, non-shrinking so it stays visible in the row. */
.model-opt .model-price, .model-item .model-price {
  flex: 0 0 auto; opacity: 0.8; white-space: nowrap;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.model-price .money { font-family: inherit; }
.money { position: relative; }
.money[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute; bottom: calc(100% + 6px); left: 50%;
  transform: translateX(-50%); white-space: nowrap;
  background: var(--surface2, #1e293b); color: var(--fg, #e0e0e0);
  padding: 4px 10px; border-radius: 6px; font-size: 0.82rem;
  font-weight: 400; box-shadow: 0 2px 8px rgba(0,0,0,.3);
  pointer-events: none; z-index: 9999; opacity: 0;
  animation: money-tip-in .15s ease-out forwards;
}
.money[data-tooltip]::before {
  content: ''; position: absolute; bottom: calc(100% + 2px); left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--surface2, #1e293b);
  pointer-events: none; z-index: 9999; opacity: 0;
  animation: money-tip-in .15s ease-out forwards;
}
@keyframes money-tip-in { to { opacity: 1; } }
.ai-summary-model .model-price { margin-left: 0.4em; }
/* Mobile: the price is the most important column — drop the leading capability
   icons from the dropdown row (they remain in the ⓘ tooltip) so the price
   never gets pushed off-screen. Only the option/item's own caps are hidden;
   the ⓘ, name, id and price stay. */
@media (max-width: 720px) {
  .model-opt > .cap, .model-item > .cap { display: none; }
  /* Hide the raw model id/code too — only the human-readable name + price
     matter on a narrow row (the code stays in the ⓘ tooltip). */
  .model-opt .model-id, .model-item .model-id { display: none; }
}
.ts-dropdown .optgroup-header { font-size: 1.1rem  !important; }
.ts-dropdown .optgroup::before  { margin: 0 !important;}
/* Smooth locale switch: fade body out before reload, fade in on arrival.
   Guarded by prefers-reduced-motion. Class is set on <html> just before
   reload; the fade-in class is added by a tiny inline head script when a
   sessionStorage flag is present, so a no-JS load shows content normally. */
html.locale-changing body { opacity: 0; transition: opacity .16s ease; }
html.locale-fade-in body { opacity: 0; animation: localeFadeIn .16s ease forwards; }
@keyframes localeFadeIn { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  html.locale-changing body, html.locale-fade-in body { opacity: 1; transition: none; animation: none; }
}
.ts-dropdown .optgroup-header:has(.optgroup-toggle) { cursor: pointer; user-select: none; }
.optgroup-toggle {
  display: inline-block; width: 1em; flex: 0 0 auto;
  transition: transform 0.12s ease;
}
.optgroup-toggle::before { content: "▸"; }
.optgroup-header.collapsed .optgroup-toggle { transform: rotate(-90deg); }
.model-latest-tag {
  font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
  border: 1px solid currentColor; border-radius: 3px; padding: 0 4px; margin-left: 4px; opacity: 0.85;
}
/* A model failing an active feature filter is hidden with !important so it
   stays hidden regardless of TomSelect's inline display (text-search) state. */
.ts-dropdown .option.model-feat-hidden { display: none !important; }
/* Feature-filter bar pinned at the top of the model dropdown. Icon toggles
   AND-filter the list; collapse/expand-all appear only when optgroups exist. */
.model-filter-bar {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  padding: 6px 8px; border-bottom: 1px solid var(--surface2);
  position: sticky; top: 0; z-index: 2; background: var(--surface);
}
.model-filter-btn {
  background: var(--surface2); border: 1px solid transparent; border-radius: 5px;
  padding: 2px 6px; font-size: 1rem; line-height: 1.2; cursor: pointer; opacity: 0.55;
  transition: opacity 0.1s ease, border-color 0.1s ease;
}
.model-filter-btn:hover { opacity: 0.85; }
.model-filter-btn.active { opacity: 1; border-color: var(--accent); }
.model-filter-grp-controls { margin-left: auto; display: none; gap: 4px; }
.model-filter-bar.has-groups .model-filter-grp-controls { display: inline-flex; }
.model-grp-collapse-all, .model-grp-expand-all {
  background: none; border: 1px solid var(--surface2); border-radius: 5px;
  color: var(--muted); padding: 2px 8px; cursor: pointer;
}
.model-grp-collapse-all:hover, .model-grp-expand-all:hover { color: var(--text); border-color: var(--muted); }

.nav-icon-link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.nav-icon-link.nav-active {
  border-bottom-color: var(--accent);
}

.nav-logout {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 34px;
  padding: 0 0.65rem;
  background: var(--surface2);
  border-radius: 4px;
  color: var(--muted) !important;
  line-height: 1;
  text-decoration: none;
}
.nav-logout::before { content: "⎋"; }
.nav-logout:hover { background: #c0392b !important; color: #fff !important; }

/* Hamburger — hidden on desktop, revealed below the breakpoint below. */
.nav-toggle {
  display: none;
  background: none;
  border: none;
  color: var(--text);
  font-size: 1.4rem;
  cursor: pointer;
  padding: 0.15rem 0.5rem;
  line-height: 1;
}
.nav-toggle:hover { color: var(--accent); }

@media (max-width: 720px) {
  nav {
    flex-wrap: wrap;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
  }
  .nav-toggle {
    display: inline-flex;
    align-items: center;
    background: var(--surface2);
    border-radius: 6px;
    padding: 0.35rem 0.55rem;
    font-size: 1.2rem;
  }

  /* Drawer (hamburger-toggled): primary links stack as full-width tappable
     cards below the burger row. order: 2 places the drawer right after
     first-row items; utility gets order: 3 so it flows after the drawer. */
  .nav-primary {
    display: none;
    flex-basis: 100%;
    order: 2;
    margin: 0.5rem -0.75rem 0;
    padding: 0.25rem 0.75rem 0.5rem;
    border-top: 1px solid var(--surface2);
    background: var(--bg);
  }
  nav.open .nav-primary { display: flex; }

  .nav-utility {
    order: 3;
    display: flex;
    margin-left: auto;
    align-items: center;
    gap: 0.35rem;
    flex-wrap: wrap;
  }

  .nav-primary { flex-direction: column; align-items: stretch; gap: 0.35rem; }
  .nav-primary a {
    align-items: center; gap: 0.6rem;
    padding: 0.7rem 0.85rem;
    background: var(--surface);
    border: 1px solid var(--surface2);
    border-radius: 6px;
    color: var(--text); text-decoration: none;
    min-height: 44px;   /* Apple/Android touch target min */
  }
  .nav-primary a:hover, .nav-primary a:active { background: var(--surface2); border-color: var(--accent); }
  .nav-primary a.nav-active { border-color: var(--accent); color: var(--accent); }
  .nav-primary a::before { content: "›"; color: var(--muted); font-size: 1.15rem; line-height: 1; }

  .nav-utility a,
  .nav-utility .err-log-bell-btn {
    flex: 0 0 auto;
    display: inline-flex; align-items: center; justify-content: center; gap: 0.3rem;
    min-height: 34px; padding: 0.3rem 0.5rem;
    background: var(--surface);
    border: 1px solid var(--surface2);
    border-radius: 6px;
    color: var(--text); text-decoration: none;
  }
  .nav-utility a:hover, .nav-utility a:active,
  .nav-utility .err-log-bell-btn:hover { background: var(--surface2); border-color: var(--accent); }
  .nav-utility a.nav-active { border-color: var(--accent); color: var(--accent); }
  .nav-utility a::before { content: none; }   /* no chevron on compact chips */

  /* Compact header chips: settings + logout icon-only; locale picker
     constrained so the whole cluster fits one header line. */
  .nav-icon-link .nav-label { display: none; }

  .nav-locale { width: auto; max-width: 8rem; min-height: 34px; }
  /* Currency picker on mobile. ONLY the NAV picker goes compact — the Profile
     picker keeps the full web format (icon + name + symbol) even on mobile, so
     every rule here is scoped to <nav>. HTML order is icon, name, code, sym;
     we show/hide per context and wrap the symbol in parens only in the compact
     nav forms. .cur-nosym (no distinct symbol) always hides the symbol span. */
  nav .ts-wrapper.currency-picker { max-width: 6.5rem; }
  /* NAV chip: "CODE (SYMBOL)" — icon + name hidden. */
  nav .ts-wrapper.currency-picker .locale-item .cur-icon,
  nav .ts-wrapper.currency-picker .locale-item .cur-name { display: none; }
  nav .ts-wrapper.currency-picker .locale-item .cur-code { display: inline; }
  nav .ts-wrapper.currency-picker .locale-item:not(.cur-nosym) .cur-sym {
    display: inline; margin-left: 0;
  }
  nav .ts-wrapper.currency-picker .locale-item:not(.cur-nosym) .cur-sym::before { content: "("; }
  nav .ts-wrapper.currency-picker .locale-item:not(.cur-nosym) .cur-sym::after { content: ")"; }
  /* NAV dropdown: "name CODE (SYMBOL)" — icon hidden, name + code + symbol. */
  nav .ts-wrapper.currency-picker .locale-opt .cur-icon { display: none; }
  nav .ts-wrapper.currency-picker .locale-opt .cur-code { display: inline; }
  nav .ts-wrapper.currency-picker .locale-opt:not(.cur-nosym) .cur-sym {
    display: inline; margin-left: 0;
  }
  nav .ts-wrapper.currency-picker .locale-opt:not(.cur-nosym) .cur-sym::before { content: "("; }
  nav .ts-wrapper.currency-picker .locale-opt:not(.cur-nosym) .cur-sym::after { content: ")"; }
}
/* Currency picker on profile — selected item + search input on one line */
.ts-wrapper.currency-picker .ts-control {
  flex-wrap: nowrap !important;
  overflow-x: auto;
}
.ts-wrapper.currency-picker .ts-control > input {
  min-width: 40px !important;
  flex: 0 1 auto !important;
}
.ts-wrapper.currency-picker .ts-control .item {
  white-space: nowrap;
}
@media (max-width: 720px) {
  .nav-user { max-width: none; padding: 0.3rem 0.45rem; }
  .nav-user-avatar img { width: 26px; height: 26px; }
  .nav-user-glyph { font-size: 1rem; width: 26px; height: 26px; }
  .nav-user-name { display: none; }   /* avatar / glyph suffices on mobile */

  .nav-utility .nav-logout::before { content: "⎋"; }

  /* Dropdowns open full-screen on phones — the narrow chip can't host a
     usable floating list. Applies to EVERY TomSelect dropdown. The dropdown
     is a flex column: a sticky header (search + ✕) over a scrolling option
     list. !important overrides TomSelect's inline positioning. */
  .ts-wrapper .ts-dropdown {
    position: fixed !important;
    top: 0 !important; right: 0 !important; bottom: 0 !important; left: 0 !important;
    width: 100vw !important; max-width: 100vw !important;
    min-width: 0 !important;
    border-radius: 0 !important;
    margin: 0 !important;
    overflow: hidden !important;
  }
  /* Only flex into the full-screen layout when actually open — without this
     guard the !important display would override TomSelect's display:none and
     cover the whole page with an empty dropdown (the "empty blue" bug). */
  .ts-wrapper.dropdown-active .ts-dropdown {
    display: flex !important;
    flex-direction: column !important;
  }
  .ts-wrapper .ts-dropdown .ts-dropdown-content {
    max-height: none !important;
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
  }

  /* Sticky header: the search input (moved here from the covered control by
     ts_mobile.js) + an ✕ that closes without changing the selection. */
  .ts-mobile-header {
    flex: 0 0 auto;
    display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap;
    padding: 0.5rem 0.6rem;
    background: var(--surface2);
    border-bottom: 1px solid rgba(255,255,255,0.12);
  }
  .ts-mobile-header input {
    flex: 1 1 auto; min-width: 0;
    font-size: 16px !important;
    padding: 0.55rem 0.7rem !important;
    background: var(--bg) !important; color: var(--text) !important;
    border: 1px solid var(--surface2); border-radius: 6px;
  }
  .ts-mobile-close {
    flex: 0 0 auto;
    display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px;
    background: var(--surface); color: var(--muted);
    border: 1px solid var(--surface2); border-radius: 6px;
    font-size: 1.3rem; line-height: 1; cursor: pointer;
  }
  .ts-mobile-close:hover { background: var(--accent); color: #fff; border-color: var(--accent); }

  /* Currently-selected option: accent tint + a check mark. */
  .ts-wrapper .ts-dropdown .option.selected {
    background: rgba(233, 69, 96, 0.18) !important;
    color: var(--text) !important;
    font-weight: 600;
  }
  .ts-wrapper .ts-dropdown .option.selected::after {
    content: "✓";
    float: right;
    color: var(--accent);
    font-weight: 700;
  }

  /* Model/info popover becomes a full-width bottom sheet on phones so the
     model label + description have room. !important beats place()'s inline
     top/left. */
  .doc-popover {
    position: fixed !important;
    top: 0 !important; left: 0 !important; right: 0 !important; bottom: auto !important;
    width: 100vw !important; max-width: 100vw !important;
    max-height: 65vh !important;
    overflow: auto !important;
    border-radius: 10px 10px 0 0 !important;
  }

  /* ≥16px stops iOS Safari from auto-zooming + dropping focus on the search
     input; larger option text improves touch targets on the full-screen lists. */
  .ts-wrapper .ts-dropdown .option { font-size: 1rem; padding: 0.6rem 0.7rem !important; }
}

/* On wide screens the settings icon replaces the word label to save space,
   while still keeping full-text on the mobile drawer (see media query). */
@media (min-width: 721px) {
  .nav-icon-link .nav-label { display: none; }
  .nav-logout .nav-label { display: none; }
}

/* Docs */
.doc-info-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35rem;
  height: 1.35rem;
  border-radius: 50%;
  border: none;
  background: var(--surface2);
  color: var(--muted);
  cursor: pointer;
  line-height: 1;
  padding: 0;
  margin-left: 0.5rem;
}
.doc-info-btn:hover { color: var(--accent); background: var(--surface); }
.doc-info-btn.active { color: var(--accent); background: var(--surface); }
.oth-note-display {
  margin-top: 0.5rem;
  padding: 0.5rem;
  background: var(--surface2);
  border-radius: 4px;
  border-left: 3px solid #8b5cf6;
}
.oth-note-date {
  display: flex; align-items: center; gap: 0.4em;
  color: var(--muted);
  margin-bottom: 0.25rem;
}
.doc-popover {
  position: absolute;
  z-index: 10000;
  max-width: min(24rem, 90vw);
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--surface2);
  border-radius: 6px;
  padding: 0.8rem 1rem;
  box-shadow: 0 8px 24px rgba(0,0,0,0.35);
  line-height: 1.4;
}
.doc-popover h4 { margin: 0 0 0.35rem; }
.doc-popover a { color: #7ab8ff; }
.doc-popover .doc-popover-md > *:first-child { margin-top: 0; }
.doc-popover .doc-popover-md > *:last-child { margin-bottom: 0; }
.doc-popover .doc-popover-md p { margin: 0 0 0.4rem; }

/* Mediator-actions doc table: parameter block under each action's description,
   and the example ("fantasy") language codes highlighted so readers know they're
   placeholders, not literal values. */
.doc-action-params { font-size: 0.95em; margin-top: 0.5em; line-height: 1.7; }
.doc-actions-table td { vertical-align: top; }
code.doc-fantasy {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  border: 1px dashed color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: 4px; padding: 0 4px; font-style: normal;
}

/* 🤖 model-info trigger: the robot head is a .doc-info-btn so it reuses the
   docs.js popover, but it should look like the plain sender icon — no info
   pill — and be clickable (msg-sender-label is pointer-events:none by default). */
.msg-sender-label.model-trigger,
.model-trigger.doc-info-btn {
  pointer-events: auto;
  cursor: pointer;
  width: auto; height: auto;
  margin-left: 0;
  background: transparent;
  border-radius: 0;
}
.model-trigger.doc-info-btn:hover { background: transparent; color: var(--accent); }
.doc-popover .model-pop-head { display: flex; align-items: center; gap: 0.4em; flex-wrap: wrap; }
.doc-popover .model-pop-name { font-weight: 600; }
.doc-popover .model-pop-tech { opacity: 0.6; word-break: break-all; }
.doc-popover .model-pop-caps { white-space: nowrap; }
.oth-note-model { line-height: 1; }


/* Reusable fullscreen-expand (static/fullscreen.js). [data-fullscreen] hosts
   get a ⛶ trigger; .fs-active lifts them to a fixed full-viewport overlay that
   stacks (rising z-index) and is not resizable. */
[data-fullscreen] { position: relative; }
.fs-trigger {
  position: absolute; top: 4px; right: 4px; z-index: 5;
  background: rgba(0,0,0,0.35); color: var(--text);
  border: 1px solid var(--surface2); border-radius: 5px;
  width: 26px; height: 26px; line-height: 1; cursor: pointer;
  opacity: 0.55; transition: opacity 0.15s;
}
.fs-trigger:hover { opacity: 1; }
.fs-active {
  position: fixed !important; inset: 0 !important;
  z-index: 9000; margin: 0 !important;
  width: 100vw !important; height: 100vh !important;
  max-width: none !important; max-height: none !important;
  resize: none !important;
  background: var(--bg);
  border-radius: 0; box-shadow: 0 0 0 100vmax rgba(0,0,0,0.6);
  overflow: auto;
}
.fs-active .fs-trigger { opacity: 1; }
/* Title bar at the top of every fullscreen overlay (fullscreen.js injects it
   from data-fs-label). Sticky so it stays visible while the content scrolls;
   right-padded so it clears the fixed ✕. */
.fs-active > .fs-title {
  position: sticky; top: 0; z-index: 9998;
  padding: 0.6rem 3rem 0.6rem 0.6rem;
  font-size: 1.1rem; font-weight: 600; color: var(--text);
  background: var(--bg); border-bottom: 1px solid var(--surface2);
}
/* HTML-title mode: the bar holds a relocated header block (not text). Reset the
   text-title font weight/size and give the moved header its normal look; keep the
   right padding so the fixed ✕ never overlaps the header's right-edge controls. */
.fs-active > .fs-title-html {
  padding: 0.4rem 3rem 0.4rem 0.6rem;
  font-size: inherit; font-weight: normal;
}
.fs-active > .fs-title-html > .chat-header { margin: 0; }
/* Pin the close (✕) to the viewport corner while fullscreen so it can't scroll
   out of view with the overlay's content. Fixed + high z-index keeps it above
   the panel (which is itself fixed inset:0). */
.fs-active > .fs-trigger {
  position: fixed !important; top: 10px !important; right: 14px !important;
  z-index: 9999 !important;
}

/* Shared close (×) control — error/notification toasts and a fullscreen
   overlay's close button are the same affordance, so they look the same. */
.err-close,
.fs-active .fs-trigger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0;
  background: var(--surface2); color: var(--muted);
  border: 1px solid var(--surface2); border-radius: 5px;
  font-size: 1rem; line-height: 1; cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.err-close:hover,
.fs-active .fs-trigger:hover {
  background: var(--accent); color: #fff; border-color: var(--accent);
}

/* Fullscreened chat surfaces keep their composer pinned and only the message
   list scrolls — overriding .fs-active's generic overflow:auto (which would
   scroll the whole panel and drop the composer out of view). */
.chat-panel.fs-active,
.assistant-chat.fs-active,
.on-site-chatbody.fs-active {
  display: flex; flex-direction: column; overflow: hidden;
}
.chat-panel.fs-active .messages-container,
.assistant-chat.fs-active .assistant-messages,
.on-site-chatbody.fs-active .messages-container {
  flex: 1 1 0%; min-height: 0; max-height: none;
}
.on-site-chatbody.fs-active { background: var(--bg); padding: 2.5rem 0 0; }
.on-site-chatbody.fs-active .on-site-footer { flex-shrink: 0; }

/* A fullscreened markdown editor (system prompt, memory, on-site composer) fills
   the whole height — grow the EasyMDE stack (wrap → container → CodeMirror).
   EasyMDE's minHeight pins .CodeMirror-scroll at 300px, so override it. */
.mde-editor-wrap.fs-active {
  /* No top padding — the injected .fs-title is the top bar and must align with
     the fixed ✕ (top:10). Extra top padding pushed the title onto a 2nd line. */
  display: flex; flex-direction: column; padding: 0 1rem 1rem; background: var(--bg); overflow: hidden;
}
/* The title bar spans the editor's full width (cancel the wrap's side padding) so
   it reads as a proper header row with the ✕. */
.mde-editor-wrap.fs-active > .fs-title { margin: 0 -1rem; padding-left: 1rem; }
.mde-editor-wrap.fs-active .EasyMDEContainer {
  flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; width: 100%;
}
.mde-editor-wrap.fs-active .EasyMDEContainer .CodeMirror {
  flex: 1 1 auto; min-height: 0 !important; height: auto !important;
}
.mde-editor-wrap.fs-active .EasyMDEContainer .CodeMirror-scroll { min-height: 0 !important; }
/* When the composer's button row is relocated INTO the editor (has-actions),
   keep it out of the way at the bottom-right of the fullscreen editor. */
.mde-editor-wrap.fs-active .composer-fs-btn { display: none; }

/* Send/edit disabled while the mediator is reacting (visible but blocked). */
.send-btn.mediator-busy { opacity: 0.5; cursor: wait; }
.edit-btn.mediator-busy-hidden { display: none !important; }

/* OTH temporary-block banner (replaces the composer while blocked). */
.composer-blocked {
  padding: 0.9rem 1rem; text-align: center;
  background: rgba(248, 113, 113, 0.08); border-top: 1px solid #f87171;
}
.composer-blocked-title { font-weight: 600; color: #fca5a5; }
.composer-blocked-until { margin-top: 0.25rem; }
.composer-blocked-countdown { margin-top: 0.15rem; font-variant-numeric: tabular-nums; }

.action-picker-section.fs-active {
  display: flex; flex-direction: column; overflow: hidden; padding: 0px 5px 0px 5px;
}
.action-picker-section.fs-active .action-picker {
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin-bottom: 5px;
}
.action-picker-section.fs-active .action-picker-list {
  flex: 1 1 auto; min-height: 0; max-height: none;
}
.doc-inline { max-width: 60rem; line-height: 1.55; }
.doc-page { max-width: 100%; line-height: 1.55; }
.doc-page > header { margin-bottom: 1rem; }
.doc-info-lead { color: var(--muted); margin: 0 0 1rem; }

.doc-frontmatter {
  width: 100%;
  margin: 0.75rem 0 1.25rem;
  border: 1px solid var(--surface2);
  border-radius: 6px;
  background: var(--surface);
}
.doc-frontmatter > summary {
  cursor: pointer;
  padding: 0.5rem 0.75rem;
  font-weight: 600;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  user-select: none;
  border-bottom: 1px solid var(--surface2);
}
.doc-frontmatter[open] > summary {
  border-bottom: 1px solid var(--surface2);
}
.doc-frontmatter:not([open]) > summary {
  border-bottom: none;
}
.doc-meta-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
.doc-meta-table th,
.doc-meta-table td {
  padding: 0.45rem 0.75rem;
  border-bottom: 1px solid var(--surface2);
  text-align: left;
  vertical-align: top;
}
.doc-meta-table tr:last-child th,
.doc-meta-table tr:last-child td { border-bottom: none; }
.doc-meta-table th {
  width: 12rem;
  white-space: nowrap;
  color: var(--muted);
  font-weight: 600;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.doc-meta-table td { color: var(--text); }
.doc-meta-table td a { color: var(--accent); }
.doc-meta-nested {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.6rem;
  margin: 0;
}
.doc-meta-nested dt { color: var(--muted); font-weight: 600; }
.doc-meta-nested dd { margin: 0; }
.doc-meta-list { margin: 0; padding-left: 1.2rem; }
.doc-meta-list li { margin: 0.1rem 0; }

/* Legacy .doc-body rules kept for backward compatibility with existing
   docs templates. Colors + sizes are inherited from .markdown-body now. */
.doc-body h1 { margin: 1.5rem 0 0.5rem; }
.doc-body h2 { margin: 1.25rem 0 0.4rem; }
.doc-body h3 { margin: 1rem 0 0.3rem; }
.doc-body p, .doc-body ul, .doc-body ol { margin: 0.5rem 0; }
.doc-body ul, .doc-body ol { padding-left: 1.35rem; }
.doc-body li { margin: 0.15em 0; }
.doc-body code {
  background: rgba(0,0,0,0.25);
  padding: 0.05rem 0.35rem;
  border-radius: 3px;
}
.doc-body pre {
  background: #020617;
  padding: 0.75rem 1rem;
  border-radius: 6px;
  overflow-x: auto;
  margin: 0.6rem 0;
}
.doc-body pre code { background: none; padding: 0; }
.doc-body kbd {
  background: var(--surface2);
  border: 1px solid var(--muted);
  border-radius: 3px;
  padding: 0.05rem 0.35rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.doc-platform-switch {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
  margin: 0.5rem 0 1rem;
  color: var(--muted);
}
.doc-plat-link {
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  background: var(--surface2);
  color: var(--muted);
  text-decoration: none;
  border: 1px solid transparent;
}
.doc-plat-link:hover { color: var(--text); }
.doc-plat-link.active { color: var(--accent); border-color: var(--accent); }

.doc-attachments {
  margin-top: 1.25rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--surface2);
}
.doc-attachments h2, .doc-attachments h4 {
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  margin-bottom: 0.4rem;
}
.doc-attachments ul { list-style: none; padding: 0; margin: 0; }
.doc-attachments li { margin: 0.25rem 0; }
.doc-attachments a {
  display: inline-flex;
  gap: 0.4rem;
  align-items: center;
  padding: 0.35rem 0.7rem;
  background: var(--surface2);
  border-radius: 4px;
  text-decoration: none;
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.doc-attachments a::before { content: "⬇"; color: var(--muted); }
.doc-attachments a:hover { background: var(--surface); }

.doc-sources {
  margin-top: 1.25rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--surface2);
}
.doc-sources h2 {
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  margin-bottom: 0.4rem;
  font-size: 0.85rem;
}
.doc-sources ul { list-style: none; padding: 0; margin: 0; }
.doc-sources li { margin: 0.25rem 0; }
.doc-sources a {
  display: inline-flex;
  gap: 0.4rem;
  align-items: center;
  padding: 0.35rem 0.7rem;
  background: var(--surface2);
  border-radius: 4px;
  text-decoration: none;
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.88rem;
}
.doc-sources a::before { content: "📄"; }
.doc-sources a[href$=".pdf"]::before { content: "📕"; }
.doc-sources a[href$=".doc"]::before,
.doc-sources a[href$=".docx"]::before { content: "📝"; }
.doc-sources a[href$=".xls"]::before,
.doc-sources a[href$=".xlsx"]::before { content: "📊"; }
.doc-sources a[href$=".json"]::before { content: "{ }"; font-family: monospace; }
.doc-sources a[href$=".xml"]::before { content: "◇"; }
.doc-sources a[href$=".png"]::before,
.doc-sources a[href$=".jpg"]::before,
.doc-sources a[href$=".jpeg"]::before,
.doc-sources a[href$=".svg"]::before,
.doc-sources a[href$=".webp"]::before,
.doc-sources a[href$=".gif"]::before { content: "🖼️"; }
.doc-sources a[href$=".zip"]::before,
.doc-sources a[href$=".gz"]::before,
.doc-sources a[href$=".tar"]::before { content: "📦"; }
.doc-sources a:hover { background: var(--surface); }

h2 { margin-bottom: 1rem; }
h3 { margin-bottom: 0.75rem; }

.page-head { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1rem; flex-wrap: wrap; }
.page-head h2 { margin-bottom: 0; }
.page-head-spacer { flex: 1; }
.block-new-label {
  display: inline-flex; align-items: center; gap: 0.3rem;
  color: var(--muted); cursor: pointer; user-select: none;
}
.block-new-label input[type="checkbox"] { cursor: pointer; accent-color: var(--accent); width: 14px; height: 14px; }
.block-new-label:has(input:checked) .block-new-text { color: #f87171; font-weight: 600; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  height: 34px;
  padding: 0 1rem;
  background: var(--accent);
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  text-decoration: none;
  line-height: 1;
  white-space: nowrap;
  vertical-align: middle;
}
.btn:hover { opacity: 0.85; }
.btn:disabled, .btn[disabled] { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.btn-sm { height: 34px; padding: 0 0.65rem; }
.btn-save    { background: #27ae60; }
.btn-save:hover { opacity: 0.85; }
.btn-connect { background: #2471a3; }
.btn-connect:hover { opacity: 0.85; }
.btn-danger  { background: #c0392b; }

.login-container {
  width: 100%;
  max-width: 26rem;
  margin: 4rem auto;
  text-align: center;
  padding: 2rem;
  background: var(--surface);
  border-radius: 8px;
}
@media (max-width: 720px) {
  .login-container { margin: 2rem auto; padding: 1.25rem; }
}
.login-container h1 { color: var(--accent); margin-bottom: 0.5rem; }
.login-container p { color: var(--muted); margin-bottom: 2rem; }
.login-buttons { display: flex; flex-direction: column; gap: 0.75rem; }

.flash { padding: 0.75rem 1rem; border-radius: 4px; margin-bottom: 1rem; }
.flash-error { background: var(--danger); }
.flash-success { background: var(--success); }

.accounts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 0.85rem;
  margin-top: 1rem;
}
.accounts-empty { grid-column: 1 / -1; }

.account-card {
  position: relative;
  background: var(--surface);
  border-radius: 8px;
  border: 1px solid var(--surface2);
  border-left: 4px solid var(--muted);
  padding: 0.8rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.linked-account-details-btn {
  position: absolute; top: 0.5rem; right: 0.5rem;
  border: 1px solid var(--surface2); border-radius: 4px;
  background: none; color: var(--muted); cursor: pointer;
  font-size: 1.1rem; padding: 0.15rem 0.4rem; line-height: 1;
}
.linked-account-details-btn:hover { color: var(--accent); border-color: var(--accent); }
.account-card.status-connected { border-left-color: #27ae60; }
.account-card.status-connecting { border-left-color: #f39c12; }
.account-card.status-error { border-left-color: var(--accent); }
.account-card.status-disconnected { border-left-color: var(--muted); }

.account-card-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.account-card-head .account-own {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
  overflow: hidden;
}
.account-own-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-own-name.rename-input { max-width: 100%; }
.account-own-id { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--muted); }
.account-own-sys { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--muted); opacity: 0.7; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  font-weight: 600;
  background: var(--surface2);
  color: var(--text);
  white-space: nowrap;
}
.status-pill-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); flex-shrink: 0; }
.status-pill-connected { background: rgba(39,174,96,0.18); color: #5ef85e; }
.status-pill-connected .status-pill-dot { background: #27ae60; }
.status-pill-connecting { background: rgba(243,156,18,0.18); color: #f5b94e; }
.status-pill-connecting .status-pill-dot { background: #f39c12; }
.status-pill-error { background: rgba(233,69,96,0.18); color: #ff8197; }
.status-pill-error .status-pill-dot { background: var(--accent); }
.status-pill-disconnected { color: var(--muted); }

.account-card-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: auto;
}

.account-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.75rem;
  margin: 0.35rem 0 0.15rem;
  color: var(--muted);
}
.account-meta-item { white-space: nowrap; }
.account-card.status-connected .account-meta-item:first-child { color: #5ef85e; }

.account-error > summary {
  cursor: pointer; color: var(--accent); font-weight: 600; 
}
.account-error .status-error-detail {
  margin: 0.4rem 0 0;
  padding: 0.5rem 0.6rem;
  background: var(--surface2);
  border-radius: 4px;
  white-space: pre-wrap; word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* Connect-page error card */
.card { padding: 0.2rem; background: var(--surface); border-radius: 8px; }
.error-card { border-left: 4px solid var(--danger); }
.success-card { border-left: 4px solid #27ae60; }
.success-card h3 { margin: 0 0 0.4rem; color: #27ae60; }
.error-card h3 { margin: 0 0 0.3rem; }
.error-detail {
  margin: 0.75rem 0;
  padding: 0.75rem 0.9rem;
  background: var(--surface2);
  border-radius: 4px;
  white-space: pre-wrap; word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.error-actions { display: flex; gap: 0.6rem; align-items: center; }
.qr-img { width: 220px; max-width: 100%; border-radius: 8px; background: #fff; padding: 0.5rem; }

.platform-badge {
  display: inline-block;
  padding: 0.15rem 0.4rem;
  background: var(--surface2);
  border-radius: 3px;
  font-weight: 600;
}
.platform-badge-wa { background: #123f31; color: #4fe0a0; }
.platform-badge-fb { background: #16324f; color: #6cb6ff; }

/* Platform logo macro */
.platform-logo { display: inline-flex; align-items: center; gap: 4px; vertical-align: middle; margin-right: 20px; }
.platform-logo svg { display: block; flex-shrink: 0; }
.platform-label { font-weight: 600; }
.platform-wa .platform-label { color: #25D366; }
.platform-fb .platform-label { color: #0099FF; }
.platform-onsite .platform-label { color: #6366f1; }

/* Mediator active highlighting */
.contact-row.mediator-active {
  border-left: 3px solid var(--accent);
  padding-left: calc(1rem - 3px);
  background: rgba(233,69,96,0.07);
}
.contact-row.mediator-active:hover { background: rgba(233,69,96,0.13); }
.text-accent { color: var(--accent) !important; }

/* The active state is signalled by the Mediator-active chip, not by tinting the
   whole header — keep the header background neutral. */

.state-warning { color: #f0a040; margin-top: 0.5rem; }

.mediator-badge {
  display: inline-block;
  padding: 0.15rem 0.4rem;
  background: #1a4a1a;
  border-radius: 3px;
  color: #5ef85e;
  flex-shrink: 0;
}
.muted { color: var(--muted); }
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); display: inline-block; }


/* ── Dashboard connect cards ─────────────────────────────── */
.connect-section { margin-top: 2rem; }
.connect-cards { display: flex; gap: 1rem; flex-wrap: wrap; }
.connect-card {
  flex: 1;
  display: flex; align-items: center; gap: 1rem;
  padding: 1rem 1.25rem; background: var(--surface);
  border-radius: 8px; border: 1px solid var(--surface2);
}
.connect-card-icon {
  width: 48px; height: 48px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.connect-card-body { flex: 1; }
.connect-card-body h4 { margin-bottom: 0.2rem; font-size: 1rem; }
.connect-card-body p { margin: 0; }

/* ── FB login page ───────────────────────────────────────── */
.fb-login-page { width: 100%; }
.fb-login-page h2 { margin-bottom: 1.5rem; }
.fb-login-options { display: flex; flex-direction: column; gap: 1.25rem; }
.fb-login-option.card { background: var(--surface); border-radius: 8px; padding: 1.25rem 1.5rem; border: 1px solid var(--surface2); }
.card-header { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.75rem; }
.card-header h3 { margin: 0; font-size: 1.05rem; }
.option-badge { font-weight: 700; padding: 2px 8px; border-radius: 999px; text-transform: uppercase; letter-spacing: 0.05em; }
.option-badge-easy { background: #2a5a2a; color: #9be69b; }
.option-badge-browser { background: #16324f; color: #6cb6ff; }
.fb-steps { margin: 0.5rem 0 1rem 1.25rem; display: flex; flex-direction: column; gap: 0.75rem; }
.fb-steps li { line-height: 1.5; }
.snippet-wrap { margin: 0.5rem 0; }
.code-snippet {
  background: var(--bg); color: #9be69b; padding: 0.75rem 1rem; border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; 
  margin-bottom: 0.4rem; overflow-x: auto; white-space: pre; display: block;
}
.fb-textarea-wrap { margin: 0.75rem 0; }
.fb-textarea-wrap textarea {
  width: 100%; background: var(--bg); color: var(--text);
  border: 1px solid var(--surface2); border-radius: 4px; padding: 0.6rem 0.75rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; resize: vertical;
}
textarea {
  overflow-y: hidden;
  resize: vertical;
}
textarea:focus {
  overflow-y: auto;
}
.cookie-validation { padding: 0.3rem 0; min-height: 1.2em; }
.cookie-validation.ok { color: #9be69b; }
.cookie-validation.warn { color: #f0c040; }
.cookie-validation.error { color: #f08080; }
.fb-form-actions { display: flex; gap: 0.75rem; align-items: center; margin-top: 1.5rem; }
.btn-muted { background: var(--surface2); color: var(--muted); }
.btn-muted:hover { background: var(--surface); color: var(--text); }
.cmd {
  background: var(--bg); color: #9be69b; padding: 0.5rem 0.7rem; border-radius: 4px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; 
  margin: 0.6rem 0; overflow-x: auto; display: block; white-space: pre;
}
.fb-cookie-form { margin-top: 0.75rem; background: var(--surface); padding: 1rem; border-radius: 6px; }
.fb-cookie-form textarea { width: 100%; margin: 0.5rem 0; background: var(--bg); color: var(--text); border: 1px solid var(--surface2); border-radius: 4px; padding: 0.5rem; }

.search-form { display: flex; gap: 0.5rem; margin-bottom: 1.5rem; align-items: center; }
.search-form input { flex: 1; padding: 0.5rem 0.7rem; background: var(--surface); color: var(--text); border: 1px solid var(--surface2); border-radius: 4px; }

.contacts-list { display: flex; flex-direction: column; gap: 0.5rem; }
.contacts-empty { padding: 1.5rem; text-align: center; }

.contacts-help {
  border: 1px solid var(--surface2);
  background: var(--surface);
  border-radius: 8px;
  padding: 0.85rem 1.1rem;
  margin-bottom: 1rem;
}
.contacts-help-lead { font-weight: 600; margin: 0 0 0.35rem; }
.contacts-help-text { margin: 0 0 0.75rem; color: var(--muted); }
.contacts-help-actions { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; }
/* Checkbox embedded inline in the helper sentence — flows with the text. */
.block-new-inline { display: inline-flex; vertical-align: middle; margin: 0; gap: 0.25rem; }

.contact-item {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
}
.contact-item .contact-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border-radius: 6px;
  border: 1px solid transparent;
  text-decoration: none;
  color: var(--text);
  position: relative;
  z-index: 1;
  transition: transform 0.15s ease-out;
  touch-action: pan-y;
}
.contact-item .contact-row:hover { background: var(--surface2); border-color: var(--surface2); }

.contact-swipe-delete {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 5rem;
  z-index: 0;
  margin: 0;
}
.contact-swipe-delete button {
  width: 100%;
  height: 100%;
  border: none;
  background: var(--danger);
  color: #fff;
  font-size: 1.25rem;
  cursor: pointer;
  border-radius: 0 6px 6px 0;
}
.contact-swipe-delete button:hover { background: #7a1a1a; }

.contact-item.swiped .contact-row { transform: translateX(-5rem); }

/* Desktop: reveal the trash button on row hover so the affordance is
   always available without swiping. Below the pointer breakpoint we hide
   it — touch users swipe or long-press instead. */
@media (hover: hover) and (pointer: fine) {
  .contact-swipe-delete { opacity: 0; transition: opacity 0.15s; }
  .contact-item:hover .contact-swipe-delete,
  .contact-item.swiped .contact-swipe-delete { opacity: 1; }
}
.contact-main { flex: 1; display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.contact-name { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.contact-gender { opacity: 0.7; }
.contact-fb-avatar { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.contact-sub { display: flex; gap: 0.4rem; align-items: baseline; color: var(--muted); overflow: hidden; }
.contact-sub .contact-preview { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: 0.85; }
.contact-phone { color: var(--muted); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.contact-detail { display: grid; grid-template-columns: 26% 1fr; gap: 0.5rem; min-height: 0; }
.contact-detail.panel-collapsed { grid-template-columns: 36px 1fr; }
/* Full-bleed app-shell layout (shared with .doc-browser). The body is pinned
   to the viewport (height:100vh + overflow:hidden) ONLY on these pages, via
   :has — so <main> gets a definite height its grid child can fill, and only
   the message list / reader panel scrolls, never the page. Scoped so normal
   pages keep their scrolling body (inline dropdowns never get clipped).
   Robust to main's margin — no fragile vh calc. */
@media (min-width: 720px) {
  body:has(.contact-detail),
  body:has(.doc-browser) { height: 100vh; overflow: hidden; }
  main:has(.contact-detail),
  main:has(.doc-browser) { flex: 1 1 0%; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
  .contact-detail { flex: 1 1 0%; min-height: 0; }
}
@media (max-width: 720px) {
  /* Pin the CHAT page to the VISIBLE viewport on mobile too (scoped via :has so
     other mobile pages keep their normal scrolling body) — so the composer stays
     fixed at the bottom and only the message list scrolls, instead of the whole
     page scrolling and hiding the composer below the fold. Mirrors the desktop
     app-shell pin above; `100dvh` tracks the phone's dynamic (URL-bar) viewport. */
  body:has(.contact-detail) {
    height: 100dvh; overflow: hidden;
    display: flex; flex-direction: column;
  }
  body:has(.contact-detail) > .site-footer { flex-shrink: 0; }
  main:has(.contact-detail) {
    flex: 1 1 0%; min-height: 0; display: flex; flex-direction: column; overflow: hidden;
  }
  .contact-detail,
  .contact-detail.panel-collapsed {
    grid-template-columns: 1fr;
    /* Panel row = its own content height (just the header when collapsed); the chat
       row fills the rest and is allowed to shrink so its message list scrolls and
       the composer stays pinned (minmax(0,1fr), not 1fr). */
    grid-template-rows: auto minmax(0, 1fr);
    align-content: stretch;
    height: auto;
    min-height: 0;
    flex: 1 1 0%;
    gap: 0.75rem;
  }
  /* An EXPANDED settings panel scrolls within its own space instead of pushing the
     chat + composer off-screen (the panel already has overflow-y:auto). */
  .mediator-panel { max-height: 45dvh; }
}

.panel-toggle {
  align-self: flex-end;
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  padding: 2px 4px;
  line-height: 1;
  border-radius: 3px;
  flex-shrink: 0;
}
.panel-toggle:hover { color: var(--text); background: var(--surface2); }

/* Shared by the mediator + docs panels: ONLY the ◶ glyph sticks to the
   top-right so it stays reachable while the panel scrolls; the heading
   scrolls away — no persistent bar over the content. The toggle is a direct
   child of the scroll container (so sticky spans the whole panel) and uses a
   negative bottom margin to share the heading's line instead of sitting
   above it. */
.mediator-panel > .panel-toggle,
.doc-tree-panel > .panel-toggle {
  position: sticky; top: 0; z-index: 10;
  align-self: flex-end;
  background: var(--surface);
  padding: 4px 6px;
  margin: 0 0 -2.1rem 0;
}
.mediator-panel > h3,
.doc-tree-panel > h3 { margin: 0; font-size: 1rem; }

/* Docs breadcrumb — mobile-only header (Docs › Section › Current). Hidden
   on desktop where the corner glyph + scrolling h3 heading are the UI. */
.doc-crumbs { display: none; }

.mediator-panel.collapsed,
.doc-browser.panel-collapsed .doc-tree-panel {
  padding: 0.5rem 0;
  align-items: center;
  overflow: hidden;
  gap: 0;
}
.mediator-panel.collapsed > *:not(.panel-toggle),
.doc-browser.panel-collapsed .doc-tree-panel > *:not(.panel-toggle) { display: none !important; }
.mediator-panel.collapsed > .panel-toggle,
.doc-browser.panel-collapsed .doc-tree-panel > .panel-toggle { align-self: center; margin: 0; }

/* The labelled bar (label left, arrow right) is a phone-only affordance — the
   bare corner glyph reads as an empty line on a narrow screen. On desktop the
   toggle stays a compact corner glyph in every state (expanded or collapsed). */
.panel-toggle-label { display: none; }
@media (max-width: 720px) {
  .mediator-panel .panel-toggle,
  .doc-tree-panel .panel-toggle {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    width: 100%; align-self: stretch; margin: 0;
  }
  .mediator-panel .panel-toggle .panel-toggle-label,
  .doc-tree-panel .panel-toggle .panel-toggle-label { display: inline; }
  .mediator-panel > h3,
  .doc-tree-panel > h3 { display: none; }

  /* Docs panel: the toggle shrinks to a corner arrow so the breadcrumb can
     share its line (same negative-margin trick as the heading on desktop).
     Each crumb is a plain link; the current page is a non-link label. */
  .doc-tree-panel .panel-toggle {
    width: auto; align-self: flex-end; margin: 0 0 -2.1rem 0;
  }
  .doc-crumbs {
    display: flex; align-items: center; flex-wrap: nowrap; gap: 0.3rem;
    min-width: 0; padding: 4px 1.75rem 0 0;
    font-size: 1rem; overflow: hidden;
  }
  .doc-crumbs a, .doc-crumbs .doc-crumb-current { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
  .doc-crumbs .doc-crumb-current { font-weight: 600; }
  .doc-crumbs .doc-crumb-sep { color: var(--muted); flex: 0 0 auto; }

  /* Collapsed on mobile: keep the breadcrumb bar visible next to the
     expand arrow — only the tree + heading hide. */
  .doc-browser.panel-collapsed .doc-tree-panel {
    flex-direction: row; align-items: center; gap: 0.3rem; padding: 0.5rem;
  }
  .doc-browser.panel-collapsed .doc-tree-panel > .doc-crumbs {
    display: flex !important; flex: 1 1 auto; min-width: 0; margin: 0;
  }
  .doc-browser.panel-collapsed .doc-tree-panel > .panel-toggle {
    flex: 0 0 auto; margin: 0;
  }
}

.mediator-panel {
  background: var(--surface);
  border-radius: 8px;
  padding: 1rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.mediator-panel textarea {
  width: 100%;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--surface2);
  border-radius: 4px;
  padding: 0.5rem;
  resize: vertical;
}
.mediator-panel hr { border-color: var(--surface2); }
.tool-row { display: flex; justify-content: space-between; align-items: center; padding: 0.4rem 0; }
.add-tool-form { padding: 0.75rem; background: var(--bg); border-radius: 6px; }
.add-tool-form select, .add-tool-form textarea {
  width: 100%;
  margin: 0.4rem 0;
  padding: 0.5rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--surface2);
  border-radius: 4px;
}

.chat-panel {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: 8px;
  overflow: hidden;
}
.chat-panel h3 { padding: 0; border-bottom: none; }

/* ── Documentation browser (tree + reader) ───────────────────────────
   Layout fills the viewport between nav and footer (no page scroll); only
   the reader panel scrolls. Folders are div + arrow-button (NOT
   <details>/<summary>) so the arrow alone toggles and the folder label is
   a plain link — this also kills the Chrome disclosure-marker that shifted
   the summary ~14px between open/closed. */
.doc-browser { display: grid; grid-template-columns: 260px 1fr; gap: 10px; min-height: 0; }
.doc-browser.panel-collapsed { grid-template-columns: 36px 1fr; }
@media (min-width: 720px) {
  .doc-browser { flex: 1 1 0%; min-height: 0; }
}
@media (max-width: 720px) {
  .doc-browser,
  .doc-browser.panel-collapsed {
    grid-template-columns: 1fr;
    min-height: calc(100vh - 120px);
    gap: 0.75rem;
  }
  .doc-browser.panel-collapsed .doc-tree-panel { display: flex; }
}
.doc-tree-panel {
  background: var(--surface); border-radius: 8px; padding: 1rem;
  overflow-y: auto; display: flex; flex-direction: column; gap: 0.75rem;
  position: relative; min-height: 0;
}

.doc-search { margin: 0.4rem 0 0.6rem; }
.doc-search-input {
  width: 100%; box-sizing: border-box; padding: 0.45rem 0.6rem;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--surface2); border-radius: 6px;
}
.doc-search-input:focus { outline: none; border-color: var(--accent); }
.doc-search-results { display: flex; flex-direction: column; gap: 0.15rem; }
.doc-search-hit {
  display: flex; flex-direction: column; gap: 0.15rem;
  padding: 0.5rem 0.55rem; border-radius: 6px; text-decoration: none;
  color: var(--text); border-top: 1px solid var(--surface2);
}
.doc-search-hit:first-child { border-top: 0; }
.doc-search-hit:hover { background: var(--surface2); }
.doc-search-title { font-weight: 600; }
.doc-search-heading { font-weight: 400; color: var(--accent); }
.doc-search-snippet { color: var(--muted); line-height: 1.35; }
.doc-search-empty { padding: 0.5rem 0.55rem; }
.doc-tree { display: flex; flex-direction: column; gap: 1px; align-items: stretch; }
.doc-tree > * { margin-left: 0; }
.doc-tree-link {
  color: var(--text); text-decoration: none; 
  cursor: pointer; flex: 1 1 auto; min-width: 0;
}
/* Folder row: arrow button (toggles) + label (link or plain text). */
.doc-tree-row {
  display: flex; align-items: center; gap: 0.35rem;
  padding: 0.35rem 0.4rem; border-radius: 4px;
}
.doc-tree-row:hover { background: var(--surface2); }
.doc-tree-arrow {
  background: none; border: none; color: var(--muted); cursor: pointer;
  padding: 0; width: 0.9rem; flex: none; text-align: center; 
  display: inline-flex; align-items: center; justify-content: center; line-height: 1;
}
.doc-tree-arrow:hover { color: var(--text); }
.doc-tree-folder-link, .doc-tree-folder-name { font-weight: 600; }
.doc-tree-link.active { color: var(--accent); }
.doc-tree-folder-link.active { color: var(--accent); }
/* Top-level leaves and child links are full-width rows with their own padding. */
.doc-tree-top {
  display: block; padding: 0.35rem 0.4rem; border-radius: 4px; font-weight: 600;
}
.doc-tree-top:hover { background: var(--surface2); }
.doc-tree-top.active { background: var(--accent); color: #fff; }
.doc-tree-children {
  list-style: none; margin: 2px 0 2px 0.85rem; padding: 0;
  border-left: 1px solid var(--surface2);
  display: flex; flex-direction: column; gap: 1px;
}
.doc-tree-children .doc-tree-link {
  display: block; padding: 0.35rem 0.4rem 0.35rem 1.25rem;
  border-radius: 4px; font-weight: 400;
}
.doc-tree-children .doc-tree-link:hover { background: var(--surface2); }
.doc-tree-children .doc-tree-link.active { background: var(--accent); color: #fff; }
.doc-tree-folder.collapsed > .doc-tree-children { display: none; }
.doc-reader-panel {
  overflow-y: auto; background: var(--surface); border-radius: 8px;
  padding: 1.5rem; min-height: 0;
}

/* ── Tool catalog (dynamic {% tools %} block on /docs/integrations/tools) ── */
.tool-catalog { display: flex; flex-direction: column; gap: 0.5rem; }
.tool-toolkit, .tool-cat {
  background: var(--bg); border: 1px solid var(--surface2); border-radius: 6px;
}
.tool-toolkit > summary, .tool-cat > summary {
  cursor: pointer; list-style: none; padding: 0.6rem 0.8rem;
  display: flex; align-items: center; gap: 0.5rem; font-weight: 600;
}
.tool-toolkit > summary::-webkit-details-marker,
.tool-cat > summary::-webkit-details-marker { display: none; }
.tool-toolkit > summary::before, .tool-cat > summary::before {
  content: "▸"; opacity: 0.55; width: 0.9rem; text-align: center;
  transition: transform 0.12s ease;
}
.tool-toolkit[open] > summary::before, .tool-cat[open] > summary::before { transform: rotate(90deg); }
.tool-logo { width: 20px; height: 20px; object-fit: contain; flex: none; border-radius: 3px; }
.tool-count { margin-left: auto; font-weight: 400; color: var(--muted); }
.tool-toolkit-body { padding: 0 0.5rem 0.5rem; display: flex; flex-direction: column; gap: 0.4rem; }
.tool-cat-body { padding: 0 0.5rem 0.4rem; display: flex; flex-direction: column; gap: 0.5rem; }
.tool-card { background: var(--surface); border: 1px solid var(--surface2); border-radius: 5px; padding: 0.6rem 0.75rem; }
.tool-name { margin: 0 0 0.2rem; display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.tool-slug { font-weight: 400; color: var(--muted); }
.tool-badge {
  padding: 0 0.35rem; border-radius: 3px;
  background: var(--surface2); color: var(--text);
}
.tool-badge-deprecated { background: #5a2a2a; color: #ffb3b3; }
.tool-badge-used { background: #1e3a2a; color: #4ade80; }
.tool-desc { margin: 0 0 0.4rem; font-size: 1rem; color: var(--muted); }
.tool-params { width: 100%; border-collapse: collapse; font-size: 1rem; }
.tool-params th, .tool-params td { border: 1px solid var(--surface2); padding: 0.3rem 0.45rem; text-align: left; vertical-align: top; }
.tool-params th { background: var(--bg); font-weight: 600; }
.tool-params-empty { margin: 0; color: var(--muted); font-style: italic; }
.chat-header { padding: 1rem; border-bottom: 1px solid var(--surface2); }
.chat-head { display: flex; align-items: center; gap: 0.5rem 0.75rem; flex-wrap: wrap; }
.chat-head .rename-wrap { display: inline-flex; align-items: center; gap: 0.6rem; }
.chat-head-name-group { display: inline-flex; align-items: center; gap: 0.35rem; }
.chat-head-gender { opacity: 0.7; }
/* Controls (mediator chip, prompt-preview, platform badge, block badge) sit as
   one group pushed to the right edge of the header. */
.chat-head-controls { display: inline-flex; align-items: center; gap: 0.5rem; margin-left: auto; flex-shrink: 0; margin-right: 20px; }

/* Mobile: tighten the header. The meta wraps under the name; controls stay on
   the top row (name row) pushed right, so the header stays compact. */
@media (max-width: 640px) {
  .chat-header { padding: 0.6rem 0.75rem; }
  .chat-head { gap: 0.3rem 0.5rem; }
  .contact-meta { flex-basis: 100%; order: 3; gap: 0.25rem 0.75rem; }
  .chat-head-controls { gap: 0.35rem; }
  /* Collapse the mediator chip to just its emoji to save width. */
  .chat-head-controls .mediator-active-chip .chip-text { display: none; }
  .platform-label { display: none; }
}
.rename-name { font-size: 1.15rem; font-weight: 700; }
.rename-wrap .btn-sm:not(.btn-save):not(.btn-danger) { background: var(--surface2); }
.rename-wrap .btn-sm:not(.btn-save):not(.btn-danger):hover { background: var(--accent); }
.rename-form { display: inline-flex; gap: 0.4rem; align-items: center; }
.rename-form input { padding: 0.35rem 0.55rem; background: var(--bg); color: var(--text); border: 1px solid var(--surface2); border-radius: 4px; font-size: 1rem; min-width: 200px; }

.contact-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 1.25rem; }
.meta-field { display: flex; flex-direction: row; align-items: baseline; gap: 0.35rem; min-width: 0; }
.meta-chat-link { align-self: center; }
/* Detected conversation-language chip (both chat headers). */
.lang-chip {
  align-self: center; white-space: nowrap; cursor: default;
  color: var(--text); background: var(--surface2);
  border-radius: 10px; padding: 1px 8px;
  display: inline-flex; align-items: center; gap: 0.35rem;
}
.on-site-lang { margin-left: 0.4rem; }
.lang-chip .lang-lead { font-size: 1em; }
.lang-chip .lang-you-wrap,
.lang-chip .lang-them-wrap { display: inline-flex; align-items: center; gap: 0.25rem; }
/* The two sides of the chip are visually distinct so it's clear which language
   is yours (an editable picker) vs the other party's (display-only). */
.lang-chip .lang-side.lang-you  { color: var(--accent); font-weight: 600; }
.lang-chip .lang-side.lang-them { color: #46c76a; font-weight: 600; }
.lang-chip .lang-them-val { font-weight: 600; }
.lang-chip .lang-lock { font-size: 0.85em; opacity: 0.75; cursor: help; }
/* A side whose language is DETERMINED (user-picked or auto-detection locked): a
   green ✓ + a soft green wash so it reads as "settled". */
.lang-chip .lang-final { color: #46c76a; font-weight: 700; cursor: help; }
.lang-chip .lang-determined {
  background: rgba(70, 199, 106, 0.14); border-radius: 8px; padding: 0 5px;
}
/* The embedded language picker (viewer's own side) is a compact inline control,
   not the full-width header dropdown — override the nav sizing. */
.lang-chip .ts-wrapper.nav-locale { min-width: 0; margin: 0; }
.lang-chip .ts-wrapper.nav-locale .ts-control {
  min-height: 0; padding: 1px 18px 1px 6px; background: var(--surface); font-weight: 600;
}
.lang-chip .ts-wrapper.single .ts-control { border-radius: 8px; }
.meta-fb-avatar-wrap { flex-direction: row; align-items: center; gap: 0.5rem; }
.meta-fb-avatar { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.meta-fb-gender { font-size: 1rem; opacity: 0.8; }
.meta-label { text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.meta-value { word-break: break-all; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* .mediator-panel label forces column; scope-match specificity so the checkbox row stays inline. */
.checkbox-label, .mediator-panel label.checkbox-label { display: flex; flex-direction: row; align-items: center; gap: 0.45rem; font-weight: 600; cursor: pointer; }
.checkbox-label input { width: 16px; height: 16px; cursor: pointer; }
.field-label { display: block; margin: 0.75rem 0 0.3rem; }

/* Unsaved-change markers (static/form_dirty.js adds .field-dirty to a changed
   control, or to its wrapping [data-dirty-item]/.change-item-element so the
   label is included). An amber outline + a small ⚠ badge make edits obvious;
   the badge's tooltip says "Unsaved change" (data-dirty-title, localized). */
.field-dirty {
  outline: 2px solid #f0a83c; outline-offset: 2px; border-radius: 4px;
  position: relative;   /* anchor for a badge placed directly on the target */
}
/* The EasyMDE box clips its children (overflow:hidden) — let the corner badge
   show when it's the dirty target, and make the yellow border obvious. */
.mde-editor-wrap.field-dirty { overflow: visible; border-color: #f0a83c; }
/* Tight wrapper the dirty badge anchors to, so the ⚠ sits at the CONTROL's
   corner — not at the right edge of a full-width parent row. Sized to the field
   (block, capped like the inputs) with the control filling it. */
.field-dirty-anchor { position: relative; display: block; max-width: 480px; }
.field-dirty-anchor > input, .field-dirty-anchor > select, .field-dirty-anchor > textarea { width: 100%; }
/* Real ⚠ badge node (form_dirty.js inserts it; a CSS ::after can't render on a
   void <input>/<select>). Sits at the anchor's top-right corner. */
.field-dirty-badge {
  position: absolute; top: -1px; right: -9px; z-index: 3;
  width: 18px; height: 18px; border-radius: 50%;
  background: #f0a83c; color: #1a1200; font-size: 11px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 1px 3px rgba(0,0,0,0.4); cursor: help;
}
/* When the wrapper is flagged, tint the label too so it's unmistakable. */
.field-dirty .field-label, .field-dirty > label { color: #f0a83c; }
/* The action picker manages its OWN dirty cue on the visible section (its hidden
   `_actions_state` sentinel drives form-level dirty but must not show a stray
   badge down by the Save button). */
.field-dirty-anchor:has(> input[name="_actions_state"]) > .field-dirty-badge { display: none; }
/* In fullscreen the section is fixed inset:0, so a top:-9/right:-9 badge lands
   off-screen — pull it inside, left of the ✕. Drop the edge outline there too. */
.action-picker-section.fs-active.field-dirty { outline: none; }
.action-picker-section.fs-active > .field-dirty-badge { top: 12px; right: 52px; }
/* Slider fields flag the whole visible field (data-dirty-item) — tint the label
   and move the ⚠ to the TOP-LEFT so it never overlaps the value output at the
   top-right. */
.slider-field.field-dirty { color: #f0a83c; }
.slider-field.field-dirty > .field-dirty-badge { right: auto; left: -9px; }

/* Timezone picker: select at a normal field width with the Detect button inline
   beside it (not a full-width select with the button dropped underneath). */
.tz-picker-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: nowrap; }
.tz-picker-row .ts-wrapper { max-width: 24rem; width: 100%; }
.tz-picker-row #pf-timezone-detect,
.tz-picker-row #pf-timezone-map-btn { flex: 0 0 auto; white-space: nowrap; }
/* Two-line option: human name (with GMT offset) over the system id. */
.tz-opt .tz-opt-main { display: block; }
.tz-opt .tz-opt-sub { display: block; opacity: 0.55;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.tz-opt .tz-off { color: var(--accent); font-variant-numeric: tabular-nums; }
/* Clickable timezone map (fullscreen host). Bands highlight on hover/selected. */
/* The map host only exists as a fullscreen overlay — hidden inline so it never
   lingers under the field after close (it's opened via Fullscreen.open). */
.tz-map-host { display: none; }
.tz-map-host.fs-active {
  display: flex; flex-direction: column; overflow: hidden;
}
/* AI prompt preview: icon-only header button + read-only fullscreen overlay. */
.prompt-preview-btn {
  background: none; border: none; cursor: pointer; padding: 2px 4px;
  font-size: 1rem; line-height: 1; opacity: 0.6; transition: opacity .15s;
}
.prompt-preview-btn:hover { opacity: 1; }
.prompt-preview-host { display: none; }
.prompt-preview-host.fs-active { display: block; padding: 0rem 1.5rem 0rem; }
.prompt-preview-host .prompt-preview-tools { list-style: none; padding: 0; }
.prompt-preview-host .prompt-preview-tools > li {
  padding: 0.5rem 0; border-top: 1px solid var(--surface2);
}
.prompt-preview-host .prompt-preview-tools > li:first-child { border-top: 0; }
/* Structured-actions list (REPLY/MARK/… with every param the AI sees). */
.prompt-preview-host .prompt-preview-actions { list-style: none; padding: 0; }
.prompt-preview-host .prompt-preview-actions > li {
  padding: 0.6rem 0; border-top: 1px solid var(--surface2);
}
.prompt-preview-host .prompt-preview-actions > li:first-child { border-top: 0; }
.prompt-preview-host .pp-action { font-weight: 700; font-size: 1rem; }
.prompt-preview-host .prompt-preview-params {
  list-style: none; margin: 0.4rem 0 0; padding: 0 0 0 1rem;
  border-left: 2px solid var(--surface2);
}
.prompt-preview-host .prompt-preview-params > li { padding: 0.3rem 0; }
.prompt-preview-host .pp-type { color: var(--muted); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.prompt-preview-host .pp-req {
  text-transform: uppercase; letter-spacing: 0.04em;
  color: #fca5a5; border: 1px solid #f87171; border-radius: 4px; padding: 0 0.35rem;
}
.prompt-preview-host .pp-opt {
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted); border: 1px solid var(--surface2); border-radius: 4px; padding: 0 0.35rem;
}
.prompt-preview-host .prompt-preview-params .muted.small { margin-top: 0.15rem; }
/* Hint sits ABOVE the map, aligned with the ✕ (which is fixed top:10px), big
   enough to read as the overlay's title. Right-padded so it clears the ✕. */
.tz-map-hint {
  margin: 0 0 0.75rem; padding-right: 3rem; flex-shrink: 0;
  font-size: 1.05rem; font-weight: 600; color: var(--text);
}
.tz-map-inner svg.tz-world { width: 100%; height: 100%; display: block; border-radius: 6px; cursor: grab; touch-action: none; }
.tz-map-inner svg.tz-world.tz-panning { cursor: grabbing; }
/* Bands are VISUAL ONLY — pointer-events off so hovering a country is never
   intercepted by the full-height band overlay sitting on top of the land. */
.tz-map-inner .tz-bands { pointer-events: none; }
.tz-map-inner .tz-bands [data-tz] rect { transition: fill-opacity .1s, fill .1s; }
/* The SELECTED zone's UTC band (matched by offset) → clear RED column. */
.tz-map-inner .tz-bands [data-tz].tz-selected rect {
  fill: #ff5a5a !important; fill-opacity: 0.28 !important;
  stroke: #ff5a5a !important; stroke-opacity: 0.75 !important; stroke-width: 1 !important;
}
/* Live hover preview → GREEN column (follows the mouse). Placed AFTER the red
   rule so hovering the selected band still shows the green preview. */
.tz-map-inner .tz-bands [data-tz].tz-band-hover rect {
  fill: #46c76a !important; fill-opacity: 0.38 !important;
  stroke: #46c76a !important; stroke-opacity: 0.8 !important; stroke-width: 1 !important;
}
/* Always-visible country borders (the baked-in stroke is too faint). */
.tz-map-inner .tz-land path,
.tz-map-inner .tz-slices path {
  stroke: #56688c; stroke-width: 0.6;
  vector-effect: non-scaling-stroke; transition: fill .12s;
}
/* Multi-zone country slices: alternating tint so the timezone divisions read
   at a glance; a darker seam separates neighbours. */
.tz-map-inner .tz-slice-even { fill: #2b3a55; }
.tz-map-inner .tz-slice-odd  { fill: #37496b; }
.tz-map-inner .tz-slice { stroke: #17223b; stroke-width: 0.5; }
.tz-map-inner .tz-cc-base { fill: #2b3a55; }
/* Selected offset → bright fill + white outline (countries AND slices). */
.tz-map-inner [data-cc].tz-cc-selected {
  fill: var(--accent) !important;
  stroke: #fff !important; stroke-width: 1 !important;
}
/* Hover a country/slice → green highlight + custom name tooltip. */
.tz-map-inner [data-cc].tz-cc-hover { fill: #46c76a !important; cursor: pointer; }
/* Browser-detected country → gold dashed border so the user sees "you are here". */
.tz-map-inner [data-cc].tz-cc-detected {
  stroke: #fbbf24 !important; stroke-width: 2 !important;
  stroke-dasharray: 4 2; filter: drop-shadow(0 0 3px rgba(251,191,36,.6));
}
/* Localized list of the selected zone's countries, under the map. */
.tz-selected-countries { padding: 0.6rem 1rem 0.2rem; line-height: 1.5; flex-shrink: 0; }
.tz-selected-countries .tz-selected-label { font-weight: 600; margin-right: 0.4rem; }
.tz-selected-countries .tz-selected-list { color: var(--muted); }
.tz-map-inner { position: relative; flex: 1; min-height: 0; overflow: hidden; }
/* Google-style zoom controls, stacked at the map's bottom-right. */
.tz-map-zoom {
  position: absolute; right: 1.2rem; bottom: 5rem; z-index: 8;
  display: flex; flex-direction: column; gap: 1px;
  border-radius: 8px; overflow: hidden; box-shadow: 0 2px 10px rgba(0,0,0,.4);
}
.tz-zoom-btn {
  width: 40px; height: 40px; border: none; cursor: pointer;
  background: var(--surface); color: var(--text);
  font-size: 1.35rem; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.tz-zoom-btn:hover { background: var(--surface2); }
.tz-zoom-btn + .tz-zoom-btn { border-top: 1px solid var(--surface2); }
.tz-map-tip {
  position: absolute; z-index: 6; pointer-events: none; white-space: nowrap;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--surface2); border-radius: 6px; padding: 0.3rem 0.55rem;
  box-shadow: 0 4px 14px rgba(0,0,0,.35);
}
.tz-map-host.fs-active .tz-map-inner { max-width: 1100px; margin: 0 auto; }
.tz-detected-badge:not(:empty) {
  font-size: 0.85rem; color: var(--muted); padding: 0.15rem 0.5rem;
  border: 1px dashed #fbbf24; border-radius: 4px; white-space: nowrap;
}
.tz-detected-badge:not(:empty)::before { content: "📍 "; }

/* Range slider (History limit / Rate limit on the contact panel) — noUiSlider,
   themed to the app accent. Only layout + accent overrides; the base widget
   styling comes from vendor/nouislider/nouislider.min.css. */
.slider-field .slider-label {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem;
}
.slider-field .slider-value {
  font-variant-numeric: tabular-nums; font-weight: 600; color: var(--accent);
  min-width: 2.5ch; text-align: right;
}
.slider-field .slider-ui { margin: 0.6rem 0.4rem 0.4rem; }
/* !important because vendor/nouislider.min.css loads AFTER style.css (in the
   page's extra_head) and would otherwise win the cascade. */
.slider-ui.noUi-target {
  height: 5px !important; border: none !important; background: var(--surface2) !important;
  box-shadow: none !important;
}
.slider-ui .noUi-connect { background: var(--accent) !important; }
.slider-ui .noUi-handle {
  width: 19px !important; height: 19px !important;
  right: -7px !important; top: -8px !important;
  border-radius: 50%; background: var(--accent); border: 2px solid var(--surface);
  box-shadow: 0 1px 3px rgba(0,0,0,0.4); cursor: pointer;
}
.slider-ui .noUi-handle::before, .slider-ui .noUi-handle::after { display: none !important; }
.slider-ui .noUi-handle:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.delete-contact-form { margin-top: 1rem; }

.add-contact-details { position: relative; display: inline-block; }
.add-contact-details > summary { list-style: none; cursor: pointer; }
.add-contact-details > summary::-webkit-details-marker { display: none; }
.add-contact-form-wrap {
  position: absolute; top: calc(100% + 0.4rem); right: 0; z-index: 5;
  background: var(--surface); border: 1px solid var(--surface2);
  border-radius: 6px; padding: 0.75rem;
  width: min(340px, calc(100vw - 1.5rem));
}
.add-contact-form-wrap p { margin-bottom: 0.5rem; }
.add-contact-form {
  display: flex; flex-direction: column; gap: 0.4rem;
}
.add-contact-form input { padding: 0.4rem 0.5rem; background: var(--bg); color: var(--text); border: 1px solid var(--surface2); border-radius: 4px; }

.fb-search-input {
  width: 100%;
  padding: 0.4rem 0.5rem;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--surface2);
  border-radius: 4px;
  box-sizing: border-box;
}
.fb-search-options {
  display: flex; align-items: center; gap: 0.35rem;
  margin-top: 0.4rem; color: var(--muted); cursor: pointer;
}
.fb-search-options input[type="checkbox"] { cursor: pointer; accent-color: var(--accent); width: 13px; height: 13px; }
.fb-search-results-wrap { margin-top: 0.5rem; max-height: 300px; overflow-y: auto; }
.fb-search-results { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.fb-search-result {
  display: flex; align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.4rem;
  border-radius: 4px;
  border-left: 2px solid transparent;
}
.fb-result-friend { background: var(--surface2); border-left-color: #4ade80; }
.fb-result-stranger { background: var(--surface); border-left-color: var(--muted); }
.fb-result-stranger .fb-result-form .btn-save {
  background: transparent; border: 1px solid var(--muted); color: var(--muted);
}
.fb-result-stranger .fb-result-form .btn-save:hover { border-color: var(--text); color: var(--text); }
.fb-avatar {
  width: 34px; height: 34px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
}
.fb-avatar-placeholder { background: #3a3a3a; }
.fb-result-info { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.fb-result-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fb-result-altname { font-style: italic; }
.fb-result-form { flex-shrink: 0; margin-left: auto; }
.fb-result-exists { flex-shrink: 0; margin-left: auto; }
.fb-search-count { color: var(--muted); margin-top: 0.25rem; }

.messages-container {
  flex: 1;
  overflow-y: auto;
  scrollbar-gutter: stable;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.message {
  position: relative;
  max-width: 80%;
  padding: 0.5rem 0.75rem;
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin-bottom: 14px;
}
.message-oth { background: var(--oth); align-self: flex-start; border-bottom-left-radius: 3px; }
.message-own { background: var(--own); align-self: flex-end; border-bottom-right-radius: 3px; }
.message-ai  { background: var(--ai);  align-self: flex-end; border: 1px solid #2a5a2a; border-bottom-right-radius: 3px; }
/* AI bubble that primarily addresses OWN — accent border so OWN can tell at a
   glance the mediator is talking to them, not to OTH. */
/* Accent border when the AI reply addresses THE VIEWER (OWN on admin, OTH on-site) —
   set via `msg-to-viewer` so each side highlights only messages aimed at them. */
.message-ai.msg-to-viewer { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
/* "→ {name}" chip next to the 🤖, only on viewer-addressed AI bubbles. */
.msg-addressee-tag {
  position: absolute;
  top: -14px;
  right: 52px;
  z-index: 20;
  line-height: 1;
  font-weight: 600;
  color: var(--accent);
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: 8px;
  padding: 2px 5px;
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}
.chat-mirrored .message-ai.msg-to-viewer .msg-addressee-tag { right: auto; left: 52px; }
/* Per-message AI cost in the footer — muted mono, beside the tick. The inner
   .money span is re-rendered by Money.refreshAll() if currencies convert. */
.msg-cost { color: var(--muted); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; opacity: 0.9; }

/* ── Mirrored layout ─────────────────────────────────────────────────
   Used when the viewer is OTH (e.g. the public on-site chat link).
   From OTH's perspective, their own messages should appear on the right,
   and OWN/AI on the left. Wrap the messages-container with .chat-mirrored
   to swap sides without changing any DOM. */
.chat-mirrored .message-oth {
  align-self: flex-end;
  border-bottom-left-radius: 12px;
  border-bottom-right-radius: 3px;
}
.chat-mirrored .message-own,
.chat-mirrored .message-ai {
  align-self: flex-start;
  border-bottom-right-radius: 12px;
  border-bottom-left-radius: 3px;
}
/* Top-corner badge cluster: sender icon (👤/🤖), the AI run-🤖 on a MARKed
   message, and the AI mark emoji all sit in ONE flex row so they line up side by
   side and never overlap — however many are present (multi-run notes add more
   🤖 into the same row via JS). This container is the only absolutely-positioned
   piece; its children flow with flex. */
.message-badges-top {
  position: absolute;
  top: -12px;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 4px;
}
.message-oth .message-badges-top { left: 6px; }
.message-own .message-badges-top,
.message-ai  .message-badges-top { right: 6px; }
.chat-mirrored .message-oth .message-badges-top { left: auto; right: 6px; }
.chat-mirrored .message-own .message-badges-top,
.chat-mirrored .message-ai  .message-badges-top { right: auto; left: 6px; }

.msg-sender-label {
  font-size: 13px;
  line-height: 1;
  opacity: 0.9;
  pointer-events: none;
  user-select: none;
}
/* Give space above for the part that sticks out beyond the bubble */
.message-own, .message-ai, .message-oth { margin-top: 10px; }
.message-content { word-break: break-word; }
.message-images-container {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 4px;
}
.message-image-wrap { display: block; }
.message-image {
  max-width: 200px;
  max-height: 200px;
  border-radius: 6px;
  display: block;
  cursor: zoom-in;
  object-fit: cover;
}

/* Lightbox overlay */
/* Lightbox handled by GLightbox library (see _head.html for CSS import) */

/* Emoji badge chips — float just below the bubble border */

/* AI mark badge — a flex item inside .message-badges-top (no absolute
   positioning; the cluster handles placement + spacing). */
.message-mark-badge { display: flex; align-items: center; }

/* Per-bubble "show original / show translation" chip (incoming translation).
   Lives in the top badge cluster: a 文A translate glyph + a persistent state
   word ("Translated" / "Original") so it's clear WITHOUT a tooltip (mobile). The
   colour also encodes the state: accent = you're reading the translation, muted
   = you're reading the original. */
.translate-toggle {
  display: inline-flex; align-items: center; gap: 3px;
  border: 1px solid transparent; border-radius: 8px; cursor: pointer;
  padding: 0 5px; height: 20px; line-height: 1; user-select: none;
  font-weight: 600;
}
.translate-toggle .tr-icon { letter-spacing: -1px; }
.translate-toggle .tr-state { text-transform: uppercase; letter-spacing: 0.02em; }
/* Reading the TRANSLATION (default) → accent. */
.translate-toggle.showing-translated {
  color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
}
/* Reading the ORIGINAL → muted/grey. */
.translate-toggle.showing-original {
  color: var(--muted); background: var(--surface2); border-color: var(--surface2);
}
/* Sanitized layer present (🧼) → green tint when showing the processed text, so
   it reads distinctly from a pure translation. */
.translate-toggle.has-clean.showing-translated {
  color: color-mix(in srgb, var(--success), var(--text) 45%);
  background: color-mix(in srgb, var(--success) 22%, transparent);
  border-color: color-mix(in srgb, var(--success) 50%, transparent);
}
.translate-toggle:hover { filter: brightness(1.15); }

/* OWN/OTH reaction badges - BOTTOM corner, horizontal row */
.message-reaction-badges {
  position: absolute;
  bottom: -13px;
  z-index: 1;
  display: flex !important;
  flex-direction: row !important;
  flex-wrap: nowrap !important;
  gap: 6px;
}
.message-oth .message-reaction-badges { left: 10px; }
.message-own .message-reaction-badges,
.message-ai .message-reaction-badges { right: 10px; }

/* Mirrored: swap badge sides too */
.chat-mirrored .message-oth .message-badges { left: auto; right: 10px; }
.chat-mirrored .message-own .message-badges,
.chat-mirrored .message-ai  .message-badges { right: auto; left: 10px; }

.message-mark {
  line-height: 1;
  background: var(--surface);
  border: 1.5px solid var(--surface2);
  border-radius: 10px;
  padding: 1px 5px;
  cursor: default;
  user-select: none;
  white-space: nowrap;
}
.message-reaction {
  line-height: 1;
  background: var(--surface);
  border: 1.5px solid var(--surface2);
  border-radius: 10px;
  padding: 1px 5px;
  cursor: default;
  user-select: none;
  white-space: nowrap;
  flex-shrink: 0;
}
.message-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  gap: 0.25rem;
  min-height: 1em;
}
.message-time { color: var(--muted); margin-left: auto; }
/* AI model id on AI bubbles / note displays — muted, mono, truncated. */
.msg-model {
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  max-width: 9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.85;
}
.oth-note-date .msg-model { margin-left: 0.6em; }
.message-edited { color: var(--muted); cursor: default; user-select: none; }
/* Rolled-back (superseded) AI reply: kept visible with its 🤖 model badge and
   cost, but struck through + dimmed and tagged "replaced" so the spend stays
   auditable while it's clearly no longer the live answer. */
.message-deleted { opacity: 0.6; }
.message-deleted .message-content { text-decoration: line-through; opacity: 0.75; }
.message-deleted .message-footer::before {
  content: "🚫 " attr(data-replaced-label);
  color: var(--muted); font-style: italic; margin-right: 0.4rem;
}
/* Cumulated-cost marker (Σ) on a person's message that absorbed several
   mark-only runs; the full "a + b + …" breakdown is in the title tooltip. */
.msg-cost-cum { font-weight: 600; opacity: 0.8; }

.edit-btn {
  position: absolute;
  bottom: calc(50%);
  left: -8px;
  opacity: 0;
  background: var(--surface2);
  border: 1px solid transparent;
  border-radius: 50%;
  width: 1.35rem;
  height: 1.35rem;
  cursor: pointer;
  padding: 0;
  transition: opacity 0.1s;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
}
.message-own .edit-btn,
.message-ai .edit-btn { left: auto; right: -8px; }
.message:hover .edit-btn { opacity: 1; }
.edit-btn[hidden] { display: none; }

/* Mirrored: OTH bubble is now on the right, so edit-btn goes to the right
   (like OWN/AI in normal mode). OWN/AI move to the left. */
.chat-mirrored .message-oth .edit-btn { left: auto; right: -8px; }
.chat-mirrored .message-own .edit-btn,
.chat-mirrored .message-ai  .edit-btn { right: auto; left: -8px; }

.inline-edit-form { display: flex; gap: 4px; margin-top: 2px; }
.inline-edit-form input { flex: 1; padding: 2px 6px; background: var(--bg); color: var(--text); border: 1px solid var(--surface2); border-radius: 4px; }
.inline-edit-form button { padding: 2px 8px; }

.react-btn {
  position: absolute;
  bottom: calc(50% - 24px);
  left: -8px;
  opacity: 0;
  background: var(--surface2);
  border: 1px solid transparent;
  border-radius: 50%;
  width: 1.35rem;
  height: 1.35rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--muted);
  padding: 0;
  transition: opacity 0.1s;
}
.react-btn[hidden] { display: none; }
.message-own .react-btn,
.message-ai .react-btn { left: auto; right: -8px; }
.message:hover .react-btn { opacity: 1; }
/* Touch devices: no hover — keep the button reachable at reduced opacity */
@media (hover: none) or (pointer: coarse) {
  .react-btn { opacity: 0.55; }
  .react-btn:focus, .message:active .react-btn { opacity: 1; }
}

/* Mirrored: swap react-btn sides */
.chat-mirrored .message-oth .react-btn { left: auto; right: -8px; }
.chat-mirrored .message-own .react-btn,
.chat-mirrored .message-ai  .react-btn { right: auto; left: -8px; }

#reaction-picker {
  position: fixed;
  z-index: 9999;
  background: var(--surface);
  border: 1px solid var(--surface2);
  border-radius: 24px;
  padding: 5px 8px;
  display: flex;
  gap: 2px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.5);
}
#reaction-picker[hidden] { display: none; }
#reaction-picker button {
  background: none;
  border: none;
  font-size: 1.3rem;
  cursor: pointer;
  padding: 4px 5px;
  border-radius: 8px;
  transition: background 0.1s, transform 0.1s;
  line-height: 1;
}
#reaction-picker button:hover { background: var(--surface2); transform: scale(1.2); }
#reaction-picker button.picker-active { background: var(--accent); transform: scale(1.1); }

.own-message-form { padding: 0.75rem; border-top: 1px solid var(--surface2); }
.send-form { display: block; }

#qr-display img { width: 220px; max-width: 100%; border-radius: 8px; }

/* ── Settings page ───────────────────────────────────────── */
.settings-page { width: 100%; }

.settings-section { margin-top: 1.5rem; }
.settings-section h3 { margin-bottom: 0.5rem; }

.integration-list { list-style: none; padding: 0; margin: 0; }
.integration-row {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.5rem 0.75rem; border: 1px solid var(--surface2);
  border-radius: 6px; margin-bottom: 0.5rem;
  background: var(--surface); color: var(--text);
}
.integration-row .integration-logo-chip {
  width: 36px; height: 36px; padding: 4px; flex-shrink: 0;
}
.integration-logo-chip-sm {
  width: 32px !important; height: 32px !important; padding: 3px !important;
  flex-shrink: 0;
}
.integration-connected-info { flex: 1; min-width: 0; }
.integration-connected-info .integration-name { font-weight: 500; }
.integration-connected-info .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.integration-name { font-weight: 500; }
.integration-status { padding: 0.1rem 0.4rem; border-radius: 4px; }
.integration-status.ok    { background: rgba(46, 204, 113, 0.18); color: #7bdca4; }
.integration-status.warn  { background: rgba(233, 69, 96, 0.18);  color: #ff8fa3; }

.integration-toolbar {
  display: flex; gap: 0.5rem; margin: 0.75rem 0 0.25rem 0; align-items: center;
  flex-wrap: wrap;
}
.integration-search-input {
  flex: 1 1 240px;
  padding: 0.5rem 0.75rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--surface2);
  border-radius: 6px;
  min-height: 36px;
}
.integration-search-input:focus { outline: 1px solid var(--accent); border-color: var(--accent); }
.integration-sort {
  padding: 0.5rem 0.75rem;
  background: var(--surface2);
  color: var(--text);
  border: 1px solid var(--surface2);
  border-radius: 6px;
  min-width: 160px;
}

.integration-grid {
  display: grid; gap: 0.5rem; margin-top: 0.75rem;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.integration-card {
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 0.4rem; padding: 0.9rem 0.6rem 0.75rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--surface2);
  border-radius: 10px;
  cursor: pointer;
  transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease;
  text-align: center;
  min-height: 108px;
}
.integration-card:hover {
  background: var(--surface2);
  border-color: var(--accent);
  transform: translateY(-1px);
}
.integration-logo-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  background: #fff;
  border-radius: 10px;
  padding: 6px;
  overflow: hidden;
}
.integration-logo { max-width: 1.3em; -margin-right: 5px; object-fit: contain; }
.integration-logo-fallback {
  font-family: system-ui, sans-serif;
  font-weight: 700; font-size: 1.15rem;
  color: var(--surface2);
}
.integration-card-name {
  color: var(--text);
  font-weight: 500;
  line-height: 1.2;
  word-break: break-word;
}
.integration-card-cat {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.profile-form input[type="text"],
.profile-form input[type="email"],
.profile-form input[type="tel"],
.profile-form input[type="url"],
.profile-form input[type="date"],
.profile-form select {
  width: 100%; max-width: 24rem;
  padding: 0.4rem 0.6rem;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--surface2); border-radius: 6px;
  color-scheme: dark;
}
.profile-form input:focus,
.profile-form select:focus { outline: 1px solid var(--accent); border-color: var(--accent); }
.profile-field { margin-bottom: 0.7rem; }
.profile-field-with-badge {
  display: flex; gap: 0.5rem; align-items: center;
  flex-wrap: nowrap;
}
.profile-field-with-badge .ts-wrapper { flex: 1 1 0; min-width: 0; max-width: none; }
.profile-field-with-badge .ts-wrapper .ts-control { max-width: none; }
.profile-field-with-badge .nav-locale { max-width: none; }
.profile-field-with-badge .btn { flex: 0 0 auto; }
.verified-badge {
  padding: 0.1rem 0.5rem; border-radius: 999px;
  white-space: nowrap;
}
.verified-badge.ok    { background: rgba(46,204,113,0.18); color: #7bdca4; }
.verified-badge.muted { background: var(--surface2); color: var(--muted); }
.bool-yes { color: #7bdca4; font-weight: 600; }
.bool-no  { color: var(--muted); }

.verify-banner {
  display: flex; align-items: center; gap: 1rem;
  padding: 0.75rem 1rem;
  background: rgba(240, 192, 64, 0.10);
  border: 1px solid rgba(240, 192, 64, 0.5);
  border-left: 4px solid #f0c040;
  border-radius: 6px;
  margin: 0.75rem 0 1.25rem;
}
.verify-banner .verify-banner-text { flex: 1; display: flex; flex-direction: column; gap: 0.15rem; color: var(--text); }
.verify-inline {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
  margin-top: 0.35rem;
  padding: 0.35rem 0.5rem;
  background: rgba(240, 192, 64, 0.08);
  border-left: 3px solid #f0c040;
  border-radius: 4px;
  max-width: 480px;
}
.verify-inline .muted { flex: 1; min-width: 200px; }
.section-heading-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.75rem; margin-bottom: 0.25rem;
}
.section-heading-row h3 { margin: 0; }
.profile-gdpr-links {
  margin-top: 1.5rem;
  font-size: 1rem;
  display: flex; gap: 0.75rem; align-items: center;
  color: var(--muted);
}
.profile-gdpr-links a { color: var(--accent); text-decoration: none; }
.profile-gdpr-links a:hover { text-decoration: underline; }

/* Linked social account cards on the Profile page. Same account-card shell
   as Integrations/Contacts. The brand logo (Google G / Facebook f) is the
   primary mark, with the user's provider profile photo as a small avatar
   badge in the corner — a composite "connected as <photo>" chip. */
.linked-account-card .linked-account-brand {
  position: relative; flex-shrink: 0;
  width: 32px; height: 32px; display: inline-flex;
}
.linked-account-card .linked-account-brand .platform-logo { line-height: 0; }
.linked-account-card .linked-account-avatar {
  position: absolute; right: -5px; bottom: -5px;
  width: 18px; height: 18px; border-radius: 50%;
  object-fit: cover; background: #fff;
  border: 2px solid var(--surface);
}
/* Status dot overlaid on the brand logo (replaces the old status-pill). */
.linked-account-card .brand-status-dot {
  position: absolute; top: -7px; right: -7px;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--muted);
  border: 2px solid var(--surface);
}
.linked-account-card.status-connected .brand-status-dot { background: #27ae60; }
.linked-account-card.status-error .brand-status-dot { background: var(--accent); }
.linked-account-card.status-disconnected .brand-status-dot { background: var(--muted); }
.linked-account-details {
  margin-top: 0.5rem;
  padding: 0.35rem 0;
  border-top: 1px solid var(--surface2);
}
.linked-account-details .profile-dl { margin-top: 0.5rem; }

/* Fullscreen-based details (account-details-fs): a "Show details" hint + the ⛶
   trigger (added by fullscreen.js). The body is hidden until expanded, then the
   overlay shows it with room to read. The hint is clickable too (mirrors ⛶). */
.account-details-fs { cursor: pointer; }
.account-details-fs .account-details-hint {
  color: var(--muted); padding: 0.25rem 0; display: inline-block;
}
.account-details-fs:hover .account-details-hint { color: var(--accent); }
.account-details-fs .account-details-body { display: none; }
.account-details-fs.fs-active {
  padding: 2.5rem 1.25rem 1.25rem;
}
.account-details-fs.fs-active .account-details-hint { display: none; }
.account-details-fs.fs-active .account-details-body { display: block; }
.account-details-fs.fs-active .raw-payload,
.account-details-fs.fs-active .raw-payload pre { max-width: 100%; }

/* intl-tel-input — dark theme */
.iti { max-width: 24rem; width: 100%; }
/* intl-tel-input wraps the dropdown in a container div that has its own
   default (white) background. Force every container in the tree to our
   dark surface so nothing peeks through. */
.iti__country-list,
.iti__dropdown-content,
.iti__country-container {
  background: var(--surface) !important;
  color: var(--text) !important;
  border-color: var(--surface2) !important;
}
.iti__country-list { border: 1px solid var(--surface2); }
.iti__country.iti__highlight { background: var(--surface2); }
.iti__country.iti__current {
  background: var(--accent-bg, rgba(99,102,241,.15));
  border-left: 3px solid var(--accent);
}
.iti__selected-country { background: var(--surface2); border-radius: 6px 0 0 6px; }
.iti__selected-country-primary:hover, .iti__selected-country-primary:focus { background: var(--surface2); }
.iti input[type="tel"] { padding-left: 92px !important; }
.iti--separate-dial-code .iti__selected-dial-code { color: var(--text); }
.iti__search-input {
  padding: 0.35rem 0.5rem;
  background: var(--surface) !important;
  color: var(--text) !important;
  border: 1px solid var(--surface2) !important;
}
/* Kill the native search "clear (×)" chip that renders as a bright white
   block on our dark surface. */
.iti__search-input::-webkit-search-cancel-button,
.iti__search-input::-webkit-search-decoration,
.iti__search-input::-webkit-search-results-button,
.iti__search-input::-webkit-search-results-decoration {
  -webkit-appearance: none;
  appearance: none;
  display: none;
}

.export-toolbar {
  display: flex; align-items: center; gap: 0.75rem;
  margin: 0.75rem 0;
  padding: 0.5rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--surface2);
  border-radius: 6px;
  flex-wrap: wrap;
}
.export-toggle { display: inline-flex; align-items: center; gap: 0.3rem; cursor: pointer; }
.export-view {
  background: var(--surface);
  border: 1px solid var(--surface2);
  border-radius: 6px;
  padding: 1rem;
  max-height: 65vh;
  overflow: auto;
}
.export-view.markdown-body table { border-collapse: collapse; width: 100%; margin: 0.5rem 0; }
.export-view.markdown-body th, .export-view.markdown-body td {
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--surface2);
  vertical-align: top;
}
.export-view.markdown-body th { background: var(--surface2); text-align: left; }
.export-view.markdown-body code { background: var(--surface2); padding: 0 0.3rem; border-radius: 3px; }
pre.export-view { white-space: pre-wrap; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* ── .dev-only ─────────────────────────────────────────────────
   Hidden by default, visible when the DEV toggle is ON (body.dev-mode).
   Styled with amber accent to make dev elements visually obvious. */
.dev-only { display: none !important; }
body.dev-mode .dev-only {
  display: initial !important;
  position: relative;
  border-left: 3px solid #f0c040;
  padding-left: 0.5rem !important;
  background: rgba(240, 192, 64, 0.04);
}
body.dev-mode .dev-only::before {
  content: 'DEV';
  position: absolute;
  top: -0.35rem;
  right: -0.35rem;
  background: #f0c040;
  color: #16213e;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 700;
  padding: 0.05rem 0.35rem;
  border-radius: 3px;
  letter-spacing: 0.05em;
  pointer-events: none;
}
body.dev-mode span.dev-only, body.dev-mode a.dev-only { border-left: none; padding-left: 0 !important; background: transparent; }
body.dev-mode span.dev-only::before, body.dev-mode a.dev-only::before { content: 'DEV'; margin-right: 0.35rem; background: #f0c040; color: #16213e; padding: 0.05rem 0.3rem; border-radius: 3px; position: static; font-weight: 700; letter-spacing: 0.05em; }

.raw-payload { margin-top: 0.75rem; }
.raw-payload summary { cursor: pointer; color: var(--muted); }
.raw-payload summary:hover { color: var(--accent); }
.raw-payload h4 { margin: 0.75rem 0 0.25rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.raw-payload pre {
  background: var(--surface2); border: 1px solid var(--surface2); border-radius: 6px;
  padding: 0.6rem 0.75rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--text);
  white-space: pre-wrap; word-break: break-word;
}
.profile-account-head { display: flex; align-items: center; gap: 1rem; margin-bottom: 0.75rem; }
.profile-avatar { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; background: #fff; }
.profile-name { font-size: 1.15rem; font-weight: 600; color: var(--text); }
.profile-dl {
  display: grid; grid-template-columns: max-content 1fr;
  gap: 0.35rem 1rem; margin: 0.5rem 0;
}
.profile-row { display: contents; }
.profile-key { color: var(--muted); }
.profile-val { color: var(--text); word-break: break-word; margin: 0; }
.profile-table {
  width: 100%; border-collapse: collapse; margin-top: 0.5rem;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--surface2); border-radius: 6px; overflow: hidden;
}
.profile-table th, .profile-table td {
  padding: 0.45rem 0.75rem; text-align: left;
  border-bottom: 1px solid var(--surface2);
}
.profile-table th { color: var(--muted); font-weight: 500; text-transform: uppercase; letter-spacing: 0.03em; }
.profile-table tr:last-child td { border-bottom: none; }
.profile-table .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.site-footer {
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--surface2);
  background: var(--surface);
  color: var(--muted);
  display: flex; flex-wrap: wrap;
  align-items: center; gap: 0.5rem;
}
.site-footer a { color: var(--muted); text-decoration: none; }
.site-footer a:hover { color: var(--accent); }
.site-footer .footer-brand { font-weight: 600; color: var(--text); }
.site-footer .footer-sep { opacity: 0.5; }
.site-footer .footer-spacer { flex: 1; }
.site-footer .footer-build { color: var(--muted); }
.site-footer .footer-updated { color: var(--muted); }
.site-footer .footer-cookie-link {
  background: none; border: none; color: var(--muted); cursor: pointer;
  padding: 0; font: inherit; text-decoration: underline;
}
.site-footer .footer-cookie-link:hover { color: var(--accent); }
.site-footer .footer-dev-toggle { display: inline-flex; align-items: center; gap: 0.4rem; cursor: pointer; }
.site-footer .footer-dev-toggle .toggle-label { font-weight: 700; font-size: 0.75rem; letter-spacing: 0.05em; color: #f0c040; }
.site-footer .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.integration-sentinel { height: 1px; }
.integration-category { margin: 1.25rem 0 0.5rem; }
.integration-category-title {
  display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap;
  margin: 0 0 0.4rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  border-bottom: 1px solid var(--surface2);
  padding-bottom: 0.25rem;
  cursor: pointer; user-select: none;
}
.integration-category-toggle {
  background: none; border: none; color: inherit; cursor: pointer;
  padding: 0; line-height: 1;
}
.integration-category.collapsed .integration-grid { display: none; }
.integration-cat-controls { display: inline-flex; gap: 0.4rem; }
.integration-cat-controls[hidden] { display: none; }
.integration-cat-controls button {
  background: var(--surface2); color: var(--text);
  border: 1px solid transparent; border-radius: 999px;
  padding: 3px 10px; cursor: pointer;
}
.integration-cat-controls button:hover { border-color: var(--surface2); background: var(--surface); }
.action-picker { margin-top: 0.5rem; }
.action-picker-list { max-height: 320px; overflow-y: auto; border: 1px solid var(--surface2); border-radius: 6px; padding: 0.5rem; }
.action-row { display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.25rem 0; }
.action-row label { display: block; flex: 1; cursor: pointer; }
.action-row .action-slug { font-family: monospace; color: var(--muted); }
.action-row .action-desc { color: var(--muted); }
.action-row label strong + .action-slug,
.action-row label .action-toolkit-tag + .action-slug { margin-left: 0.4rem; }
.action-row label .action-desc { margin-left: 0.4rem; }
.action-row label .action-desc::before { content: "— "; }
.ai-key-status {
  padding: 0.6rem 1rem; border-radius: 6px; margin-bottom: 1rem; 
}
.ai-key-status.ok { background: #1a3a1a; border: 1px solid #2a5a2a; color: #9be69b; }
.ai-key-status.missing { background: #3a2a0a; border: 1px solid #6a4a10; color: #f0c040; }
.ai-settings-form { display: flex; flex-direction: column; gap: 0.75rem; }
.form-row { display: flex; flex-direction: column; gap: 0.25rem; }
.form-row select, .form-row input[type="text"], .form-row input[type="password"] {
  padding: 0.45rem 0.6rem; background: var(--bg); color: var(--text);
  border: 1px solid var(--surface2); border-radius: 4px; 
}
.form-row select { max-width: 24rem; }
.form-row input[type="text"], .form-row input[type="password"] { max-width: 24rem; }
@media (max-width: 720px) {
  .form-row select,
  .form-row input[type="text"],
  .form-row input[type="password"] { max-width: none; width: 100%; }
}
/* Mask API key visually without type=password (prevents browser save-password prompts) */
.api-key-input { -webkit-text-security: disc; font-family: monospace; }
.model-fetch-row { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.model-fetch-row select { flex: 1; }
.form-actions { display: flex; gap: 0.75rem; align-items: center; margin-top: 1.5rem; }

/* ── AI model catalog (docs page, keyless models.dev reference) ────────────── */
.model-docs { margin-top: 1rem; }
.model-docs-prov { margin-top: 0.75rem; border: 1px solid var(--surface2); border-radius: 8px; background: var(--surface); }
.model-docs-prov > summary { cursor: pointer; padding: 0.6rem 0.9rem; font-weight: 600; user-select: none; }
.model-docs-count { font-weight: 400; color: var(--muted); margin-left: 0.4rem; }
.model-docs-scroll { overflow-x: auto; padding: 0 0.5rem 0.5rem; }
.model-docs-table { width: 100%; border-collapse: collapse; min-width: 820px; }
.model-docs-table th, .model-docs-table td {
  padding: 0.4rem 0.55rem; text-align: left; vertical-align: top;
  border-bottom: 1px solid var(--surface2); white-space: nowrap;
}
.model-docs-table th { text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.model-docs-table .mdl-name { white-space: normal; min-width: 16ch; }
.model-docs-table .mdl-name .model-name { display: block; font-weight: 600; }
.model-docs-table .mdl-name .model-id { opacity: 0.55; font-family: ui-monospace, monospace; }
.model-docs-table .caps-cell { white-space: normal; min-width: 24ch; }
.model-docs-table .caps-cell .cap { margin-right: 2px; }
.model-docs-table .md-caps .md-desc { display: block; margin-top: 0.2rem; }
.model-docs-table .grp-cell { white-space: normal; min-width: 10ch; }
.model-docs-table .md-field { display: block; line-height: 1.35; }
.model-docs-table .md-field b { font-weight: 500; color: var(--muted); margin-right: 0.2rem; }
.model-docs-table .md-field code { word-break: break-word; }
.model-docs-grp td { background: var(--surface2); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text); }
.model-docs-row[data-tech] { cursor: default; }
/* Merged snapshot/alias cluster: one row, plain id list in the name column,
   and per-id values placed in each field's OWN column. */
.model-docs-table .model-id-list { list-style: none; margin: 0.2rem 0 0; padding: 0; }
.model-docs-table .model-id-list > li {
  font-family: ui-monospace, monospace; opacity: 0.75; line-height: 1.5;
}
.model-docs-table .model-id-list > li > code { opacity: 0.85; }
/* A field that varies across the cluster: label + a per-id list of values,
   rendered in the field's own column. The list reuses the global
   `.markdown-body ul` disc-bullet styling — only the tight line-height is
   tuned here for the dense table. */
.model-docs-table .md-varies { display: block; }
.model-docs-table .md-diff-list { margin: 0.1rem 0 0.3rem; }
.model-docs-table .md-diff-list > li { line-height: 1.4; }
.model-docs-table .md-diff-id {
  font-family: ui-monospace, monospace; color: var(--accent);
  margin-right: 0.4ch;
}
@media (max-width: 720px) {
}


/* ── Contact detail: AI key warning ─────────────────────── */
.mediator-no-key {
  background: #3a2a0a; border: 1px solid #6a4a10; color: #f0c040;
  padding: 0.5rem 0.75rem; border-radius: 6px; margin-bottom: 0.75rem;
}
.mediator-no-key a { color: #f0c040; }
input[disabled] + span, input[disabled] ~ * { opacity: 0.5; }
.checkbox-label input[disabled] { cursor: not-allowed; }
.checkbox-label input[disabled] ~ * { cursor: not-allowed; }

/* Toggle switch (Mediator active) — native checkbox, visually a switch. */
.toggle-field { justify-content: space-between; }
.toggle-switch { position: relative; display: inline-flex; flex: 0 0 auto; }
.toggle-switch input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.toggle-track {
  display: inline-block; width: 40px; height: 22px; border-radius: 999px;
  background: var(--surface2); transition: background 0.15s ease; position: relative;
}
.toggle-knob {
  position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.4); transition: transform 0.15s ease;
}
.toggle-switch input:checked ~ .toggle-track { background: var(--accent); }
.toggle-switch input:checked ~ .toggle-track .toggle-knob { transform: translateX(18px); }
/* Indeterminate (e.g. SOME actions enabled) → half-on: dimmed accent + mid knob. */
.toggle-switch input:indeterminate ~ .toggle-track { background: color-mix(in srgb, var(--accent) 45%, var(--surface2)); }
.toggle-switch input:indeterminate ~ .toggle-track .toggle-knob { transform: translateX(9px); }
.toggle-switch input:focus-visible ~ .toggle-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.toggle-switch input[disabled] ~ .toggle-track { opacity: 0.5; cursor: not-allowed; }

/* Header chip mirroring the toggle — only shown when the settings panel is
   collapsed (otherwise the toggle itself is visible in the panel). */
.mediator-active-chip {
  display: none; align-items: center; gap: 0.3rem; font-weight: 600;
  background: var(--surface2); border: 1px solid var(--surface2); border-radius: 999px;
  padding: 0.2rem 0.6rem; cursor: pointer; color: inherit;
  transition: border-color .15s, background .15s;
}
.contact-detail.panel-collapsed .mediator-active-chip { display: inline-flex; }
.mediator-active-chip:hover:not(:disabled) { border-color: var(--accent); }
.mediator-active-chip:disabled { cursor: not-allowed; opacity: 0.6; }
.mediator-active-chip .chip-text { color: var(--muted); }
.mediator-active-chip.on { border-color: var(--accent); }
.mediator-active-chip.on .chip-text { color: var(--accent); }

/* 🧼 sanitize toggle chip in the chat header: full-colour when on, greyed +
   desaturated when off. Click flips it. */
.sanitize-chip {
  border: none; background: transparent; cursor: pointer; line-height: 1;
  font-size: 1.1rem; padding: 0.1rem 0.25rem; border-radius: 6px;
  filter: grayscale(1) opacity(0.45); transition: filter .15s, background .15s;
}
.sanitize-chip.on { filter: none; }
.sanitize-chip:hover { background: var(--surface2); }

/* OTH block badge (mediator BLOCK action / manual). Hidden until blocked. */
.block-badge {
  display: inline-flex; align-items: center; gap: 0.3rem; font-weight: 600;
  background: rgba(248, 113, 113, 0.12); border: 1px solid #f87171;
  border-radius: 999px; padding: 0.15rem 0.3rem 0.15rem 0.6rem; color: #fca5a5;
  cursor: pointer;  /* whole badge unblocks on click */
}
.block-badge:hover { background: rgba(248, 113, 113, 0.22); }
.block-badge.hidden { display: none; }
.block-badge .block-unblock {
  border: none; background: transparent; color: inherit; cursor: pointer;
  width: 1.4rem; height: 1.4rem; border-radius: 50%; line-height: 1;
}
.block-badge .block-unblock:hover { background: #f87171; color: #16213e; }

/* ── Tom Select dark theme ───────────────────────────────── */
.ts-wrapper .ts-control,
.ts-wrapper.single .ts-control {
  background: var(--bg) !important;
  border: 1px solid rgba(255,255,255,0.22) !important;
  color: var(--text) !important;
  border-radius: 4px;
  min-height: 34px;
  box-shadow: none !important;
}
.ts-wrapper.focus .ts-control { border-color: var(--accent) !important; outline: none !important; }
.ts-dropdown {
  background: var(--surface) !important;
  border-color: rgba(255,255,255,0.15) !important;
  color: var(--text) !important;
  border-radius: 4px;
}
.ts-dropdown .option { color: var(--text); }
.ts-dropdown .option:hover,
.ts-dropdown .option.active { background: var(--surface2) !important; color: var(--text) !important; }
/* Keep the CURRENTLY-SELECTED option visibly marked even while hovering other
   rows — TomSelect moves `.active` to the hovered row, which would otherwise
   drop the selected row's highlight. An accent left-bar + tint persists; the
   hover/active row still gets its own `.surface2` background from the rule
   above (a hovered non-selected row), and a hovered selected row keeps both. */
.ts-dropdown .option.selected {
  background: rgba(233, 69, 96, 0.16);
  box-shadow: inset 3px 0 0 var(--accent);
  font-weight: 600;
}
.ts-dropdown .option.selected:hover,
.ts-dropdown .option.selected.active {
  background: rgba(233, 69, 96, 0.24) !important;
}
.ts-dropdown input.dropdown-input {
  background: var(--bg) !important;
  color: var(--text) !important;
  border-bottom-color: rgba(255,255,255,0.12) !important;
}
/* When the dropdown is open, the filter input is its own field — a divider
   plus a fill so it no longer reads as a continuation of the selected item's
   label (which ends in the ⓘ button on the model picker). Kept inline so the
   control height is unchanged. */
.ts-wrapper.nav-locale.dropdown-active .ts-control input,
.ts-wrapper.model-picker.dropdown-active .ts-control input {
  flex: 1 1 30px;
  min-width: 30px;
  margin-left: 6px;
  padding: 0 8px;
  background: var(--surface2) !important;
  border-left: 1px solid rgba(255,255,255,0.18) !important;
  border-radius: 0 !important;
  color:  rgba(255,255,255,0.58);
}
.ts-wrapper.single .ts-control::after {
  border-top-color: #aaa !important;
  border-width: 6px 5px 0 5px !important;
}

/* ── OWN_NOTE (AI internal notes, admin-only) ────────────────────── */
.message-own_note {
  background: #1e1030;
  border: 1px dashed #7c3aed;
  align-self: center;
  max-width: 92%;
  width: 92%;
  color: #c4b5fd;
  border-radius: 8px;
  padding: 0.5rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  margin-bottom: 14px;
}
.own-note-label {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #8b5cf6;
  font-weight: 700;
}
.own-note-info-btn {
  background: none;
  border: none;
  font-size: 1rem;
  cursor: pointer;
  padding: 0 0.25rem;
  opacity: 0.5;
  transition: opacity 0.2s;
  color: #8b5cf6;
}
.own-note-info-btn:hover {
  opacity: 1;
}
.own-note-content {
  display: none;
  margin-left: 0.5rem;
  padding: 0.5rem;
  background: var(--surface2);
  border-radius: 4px;
  border-left: 3px solid #8b5cf6;
}
.message-own_note .message-time {
  color: #6d4fc0;
  align-self: flex-end;
}

/* ── Unread messages ─────────────────────────────────────────────── */
.message-oth.unread {
  outline: 2px solid #3b82f6;
  outline-offset: 1px;
}

/* Unread badge on contact list rows */
.contact-badges {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}
.contact-row .mediator-badge { margin-left: 0; }
.unread-badge {
  background: var(--accent);
  color: #fff;
  border-radius: 999px;
  font-weight: 700;
  min-width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
}

/* ── Settings: AI configured row ────────────────────────────────── */
.ai-configured-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}
.ai-configured-row .ai-key-status { margin-bottom: 0; flex: 1; }
/* The "Model:" segment of the Engine·Model·Key summary reuses the picker's
   model label (caps + name + id + ⓘ). Render it inline within the sentence. */
.ai-summary-model {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  vertical-align: baseline;
}
.ai-summary-model .model-id { opacity: 0.6; }

/* ── Login branded buttons ───────────────────────────────────────── */
.btn-login {
  width: 100%;
  justify-content: center;
  gap: 0.65rem;
  height: 46px;
  border-radius: 6px;
  font-weight: 500;
}
.btn-google {
  background: #fff !important;
  color: #3c4043 !important;
  border: 1px solid #dadce0;
}
.btn-google:hover { background: #f0f0f0 !important; opacity: 1; }
.btn-google span { color: #3c4043; }
.btn-facebook { background: #1877f2; color: white; }
.btn-facebook:hover { background: #166fe5; color: white; opacity: 1; }

/* ── Shared inline-editable style (input & contenteditable) ──────── */
.rename-input,
[contenteditable].inline-edit {
  color: var(--text);
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 4px;
  padding: 2px 6px;
  outline: none;
  font-family: inherit;
  font-size: inherit;
  cursor: text;
}
.rename-input:hover,
[contenteditable].inline-edit:hover { border-color: var(--muted); background: rgba(255,255,255,0.07); }
.rename-input:focus,
[contenteditable].inline-edit:focus { border-color: var(--accent); background: var(--surface2); }

/* ── Rename input specific sizing ─────────────────────────────────── */
.rename-input {
  font-size: 1.15rem;
  font-weight: 700;
  min-width: 40px;
  max-width: 400px;
}

/* ── On-site setup form ──────────────────────────────────────────── */
.on-site-form { display: flex; flex-direction: column; gap: 1rem; margin-top: 1rem; }
.form-group { display: flex; flex-direction: column; gap: 0.3rem; }
.form-group input[type="text"],
.form-group input[type="email"] {
  padding: 0.45rem 0.65rem;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--surface2);
  border-radius: 4px;
  max-width: 440px;
}
.on-site-url-box {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  background: var(--bg);
  border: 1px solid var(--surface2);
  border-radius: 4px;
  padding: 0.5rem 0.75rem;
  margin: 0.5rem 0;
  flex-wrap: wrap;
}
.on-site-url-box a {
  flex: 1;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  word-break: break-all;
}

/* ── On-site link rows in status grid ────────────────────────────── */
.on-site-links { display: flex; flex-direction: column; gap: 0.4rem; padding: 0.5rem 0; }
.on-site-link-row { display: flex; flex-direction: column; gap: 0.1rem; padding: 0.35rem 0.5rem; border-left: 2px solid var(--accent); }
.on-site-link-name { font-weight: 500; }
.on-site-last-msg { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }

/* ── Shared EasyMDE send row (admin chat + on-site) ──────────────── */
.mde-send-row { display: flex; gap: 6px; align-items: flex-end; }
.mde-send-row .mde-editor-wrap,
.mde-send-row .chat-line-input { flex: 1; }
.mde-send-btns { display: flex; flex-direction: row; gap: 4px; align-items: flex-end; flex-shrink: 0; }
.chat-line-input {
  padding: 0.4rem 0.65rem;
  background: var(--bg);
  color: var(--text);
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 6px;
  font-family: system-ui, sans-serif;
  outline: none;
  min-width: 0;
  height: 34px;
  box-sizing: border-box;
}
.chat-line-input:focus { border-color: var(--accent); }
.chat-line-input::placeholder { color: var(--muted); }
.mde-composer-status {
  color: var(--muted);
  padding: 0.1rem 0;
  min-height: 0;
}
.mde-composer-status:empty {
  display: none;
}
/* Small muted icon button for expand/attach */
.btn-ghost {
  background: var(--surface2);
  color: var(--muted);
  border: 1px solid rgba(255,255,255,0.08);
  height: 28px;
  width: 28px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  cursor: pointer;
  line-height: 1;
  flex-shrink: 0;
}
.btn-ghost:hover { background: var(--surface); color: var(--text); opacity: 1; }
.edit-cancel-btn { color: #f87171; border-color: rgba(248,113,113,0.35); }
.edit-cancel-btn:hover { color: #fff; background: #b91c1c; border-color: #b91c1c; }
.edit-cancel-btn[hidden] { display: none; }
/* Composer action buttons (expand ⤢, attach 📎) share the SEND button's look —
   blue, white glyph, same 34px height — for a uniform composer row on every chat
   window. (Cancel-edit ✕ stays red; it's a distinct destructive action.) */
.mde-send-btns .mde-toggle-btn,
.mde-send-btns .attach-btn {
  background: #2471a3; color: #fff; border: none;
  height: 34px; width: 34px; border-radius: 4px;
}
.mde-send-btns .mde-toggle-btn:hover,
.mde-send-btns .attach-btn:hover { background: #2471a3; color: #fff; opacity: 0.85; }
.mde-editor-wrap { border: 1px solid rgba(255,255,255,0.15); border-radius: 6px; overflow: hidden; background: var(--bg); }
/* Buttons overlaid top-right of editor toolbar in expanded mode */
.mde-editor-wrap.has-actions { position: relative; overflow: visible; }
.mde-editor-wrap.has-actions > .mde-send-btns {
  position: absolute;
  top: 0px;
  right: 5px;
  z-index: 10;
  flex-direction: row;
  gap: 4px;
  align-items: center;
}
.mde-editor-wrap .EasyMDEContainer { background: var(--bg); }
.mde-editor-wrap .editor-toolbar { background: var(--surface); border-bottom: 1px solid rgba(255,255,255,0.1); border-top: none; border-left: none; border-right: none; padding: 2px 6px; }
.mde-editor-wrap .editor-toolbar button { color: var(--muted) !important; border-radius: 4px; }
.mde-editor-wrap .editor-toolbar button:hover,
.mde-editor-wrap .editor-toolbar button.active { background: var(--surface2) !important; color: var(--text) !important; }
.mde-editor-wrap .CodeMirror { background: var(--bg); color: var(--text); border: none; font-family: system-ui, sans-serif; min-height: 44px; padding: 6px 10px; display: flex; flex-direction: column; }
/* CodeMirror's vendor `.CodeMirror-scroll { height:100% }` doesn't resolve
   through our flex/max-height chain, so long content is clipped instead of
   scrolled. Make `.CodeMirror` a flex column and let the scroller flex with
   `min-height:0` so it is bounded by the editor height and scrolls — for
   every EasyMDE editor (mediator prompts + chat composer). Always scrollable,
   including when focused; fullscreen needs nothing extra. */
.mde-editor-wrap .CodeMirror-scroll { flex: 1 1 auto; min-height: 0; height: auto; max-height: none; }
.mde-editor-wrap .CodeMirror-cursor { border-left-color: var(--text); }
/* Selection in the markdown editor — CodeMirror's default `#d9d9d9` is
   near-white and swallows light text on the dark editor background, so
   override both the CM selection class and the native ::selection. */
.mde-editor-wrap .CodeMirror-selected,
.mde-editor-wrap .CodeMirror-focused .CodeMirror-selected { background: rgba(99, 155, 255, 0.45) !important; }
.mde-editor-wrap .CodeMirror-line::selection,
.mde-editor-wrap .CodeMirror-line > span::selection,
.mde-editor-wrap .CodeMirror-line > span > span::selection { background: rgba(99, 155, 255, 0.45); }
.mde-editor-wrap .CodeMirror-line ::-moz-selection,
.mde-editor-wrap .CodeMirror-line > span ::-moz-selection { background: rgba(99, 155, 255, 0.45); }
/* ── Prose / markdown block ─────────────────────────────────────
   Shared by: the mediator-editor live preview (`.editor-preview`),
   rendered chat messages (`.message-content`), the GDPR export view
   (`.export-view.markdown-body`), and any HTML-prose page that adds
   `.markdown-body` (legal pages). One source of truth for list
   spacing, headings, code, links. */
.markdown-body p,
.mde-editor-wrap .editor-preview p,
.message-content p { margin: 0 0 0.5em; line-height: 1.5; }
.markdown-body p:last-child,
.mde-editor-wrap .editor-preview p:last-child,
.message-content p:last-child { margin-bottom: 0; }
.markdown-body ul, .markdown-body ol,
.mde-editor-wrap .editor-preview ul, .mde-editor-wrap .editor-preview ol,
.message-content ul, .message-content ol { margin: 0.3em 0 0.5em 0; padding-left: 1.5em; }
.markdown-body ul,
.mde-editor-wrap .editor-preview ul { list-style-type: disc; }
.markdown-body ul ul,
.mde-editor-wrap .editor-preview ul ul { list-style-type: circle; }
.markdown-body ul ul ul,
.mde-editor-wrap .editor-preview ul ul ul { list-style-type: square; }
.markdown-body ol,
.mde-editor-wrap .editor-preview ol { list-style-type: decimal; }
.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4,
.mde-editor-wrap .editor-preview h1,
.mde-editor-wrap .editor-preview h2,
.mde-editor-wrap .editor-preview h3,
.mde-editor-wrap .editor-preview h4 { margin: 0.9em 0 0.35em; }
.markdown-body h1:first-child, .markdown-body h2:first-child, .markdown-body h3:first-child, .markdown-body h4:first-child,
.mde-editor-wrap .editor-preview h1:first-child,
.mde-editor-wrap .editor-preview h2:first-child,
.mde-editor-wrap .editor-preview h3:first-child,
.mde-editor-wrap .editor-preview h4:first-child { margin-top: 0; }
.markdown-body code,
.mde-editor-wrap .editor-preview code { background: rgba(0,0,0,0.25); padding: 0 3px; border-radius: 3px; font-size: 1em; }
.markdown-body pre,
.mde-editor-wrap .editor-preview pre { background: rgba(0,0,0,0.35); padding: 0.5rem 0.7rem; border-radius: 4px; overflow-x: auto; margin: 0.4em 0; }
.markdown-body a { color: var(--accent); }
.markdown-body a:hover { text-decoration: underline; }
.markdown-body blockquote {
  margin: 0.5em 0; padding: 0.25em 0.75em;
  border-left: 3px solid var(--surface2);
  color: var(--muted);
}
/* Table gets a real cell border + zebra-like header so it doesn't look
   like a formatting accident. */
.markdown-body table {
  border-collapse: collapse;
  margin: 0.75em 0;
  border: 1px solid var(--surface2);
  border-radius: 6px;
  overflow: hidden;
}
.markdown-body th,
.markdown-body td {
  padding: 0.4rem 0.75rem;
  border-bottom: 1px solid var(--surface2);
  border-right: 1px solid var(--surface2);
  text-align: left;
  vertical-align: top;
}
.markdown-body th:last-child,
.markdown-body td:last-child { border-right: none; }
.markdown-body tr:last-child td { border-bottom: none; }
.markdown-body th {
  background: var(--surface2);
  font-weight: 600;
  color: var(--text);
}
/* Horizontal rule: full-width thin line with breathing room around it. */
.markdown-body hr {
  border: 0;
  height: 1px;
  background: var(--surface2);
  margin: 1.5em 0;
}
/* Prose heading sizes — the single source of truth shared by every render
   surface (docs/legal `.markdown-body`, chat `.message-content`, and the
   EasyMDE editor `.editor-preview`) so what you author is exactly what ships. */
.markdown-body h1,
.mde-editor-wrap .editor-preview h1,
.message-content h1 { font-size: 1.5rem; margin-top: 1.2em; }
.markdown-body h2,
.mde-editor-wrap .editor-preview h2,
.message-content h2 { font-size: 1.2rem; }
.markdown-body h3,
.mde-editor-wrap .editor-preview h3,
.message-content h3 { font-size: 1.05rem; }
.markdown-body h4,
.mde-editor-wrap .editor-preview h4,
.message-content h4 { color: var(--muted); text-transform: uppercase; letter-spacing: 0.03em; }
.mde-editor-wrap .editor-preview { background: var(--surface); color: var(--text); padding: 0.5rem 0.75rem; font-family: system-ui, sans-serif; font-size: 1rem; line-height: 1.5; }
/* ── Mediator-panel markdown editors: small default, user-resizable,
   content scrolls instead of growing the whole panel. The chat composer
   (.mde-send-row) is excluded — it auto-grows. */
.mediator-panel .mde-editor-wrap {
  resize: vertical; 
  min-height: 130px; max-height: 65vh;
  display: flex; flex-direction: column;
}
.mediator-panel .mde-editor-wrap .EasyMDEContainer { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.mediator-panel .mde-editor-wrap .editor-toolbar { flex: 0 0 auto; }
.mediator-panel .mde-editor-wrap .CodeMirror { flex: 1 1 auto; height: 100%; min-height: 0; }
.mediator-panel .mde-editor-wrap .editor-preview { flex: 1 1 auto; overflow-y: auto; min-height: 0; }
/* Unify editor + preview typography so toggling edit/preview doesn't jump:
/* EasyMDE's vendor CSS sizes `#`-lines via .cm-header-N at huge vw-based
   sizes (h1 ≈ 41px), so the editor's headings dwarf the rendered preview.
   Pin them to the same sizes as the rendered headings above so authoring,
   preview, and shipped output stay identical. Specificity (.mde-editor-wrap
   .cm-s-easymde .cm-header-N) beats the vendor rule. */
.mde-editor-wrap .cm-s-easymde .cm-header-1 { font-size: 1.5rem; }
.mde-editor-wrap .cm-s-easymde .cm-header-2 { font-size: 1.2rem; }
.mde-editor-wrap .cm-s-easymde .cm-header-3 { font-size: 1.05rem; }
.message-content ul { list-style-type: disc; }
.message-content ol { list-style-type: decimal; }
.message-content h1,
.message-content h2,
.message-content h3,
.message-content h4 { margin: 0.6em 0 0.3em; }
.message-content h1:first-child,
.message-content h2:first-child,
.message-content h3:first-child,
.message-content h4:first-child { margin-top: 0; }
.message-content code { background: rgba(0,0,0,0.2); padding: 0 3px; border-radius: 3px; font-size: 1.2em; }
.message-content pre { background: rgba(0,0,0,0.25); padding: 0.4rem 0.6rem; border-radius: 4px; overflow-x: auto; margin: 0.3em 0; }

/* ── AI Assistant ─────────────────────────────────────────────────────── */
.assistant-toolbar {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  margin: 8px 0 12px;
}
.assistant-model { display: flex; flex-direction: column; gap: 2px; min-width: 180px; }
.assistant-model select { padding: 4px 6px; }

.assistant-chat {
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); padding: 8px;
}
.assistant-messages {
  display: flex; flex-direction: column;
  min-height: 200px; max-height: 60vh; overflow-y: auto;
  scrollbar-gutter: stable;
  padding: 6px 12px; gap: 4px;
}
.assistant-messages:empty::before {
  content: attr(data-empty-hint);
  color: var(--muted); font-style: italic;
  align-self: center; margin: auto 0; text-align: center;
}
.assistant-summary {
  opacity: 0.8;
  border-left: 3px solid var(--accent);
}

/* AI Assistant: thinking indicator (three animated dots inside a fake AI bubble). */
.assistant-thinking .message-content { padding: 4px 0; }
.as-thinking-dots {
  display: inline-flex; gap: 4px; align-items: center;
}
.as-thinking-dots > span {
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; opacity: 0.35;
  animation: asThinkPulse 1.2s infinite;
}
.as-thinking-dots > span:nth-child(2) { animation-delay: 0.15s; }
.as-thinking-dots > span:nth-child(3) { animation-delay: 0.30s; }
@keyframes asThinkPulse {
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
  40%           { opacity: 1;    transform: translateY(-2px); }
}
/* Composer disabled state while awaiting the reply. */
.chat-line-input.is-busy,
.mde-send-btns .send-btn.is-busy,
.mde-send-btns .attach-btn.is-busy { opacity: 0.5; pointer-events: none; cursor: wait; }

/* ── Network-stall banner + blocked composer ──────────────────────── */
.chat-net-banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  padding: 6px 12px;
  background: #7d2828;
  color: #fff;
  text-align: center;
  z-index: 9999;
  box-shadow: 0 2px 6px rgba(0,0,0,0.25);
}
.chat-net-banner::before { content: "⚠ "; }

.chat-net-blockable.is-net-blocked {
  opacity: 0.55;
  cursor: not-allowed;
}
.chat-net-blockable.is-net-blocked::placeholder { opacity: 0.45; }

/* AI bubble header (icon + model chip). The `.msg-sender-label` positions the
   icon in the top-right corner of the bubble (or top-left when mirrored via
   .chat-mirrored). For the Assistant where the AI plays "the other side",
   .message-oth places the icon on the LEFT, so the model chip sits to its
   right. */
.msg-sender-label.ai-header {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
}
.ai-model-name {
  color: var(--muted);
  font-weight: 400;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

/* Action-picker search + count row */
.action-search-row {
  display: flex; align-items: center; gap: 0.6rem;
  margin: 0.4rem 0 0.2rem;
}
.action-search {
  flex: 1;
  padding: 4px 8px;
  background: var(--bg);
  border: 1px solid var(--surface2);
  border-radius: 4px;
  color: var(--text);
}
.action-search:focus { border-color: var(--accent); outline: none; }
.action-row input[type="checkbox"]:checked ~ label strong { color: var(--accent); }

/* ── Actions picker: chips + inline search ─────────────────────────── */
.action-picker-toolbar {
  display: flex; align-items: center; gap: 0.6rem;
  margin: 0.4rem 0 0.4rem;
  padding-right: 40px;
}
.action-picker-toolbar .action-search { flex: 1; }

.toolkit-chips {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-bottom: 0.5rem;
}
.toolkit-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px;
  background: var(--surface2);
  border: 1px solid transparent;
  border-radius: 999px;
  color: var(--text);
  cursor: pointer;
  transition: background 0.1s, border-color 0.1s;
}
.toolkit-chip:hover { border-color: var(--surface2); background: var(--surface); }
.toolkit-chip-logo { width: 14px; height: 14px; object-fit: contain; flex: 0 0 auto; }
.toolkit-chip.is-active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.toolkit-chip-count {
  opacity: 0.7;
  margin-left: 2px;
}
.toolkit-chip.is-active .toolkit-chip-count { opacity: 0.9; }

.action-toolkit-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--surface2);
  color: var(--muted);
  font-weight: normal;
}

/* ── Contact presence indicator ────────────────────────────────────── */
.presence-dot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid var(--muted);
  vertical-align: middle;
  margin-right: 0.4em;
  transition: background 0.15s, border-color 0.15s;
}
.presence-dot.online {
  background: #4ade80;
  border-color: #4ade80;
  box-shadow: 0 0 0 2px rgba(74, 222, 128, 0.18);
}
.presence-dot.away {
  background: transparent;
  border-color: #fbbf24;
  box-shadow: 0 0 0 2px rgba(251, 191, 36, 0.15);
}
.presence-dot.offline {
  background: transparent;
  border-color: var(--muted);
}

/* ── Read-receipt tick (WA-style) ─────────────────────────────────── */
.send-tick {
  color: var(--muted);
  margin: 0 4px;
  transition: color 0.15s;
  letter-spacing: -0.15em;   /* compress the ✓✓ double-tick */
}
/* Color encodes how far the message travelled:
   queued (faded, not sent) → sent (server got it) → delivered (recipient got it)
   → read (recipient saw it, blue). Red is reserved for `failed` — a real alert —
   so a read receipt never looks like an error. The hover title says what went wrong. */
.send-tick[data-state="queued"]    { color: var(--muted); opacity: 0.45; }
.send-tick[data-state="sent"]      { color: var(--muted); }
.send-tick[data-state="delivered"] { color: var(--tick-delivered); }
.send-tick[data-state="read"]      { color: var(--tick-read); }
.send-tick[data-state="failed"]    { color: var(--tick-failed); }

/* ── Notification bell ──────────────────────────────────────────────── */
.err-log-bell-btn {
  position: relative;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0 .25rem;
  color: var(--text);
  font-size: 1.1rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
}
.err-log-bell-btn:hover { color: var(--accent); }
/* `[hidden]` must win over the `display:inline-flex/flex` above, otherwise
   setting .hidden=true (bell with no notifications, panel after close) is
   a no-op and the dropdown sticks open / floats to top-left on navigation. */
.err-log-bell-btn[hidden] { display: none !important; }
.err-log-panel[hidden] { display: none !important; }

.err-log-badge {
  position: absolute;
  top: -5px;
  right: -6px;
  background: var(--accent);
  color: #fff;
  font-weight: 700;
  min-width: 15px;
  height: 15px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 3px;
  pointer-events: none;
  line-height: 1;
}
.err-log-badge[data-level="info"] { background: #3b82f6; }
.err-log-badge[data-level="success"] { background: #22c55e; }
.err-log-badge[data-level="warn"],
.err-log-badge[data-level="warning"] { background: #f59e0b; }

/* ── Notification log panel ─────────────────────────────────────────── */
.err-log-panel {
  position: fixed;
  z-index: 99998;
  width: min(95vw, 28rem);
  max-height: min(90vh, calc(100dvh - 3rem));
  min-height: 100px;
  min-width: 250px;
  background: var(--surface);
  border: 1px solid var(--surface2);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0,0,0,.35);
  overflow-y: auto;
  overflow-x: hidden;
  font-family: system-ui, sans-serif;
  color: var(--text);
  resize: both;
}
.err-log-panel-head {
  display: flex;
  align-items: center;
  padding: .5rem .6rem;
  border-bottom: 1px solid var(--surface2);
  gap: .3rem;
  flex-wrap: wrap;
  background: var(--surface2);
  position: sticky;
  top: 0;
  z-index: 1;
}
.err-log-panel-title {
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  flex: 1;
}
.err-log-close-btn {
  display: none;
  background: var(--surface);
  border: 1px solid var(--surface2);
  color: var(--muted);
  font-size: 1rem;
  cursor: pointer;
  padding: .35rem .6rem;
  border-radius: 6px;
  line-height: 1;
  min-height: 36px;
  min-width: 36px;
  text-align: center;
}
.err-log-close-btn:hover { color: var(--text); background: var(--surface2); }
@media (max-width: 720px) {
  .err-log-close-btn { display: flex; align-items: center; justify-content: center; }
}
.err-log-panel-actions {
  display: flex;
  gap: .4rem;
  flex-wrap: wrap;
}
.err-log-btn-icon { display: none; }
.err-log-action-btn {
  background: none;
  border: 1px solid var(--surface2);
  color: var(--muted);
  padding: .2rem .5rem;
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.15s ease;
}
.err-log-action-btn:hover {
  color: var(--text);
  border-color: var(--accent);
  background: rgba(255, 107, 107, 0.1);
}
.err-log-danger-btn:hover {
  color: #fca5a5 !important;
  border-color: #f87171 !important;
}
.err-log-list {
  padding: .5rem;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.err-log-empty {
  padding: 1.5rem;
  text-align: center;
  color: var(--muted);
  font-style: italic;
}
/* Log items reuse .err-toast but without the slide-in animation */
.err-log-item {
  animation: none !important;
  background: var(--surface2) !important;
  border-left: 4px solid #f87171 !important;
  color: var(--text) !important;
  border-radius: 6px !important;
  box-shadow: 0 4px 12px rgba(0,0,0,.2) !important;
  margin-bottom: .5rem;
  overflow: visible !important;
  max-height: none !important;
  max-width: 100%;
  position: relative;
}
.err-log-item .err-title { color: var(--text) !important; flex: 1 !important; min-width: 0; overflow-wrap: break-word !important; word-break: normal !important; }
.err-log-item.err-info { border-left-color: #3b82f6 !important; }
.err-log-item.err-warn { border-left-color: #f59e0b !important; }
.err-log-item.err-success { border-left-color: #22c55e !important; }
.err-log-item .err-head {
  display: flex !important;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: .3rem;
  padding-right: 4.2rem !important;
}
.err-log-item .err-log-ts {
  flex-shrink: 1;
  overflow: hidden;
  text-overflow: ellipsis;
}
.err-log-item .err-close {
  position: absolute;
  top: 6px;
  right: 32px;
  z-index: 5;
  background: rgba(0,0,0,0.35);
  color: var(--text);
  border: 1px solid var(--surface2);
  border-radius: 5px;
  width: 26px;
  height: 26px;
  opacity: 0.55;
  transition: opacity 0.15s;
}
.err-log-item .err-close:hover { opacity: 1; background: var(--accent); color: #fff; border-color: var(--accent); }
.err-log-item .fs-trigger { top: 6px; }
.err-log-item .err-body { overflow: visible !important; max-height: none !important; flex: none !important; }
.err-log-item .err-message { color: var(--text) !important; }
.err-log-item .err-rid { color: var(--muted) !important; }
.err-log-item details { color: var(--muted) !important; }
.err-log-item details > summary { color: #60a5fa !important; cursor: pointer; user-select: none; }
.err-log-item details > summary:hover { color: #93c5fd !important; }
.err-log-item .err-section h4 { color: #60a5fa !important; }
.err-log-item .err-block {
  background: var(--surface) !important;
  color: var(--text) !important;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
  max-height: none !important;
  overflow: visible !important;
}
.err-log-item-unread > .err-head > .err-title::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  margin-right: 5px;
  vertical-align: middle;
  flex-shrink: 0;
}
/* Unread items: accent-tinted background + bold title + accent stripe so they
   read as "needs attention" against already-read items, which are dimmed. */
.err-log-item-unread {
  background: rgba(233, 69, 96, 0.16) !important;
  border-left-color: var(--accent) !important;
  border-left-width: 5px !important;
}
.err-log-item-unread .err-title { font-weight: 700 !important; }
.err-log-item:not(.err-log-item-unread) { opacity: 0.7; }
.err-log-ts {
  color: #6b7280;
  white-space: nowrap;
  padding: 0 .3rem;
}
@media (max-width: 720px) {
  .err-log-panel {
    inset: 0 !important;
    width: 100% !important;
    max-width: 100vw !important;
    max-height: 100dvh !important;
    height: 100dvh !important;
    min-width: 0 !important;
    border-radius: 0;
    resize: none;
  }
  .err-log-panel-head {
    padding: .5rem .6rem;
    gap: .3rem;
    flex-wrap: nowrap;
  }
  .err-log-btn-icon { display: inline; }
  .err-log-btn-text { display: none; }
  .err-log-action-btn {
    min-height: 36px;
    min-width: 36px;
    padding: .3rem;
    font-size: 1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .err-log-list { padding: .5rem; gap: .45rem; }
  .err-log-item .err-close {
    width: 32px;
    height: 32px;
  }
}

/* Minimize (−) button on floating toasts */
.err-minimize {
  background: none;
  border: none;
  color: #6b7280;
  font-size: 1rem;
  cursor: pointer;
  padding: 0 .1rem;
  line-height: 1;
  margin-top: .1rem;
}
.err-minimize:hover { color: #9ca3af; }

/* ── Image Queue (pending attachments) ──────────────────────────────────── */
.image-queue {
  display: none;
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 8px;
  padding: 8px;
  background: var(--surface2);
  border-radius: 4px;
  margin-top: 8px;
}
.image-queue-item {
  position: relative;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid var(--surface);
  cursor: pointer;
  transition: transform 0.15s, box-shadow 0.15s;
}
.image-queue-item:hover {
  transform: scale(1.05);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.image-queue-preview {
  width: 100%;
  height: 80px;
  object-fit: cover;
  display: block;
}
.image-queue-remove {
  position: absolute;
  top: 2px;
  right: 2px;
  background: rgba(0, 0, 0, 0.6);
  border: none;
  color: white;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  padding: 0;
  transition: background 0.15s;
  z-index: 2;
}
.image-queue-remove:hover { background: rgba(0, 0, 0, 0.9); }
.image-queue-add-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: 2px dashed var(--surface);
  background: transparent;
  border-radius: 4px;
  cursor: pointer;
  padding: 4px;
  height: 80px;
  transition: all 0.15s;
  font-size: 28px;
  color: var(--muted);
  gap: 2px;
  position: relative;
}
.image-queue-add-btn:hover {
  border-color: var(--text);
  color: var(--text);
  background: var(--surface);
}
.image-queue-add-btn .add-icon {
  display: block;
  line-height: 1;
}
.image-queue-add-btn::after {
  content: attr(data-limits);
  font-size: 0.6rem;
  line-height: 1.2;
  color: var(--muted);
  text-align: center;
  white-space: normal;
  word-break: break-word;
  max-width: 75px;
}
.image-queue-status {
  color: var(--muted);
}
.image-gallery-lightbox {
  display: none;
}

/* ── Cookie consent (vanilla-cookieconsent) — themed to the app palette.
   The vendor CSS exposes its whole look via --cc-* custom properties on
   :root (light defaults). Override them scoped to #cc-main so the dialog
   matches the dark navy/red design instead of shipping the white default. ── */
#cc-main {
  color-scheme: dark;
  --cc-bg: var(--surface);
  --cc-primary-color: var(--text);
  --cc-secondary-color: var(--muted);
  --cc-link-color: #7ab8ff;
  --cc-btn-primary-bg: var(--accent);
  --cc-btn-primary-color: #fff;
  --cc-btn-primary-hover-bg: #c73852;
  --cc-btn-primary-hover-color: #fff;
  --cc-btn-secondary-bg: var(--surface2);
  --cc-btn-secondary-color: var(--text);
  --cc-btn-secondary-hover-bg: #15497e;
  --cc-btn-secondary-hover-color: #fff;
  --cc-separator-border-color: rgba(255, 255, 255, 0.08);
  --cc-cookie-category-block-bg: rgba(255, 255, 255, 0.04);
  --cc-cookie-category-block-border: rgba(255, 255, 255, 0.08);
  --cc-cookie-category-block-hover-bg: rgba(255, 255, 255, 0.07);
  --cc-cookie-category-block-hover-border: rgba(255, 255, 255, 0.14);
  --cc-footer-bg: rgba(0, 0, 0, 0.2);
  --cc-footer-border-color: rgba(255, 255, 255, 0.08);
  --cc-overlay-bg: rgba(0, 0, 0, 0.65);
  --cc-toggle-on-bg: var(--accent);
  --cc-toggle-off-bg: var(--surface2);
}
#cc-main .cm,
#cc-main .pm {
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}
#cc-main .cm__title,
#cc-main .pm__title {
  color: var(--text);
}
#cc-main .cm__desc,
#cc-main .pm__section-desc {
  color: var(--muted);
}

/* ── Filter form (shared across projects) ────────────────────────────── */
.filter-form {
  display: flex; flex-wrap: wrap;
  gap: 0.5rem; align-items: end;
  margin-bottom: 0.5rem;
}
.filter-form > * {
  flex: 1 1 110px; min-width: 0;
  display: flex; flex-direction: column;
}
.filter-form > div:has(.price-field),
.filter-form > div:has(.more-toggle-btn),
.filter-form > div:has(.star-filter),
.filter-form > div:has(.toggle-btn),
.filter-form > div:has(.cp-trigger-wrap),
.filter-form > .submit-cell,
.filter-form > div:has(.sort-group) {
  flex: 0 0 auto;  min-width: max-content;
}
.sort-group { display: flex; gap: 0.2rem; }
.sort-dir-btn {
  border: 1px solid var(--surface2, #ddd); border-radius: 4px;
  background: var(--surface, #fff); color: var(--text);
  padding: 0.35rem 0.5rem; cursor: pointer; font-size: 0.9rem;
}
.sort-dir-btn:hover { border-color: var(--accent); }
.filter-form input,
.filter-form select {
  width: 100%; min-width: 0;
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--surface2, #ddd);
  border-radius: 4px;
  background: var(--surface, #fff);
  color: var(--text, #222);
  box-sizing: border-box;
}
.filter-form label {
  color: var(--muted, #666); display: block;
  margin-bottom: 0.15rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.filter-form .submit-cell {
  display: flex; flex-direction: row; align-items: end; gap: 0.35rem;
}
.filter-form .submit-cell .btn {
  flex: 1 1 auto; min-width: 0;
  background: var(--surface2, #334155); color: var(--fg, #e0e0e0);
  transition: box-shadow .2s, transform .2s, background .2s;
}
.filter-form .submit-cell .btn:hover { background: #475569; opacity: 1; }
.filter-form .submit-cell .btn.filter-dirty {
  background: var(--accent, #e94560); color: #fff;
  animation: filter-pulse 1.2s ease-in-out infinite;
}
@keyframes filter-pulse {
  0%, 100% { box-shadow: 0 0 6px var(--accent, #e94560); transform: scale(1); }
  50% { box-shadow: 0 0 18px var(--accent, #e94560); transform: scale(1.04); }
}
.filter-reset {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0.4rem 0.55rem;
  color: var(--muted); text-decoration: none;
  border: 1px solid var(--surface2); border-radius: 4px;
  font-size: 1.05rem; line-height: 1;
  transition: color .15s, border-color .15s, transform .15s;
}
.filter-reset:hover {
  color: var(--accent); border-color: var(--accent); transform: rotate(-15deg);
}

/* ── City picker trigger (inside filter-form) ────────────────────────── */
.cp-trigger-wrap { width: 100%; }
.filter-form .cp-trigger-btn {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; margin: 0;
  padding: 0; padding-inline: 0.5rem;
  height: 30px;
  border: 1px solid var(--surface2, #ddd); border-radius: 4px;
  background: var(--surface, #fff); color: var(--text, #222);
  cursor: pointer;
  font-size: 13.3333px; line-height: normal;
  box-sizing: border-box;
  transition: border-color .15s;
}
.filter-form .cp-trigger-btn:hover { border-color: var(--accent, #3498db); }
.cp-trigger-label {
  flex: 1; text-align: left; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cp-trigger-icon { flex-shrink: 0; margin-left: .4rem; font-size: .85rem; }

/* ── Pagination (shared) ─────────────────────────────────────────────── */
.pagination {
  display: flex; justify-content: center; align-items: center; gap: 0.35rem;
  flex-wrap: nowrap; white-space: nowrap;
  margin: 0.5rem 0;
}
#listing-results > .pagination,
main > .pagination,
#feedback-section > .pagination {
  position: sticky; bottom: 0;
  z-index: 10;
  background: var(--surface); padding: 0.5rem 0.75rem;
  border-top: 1px solid var(--surface2);
  box-shadow: 0 -2px 8px rgba(0,0,0,.2);
}
.pagination .pg-pages {
  display: inline-flex; align-items: center; gap: 0.35rem;
  flex: 0 0 auto;
}
.pagination a,
.pagination .pg-gap {
  padding: 0.4rem 0.7rem; border-radius: 4px; text-decoration: none;
  color: var(--text, #222); background: var(--surface, #fff);
  border: 1px solid var(--surface2, #ddd); line-height: 1;
}
.pagination a.active,
.pagination a:hover { background: var(--accent, #3498db); color: #fff; border-color: var(--accent, #3498db); }
.pagination .pg-gap { color: var(--muted, #999); border-color: transparent; background: transparent; }
.pagination .pg-prev, .pagination .pg-next { flex: 0 0 auto; }
.pagination .pg-icon { display: none; }
@media (max-width: 480px) {
  .pagination .pg-label { display: none; }
  .pagination .pg-icon { display: inline; }
  .pagination a, .pagination .pg-gap { padding: 0.35rem 0.5rem; font-size: 0.85rem; }
  .pagination .pg-jump { display: none; }
}
.pagination .pg-jump {
  flex: 0 0 auto; padding: 0.35rem 0.5rem; border-radius: 4px;
  border: 1px solid var(--surface2, #ddd); background: var(--surface, #fff);
  color: var(--text, #222); font-size: 0.95rem; cursor: pointer;
}
.pagination .pg-jump:hover { border-color: var(--accent, #3498db); }

/* ── Contact PII app links ───────────────────────────────────────────── */
.pii-phone-apps { display: inline-flex; align-items: center; gap: 0.4rem; }
.pii-app-link { text-decoration: none; font-size: 1.1rem; opacity: 0.8; transition: opacity .15s; }
.pii-app-link:hover { opacity: 1; }

/* ── Detail gallery — horizontal scrollable row ─────────────────────── */
.listing-gallery {
  display: flex; gap: 0.4rem; overflow-x: auto;
  padding-bottom: 0.3rem; margin-bottom: 0.75rem;
  scroll-snap-type: x mandatory;
}
.listing-gallery .listing-thumb-link {
  flex: 0 0 auto; width: 200px;
  scroll-snap-align: start;
}
.listing-thumb-link {
  display: block; overflow: hidden; border-radius: 6px;
  background: var(--surface2); line-height: 0;
}
.listing-thumb {
  width: 100%; height: 140px; display: block;
  object-fit: contain;
  transition: transform .2s;
}
.listing-thumb-link:hover .listing-thumb { transform: scale(1.03); }

/* ── More toggle button with badge ───────────────────────────────────── */
.more-toggle-btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  height: 30px; box-sizing: border-box;
  padding: 0 0.75rem; border: 1px solid var(--surface2, #334155);
  border-radius: 4px; background: var(--surface, #16213e);
  color: var(--muted, #94a3b8); cursor: pointer;
  font: inherit; font-size: 0.85rem; white-space: nowrap;
  transition: all .15s;
}
.more-toggle-btn:hover { border-color: var(--accent); color: var(--accent); }
.more-toggle-btn.has-active {
  border-color: var(--accent, #e94560); color: var(--accent, #e94560);
}
.more-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 8px; font-size: 0.65rem; font-weight: 700;
  background: var(--accent, #e94560); color: #fff;
  margin-left: 0.3rem;
}

/* ── Shared listing card base ───────────────────────────────────────── */
.listing-card {
  display: flex; flex-direction: column;
  border: 1px solid var(--border, #334155); border-radius: 8px;
  overflow: hidden; cursor: pointer; position: relative;
  text-decoration: none; color: inherit;
  transition: box-shadow 0.15s;
  background: var(--card-bg, #1e293b);
}
.listing-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,.25); }
.listing-card-footer { display: flex; flex-wrap: wrap; gap: 0.25rem; }

/* ── Chips (shared) ────────────────────────────────────────────────── */
.chip {
  display: inline-block; padding: 1px 6px;
  background: var(--bg-muted, #374151); border-radius: 4px;
  color: var(--muted, #94a3b8);
}
.chips { display: flex; flex-wrap: wrap; gap: 0.3rem; }

/* ── Toggle button (shared) ────────────────────────────────────────── */
.toggle-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 100%; height: 30px; box-sizing: border-box;
  padding: 0 0.5rem; border: 1px solid var(--surface2, #334155);
  border-radius: 4px; background: var(--surface, #16213e);
  color: var(--muted, #94a3b8); cursor: pointer;
  font: inherit; font-size: 0.85rem; white-space: nowrap; line-height: 1;
  transition: all .15s;
}
.toggle-btn.active {
  background: #166534; color: #86efac;
  border-color: #22c55e;
}
.toggle-btn:hover { border-color: var(--accent); }

/* ── Glow animation (shared, set --glow-color per use) ─────────────── */
.cw-glow {
  animation: cw-glow-pulse 1.5s ease-in-out infinite;
  border-radius: 3px; padding: 1px 4px;
}
@keyframes cw-glow-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--glow-color, rgba(34,197,94,.5)); text-shadow: none; }
  50% { box-shadow: 0 0 8px 2px var(--glow-color, rgba(34,197,94,.5)); text-shadow: 0 0 6px var(--glow-color, rgba(34,197,94,.6)); }
}

/* ── Card carousel (cw-carousel) ────────────────────────────────────── */
.cw-card-carousel { position: relative; overflow: hidden; background: #0f172a; }
.cw-carousel { width: 100%; height: 100%; position: relative; }
.cw-carousel-slide {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; transition: opacity .25s; display: block;
}
.cw-carousel-slide img { width: 100%; height: 100%; object-fit: cover; }
.cw-carousel-slide.active { opacity: 1; z-index: 1; }
.cw-carousel-prev, .cw-carousel-next {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: rgba(0,0,0,.4); color: #fff; border: none;
  font-size: 1.4rem; padding: 0.2rem 0.4rem; cursor: pointer;
  opacity: 0; transition: opacity .2s; z-index: 3; border-radius: 3px;
}
.cw-carousel:hover .cw-carousel-prev,
.cw-carousel:hover .cw-carousel-next { opacity: 1; }
.cw-carousel-prev { left: 4px; }
.cw-carousel-next { right: 4px; }
.cw-carousel-dots {
  position: absolute; bottom: 6px; left: 50%; transform: translateX(-50%);
  display: flex; gap: 4px; z-index: 3;
}
.cw-dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,.4); }
.cw-dot.active { background: #fff; }
