/*
 * BESIDA — Swiss Style 2026
 * Brockmann principles. Modern execution.
 * Grid in proportions, not in lines.
 */

@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap");

:root {
  /* ═════════════════════════════════════════════════════════════════
     BESIDA — Editorial Messenger, 2026 rebrand
     Direction: Siena / Trunk.io — calm, warm, sophisticated dark UI.
     Swiss Red is retired; accent is a muted amber that reads as
     "warmth / conversation" instead of "alarm". Backgrounds warmed by
     a few percent so pure-gray doesn't feel clinical.
     ═════════════════════════════════════════════════════════════════ */

  /* Backgrounds — warm-neutral greys, ≥2% brighter at each tier so
     depth reads even in ambient light. */
  /* Monochrome palette — like the playlist project. Pure black/white +
     5 shades of gray. Zero colour hue. All emphasis via contrast and
     surface elevation. Matches Linear/Arc/Vercel aesthetic. */
  --bg: #0d0d0e;            /* near-black (not pure) for eye-comfort */
  --bg-secondary: #18181a;  /* first elevation step */
  --bg-tertiary: #232326;   /* bubbles / surfaces */
  --bg-hover: #2e2e31;      /* hover / outgoing bubble */
  --bg-elevated: #39393c;   /* dropdowns, popovers */

  /* Grayscale text — 4 steps, each passing WCAG AA on --bg. */
  --fg: #f5f5f5;            /* primary body/heading — 18.89:1 */
  --fg-secondary: #d4d4d7;  /* secondary — 13.85:1 */
  --fg-tertiary: #a1a1a4;   /* muted — 7.55:1 */
  --fg-muted: #74747a;      /* captions/timestamps — 4.56:1 */

  /* Accent — monochrome white. Only difference from body text is
     opacity/weight context. Used for selected states, online dots,
     focus rings. No hue bleeding into the conversation. */
  --accent: #f5f5f5;
  --accent-hover: #ffffff;
  --accent-light: rgba(245, 245, 245, 0.08);
  --accent-glow: rgba(245, 245, 245, 0.18);

  /* Primary — mid-gray for secondary emphasis (pin/unread badge bg). */
  --primary: #a1a1a4;
  --primary-hover: #b4b4b7;

  --tg: #0088cc;         /* Telegram brand — external, keep blue */
  --danger: #f07b8a;     /* muted coral — only for errors/destructive */
  --success: #a1a1a4;    /* gray (no green) — online/delivered use fg-tertiary */
  --warning: #d4d4d7;    /* gray */

  /* Borders — 8/16% white on near-black. */
  --border: rgba(245, 245, 245, 0.08);
  --border-strong: rgba(245, 245, 245, 0.16);

  /* Typography — Inter for all UI; mono only for timestamps / code
     / system IDs (see --font-mono usage sites). */
  --font: "Inter", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-mono: "JetBrains Mono", "SF Mono", "Fira Code", monospace;

  /* Spacing — 4px base, unchanged. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;

  --error-color: var(--danger);
  --success-color: var(--fg-tertiary);

  /* Radius — retire the Swiss brutalist 0/50% binary. Messenger needs
     soft edges on bubbles and cards; crisp edges on inputs stay via
     --radius-xs. All values in rem so they scale with root font-size. */
  --radius-xs: 0.25rem;  /*  4px — inputs, chips */
  --radius-sm: 0.5rem;   /*  8px — buttons, badges */
  --radius: 0.75rem;     /* 12px — cards, bubbles */
  --radius-lg: 1.25rem;  /* 20px — hero / modal */
  --radius-full: 50%;    /* avatars, pills */

  /* Type scale */
  /* Type scale — fluid for content-bearing sizes (--t1..t3), static for
     UI chrome (--t4..t7). Ben Frain Ch.4/6: body and headings should
     breathe between phone and 4K so reading comfort tracks viewport;
     small UI labels stay exact so icons, buttons, tab rows don't drift.
     `clamp(min, preferred, max)` pins the minimum at pre-rebrand size
     and grows ~12% wider by ~1280 px viewport. */
  --t1: clamp(1.125rem, 0.95rem + 0.9vw, 1.375rem);   /* headings / titles */
  --t2: clamp(0.9375rem, 0.85rem + 0.45vw, 1.0625rem); /* body / bubble text */
  --t3: clamp(0.875rem, 0.82rem + 0.3vw, 1rem);        /* secondary body */
  --t4: 0.8125rem;
  --t5: 0.75rem;
  --t6: 0.6875rem;
  --t7: 0.625rem;

  /* Motion tokens — single source of truth (Stepanov) */
  --ease-out: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --ease-spring: var(--ease-spring);
  --ease-in-out: var(--ease-in-out);
  --duration-fast: 0.15s;
  --duration-normal: 0.25s;
  --duration-slow: 0.4s;

  /* Shadows — multi-layer depth (Craft) */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.15), 0 2px 6px rgba(0,0,0,0.08);
  --shadow-md: 0 2px 4px rgba(0,0,0,0.2), 0 8px 24px rgba(0,0,0,0.12);
  --shadow-lg: 0 4px 8px rgba(0,0,0,0.2), 0 16px 48px rgba(0,0,0,0.15);
}

[data-theme="light"] {
  /* ═════ BESIDA LIGHT — warm paper, not cold glossy white ═════════
     Paper-tone bg (very slightly warm) + accent darkens for contrast. */
  --bg: #faf8f4;
  --bg-secondary: #f3f0ea;
  --bg-tertiary: #ebe8e2;
  --bg-hover: #e0ddd6;
  --bg-elevated: #ffffff;

  --fg: #1a1a1a;
  --fg-secondary: #5a5e68;
  --fg-tertiary: #8b8f99;
  --fg-muted: #b0b4bd;

  /* Light-theme monochrome tokens — mirror dark theme in the opposite
     direction, single near-black as accent, grayscale for body. */
  --accent: #111114;
  --accent-hover: #000000;
  --accent-light: rgba(0, 0, 0, 0.06);
  --accent-glow: rgba(0, 0, 0, 0.12);

  --danger: #d04a3a;     /* muted red — errors/destructive only */
  --success: #78716c;    /* gray — no green */

  --border: rgba(0, 0, 0, 0.08);
  --border-strong: rgba(0, 0, 0, 0.16);
}

/* Theme toggle buttons */
.theme-toggle,
.model-toggle {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.theme-toggle .btn--small,
.model-toggle .btn--small {
  flex: 1;
  background: var(--bg-tertiary);
  color: var(--fg-secondary);
  border: none;
  border-radius: var(--radius-sm);
}

.theme-toggle .btn--small:hover,
.model-toggle .btn--small:hover {
  background: var(--bg-hover);
  color: var(--fg);
}

.theme-toggle .btn--small.active,
.model-toggle .btn--small.active {
  background: var(--accent);
  color: #fff;
}

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

html, body {
  overflow: hidden;
  height: 100%;
  /* Modern dvh keeps height sane on mobile browsers that hide the
     address bar on scroll — 100vh overflowed by the bar height,
     100dvh tracks the actually-visible area. */
  height: 100dvh;
}

html {
  font-size: 1rem; /* Prevents iOS auto-zoom on inputs */
  -webkit-font-smoothing: antialiased;
  text-rendering: geometricPrecision;
  scrollbar-gutter: stable;
}

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--fg);
  line-height: 1.4;
  letter-spacing: -0.01em;
  min-height: 100vh;
  min-height: 100dvh;
  overflow: hidden;
  touch-action: pan-y;
  overscroll-behavior: none;
  /* Safe area insets for notch/dynamic island */
  padding-top: env(safe-area-inset-top);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
  transition:
    background-color 0.3s ease,
    color 0.3s ease;
}

::selection {
  background: var(--accent);
  color: #fff;
}

/* ═══════════════════════════════════════════
   LAYOUT - Mobile first
   ═══════════════════════════════════════════ */

/* Mobile-first refactor (Ben Frain Ch.3-4): the default rules describe
   the DESKTOP 2-column grid; mobile additions live in one `@media
   (max-width: var(--bp-md))` block below. This eliminates the old
   `!important` cluster that was resolving specificity fights between
   a mobile default and a desktop override.
   Sidebar track is fluid: `clamp(15rem, 22vw, 24rem)` reads at 240-384px
   across typical screens, scaling with viewport instead of a 320px
   hardcode. */
.layout {
  display: grid;
  grid-template-columns: clamp(15rem, 22vw, 24rem) 1fr;
  grid-template-rows: 3.5rem 1fr;
  grid-template-areas:
    "header header"
    "sidebar main";
  height: 100vh;
  height: 100dvh;
  position: relative;
  overflow: hidden;
}

/* ═══════════════════════════════════════════
   HEADER
   ═══════════════════════════════════════════ */

.header {
  grid-area: header;
  display: flex;
  align-items: center;
  padding: 0 var(--space-3);
  gap: var(--space-3);
  background: var(--bg);
  z-index: 100;
}

.status {
  width: 0.5rem;
  height: 0.5rem;
  background: var(--fg-tertiary);
  border-radius: 50%;
  flex-shrink: 0;
}

.status.connected {
  background: var(--success);
}

.title {
  font-size: var(--t2);
  font-weight: 600;
  letter-spacing: -0.04em;
  flex: 1;
}

.logo {
  display: flex;
  align-items: center;
  flex: 1;
  color: var(--fg);
  text-decoration: none;
}

.logo svg {
  width: 1.5rem;
  height: 1.5rem;
}

.btn--icon {
  /* Apple HIG: min 44x44 pt touch target. SVG inside can be smaller —
     the padding carries the hit area. */
  min-width: 2.75rem;
  min-height: 2.75rem;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent !important;
  color: var(--fg-secondary);
  border: none !important;
  border-radius: 0;
  cursor: pointer;
  transition: all var(--duration-fast) var(--ease-out);
}

.btn svg {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
}

.btn--icon:hover {
  background: transparent;
}

.btn--icon:active {
  background: transparent;
}

/* ═══════════════════════════════════════════
   SIDEBAR
   ═══════════════════════════════════════════ */

.sidebar {
  grid-area: sidebar;
  display: flex;
  flex-direction: column;
  background: var(--bg-secondary);
  border-right: 1px solid var(--border-strong);
  min-height: 0;
  overflow: hidden;
  /* Enable container queries so dialog-items can adapt to sidebar
     width, not viewport width (Ch.5 — "components respond to space
     they occupy, not the window"). */
  container-type: inline-size;
  container-name: side;
}

/* Mobile state machine: data-view="list" | "chat" — only meaningful
   below the breakpoint, where sidebar and main overlap as sliding
   overlays. On desktop both are grid children and no `data-view`
   dance is needed. */
@media (max-width: 48em) {
  .layout {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "content";
  }

  .sidebar {
    grid-area: content;
    position: absolute;
    /* `inset: 0` positions within the grid-area containing block, which
       is row 2 of the layout grid (starting at y = 3.5rem). Adding an
       explicit `top: 3.5rem` would double-offset — a 56px gap above
       the dialog-search input the user spotted. */
    inset: 0;
    z-index: 50;
    border-right: none;
    transition: transform 0.3s var(--ease-in-out);
  }

  .layout[data-view="chat"] .sidebar { transform: translateX(-100%); visibility: hidden; }
  .layout[data-view="chat"] .main { transform: translateX(0); }
  .layout[data-view="chat"] .header { display: none; }
  .layout[data-view="chat"] { grid-template-rows: 1fr; grid-template-areas: "content"; }
  .layout[data-view="list"] .sidebar { transform: translateX(0); }
  .layout[data-view="list"] .main { transform: translateX(100%); }
}

.sidebar.hidden {
  transform: translateX(-100%);
  pointer-events: none;
}

.sidebar__header {
  display: none;
}

/* Mobile backdrop when chat is open */
.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 49;
  opacity: 0;
  transition: opacity 0.3s;
}

.sidebar-backdrop.visible {
  display: block;
  opacity: 1;
}

.sidebar__title {
  display: none;
}

/* ═══════════════════════════════════════════
   DIALOG SEARCH
   ═══════════════════════════════════════════ */

.dialog-search {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-2);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
/* Header slot — compact, pill, fills available space between logo and settings */
.dialog-search--header {
  flex: 1;
  border: 1px solid var(--border);
  border-radius: 1rem;
  background: var(--bg-secondary);
  padding: 0.25rem var(--space-2);
  min-height: 2.25rem;
  margin: 0 var(--space-1);
}
.dialog-search--header .dialog-search__input {
  min-height: 2rem;       /* stay inside header's 3.5rem row */
  padding: 0.25rem 0;
  border: none;
  font-size: var(--t5);
}

.dialog-search__icon {
  color: var(--fg-tertiary);
  flex-shrink: 0;
}

.dialog-search__input {
  flex: 1;
  width: 100%;
  min-height: 2.75rem;  /* HIG 44pt */
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  padding: 0.625rem var(--space-2);
  font-size: var(--t5);
  font-family: var(--font-mono, monospace);
  color: var(--fg);
  outline: none;
  transition: border-color var(--duration-fast) var(--ease-out);
  min-width: 0;
}

.dialog-search__input:focus {
  border-color: var(--accent);
}

.dialog-search__input::placeholder {
  color: var(--fg-muted);
}

.dialog-search__clear {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  background: none;
  border: none;
  border-radius: var(--radius-xs);
  color: var(--fg-tertiary);
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
  transition: color var(--duration-fast);
}

.dialog-search__clear:hover {
  color: var(--fg);
}

/* ═══════════════════════════════════════════
   DIALOG LIST - Unified (P2P + Telegram)
   ═══════════════════════════════════════════ */

.dialog-list {
  list-style: none;
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: var(--space-2) 0;
  /* Hide scrollbar — iOS-style ghost scroll, only appears during active
     drag (native behavior on WebKit). Desktop keeps it hidden too. */
  scrollbar-width: none;
}
.dialog-list::-webkit-scrollbar { display: none; }

.dialog-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  margin: 0;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out);
  /* Perf: offscreen items skip layout/paint until scrolled into view */
  content-visibility: auto;
  contain-intrinsic-size: 3.5rem 0;
  /* Awwwards pattern: blur-to-sharp + subtle rise + micro-scale.
     Reads as "list materializes from fog" — premium/cinematic feel.
     Motion.dev stagger(0.05s) with Apple's ease-out quad curve. */
  animation: dialogRevealIn 0.5s cubic-bezier(0.32, 0.23, 0.4, 0.9) both;
  will-change: opacity, transform, filter;
}
/* Stagger 50ms per item — Motion.dev recommended "tight cascade"
   tempo. Clamp at index 12 so a 100-dialog list doesn't stretch 5s. */
.dialog-item:nth-child(1)  { animation-delay: 0ms; }
.dialog-item:nth-child(2)  { animation-delay: 50ms; }
.dialog-item:nth-child(3)  { animation-delay: 100ms; }
.dialog-item:nth-child(4)  { animation-delay: 150ms; }
.dialog-item:nth-child(5)  { animation-delay: 200ms; }
.dialog-item:nth-child(6)  { animation-delay: 250ms; }
.dialog-item:nth-child(7)  { animation-delay: 300ms; }
.dialog-item:nth-child(8)  { animation-delay: 350ms; }
.dialog-item:nth-child(9)  { animation-delay: 400ms; }
.dialog-item:nth-child(10) { animation-delay: 450ms; }
.dialog-item:nth-child(11) { animation-delay: 500ms; }
.dialog-item:nth-child(12) { animation-delay: 550ms; }
.dialog-item:nth-child(n+13) { animation-delay: 580ms; }

/* Re-rendered items (same data-dialog-id) skip the animation. */
.dialog-item--seen { animation: none !important; will-change: auto; }

@media (prefers-reduced-motion: reduce) {
  .dialog-item { animation: none; will-change: auto; }
}

/* View Transitions — smooth cross-fade between list states. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.25s;
}

/* Reveal keyframes:
   - opacity 0→1 (fade)
   - translateY(14px → 0) (subtle rise)
   - scale(0.94 → 1) (micro-zoom for depth)
   - blur(10px → 0) (cinematic materialization — the Awwwards signature) */
@keyframes dialogRevealIn {
  0% {
    opacity: 0;
    transform: translateY(14px) scale(0.94);
    filter: blur(10px);
  }
  60% {
    filter: blur(2px);   /* settle blur first, then rest glides in */
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
}

.dialog-item:hover {
  background: transparent;
}

.dialog-item--selected {
  background: transparent;
}

.dialog-item--selected .dialog-name {
  color: var(--accent);
}

.dialog-item--selected:hover {
  background: transparent;
}

/* Container queries — dialog-item adapts to sidebar width, not viewport
   (Ben Frain Ch.5 + Ch.11). When `smart-ui--collapsed` narrows the
   sidebar, items shed the secondary text first, then align to centre
   as a compact icon strip. No JS, no viewport lookup — the component
   responds to the space its parent actually gives it.
   Container is `side` (see `.sidebar` block above). */
@container side (max-width: 14rem) {
  /* First casualty: the 2nd-line preview text. Avatar + name still fit. */
  .dialog-preview { display: none; }
  .dialog-item { gap: var(--space-2); padding: var(--space-2); }
}
@container side (max-width: 10rem) {
  /* Name line also drops. Dialog reduces to avatar with absolute badge. */
  .dialog-info { display: none; }
  .dialog-item {
    justify-content: center;
    padding: var(--space-2) 0;
  }
  .dialog-badge {
    position: absolute;
    top: 0.25rem;
    right: 0.5rem;
  }
}
@container side (max-width: 7rem) {
  /* Ultra-compact: kill the badge too. Unread count lives on avatar
     ring colour via `.dialog-item--selected` / incoming status. */
  .dialog-badge { display: none; }
}

/* Search input + tabs also adapt — at narrow widths the search bar
   collapses to an icon-only placeholder and tabs drop their labels. */
@container side (max-width: 12rem) {
  .dialog-search__input { text-align: center; padding: var(--space-2); }
  .dialog-search__input::placeholder { font-size: 0; }   /* hide placeholder, focus still works */
  .dialog-search__input:focus { padding: var(--space-2) var(--space-3); }
  .dialog-tabs { gap: 0; }
  .dialog-tab { padding: var(--space-1); font-size: var(--t7); }
}

/* Avatar — squared with subtle radius, 2.75rem for touch */
.dialog-avatar {
  width: 2.25rem;
  height: 2.25rem;
  min-width: 2.25rem;
  min-height: 2.25rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--t6);
  font-weight: 500;
  text-transform: uppercase;
  flex-shrink: 0;
  color: var(--fg-secondary);
  background: transparent;
  border: 1px solid var(--border-strong);
  position: relative;
}

/* Avatars — monochrome: surface colour varies by elevation, not hue.
   Type distinction lives in the initial letter/badge, not a coloured
   swatch. Matches Linear/Vercel/Arc's "identity via letter" pattern. */
.dialog-avatar--ai,
.dialog-avatar--p2p,
.dialog-avatar--tg,
.dialog-avatar--tg-group,
.dialog-avatar--tg-channel,
.dialog-avatar--email {
  background: var(--bg-tertiary);
  color: var(--fg-secondary);
}

/* Avatar images for Telegram */
.dialog-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

/* Icon tab bar for dialog sections */
.dialog-tabs {
  display: flex;
  align-items: center;
  gap: 0.125rem;
  padding: 0.375rem 0.5rem;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  scrollbar-width: none;
  flex-shrink: 0;
}
.dialog-tabs::-webkit-scrollbar { display: none; }

.dialog-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;  /* Apple HIG 44pt */
  min-width: 2.75rem;
  height: 2.75rem;
  padding: 0 var(--space-3);
  border-radius: 0;
  background: transparent;
  border: none;
  color: var(--fg-tertiary);
  font-size: var(--t6);
  font-family: var(--font-mono, monospace);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  position: relative;
  transition: color 0.15s;
  flex-shrink: 0;
}
.dialog-tab:hover { color: var(--fg); }
.dialog-tab--active { background: transparent; color: var(--fg); }
.dialog-tab--active::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0; right: 0;
  height: 1px;
  background: var(--accent);
}

.dialog-tab svg { width: 1.125rem; height: 1.125rem; }

.dialog-tab__badge {
  position: absolute;
  top: 0.125rem;
  right: 0.125rem;
  min-width: 0.875rem;
  height: 0.875rem;
  border-radius: 0.4375rem;
  background: var(--accent);
  color: #fff;
  font-size: 0.5625rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 0.1875rem;
  line-height: 1;
}

.dialog-tab--add {
  color: var(--fg-muted);
  border: 1px dashed var(--border-strong);
  width: 2rem;
  height: 1.75rem;
}
.dialog-tab--add:hover { color: var(--fg-secondary); border-color: var(--fg-tertiary); }
.dialog-tab--add svg { width: 0.875rem; height: 0.875rem; }

/* Custom folder tab with name */
.dialog-tab--folder {
  width: auto;
  padding: 0 0.5rem;
  gap: 0.25rem;
  font-size: 0.6875rem;
  font-weight: 500;
}
.dialog-tab--folder span { max-width: 3rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Section headers — hidden when tabs are active */
.dialog-section-header {
  display: none;
}

/* Folder toggle on dialog items */
.dialog-folder-toggle {
  position: absolute;
  right: 0.25rem;
  top: 50%;
  transform: translateY(-50%);
  width: 1.375rem;
  height: 1.375rem;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--bg-tertiary);
  color: var(--fg-secondary);
  font-size: 0.875rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.15s;
}
.dialog-item:hover .dialog-folder-toggle { opacity: 1; }

/* Dynamic avatar colors */
.dialog-avatar[data-hue] {
  background: hsl(var(--avatar-hue, 220), 25%, 25%);
  color: hsl(var(--avatar-hue, 220), 30%, 70%);
}

[data-theme="light"] .dialog-avatar[data-hue] {
  background: hsl(var(--avatar-hue, 220), 30%, 92%);
  color: hsl(var(--avatar-hue, 220), 40%, 40%);
}

/* Content */
.dialog-content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.dialog-name {
  font-size: var(--t5);
  font-weight: 500;
  letter-spacing: -0.03em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dialog-preview {
  font-size: var(--t5);
  color: var(--fg-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dialog-preview--locked {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--fg-tertiary);
  font-size: var(--t6);
}

.dialog-preview--locked::before {
  content: "";
  width: 1rem;
  height: 1rem;
  background: currentColor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z'/%3E%3C/svg%3E")
    center / contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z'/%3E%3C/svg%3E")
    center / contain no-repeat;
}

.dialog-item--selected .dialog-preview {
  color: rgba(255, 255, 255, 0.7);
}

/* Badge — Minimalist dot style */
.dialog-badge {
  min-width: 1.125rem;
  height: 1.125rem;
  padding: 0 0.3125rem;
  background: var(--accent);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 600;
  border-radius: 99px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-shadow: 0 2px 8px var(--accent-glow);
  transition: transform 0.2s var(--ease-spring);
}

.dialog-item:hover .dialog-badge {
  transform: scale(1.1);
}

.dialog-item--selected .dialog-badge {
  background: #fff;
  color: var(--accent);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* Status dot for P2P contacts */
.dialog-status-dot {
  position: absolute;
  bottom: -1px;
  right: -1px;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 50%;
  background: var(--text-3, #999);
  border: 2px solid var(--bg, #fff);
  transition: background 0.3s ease;
}
.dialog-status-dot--online {
  background: #34c759;
}

/* Chat header status labels */
.chat-header__status {
  font-size: 0.6875rem;
  font-weight: 400;
  margin-left: 0.375rem;
}
.chat-header__status--online {
  color: #34c759;
}
.chat-header__status--offline {
  color: var(--text-3, #999);
}

.chat-header__badge {
  font-size: 0.625rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 1px 0.3125rem;
  border-radius: var(--radius-xs);
  margin-left: 0.375rem;
}
.chat-header__badge--tg { background: var(--tg); color: #fff; }
.chat-header__badge--email { background: #e65100; color: #fff; }
.chat-header__badge--ai { background: var(--accent); color: #fff; }

/* Source indicator (tiny) */
.dialog-source {
  font-size: var(--t7);
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.dialog-source--tg {
  color: var(--tg);
}

.dialog-source--email {
  color: #e65100;
  font-weight: 700;
}

.dialog-item--selected .dialog-source {
  color: rgba(255, 255, 255, 0.6);
}

/* ═══════════════════════════════════════════
   MAIN CHAT
   ═══════════════════════════════════════════ */

/* ── Chat column (Stepanov: minimal vocabulary) ─────────────────────
   `.main` is a flex column whose ONLY scrolling child is `.messages`.
   Default (desktop): a grid child that sits next to the sidebar.
   Mobile adds absolute+translate for the slide-in overlay. No
   !important: the mobile MQ adds, it never fights a desktop default. */
.main {
  grid-area: main;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  min-height: 0;
  overflow: hidden;         /* clip only: scrolling lives one level deeper */
}
@media (max-width: 48em) {
  .main {
    grid-area: content;
    position: absolute;
    inset: 0;
    z-index: 40;
    transform: translateX(100%);
    transition: transform 0.3s var(--ease-in-out);
  }
}

.chat-body {
  position: relative;
  flex: 1 1 0;              /* take all leftover vertical space */
  min-height: 0;            /* allow flex child to shrink below content */
  overflow: hidden;         /* pure clip; real scroll on .messages */
  display: flex;
  flex-direction: column;
}

/* Legacy .active class — no longer used, state via data-view */

.chat-header {
  display: grid;
  /* `auto` for the back button — when `display:none` on desktop, the
     track still exists. A fixed 2.25rem reserved the slot for content
     (since grid tracks are positional) and shoved the name into the
     tiny track. `auto` collapses to 0 when back is hidden. */
  grid-template-columns: auto 1fr auto;
  align-items: center;
  padding: 0.375rem var(--space-2);
  background: var(--bg);
  min-height: 2.5rem;
  flex-shrink: 0;
  transition: transform 0.2s var(--ease-out);
}

/* Header stays put. The previous "auto-hide on scroll" trick reflowed
   `.chat-body` every time it toggled absolute positioning, which
   caused the jumpy-scroll the user was complaining about. Removed
   entirely — real messengers keep the chat header static. */

/* Glyph buttons: < and > as text characters */
.btn--glyph {
  font-family: var(--font-mono, "SF Mono", "Fira Code", monospace);
  font-size: 1.5rem;
  font-weight: 300;
  line-height: 1;
  color: var(--fg);
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  transition: transform 0.15s var(--ease-spring), color 0.15s;
}
.btn--glyph:hover,
.btn--glyph:active,
.btn--glyph:focus {
  background: transparent !important;
  box-shadow: none !important;
}

.btn--back {
  width: 2.75rem;
  height: 2.75rem;
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--fg-secondary);
  margin-left: calc(var(--space-1) * -1);
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.3s var(--ease-spring), color 0.15s;
}
.btn--back:hover { transform: translateX(-3px); color: var(--accent); }
.btn--back:active { transform: translateX(-6px) scale(0.9); transition-duration: 0.08s; }

#chat-header-content {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.375rem;
  min-width: 0;
  width: 100%;
  /* Explicit grid placement — back button (col 1) may be display:none
     on desktop, which otherwise makes this span the first auto-flow item
     and end up in the tiny col 1. Pin to middle track. */
  grid-column: 2;
}
.chat-header__calls { grid-column: 3; }
.chat-header__name {
  /* Let the name eat all free space inside the header, shrinking with
     ellipsis only when the column genuinely can't fit it. Without this
     the span's intrinsic width collapses to content, then overflow-hidden
     paints "ar..." at a narrow intrinsic size. */
  flex: 1 1 auto;
  min-width: 0;
}
.chat-header__calls {
  display: flex;
  gap: 0.125rem;
}
.chat-header__calls .btn--icon {
  width: 2rem;
  height: 2rem;
  color: var(--fg-tertiary);
}
.chat-header__calls .btn--icon:hover {
  color: var(--accent);
}
.chat-header__name {
  font-size: var(--t4);
  font-weight: 500;
  letter-spacing: -0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#chat-target {
  flex: 1;
  font-size: var(--t3);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#chat-target strong {
  color: var(--fg);
}

/* ═══════════════════════════════════════════
   TRANSLATION
   ═══════════════════════════════════════════ */

.translate-settings {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
}

.translate-toggle {
  display: flex;
  align-items: center;
  cursor: pointer;
}

.translate-toggle input {
  display: none;
}

.translate-toggle__label {
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--t6);
  font-weight: 600;
  background: transparent;
  border: none;
  border-radius: var(--radius-xs);
  color: var(--fg-secondary);
  transition: all 0.15s ease;
}

.translate-toggle__label:hover {
  color: var(--fg);
}

.translate-toggle input:checked + .translate-toggle__label {
  background: var(--accent);
  color: #fff;
}

.translate-langs {
  display: flex;
  align-items: center;
}

.lang-select {
  appearance: none;
  background: transparent;
  border: none;
  border-radius: var(--radius-xs);
  color: var(--fg);
  font-family: var(--font);
  font-size: var(--t6);
  font-weight: 500;
  padding: var(--space-2);
  cursor: pointer;
  outline: none;
}

.lang-select:hover {
  background: var(--bg-hover);
}

.peer-lang {
  font-size: var(--t6);
  font-weight: 500;
  color: var(--fg-secondary);
  padding: var(--space-2);
}

/* ═══════════════════════════════════════════
   MESSAGES
   ═══════════════════════════════════════════ */

/* ── The one scroll root ────────────────────────────────────────────
   Stepanov §Concept: this is the `Scroller`. Everything UI-layer in
   `./scroll.js` talks to it via a tiny API — `atBottom()`,
   `toBottom()`, `preserveAnchor(fn)` — and nothing else needs to
   know it's scrollable. */
.messages {
  flex: 1 1 0;
  min-width: 0;                 /* forbid flex item from widening parent */
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain; /* stop scroll-chain up to document */
  padding: var(--space-1) var(--space-2) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  position: relative;
  scroll-padding-bottom: var(--space-6);

  /* Native sticky-bottom: when new siblings are inserted while user
     is scrolled up, the browser preserves scroll anchor instead of
     forcing content up. Combined with scroll-to-bottom-on-send in JS
     gives proper messenger feel without per-insert scroll math. */
  overflow-anchor: auto;

  /* Allow native text selection for copy-paste. The swipe-to-reply
     gesture runs from message bubbles, not the scroll container. */
  -webkit-user-select: text;
  user-select: text;
}

/* Defence against horizontal overflow. Any descendant — image,
   `<audio>`, `<pre>`, long URLs, table, embedded player — is clamped
   to the column width. Fixes the horizontal scrollbar that appeared
   in the list when a message carried wide media. */
.messages * {
  min-width: 0;
  max-width: 100%;
}
.messages img,
.messages video,
.messages audio,
.messages pre,
.messages table,
.messages iframe {
  max-width: 100%;
  height: auto;
}
.messages pre,
.messages code {
  overflow-x: auto;             /* long code scrolls inside, not list */
  white-space: pre-wrap;
  word-break: break-word;
}

.message {
  position: relative;
  display: flex;
  gap: var(--space-2);
  max-width: min(85%, 40rem);
  line-height: 1.4;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  /* Base state: no transition, no will-change. The earlier rule kept
     a GPU layer active per-message forever — compositor churn that
     showed up as visible scroll jitter once the list got long.
     Transitions are opted into by interaction states below. */
}
/* Hint the compositor only while an interaction is actually in
   flight, not for every idle bubble in the list. */
.message.swiping,
.message.pressing,
.message.swipe-return {
  will-change: transform;
  transition: transform 0.15s var(--ease-out), opacity 0.15s;
}
/* Long-press feedback — stronger than subtle scale so user feels the
   press register even when Vibration API is unavailable (iOS Safari).
   Scales down + brightens + ring expands outward like an ink drop. */
.message.pressing .message__bubble {
  transform: scale(0.94);
  opacity: 0.92;
  filter: brightness(1.15);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 40%, transparent);
  transition:
    transform 0.2s var(--ease-spring),
    opacity 0.2s,
    filter 0.2s,
    box-shadow 0.3s ease-out;
}
/* Swipe-to-reply visual */
.message.swiping {
  transition: none !important;
}
.message.swiping .message__bubble {
  transition: none;
}
/* Spring-back when released */
.message.swipe-return {
  transition: transform 0.5s var(--ease-spring) !important;
}
/* Reply arrow indicator that reveals during swipe */
.message .swipe-reply-hint {
  position: absolute;
  left: -2.5rem;
  top: 50%;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translateY(-50%) scale(0.4) rotate(-30deg);
  opacity: 0;
  color: var(--fg-tertiary);
  transition: transform 0.25s var(--ease-spring), opacity 0.15s, color 0.15s;
  pointer-events: none;
}
/* Incoming: hint on left */
.message--incoming.swiping .swipe-reply-hint {
  opacity: 1;
  transform: translateY(-50%) scale(1) rotate(0);
}
.message--incoming.swipe-triggered .swipe-reply-hint {
  color: var(--accent);
  transform: translateY(-50%) scale(1.2) rotate(0);
}
/* Outgoing: hint on right, mirrored */
.message--outgoing.swiping .swipe-reply-hint {
  opacity: 1;
  transform: translateY(-50%) scale(1) rotate(0) scaleX(-1);
}
.message--outgoing.swipe-triggered .swipe-reply-hint {
  color: var(--accent);
  transform: translateY(-50%) scale(1.2) rotate(0) scaleX(-1);
}
/* Copy-feedback: spring micro-pulse + expanding accent halo. The old
   `inset` box-shadow animation read as a weird internal glow fighting
   the text. New version keeps the bubble legible — a 1.02× scale
   acknowledges the action, a single clean outer ring provides the
   "got it" pulse, then everything settles back in 420ms. */
@keyframes copyPulse {
  0%   { transform: scale(1);      box-shadow: 0 0 0 0 var(--accent-glow); }
  40%  { transform: scale(1.02);   box-shadow: 0 0 0 6px var(--accent-glow); }
  70%  { transform: scale(1);      box-shadow: 0 0 0 10px transparent; }
  100% { transform: scale(1);      box-shadow: 0 0 0 0 transparent; }
}
.message.copied .message__bubble {
  animation: copyPulse 0.42s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Respect reduced-motion: replace animation with a brief border tint. */
@media (prefers-reduced-motion: reduce) {
  .message.copied .message__bubble {
    animation: none;
    outline: 2px solid var(--accent);
    outline-offset: -2px;
    transition: outline-color 0.5s ease-out;
  }
}
/* Allow text selection inside bubble text only */
.message__text {
  -webkit-user-select: text;
  user-select: text;
}
/* On touch devices, text selection steals the long-press gesture — iOS
   shows selection handles + callout before our 500ms context-menu timer
   fires. Disable selection for touch; desktop mouse still gets it. */
@media (hover: none) and (pointer: coarse) {
  .message__text {
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
  }
}

/* Time hidden by default, shown on tap/hover */
.message__time {
  opacity: 0;
  max-width: 0;
  overflow: hidden;
  transition: opacity 0.2s, max-width 0.2s;
}
.message:hover .message__time,
.message.show-time .message__time {
  opacity: 1;
  max-width: 3.75rem;
}

.message.message--new {
  animation: msgIn 0.4s var(--ease-spring);
}

.message--incoming {
  align-self: flex-start;
}

.message--outgoing {
  align-self: flex-end;
  flex-direction: row-reverse;
}

.message__avatar {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  display: none; /* Hidden in 1:1 chats */
  align-items: center;
  justify-content: center;
  font-size: 0.625rem;
  font-weight: 600;
  flex-shrink: 0;
  text-transform: uppercase;
  align-self: flex-end;
  background: var(--bg-tertiary);
  color: var(--fg-secondary);
}
/* Show avatars in group/email/AI chats */
.messages--group .message__avatar { display: flex; }

.message--incoming .message__avatar {
  background: hsl(var(--avatar-hue, 220), 20%, 25%);
  color: hsl(var(--avatar-hue, 220), 30%, 65%);
}

.message--outgoing .message__avatar {
  background: var(--accent-light);
  color: var(--accent);
}

.message__avatar[style*="--avatar-hue"] {
  background: hsl(var(--avatar-hue), 20%, 25%);
  color: hsl(var(--avatar-hue), 30%, 65%);
}

/* Bubble geometry — messenger-standard asymmetric radius.
   Standalone / first-in-group: full radius on three corners, a small
   "tail" radius on bottom-speaker-side (incoming→bottom-left,
   outgoing→bottom-right). The tail replaces a full SVG chat-tail —
   cheaper to render, reads the same ("this bubble points at me").
   Grouped (consecutive same-sender, not first): also tightens the
   TOP-speaker-side corner so consecutive bubbles visually join. */
.message__bubble {
  position: relative;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  font-size: var(--t3);
  line-height: 1.5;
  min-width: 3rem;  /* prevent "Tt"-narrow bubbles from looking like badges */
  overflow: hidden;
  overflow-wrap: break-word;
  word-break: break-word;
}

/* Bubble padding per Awwwards chat-UI research (2025): 12px side,
   8px vertical, asymmetric so thumb/cursor lands easily on content. */
.message__bubble {
  padding: 0.5rem 0.75rem;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}

.message--incoming .message__bubble {
  background: var(--bg-tertiary);
  border-bottom-left-radius: var(--radius-xs);
}
.message--outgoing .message__bubble {
  background: var(--bg-hover);
  color: var(--fg);
  border-bottom-right-radius: var(--radius-xs);
}

/* Grouped-bubble adaptive radius (Facebook Messenger technique via
   CSS logical properties — auto-flips for RTL). Consecutive messages
   from same sender "stack" with sharp corners facing each other and
   rounded corners outward, without needing per-position classes. */
.message--grouped .message__bubble {
  border-start-start-radius: var(--radius-xs);
}
.message--outgoing.message--grouped .message__bubble {
  border-start-end-radius: var(--radius-xs);
  border-start-start-radius: var(--radius);  /* reset incoming's */
}
/* When this bubble has a grouped follower, its "tail" corner becomes
   sharp — the next bubble continues the thread visually. */
.message:not(:last-child).message--incoming:has(+ .message--incoming.message--grouped) .message__bubble {
  border-end-start-radius: var(--radius-xs);
}
.message:not(:last-child).message--outgoing:has(+ .message--outgoing.message--grouped) .message__bubble {
  border-end-end-radius: var(--radius-xs);
}

/* Grouped — tighter vertical rhythm only. We deliberately do NOT change
   the border-radius of grouped bubbles: doing so used to produce a
   visual mismatch where the first-of-group had 1 sharp corner while the
   rest had 2, reading as "half round / half square". Uniform radii +
   compressed gap gives the same "thought cluster" feel with zero
   corner inconsistency. */
.messages .message.message--grouped {
  margin-top: -2px;    /* collapses the 3px gap to 1px within a group */
}

[data-theme="light"] .message--outgoing .message__bubble {
  background: rgba(0, 0, 0, 0.04);
  color: var(--fg);
}

/* Grouped messages — hide repeated avatar/name */
.message--grouped .message__avatar {
  visibility: hidden;
}

.message--grouped .message__header {
  display: none;
}

/* Legacy flat-radius + extra margin-top overrides on grouped bubbles
   removed — they were the actual source of "half round / half square":
   first bubble kept the asymmetric tail (--radius + --radius-xs), every
   grouped one got reset to a uniform --radius-sm with no tail. Now all
   bubbles share geometry; the margin-top collapse for grouping is
   defined once, in the `.messages .message.message--grouped` rule above. */

@keyframes msgIn {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.message__header {
  display: none; /* Hidden by default in 1:1 chats */
  align-items: center;
  gap: var(--space-2);
  font-size: var(--t7);
  color: var(--fg-muted);
  margin-bottom: 0.125rem;
}

/* Show header only in group/email/AI chats */
.messages--group .message__header { display: flex; }

.message--outgoing .message__header {
  justify-content: flex-end;
}

.message--system {
  align-self: center;
  max-width: 90%;
}

.message--system .message__bubble {
  background: var(--bg-hover);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-align: center;
  font-size: var(--t5);
  color: var(--fg-secondary);
  padding: var(--space-2) var(--space-4);
}

.message--system .message__avatar {
  display: none;
}

.message__sender {
  font-weight: 500;
  font-size: var(--t6);
  color: var(--fg-tertiary);
}

.message__time {
  font-variant-numeric: tabular-nums;
}

.message__subject {
  font-weight: 600;
  font-size: 0.85em;
  opacity: 0.7;
  margin-bottom: 0.25rem;
  font-style: italic;
}

.message__status {
  font-size: 0.625rem;
  opacity: 0.6;
}

.message__status--sent,
.message__status--delivered,
.message__status--read {
  display: inline-flex;
  width: 1rem;
  height: 1rem;
}

.message__status--sent {
  background: currentColor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E")
    center/contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E")
    center/contain no-repeat;
}

.message__status--delivered {
  background: currentColor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 7l-1.41-1.41-6.34 6.34 1.41 1.41L18 7zm4.24-1.41L11.66 16.17 7.48 12l-1.41 1.41L11.66 19l12-12-1.42-1.41zM.41 13.41L6 19l1.41-1.41L1.83 12 .41 13.41z'/%3E%3C/svg%3E")
    center/contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 7l-1.41-1.41-6.34 6.34 1.41 1.41L18 7zm4.24-1.41L11.66 16.17 7.48 12l-1.41 1.41L11.66 19l12-12-1.42-1.41zM.41 13.41L6 19l1.41-1.41L1.83 12 .41 13.41z'/%3E%3C/svg%3E")
    center/contain no-repeat;
}

.message__status--read {
  background: var(--fg);  /* monochrome: read = brighter than delivered */
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 7l-1.41-1.41-6.34 6.34 1.41 1.41L18 7zm4.24-1.41L11.66 16.17 7.48 12l-1.41 1.41L11.66 19l12-12-1.42-1.41zM.41 13.41L6 19l1.41-1.41L1.83 12 .41 13.41z'/%3E%3C/svg%3E")
    center/contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 7l-1.41-1.41-6.34 6.34 1.41 1.41L18 7zm4.24-1.41L11.66 16.17 7.48 12l-1.41 1.41L11.66 19l12-12-1.42-1.41zM.41 13.41L6 19l1.41-1.41L1.83 12 .41 13.41z'/%3E%3C/svg%3E")
    center/contain no-repeat;
}

.message__lock {
  display: inline-flex;
  opacity: 0.5;
}

/* Email signature pinned footer */
.email-signatures {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border-top: 1px solid var(--border);
  background: var(--bg-secondary);
  max-height: 30vh;
  overflow-y: auto;
  flex-shrink: 0;
}

.email-sig {
  flex: 1;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--t5);
  line-height: 1.3;
  color: var(--text-secondary);
  background: var(--bg);
  cursor: pointer;
  max-height: 5em;
  overflow: hidden;
  transition: max-height 0.2s;
  white-space: pre-line;
}

.email-sig.expanded {
  max-height: none;
}

.email-sig__label {
  font-weight: 600;
  font-size: var(--t6);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: var(--space-1);
  color: var(--text-tertiary);
}

.email-sig--incoming {
  border-left: 3px solid var(--accent-secondary, #888);
}

.email-sig--outgoing {
  border-right: 3px solid var(--accent, #f5f5f5);
}

/* Typing indicator — wave style */
.typing-indicator {
  display: none;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  font-size: var(--t6);
  color: var(--fg-muted);
  flex-shrink: 0;
}

.typing-indicator.visible {
  display: flex;
  animation: fadeIn 0.2s ease-out;
}

.typing-indicator__dots {
  display: flex;
  gap: 0.375rem;
}

.typing-indicator__dots span {
  width: 0.375rem;
  height: 0.375rem;
  background: var(--accent);
  border-radius: 50%;
  animation: typingWave 1.2s ease-in-out infinite;
}

.typing-indicator__dots span:nth-child(2) {
  animation-delay: 0.15s;
}

.typing-indicator__dots span:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes typingWave {
  0%,
  60%,
  100% {
    transform: translateY(0);
    opacity: 0.4;
  }
  30% {
    transform: translateY(-4px);
    opacity: 1;
  }
}

/* ═══════════════════════════════════════════
   EMPTY STATES
   ═══════════════════════════════════════════ */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  height: 100%;
  color: var(--fg-tertiary);
  animation: fadeIn 0.4s ease-out;
  user-select: none;
}

.empty-state__icon {
  opacity: 0.3;
}

.empty-state__text {
  font-size: var(--t3);
  font-weight: 500;
}

/* ═══════════════════════════════════════════
   LOADING STATES
   ═══════════════════════════════════════════ */

.loading-state {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: var(--space-6);
}

.loading-state--inline {
  height: auto;
  padding: var(--space-3);
}

.loading-spinner {
  width: 1.5rem;
  height: 1.5rem;
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
}

.loading-spinner--small {
  width: 1rem;
  height: 1rem;
}

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

/* ═══════════════════════════════════════════
   LAZY LOAD SPINNER
   ═══════════════════════════════════════════ */
.lazy-load-spinner {
  text-align: center;
  padding: 0.5rem;
  font-size: 0.75rem;
  color: var(--text-secondary);
  opacity: 0.7;
}

/* ═══════════════════════════════════════════
   MESSAGE CONTEXT MENU
   ═══════════════════════════════════════════ */
/* iOS-style context menu — full-screen backdrop blur, pressed bubble
   scales up, menu pops with overshoot spring. Mirrors Telegram iOS +
   UIKit `UIContextMenuInteraction` pattern (rockyshikoku medium). */
/* Z-order stack: toasts live at 9999+, so the long-press UI sits above
   the page but below critical system toasts. */
.msg-context-backdrop {
  position: fixed;
  inset: 0;
  z-index: 9996;
  background: rgba(0, 0, 0, 0);
  backdrop-filter: blur(0);
  -webkit-backdrop-filter: blur(0);
  pointer-events: none;
  transition: background 0.2s ease, backdrop-filter 0.2s ease;
}
.msg-context-backdrop--active {
  background: rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  pointer-events: auto;
}

/* Pressed bubble scales up and lifts ABOVE the backdrop. The
   `isolation: isolate` forces a new stacking context so the bubble's
   z-index actually wins against siblings in `.messages`. */
.message--menu-open {
  position: relative;
  z-index: 9997;
  isolation: isolate;
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  transform: scale(1.03);
  filter: drop-shadow(0 8px 24px rgba(0,0,0,0.35));
}

.msg-context-menu {
  position: fixed;
  z-index: 9998;
  flex-direction: column;
  min-width: 11rem;
  max-width: calc(100vw - 1rem);
  /* No overflow — 4 actions (reply/copy/edit/delete) always fit. A
     scrollbar inside the menu looked ugly and clipped the corner radius. */
  overflow: visible;
  background: rgba(22, 22, 22, 0.9);
  backdrop-filter: blur(1.5rem);
  -webkit-backdrop-filter: blur(1.5rem);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 0.75rem;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
  padding: 0.375rem;
  gap: 0.125rem;
  opacity: 0;
  transform: scale(0.85);
  transform-origin: top left;  /* overridden inline per msg alignment */
  transition: opacity 0.18s ease-out,
              transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
  pointer-events: none;
}
.msg-context-menu--visible {
  opacity: 1;
  transform: scale(1);
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .message--menu-open,
  .msg-context-menu { transition-duration: 0s; }
}
.msg-context-menu__item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.625rem 0.875rem;
  background: none;
  border: none;
  color: var(--fg);
  font-size: var(--t5);
  cursor: pointer;
  border-radius: 0.125rem;
  text-align: left;
  transition: background 0.15s, transform 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.msg-context-menu__item:active {
  transform: scale(0.96);
}
.msg-context-menu__item:hover {
  background: var(--bg-hover);
}
.msg-context-menu__item--danger {
  color: var(--danger);
}
.msg-context-menu__item--danger:hover {
  background: color-mix(in srgb, var(--danger) 18%, transparent);
}

/* ═══════════════════════════════════════════
   EDIT BAR
   ═══════════════════════════════════════════ */
.edit-bar {
  display: flex;
  align-items: center;
  padding: 0.375rem 0.75rem;
  background: var(--bg-secondary);
  border-top: 1px solid var(--border);
  gap: 0.5rem;
}
.edit-bar__content {
  flex: 1;
  min-width: 0;
}
.edit-bar__label {
  font-size: 0.7rem;
  color: var(--accent);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03125rem;
}
.edit-bar__text {
  font-size: 0.8rem;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.edit-bar__close {
  background: none;
  border: none;
  color: var(--text-secondary);
  cursor: pointer;
  padding: 0.25rem;
  border-radius: 0.25rem;
  flex-shrink: 0;
}
.edit-bar__close:hover {
  color: var(--text-primary);
  background: var(--bg-hover);
}

/* Edited message indicator */
.message__edited {
  font-size: 0.65rem;
  color: var(--text-secondary);
  opacity: 0.7;
  margin-left: 0.25rem;
}

/* ═══════════════════════════════════════════
   DROP OVERLAY
   ═══════════════════════════════════════════ */

.drop-overlay {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 100;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(4px);
  align-items: center;
  justify-content: center;
}

.drop-overlay.visible {
  display: flex;
}

.drop-overlay__content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  color: var(--fg);
  padding: var(--space-8);
  border: 2px dashed var(--accent);
  border-radius: var(--radius);
  animation: fadeIn 0.15s ease-out;
}

.drop-overlay__text {
  font-size: var(--t2);
  font-weight: 500;
}

/* ═══════════════════════════════════════════
   REPLY BAR
   ═══════════════════════════════════════════ */

.reply-bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  background: var(--bg-tertiary);
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

.reply-bar__content {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}

.reply-bar__sender {
  font-size: var(--t6);
  font-weight: 600;
  color: var(--accent);
}

.reply-bar__text {
  font-size: var(--t6);
  color: var(--fg-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.reply-bar__close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  background: none;
  border: none;
  color: var(--fg-tertiary);
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  border-radius: var(--radius-xs);
}

.reply-bar__close:hover {
  color: var(--fg);
}

/* Quoted text in messages */
.message__text blockquote,
.message__text .quote {
  border-left: 2px solid var(--accent);
  padding-left: var(--space-2);
  margin: 0 0 var(--space-1);
  color: var(--fg-secondary);
  font-size: var(--t5);
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.message__text {
  color: var(--fg);
  word-break: break-word;
  overflow-wrap: anywhere;
}

.message__text a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-color: var(--accent-light);
}

.message__text a:hover {
  text-decoration-color: var(--accent);
}

/* Email formatting */
.email-subject {
  font-weight: 600;
  margin-bottom: var(--space-2);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--border);
}

.email-body {
  line-height: 1.5;
}

.email-quote {
  border-left: 2px solid var(--accent);
  padding-left: var(--space-2);
  margin: var(--space-1) 0;
  color: var(--fg-secondary);
  font-size: var(--t5);
}

.email-signature {
  margin-top: var(--space-2);
  padding-top: var(--space-1);
  border-top: 1px solid var(--border);
  color: var(--fg-secondary);
  font-size: var(--t5);
}

.message__original {
  font-size: var(--t6);
  color: var(--fg-muted);
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--border);
  font-style: italic;
  opacity: 0.7;
}

/* ═══════════════════════════════════════════
   INPUT
   ═══════════════════════════════════════════ */

/* ── Composer ───────────────────────────────────────────────────────
   Pinned to the bottom of the chat column by virtue of DOM order
   (last child of `.main`). `flex-shrink: 0` keeps it from collapsing
   when the keyboard or virtual viewport shortens height. Grid uses
   implicit track sizing — children define their own widths via
   `auto` — so adding or removing an icon button doesn't require
   rewriting column-count arithmetic. */
/* Floating "scroll to newest" button. Hidden by default; scroll.js
   toggles `--visible` when user scrolls up from the bottom. Lives
   inside `.chat-body` (position: relative), anchored bottom-right. */
.scroll-bottom-fab {
  position: absolute;
  right: var(--space-3);
  bottom: var(--space-3);
  width: 2.75rem;
  height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elevated, var(--bg-tertiary));
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 50%;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
  cursor: pointer;
  opacity: 0;
  transform: translateY(0.75rem);
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 5;
}
.scroll-bottom-fab--visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.scroll-bottom-fab:hover { background: var(--bg-hover, var(--bg-tertiary)); border-color: var(--accent); }
.scroll-bottom-fab svg { width: 1.25rem; height: 1.25rem; stroke: currentColor; }
.scroll-bottom-fab__badge {
  position: absolute;
  top: -0.25rem;
  right: -0.25rem;
  min-width: 1.125rem;
  height: 1.125rem;
  padding: 0 0.375rem;
  background: var(--accent);
  color: #1a1a1a;
  font-size: var(--t7, 0.6875rem);
  font-weight: 600;
  line-height: 1.125rem;
  border-radius: 0.5625rem;
  text-align: center;
}
.scroll-bottom-fab__badge[hidden] { display: none; }

/* Visually hidden but accessible to screen readers (a11y convention) —
   absolute positioning takes it out of grid flow, otherwise the <label>
   becomes a visible empty cell that breaks the 4-column input-area grid. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.email-meta {
  padding: 0.25rem 0.75rem;
  font-size: 0.75rem;
  color: var(--fg-dim, #888);
  display: flex;
  gap: 0.5rem;
  align-items: center;
  border-top: 1px solid var(--border);
}
.email-meta__from {
  font-family: monospace;
  color: var(--fg, #fafaf9);
}
.email-meta__sig {
  margin-left: auto;
  font-style: italic;
  opacity: 0.7;
}

.input-area {
  display: grid;
  grid-template-columns: auto auto 1fr auto;  /* attach | voice | text | send */
  align-items: end;
  gap: 0;
  /* iOS screen corners are radius ~44-48pt — keep buttons inside the
     safe viewing area. Horizontal padding scales with safe-area-inset
     so landscape-notch phones keep buttons off the camera housing. */
  padding: var(--space-2);
  padding-inline-start: max(var(--space-3), env(safe-area-inset-left));
  padding-inline-end: max(var(--space-3), env(safe-area-inset-right));
  padding-bottom: max(var(--space-2), env(safe-area-inset-bottom));
  /* iOS-style elevation + rounded top corners matching device curve.
     Top border-radius so the composer "hugs" the bottom of the screen
     instead of meeting it at a 90° angle, which looks clipped against
     iPhone's rounded display. */
  background: color-mix(in srgb, var(--bg-elevated, var(--bg-secondary)) 92%, transparent);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-top: 1px solid var(--border);
  border-radius: 1rem 1rem 0 0;
  box-shadow:
    0 -0.25rem 0.75rem rgba(0, 0, 0, 0.12),
    0 -0.75rem 2rem rgba(0, 0, 0, 0.06);
  flex-shrink: 0;
  position: relative;
  z-index: 2;  /* above messages list so shadow shows */
}

/* Floating pill composer — uses a CONTAINER query on `.main` so it
   kicks in when the chat column itself is narrow (split-screen, DevTools
   open, sidebar visible), not just on small viewports. Viewport-based
   media query missed the common case of a narrow chat column on desktop. */
.main { container-type: inline-size; container-name: chat; }
@container chat (max-width: 48em) {
  .input-area {
    margin-inline: max(var(--space-2), env(safe-area-inset-left));
    margin-inline-end: max(var(--space-2), env(safe-area-inset-right));
    margin-bottom: max(var(--space-2), env(safe-area-inset-bottom));
    padding-bottom: var(--space-2);
    border-radius: 1.25rem;
    border: 1px solid var(--border);
  }
}
@media (max-width: 48em) {
  .input-area {
    margin-inline: max(var(--space-2), env(safe-area-inset-left));
    margin-inline-end: max(var(--space-2), env(safe-area-inset-right));
    margin-bottom: max(var(--space-2), env(safe-area-inset-bottom));
    padding-bottom: var(--space-2);
    border-radius: 1.25rem;
    border: 1px solid var(--border);
  }
}

.input-autocomplete {
  bottom: 100%;
  top: auto;
  margin-bottom: 0.25rem;
  margin-top: 0;
  box-shadow: 0 -0.25rem 0.75rem rgba(0, 0, 0, 0.3);
}

.input {
  flex: 1;
  padding: var(--space-2) var(--space-3);
  font-size: 1rem;
  font-family: var(--font);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  color: var(--fg);
  outline: none;
  min-height: 2.75rem;  /* HIG 44pt */
  max-height: clamp(6.25rem, 25vh, 12.5rem);
  resize: none;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  line-height: 1.4;
  field-sizing: content;
  transition: background var(--duration-fast) var(--ease-out);
}
.input:focus {
  background: transparent;
  border-bottom-color: var(--accent);
  box-shadow: none;
}

.input::placeholder {
  color: var(--fg-muted);
}

/* ═══════════════════════════════════════════
   BUTTONS
   ═══════════════════════════════════════════ */

.btn {
  padding: var(--space-2) var(--space-3);
  font-size: var(--t5);
  font-weight: 500;
  font-family: var(--font);
  background: var(--bg-tertiary);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: all var(--duration-fast) var(--ease-out);
}

.btn:hover {
  background: var(--bg-hover);
  border-color: var(--border-strong);
}

.btn:active {
  transform: scale(0.98);
}

.btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.btn--primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

.btn--primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

.btn--send {
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: var(--fg-tertiary);
  border: none;
  cursor: pointer;
  transition:
    background 0.2s ease,
    transform 0.3s var(--ease-spring),
    color 0.2s;
  position: relative;
  /* Long-press to record — iOS defaults cancel pointerdown mid-press:
     - tap-highlight-color shows a grey flash
     - touch-callout shows the system "copy/look up" menu after ~500ms
     - user-select triggers text selection
     - touch-action: manipulation prevents double-tap zoom from eating the press
     All four must be off for the hold gesture to survive to pointerup. */
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
}
.send-icon {
  position: absolute;
  transition: opacity 0.25s, transform 0.35s var(--ease-spring);
}
.send-icon--arrow { opacity: 0; transform: scale(0.3) rotate(-90deg); font-size: 1.375rem; font-weight: 700; }
.send-icon--mic { opacity: 1; transform: scale(1); }
/* When typing -- show arrow, hide mic */
.btn--send.has-text { color: var(--accent); }
.btn--send.has-text .send-icon--arrow { opacity: 1; transform: scale(1.1) rotate(0); }
.btn--send.has-text .send-icon--mic { opacity: 0; transform: scale(0.3) rotate(90deg); }

.btn--attach {
  width: 2.75rem;
  height: 2.75rem;
  font-size: 1.375rem;
  color: var(--fg-tertiary);
  background: transparent;
  border: none;
  transition: transform 0.3s var(--ease-spring), color 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.btn--attach:hover { color: var(--accent); transform: rotate(45deg); }

.btn--send:hover { color: var(--fg); }
.btn--send.has-text:hover {
  color: var(--accent);
  transform: scale(1.15);
}
.btn--send.has-text:active {
  transform: scale(0.9);
  transition-duration: 0.08s;
}
/* Send pulse on submit */
.btn--send.sending {
  animation: sendPulse 0.4s var(--ease-spring);
}
@keyframes sendPulse {
  0% { transform: scale(1); }
  30% { transform: scale(0.75); }
  60% { transform: scale(1.2); }
  100% { transform: scale(1); }
}

.btn--send.recording {
  color: var(--danger);
  animation: recPulse 1s ease-in-out infinite;
}
.btn--send.recording .send-icon {
  transform: scale(1.2);
}
@keyframes recPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.5; transform: scale(1.1); }
}

/* Base `.btn` — was missing entirely. Settings/modal buttons carry
   just `class="btn btn--small"`, so without this rule they rendered
   as padding-only naked text. Modifiers below specialise shape/colour;
   `.btn--icon` still overrides background+border to transparent via
   its own !important declarations. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--bg-tertiary);
  color: var(--fg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  font-family: var(--font);
  font-size: var(--t4);
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    color 0.15s ease,
    transform 0.05s ease;
  text-decoration: none;
  white-space: nowrap;
}
.btn:hover {
  background: var(--bg-hover);
  border-color: var(--accent);
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Selected / active state — used by settings toggles (theme, input
   position, sound on/off) where two/three buttons form a pseudo-radio. */
.btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #1a1a1a;
  font-weight: 600;
}
.btn.active:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

/* Primary — single dominant action (e.g. "save passkey"). */
.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #1a1a1a;
  font-weight: 600;
}
.btn--primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

.btn--small {
  padding: var(--space-1) var(--space-2);
  font-size: var(--t6);
  border-radius: var(--radius-xs);
}

.btn--danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}
.btn--danger:hover {
  background: #c14a3f;
  border-color: #c14a3f;
}

/* ═══════════════════════════════════════════
   CALL UI - Fullscreen WebGL Scene
   ═══════════════════════════════════════════ */

/* Incoming call — fullscreen, safe area aware */
/* Dial pad */
.dialpad-overlay {
  position: fixed;
  inset: 0;
  z-index: 9998;
  background: rgba(0, 0, 0, 0.85);
  display: flex;
  align-items: center;
  justify-content: center;
}
.dialpad {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-6);
  max-width: 17.5rem;
  width: 100%;
}
.dialpad__input {
  width: 100%;
  font-size: 1.5rem;
  text-align: center;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--fg-2);
  color: var(--fg);
  padding: var(--space-3) 0;
  font-family: var(--font-mono);
  letter-spacing: 2px;
}
.dialpad__input:focus { outline: none; border-color: var(--fg); }
.dialpad__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
  width: 100%;
}
.dialpad__key {
  aspect-ratio: 1;
  font-size: 1.25rem;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  color: var(--fg);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.dialpad__key:active { background: var(--fg-2); }
.dialpad__actions {
  display: flex;
  gap: var(--space-4);
  align-items: center;
  width: 100%;
  justify-content: space-between;
}
.dialpad__actions .call-btn--accept { width: 3rem; height: 3rem; }

.incoming-call-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background:
    linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px),
    #000;
  background-size: 32px 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  transform: translateY(100%);
  transition: transform 0.35s cubic-bezier(0.32, 0.72, 0, 1);
  will-change: transform;
}
.incoming-call-overlay.active {
  transform: translateY(0);
}

.incoming-call-overlay .call-ui {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-8);
  text-align: center;
  width: 100%;
  max-width: 22.5rem;
}

.call-avatar {
  width: 7.5rem;
  height: 7.5rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.7);
  font-size: 2.5rem;
  font-weight: 300;
  font-family: var(--font-mono, monospace);
  letter-spacing: 2px;
  animation: avatar-pulse 2s ease-in-out infinite;
}

@keyframes avatar-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(255,255,255,0.1); }
  50% { transform: scale(1.03); box-shadow: 0 0 60px rgba(255,255,255,0.08); }
}

.call-info {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.call-status {
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.4);
  text-transform: uppercase;
  letter-spacing: 3px;
  font-family: var(--font-mono, monospace);
  animation: status-blink 1.5s ease-in-out infinite;
}

@keyframes status-blink {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1; }
}

.call-name {
  font-size: 2rem;
  font-weight: 300;
  color: #fff;
  letter-spacing: -0.0.3125rem;
}

.call-buttons {
  display: flex;
  gap: 5rem;
  margin-top: var(--space-8);
  align-items: center;
}

.call-btn-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

.call-btn__label {
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 0.03125rem;
}

.call-btn {
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.15s ease;
  position: relative;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.call-btn svg {
  width: 1.75rem;
  height: 1.75rem;
}

/* Call-control colours are safety-critical — iOS/Apple HIG keeps accept
   solid green and reject solid red even in otherwise monochrome UIs so
   users never misidentify them under pressure. Hard-coded, not tokens. */
.call-btn--accept {
  background: #34c759;  /* iOS system green */
  color: #fff;
}

.call-btn--accept::before {
  content: "";
  position: absolute;
  inset: -0.5rem;
  border-radius: 50%;
  border: 2px solid #34c759;
  animation: ring-expand 1.5s ease-out infinite;
}

.call-btn--accept::after {
  content: "";
  position: absolute;
  inset: -1rem;
  border-radius: 50%;
  border: 1px solid #34c759;
  animation: ring-expand 1.5s ease-out infinite 0.3s;
  opacity: 0.5;
}

@keyframes ring-expand {
  0% { transform: scale(0.8); opacity: 1; }
  100% { transform: scale(1.4); opacity: 0; }
}

.call-btn--reject {
  background: #ff3b30;  /* iOS system red — safety-critical, always red */
  color: #fff;
}

.call-btn:active {
  transform: scale(0.9);
}

/* Legacy support */
.incoming-call { display: none !important; }
.call-actions { display: none !important; }

/* Call button in header */
.btn--call {
  background: var(--bg-tertiary);
  color: var(--fg-secondary);
  border: none;
  border-radius: var(--radius-sm);
  width: 2.25rem;
  height: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all var(--duration-fast) var(--ease-out);
  margin-left: auto;
  -webkit-tap-highlight-color: transparent;
}

.btn--call:hover {
  background: var(--bg-hover);
  color: var(--success);
}

.btn--call:active {
  transform: scale(0.95);
}

.btn--call svg {
  width: 1.125rem;
  height: 1.125rem;
  fill: currentColor;
}

/* ═══════════════════════════════════════════
   CALL OVERLAY (video + audio) — PWA safe
   ═══════════════════════════════════════════ */

.call-overlay {
  position: fixed;
  inset: 0;
  background: #000;
  z-index: 9999;
  display: flex;
  align-items: stretch;
  justify-content: stretch;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left);
  /* Slide up from bottom */
  transform: translateY(100%);
  transition: transform 0.35s cubic-bezier(0.32, 0.72, 0, 1);
  will-change: transform;
}
.call-overlay.active {
  transform: translateY(0);
}

/* Call controls muted state */
.call-ctrl--off {
  background: rgba(255,60,60,0.3) !important;
  border-color: var(--danger) !important;
}
.call-ctrl--off svg { fill: var(--danger); }

/* Audio-only call: HIDE video visually but keep it in the layout.
   `display: none` stops HTMLMediaElement playback on Chrome/Safari —
   audio tracks inside a hidden <video> go silent even though the
   underlying MediaStream still has them. Collapse to a zero-sized
   invisible element instead so the track keeps playing. */
.call-overlay--audio #remote-video,
.call-overlay--audio #local-video {
  width: 0;
  height: 0;
  opacity: 0;
  position: absolute;
  pointer-events: none;
}
.call-overlay--audio {
  align-items: center;
  justify-content: center;
  flex-direction: column;
  background: #000;
}

/* Dot-grid animation for calling/audio state (Linear) */
.call-overlay--audio::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba(255,255,255,0.12) 1px, transparent 1px);
  background-size: 32px 32px;
  animation: dotPulse 3.2s steps(1, end) infinite;
  pointer-events: none;
  z-index: 0;
}
@keyframes dotPulse {
  0%, 100% { opacity: 0.3; }
  50% { opacity: 0.8; }
}
.call-overlay--audio .call-overlay__bar {
  position: static;
  margin-top: var(--space-8);
  background: none;
}
.call-overlay--audio .call-overlay__peer { display: none; }

/* Remote video: fill entire screen */
#remote-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #111;
}

/* Local video: PiP in corner */
#local-video {
  position: absolute;
  bottom: 6.25rem;
  right: var(--space-4);
  width: 6.25rem;
  aspect-ratio: 3/4;
  object-fit: cover;
  background: #000;
  border: none;
  z-index: 2;
  border-radius: 2px;
}

/* Center content (avatar + name + timer) for audio calls */
.call-overlay__center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  z-index: 1;
  flex: 1;
}

.call-overlay__avatar {
  width: 6.25rem;
  height: 6.25rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.6);
  font-size: 2.25rem;
  font-weight: 300;
  font-family: var(--font-mono, monospace);
  letter-spacing: 2px;
}

.call-overlay__name {
  font-size: 1.5rem;
  font-weight: 300;
  color: #fff;
  letter-spacing: -0.04em;
}

.call-overlay__timer {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.4);
  font-family: var(--font-mono, monospace);
  letter-spacing: 0.15em;
}

/* Live subtitles */
.call-subtitles {
  position: absolute;
  bottom: 6.25rem;
  left: var(--space-4);
  right: var(--space-4);
  z-index: 4;
  text-align: center;
  pointer-events: none;
}
.call-subtitles__line {
  display: inline-block;
  background: rgba(0, 0, 0, 0.7);
  color: #fff;
  font-size: var(--t4);
  letter-spacing: -0.02em;
  padding: var(--space-1) var(--space-3);
  border-radius: 2px;
  max-width: 100%;
  animation: fadeInUp 0.2s var(--ease-out);
}

/* Bottom controls bar — safe area for home indicator */
.call-overlay__bar {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-6) var(--space-6) calc(var(--space-6) + env(safe-area-inset-bottom));
  background: linear-gradient(transparent, rgba(0,0,0,0.8));
  z-index: 3;
}

.call-overlay__peer {
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.4);
  font-family: var(--font-mono, monospace);
}

.call-overlay__controls {
  display: flex;
  gap: var(--space-4);
  align-items: center;
}

.call-ctrl {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.15);
  background: rgba(255,255,255,0.08);
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s, transform 0.1s;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.call-ctrl:active {
  transform: scale(0.9);
}

.call-ctrl.muted {
  background: var(--danger);
  border-color: var(--danger);
}

.call-ctrl--end {
  background: var(--danger);
  border-color: var(--danger);
  width: 4rem;
  height: 3.25rem;
  border-radius: 26px;
}

.call-ctrl--end:active {
  background: #e02020;
}

/* ═══════════════════════════════════════════
   OVERLAY / MODAL
   ═══════════════════════════════════════════ */

.overlay {
  position: fixed;
  inset: 0;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

/* ═══════════════════════════════════════════
   LOGIN
   ═══════════════════════════════════════════ */

.login {
  flex-direction: column;
  overflow: hidden;
}

/* Decorative overlays from the Swiss-Red era — retired. Kept in DOM
   (aria-hidden) so no markup diff, hidden via CSS. */
.login__grid, .login__scan { display: none; }

.login__box {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: 22rem;
  max-width: 100%;
  padding: var(--space-8) var(--space-6);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}

.login__box #nickname-form {
  display: contents;   /* form participates in parent's flex layout */
}

.login__logo {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  justify-content: center;
}
.login__logo svg { color: var(--accent); }

.login__title {
  font-family: var(--font);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-transform: none;
  color: var(--fg);
}

.login__input {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-xs);
  padding: var(--space-3) var(--space-4);
  font-size: 0.9375rem;
  font-family: var(--font);
  color: var(--fg);
  outline: none;
  text-align: left;
  letter-spacing: 0;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.login__input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.login__input::placeholder { color: var(--fg-tertiary); }

/* Primary CTA — filled amber. Replaces the mono "> enter" text-only
   button. The text "> enter" in HTML is harmless (reads as "> enter"
   on the solid button) but we recommend updating it to "Continue". */
.login__btn {
  width: 100%;
  background: var(--accent);
  border: 1px solid var(--accent);
  color: #1a1a1a;
  font-family: var(--font);
  font-size: 0.9375rem;
  font-weight: 600;
  cursor: pointer;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  transition: background 0.15s, transform 0.05s;
  letter-spacing: 0;
}
.login__btn:hover   { background: var(--accent-hover); border-color: var(--accent-hover); }
.login__btn:active  { transform: translateY(1px); }

.login__error {
  color: var(--danger);
  font-size: 0.8125rem;
  font-family: var(--font);
  min-height: 1rem;
  text-align: left;
}
.login__hint {
  font-size: 0.75rem;
  color: var(--fg-tertiary);
  font-family: var(--font);
  letter-spacing: 0;
  text-align: center;
  margin-top: var(--space-2);
}

.login__passkey {
  margin-top: var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
  width: 100%;
  text-align: center;
}
.login__passkey-btn {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--fg-secondary);
  font-family: var(--font);
  font-size: 0.8125rem;
  font-weight: 500;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-xs);
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
  letter-spacing: 0;
}
.login__passkey-btn:hover {
  border-color: var(--accent);
  color: var(--fg);
  background: var(--accent-light);
}

.overlay--settings {
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(0.5rem);
  -webkit-backdrop-filter: blur(0.5rem);
}

.modal {
  width: 90%;
  max-width: 22.5rem;
  padding: var(--space-8);
  border: 1px solid var(--fg);
  background: var(--bg);
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: var(--shadow-lg);
}

.modal--settings {
  max-width: 25rem;
  width: 100%;
  background: var(--bg-secondary);
  border: none;
  border-radius: var(--radius);
  padding: var(--space-6);
}

/* ═══════════════════════════════════════════
   SETTINGS DRAWER (slide-over)
   ═══════════════════════════════════════════ */

.settings-backdrop {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: rgba(0, 0, 0, 0.4);
}

.settings-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 21.25rem;
  z-index: 1000;
  background: var(--bg);
  border-left: 1px solid var(--border-strong);
  display: flex;
  flex-direction: column;
  animation: drawerIn 0.15s var(--ease-out);
  box-shadow: var(--shadow-lg);
}

@keyframes drawerIn {
  from { transform: translateX(100%); }
  to { transform: none; }
}

.settings-drawer__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--space-4);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.settings-drawer__title {
  font-size: var(--t2);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-secondary);
}

.settings-drawer__body {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-4);
}

/* Groups */
.settings-group {
  margin-bottom: var(--space-6);
}

.settings-group__title {
  font-size: var(--t6);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--fg-tertiary);
  margin-bottom: var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border);
}

/* Row: label left, control right */
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) 0;
  gap: var(--space-3);
  font-size: var(--t4);
  color: var(--fg);
}

.settings-row__control {
  display: flex;
  gap: var(--space-1);
  align-items: center;
  flex-shrink: 0;
}

.settings-row__control .btn {
  width: auto;
}

.settings-row--danger span {
  color: var(--fg-tertiary);
}

/* Block: vertical stack for complex sections */
.settings-block {
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
}

.settings-block:last-child {
  border-bottom: none;
}

.settings-block__label {
  font-size: var(--t4);
  font-weight: 500;
  color: var(--fg);
  margin-bottom: var(--space-1);
}

.settings-block__status {
  font-size: var(--t5);
  color: var(--fg-tertiary);
  margin-bottom: var(--space-2);
}

.settings-block__error {
  font-size: var(--t5);
  color: var(--danger);
  margin-top: var(--space-1);
}

.settings-block__mono {
  font-family: var(--font-mono);
  font-size: var(--t4);
  margin: var(--space-2) 0;
}

.settings-block__code {
  margin: var(--space-2) 0;
}

.settings-block__code span {
  font-size: 1.5em;
  letter-spacing: 0.2em;
  font-family: var(--font-mono);
}

.settings-block__row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  margin-top: var(--space-2);
}

.settings-block__row .input {
  flex: 1;
  max-width: 8.75rem;
}

.settings-block__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.settings-block__form .input {
  width: 100%;
}

.settings-block .btn {
  width: auto;
}

/* Mobile: full width drawer */
@media (max-width: 48em) {
  .settings-drawer {
    width: 100%;
    border-left: none;
  }
}

.modal__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--space-6);
}

.modal__header h2 {
  font-size: var(--t2);
  font-weight: 600;
  margin: 0;
}

.modal__header .btn--icon {
  width: 2rem;
  height: 2rem;
  background: var(--bg-tertiary);
  border-radius: 50%;
  flex-shrink: 0;
}

.modal__header .btn--icon:hover {
  background: var(--bg-hover);
}

.modal h2 {
  font-size: var(--t6);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-secondary);
  margin-bottom: var(--space-4);
}

.modal input {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  font-size: 1rem;
  font-family: var(--font);
  background: var(--bg-tertiary);
  border: none;
  border-radius: var(--radius-sm);
  color: var(--fg);
  outline: none;
  margin-bottom: var(--space-3);
}

.modal input:focus {
  background: var(--bg-hover);
}

.modal input::placeholder {
  color: var(--fg-tertiary);
}

/* Only full-width for submit buttons, not icon buttons */
.modal > .btn,
.settings-section .btn {
  width: 100%;
}

/* Settings sections */
.settings-section {
  margin-bottom: var(--space-6);
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--border);
}

.settings-section:last-child {
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: none;
}

.settings-section h3 {
  font-size: var(--t4);
  font-weight: 600;
  color: var(--fg);
  margin-bottom: var(--space-3);
}

.settings-hint {
  font-size: 0.6875rem;
  color: var(--text-3, #999);
  margin-top: 0.375rem;
}

.settings-status {
  font-size: var(--t5);
  color: var(--fg-secondary);
  margin-bottom: var(--space-3);
  line-height: 1.5;
}

.settings-status.connected {
  color: var(--success);
}

.settings-status.unlocked {
  color: var(--fg);
}

.settings-status.waiting {
  color: var(--warning, #d4d4d7);
  animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.6;
  }
}

.tg-login {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.tg-login .input--small {
  padding: var(--space-3) var(--space-4);
  font-size: 1rem;
  background: var(--bg-tertiary);
  border: none;
  border-radius: var(--radius-sm);
  color: var(--fg);
  outline: none;
  transition: background 0.15s ease;
}

.tg-login .input--small::placeholder {
  color: var(--fg-tertiary);
}

.tg-login .input--small:focus {
  background: var(--bg-hover);
}

.tg-login .btn {
  margin-top: var(--space-2);
}

.tg-error {
  font-size: var(--t6);
  color: var(--danger);
  letter-spacing: 0.03em;
}

/* Telegram share/link */
.tg-share,
.tg-link {
  margin-top: var(--space-4);
}

.tg-share-row,
.tg-link-row {
  display: flex;
  gap: var(--space-3);
  align-items: center;
}

.tg-share-code {
  font-family: var(--font-mono, monospace);
  font-size: 1.125rem;
  letter-spacing: 3px;
  color: var(--fg);
  font-weight: 600;
}

.tg-link-input {
  width: 6.875rem;
  flex-shrink: 0;
  font-family: var(--font-mono, monospace);
  letter-spacing: 2px;
  text-align: center;
}

.tg-link-status {
  font-size: var(--t6);
  color: var(--fg-secondary);
  margin-top: var(--space-2);
}

/* Inline button — doesn't stretch to full width */
.btn--inline {
  width: auto !important;
  flex-shrink: 0;
}

/* Settings danger button */
.settings-section .btn--danger {
  background: rgba(255, 59, 48, 0.1);
  color: var(--danger);
  border: none;
  border-radius: var(--radius-sm);
}

.settings-section .btn--danger:hover {
  background: rgba(255, 59, 48, 0.2);
}

/* ═══════════════════════════════════════════
   NOTIFICATION (legacy — hidden, replaced by toasts)
   ═══════════════════════════════════════════ */

.notification {
  display: none !important;
}

/* ═══════════════════════════════════════════
   TOASTS
   ═══════════════════════════════════════════ */

.toast-container {
  position: fixed;
  bottom: var(--space-6);
  left: 50%;
  transform: translateX(-50%);
  z-index: 600;
  display: flex;
  flex-direction: column-reverse;
  gap: var(--space-2);
  pointer-events: none;
  max-width: 90vw;
  width: 22.5rem;
}

.toast {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--fg);
  font-size: var(--t4);
  font-family: var(--font);
  pointer-events: auto;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s, transform 0.2s;
  backdrop-filter: blur(0.75rem);
}

.toast--visible {
  opacity: 1;
  transform: translateY(0);
}

.toast--exit {
  animation: toastExit 0.25s ease-in forwards;
}

@keyframes toastExit {
  to { opacity: 0; transform: translateY(-8px) scale(0.95); }
}

.toast__icon {
  flex-shrink: 0;
  display: flex;
  color: var(--fg-secondary);
}

.toast--success .toast__icon { color: var(--success); }
.toast--error .toast__icon { color: var(--danger); }

.toast__text {
  flex: 1;
  min-width: 0;
}

.toast__progress {
  position: absolute;
  bottom: 0;
  left: 0;
  height: 2px;
  background: var(--accent);
  animation: toastProgress 3.5s linear forwards;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
}

@keyframes toastProgress {
  from { width: 100%; }
  to { width: 0%; }
}

@keyframes notifyIn {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}

/* ═══════════════════════════════════════════
   UPDATE POPUP
   ═══════════════════════════════════════════ */

.update-popup {
  position: fixed;
  top: var(--space-8);
  right: var(--space-8);
  z-index: 1000;
  animation: slideInRight 0.3s ease;
}

@keyframes slideInRight {
  from {
    opacity: 0;
    transform: translateX(100%);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.update-popup__content {
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  padding: var(--space-6);
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
  max-width: 20rem;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}

.update-popup__icon {
  font-size: var(--t2);
  line-height: 1;
}

.update-popup__text {
  flex: 1;
}

.update-popup__title {
  font-weight: 600;
  font-size: var(--t4);
  margin-bottom: var(--space-1);
}

.update-popup__version {
  font-size: var(--t6);
  color: var(--accent);
  font-family: var(--font-mono);
}

.update-popup__message {
  font-size: var(--t5);
  color: var(--fg-muted);
  margin-top: var(--space-2);
}

.update-popup__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.update-popup__btn {
  white-space: nowrap;
}

.update-popup__dismiss {
  font-size: var(--t6);
  padding: var(--space-1) var(--space-2);
}

/* ═══════════════════════════════════════════
   SCROLLBAR
   ═══════════════════════════════════════════ */

::-webkit-scrollbar {
  width: 0.5rem;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: var(--radius-full);
  border: 2px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--fg-tertiary);
  background-clip: content-box;
}

/* Firefox */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}

/* ═══════════════════════════════════════════
   DESKTOP — grid layout is now the base (see mobile-first refactor
   at top of file). This block only handles the remaining desktop-only
   specifics: back-button hidden, header title layout, etc.
   ═══════════════════════════════════════════ */

/* The old `.sidebar.hidden { transform: none !important }` override
   is unnecessary: on desktop `.sidebar.hidden` never has `transform`
   defined in the base, so there's nothing to override. */

/* `.btn--back` is "home" navigation only meaningful on mobile where
   the sidebar overlays the chat. On desktop both panes are always
   visible; the button is redundant. */
.btn--back { display: none; }

@media (max-width: 48em) {
  .btn--back { display: flex; }
}

/* Breakpoint unified to 48em (was the 48.0625em trick which caused a
   1px specificity overlap). Mobile MQs use `max-width: 48em`; desktop
   uses `min-width: 48em`; they meet at exactly 48em where the later
   rule in source order wins — acceptable since 48em boundary is
   rarely hit exactly. */
@media (min-width: 48em) {
  .header   { padding: 0 var(--space-3); }
  .title    { font-size: var(--t4); }
  .dialog-item  { padding: var(--space-2) var(--space-3); }
  .chat-header  { padding: var(--space-2) var(--space-3); }
  .messages { padding: var(--space-3) var(--space-3) var(--space-6); }
  .input    { padding: var(--space-1) var(--space-2); }

  /* Bubble clamped to ~70-character reading measure on wide displays.
     Previously `max-width: 65%` meant on a 1920px viewport bubbles grew
     to ~830px — past the optimum line length. Ch.4 + Ch.11 both argue
     for ~66ch / 42rem ceiling. */
  .message { max-width: min(65%, 42rem); }

  #remote-video { width: 40rem; height: 30rem; max-width: none; }
  #local-video  { width: 13rem; height: 10rem; }
}

/* ═══════════════════════════════════════════
   AGENT PANEL — Brockmann Style
   ═══════════════════════════════════════════ */

.agent-toggle {
  position: fixed;
  bottom: var(--space-6);
  right: var(--space-6);
  width: 3rem;
  height: 3rem;
  background: var(--fg);
  color: var(--bg);
  border: none;
  border-radius: 0;
  cursor: pointer;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.1s;
}

.agent-toggle:hover {
  transform: scale(1.05);
}

.agent-toggle:active {
  transform: scale(0.95);
}

.agent-panel {
  position: fixed;
  bottom: var(--space-6);
  right: var(--space-6);
  width: 25rem;
  max-width: calc(100vw - var(--space-2) * 6);
  height: 30rem;
  max-height: calc(100vh - var(--space-2) * 6);
  background: var(--bg);
  border: 1px solid var(--fg);
  display: flex;
  flex-direction: column;
  z-index: 1001;
}

.agent-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--fg);
}

.agent-panel__header h2 {
  font-size: var(--t5);
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin: 0;
}

.agent-panel__output {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--t7);
  line-height: 1.5;
}

.agent-panel__output .cmd {
  color: var(--fg-muted);
  margin-bottom: var(--space-2);
}

.agent-panel__output .cmd::before {
  content: "";
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  margin-right: 4px;
  background: var(--fg);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z'/%3E%3C/svg%3E")
    center/contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z'/%3E%3C/svg%3E")
    center/contain no-repeat;
  vertical-align: middle;
}

.agent-panel__output .result {
  color: var(--fg);
  margin-bottom: var(--space-4);
  white-space: pre-wrap;
  word-break: break-word;
}

.agent-panel__output .tool {
  color: var(--fg-muted);
  font-style: italic;
  margin-bottom: var(--space-2);
}

.agent-panel__output .tool::before {
  content: "";
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  margin-right: 4px;
  background: var(--fg-muted);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z'/%3E%3C/svg%3E")
    center/contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z'/%3E%3C/svg%3E")
    center/contain no-repeat;
  vertical-align: middle;
}

.agent-panel__output .error {
  color: #ff4444;
}

.agent-panel__input {
  display: flex;
  border-top: 1px solid var(--fg);
}

.agent-panel__input .input {
  flex: 1;
  border: none;
  background: transparent;
  padding: var(--space-4) var(--space-6);
}

.agent-panel__input .btn--send {
  width: 3rem;
  background: var(--fg);
  color: var(--bg);
  border: none;
  font-size: var(--t5);
}

/* Agent auth in settings */
.agent-auth {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.agent-error {
  color: #ff4444;
  font-size: var(--t7);
  min-height: var(--space-6);
}

/* Mobile adjustments */
@media (max-width: 30em) {
  .agent-panel {
    width: calc(100vw - var(--space-2) * 4);
    height: calc(100vh - var(--space-2) * 20);
    bottom: var(--space-4);
    right: var(--space-4);
  }

  .agent-toggle {
    bottom: var(--space-4);
    right: var(--space-4);
  }
}

/* ═══════════════════════════════════════════
   UPDATE BANNER
   ═══════════════════════════════════════════ */

.update-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background: var(--fg);
  color: var(--bg);
  padding: var(--space-4);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  z-index: 9999;
  font-size: var(--t6);
}

.update-banner button {
  background: var(--bg);
  color: var(--fg);
  border: none;
  padding: var(--space-2) var(--space-4);
  cursor: pointer;
  font-size: var(--t7);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* ═══════════════════════════════════════════
   AI PIPELINE (Brockmann style)
   ═══════════════════════════════════════════ */

.ai-pipeline {
  font-family: var(--font);
  font-size: var(--t6);
  line-height: 1.6;
}

.pipe-step {
  padding: var(--space-2) 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  cursor: pointer;
  transition: background 0.1s;
}

.pipe-step:hover {
  background: rgba(255, 255, 255, 0.02);
}

.pipe-step:last-of-type {
  border-bottom: none;
}

.pipe-step__header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.step-status {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--space-5);
  height: var(--space-5);
  font-size: var(--t7);
  font-family: var(--font-mono);
  flex-shrink: 0;
}

.step--done .step-status {
  color: var(--fg);
}

.step--pending {
  opacity: 0.4;
}

.step--pending .step-status {
  color: var(--fg-muted);
}

.step--error .step-status {
  color: var(--danger);
}

.step-name {
  flex: 1;
  font-weight: 500;
}

.step-toggle {
  font-size: 0.625rem;
  color: var(--fg-muted);
  transition: transform 0.2s;
}

.pipe-step.expanded .step-toggle {
  transform: rotate(90deg);
}

.step-result {
  display: none;
  margin-top: var(--space-2);
  margin-left: var(--space-6);
  padding: var(--space-2);
  background: rgba(255, 255, 255, 0.02);
  border-left: 2px solid var(--fg-muted);
  font-family: var(--font-mono);
  font-size: var(--t7);
  color: var(--fg-muted);
  max-height: 12.5rem;
  overflow-y: auto;
}

.pipe-step.expanded .step-result {
  display: block;
}

.step-result code {
  display: block;
  white-space: pre-wrap;
  word-break: break-all;
  line-height: 1.4;
}

/* Syntax highlighting for code results */
.step-result .hl-keyword {
  color: #ff6b6b;
}
.step-result .hl-string {
  color: #a5d6a7;
}
.step-result .hl-number {
  color: #90caf9;
}
.step-result .hl-comment {
  color: #888;
  font-style: italic;
}

.result-files {
  color: var(--fg);
  margin-bottom: var(--space-2);
}

.result-content {
  white-space: pre-wrap;
  word-break: break-all;
}

.result-edit {
  color: var(--danger);
}

/* AI Thinking animation */
.ai-thinking {
  display: flex;
  align-items: center;
  padding: var(--space-2) 0;
}

.thinking-dots {
  display: flex;
  gap: 4px;
}

.thinking-dots span {
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 50%;
  background: var(--fg-muted);
  animation: thinkPulse 1.4s ease-in-out infinite;
  will-change: transform, opacity;
}

.thinking-dots span:nth-child(2) {
  animation-delay: 0.2s;
}

.thinking-dots span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes thinkPulse {
  0%,
  80%,
  100% {
    transform: scale(0.6);
    opacity: 0.3;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
}

/* Phase indicator for pipeline */
.ai-phase {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: var(--space-3) var(--space-4);
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-2);
}

.phase-spinner {
  width: 1rem;
  height: 1rem;
  border: 2px solid var(--fg-muted);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: phaseSpin 0.8s linear infinite;
}

.phase-text {
  color: var(--fg-secondary);
  font-size: var(--t5);
  font-weight: 500;
}

@keyframes phaseSpin {
  to {
    transform: rotate(360deg);
  }
}

/* Collapsible steps */
.ai-steps-details {
  margin-top: var(--space-2);
}

.ai-steps-summary {
  font-size: var(--t7);
  color: var(--fg-muted);
  cursor: pointer;
  user-select: none;
  list-style: none;
}

.ai-steps-summary::-webkit-details-marker {
  display: none;
}

.ai-steps-summary::before {
  content: "▸ ";
}

.ai-steps-details[open] .ai-steps-summary::before {
  content: "▾ ";
}

.ai-steps-container {
  margin-top: var(--space-2);
  padding-left: var(--space-2);
  border-left: 1px solid var(--border);
}

.step--run .step-status {
  color: var(--fg-muted);
  animation: blink 1s infinite;
}

@keyframes blink {
  50% {
    opacity: 0.3;
  }
}

.step-name {
  color: var(--fg);
}

.step-params {
  margin-left: 2rem;
  color: var(--fg-muted);
  font-family: monospace;
  font-size: var(--t7);
  word-break: break-all;
}

.step-result {
  margin-left: 2rem;
  color: var(--fg-muted);
  font-family: monospace;
  font-size: var(--t7);
  opacity: 0.7;
  word-break: break-all;
}

.pipe-answer {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  color: var(--fg);
  font-size: var(--t5);
  line-height: 1.5;
}

/* AI Controls */
.ai-controls {
  display: flex;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
}

.ai-mode-btn {
  width: 2rem;
  height: 2rem;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: var(--radius-xs);
  color: var(--fg-secondary);
  cursor: pointer;
  transition: all 0.15s ease;
}

.ai-mode-btn:hover {
  color: var(--fg);
}

.ai-mode-btn.active {
  background: var(--accent);
  color: #fff;
}

/* Pipeline mode wrapper for hints dropdown */
.ai-mode-wrapper {
  position: relative;
}

.pipeline-hints {
  display: none;
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 0.5rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0;
  min-width: 12.5rem;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  z-index: 1000;
}

.pipeline-hints::before {
  content: "";
  position: absolute;
  top: -0.375rem;
  left: 50%;
  transform: translateX(-50%);
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-bottom: 6px solid var(--border-color);
}

.pipeline-hints::after {
  content: "";
  position: absolute;
  top: -0.3125rem;
  left: 50%;
  transform: translateX(-50%);
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 5px solid var(--bg-secondary);
}

.ai-mode-wrapper:hover .pipeline-hints,
.pipeline-hints:hover {
  display: block;
}

.pipeline-hints__header {
  padding: 4px 0.75rem 0.5rem;
  font-size: var(--t7);
  color: var(--fg-muted);
  border-bottom: 1px solid var(--border-color);
  margin-bottom: 4px;
}

.pipeline-hints__item {
  padding: 0.5rem 0.75rem;
  font-size: var(--t6);
  color: var(--fg);
  cursor: pointer;
  transition: background 0.15s ease;
}

.pipeline-hints__item:hover {
  background: var(--bg-tertiary);
}

/* Input autocomplete dropdown */
.input-autocomplete {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: 4px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  z-index: 1000;
  max-height: 12.5rem;
  overflow-y: auto;
}

.input-autocomplete.visible {
  display: block;
}

.autocomplete-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 0.75rem;
  cursor: pointer;
  transition: background 0.15s ease;
}

.autocomplete-item:hover,
.autocomplete-item.active {
  background: var(--bg-tertiary);
}

.ac-cmd {
  font-family: monospace;
  color: var(--accent);
  font-weight: 600;
}

.ac-label {
  flex: 1;
  color: var(--fg);
  font-size: var(--t6);
}

.ac-mode {
  font-size: var(--t7);
  padding: 2px 0.375rem;
  border-radius: var(--radius-xs);
  text-transform: uppercase;
}

.ac-mode--pipeline {
  background: var(--accent);
  color: #fff;
}

.ac-mode--chat {
  background: var(--bg-tertiary);
  color: var(--fg-muted);
}

/* AI avatar color */
.dialog-avatar--ai {
  background: linear-gradient(135deg, #666 0%, #333 100%);
  color: var(--fg);
}

/* ═══════════════════════════════════════════
   PIPELINE
   ═══════════════════════════════════════════ */

.overlay--pipeline {
  align-items: flex-start;
  padding: var(--space-4);
}

.pipeline-container {
  width: 100%;
  max-width: 37.5rem;
  max-height: 90vh;
  background: var(--bg);
  border: 1px solid var(--fg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.pipeline-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--space-4);
  border-bottom: 1px solid var(--fg);
}

.pipeline-header h2 {
  font-size: var(--t4);
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.pipeline-input {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-4);
  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}

.pipeline-input .input {
  flex: 1;
  margin: 0;
  border: 1px solid var(--fg-muted);
  padding: var(--space-3);
}

.pipeline-status {
  padding: var(--space-4);
  font-size: var(--t6);
  color: var(--fg-muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  display: none;
}

.pipeline-status.active {
  display: block;
  color: var(--danger);
  animation: pulse 1s infinite;
}

/* pulse defined above */

.pipeline-plan {
  padding: 0 var(--space-4);
  max-height: 9.5rem;
  overflow-y: auto;
}

.pipeline-plan-step {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  font-size: var(--t6);
  color: var(--fg-muted);
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

.pipeline-plan-step.done {
  color: var(--fg);
}

.pipeline-plan-step.running {
  color: var(--danger);
}

.pipeline-plan-step__num {
  width: var(--space-5);
  height: var(--space-5);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid currentColor;
  font-weight: 600;
}

.pipeline-plan-step.done .pipeline-plan-step__num {
  background: var(--fg);
  color: var(--bg);
  border-color: var(--fg);
}

.pipeline-plan-step.running .pipeline-plan-step__num {
  border-color: var(--danger);
  animation: pulse 1s infinite;
}

.pipeline-steps {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.pipeline-step {
  padding: var(--space-3);
  background: rgba(255, 255, 255, 0.03);
  border-left: 2px solid var(--fg-muted);
  font-size: var(--t6);
}

.pipeline-step.success {
  border-left-color: var(--fg);
}

.pipeline-step.error {
  border-left-color: var(--danger);
}

.pipeline-step__action {
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  margin-bottom: var(--space-2);
}

.pipeline-step__data {
  font-family: var(--font-mono);
  font-size: var(--t7);
  color: var(--fg-muted);
  max-height: 6rem;
  overflow-y: auto;
  white-space: pre-wrap;
  word-break: break-all;
}

.pipeline-result {
  padding: var(--space-4);
  border-top: 1px solid var(--fg);
  display: none;
}

.pipeline-result.visible {
  display: block;
}

.pipeline-result__title {
  font-size: var(--t6);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg);
  margin-bottom: var(--space-2);
}

.pipeline-result__summary {
  font-size: var(--t5);
  color: var(--fg);
}

.pipeline-result__stats {
  font-size: var(--t6);
  color: var(--fg-muted);
  margin-top: var(--space-2);
}

/* ═══════════════════════════════════════════
   SMART UI — Predictive Interface
   Desktop only: auto-hide panels when reading history
   ═══════════════════════════════════════════ */

@media (min-width: 48em) {
  /* Transition on the layout's grid tracks, not on the children's
     `width`. Grid track sizes animate cleanly in modern browsers when
     both states use the same unit. `width` transitions on grid-area
     children were no-ops (the grid is what controls their size), so
     the old setup animated `transform`+`opacity` only — the sidebar
     snapping to 0 column width was the jank. Now: 20rem ↔ 0rem on the
     grid itself, children just fade/slide into their own space. */
  .layout {
    transition: grid-template-columns var(--duration-normal) var(--ease-out),
                grid-template-rows var(--duration-normal) var(--ease-out);
  }
  .layout .sidebar,
  .layout .header {
    transition:
      transform var(--duration-normal) var(--ease-out),
      opacity var(--duration-normal) var(--ease-out);
  }

  /* Collapsed state — sidebar slides + fades (width is driven by the
     grid track collapse below). */
  .layout.smart-ui--collapsed .sidebar {
    opacity: 0;
    transform: translateX(-100%);
    pointer-events: none;
  }

  /* Collapsed state — header slides up */
  .layout.smart-ui--collapsed .header {
    transform: translateY(-100%);
    opacity: 0;
    pointer-events: none;
  }

  /* Collapse grid tracks to 0. Matching unit type (rem ↔ rem) is
     required for smooth interpolation of `grid-template-columns`. */
  .layout.smart-ui--collapsed {
    grid-template-columns: 0rem 1fr;
    grid-template-rows: 0rem 1fr;
  }

  /* Main area takes full space */
  .layout.smart-ui--collapsed .main {
    border-radius: 0;
  }

  /* Chat header stays visible but minimal */
  .layout.smart-ui--collapsed .chat-header {
    background: transparent;
    border-bottom-color: transparent;
  }

  /* Subtle indicator that panels are hidden */
  .layout.smart-ui--collapsed::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    width: 3px;
    height: 100%;
    background: var(--accent);
    opacity: 0.3;
    z-index: 100;
    pointer-events: none;
  }
}

/* Settings Tabs */
.settings-tabs {
  display: flex;
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-6);
}

.tab-btn {
  flex: 1;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  padding: var(--space-3);
  font-size: var(--t5);
  font-weight: 500;
  color: var(--fg-secondary);
  cursor: pointer;
  transition: all 0.2s ease;
}

.tab-btn:hover {
  color: var(--fg);
}

.tab-btn.active {
  color: var(--fg);
  border-bottom-color: var(--accent);
}

.tab-content {
  display: none;
  animation: fadeIn 0.2s ease-out;
}

.tab-content.active {
  display: block;
}

/* ═══════════════════════════════════════════
   BEAUTIFY CARDS - Minimal SVG Style
   ═══════════════════════════════════════════ */

.beautify-card {
  margin: var(--space-2) 0;
  padding: var(--space-2) var(--space-3);
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

/* ─── Weather Card ─── */
.weather-card {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.weather-card__icon {
  width: 1.25rem;
  height: 1.25rem;
  color: var(--fg);
  flex-shrink: 0;
}

.weather-card__icon svg {
  width: 100%;
  height: 100%;
}

/* Icon Animations */
.weather--sunny .weather-card__icon svg {
  animation: iconSpin 20s linear infinite;
}

.weather--partly .weather-card__icon svg,
.weather--cloudy .weather-card__icon svg {
  animation: iconDrift 4s ease-in-out infinite;
}

.weather--rainy .weather-card__icon svg {
  animation: iconBounce 1.5s ease-in-out infinite;
}

.weather--snowy .weather-card__icon svg {
  animation: iconFloat 3s ease-in-out infinite;
}

.weather--storm .weather-card__icon svg {
  animation: iconFlash 2s ease-in-out infinite;
}

.weather--foggy .weather-card__icon svg {
  animation: iconFade 3s ease-in-out infinite;
}

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

@keyframes iconDrift {
  0%,
  100% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(4px);
  }
}

@keyframes iconBounce {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(3px);
  }
}

@keyframes iconFloat {
  0%,
  100% {
    transform: translateY(0) scale(1);
  }
  50% {
    transform: translateY(-2px) scale(1.02);
  }
}

@keyframes iconFlash {
  0%,
  85%,
  100% {
    opacity: 1;
  }
  90%,
  95% {
    opacity: 0.4;
  }
}

@keyframes iconFade {
  0%,
  100% {
    opacity: 0.7;
  }
  50% {
    opacity: 1;
  }
}

.weather-card__content {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  flex: 1;
  min-width: 0;
}

.weather-card__location {
  font-size: var(--t7);
  color: var(--fg-muted);
}

.weather-card__temp {
  display: flex;
  align-items: baseline;
}

.temp-value {
  font-size: var(--t5);
  font-weight: 600;
  font-family: var(--font-mono);
  color: var(--fg);
}

.temp-unit {
  font-size: var(--t6);
  color: var(--fg-muted);
}

.weather-card__condition {
  font-size: var(--t7);
  color: var(--fg-secondary);
}

.weather-card__wind {
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--fg-muted);
  font-size: var(--t7);
  margin-left: auto;
}

.wind-icon {
  width: 0.875rem;
  height: 0.875rem;
  animation: windBlow 2s ease-in-out infinite;
}

.wind-icon svg {
  width: 100%;
  height: 100%;
}

@keyframes windBlow {
  0%,
  100% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(2px);
  }
}

.wind-value {
  font-family: var(--font-mono);
}

/* ─── Exchange Card ─── */
.exchange-card {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.exchange-card__icon {
  width: 1rem;
  height: 1rem;
  color: var(--fg-muted);
  flex-shrink: 0;
  animation: exchangePulse 3s ease-in-out infinite;
}

.exchange-card__icon svg {
  width: 100%;
  height: 100%;
}

@keyframes exchangePulse {
  0%,
  100% {
    transform: scaleX(1);
  }
  50% {
    transform: scaleX(1.1);
  }
}

.exchange-card__rate {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.exchange-card__from,
.exchange-card__to {
  display: flex;
  align-items: baseline;
  gap: 4px;
}

.currency-code {
  font-size: var(--t7);
  color: var(--fg-muted);
}

.currency-amount {
  font-size: var(--t5);
  font-weight: 600;
  font-family: var(--font-mono);
  color: var(--fg);
}

.exchange-card__to .currency-amount {
  color: var(--accent);
}

.exchange-card__arrow {
  width: 0.875rem;
  height: 0.875rem;
  color: var(--fg-muted);
  animation: arrowSlide 2s ease-in-out infinite;
}

.exchange-card__arrow svg {
  width: 100%;
  height: 100%;
}

@keyframes arrowSlide {
  0%,
  100% {
    transform: translateX(0);
    opacity: 0.5;
  }
  50% {
    transform: translateX(2px);
    opacity: 1;
  }
}

.exchange-card__date {
  font-size: 0.7rem;
  color: var(--fg-muted);
  margin-left: auto;
}

/* ─── Error Card ─── */
.error-card {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--danger);
  background: rgba(255, 80, 80, 0.08);
  border-color: rgba(255, 80, 80, 0.2);
}

.error-card__icon {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
}

.error-card__icon svg {
  width: 100%;
  height: 100%;
}

.error-card__text {
  font-size: var(--t6);
}

/* ─── News Card ─── */
.news-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: 100%;
}

.news-card--empty {
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
}

.news-card__header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--border);
}

.news-card__icon {
  width: 1.125rem;
  height: 1.125rem;
  flex-shrink: 0;
  color: var(--accent);
}

.news-card__icon svg {
  width: 100%;
  height: 100%;
}

.news-card__title {
  font-weight: 500;
  font-size: var(--t5);
  text-transform: capitalize;
}

.news-card__count {
  margin-left: auto;
  font-size: var(--t7);
  color: var(--muted);
}

.news-card__empty {
  color: var(--muted);
  font-size: var(--t6);
}

.news-card__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.news-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  animation: newsSlideIn 0.3s ease-out backwards;
}

@keyframes newsSlideIn {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.news-item__title {
  font-size: var(--t6);
  line-height: 1.4;
  color: var(--fg);
}

.news-item__meta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--t7);
  color: var(--muted);
}

.news-item__source,
.news-item__time {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.news-item__source svg,
.news-item__time svg {
  width: 0.75rem;
  height: 0.75rem;
  opacity: 0.6;
}

/* ─── JSON Cards ─── */
.json-card {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  font-family: var(--font-mono, monospace);
  font-size: var(--t7);
}

.json-card--array {
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.json-card--list {
  gap: 0.625rem;
}

.json-row {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
}

.json-key {
  color: var(--accent);
  font-weight: 500;
  flex-shrink: 0;
}

.json-key::after {
  content: ":";
  color: var(--muted);
}

.json-value {
  color: var(--fg);
  word-break: break-word;
}

.json-array-item {
  padding: var(--space-1) 0.375rem;
  background: var(--surface);
  border-radius: calc(var(--radius) * 0.5);
  color: var(--fg);
}

.json-list-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.json-list-title {
  color: var(--fg);
  font-family: var(--font, system-ui);
  font-size: var(--t6);
}

.json-list-sub {
  color: var(--muted);
  font-size: var(--t7);
}

.json-more {
  color: var(--muted);
  font-size: var(--t7);
  font-style: italic;
}

/* ─── LLM Generated Widgets ─── */
.beautify-llm {
  font-size: var(--t6);
  line-height: 1.5;
}

.beautify-llm ul,
.beautify-llm ol {
  margin: 0;
  padding-left: var(--space-4);
}

.beautify-llm li {
  margin-bottom: var(--space-1);
}

.beautify-llm table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t7);
}

.beautify-llm td,
.beautify-llm th {
  padding: var(--space-1);
  text-align: left;
  border-bottom: 1px solid var(--border);
}

/* ═══════════════════════════════════════════
   WIDGET SYSTEM - AI-Rendered Components
   ═══════════════════════════════════════════ */

.widget {
  margin: var(--space-2) 0;
  padding: var(--space-3);
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--t6);
}

.widget.w-error {
  background: rgba(255, 80, 80, 0.08);
  border-color: rgba(255, 80, 80, 0.2);
  color: var(--danger);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* Widget Layout */
.w-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-bottom: 0.375rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.375rem;
}

.w-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.w-footer {
  margin-top: 0.375rem;
  padding-top: var(--space-1);
  border-top: 1px solid var(--border);
  font-size: var(--t7);
}

/* Widget Flex */
.w-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.w-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* Widget Typography */
.w-title {
  font-weight: 500;
  font-size: var(--t5);
}

.w-meta {
  margin-left: auto;
  font-size: var(--t7);
  color: var(--fg-muted);
}

.w-label {
  font-size: var(--t7);
  color: var(--fg-muted);
}

.w-value {
  font-family: var(--font-mono);
  color: var(--fg);
}

.w-big {
  font-size: var(--t4);
  font-weight: 600;
  font-family: var(--font-mono);
  color: var(--fg);
}

.w-highlight {
  color: var(--accent);
}

.w-muted {
  color: var(--fg-muted);
  font-size: var(--t7);
}

/* Widget List */
.w-list {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.w-list-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-1) 0;
  border-bottom: 1px solid var(--border-light, rgba(128, 128, 128, 0.1));
  animation: w-anim-slide 0.3s ease-out backwards;
}

.w-list-item:last-child {
  border-bottom: none;
}

.w-list-item .w-muted {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* Widget Icons */
.w-icon {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  color: currentColor;
}

.w-icon--sm {
  width: 0.875rem;
  height: 0.875rem;
}

.w-icon svg {
  width: 100%;
  height: 100%;
}

/* Widget Animations */
@keyframes w-anim-fade-kf {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes w-anim-slide-kf {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes w-anim-pulse-kf {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.6;
  }
}

@keyframes w-anim-bounce-kf {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-4px);
  }
}

.w-anim-fade {
  animation: w-anim-fade-kf 0.3s ease-out;
}

.w-anim-slide {
  animation: w-anim-slide-kf 0.3s ease-out;
}

.w-anim-pulse {
  animation: w-anim-pulse-kf 2s ease-in-out infinite;
}

.w-anim-bounce {
  animation: w-anim-bounce-kf 1s ease-in-out infinite;
}

/* Staggered list animations */
.w-list-item:nth-child(1) {
  animation-delay: 0ms;
}
.w-list-item:nth-child(2) {
  animation-delay: 50ms;
}
.w-list-item:nth-child(3) {
  animation-delay: 100ms;
}
.w-list-item:nth-child(4) {
  animation-delay: 150ms;
}
.w-list-item:nth-child(5) {
  animation-delay: 200ms;
}
.w-list-item:nth-child(6) {
  animation-delay: 250ms;
}

/* File Transfer Styles */
.file-transfer-container {
  position: fixed;
  bottom: 4.375rem;
  right: 1.25rem;
  width: 18.75rem;
  max-height: 25rem;
  overflow-y: auto;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.625rem;
  z-index: 1000;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

.file-transfer-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.625rem;
  padding-bottom: 0.3125rem;
  border-bottom: 1px solid var(--border);
}

.file-transfer-header h4 {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 600;
}

.file-transfer-item {
  margin-bottom: 0.5rem;
  padding: 0.5rem;
  background: var(--bg-primary);
  border-radius: 4px;
  border: 1px solid var(--border);
  transition: all 0.2s ease;
}

.file-transfer-item:hover {
  background: var(--bg-hover);
}

.file-transfer-item-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 4px;
}

.file-transfer-item-name {
  font-weight: bold;
  font-size: 0.75rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 11.25rem;
}

.file-transfer-item-size {
  font-size: 0.6875rem;
  color: var(--fg-secondary);
}

.file-transfer-item-type {
  font-size: 0.6875rem;
  color: var(--fg-secondary);
  margin-left: 0.3125rem;
}

.file-transfer-progress {
  height: 4px;
  background: var(--bg-secondary);
  border-radius: 2px;
  overflow: hidden;
  margin: 4px 0;
}

.file-transfer-progress-bar {
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 0.3s ease;
}

.file-transfer-item-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.625rem;
  color: var(--fg-secondary);
}

.file-transfer-status {
  transition: color 0.3s ease;
}

.file-transfer-status.error {
  color: var(--error-color);
}

.file-transfer-status.success {
  color: var(--success-color);
}

.file-transfer-peer {
  font-size: 0.625rem;
  opacity: 0.8;
}

/* File message in chat */
.message.file-message {
  padding: 0.5rem 0.75rem;
  border-radius: 12px;
  max-width: 70%;
  margin: 4px 0;
  position: relative;
}

.message.file-message.outgoing {
  background: var(--accent-light);
  border: 1px solid var(--accent);
  align-self: flex-end;
  margin-left: auto;
}

.message.file-message.incoming {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  align-self: flex-start;
}

.file-message-content {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.file-message-icon {
  font-size: 1rem;
}

.file-message-info {
  display: flex;
  flex-direction: column;
}

.file-message-name {
  font-weight: 500;
  font-size: 0.875rem;
}

.file-message-size {
  font-size: 0.6875rem;
  color: var(--fg-secondary);
  margin-top: 2px;
}

.file-message-download {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--accent);
  text-decoration: none;
}

.file-message-download:hover {
  text-decoration: underline;
}

/* ─── File Cards (Beautify) ─── */
.file-card {
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  max-width: 20rem;
  min-width: 12.5rem;
}

.file-card__preview {
  display: block;
  max-height: 15rem;
  overflow: hidden;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}

.file-card__preview img {
  width: 100%;
  display: block;
  object-fit: cover;
  max-height: 15rem;
  transition: transform 0.2s ease;
}

.file-card__preview:hover img {
  transform: scale(1.03);
}

.file-card__info {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.625rem;
}

.file-card__icon-wrap {
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-secondary);
  border-radius: 6px;
}

.file-card__icon {
  width: 1.125rem;
  height: 1.125rem;
  color: var(--fg-secondary);
}

.file-card--image .file-card__icon { color: #34c759; }
.file-card--video .file-card__icon { color: #af52de; }
.file-card--audio .file-card__icon { color: #ff9500; }
.file-card--pdf .file-card__icon { color: #ff3b30; }
.file-card--archive .file-card__icon { color: #ffcc00; }
.file-card--doc .file-card__icon { color: var(--fg); }

.file-card__details {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.file-card__name {
  font-size: 0.8125rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.file-card__size {
  font-size: 0.6875rem;
  color: var(--fg-secondary);
}

.file-card__download {
  flex-shrink: 0;
  color: var(--accent);
  opacity: 0.7;
  transition: opacity 0.15s;
  display: flex;
  align-items: center;
  padding: 4px;
  border-radius: 4px;
}

.file-card__download:hover {
  opacity: 1;
  background: var(--bg-hover);
}

/* File button in input area */
.btn--file {
  background: transparent;
  border: none;
  color: var(--fg-secondary);
  padding: 0.5rem;
  cursor: pointer;
  border-radius: 4px;
  transition: all 0.2s ease;
}

.btn--file:hover {
  color: var(--fg);
  background: var(--bg-hover);
}

.btn--file svg {
  width: 1.25rem;
  height: 1.25rem;
}

/* ── Share Dialog ── */
.overlay--share {
  background: rgba(0, 0, 0, 0.85);
  backdrop-filter: blur(0.75rem);
  -webkit-backdrop-filter: blur(0.75rem);
}

.modal--share {
  max-width: 21.25rem;
  width: 90%;
  background: var(--bg-secondary);
  border: none;
  border-radius: var(--radius);
  padding: var(--space-6);
}

.share-contacts {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-height: 50vh;
  overflow-y: auto;
}

.share-contact-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  transition: background var(--duration-fast) var(--ease-out);
}

.share-contact-item:hover {
  background: var(--bg-tertiary);
}

.share-contact-avatar {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--fg);
  color: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
  font-weight: 700;
  flex-shrink: 0;
}

.share-contact-name {
  flex: 1;
  font-size: var(--t4);
  font-weight: 500;
}

.share-contact-btn {
  padding: 4px 0.75rem;
  font-size: 0.75rem;
  font-weight: 600;
  background: var(--fg);
  color: var(--bg);
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: opacity var(--duration-fast);
}

.share-contact-btn:hover {
  opacity: 0.85;
}

.share-contact-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.share-contact-btn--done {
  background: #34c759;
  color: #fff;
}

.share-empty,
.share-loading {
  text-align: center;
  padding: var(--space-3);
  color: var(--fg-secondary);
  font-size: var(--t4);
}

.chat-header__from {
  display: block;
  font-size: 0.625rem;
  color: var(--fg-secondary);
  font-weight: 400;
  opacity: 0.7;
}

.chat-header__status--shared {
  color: var(--fg-secondary);
  font-size: 0.6875rem;
  font-weight: 400;
}

.dialog-source--shared {
  background: var(--bg-tertiary);
  color: var(--fg-secondary);
}

.dialog-avatar--shared {
  background: var(--bg-tertiary);
  color: var(--fg-secondary);
}

/* AI Email Assistant button */
#ai-email-btn {
  display: none;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  border: none;
  border-radius: 6px;
  color: #fff;
  cursor: pointer;
  padding: 4px 0.5rem;
  margin-left: 0.375rem;
  transition: opacity 0.2s;
}
#ai-email-btn:hover { opacity: 0.85; }

/* ── AI Inline Draft Mode ── */
.ai-model-select {
  background: var(--bg-tertiary, #1e1e1e);
  color: var(--fg-secondary, #888);
  border: 1px solid var(--border, rgba(255,255,255,0.06));
  border-radius: 6px;
  padding: 2px 0.375rem;
  font-size: 0.6875rem;
  cursor: pointer;
  outline: none;
  margin-left: 4px;
}
.ai-model-select:focus {
  border-color: var(--accent, #f5f5f5);
}
.btn--send--ai {
  background: var(--accent, #f5f5f5) !important;
  color: #fff !important;
  border-radius: 50%;
  transition: all 0.2s var(--ease-out);
}

.btn--send--ai svg {
  stroke: #fff;
}
.btn--send--ai-dialog {
  background: #a855f7 !important;
  color: #fff !important;
  border-radius: 50%;
  transition: all 0.2s var(--ease-out);
}
.btn--send--ai-dialog svg {
  stroke: #fff;
}

.message--ai-draft .message__bubble {
  border: 1px solid var(--border-strong);
  background: var(--bg-secondary);
}

.ai-draft-header {
  font-size: 0.625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03125rem;
  color: var(--accent, #f5f5f5);
  margin-bottom: 4px;
}

.ai-draft-text {
  font-size: var(--t4);
  line-height: 1.5;
}
.ai-draft-text--editing {
  outline: 2px solid var(--accent, #f5f5f5);
  border-radius: 4px;
  padding: 0.5rem;
  background: var(--bg, #0c0c0c);
  min-height: 3.75rem;
  cursor: text;
}

.ai-draft-error {
  color: #ff3b30;
  font-size: var(--t5);
}

.ai-draft-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.625rem;
  flex-wrap: wrap;
}

.btn--draft-send,
.btn--draft-edit,
.btn--draft-retry,
.btn--draft-continue {
  padding: 0.375rem 0.875rem;
  font-size: 0.75rem;
  font-weight: 600;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: opacity 0.15s;
}

.btn--draft-send {
  background: #34c759;
  color: #fff;
}

.btn--draft-edit {
  background: var(--bg-tertiary);
  color: var(--fg);
}

.btn--draft-retry {
  background: var(--bg-tertiary);
  color: var(--fg-secondary);
}

.btn--draft-continue {
  background: var(--accent);
  color: #fff;
}

.btn--draft-send:hover,
.btn--draft-edit:hover,
.btn--draft-retry:hover,
.btn--draft-continue:hover {
  opacity: 0.85;
}

.message--ai-instruction .message__bubble {
  opacity: 0.7;
  font-style: italic;
}

/* ============ Cases ============ */
.case-view {
  padding: 1rem 1.25rem;
  overflow-y: auto;
  height: 100%;
}
.case-header {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.case-title {
  font-size: 1.125rem;
  font-weight: 600;
  margin: 0;
  color: var(--fg-primary);
}
.case-status {
  font-size: 0.6875rem;
  padding: 2px 0.5rem;
  border-radius: 10px;
  font-weight: 500;
}
.case-status--open {
  background: rgba(76, 175, 80, 0.15);
  color: #4caf50;
}
.case-status--closed {
  background: rgba(158, 158, 158, 0.15);
  color: #9e9e9e;
}
.case-header__actions {
  margin-left: auto;
  display: flex;
  gap: 0.375rem;
}
.case-btn-generate {
  background: rgba(33, 150, 243, 0.15);
  color: #64b5f6;
}
.case-btn-generate:hover {
  background: rgba(33, 150, 243, 0.25);
}

/* Case Members */
.case-members {
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: 0.75rem 0;
  margin-bottom: 1rem;
}
.case-members h3 {
  font-size: 0.75rem;
  text-transform: uppercase;
  color: var(--fg-tertiary);
  margin: 0 0 0.5rem 0;
  letter-spacing: 0.03125rem;
}
.case-member {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 4px 0;
  font-size: 0.8125rem;
}
.case-member--unlinked {
  opacity: 0.4;
}
.case-member__name {
  color: var(--fg-primary);
  font-weight: 500;
}
.case-member__role {
  color: var(--fg-tertiary);
  font-size: 0.6875rem;
}
.case-member__unlinked {
  color: #f44336;
  font-size: 0.625rem;
  font-style: italic;
}
.case-member__goto {
  margin-left: auto;
  font-size: 1rem;
  opacity: 0.5;
  cursor: pointer;
  background: none;
  border: none;
  color: var(--fg-secondary);
  padding: 2px 0.375rem;
}
.case-member__goto:hover {
  opacity: 1;
}
.case-btn-add-member {
  margin-top: 0.375rem;
  font-size: 0.6875rem;
  opacity: 0.6;
}

/* Channel Badge */
.channel-badge {
  font-size: 0.5625rem;
  padding: 1px 0.3125rem;
  border-radius: 3px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.channel-badge--tg {
  background: rgba(33, 150, 243, 0.2);
  color: #64b5f6;
}
.channel-badge--email {
  background: rgba(255, 152, 0, 0.2);
  color: #ffb74d;
}
.channel-badge--p2p {
  background: rgba(76, 175, 80, 0.2);
  color: #81c784;
}

/* Case Body (rendered markdown) */
.case-body {
  line-height: 1.6;
  color: var(--fg-secondary);
  font-size: 0.8125rem;
}
.case-body h1 {
  font-size: 1.125rem;
  color: var(--fg-primary);
  margin: 1.25rem 0 0.5rem;
  border-bottom: 1px solid var(--border);
  padding-bottom: 4px;
}
.case-body h2 {
  font-size: var(--t2);
  color: var(--fg-primary);
  margin: 1.125rem 0 0.375rem;
}
.case-body h3 {
  font-size: 0.8125rem;
  color: var(--fg-secondary);
  margin: 0.875rem 0 4px;
}
.case-body p {
  margin: 4px 0;
}
.case-body ul {
  margin: 4px 0;
  padding-left: 1.25rem;
}
.case-body li {
  margin: 2px 0;
}
.case-body blockquote {
  border-left: 3px solid var(--accent);
  margin: 0.375rem 0;
  padding: 4px 0.75rem;
  color: var(--fg-tertiary);
  font-style: italic;
}
.case-body table {
  border-collapse: collapse;
  width: 100%;
  margin: 0.5rem 0;
  font-size: 0.75rem;
}
.case-body th,
.case-body td {
  border: 1px solid var(--border);
  padding: 4px 0.5rem;
  text-align: left;
}
.case-body th {
  background: var(--bg-elevated);
  font-weight: 600;
  color: var(--fg-primary);
}
.case-body code {
  background: var(--bg-elevated);
  padding: 1px 4px;
  border-radius: 3px;
  font-size: 0.75rem;
}
.case-body pre {
  background: var(--bg-elevated);
  padding: 0.625rem;
  border-radius: 6px;
  overflow-x: auto;
  margin: 0.5rem 0;
}
.case-body pre code {
  background: none;
  padding: 0;
}
.case-body strong {
  color: var(--fg-primary);
}
.case-body__empty {
  color: var(--fg-tertiary);
  font-style: italic;
  text-align: center;
  padding: 2.5rem 0;
}
.case-body__generating {
  color: var(--fg-tertiary);
  font-style: italic;
  animation: pulse 1.5s ease-in-out infinite;
}
.case-body__error {
  color: #f44336;
}
.case-body__editor {
  width: 100%;
  min-height: 18.75rem;
  background: var(--bg-elevated);
  color: var(--fg-primary);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.625rem;
  font-family: monospace;
  font-size: 0.75rem;
  resize: vertical;
}
.case-body__editor-actions {
  display: flex;
  gap: 0.375rem;
  margin-top: 0.5rem;
}

/* Case Checklist */
.case-checklist {
  list-style: none;
  padding-left: 0;
}
.case-checklist li::before {
  content: "\2610 ";
}
.case-checklist li.case-todo-done::before {
  content: "\2611 ";
}
.case-checklist li.case-todo-done {
  text-decoration: line-through;
  opacity: 0.6;
}

/* Case Todos */
.case-todos {
  border-top: 1px solid var(--border);
  padding: 0.75rem 0;
  margin-top: 1rem;
}
.case-todos h3 {
  font-size: 0.75rem;
  text-transform: uppercase;
  color: var(--fg-tertiary);
  margin: 0 0 0.5rem 0;
  letter-spacing: 0.03125rem;
}
.case-todo {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 3px 0;
  font-size: 0.8125rem;
  color: var(--fg-secondary);
}
.case-todo input[type="checkbox"] {
  cursor: pointer;
  accent-color: var(--accent);
}
.case-todo__done {
  text-decoration: line-through;
  opacity: 0.5;
}
.case-todo__input {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--fg-primary);
  font-size: 0.8125rem;
  padding: 4px 0;
  width: 100%;
  outline: none;
}
.case-todo__input:focus {
  border-color: var(--accent);
}

/* Chat header status for cases */
.chat-header__status--case {
  color: var(--fg-tertiary);
  font-size: 0.6875rem;
  margin-left: 0.5rem;
}

/* Case context menu */
.case-ctx-menu {
  position: fixed;
  z-index: 999;
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  padding: 4px 0;
  min-width: 11.25rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
}
.case-ctx-item {
  padding: 0.5rem 1rem;
  cursor: pointer;
  font-size: 0.8125rem;
  color: var(--fg-secondary);
}
.case-ctx-item:hover {
  background: var(--bg-hover);
}
.case-ctx-item--danger {
  color: #f44336;
}

/* ═══════════════════════════════════════════
   DATE SEPARATORS
   ═══════════════════════════════════════════ */

.date-separator {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: var(--space-3) 0 var(--space-1);
  align-self: center;
}

.date-separator::before,
.date-separator::after {
  display: none;
}

.date-separator__text {
  font-size: var(--t7);
  color: var(--fg-tertiary);
  white-space: nowrap;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 400;
  opacity: 0.5;
}

/* ═══════════════════════════════════════════
   SCROLL-TO-BOTTOM FAB
   ═══════════════════════════════════════════ */

.scroll-bottom-btn {
  position: absolute;
  bottom: var(--space-4);
  right: var(--space-4);
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-full);
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  color: var(--fg-secondary);
  cursor: pointer;
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 10;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
  transition: opacity var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out),
              background var(--duration-fast);
}

.scroll-bottom-btn:hover {
  background: var(--bg-hover);
  color: var(--fg);
  transform: scale(1.08);
}

.scroll-bottom-btn.visible {
  display: flex;
}

.scroll-bottom-btn__badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 1.125rem;
  height: 1.125rem;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 600;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
  line-height: 1;
}

.scroll-bottom-btn__badge.has-count {
  display: flex;
}

/* Link preview card */
.message__link-preview {
  display: flex;
  gap: var(--space-2);
  background: var(--bg-hover);
  margin-top: var(--space-1);
  overflow: hidden;
  max-width: 20rem;
}
.message__link-preview img {
  width: 4rem;
  height: 4rem;
  object-fit: cover;
  flex-shrink: 0;
}
.link-preview__text {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  padding: var(--space-1) var(--space-2);
  font-size: var(--t6);
  min-width: 0;
}
.link-preview__text strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg);
}
.link-preview__text span {
  color: var(--fg-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.link-preview__domain {
  color: var(--fg-tertiary) !important;
  font-size: var(--t7);
}

/* Voice input button recording state */
#voice-input-btn.recording {
  color: var(--accent);
  animation: pulse 1s ease-in-out infinite;
}

/* Reactions */
.message__reactions {
  display: flex;
  gap: 0.25rem;
  margin-top: var(--space-1);
  flex-wrap: wrap;
}
.reaction {
  font-size: var(--t5);
  padding: 0.125rem 0.25rem;
  background: var(--bg-hover);
  cursor: pointer;
}
.react-picker {
  display: flex;
  gap: 0.125rem;
  padding: 0.25rem;
  background: var(--bg-elevated);
  box-shadow: var(--shadow-md);
  position: absolute;
  bottom: 100%;
  z-index: 10;
}
.react-picker button {
  background: none;
  border: none;
  font-size: 1.25rem;
  cursor: pointer;
  padding: 0.25rem;
  transition: transform var(--duration-fast) var(--ease-spring);
}
.react-picker button:hover {
  transform: scale(1.3);
}

/* Reply quote — 2-line clamped snippet of the message being answered.
   Was single-line nowrap which truncated aggressively; the 2-line clamp
   shows enough context without ballooning the bubble. Amber-tint +
   accent border read as "this is a quote", matching Telegram/Signal. */
.message__quote {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  text-overflow: ellipsis;

  padding: 4px 8px;
  margin-bottom: var(--space-1);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius-xs);
  background: var(--accent-light);
  font-size: var(--t6);
  line-height: 1.35;
  color: var(--fg);
  max-width: 100%;

  cursor: pointer;
  transition: background 0.15s ease;
}
.message__quote:hover {
  background: var(--accent-glow);
}
/* Outgoing bubble already tinted accent-light; contrast the quote a bit
   more so it doesn't blend with its own background. */
.message--outgoing .message__quote {
  background: rgba(255, 255, 255, 0.06);
  border-left-color: var(--accent);
}
.message--outgoing .message__quote:hover {
  background: rgba(255, 255, 255, 0.1);
}

/* ═══════════════════════════════════════════
   MESSAGE HOVER ACTIONS
   ═══════════════════════════════════════════ */

.message__attachments {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--border);
}
.message__attachment {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  background: var(--bg-hover);
  color: var(--fg-secondary);
  text-decoration: none;
  font-size: var(--t5);
  font-family: var(--font-mono, monospace);
  overflow: hidden;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}
.message__attachment:hover {
  color: var(--fg);
  background: var(--bg-elevated);
}
.message__attachment svg {
  flex-shrink: 0;
  opacity: 0.6;
}
.attachment__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.attachment__size {
  opacity: 0.5;
  flex-shrink: 0;
}

.message__actions {
  position: absolute;
  bottom: 100%;
  right: 0;
  margin-bottom: 0.25rem;
  display: none;
  gap: 0.125rem;
  background: var(--bg-elevated);
  padding: 0.125rem;
  box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.3);
  white-space: nowrap;
  z-index: 5;
}

.message--incoming .message__actions {
  right: auto;
  left: 0;
}
.message--outgoing .message__actions {
  right: 0;
  left: auto;
}

.message:hover .message__actions {
  display: flex;
}

.message__actions button {
  width: 1.75rem;
  height: 1.75rem;
  border: none;
  background: transparent;
  color: var(--fg-secondary);
  cursor: pointer;
  border-radius: var(--radius-xs);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background var(--duration-fast), color var(--duration-fast);
}

.message__actions button:hover {
  background: var(--bg-hover);
  color: var(--fg);
}

/* Photo in messages */
.message__photo {
  display: block;
  max-width: 100%;
  max-height: 18.75rem;
  object-fit: contain;
  margin: 4px 0;
  cursor: pointer;
}
.message__photo:hover { opacity: 0.9; }

/* Video in messages */
.message__video {
  display: block;
  max-width: 100%;
  max-height: 18.75rem;
  margin: 4px 0;
}

/* Voice message */
.message__voice {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 4px 0;
}
.message__voice audio {
  width: 12.5rem;
  height: 2rem;
  filter: grayscale(1) brightness(1.5) contrast(0.8);
  opacity: 0.8;
}
.message__voice audio::-webkit-media-controls-panel {
  background: var(--bg-tertiary);
}
.message__voice audio::-webkit-media-controls-current-time-display,
.message__voice audio::-webkit-media-controls-time-remaining-display {
  color: var(--fg-secondary);
  font-family: var(--font-mono, monospace);
  font-size: 0.625rem;
}

/* Sticker */
.message__sticker {
  display: block;
  max-width: 10rem;
  max-height: 10rem;
  margin: 4px 0;
}

/* File link */
.message__file {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0.375rem 0.625rem;
  background: rgba(255, 255, 255, 0.04);
  font-size: var(--t6);
  font-family: var(--font-mono, monospace);
  color: var(--fg-secondary);
  text-decoration: none;
  margin: 4px 0;
}
.message__file:hover { color: var(--accent); }
.message__file svg { width: 0.875rem; height: 0.875rem; }

/* Inline audio (from safe_html voice upload) */
.message__text audio {
  display: block;
  max-width: 15rem;
  height: 2rem;
  margin: 4px 0;
  filter: grayscale(1) brightness(1.5) contrast(0.8);
  opacity: 0.8;
}

/* Inline file link (from safe_html) */
.message__text a[href*="/api/files/"] {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 0.5rem;
  background: rgba(255, 255, 255, 0.04);
  font-size: var(--t6);
  font-family: var(--font-mono, monospace);
}

/* Media badge fallback */
.message__media-badge {
  display: inline-block;
  font-size: var(--t7);
  color: var(--fg-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 2px 0;
}

/* Transcription (whisper) */
.message__transcription {
  font-size: var(--t5);
  color: var(--fg-secondary);
  font-style: italic;
  padding: 2px 0;
  border-left: 2px solid var(--accent);
  padding-left: var(--space-2);
  margin-bottom: 2px;
}

/* Voice waveform player */
.message__voice {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) 0;
}
.voice-play {
  /* HIG 44pt — outer hit area transparent, inner circle 2rem
     accent-tinted with outline instead of solid fill. Less shouty,
     reads as "button" without screaming. */
  width: 2.75rem;
  height: 2.75rem;
  padding: 0.375rem;
  border-radius: 50%;
  background: transparent !important;
  color: var(--accent) !important;
  position: relative;
  border: 1px solid var(--accent);
  background: var(--accent-light);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background 0.15s ease, transform 0.1s ease;
}
.voice-play:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.voice-play:active { transform: scale(0.94); }
.voice-play svg { width: 1rem; height: 1rem; }
.voice-play.playing svg { display: none; }
.voice-play.playing::after { content: "||"; font-size: 0.625rem; font-weight: 700; letter-spacing: 1px; }
.voice-waveform {
  height: 1.75rem;
  min-width: 7.5rem;
  flex: 1;
  display: block;
  cursor: pointer;
  touch-action: none;
  transition: filter 0.2s ease;
}
.voice-waveform:hover { filter: brightness(1.15); }
.voice-waveform:active { filter: brightness(0.9); }
/* Subtle "breathing" when audio is playing — mirrors Telegram's waveform
   pulse. Applied to the parent wrapper via .playing class set by toggleVoice. */
.message__voice .voice-play.playing ~ .voice-waveform {
  animation: voicePulse 1.6s ease-in-out infinite;
}
@keyframes voicePulse {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.12); }
}
.voice-dur {
  font-size: var(--t7);
  color: var(--fg-tertiary);
  font-family: var(--font-mono);
  min-width: 2rem;
  text-align: right;
}
.message__voice audio { display: none; }

/* Live voice waveform in call messages */
.message--voice-live .message__bubble {
  min-width: 8.75rem;
}
.message--voice-live .message__transcription {
  min-height: 1em;
}

/* Code blocks in messages */
.message__text pre {
  background: var(--bg);
  padding: var(--space-2);
  margin: var(--space-1) 0;
  overflow-x: auto;
  font-size: var(--t6);
}
.message__text code {
  font-family: var(--font-mono, monospace);
  font-size: 0.9em;
}
.message__text pre code {
  font-size: var(--t6);
}
.message__text code:not(pre code) {
  background: rgba(255, 255, 255, 0.06);
  padding: 1px 4px;
}

/* Links in messages */
.message__text a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s;
}
.message__text a:hover {
  border-bottom-color: var(--accent);
}

/* AI email draft — bottom sheet (mini-app style) */
#ai-reply-box {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 200;
  transform: translateY(100%);
  transition: transform 0.3s var(--ease-in-out);
  max-height: 70vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--bg-secondary);
  border-top: 1px solid var(--border-strong);
}
#ai-reply-box:not(:empty) {
  transform: translateY(0);
}

.ai-draft {
  padding: var(--space-3);
}
.ai-draft__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: var(--t7);
  color: var(--fg-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: var(--space-2);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border);
}
.ai-draft__handle {
  width: 2rem;
  height: 4px;
  background: var(--fg-tertiary);
  border-radius: 2px;
  margin: 0 auto var(--space-2);
}
.ai-draft__subject {
  font-size: var(--t5);
  font-family: var(--font-mono, monospace);
  color: var(--fg-secondary);
  margin-bottom: var(--space-2);
}
.ai-draft__text {
  font-size: var(--t3);
  line-height: 1.6;
  padding: var(--space-3);
  background: var(--bg);
  min-height: 5rem;
  max-height: 40vh;
  overflow-y: auto;
  outline: none;
}
.ai-draft__text:focus {
  box-shadow: inset 2px 0 0 var(--accent);
}
.ai-draft__actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-2);
  border-top: 1px solid var(--border);
}
.ai-draft__actions .btn--small {
  flex: 1;
  text-align: center;
  font-family: var(--font-mono, monospace);
  text-transform: lowercase;
  letter-spacing: 0.05em;
}

/* Reply bar */
.reply-bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  background: var(--bg-tertiary);
  border-left: none;
  font-size: var(--t6);
  color: var(--fg-secondary);
  animation: msgAppear 0.15s var(--ease-out);
}
.reply-bar__text {
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.reply-bar__text strong {
  color: var(--fg);
  margin-right: 4px;
}
.reply-bar__close {
  font-size: 0.875rem;
  color: var(--fg-tertiary);
  padding: 4px;
}

/* Message swipe hint */
.message {
  touch-action: pan-y;
  overflow: visible;
}

/* AI loading indicator */
.ai-loading {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3);
  color: var(--fg-tertiary);
  font-size: var(--t6);
  font-family: var(--font-mono, monospace);
  animation: aiFade 1.5s ease-in-out infinite;
}
@keyframes aiFade {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1; }
}

/* Accounts bottom sheet */
#accounts-box {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 200;
  transform: translateY(100%);
  transition: transform 0.3s var(--ease-in-out);
  max-height: 80vh;
  overflow-y: auto;
  background: var(--bg-secondary);
  border-top: 1px solid var(--border-strong);
}
#accounts-box:not(:empty) { transform: translateY(0); }
.accounts-panel { padding: var(--space-3); }
.accounts-panel__header {
  display: flex; justify-content: space-between; align-items: center;
  font-size: var(--t7); color: var(--fg-tertiary);
  text-transform: uppercase; letter-spacing: 0.08em;
  padding-bottom: var(--space-2); border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-3);
}
.accounts-panel__item {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) 0; border-bottom: 1px solid var(--border);
}
.accounts-panel__type {
  font-family: var(--font-mono, monospace); font-size: var(--t6);
  text-transform: uppercase; color: var(--fg-tertiary); width: 60px;
}
.accounts-panel__key { flex: 1; font-size: var(--t4); font-family: var(--font-mono, monospace); }
.accounts-panel__status { font-size: var(--t7); }
.accounts-panel__status--authorized { color: var(--success); }
.accounts-panel__status--connected { color: var(--warning); }
.accounts-panel__status--disconnected { color: var(--fg-tertiary); }
.accounts-panel__status--active { color: var(--success); }
.accounts-panel__empty { color: var(--fg-tertiary); font-size: var(--t5); padding: var(--space-4) 0; text-align: center; }
.accounts-panel__add { margin-top: var(--space-3); padding-top: var(--space-2); }
.accounts-panel__add-title { font-size: var(--t6); color: var(--fg-secondary); margin-bottom: var(--space-2); }
.accounts-panel__add form { display: flex; gap: var(--space-2); }
.accounts-panel__section {
  font-size: var(--t7); color: var(--fg-tertiary);
  text-transform: uppercase; letter-spacing: 0.08em;
  margin-top: var(--space-3); margin-bottom: var(--space-1);
}
.accounts-panel__hint {
  font-size: var(--t6); color: var(--fg-tertiary);
  font-family: var(--font-mono, monospace);
  padding: var(--space-2) 0;
}

/* Toast notifications */
.toast-container {
  position: fixed;
  top: var(--space-3);
  left: 50%;
  transform: translateX(-50%);
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  pointer-events: none;
}
.toast {
  background: var(--bg-elevated);
  color: var(--fg);
  padding: var(--space-2) var(--space-4);
  font-size: var(--t5);
  font-family: var(--font-mono, monospace);
  border-left: 2px solid var(--accent);
  transition: opacity 0.3s;
}

/* Translation under message */
.message__translation {
  font-size: var(--t6);
  color: var(--fg-secondary);
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px solid var(--border);
  font-style: italic;
}

/* Long press: show actions on mobile */
.message.show-actions .message__actions {
  display: flex;
}

@media (hover: none) {
  .message:hover .message__actions {
    display: none;
  }
  .message.show-actions .message__actions {
    display: flex;
  }
}

/* ═══════════════════════════════════════════
   REDUCED MOTION — Stepanov: "Don't pay for what you don't use."
   One rule disables all non-essential animation.
   ═══════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ═══════════════════════════════════════════
   MICRO-ANIMATIONS (Dribbble style)
   ═══════════════════════════════════════════ */

/* Message appear — spring slide up + fade in */
/* Skip animation during bulk load — only animate new messages */
.messages--no-anim .msg-appear,
.messages--no-anim .message--outgoing.msg-appear {
  animation: none !important;
}
/* Message appear — opacity + subtle Y-slide. Transform on :not(msgAppear)
   element itself doesn't shift siblings (it's just visual), so no scroll
   jitter; the spring/scale version that did caused layout reflow and was
   removed. 6px of travel is enough to feel "pop in" without drawing the
   eye too much. */
.msg-appear {
  animation: msgAppear 0.28s var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1));
}
@keyframes msgAppear {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.message--outgoing.msg-appear { animation-name: msgAppearOut; }
@keyframes msgAppearOut {
  from { opacity: 0; transform: translateY(6px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .msg-appear { animation: none; }
}

/* Typing indicator (P2P) */
.typing-indicator {
  padding: var(--space-2) var(--space-4);
  color: var(--fg-secondary);
  font-size: var(--t6);
}
.typing-dots { display: inline-flex; gap: 3px; }
.typing-dots span {
  width: 0.3125rem; height: 0.3125rem;
  background: var(--fg-secondary);
  border-radius: 50%;
  animation: typingBounce 1.2s ease-in-out infinite;
}
.typing-dots span:nth-child(2) { animation-delay: 0.2s; }
.typing-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes typingBounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.3; }
  30% { transform: translateY(-4px); opacity: 1; }
}

/* AI typing indicator */
.ai-typing::after {
  content: "";
  display: inline-block;
  width: 0.375rem;
  height: 0.375rem;
  background: var(--fg-secondary);
  border-radius: 50%;
  animation: aiDots 1s ease-in-out infinite;
  margin-left: 2px;
}
@keyframes aiDots {
  0%, 100% { opacity: 0.2; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1.2); }
}

/* Icon tap — scale + stroke draw on click */
.icon-tap { transition: transform 0.15s var(--ease-spring); }
.icon-tap:active { transform: scale(0.85); }
.icon-tap:hover { transform: scale(1.1); }
.icon-tap svg {
  transition: stroke-dashoffset 0.3s ease;
}
.icon-tap:active svg {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: iconDraw 0.4s ease forwards;
}
@keyframes iconDraw {
  to { stroke-dashoffset: 0; }
}

/* Icon pulse — breathing glow for online status */
.icon-pulse { animation: iconPulse 2s ease-in-out infinite; }
@keyframes iconPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

/* Icon bounce — pop for unread badge */
.icon-bounce { animation: badgePop 0.4s var(--ease-spring); }
@keyframes badgePop {
  0% { transform: scale(0); }
  60% { transform: scale(1.2); }
  100% { transform: scale(1); }
}

/* Icon float — gentle hover for empty states */
.icon-float { animation: iconFloat 3s ease-in-out infinite; }
/* iconFloat defined in icon-animations section */

/* Status dot */
.status-dot {
  display: inline-block;
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 50%;
  background: var(--success);
  margin-right: 4px;
  vertical-align: middle;
}

/* Icon in tabs — align with text */
.dialog-tab svg {
  vertical-align: -3px;
  margin-right: 2px;
}

/* Empty state icon */
.empty-state__icon {
  color: var(--fg-tertiary);
  margin-bottom: var(--space-3);
}
.empty-state__icon svg {
  width: 3rem;
  height: 3rem;
}

/* Message action buttons — smooth reveal */
.message__actions {
  transition: opacity 0.15s var(--ease-out), transform 0.15s var(--ease-out);
  transform: translateY(2px);
}
.message:hover .message__actions {
  transform: translateY(0);
}

/* Badge in chat header — subtle entrance */
.chat-header__badge svg {
  width: 0.75rem;
  height: 0.75rem;
  vertical-align: -1px;
  margin-right: 2px;
}

/* ═══════════════════════════════════════════
   LINKIFIED TEXT
   ═══════════════════════════════════════════ */

.message__text a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid var(--accent-glow);
  transition: border-color var(--duration-fast);
}

.message__text a:hover {
  border-bottom-color: var(--accent);
}

.message--incoming .message__text a {
  color: var(--tg);
  border-bottom-color: rgba(0, 136, 204, 0.2);
}

.message--incoming .message__text a:hover {
  border-bottom-color: var(--tg);
}

/* ═══════════════════════════════════════════
   MARKDOWN IN MESSAGES
   ═══════════════════════════════════════════ */

.msg-code-block {
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  margin: var(--space-2) 0;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--t5);
  line-height: 1.6;
  white-space: pre;
}

.msg-code-block code {
  background: none;
  padding: 0;
  border: none;
}

.msg-code-inline {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  padding: 1px 0.3125rem;
  font-family: var(--font-mono);
  font-size: 0.9em;
}

.msg-quote {
  border-left: 3px solid var(--fg-tertiary);
  padding-left: var(--space-3);
  margin: var(--space-1) 0;
  color: var(--fg-secondary);
  font-style: italic;
}

.message__text strong {
  font-weight: 600;
}

.message__text del {
  opacity: 0.6;
}

/* ═══════════════════════════════════════════
   IMAGE PREVIEW IN MESSAGES
   ═══════════════════════════════════════════ */

.msg-img-preview {
  display: block;
  max-width: 100%;
  max-height: 18.75rem;
  border-radius: var(--radius-sm);
  margin-top: var(--space-2);
  cursor: pointer;
  object-fit: contain;
  background: var(--bg);
}

.msg-img-preview:hover {
  opacity: 0.9;
}

/* ═══════════════════════════════════════════
   MESSAGE SEARCH
   ═══════════════════════════════════════════ */

.msg-search-bar {
  display: none;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
}

.msg-search-bar.active {
  display: flex;
}

.msg-search-bar input {
  flex: 1;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--fg);
  padding: var(--space-1) var(--space-2);
  font-size: var(--t4);
  font-family: var(--font);
  outline: none;
}

.msg-search-bar input:focus {
  border-color: var(--accent);
}

.msg-search-bar__count {
  font-size: var(--t5);
  color: var(--fg-tertiary);
  white-space: nowrap;
  min-width: 3.125rem;
  text-align: center;
}

.msg-search-bar button {
  background: transparent;
  border: none;
  color: var(--fg-secondary);
  cursor: pointer;
  padding: var(--space-1);
  border-radius: var(--radius-xs);
  display: flex;
  align-items: center;
}

.msg-search-bar button:hover {
  color: var(--fg);
  background: var(--bg-hover);
}

.message--search-highlight .message__bubble {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.message__text mark {
  background: rgba(255, 200, 0, 0.3);
  color: inherit;
  border-radius: 2px;
  padding: 0 1px;
}

/* ── File Preview Panel ── */
/* ═══════════════════════════════════════════
   PREVIEW PANEL — mobile-first
   ═══════════════════════════════════════════ */
#preview-panel {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 0;
  background: var(--bg);
  border-top: 1px solid var(--bg-tertiary);
  z-index: 100;
  transition: height 0.3s var(--ease-out);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* Mobile: full height */
#preview-panel.open {
  height: 100vh;
  height: 100dvh;
}
/* Desktop: half height */
@media (min-width: 48.0625em) {
  #preview-panel.open {
    height: 50vh;
  }
}

.preview-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--bg-tertiary);
  flex-shrink: 0;
}
.preview-title {
  font-family: var(--font-mono, monospace);
  font-size: var(--t5);
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1;
}
.preview-actions {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  flex-shrink: 0;
}
.preview-download {
  font-size: var(--t6);
  color: var(--fg-secondary);
  text-decoration: none;
}
.preview-download:hover { color: var(--fg); }
.preview-close {
  background: none;
  border: none;
  color: var(--fg-secondary);
  cursor: pointer;
  font-size: var(--t3);
  padding: var(--space-1);
}
.preview-close:hover { color: var(--fg); }
.preview-body {
  flex: 1;
  overflow: auto;
  padding: var(--space-3);
  -webkit-overflow-scrolling: touch;
}
@media (min-width: 48.0625em) {
  .preview-body { padding: var(--space-4); }
}
.preview-body table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono, monospace);
  font-size: var(--t6);
}
@media (min-width: 48.0625em) {
  .preview-body table { font-size: var(--t5); }
}
.preview-body table td {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--bg-tertiary);
  white-space: nowrap;
}
.preview-body pre {
  font-family: var(--font-mono, monospace);
  font-size: var(--t5);
  white-space: pre-wrap;
  word-break: break-word;
}
.preview-body img {
  max-width: 100%;
  max-height: 80vh;
}
@media (min-width: 48.0625em) {
  .preview-body img { max-height: 40vh; }
}
.preview-loading, .preview-error, .preview-unsupported {
  color: var(--fg-tertiary);
  font-family: var(--font-mono, monospace);
  font-size: var(--t5);
  padding: var(--space-4);
}

/* ═══════════════════════════════════════════
   UPLOAD PROGRESS BAR
   ═══════════════════════════════════════════ */
.upload-bar {
  position: relative;
  height: 1.5rem;
  background: var(--bg-tertiary);
  overflow: hidden;
  flex-shrink: 0;
}
.upload-bar__fill {
  position: absolute;
  inset: 0;
  width: 0;
  background: var(--accent);
  opacity: 0.15;
  transition: width 0.15s linear;
}
.upload-bar__text {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  font-family: var(--font-mono, monospace);
  font-size: var(--t6);
  color: var(--fg-secondary);
  letter-spacing: 0.05em;
}
.upload-bar--done .upload-bar__fill {
  width: 100% !important;
  background: var(--success);
  opacity: 0.2;
}
.upload-bar--done .upload-bar__text { color: var(--success); }
.upload-bar--done {
  animation: uploadDone 0.4s var(--ease-out) forwards;
}
@keyframes uploadDone {
  to { opacity: 0; height: 0; }
}
.upload-bar--error .upload-bar__fill {
  width: 100% !important;
  background: var(--danger);
  opacity: 0.15;
}
.upload-bar--error .upload-bar__text { color: var(--danger); }

/* Settings row + button icons — Feather SVGs inline with stroke=currentColor. */
.settings-row__icon {
  width: 1.125rem;
  height: 1.125rem;
  flex-shrink: 0;
  vertical-align: -0.15em;
  margin-right: var(--space-2);
  color: var(--fg-muted);
  stroke-width: 2;
}
.settings-row__label { display: inline-flex; align-items: center; gap: var(--space-2); }

.btn__icon {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  stroke-width: 2;
}
.btn--icon .btn__icon { width: 1.125rem; height: 1.125rem; }

/* [reconstructed: Edit target not present in HEAD base — inserted from new_string] */
:focus-visible {
  outline: 2px solid var(--accent, #f5f5f5);
  outline-offset: 2px;
}

/* ═══════════════════════════════════════════
   INLINE MEDIA BUBBLES (image/file attachments)
   Telegram/WhatsApp pattern — blurred thumb now,
   full bitmap once chunks arrive.
   ═══════════════════════════════════════════ */
.message--media .message__bubble--media {
  padding: 0;
  overflow: hidden;
  background: transparent;
}
.message__image {
  display: block;
  max-width: min(18rem, 70vw);
  max-height: 24rem;
  width: auto;
  height: auto;
  border-radius: var(--radius-md);
  object-fit: cover;
  transition: filter 0.3s ease, transform 0.3s ease;
  cursor: zoom-in;
}
.message__image:hover { filter: brightness(1.03); }

.message--file .message__bubble--file {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 10rem;
}
.message__file-icon {
  width: 1.5rem;
  height: 1.5rem;
  flex-shrink: 0;
  color: var(--fg-muted);
}
.message__file-info { flex: 1; min-width: 0; }
.message__file-name {
  font-size: var(--t5, 0.875rem);
  font-weight: 500;
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.message__file-size {
  font-size: var(--t7, 0.6875rem);
  color: var(--fg-tertiary);
  font-family: var(--font-mono, monospace);
}
.message__file-link {
  width: 1.75rem;
  height: 1.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  font-weight: 700;
  text-decoration: none;
  border-radius: 50%;
  border: 1px solid var(--border);
  transition: background 0.15s ease;
}
.message__file-link:hover { background: var(--bg-hover, var(--bg-tertiary)); }

/* ═══════════════════════════════════════════
   VOICE RECORDING OVERLAY (WhatsApp/Telegram)
   Lives inside .input-area, flex-covers over
   the textarea while user holds the mic button.
   ═══════════════════════════════════════════ */
.voice-rec {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  gap: var(--space-3);
  padding: 0 var(--space-2);
  padding-inline-end: 3rem;  /* leave room for send button */
  background: var(--bg);
  border-top: 1px solid var(--border);
  color: var(--fg);
  pointer-events: none;  /* overlay is passive during hold; buttons re-enable per-state */
  z-index: 2;
}
.input-area { position: relative; }  /* anchor voice-rec */
.voice-rec--visible { display: flex; animation: voiceRecIn 0.2s var(--ease-out); }
.input-area--recording .input,
.input-area--recording .btn--attach,
.input-area--recording #voice-input-btn { opacity: 0; pointer-events: none; }

@keyframes voiceRecIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

.voice-rec__mic {
  width: 1.75rem;
  height: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--danger);
  animation: recPulse 1s ease-in-out infinite;
  flex-shrink: 0;
}
.voice-rec__mic svg { width: 1.25rem; height: 1.25rem; }

.voice-rec__wf {
  flex: 1;
  height: 1.75rem;
  max-width: 18rem;
}

.voice-rec__timer {
  font-family: var(--font-mono, monospace);
  font-size: var(--t5, 0.875rem);
  color: var(--fg-muted);
  min-width: 3rem;
  font-variant-numeric: tabular-nums;
}

.voice-rec__hint {
  font-size: var(--t6, 0.75rem);
  color: var(--fg-tertiary);
  white-space: nowrap;
  animation: hintSlide 1.6s ease-in-out infinite;
}
@keyframes hintSlide {
  0%, 100% { opacity: 0.5; transform: translateX(0); }
  50%      { opacity: 1;   transform: translateX(-4px); }
}

/* Cancel intent — entire overlay warns red + hint becomes "Release to cancel" */
.voice-rec--cancel-intent {
  background: color-mix(in srgb, var(--danger) 12%, var(--bg));
}
.voice-rec--cancel-intent .voice-rec__mic { color: var(--danger); transform: scale(1.1); }
.voice-rec--cancel-intent .voice-rec__hint { color: var(--danger); animation: none; }
.voice-rec--cancel-intent .voice-rec__hint::after {
  content: " — release to cancel";
  font-weight: 600;
}

/* Lock indicator — shows above the mic button during hold; highlights when user slides up */
.voice-rec__lock {
  position: absolute;
  right: var(--space-2);
  bottom: calc(100% + 0.5rem);
  width: 2rem;
  padding: 0.375rem 0;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: 1rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  color: var(--fg-muted);
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity 0.15s ease, transform 0.15s ease, color 0.15s ease;
  pointer-events: none;
}
.voice-rec--visible .voice-rec__lock { opacity: 1; transform: translateY(0); }
.voice-rec__lock svg { width: 1rem; height: 1rem; }
.voice-rec__lock-chevron {
  font-size: 0.625rem;
  animation: lockBounce 1.4s ease-in-out infinite;
}
@keyframes lockBounce {
  0%, 100% { transform: translateY(0); opacity: 0.5; }
  50%      { transform: translateY(-3px); opacity: 1; }
}

.voice-rec--lock-intent .voice-rec__lock {
  color: var(--accent);
  border-color: var(--accent);
  transform: translateY(-2px) scale(1.1);
}

/* Locked state — overlay stays, hint swapped for permanent preview controls */
.voice-rec--locked .voice-rec__hint { display: none; }
.voice-rec--locked .voice-rec__lock svg path { d: path("M5 11h14v10H5z M8 11V9a4 4 0 0 1 8 0v2"); }

/* Live transcript shown under waveform during voice recording */
.voice-rec__live {
  flex-basis: 100%;
  font-size: var(--t6, 0.75rem);
  color: var(--fg-muted);
  max-height: 2.4em;
  overflow: hidden;
  opacity: 0.9;
}

/* Translated bubble — original text shown below in a dim line */
.message__text-orig {
  font-size: var(--t6, 0.75rem);
  color: var(--fg-tertiary);
  margin-top: 0.25rem;
  padding-top: 0.25rem;
  border-top: 1px dashed var(--border);
  opacity: 0.7;
  font-style: italic;
}

/* iOS-style toggle switch (used in settings rows) */
.switch {
  position: relative;
  display: inline-block;
  width: 2.75rem;
  height: 1.5rem;
}
.switch input { opacity: 0; width: 0; height: 0; }
.switch__slider {
  position: absolute;
  cursor: pointer;
  inset: 0;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.switch__slider::before {
  content: "";
  position: absolute;
  width: 1.125rem;
  height: 1.125rem;
  left: 0.125rem;
  top: 50%;
  transform: translateY(-50%);
  background: var(--fg);
  border-radius: 50%;
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.18s ease;
}
.switch input:checked + .switch__slider {
  background: var(--accent);
  border-color: var(--accent);
}
.switch input:checked + .switch__slider::before {
  transform: translate(1.125rem, -50%);
  background: #1a1a1a;
}
