:root {
  --bg: #f6f7fb;
  --panel: #ffffff;
  --ink: #1c2333;
  --muted: #7a8295;
  --accent: #5b6cff;
  --accent-ink: #ffffff;
  --bubble-me: #5b6cff;
  --bubble-them: #eef0f6;
  --radius: 18px;
  --border: #e7e9f0;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}
/* The app shell must fill the viewport so the flex height chain (.tt → .thread-view
   → .feed flex:1) resolves and the composer pins to the bottom. Without an explicit
   height here, .tt's height:100% resolves against an auto-height parent, the layout
   collapses to content height, and the composer floats with blank space below it. */
#app { height: 100%; }

button {
  font: inherit;
  cursor: pointer;
  border: none;
  border-radius: 999px;
  padding: 10px 18px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  white-space: nowrap;
  line-height: 1.2;
}
button.secondary {
  background: var(--bubble-them);
  color: var(--ink);
}
button:disabled { opacity: 0.5; cursor: default; }

input, textarea {
  font: inherit;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
  background: #fff;
  color: var(--ink);
  width: 100%;
  caret-color: var(--accent); /* the typing cursor picks up the accent (à la iMessage) */
}
input:focus, textarea:focus { outline: 2px solid var(--accent); border-color: transparent; }
/* the message box doesn't get the bright focus ring (chat-app convention) — the
   coloured caret is the cue. */
.composer textarea:focus { outline: none; border-color: var(--border); }

/* ---- centered card layout (join / fallback) ---- */
.center {
  min-height: 100%;
  display: grid;
  place-items: center;
  padding: 24px;
}
.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 24px;
  padding: 28px;
  width: 100%;
  max-width: 420px;
  box-shadow: 0 12px 40px rgba(20, 30, 80, 0.06);
}
.card h1 { margin: 0 0 6px; font-size: 24px; }
.card p { margin: 0 0 18px; color: var(--muted); }
.card .row { display: flex; gap: 10px; margin-top: 14px; }

/* ---- chat ---- */
.chat {
  display: flex;
  flex-direction: column;
  height: 100%;
  max-width: 720px;
  margin: 0 auto;
  background: var(--panel);
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  position: relative; /* anchors the drag-and-drop overlay */
}
/* Native shell (iOS/macOS) embeds only the message feed — the app draws its own
   title bar and composer. Drop the centered max-width column + side borders so the
   feed is full width, and hide the web header/composer. Gated on body.native-embed,
   which only chat.js sets when window.__lchatEmbed is injected; browsers are
   unaffected. */
.native-embed .chat {
  max-width: none;
  border-left: none;
  border-right: none;
}
.native-embed .chat header,
.native-embed .composer,
.native-embed .composer-reply,
.native-embed .composer-edit {
  display: none;
}
/* Keep the attachment preview visible: it's how a staged photo/file shows up just
   above the native composer (drag-drop or the native + button stage into it). The
   composer below is hidden, so add the bottom padding the composer would have
   provided. */
.native-embed .composer-preview { padding-bottom: 10px; }

.chat header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--panel);
}
.chat header .title {
  font-weight: 700;
  font-size: 17px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding-right: 10px;
}

/* kebab settings menu */
.icon-btn {
  background: transparent;
  color: var(--ink);
  font-size: 22px;
  line-height: 1;
  padding: 4px 10px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.icon-btn svg { display: block; }
.icon-btn:hover { background: var(--bubble-them); }
.menu-wrap { position: relative; flex: none; }
.menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 12px 40px rgba(20, 30, 80, 0.14);
  min-width: 230px;
  padding: 6px;
  z-index: 20;
}
.menu-who {
  font-size: 12px;
  color: var(--muted);
  padding: 8px 12px 6px;
}
.menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  color: var(--ink);
  border-radius: 10px;
  padding: 10px 12px;
  font-weight: 500;
  white-space: normal;
}
.menu-item:hover { background: var(--bubble-them); }
.menu-item.danger { color: #c2410c; }
.menu-item.disabled,
.menu-item.disabled:hover { color: var(--muted); cursor: default; background: transparent; }

.feed-wrap {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* shown only if the initial history load/decrypt is slow (>500ms) */
.chat-loading {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--panel);
}
.spinner {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
#feed {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden; /* clip messages mid swipe-to-reply; no horizontal scrollbar */
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* push a few messages to the bottom (near the composer); scrolls normally when full */
#feed::before {
  content: "";
  margin-top: auto;
}
.msg {
  display: flex;
  flex-direction: column;
  align-self: flex-start; /* shrink to the bubble width (me overrides to flex-end) */
  max-width: 78%;
  margin-top: 10px;
  position: relative; /* anchors hover affordances + the swipe-to-reply icon */
  touch-action: pan-y; /* vertical scroll stays native; we handle horizontal swipes */
}
/* continuation of a same-sender, same-minute run — tighter gap (see refreshGrouping) */
.msg.cont { margin-top: 2px; }
/* swipe-to-reply (touch): reply arrow that fades in just left of the bubble */
.swipe-reply-icon {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translate(-130%, -50%);
  color: var(--accent);
  opacity: 0;
  pointer-events: none;
  display: inline-flex;
}
.swipe-reply-icon svg { width: 20px; height: 20px; }
.msg .name { font-size: 12px; color: var(--muted); margin: 0 6px 3px; }
.msg .bubble {
  padding: 9px 13px;
  border-radius: var(--radius);
  background: var(--bubble-them);
  line-height: 1.35;
  white-space: pre-wrap;
  /* break long unbroken strings (e.g. a giant URL) instead of overflowing */
  overflow-wrap: anywhere;
  min-width: 0;
}
.msg .bubble code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.92em;
  background: rgba(0, 0, 0, 0.06);
  padding: 1px 5px;
  border-radius: 5px;
}
.msg.me .bubble code { background: rgba(255, 255, 255, 0.22); }
.msg.me { align-self: flex-end; align-items: flex-end; }
.msg.me .bubble { background: var(--bubble-me); color: #fff; border-bottom-right-radius: 6px; }
.msg.them .bubble { border-bottom-left-radius: 6px; }
.msg .bubble a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
/* a message of just a few emoji: large and bubble-less, no background or padding (see fillContent) */
.msg .bubble.jumbo-emoji,
.msg.me .bubble.jumbo-emoji { background: none; color: inherit; padding: 2px 0; font-size: 44px; line-height: 1.15; }

/* centered time separator that opens a burst (replaces per-message timestamps) */
.time-sep {
  align-self: center;
  margin: 16px 0 6px;
  font-size: 11px;
  color: var(--muted);
  text-align: center;
}
.time-sep strong { color: var(--ink); font-weight: 600; }

/* persistent "Edited" label under an edited bubble */
.edited-tag { font-size: 11px; color: var(--muted); margin: 1px 6px 0; }

/* Hover affordances live in a full-height strip beside the bubble: the hover zone
   spans the whole message height, so you can move straight from anywhere in the
   bubble to an icon (no need to find the vertical centre), and the action icons +
   the exact time sit in a row so they never overlap. Revealed on hover (desktop). */
.msg-actions {
  position: absolute;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 2px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s;
}
.msg.them .msg-actions { left: 100%; padding-left: 4px; } /* just right of the bubble */
.msg.me .msg-actions { right: 100%; padding-right: 4px; flex-direction: row-reverse; } /* just left */
.msg-actions button {
  background: transparent;
  color: var(--muted);
  padding: 4px 6px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  line-height: 1;
}
.msg-actions button:hover { background: var(--bubble-them); color: var(--accent); }
.msg-actions button svg { width: 18px; height: 18px; }
.msg-actions .msg-time {
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
  margin: 0 4px;
}
@media (hover: hover) {
  .msg:hover .msg-actions { opacity: 1; pointer-events: auto; }
}

/* message content (text bubble + any attachments) */
.content {
  position: relative; /* anchors the absolute hover reply icon */
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-start;
  min-width: 0;
}
.msg.me .content { align-items: flex-end; }

/* inline attachments */
.msg-image-wrap { max-width: 240px; }
.msg-image {
  max-width: min(260px, 100%);
  max-height: 320px;
  border-radius: var(--radius);
  display: block;
  background: var(--bubble-them);
  cursor: zoom-in;
}

/* full-screen image viewer */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(0, 0, 0, 0.9);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.lightbox img { max-width: 100%; max-height: 100%; border-radius: 8px; }

/* open animation: the backdrop fades, the image rises into place */
.lightbox { animation: fade-in 0.18s ease; }
.lightbox img { animation: lightbox-img-in 0.26s cubic-bezier(0.2, 0.8, 0.2, 1); }
@keyframes fade-in { from { opacity: 0; } }
@keyframes lightbox-img-in {
  from { opacity: 0; transform: translateY(14px) scale(0.98); }
}

/* a newly-sent/arrived message eases up into the feed (initial history doesn't) */
.msg.appear { animation: msg-appear 0.22s cubic-bezier(0.2, 0.8, 0.2, 1); }
@keyframes msg-appear {
  from { opacity: 0; transform: translateY(10px); }
}

@media (prefers-reduced-motion: reduce) {
  .lightbox,
  .lightbox img,
  .msg.appear { animation: none; }
}
.lightbox-close {
  position: fixed;
  top: 14px;
  right: 16px;
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.lightbox-close svg { width: 20px; height: 20px; }

/* drag-and-drop overlay */
.drop-overlay {
  position: absolute;
  inset: 0;
  z-index: 40;
  background: rgba(91, 108, 255, 0.12);
  border: 3px dashed var(--accent);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 18px;
  color: var(--accent);
  pointer-events: none;
}
.file-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--bubble-them);
  color: var(--ink);
  padding: 10px 14px;
  border-radius: var(--radius);
  text-decoration: none;
  font-size: 14px;
  max-width: 260px;
  word-break: break-word;
}
.msg.me .file-chip { background: var(--bubble-me); color: #fff; }

/* link (OpenGraph) preview card */
.link-preview {
  display: flex;
  flex-direction: column;
  max-width: 280px;
  background: var(--bubble-them);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
}
.lp-image { width: 100%; max-height: 150px; object-fit: cover; display: block; }
.lp-body { padding: 8px 11px; }
.lp-title { font-weight: 600; font-size: 14px; line-height: 1.3; }
.lp-desc {
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.lp-host { font-size: 11px; color: var(--muted); margin-top: 5px; }

/* composer attachment preview */
.composer-preview { padding: 10px 16px 0; position: relative; display: inline-block; }
.composer-preview.hidden { display: none; }
.composer-preview img { max-height: 80px; border-radius: 10px; display: block; }
.preview-x {
  position: absolute; top: 4px; left: 22px; width: 22px; height: 22px; padding: 0;
  border-radius: 50%; background: rgba(0, 0, 0, 0.6); color: #fff; font-size: 16px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
}
.preview-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--bubble-them);
  border-radius: 12px;
  padding: 6px 34px 6px 8px;
  max-width: 100%;
}
.preview-chip img { width: 40px; height: 40px; object-fit: cover; border-radius: 8px; }
.preview-file { font-size: 24px; }
.preview-name {
  font-size: 13px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 220px;
}
.preview-remove {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  background: var(--ink);
  color: #fff;
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.preview-remove svg { width: 13px; height: 13px; }

/* reactions */
.bubble-row { display: flex; align-items: center; gap: 6px; max-width: 100%; min-width: 0; }
.msg.me .bubble-row { flex-direction: row-reverse; }
/* Text selection works everywhere now: desktop reacts with a stationary hold
   (drag-select cancels it) and touch reacts with a double-tap, so long-press is
   free for native selection/copy on mobile. */
.reactions { display: flex; flex-wrap: wrap; gap: 4px; margin: 3px 2px 0; }
.msg.me .reactions { justify-content: flex-end; }
.reactions:empty { display: none; }
.reaction-chip {
  background: var(--bubble-them);
  color: var(--ink);
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 2px 9px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.35;
}
.reaction-chip.mine { border-color: var(--accent); background: #e7eaff; }
.emoji-picker {
  position: fixed;
  display: flex;
  gap: 2px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 6px;
  box-shadow: 0 12px 40px rgba(20, 30, 80, 0.18);
  z-index: 60;
}
.emoji-opt {
  background: transparent;
  font-size: 22px;
  padding: 4px 6px;
  border-radius: 50%;
  line-height: 1;
}
.emoji-opt:hover { background: var(--bubble-them); }
/* the "Reply" action in the message menu, set off from the emoji row */
.picker-action {
  background: transparent;
  color: var(--accent);
  padding: 4px 8px;
  margin-left: 2px;
  border-radius: 50%;
  border-left: 1px solid var(--border);
  display: inline-flex;
  align-items: center;
  line-height: 1;
}
.picker-action svg { width: 22px; height: 22px; }
.picker-action:hover { background: var(--bubble-them); }

/* a reply: a tappable quote of the parent sits above the bubble (à la Messages),
   and the parent gets a "N Replies" tag below it. */
.reply-quote {
  align-self: stretch;
  text-align: left;
  max-width: 100%;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 6px 11px;
  margin-bottom: 1px;
  font-weight: 400;
  white-space: normal;
}
.msg.me .reply-quote { text-align: right; }
.reply-quote-name { font-size: 11px; color: var(--muted); margin-bottom: 1px; }
.reply-quote-text {
  font-size: 13px;
  color: var(--muted);
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.msg.me .reply-quote-text { margin-left: auto; }
.reply-count {
  font-size: 11px;
  font-weight: 600;
  color: var(--accent);
  margin: 3px 6px 0;
  cursor: pointer;
}
.reply-count[hidden] { display: none; }
/* flash a message when you jump to it from a quote */
.msg.flash { animation: flash-msg 1.2s ease; border-radius: var(--radius); }
@keyframes flash-msg {
  0%, 100% { background: transparent; }
  25% { background: rgba(91, 108, 255, 0.14); }
}

/* composer "Replying to …" / "Editing message" banners, above the composer
   (and any attachment preview). They share the .reply-bar inner markup. */
.composer-reply,
.composer-edit {
  padding: 8px 14px;
  border-top: 1px solid var(--border);
  background: var(--panel);
}
.composer-reply.hidden,
.composer-edit.hidden { display: none; }
.composer-edit { display: flex; align-items: center; justify-content: space-between; color: var(--muted); font-size: 14px; }
.banner-x { background: transparent; color: var(--muted); font-size: 20px; line-height: 1; padding: 0 6px; }
.edited { font-size: 11px; opacity: 0.6; margin-left: 6px; }
.reply-bar { display: flex; align-items: center; gap: 10px; }
.reply-bar-icon { flex: none; color: var(--accent); display: inline-flex; }
.reply-bar-icon svg { width: 18px; height: 18px; }
.reply-bar-body {
  flex: 1;
  min-width: 0;
  border-left: 2px solid var(--accent);
  padding-left: 10px;
}
.reply-bar-name { font-size: 12px; font-weight: 600; color: var(--ink); }
.reply-bar-text {
  font-size: 13px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.reply-bar-cancel {
  flex: none;
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.reply-bar-cancel svg { width: 15px; height: 15px; }
.reply-bar-cancel:hover { background: var(--bubble-them); }

/* Subtle "… is typing" line, just above the composer. Transient presence only. */
.typing {
  padding: 2px 16px 6px;
  font-size: 12px;
  font-style: italic;
  color: var(--muted);
  background: var(--panel);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.typing.hidden { display: none; }

.composer {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  /* Desktop (fine pointer): the input hugs the bottom — env() is 0, so no fixed
     bottom padding. Touch devices get breathing room + the safe-area inset below
     (see the pointer:coarse rule), which desktop never picks up. */
  padding: 12px 16px;
  padding-bottom: env(safe-area-inset-bottom, 0px);
  border-top: 1px solid var(--border);
  background: var(--panel);
}
/* Touch: 12px of breathing room ABOVE the Home indicator / swipe bar (the inset),
   so the input never sits flush against the bottom edge or a browser toolbar.
   Scoped to coarse pointers so desktop stays at the bare inset (≈0). */
@media (pointer: coarse) {
  .composer { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
}
.composer-field {
  position: relative;
  flex: 1;
  display: flex;
}
.composer textarea {
  flex: 1;
  resize: none;
  max-height: 140px;
  /* 8+8 padding + 22 line + 2 border = 40px at rest. Symmetric so the text is
     vertically centred in the box; right padding leaves room for the send button. */
  padding: 8px 46px 8px 14px;
  line-height: 22px;
  min-height: 40px;
  border-radius: 20px;
  font-family: inherit;
  overflow: hidden;
}
/* circular up-arrow send button, tucked into the bottom-right of the field */
.send-btn {
  position: absolute;
  right: 4px;
  bottom: 3px;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  color: #fff;
}
.send-btn[hidden] { display: none; }
/* left-side attach (＋) button */
.attach-btn {
  flex: none;
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bubble-them);
  color: var(--ink);
  font-size: 24px;
  line-height: 1;
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(20, 30, 80, 0.45);
  overflow: auto;
}

/* invite QR (admin) — full-screen opaque takeover so nothing else is on screen */
.qr-screen {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--bg);
  overflow: auto;
}
.qr-modal {
  margin: 8vh auto;
  max-width: 360px;
  text-align: center;
  border: none;
  box-shadow: none;
}
.qr-modal h2 { margin: 0 0 6px; font-size: 20px; }
.qr-wrap {
  display: flex;
  justify-content: center;
  margin: 18px 0;
}
.qr-wrap canvas {
  max-width: 100%;
  height: auto;
  image-rendering: pixelated; /* keep modules crisp when CSS scales the canvas down */
  border-radius: 8px;
}
.qr-modal .row { justify-content: center; }

/* input + button on one row (e.g. Create invite) */
.inline-form {
  display: flex;
  gap: 10px;
  align-items: stretch;
}
.inline-form input {
  flex: 1;
  min-width: 0;
}

.banner {
  text-align: center;
  font-size: 13px;
  color: var(--muted);
  padding: 6px;
}
.banner.warn { color: #b4530a; }

/* connection status as a floating pill so it never reflows the message list */
#banner {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
  padding: 5px 14px;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  box-shadow: 0 6px 20px rgba(20, 30, 80, 0.18);
  pointer-events: none;
  white-space: nowrap;
}
#banner.warn { background: #b4530a; color: #fff; }

/* ---- admin ---- */
.admin { max-width: 760px; margin: 0 auto; padding: 24px; }
.admin h1 { margin: 0 0 4px; }
.admin .sub { color: var(--muted); margin: 0 0 24px; }
.admin section {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 18px;
  margin-bottom: 18px;
}
.admin section h2 { margin: 0 0 12px; font-size: 16px; }
.invite {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 0;
  border-top: 1px solid var(--border);
}
.invite:first-of-type { border-top: none; }
.invite .meta { flex: 1; min-width: 0; }
.invite .meta .label { font-weight: 600; }
.invite .meta .status { font-size: 12px; color: var(--muted); }
.invite .status.revoked { color: #c2410c; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
.key-box {
  background: var(--bubble-them);
  border-radius: 12px;
  padding: 12px;
  word-break: break-all;
  margin: 10px 0;
}
.hidden { display: none !important; }
.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  background: var(--ink); color: #fff; padding: 10px 16px; border-radius: 999px;
  font-size: 14px; opacity: 0; transition: opacity .2s; pointer-events: none;
  z-index: 100; /* above full-screen overlays (qr-screen) so it's never hidden */
}
.toast.show { opacity: 1; }

.header-actions { display: flex; gap: 8px; align-items: center; }
.notif {
  background: var(--bubble-them);
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
  padding: 7px 12px;
  white-space: nowrap;
}

/* full-screen onboarding cards */
.card.onboard { text-align: center; }
.card.onboard .row { justify-content: center; }
.card.onboard p { margin-bottom: 14px; }
.onboard-icon { font-size: 46px; line-height: 1; margin-bottom: 10px; }
.steps {
  text-align: left;
  color: var(--muted);
  line-height: 1.6;
  padding-left: 20px;
  margin: 4px 0 18px;
}
.steps li { margin-bottom: 6px; }
.steps strong { color: var(--ink); }

/* ---- multi-thread layout (docs/threads-and-dms.md) ---- */
.tt { display: flex; height: 100%; width: 100%; background: var(--panel); }
/* floating connection-status pill (only shown during a sustained outage) */
.conn-status {
  position: fixed;
  top: calc(10px + env(safe-area-inset-top, 0px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 90;
  background: var(--ink);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  padding: 6px 14px;
  border-radius: 999px;
  box-shadow: 0 6px 20px rgba(20, 30, 80, 0.25);
}
.conn-status.hidden { display: none; }
.sidebar { width: 320px; flex: none; display: flex; flex-direction: column; border-right: 1px solid var(--border); min-height: 0; }
/* Both headers share a height so their bottom borders line up across the panes. */
.side-head, .thread-head { box-sizing: border-box; min-height: 62px; padding: 8px 16px; border-bottom: 1px solid var(--border); }
.side-head { display: flex; align-items: center; gap: 8px; }
.side-head .title { flex: 1; min-width: 0; font-weight: 700; font-size: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.head-actions { display: flex; align-items: center; gap: 2px; flex: none; }
.avatar {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 34px; height: 34px; border-radius: 50%; color: #fff; font-weight: 700; font-size: 15px; line-height: 1;
}
.avatar-btn { background: transparent; padding: 0; border-radius: 50%; flex: none; }
.avatar-lg { width: 64px; height: 64px; font-size: 28px; }
.avatar.zoomable { cursor: pointer; } /* header avatar with a real photo: tap to zoom */
.field-label { display: block; font-size: 13px; color: var(--muted); margin: 2px 0 4px; }
.thread-list { flex: 1; overflow-y: auto; min-height: 0; padding: 6px; display: flex; flex-direction: column; gap: 2px; }
.thread-empty-note { color: var(--muted); padding: 16px; font-size: 14px; }
.thread-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: transparent; color: var(--ink); border-radius: 12px; padding: 10px 12px;
}
.thread-row:hover, .thread-row.active { background: var(--bubble-them); }
.thread-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.thread-row-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thread-row-preview { font-size: 13px; font-weight: 400; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thread-row-meta { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex: none; }
.thread-row-time { font-size: 11px; font-weight: 400; color: var(--muted); white-space: nowrap; }
.unread-dot { width: 8px; height: 8px; border-radius: 50%; background: transparent; flex: none; }
.unread-dot.on { background: var(--accent); }
.thread-pane { flex: 1; display: flex; min-height: 0; min-width: 0; position: relative; }
.empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--muted); gap: 6px; text-align: center; padding: 24px; }
.empty-art { font-size: 42px; }
/* min-width:0 lets these panes shrink below their content so a long unbroken
   URL wraps inside a bubble instead of widening the whole column. */
.thread-view { flex: 1; display: flex; flex-direction: column; min-height: 0; min-width: 0; width: 100%; position: relative; }
.thread-head { display: flex; align-items: center; gap: 6px; }
.thread-head-title { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.thread-title { font-weight: 700; font-size: 16px; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thread-sub { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.back-btn { display: none; font-size: 24px; padding: 0 8px; }
.feed { flex: 1; overflow-y: auto; overflow-x: hidden; min-height: 0; min-width: 0; padding: 16px; display: flex; flex-direction: column; gap: 4px; }
.feed > .msg { max-width: 78%; }
.feed::before { content: ""; margin-top: auto; }

/* modal sheet (new chat / add device) — centered overlay */
.overlay {
  position: fixed; inset: 0; z-index: 60; background: rgba(20, 30, 80, 0.45);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.sheet { max-width: 460px; width: 100%; max-height: 82vh; overflow-y: auto; }
.sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.sheet-head h2 { margin: 0; }
.linkish { background: transparent; color: var(--accent); padding: 6px 8px; font-weight: 600; }
.sheet-input { margin-bottom: 10px; }
/* full-bleed list inside the sheet: rows span the card edges (which pads 28px) */
.pick-list { margin: 4px -28px 0; max-height: 56vh; overflow-y: auto; }
.list-row {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  background: transparent; color: var(--ink); border: none; border-bottom: 1px solid var(--border);
  padding: 14px 28px; border-radius: 0; font-weight: 500; font-size: 16px; cursor: pointer;
}
.list-row:hover:not(.static) { background: var(--bubble-them); }
.list-row.static { cursor: default; }
.list-row input { width: auto; }
.sheet-foot { display: flex; justify-content: flex-end; gap: 10px; margin-top: 16px; }

/* mobile: show one pane at a time, toggled by .show-thread */
@media (max-width: 720px) {
  .sidebar { width: 100%; border-right: none; }
  .thread-pane { display: none; }
  .tt.show-thread .sidebar { display: none; }
  .tt.show-thread .thread-pane { display: flex; }
  .back-btn { display: inline-flex; }
}
