:root {
  --bg: #f5f6f8;
  --surface: #ffffff;
  --surface-2: #fafbfc;
  --border: #e3e6ea;
  --border-strong: #c9cfd6;
  --text: #1c2128;
  --text-muted: #5b6571;
  --text-faint: #8a929c;
  --accent: #1f4ed8;
  --accent-hover: #1740b8;
  --danger: #b42318;
  --danger-soft: #fdecec;
  --ok: #137a3f;
  --shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 1px 3px rgba(16, 24, 40, 0.06);
  --radius: 6px;
  --radius-lg: 10px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

/* The `hidden` attribute must win over component display rules (e.g. .chat-wrap
   and .empty-state set display:flex, which would otherwise defeat [hidden]). */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* Kills the iOS double-tap-zoom delay so the triple-tap panic gesture
     (boss.js) registers cleanly and taps feel instant. */
  touch-action: manipulation;
}

button, input, select, textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  padding: 8px 14px;
  border-radius: var(--radius);
  transition: background 120ms ease, border-color 120ms ease;
}
button:hover:not(:disabled) { background: var(--surface-2); }
button:disabled { opacity: 0.55; cursor: not-allowed; }

button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
button.primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); }

button.danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}
button.danger:hover:not(:disabled) { filter: brightness(0.95); }

button.ghost { background: transparent; border-color: transparent; padding: 6px 10px; color: var(--text-muted); }
button.ghost:hover { background: var(--surface-2); color: var(--text); }

input, textarea, select {
  width: 100%;
  padding: 9px 12px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  outline: none;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
input:focus, textarea:focus, select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(31, 78, 216, 0.12);
}

.muted { color: var(--text-muted); }
.small { font-size: 12px; }
.error { color: var(--danger); font-size: 13px; margin: 6px 0 0; }
.error.ok { color: var(--ok); }
.ok-text { color: var(--ok); }

/* ---------- Auth ---------- */
body.auth {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.auth-card {
  width: 100%;
  max-width: 360px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 32px;
  box-shadow: var(--shadow);
  text-align: center;
}
.auth-card h1 {
  font-size: 18px;
  margin: 8px 0 4px;
  font-weight: 600;
}
.auth-card form {
  margin-top: 20px;
  text-align: left;
}
.auth-card label { display: block; margin-bottom: 14px; }
.auth-card label span { display: block; font-size: 12px; color: var(--text-muted); margin-bottom: 6px; font-weight: 500; }
.auth-card button[type="submit"] {
  width: 100%;
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
  padding: 10px;
  font-weight: 500;
}
.auth-card button[type="submit"]:hover:not(:disabled) { background: var(--accent-hover); }
.auth-card footer { margin-top: 24px; }

.logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 8px;
  background: var(--text);
  color: #fff;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.5px;
}

/* ---------- App layout ---------- */
body.app {
  display: grid;
  grid-template-rows: 56px 1fr;
  min-height: 100vh;
}

.topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.topbar .brand { display: flex; align-items: center; gap: 10px; font-weight: 600; }
.topbar .brand .logo { width: 28px; height: 28px; font-size: 11px; border-radius: 6px; }
.topbar nav { display: flex; gap: 4px; margin-left: 20px; }
.tab {
  border: none;
  background: transparent;
  padding: 8px 12px;
  border-radius: var(--radius);
  color: var(--text-muted);
  font-weight: 500;
}
.tab:hover { background: var(--surface-2); color: var(--text); }
.tab.active { background: var(--surface-2); color: var(--text); }

.topbar .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.topbar-urgent { display: flex; align-items: center; gap: 10px; }
.user-badge {
  font-size: 12px;
  color: var(--text-muted);
  font-family: var(--mono);
  padding: 4px 8px;
  background: var(--surface-2);
  border-radius: 4px;
}
.presence-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--text-faint);
  margin-right: 6px;
}
.presence-dot.online { background: var(--ok); }
/* Away-but-reachable: contact is push-reachable (backgrounded/closed) and can
   still be called — a hollow amber ring, distinct from solid "online". */
.presence-dot.reachable { background: transparent; box-shadow: inset 0 0 0 2px #d9a441; }

main.work {
  display: grid;
  grid-template-columns: 260px 1fr;
  min-height: 0;
}
aside.sidebar {
  border-right: 1px solid var(--border);
  background: var(--surface);
  padding: 16px;
  overflow-y: auto;
}
aside.sidebar h3 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--text-faint);
  margin: 16px 0 8px;
  font-weight: 600;
}
aside.sidebar h3:first-child { margin-top: 0; }

.peer-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border-radius: var(--radius);
  background: transparent;
  border: none;
  text-align: left;
  margin-bottom: 2px;
}
.peer-item:hover { background: var(--surface-2); }
.peer-item.selected { background: var(--surface-2); font-weight: 500; }
.peer-name { font-family: var(--mono); font-size: 13px; flex: 1 1 auto; min-width: 0; }

/* Contact avatar — a colored initial circle (stable per contact). */
.peer-avatar {
  flex: 0 0 auto;
  width: 32px; height: 32px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--mono);
  font-size: 13px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, hsl(var(--h, 250) 72% 62%), hsl(calc(var(--h, 250) + 28) 70% 46%));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
}
.peer-avatar.online { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18), 0 0 0 2px rgba(40, 200, 120, 0.55); }
.peer-avatar { position: relative; }
/* Unread-message badge on a contact's avatar (content-free, privacy-safe). */
.unread-dot {
  position: absolute; top: -2px; right: -2px;
  width: 13px; height: 13px; border-radius: 50%;
  background: #f4506b; border: 2px solid var(--surface);
}
body.app .unread-dot { border-color: #141a26; }

/* Notifications toggle "on" state */
#notifyToggle.on { color: #fff; }
body.app #notifyToggle.on { background: rgba(53, 199, 132, 0.22); border-color: rgba(53, 199, 132, 0.5); }

/* ---------- Memories ---------- */
.memories-modal { width: min(96vw, 560px); }
.mem-list { display: flex; flex-direction: column; gap: 10px; max-height: 56vh; overflow-y: auto; margin: 6px 0; }
.mem-card { border: 1px solid var(--border); border-radius: 12px; padding: 12px; background: var(--surface-2); }
body.app .mem-card { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.1); }
.mem-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.mem-who { font-weight: 600; font-size: 13px; }
.mem-when { font-size: 11px; color: var(--text-faint); }
.mem-del { margin-left: auto; border: none; background: transparent; color: var(--text-faint); font-size: 14px; cursor: pointer; padding: 2px 6px; border-radius: 6px; }
.mem-del:hover { color: var(--danger); background: var(--danger-soft); }
.mem-text { font-size: 15px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; }
.mem-img { max-width: 100%; max-height: 320px; border-radius: 10px; display: block; }

/* Shared locker item content (Memories + Vault) */
.lk-text { font-size: 15px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; }
.lk-img { max-width: 100%; max-height: 320px; border-radius: 10px; display: block; }
.lk-video { max-width: 100%; max-height: 360px; border-radius: 10px; display: block; background: #000; }
.lk-file { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 13px; }
.lk-fname { color: var(--text-muted); word-break: break-word; }
.lk-open {
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text); border-radius: 8px; padding: 6px 12px; font-size: 13px; cursor: pointer;
  text-decoration: none;
}
body.app .lk-open { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.14); }

/* Vault */
.vault-modal { width: min(96vw, 620px); }
.vault-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.vault-bar #vaultUploadBtn { margin: 0; }
.vault-sort { margin-left: auto; display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
.vault-sort select {
  font: inherit; padding: 5px 8px; border-radius: 8px;
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--text); cursor: pointer;
}
body.app .vault-sort select { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.14); }

.vault-status {
  margin: 0 0 10px; padding: 8px 12px; border-radius: 8px; font-size: 13px;
  background: rgba(109, 94, 252, 0.14); border: 1px solid rgba(109, 94, 252, 0.4); color: var(--text);
}
body.app .vault-status { color: #d7d2ff; }

.pass-remember { display: flex; align-items: center; gap: 8px; font-size: 13px; margin: 10px 0 2px; cursor: pointer; }
.pass-remember input { width: auto; margin: 0; }

/* Face ID / passkey */
.faceid-btn { margin-top: 12px; width: 100%; }
.faceid-list { display: flex; flex-direction: column; gap: 6px; margin: 12px 0 4px; }
.faceid-row { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 10px; }
body.app .faceid-row { border-color: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.04); }
.faceid-name { font-weight: 600; font-size: 13px; }
.faceid-when { font-size: 11px; color: var(--text-faint); margin-left: auto; }
#faceIdMsg.error { color: var(--danger); }

.vault-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(94px, 1fr));
  gap: 12px; align-content: start;
}
.vtile {
  display: flex; flex-direction: column; gap: 6px; padding: 0;
  border: none; background: transparent; cursor: pointer; text-align: left; font: inherit; color: inherit;
}
.vthumb {
  position: relative; width: 100%; aspect-ratio: 1 / 1; border-radius: 10px; overflow: hidden;
  background: var(--surface-2); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  transition: border-color 120ms ease, transform 120ms ease;
}
body.app .vthumb { background: rgba(255, 255, 255, 0.05); border-color: rgba(255, 255, 255, 0.1); }
.vthumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vicon { font-size: 30px; opacity: 0.85; }
.vbadge {
  position: absolute; bottom: 4px; right: 4px; background: rgba(0, 0, 0, 0.62); color: #fff;
  font-size: 10px; line-height: 1; padding: 3px 5px; border-radius: 5px; text-transform: uppercase; letter-spacing: 0.04em;
}
.vplay {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 24px; color: #fff; text-shadow: 0 1px 6px rgba(0, 0, 0, 0.7); pointer-events: none;
}
.vname {
  font-size: 11px; line-height: 1.3; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vtile:hover .vthumb { border-color: var(--border-strong); transform: translateY(-1px); }
.vtile:focus-visible { outline: none; }
.vtile:focus-visible .vthumb { border-color: #6d5efc; box-shadow: 0 0 0 2px rgba(109, 94, 252, 0.5); }

.lightbox .vault-modal { max-height: 92vh; overflow-y: auto; }
.lightbox-body { display: flex; justify-content: center; margin: 6px 0 4px; }
.lightbox-body .lk-img, .lightbox-body .lk-video { max-height: 56vh; }
.lightbox-actions { margin-top: 12px; position: sticky; bottom: 0; }

/* Per-tile delete (✕) — always reachable, especially on mobile. */
.vtile-del {
  position: absolute; top: 4px; right: 4px; z-index: 2;
  width: 26px; height: 26px; padding: 0; border: none; border-radius: 50%;
  background: rgba(0, 0, 0, 0.55); color: #fff; font-size: 12px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0.85; transition: background 120ms ease, opacity 120ms ease;
}
.vtile-del:hover { background: rgba(220, 38, 38, 0.9); opacity: 1; }

.vault-share {
  border: 1px solid rgba(109, 94, 252, 0.5); background: rgba(109, 94, 252, 0.14);
  color: #c3b9ff; border-radius: 8px; padding: 7px 12px; font-size: 13px; cursor: pointer;
}
.vault-share:hover { background: rgba(109, 94, 252, 0.24); }
.ghost.danger { color: var(--danger); }
.ghost.danger:hover { background: var(--danger-soft); }

section.panel {
  padding: 12px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
#chatPanel { padding: 12px 16px 16px; }
section.panel.hidden { display: none; }

/* ---------- Call panel ---------- */
.call-stage {
  display: flex;
  flex-direction: column;
  gap: 16px;
  height: 100%;
  min-height: 0;
}
.video-area {
  position: relative;
  flex: 1;
  min-height: 0;
  background: #0b0e14;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
}
.video-area[hidden] { display: none; }
.remote-video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #0b0e14;
  display: block;
}
.local-video {
  position: absolute;
  right: 12px;
  bottom: 12px;
  width: 160px;
  max-width: 34%;
  border-radius: 8px;
  border: 2px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
  background: #000;
  object-fit: cover;
}
.local-video[hidden] { display: none; }

/* Fullscreen toggle for a video call — sits over the top-right of the stage.
   Hidden until a video call is actually up (call.js reveals it). */
.fs-btn {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 3;
  display: none;
  width: 40px;
  height: 40px;
  padding: 0;
  font-size: 20px;
  line-height: 1;
  color: #fff;
  background: rgba(10, 14, 20, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 10px;
  cursor: pointer;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: background 150ms ease, transform 150ms ease;
}
.fs-btn:hover { background: rgba(10, 14, 20, 0.78); }
.fs-btn:active { transform: scale(0.94); }
.video-area.show-fs .fs-btn { display: block; }
/* When the stage itself is fullscreen, let the picture fill the whole screen. */
.video-area:fullscreen { background: #000; border-radius: 0; max-height: none; }
.video-area:fullscreen .remote-video { object-fit: contain; }
.video-area:-webkit-full-screen { background: #000; border-radius: 0; max-height: none; }

.call-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 24px;
  box-shadow: var(--shadow);
  max-width: 520px;
}
.call-card h2 { margin: 0 0 4px; font-size: 16px; }
.call-card .status { margin: 8px 0 16px; color: var(--text-muted); font-size: 13px; }
.call-controls { display: flex; gap: 8px; flex-wrap: wrap; }
.call-meta { margin-top: 14px; font-size: 12px; color: var(--text-faint); }

/* ---------- Chat panel ---------- */
.chat-wrap {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  height: 100%;
  min-height: 0;
  overflow: hidden;
}
.chat-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.chat-header .who { font-weight: 600; font-family: var(--mono); font-size: 13px; }
.chat-header .lock { color: var(--ok); font-size: 12px; cursor: pointer; border-radius: 6px; padding: 2px 4px; }
.chat-header .lock:hover { background: rgba(255, 255, 255, 0.06); }
.chat-header .lock:focus-visible { outline: 2px solid #6d5efc; outline-offset: 1px; }
.chat-header .chat-fp { font-size: 11px; color: var(--text-faint); font-family: ui-monospace, "SF Mono", Menlo, monospace; letter-spacing: 0.03em; }
.chat-header .chat-fp.hidden { display: none; }
.chat-header .ttl { font-size: 11px; color: var(--text-faint); margin-left: auto; }

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--surface-2);
}
.msg {
  max-width: 80%;
  padding: 10px 14px;
  border-radius: 12px;
  font-size: 14px;
  position: relative;
  word-wrap: break-word;
  white-space: pre-wrap;
  transition: opacity 400ms ease;
}
.msg.mine { align-self: flex-end; background: var(--accent); color: #fff; }
.msg.theirs { align-self: flex-start; background: var(--surface); border: 1px solid var(--border); }
.msg .meta { font-size: 10px; opacity: 0.7; margin-top: 4px; display: flex; justify-content: space-between; gap: 12px; }
.msg .meta .meta-right { display: flex; align-items: center; gap: 8px; }
.msg.fading { opacity: 0.15; }

/* Per-message self-destruct countdown. */
.msg .countdown { font-variant-numeric: tabular-nums; white-space: nowrap; }
.msg.theirs .countdown { color: var(--text-faint); }
.msg.mine .countdown { color: rgba(255, 255, 255, 0.8); }
.msg .countdown.low { color: #ff5d50; font-weight: 700; }

/* WhatsApp-style delivery ticks (only on our own messages). */
.msg .meta .ticks { font-weight: 700; letter-spacing: -1px; font-size: 11px; }
.msg.mine .meta .ticks.tick-sent,
.msg.mine .meta .ticks.tick-delivered { color: rgba(255, 255, 255, 0.85); }
.msg.mine .meta .ticks.tick-read { color: #6fe3ff; }

.chat-input {
  position: relative;
  display: flex;
  gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface);
}
.chat-input textarea {
  resize: none;
  height: 48px;
  max-height: 200px;
  padding: 12px;
}
.chat-input button { white-space: nowrap; }
.chat-input .attach,
.chat-input .camera,
.chat-input .emoji {
  width: 40px;
  min-width: 40px;
  padding: 0;
  font-size: 22px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-muted);
}
.chat-input .camera { font-size: 18px; }
.chat-input .emoji { font-size: 19px; }
.chat-input .attach:hover:not(:disabled),
.chat-input .camera:hover:not(:disabled),
.chat-input .emoji:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }

/* Emoji picker popover */
.emoji-panel {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 12px;
  width: 296px;
  max-height: 240px;
  overflow-y: auto;
  padding: 8px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.16);
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 2px;
  z-index: 20;
}
.emoji-panel.hidden { display: none; }
.emoji-panel button {
  border: none;
  background: transparent;
  padding: 4px 0;
  font-size: 20px;
  line-height: 1.4;
  border-radius: 6px;
}
.emoji-panel button:hover { background: var(--surface-2); }

/* Photo/video message bubbles */
.msg.media { padding: 6px; }
.media-thumb {
  display: block;
  max-width: 260px;
  max-height: 280px;
  width: auto;
  border-radius: 8px;
  cursor: pointer;
}
video.media-thumb { cursor: default; max-width: 280px; }
.media-file {
  display: inline-block;
  padding: 8px 12px;
  color: inherit;
  text-decoration: underline;
}
.msg.media .meta { padding: 0 2px; }

/* ---------- Message reactions ---------- */
/* Per-bubble "react" button — revealed on hover (desktop), faintly persistent
   on touch where there's no hover. Long-press also opens the picker. */
.react-btn {
  position: absolute;
  top: 50%;
  right: -32px;
  transform: translateY(-50%);
  width: 26px;
  height: 26px;
  min-width: 0;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow);
  opacity: 0;
  transition: opacity 120ms ease;
}
.msg:hover .react-btn { opacity: 1; }
@media (hover: none) { .react-btn { opacity: 0.55; } }

/* Floating quick-reaction palette (positioned by JS). */
.reaction-bar {
  position: fixed;
  z-index: 50;
  display: flex;
  gap: 2px;
  padding: 4px 6px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.2);
}
.reaction-bar.hidden { display: none; }
.reaction-bar button {
  border: none;
  background: transparent;
  padding: 4px;
  font-size: 22px;
  line-height: 1;
  border-radius: 50%;
  transition: transform 100ms ease, background 100ms ease;
}
.reaction-bar button:hover { background: var(--surface-2); transform: scale(1.2); }

/* The badge that lands on a message once reacted. */
.msg .reaction {
  position: absolute;
  bottom: -11px;
  right: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 5px;
  font-size: 13px;
  line-height: 18px;
  box-shadow: var(--shadow);
}
.msg.mine .reaction { right: auto; left: 8px; }
.reaction.pop { animation: reactionPop 240ms ease; }
@keyframes reactionPop {
  0% { transform: scale(0.4); opacity: 0; }
  60% { transform: scale(1.2); }
  100% { transform: scale(1); opacity: 1; }
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--text-faint);
  text-align: center;
  padding: 40px;
}
.empty-state h3 { color: var(--text-muted); font-weight: 500; margin: 0 0 6px; }

/* ---------- Modal ---------- */
.modal-bg {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}
.modal-bg.hidden { display: none; }
.modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 24px;
  width: 100%;
  max-width: 380px;
  box-shadow: 0 10px 30px rgba(16,24,40,0.12);
}
.modal h2 { margin: 0 0 8px; font-size: 16px; }
.modal p { color: var(--text-muted); font-size: 13px; margin: 0 0 16px; }
.modal .actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }

/* ---------- Camera capture ---------- */
.camera-modal { max-width: 460px; }
.camera-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  max-height: 60vh;
  background: #0b0e14;
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 12px;
}
.camera-stage video,
.camera-stage img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.camera-stage video[hidden],
.camera-stage img[hidden] { display: none; }
.camera-actions { flex-wrap: wrap; justify-content: center; }

/* ---------- Decoy ---------- */
.decoy-shell { padding: 24px; max-width: 1100px; margin: 0 auto; }
.decoy-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; margin-top: 20px; }
.decoy-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 16px; box-shadow: var(--shadow); }
.decoy-card h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--text-faint); margin: 0 0 8px; }
.decoy-card .value { font-size: 24px; font-weight: 600; }
.decoy-card .delta { font-size: 12px; color: var(--ok); margin-top: 4px; }
.decoy-card .delta.down { color: var(--danger); }
.decoy-table { width: 100%; border-collapse: collapse; margin-top: 20px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; }
.decoy-table th, .decoy-table td { padding: 10px 14px; text-align: left; border-bottom: 1px solid var(--border); font-size: 13px; }
.decoy-table th { background: var(--surface-2); color: var(--text-muted); font-weight: 500; font-size: 12px; text-transform: uppercase; letter-spacing: 0.4px; }
.decoy-table tr:last-child td { border-bottom: none; }
.pill { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 500; }
.pill.green { background: #e7f4ec; color: var(--ok); }
.pill.amber { background: #fef3c7; color: #92400e; }
.pill.gray  { background: var(--surface-2); color: var(--text-muted); }

/* ---------- Panic boss-key: code-review disguise ---------- */
.boss {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: #ffffff;
  color: #1f2328;
  overflow-y: auto;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  outline: none;
}
.boss.hidden { display: none; }
.gh { max-width: 1000px; margin: 0 auto; padding: 24px 20px 80px; }
.gh-head { border-bottom: 1px solid #d0d7de; padding-bottom: 0; margin-bottom: 16px; }
.gh-repo { font-size: 14px; color: #0969da; }
.gh-repo .sep { color: #656d76; }
.gh-repo strong { color: #0969da; font-weight: 600; }
.gh-pill { display: inline-block; margin-left: 8px; padding: 3px 11px; border-radius: 20px; font-size: 12px; color: #fff; vertical-align: middle; }
.gh-pill.open { background: #1f883d; }
.gh-title { font-size: 26px; font-weight: 400; margin: 10px 0 6px; }
.gh-num { color: #656d76; font-weight: 300; }
.gh-sub { font-size: 14px; color: #656d76; }
.gh-sub code { background: #eff2f5; padding: 1px 6px; border-radius: 6px; font-size: 12px; font-family: var(--mono); }
.gh-user { color: #1f2328; font-weight: 600; }
.gh-tabs { display: flex; gap: 20px; margin-top: 16px; font-size: 14px; color: #656d76; }
.gh-tabs span { padding-bottom: 12px; }
.gh-tabs em { font-style: normal; background: #eff2f5; border-radius: 20px; padding: 1px 7px; font-size: 12px; margin-left: 5px; }
.gh-tabs .active { color: #1f2328; font-weight: 600; box-shadow: inset 0 -2px 0 #fd8c73; }
.gh-meta { font-size: 14px; color: #656d76; margin-bottom: 14px; }
.add-c { color: #1a7f37; }
.del-c { color: #cf222e; }
.gh-file { border: 1px solid #d0d7de; border-radius: 6px; margin-bottom: 16px; overflow: hidden; }
.gh-file-head {
  background: #f6f8fa;
  border-bottom: 1px solid #d0d7de;
  padding: 8px 12px;
  font-family: var(--mono);
  font-size: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.gh-file-head { cursor: pointer; }
.gh-file-head .chev { color: #656d76; }
.gh-file.collapsed .gh-diff { display: none; }
.diffstat { margin-left: auto; }
.diffstat i { font-style: normal; margin-left: 6px; }
.gh-diff {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 12px;
}
.gh-diff td { padding: 0 10px; line-height: 20px; white-space: pre; }
.gh-diff .num { width: 1%; text-align: right; color: #656d76; user-select: none; }
.ln.add { background: #e6ffec; }
.ln.add .num { background: #ccffd8; }
.ln.del { background: #ffebe9; }
.ln.del .num { background: #ffd7d5; }
.ln .code { width: 100%; }
.gh-comment { border: 1px solid #d0d7de; border-radius: 6px; margin-bottom: 16px; }
.gh-comment-head { background: #f6f8fa; border-bottom: 1px solid #d0d7de; padding: 8px 12px; font-size: 13px; }
.gh-comment-body { padding: 12px; font-size: 14px; }
.gh-comment-body code { background: #eff2f5; padding: 1px 6px; border-radius: 6px; font-size: 12px; font-family: var(--mono); }
.gh-review { display: flex; align-items: center; gap: 16px; margin-top: 8px; }
.gh-approve { background: #1f883d; color: #fff; border: 1px solid rgba(27, 31, 36, 0.15); padding: 8px 16px; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; }
.gh-checks { color: #1a7f37; font-size: 13px; }

/* Clickable tabs + per-tab panels */
.gh-tabs span[data-tab] { cursor: pointer; }
.gh-tabs span[data-tab]:hover { color: #1f2328; }
.gh-panel.hidden { display: none; }

/* Conversation timeline events */
.gh-event { font-size: 13px; color: #656d76; padding: 10px 4px; border-bottom: 1px solid #eaeef2; }
.gh-event code { background: #eff2f5; padding: 1px 6px; border-radius: 6px; font-size: 12px; font-family: var(--mono); }

/* Commits list */
.gh-commit { display: flex; align-items: center; gap: 12px; border: 1px solid #d0d7de; border-bottom: none; padding: 10px 14px; }
.gh-commit:first-child { border-radius: 6px 6px 0 0; }
.gh-commit:last-child { border-bottom: 1px solid #d0d7de; border-radius: 0 0 6px 6px; }
.gc-main { display: flex; flex-direction: column; }
.gc-msg { font-size: 14px; color: #1f2328; font-weight: 500; }
.gc-meta { font-size: 12px; color: #656d76; }
.gc-sha { margin-left: auto; background: #eff2f5; padding: 2px 8px; border-radius: 6px; font-size: 12px; color: #656d76; font-family: var(--mono); }

/* Checks list */
.gh-checks-head { font-size: 14px; color: #1f2328; padding: 10px 0 14px; }
.gh-check { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-bottom: 1px solid #eaeef2; font-size: 14px; }
.gc-ok { color: #1a7f37; font-weight: 700; }
.gc-name { color: #1f2328; }
.gc-t { margin-left: auto; color: #656d76; font-size: 12px; }

/* "Review changes" form popover */
.gh-review-wrap { position: relative; }
.gh-review-form {
  position: absolute; bottom: calc(100% + 8px); left: 0;
  width: 360px; max-width: 86vw;
  background: #fff; border: 1px solid #d0d7de; border-radius: 8px; padding: 14px;
  box-shadow: 0 8px 24px rgba(31, 35, 40, 0.2); z-index: 5; text-align: left;
}
.gh-review-form.hidden { display: none; }
.grf-title { font-weight: 600; font-size: 14px; margin-bottom: 8px; color: #1f2328; }
.boss .gh-review-form textarea {
  width: 100%; border: 1px solid #d0d7de; border-radius: 6px; padding: 8px;
  font-size: 13px; font-family: inherit; resize: vertical; margin-bottom: 8px;
  color: #1f2328; background: #fff;
}
.grf-opt { display: flex; gap: 8px; align-items: flex-start; padding: 6px 0; font-size: 13px; color: #1f2328; cursor: pointer; }
.grf-opt i { color: #656d76; font-style: normal; font-size: 12px; }
.gh-submit { margin-top: 8px; background: #1f883d; color: #fff; border: 1px solid rgba(27, 31, 36, 0.15); padding: 6px 14px; border-radius: 6px; font-size: 13px; font-weight: 500; cursor: pointer; }

/* Merge box */
.gh-mergebox { border: 1px solid #d0d7de; border-radius: 6px; padding: 14px; margin-top: 16px; display: flex; align-items: center; gap: 12px; }
.gh-merge-status { font-size: 13px; color: #1f2328; }
.gh-merge { margin-left: auto; background: #8250df; color: #fff; border: 1px solid rgba(27, 31, 36, 0.15); padding: 8px 16px; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; }
.gh-merge.confirm { background: #6639ba; }
.gh-mergebox.merged { color: #8250df; font-size: 14px; }
.gh-mergebox.merged code { background: #eff2f5; padding: 1px 6px; border-radius: 6px; font-size: 12px; font-family: var(--mono); }
.gh-merged-dot { display: inline-block; width: 12px; height: 12px; border-radius: 50%; background: #8250df; }
.gh-pill.merged { background: #8250df; }

/* =====================================================================
   Rich app theme — scoped to body.app ONLY.
   The decoy dashboard (body, no class) and the panic GitHub screen
   (.boss/.gh-*) deliberately keep their neutral / hardcoded looks so the
   disguises stay believable. We override the design tokens for the real
   app subtree and layer glass, gradients, glow, and motion on top.
   ===================================================================== */
body.app {
  --bg: #080b12;
  --surface: #141a26;
  --surface-2: #0f141e;
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.16);
  --text: #e7ebf3;
  --text-muted: #9aa4b6;
  --text-faint: #6b7688;
  --accent: #6d5efc;
  --accent-hover: #5a4bf0;
  --accent-2: #38bdf8;
  --danger: #f4506b;
  --ok: #34d399;
  --shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
  --glow: 0 8px 30px rgba(109, 94, 252, 0.35);

  background:
    radial-gradient(1100px 560px at 12% -12%, rgba(109, 94, 252, 0.20), transparent 60%),
    radial-gradient(950px 520px at 112% 6%, rgba(56, 189, 248, 0.14), transparent 55%),
    radial-gradient(820px 820px at 50% 124%, rgba(124, 107, 255, 0.12), transparent 60%),
    #080b12;
  color: var(--text);
}

body.app ::placeholder { color: var(--text-faint); opacity: 1; }

/* Slim, themed scrollbars */
body.app * { scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, 0.2) transparent; }
body.app *::-webkit-scrollbar { width: 10px; height: 10px; }
body.app *::-webkit-scrollbar-track { background: transparent; }
body.app *::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
body.app *::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.26); background-clip: padding-box; }

/* ---- Top bar ---- */
body.app .topbar {
  background: #0c101a;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
body.app .topbar .brand { color: var(--text); }
body.app .topbar .brand > span {
  background: linear-gradient(135deg, #ffffff, #b9c0ff);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  letter-spacing: 0.2px;
}
body.app .logo {
  background: linear-gradient(135deg, #6d5efc, #38bdf8);
  color: #fff;
  box-shadow: 0 6px 18px rgba(109, 94, 252, 0.5);
}
body.app .tab { color: var(--text-muted); font-weight: 500; }
body.app .tab:hover { background: rgba(255, 255, 255, 0.06); color: var(--text); }
body.app .tab.active {
  background: rgba(109, 94, 252, 0.16);
  color: #fff;
  box-shadow: inset 0 0 0 1px rgba(109, 94, 252, 0.45);
}
body.app .user-badge {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: var(--text-muted);
}

/* ---- Sidebar ---- */
body.app aside.sidebar {
  background: rgba(13, 18, 28, 0.85);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border-right: 1px solid rgba(255, 255, 255, 0.07);
}
body.app .peer-item {
  border-radius: 10px;
  transition: background 150ms ease, transform 150ms ease;
}
body.app .peer-item:hover { background: rgba(255, 255, 255, 0.05); transform: translateX(2px); }
body.app .peer-item.selected {
  background: linear-gradient(90deg, rgba(109, 94, 252, 0.24), rgba(109, 94, 252, 0.04));
  box-shadow: inset 2px 0 0 #6d5efc;
  font-weight: 600;
}
body.app .presence-dot.online {
  background: var(--ok);
  box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.55);
  animation: pulseDot 2.2s infinite;
}
@keyframes pulseDot {
  0% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.5); }
  70% { box-shadow: 0 0 0 6px rgba(52, 211, 153, 0); }
  100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0); }
}

/* ---- Buttons + inputs ---- */
body.app button { transition: background 140ms ease, border-color 140ms ease, transform 140ms ease, box-shadow 140ms ease, filter 140ms ease; }
body.app button.primary {
  background: linear-gradient(135deg, #6d5efc, #5b8cff);
  border: 1px solid transparent;
  box-shadow: 0 6px 16px rgba(109, 94, 252, 0.35);
}
body.app button.primary:hover:not(:disabled) {
  filter: brightness(1.08);
  transform: translateY(-1px);
  box-shadow: 0 10px 24px rgba(109, 94, 252, 0.5);
}
body.app button.danger {
  background: linear-gradient(135deg, #f4506b, #e11d48);
  border: 1px solid transparent;
  box-shadow: 0 6px 16px rgba(244, 80, 107, 0.32);
}
body.app button.danger:hover:not(:disabled) { transform: translateY(-1px); filter: brightness(1.05); }
body.app button.ghost { color: var(--text-muted); }
body.app button.ghost:hover { background: rgba(255, 255, 255, 0.08); color: var(--text); }
body.app input, body.app textarea, body.app select {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.12);
}
/* A native <select> renders its dropdown using the control's computed colors.
   The translucent background above composites to white in the popup, so on a
   dark theme the options came out white-on-white (invisible). Force a solid,
   readable background + text on the control AND its <option>s. */
body.app select {
  background-color: #1b2331;
  color: #e8ebf2;
}
body.app select option {
  background-color: #1b2331;
  color: #e8ebf2;
}
body.app input:focus, body.app textarea:focus, body.app select:focus {
  border-color: #6d5efc;
  box-shadow: 0 0 0 3px rgba(109, 94, 252, 0.25);
  background: rgba(255, 255, 255, 0.06);
}

/* ---- Chat ---- */
body.app .chat-wrap {
  background: rgba(17, 23, 34, 0.58);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
}
body.app .chat-header {
  background: rgba(255, 255, 255, 0.03);
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
body.app .chat-messages { background: transparent; }
body.app .msg {
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.28);
  animation: msgIn 260ms cubic-bezier(0.16, 1, 0.3, 1);
}
body.app .msg.mine {
  background: linear-gradient(135deg, #6d5efc, #4f7dff);
  color: #fff;
  border-radius: 16px 16px 4px 16px;
  box-shadow: 0 8px 22px rgba(109, 94, 252, 0.38);
}
body.app .msg.theirs {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.10);
  color: var(--text);
  border-radius: 16px 16px 16px 4px;
}
@keyframes msgIn {
  from { opacity: 0; transform: translateY(10px) scale(0.97); }
  to { opacity: 1; transform: none; }
}
body.app .chat-input {
  background: rgba(255, 255, 255, 0.03);
  border-top: 1px solid rgba(255, 255, 255, 0.07);
}
body.app .chat-input textarea { border-radius: 14px; background: rgba(255, 255, 255, 0.05); }
body.app .chat-input .attach,
body.app .chat-input .camera,
body.app .chat-input .emoji {
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.05);
  color: var(--text-muted);
}
body.app .chat-input .attach:hover:not(:disabled),
body.app .chat-input .camera:hover:not(:disabled),
body.app .chat-input .emoji:hover:not(:disabled) {
  background: rgba(109, 94, 252, 0.2);
  border-color: rgba(109, 94, 252, 0.5);
  color: #fff;
}
body.app #chatSend { border-radius: 14px; padding-left: 20px; padding-right: 20px; }

/* ---- Popovers / reactions ---- */
body.app .emoji-panel,
body.app .reaction-bar,
body.app .react-btn,
body.app .msg .reaction {
  background: rgba(20, 26, 38, 0.92);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: var(--text);
}
body.app .emoji-panel button:hover,
body.app .reaction-bar button:hover { background: rgba(109, 94, 252, 0.22); }
body.app .react-btn:hover { background: rgba(109, 94, 252, 0.3); color: #fff; border-color: rgba(109, 94, 252, 0.6); }

/* ---- Empty state ---- */
body.app .empty-state::before {
  content: "🔒";
  font-size: 30px;
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  margin-bottom: 18px;
  background: radial-gradient(circle at 50% 35%, rgba(109, 94, 252, 0.35), rgba(109, 94, 252, 0.05));
  box-shadow: 0 0 0 1px rgba(109, 94, 252, 0.25), 0 10px 30px rgba(109, 94, 252, 0.25);
}
body.app .empty-state h3 { color: var(--text); font-size: 17px; }

/* ---- Call panel ---- */
body.app .call-card {
  background: rgba(17, 23, 34, 0.6);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}
body.app .video-area {
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
}

/* ---- Modals ---- */
body.app .modal-bg {
  background: rgba(4, 6, 12, 0.62);
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
}
body.app .modal {
  background: rgba(20, 26, 38, 0.86);
  -webkit-backdrop-filter: blur(22px) saturate(140%);
  backdrop-filter: blur(22px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 28px 70px rgba(0, 0, 0, 0.6);
}
body.app .camera-stage { border: 1px solid rgba(255, 255, 255, 0.1); }

/* =====================================================================
   New WhatsApp-style features: typing indicator, disappearing-timer
   control, per-message actions, quoted replies, voice notes, incoming
   call ring. All token-driven so they inherit the dark app theme.
   ===================================================================== */

/* ---- Typing indicator (chat header) ---- */
.typing {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-style: italic;
  color: var(--text-muted);
}
.typing.hidden { display: none; }
.typing-dots { display: inline-flex; gap: 3px; }
.typing-dots i {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent-2, var(--accent));
  display: inline-block;
  animation: typingBounce 1.2s infinite;
}
.typing-dots i:nth-child(2) { animation-delay: 0.2s; }
.typing-dots i:nth-child(3) { animation-delay: 0.4s; }
@keyframes typingBounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
  30% { transform: translateY(-4px); opacity: 1; }
}

/* ---- Disappearing-messages timer button ---- */
.ttl-btn {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  padding: 5px 12px;
  border-radius: 999px;
  white-space: nowrap;
  flex-shrink: 0;   /* never let the timer button get squeezed off-screen */
}
/* Scoped under .chat-header so these win over the generic `.ghost` button rules
   (otherwise the ghost hover paints a wrong whitish highlight and drops the
   border). A clean pill: subtle fill at rest, gentle accent glow on hover. */
body.app .chat-header .ttl-btn {
  border: 1px solid var(--border-strong);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-muted);
  box-shadow: none;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
body.app .chat-header .ttl-btn:hover {
  background: rgba(109, 94, 252, 0.18);
  border-color: rgba(109, 94, 252, 0.5);
  color: #fff;
}
body.app .chat-header .ttl-btn:focus-visible {
  outline: 2px solid rgba(109, 94, 252, 0.6);
  outline-offset: 2px;
}
.field-label { display: block; font-size: 12px; color: var(--text-muted); margin: 4px 0 6px; }

/* ---- Emergency: SOS button + live-share banner ---- */
.sos-btn { font-weight: 700; }
body.app .sos-btn { animation: sosPulse 1.8s ease-in-out infinite; }
@keyframes sosPulse {
  0%, 100% { box-shadow: 0 6px 16px rgba(244, 80, 107, 0.32); }
  50% { box-shadow: 0 6px 24px rgba(244, 80, 107, 0.75); }
}
.live-share-banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  background: linear-gradient(90deg, #e11d48, #f4506b);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
}
.live-share-banner.hidden { display: none; }
.live-share-banner .live-dot {
  width: 12px; height: 12px;
  border-radius: 50%;
  background: #fff;
  animation: recPulse 1s infinite;
}
.live-share-banner .live-stop {
  margin-left: auto;
  background: rgba(255, 255, 255, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.65);
  color: #fff;
}
.live-share-banner .live-stop:hover { background: rgba(255, 255, 255, 0.3); color: #fff; }

/* ---- Per-message action buttons (reply / react / delete) ---- */
.msg-actions {
  position: absolute;
  top: -13px;
  display: flex;
  gap: 3px;
  opacity: 0;
  transition: opacity 120ms ease;
  z-index: 6;
}
.msg.theirs .msg-actions { right: 6px; }
.msg.mine .msg-actions { left: 6px; }
.msg:hover .msg-actions { opacity: 1; }
@media (hover: none) { .msg-actions { opacity: 0.5; } }
.msg-action {
  width: 26px; height: 26px;
  min-width: 0; padding: 0;
  border-radius: 50%;
  font-size: 13px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  box-shadow: var(--shadow);
}
.msg-action:hover { background: var(--surface-2); color: var(--text); }
body.app .msg-action {
  background: rgba(20, 26, 38, 0.92);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.14);
}
body.app .msg-action:hover { background: rgba(109, 94, 252, 0.32); color: #fff; border-color: rgba(109, 94, 252, 0.6); }

/* ---- Quoted reply block inside a bubble ---- */
.msg-text { white-space: pre-wrap; word-wrap: break-word; }
.msg-link { font-weight: 600; text-decoration: underline; overflow-wrap: anywhere; }
.msg-link:hover { text-decoration: none; }
.msg.mine .msg-link { color: #fff; text-decoration-color: rgba(255, 255, 255, 0.7); }
.msg.theirs .msg-link { color: var(--accent-2, var(--accent)); }
.quote {
  padding: 5px 9px;
  margin-bottom: 6px;
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.06);
  font-size: 12px;
  max-width: 100%;
}
.msg.mine .quote { background: rgba(255, 255, 255, 0.18); border-left-color: rgba(255, 255, 255, 0.75); }
.msg.theirs .quote { background: rgba(255, 255, 255, 0.06); border-left-color: var(--accent-2, var(--accent)); }
.quote-author { font-weight: 700; font-size: 11px; margin-bottom: 2px; }
.quote-text { opacity: 0.85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Deleted-for-everyone tombstone + system notices */
.msg.deleted { opacity: 0.75; }
.deleted-note { font-style: italic; opacity: 0.85; }
.msg.system { font-style: italic; opacity: 0.7; }

/* ---- Composer: reply preview + voice recording bars ---- */
.chat-input { flex-wrap: wrap; }
.reply-bar, .voice-bar { width: 100%; order: -1; }

.reply-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--border);
}
.reply-bar.hidden { display: none; }
.reply-bar-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
  border-left: 3px solid var(--accent-2, var(--accent));
  padding-left: 9px;
}
.reply-bar-author { font-weight: 700; font-size: 12px; color: var(--accent-2, var(--accent)); }
.reply-bar-text { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.reply-bar-x { width: 30px; min-width: 30px; padding: 0; border-radius: 50%; }

.voice-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 12px;
  background: rgba(244, 80, 107, 0.12);
  border: 1px solid rgba(244, 80, 107, 0.32);
}
.voice-bar.hidden { display: none; }
.voice-time { font-variant-numeric: tabular-nums; font-weight: 700; }
.voice-hint { color: var(--text-muted); font-size: 12px; margin-right: auto; }
.rec-dot {
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--danger);
  animation: recPulse 1s infinite;
}
@keyframes recPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.35; transform: scale(0.75); }
}
.chat-input .mic { font-size: 18px; }
.chat-input .mic.recording { background: var(--danger); border-color: var(--danger); color: #fff; }
body.app .chat-input .mic { font-size: 18px; }

/* ---- Voice-note bubble ---- */
.media-audio { display: flex; align-items: center; gap: 8px; padding: 4px 6px; min-width: 220px; flex-wrap: wrap; }
.media-audio-label { font-size: 20px; }
.media-audio audio { height: 36px; max-width: 240px; }
/* Voice-note waveform: a compact row of amplitude bars drawn from the sampled
   envelope shipped inside the encrypted header. Purely decorative. */
.media-audio .wave { display: flex; align-items: center; gap: 2px; height: 30px; flex: 1 1 120px; min-width: 90px; }
.media-audio .wave span {
  flex: 1 1 auto; width: 2px; min-height: 3px; border-radius: 2px;
  background: var(--accent, #6ea8fe); opacity: .8; align-self: center;
}
.msg.theirs .media-audio .wave span { background: var(--accent-2, #9aa7bd); }

/* ---- Time-capsule messages ---- */
.capsule-btn.active { background: var(--accent, #6ea8fe); border-color: var(--accent, #6ea8fe); color: #fff; }
.capsule-input { max-width: 200px; font-size: 13px; padding: 4px 6px; border-radius: 8px;
  border: 1px solid var(--line, #2a3550); background: var(--surface, #131a29); color: var(--text, #dfe6f5); }
.msg.capsule { font-style: italic; opacity: .92; }
.capsule-title { font-weight: 600; font-style: normal; }
.capsule-when { font-size: 12px; color: var(--muted, #9aa7bd); margin-top: 2px; }
.capsule-tag { font-size: 11px; color: var(--accent, #6ea8fe); margin-right: 6px; }
.cap-opt { display: flex; gap: 8px; align-items: flex-start; margin: 10px 0 4px; cursor: pointer; }
.cap-opt input { margin-top: 3px; }
.cap-opt small { display: block; margin-top: 2px; }
#capsuleModal .capsule-input { margin: 4px 0 6px 26px; }
#capsuleModal .capsule-input.hidden { display: none; }
.capsule-opened-tag { font-size: 11px; color: var(--accent, #6ea8fe); margin-bottom: 4px; font-weight: 600; }
.msg.capsule-opened { outline: 1px solid rgba(110,168,254,.35); }

/* ---- What's New guide ---- */
.modal.whatsnew { max-width: 640px; width: 92vw; max-height: 86vh; display: flex; flex-direction: column; padding: 0; overflow: hidden; }
.wn-top { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px 10px; border-bottom: 1px solid var(--line, #2a3550); }
.wn-top h2 { margin: 0; }
.wn-body { overflow-y: auto; padding: 14px 20px 22px; }
.wn-intro { color: var(--muted, #9aa7bd); margin: 0 0 14px; }
.wn-cat { font-size: 13px; text-transform: uppercase; letter-spacing: .08em; color: var(--accent, #6ea8fe); margin: 20px 0 8px; }
.wn-item { padding: 12px 0; border-top: 1px solid rgba(255,255,255,.06); }
.wn-head { display: flex; align-items: center; gap: 10px; }
.wn-emoji { font-size: 22px; }
.wn-title { font-weight: 600; font-size: 16px; }
.wn-what { color: var(--muted, #9aa7bd); margin: 4px 0 6px 32px; font-size: 14px; }
.wn-steps { margin: 0 0 0 32px; padding-left: 18px; }
.wn-steps li { margin: 3px 0; font-size: 14px; }
.wn-warn { margin: 6px 0 0 32px; font-size: 13px; color: var(--danger, #e5484d); }

/* ---- Cupid (couples games) ---- */
.cupid-overlay { position: fixed; inset: 0; z-index: 9997; background: rgba(10,6,14,.72);
  display: flex; align-items: center; justify-content: center; padding: 16px; backdrop-filter: blur(4px); }
.cupid-overlay.hidden { display: none; }
.cupid-panel { width: 100%; max-width: 440px; max-height: 88vh; display: flex; flex-direction: column;
  background: linear-gradient(160deg, #241026, #14101f 60%); border: 1px solid rgba(255,120,170,.28);
  border-radius: 18px; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,.5); }
.cupid-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px;
  border-bottom: 1px solid rgba(255,255,255,.08); }
.cupid-title { font-weight: 700; font-size: 18px; color: #ffd7e6; }
.cupid-body { padding: 16px; overflow-y: auto; }
.cupid-lead { color: #d7b8c8; text-align: center; margin: 2px 0 14px; }
.cupid-menu { display: flex; flex-direction: column; gap: 10px; }
.cupid-card-btn { display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 14px 16px; border-radius: 14px; border: 1px solid rgba(255,120,170,.25);
  background: rgba(255,120,170,.08); color: #fff; cursor: pointer; transition: transform .12s, background .12s; text-align: left; }
.cupid-card-btn:hover { transform: translateY(-2px); background: rgba(255,120,170,.16); }
.cupid-card-btn .cg-ic { font-size: 26px; }
.cupid-card-btn .cg-t { font-size: 17px; font-weight: 700; }
.cupid-card-btn .cg-s { font-size: 12px; color: #d7b8c8; }
.cg-back { background: none; border: 0; color: #d7b8c8; cursor: pointer; font-size: 14px; padding: 0 0 8px; }
.cg-tiers { display: flex; gap: 6px; margin-bottom: 12px; }
.cg-tier { flex: 1; padding: 8px 4px; border-radius: 10px; border: 1px solid rgba(255,255,255,.12);
  background: transparent; color: #d7b8c8; cursor: pointer; font-size: 13px; }
.cg-tier.on { background: #d6437f; border-color: #d6437f; color: #fff; }
.cg-card, .cg-dice { min-height: 128px; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; text-align: center; padding: 18px; border-radius: 14px; background: rgba(0,0,0,.25);
  border: 1px solid rgba(255,255,255,.08); margin-bottom: 14px; }
.cg-card.pop, .cg-dice.pop { animation: cgpop .25s ease; }
@keyframes cgpop { 0% { transform: scale(.94); opacity: .5; } 100% { transform: scale(1); opacity: 1; } }
.cg-card-label { font-size: 13px; letter-spacing: .06em; text-transform: uppercase; color: #ff9ec4; }
.cg-card-text { font-size: 18px; line-height: 1.4; color: #fff; }
.cg-hint { color: #9a8a95; }
.cg-actions { display: flex; gap: 10px; }
.cg-do { flex: 1; padding: 13px; border-radius: 12px; border: 0; cursor: pointer; font-size: 16px; font-weight: 600; color: #fff; }
.cg-do.truth { background: #5b6ee0; } .cg-do.dare { background: #d6437f; }
.cg-do.roll, .cg-do.next { background: #d6437f; }
.cg-pass { text-align: center; color: #9a8a95; font-size: 12px; margin: 12px 0 2px; }
.cg-dice-line { font-size: 20px; color: #fff; } .cg-dice-line b { color: #ff9ec4; }
.cg-wyr-q { text-align: center; color: #d7b8c8; margin: 6px 0 12px; }
.cg-wyr { display: flex; align-items: stretch; gap: 8px; }
.cg-opt { flex: 1; padding: 18px 12px; border-radius: 14px; border: 1px solid rgba(255,120,170,.3);
  background: rgba(255,120,170,.08); color: #fff; cursor: pointer; font-size: 15px; }
.cg-opt:hover { background: rgba(255,120,170,.18); }
.cg-or { align-self: center; color: #9a8a95; }
.cg-wyr-res { text-align: center; color: #d7b8c8; min-height: 24px; margin: 14px 0; }
.cg-match { color: #ff9ec4; font-weight: 700; margin-top: 4px; }

/* ---- Watch party (shared YouTube) ---- */
.wp-overlay {
  position: fixed; inset: 0; z-index: 9998; background: #000;
  display: flex; flex-direction: column;
}
.wp-overlay.hidden { display: none; }
.wp-bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 14px; background: var(--surface, #131a29); gap: 12px;
  border-bottom: 1px solid var(--line, #2a3550);
}
.wp-who { font-weight: 600; color: var(--text, #dfe6f5); }
.wp-holder { flex: 1; min-height: 0; background: #000; display: flex; }
.wp-holder iframe, .wp-holder video { width: 100%; height: 100%; border: 0; display: block; object-fit: contain; background: #000; }

/* ---- Watch/listen together ---- */
.together-btn {
  display: inline-block; margin-top: 6px; font-size: 12px; padding: 3px 10px;
  border-radius: 999px; border: 1px solid var(--line, #2a3550);
  background: transparent; color: var(--muted, #9aa7bd); cursor: pointer;
}
.together-btn:hover { color: var(--text, #dfe6f5); }
.together-btn.active { background: var(--accent, #6ea8fe); border-color: var(--accent, #6ea8fe); color: #fff; }

/* ---- Check-in alert banner ---- */
.checkin-alert {
  position: fixed; top: 0; left: 0; right: 0; z-index: 9999;
  background: var(--danger, #e5484d); color: #fff; text-align: center;
  padding: 12px 16px; font-weight: 600; cursor: pointer;
  box-shadow: 0 2px 12px rgba(0,0,0,.3);
}

/* ---- Invite link ---- */
.invite-out { margin-top: 10px; border-top: 1px solid var(--line, #2a3550); padding-top: 10px; }
.invite-out input { width: 100%; font-size: 12px; font-family: ui-monospace, Menlo, Consolas, monospace;
  padding: 6px 8px; border-radius: 8px; border: 1px solid var(--line, #2a3550);
  background: var(--surface, #131a29); color: var(--text, #dfe6f5); }

/* ---- Location share ---- */
.loc-card { display: flex; flex-direction: column; gap: 3px; padding: 8px 10px; border-radius: 10px;
  background: rgba(110,168,254,.10); border: 1px solid rgba(110,168,254,.25); min-width: 180px; }
.loc-pin { font-weight: 600; }
.loc-coords { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px; color: var(--muted, #9aa7bd); }
.loc-link { font-size: 13px; color: var(--accent, #6ea8fe); text-decoration: none; }
.loc-link:hover { text-decoration: underline; }

/* ---- Safety-number verification ---- */
.safety-grid {
  display: grid; grid-template-columns: repeat(8, 1fr); gap: 3px;
  width: 176px; height: 176px; margin: 14px auto; padding: 8px;
  border-radius: 12px; background: rgba(255,255,255,.04);
}
.safety-grid span { border-radius: 3px; }
.safety-number {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 20px; letter-spacing: 2px; text-align: center;
  word-spacing: 6px; margin: 8px 0 4px; color: var(--text, #dfe6f5);
}

/* ---- Incoming call ring ---- */
.incoming-modal { text-align: center; max-width: 340px; }
.incoming-avatar {
  width: 76px; height: 76px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 34px;
  margin: 0 auto 14px;
  background: radial-gradient(circle at 50% 35%, rgba(109, 94, 252, 0.4), rgba(109, 94, 252, 0.08));
  box-shadow: 0 0 0 1px rgba(109, 94, 252, 0.3);
  animation: ringPulse 1.4s infinite;
}
@keyframes ringPulse {
  0% { box-shadow: 0 0 0 0 rgba(109, 94, 252, 0.5); }
  70% { box-shadow: 0 0 0 18px rgba(109, 94, 252, 0); }
  100% { box-shadow: 0 0 0 0 rgba(109, 94, 252, 0); }
}
.incoming-from { color: var(--text-muted); }
.incoming-actions { justify-content: center; gap: 16px; margin-top: 18px; }
.incoming-actions button { min-width: 112px; }

/* ---- "edited" marker on a message ---- */
.edited-tag { font-style: italic; font-size: 9px; opacity: 0.75; }

/* ---- Ephemeral status (sidebar) ---- */
.status-post-btn {
  width: 100%;
  text-align: left;
  font-size: 12px;
  padding: 8px 10px;
  margin-bottom: 8px;
  border: 1px dashed var(--border-strong);
  background: transparent;
  color: var(--text-muted);
  border-radius: 10px;
}
.status-post-btn:hover { color: var(--text); }
body.app .status-post-btn:hover { background: rgba(255, 255, 255, 0.05); border-color: var(--accent); color: var(--text); }
.status-item {
  padding: 8px 10px;
  margin-bottom: 6px;
  border-radius: 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
}
body.app .status-item { background: rgba(255, 255, 255, 0.05); }
.status-who { font-size: 11px; font-weight: 600; font-family: var(--mono); color: var(--text-muted); }
.status-text { font-size: 13px; margin: 3px 0; word-wrap: break-word; white-space: pre-wrap; }
.status-meta { font-size: 10px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.status-empty { padding: 2px 2px 6px; }

/* =====================================================================
   Romantic chat-window backgrounds + the dropdown that picks them.
   ===================================================================== */

/* Animation layer sits behind the chat content. */
.chat-wrap { position: relative; }
.chat-anim {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  border-radius: inherit;
}
.chat-header, .chat-messages, .chat-input { position: relative; z-index: 1; }

/* Make the mic + romance buttons match the other square composer pills. */
.chat-input .mic,
.chat-input .romance {
  width: 40px; min-width: 40px;
  padding: 0; font-size: 18px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-muted);
}
.chat-input .mic:hover:not(:disabled),
.chat-input .romance:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }
body.app .chat-input .mic,
body.app .chat-input .romance {
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.05);
  color: var(--text-muted);
}
body.app .chat-input .mic:hover:not(:disabled),
body.app .chat-input .romance:hover:not(:disabled) {
  background: rgba(109, 94, 252, 0.2);
  border-color: rgba(109, 94, 252, 0.5);
  color: #fff;
}
/* Discreet terminal-style trigger (">_") — reads as a dev/display tool, not a
   personal-chat feature. */
.chat-input .romance {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -1px;
}
.chat-input .romance.on {
  color: #fff;
  background: rgba(109, 94, 252, 0.22);
  border-color: rgba(109, 94, 252, 0.5);
}

/* Dropdown of background animations (popover above the composer). */
.romance-menu {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 12px;
  width: 224px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.16);
  display: flex;
  flex-direction: column;
  gap: 2px;
  z-index: 30;
  /* Many options now — cap the height and scroll instead of overflowing past
     the top of the screen. */
  max-height: min(60vh, 440px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.romance-menu.hidden { display: none; }
body.app .romance-menu {
  background: rgba(20, 26, 38, 0.95);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.romance-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  flex-shrink: 0;          /* don't squash items when the list scrolls */
  padding: 8px 10px;
  border: none;
  background: transparent;
  color: var(--text);
  border-radius: 8px;
  text-align: left;
  font-size: 13px;
}
.romance-item:hover { background: var(--surface-2); }
body.app .romance-item:hover { background: rgba(109, 94, 252, 0.22); }
.romance-item.active { background: rgba(109, 94, 252, 0.18); font-weight: 600; }
.romance-glyph { font-size: 18px; }

/* ---- "Run to Hug" scene (inline SVG, fills the whole window) ---- */
.anim-hug .hug-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.svg-boy { animation: boyRun 7s ease-in-out infinite; }
.svg-boy-inner { transform-box: fill-box; transform-origin: center bottom; animation: boyBob 0.45s ease-in-out infinite; }
.svg-boy .leg-a { transform-box: fill-box; transform-origin: 50% 0%; animation: legA 0.45s ease-in-out infinite; }
.svg-boy .leg-b { transform-box: fill-box; transform-origin: 50% 0%; animation: legB 0.45s ease-in-out infinite; }
.svg-girl { transform-box: fill-box; transform-origin: center bottom; animation: girlHug 7s ease-in-out infinite; }
.svg-hearts { transform-box: fill-box; transform-origin: center; opacity: 0; animation: heartsBloom 7s ease-in-out infinite; }

@keyframes boyRun {
  0%   { transform: translateX(-360px); opacity: 0; }
  8%   { opacity: 1; }
  55%  { transform: translateX(470px); }    /* arrives at the girl */
  68%  { transform: translateX(482px); }    /* leans in for the hug */
  86%  { transform: translateX(482px); opacity: 1; }
  95%  { transform: translateX(482px); opacity: 0; }
  100% { transform: translateX(-360px); opacity: 0; }
}
@keyframes boyBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
@keyframes legA { 0%, 100% { transform: rotate(22deg); } 50% { transform: rotate(-24deg); } }
@keyframes legB { 0%, 100% { transform: rotate(-24deg); } 50% { transform: rotate(22deg); } }
@keyframes girlHug {
  0%, 52% { transform: scale(1) translateY(0); }
  60% { transform: scale(1.06) translateY(-6px); }   /* the hug */
  72% { transform: scale(1.02) translateY(0); }
  80%, 100% { transform: scale(1) translateY(0); }
}
@keyframes heartsBloom {
  0%, 55% { opacity: 0; transform: scale(0) translateY(0); }
  64% { opacity: 1; transform: scale(1.15) translateY(-8px); }
  74% { transform: scale(1) translateY(-22px); }
  88% { opacity: 0.85; transform: scale(1) translateY(-72px); }
  96% { opacity: 0; transform: scale(0.9) translateY(-110px); }
  100% { opacity: 0; }
}

/* Ambient life for the anime scene: a gently pulsing sun + drifting clouds. */
.anim-hug .sun { animation: sunPulse 6s ease-in-out infinite; }
@keyframes sunPulse { 0%, 100% { opacity: 0.82; } 50% { opacity: 1; } }
.anim-hug .cloud { animation: cloudDrift 28s linear infinite; }
.anim-hug .c2 { animation-duration: 36s; }
.anim-hug .c3 { animation-duration: 31s; animation-direction: reverse; }
@keyframes cloudDrift { 0% { transform: translateX(-46px); } 100% { transform: translateX(64px); } }

/* Rising 💋 / 💕 particles over the scene. */
.anim-hug .hug-fx {
  position: absolute;
  bottom: -6%;
  z-index: 2;
  opacity: 0;
  will-change: transform, opacity;
  filter: drop-shadow(0 2px 6px rgba(244, 80, 107, 0.4));
  animation: hugFxRise linear infinite;
}
@keyframes hugFxRise {
  0%   { opacity: 0; transform: translateY(0) scale(0.7) rotate(-8deg); }
  12%  { opacity: 0.95; }
  80%  { opacity: 0.9; }
  100% { opacity: 0; transform: translateY(-78vh) scale(1.05) rotate(8deg); }
}

/* Custom message ribbon that fades in around the embrace. */
.anim-hug .hug-message {
  position: absolute;
  left: 50%;
  top: 15%;
  transform: translateX(-50%);
  max-width: 82%;
  padding: 10px 18px;
  border-radius: 999px;
  background: rgba(20, 12, 28, 0.42);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: #fff;
  font-weight: 600;
  font-size: clamp(14px, 2.4vw, 20px);
  text-align: center;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  z-index: 3;
  opacity: 0;
  animation: hugMsg 7s ease-in-out infinite;
}
@keyframes hugMsg {
  0%, 40%   { opacity: 0; transform: translateX(-50%) translateY(10px); }
  58%       { opacity: 1; transform: translateX(-50%) translateY(0); }
  86%       { opacity: 1; }
  96%, 100% { opacity: 0; transform: translateX(-50%) translateY(-8px); }
}

/* Action picker inside the "Anime: Hug & Kiss" dialog. */
.hug-actions { display: flex; gap: 8px; margin: 4px 0 8px; flex-wrap: wrap; }
.hug-action-btn {
  flex: 1 1 auto;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
}
.hug-action-btn.active {
  border-color: #f25081;
  background: rgba(242, 80, 129, 0.12);
  color: #b8344a;
  font-weight: 600;
}

/* ---------- Admin user-management panel ---------- */
.admin-modal { width: min(96vw, 540px); }
/* ---- Activity log ---- */
.admin-logs-modal { width: min(98vw, 900px); }
.logs-presence { display: flex; gap: 8px; flex-wrap: wrap; margin: 6px 0 10px; }
.logs-pill { font-size: 12px; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--border); background: rgba(255,255,255,0.04); }
.logs-pill.on { border-color: rgba(52, 211, 153, 0.45); }
.logs-pill.away { border-color: rgba(217, 164, 65, 0.5); }
.logs-toolbar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-bottom: 8px; }
.logs-filter { width: auto; flex: 0 0 auto; }
.logs-toolbar .danger { margin-left: auto; }
.logs-tablewrap { max-height: 52vh; overflow: auto; border: 1px solid var(--border); border-radius: 10px; }
.logs-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.logs-table th, .logs-table td { text-align: left; padding: 7px 10px; white-space: nowrap; }
.logs-table thead th { position: sticky; top: 0; background: var(--surface); z-index: 1; border-bottom: 1px solid var(--border); font-weight: 600; }
.logs-table tbody tr:nth-child(even) { background: rgba(255,255,255,0.03); }
.logs-table td { border-bottom: 1px solid rgba(255,255,255,0.04); }
.logs-table td.muted { color: var(--text-muted); }
.admin-create { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 6px; }
.admin-create input { flex: 1 1 140px; width: auto; }
.admin-create .primary { flex: 0 0 auto; }
.admin-users { display: flex; flex-direction: column; gap: 8px; max-height: 46vh; overflow-y: auto; margin-top: 6px; }
.admin-row {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px;
  background: var(--surface-2);
}
body.app .admin-row { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.1); }
.admin-row-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.admin-name { flex: 1 1 auto; width: auto; font-weight: 600; }
.admin-badge {
  font-size: 11px; padding: 2px 7px; border-radius: 999px;
  background: rgba(31, 78, 216, 0.15); color: var(--accent); font-weight: 600;
}
body.app .admin-badge { background: rgba(109, 94, 252, 0.25); color: #c3b9ff; }
.admin-id { font-family: var(--mono); font-size: 11px; color: var(--text-faint); }
.admin-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.admin-actions .admin-pw { flex: 1 1 120px; width: auto; }
.admin-actions button { flex: 0 0 auto; }

/* ---- "Shatter & Reform" — letters fly together, shatter, fall, reassemble ---- */
.anim-shatter {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: 24px;
  /* default theme (rose); theme classes below override these vars */
  --sh-c1: #ffa6c4; --sh-c2: #f4506b; --sh-c3: #ff6f9c; --sh-glow: rgba(244, 80, 107, 0.45);
  background: radial-gradient(120% 90% at 50% 30%, color-mix(in srgb, var(--sh-c2) 18%, transparent), transparent 70%);
}
/* Color themes for the shatter text (set on the layer alongside .anim-shatter) */
.sh-theme-rose   { --sh-c1: #ffa6c4; --sh-c2: #f4506b; --sh-c3: #ff6f9c; --sh-glow: rgba(244, 80, 107, 0.45); }
.sh-theme-sunset { --sh-c1: #ffd17a; --sh-c2: #ff7e5f; --sh-c3: #ff5fa2; --sh-glow: rgba(255, 126, 95, 0.45); }
.sh-theme-ocean  { --sh-c1: #7ee8fa; --sh-c2: #5b8cff; --sh-c3: #6d5efc; --sh-glow: rgba(91, 140, 255, 0.45); }
.sh-theme-gold   { --sh-c1: #fff1b8; --sh-c2: #ffd166; --sh-c3: #f4a261; --sh-glow: rgba(244, 162, 97, 0.45); }
.sh-theme-violet { --sh-c1: #d8b4fe; --sh-c2: #a855f7; --sh-c3: #6d5efc; --sh-glow: rgba(168, 85, 247, 0.45); }
.sh-theme-mono   { --sh-c1: #ffffff; --sh-c2: #e5e7eb; --sh-c3: #cbd5e1; --sh-glow: rgba(255, 255, 255, 0.40); }

.shatter-heading {
  font-size: clamp(15px, 3.4vw, 26px);
  font-weight: 700; letter-spacing: 0.4px;
  color: #fff; opacity: 0.92;
  margin-bottom: 20px; text-align: center;
  text-shadow: 0 2px 16px rgba(0, 0, 0, 0.45);
}
.shatter-stage {
  position: relative;
  width: 92%; max-width: 760px; min-height: 130px;
  display: flex; align-items: center; justify-content: center;
}
.sh-line {
  display: flex; flex-wrap: wrap;
  align-items: center; justify-content: center;
  max-width: 100%;
}
/* The letter container: transparent sizer that handles the fly-in. */
.sh-l {
  position: relative; display: inline-block;
  font-size: clamp(26px, 7.5vw, 66px);
  font-weight: 800; line-height: 1.12;
  color: transparent;
  will-change: transform, opacity;
  opacity: 0;
  transform: translate(var(--ax, 0), -54px) rotate(var(--arot, 0)) scale(0.3);
  transition: transform 0.7s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.5s ease;
  transition-delay: var(--d, 0s);
}
.sh-l.sp { width: 0.36em; }
.sh-line.assembled .sh-l { opacity: 1; transform: translate(0, 0) rotate(0) scale(1); }
/* The two clipped halves of each letter (themed gradient text). */
.sh-half {
  position: absolute; left: 0; top: 0; width: 100%;
  background: linear-gradient(135deg, var(--sh-c1), var(--sh-c2) 55%, var(--sh-c3));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 3px 14px var(--sh-glow));
  will-change: transform, opacity;
}
.sh-half.top { clip-path: inset(0 0 calc(50% - 0.5px) 0); }
.sh-half.bot { clip-path: inset(calc(50% - 0.5px) 0 0 0); }
.sh-line.shattered .sh-half {
  opacity: 0;
  transition: transform 1.05s cubic-bezier(0.45, 0, 0.7, 1), opacity 0.9s ease;
  transition-delay: var(--sd, 0s);
}
.sh-line.shattered .sh-half.top { transform: translate(var(--tdx, 0), var(--tdy, 150px)) rotate(var(--trot, 0)); }
.sh-line.shattered .sh-half.bot { transform: translate(var(--bdx, 0), var(--bdy, 170px)) rotate(var(--brot, 0)); }

/* Theme picker swatches in the dialog */
.sh-theme-picker { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 8px; }
.sh-theme-btn {
  flex: 1 1 auto; padding: 8px 10px; border-radius: 10px;
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text); font-size: 12px;
}
.sh-theme-btn.active { border-color: #6d5efc; box-shadow: 0 0 0 2px rgba(109, 94, 252, 0.3); font-weight: 600; }

.sh-shard {
  position: absolute; left: 50%; top: 50%;
  pointer-events: none;
  animation: shShard 1.4s ease-out forwards;
  filter: drop-shadow(0 2px 6px rgba(244, 80, 107, 0.4));
}
@keyframes shShard {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.4) rotate(0); }
  15%  { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(-50% + var(--sx, 0)), calc(-50% + var(--sy, 120px))) scale(1) rotate(var(--sr, 0)); }
}

/* ---- Custom background (user text / image) ---- */
.custom-bg {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  animation: kenBurns 20s ease-in-out infinite alternate;
}
@keyframes kenBurns {
  0% { transform: scale(1) translate(0, 0); }
  100% { transform: scale(1.15) translate(-2%, -2%); }
}
.custom-dim { position: absolute; inset: 0; background: rgba(8, 11, 18, 0.42); }
.bg-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border: 0;
}
/* Floating sound controls for a <video> background (above the messages). */
.bg-vid-controls {
  position: absolute;
  top: 62px;
  right: 14px;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 8px;
  background: rgba(20, 26, 38, 0.82);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
}
.bg-vid-controls.hidden { display: none; }
.bg-vid-controls .bg-vid-mute {
  width: 30px; height: 30px; min-width: 30px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: #fff;
  font-size: 15px;
  line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.bg-vid-controls .bg-vid-mute:hover { background: rgba(255, 255, 255, 0.14); }
.bg-vid-controls .bg-vid-vol {
  width: 88px;
  accent-color: var(--accent, #6d5efc);
  cursor: pointer;
}
/* Shown when a linked video (e.g. YouTube) can't be embedded. */
.bg-vid-fallback {
  position: absolute;
  left: 50%;
  top: 46%;
  transform: translate(-50%, -50%);
  z-index: 6;
  width: min(86%, 360px);
  text-align: center;
  padding: 20px 22px;
  background: rgba(20, 26, 38, 0.92);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 14px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
}
.bg-vid-fallback .bgf-title { font-weight: 700; font-size: 15px; color: #fff; }
.bg-vid-fallback .bgf-sub { margin-top: 6px; font-size: 12.5px; color: var(--text-muted); line-height: 1.45; }
.bg-vid-fallback .bgf-link {
  display: inline-block;
  margin-top: 12px;
  padding: 7px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  text-decoration: none;
  background: rgba(109, 94, 252, 0.25);
  border: 1px solid rgba(109, 94, 252, 0.55);
}
.bg-vid-fallback .bgf-link:hover { background: rgba(109, 94, 252, 0.4); }
.or-sep { text-align: center; color: var(--text-faint); font-size: 12px; margin: 12px 0 4px; letter-spacing: 1px; }

/* Instagram embed cropped so the media fills the background and the post chrome
   (header avatar, caption, like/comment bar) is clipped out of view. */
.bg-ig-wrap { position: absolute; inset: 0; overflow: hidden; background: #000; }
.bg-ig {
  position: absolute;
  left: 50%;
  top: -64px;                 /* push the header out the top */
  width: 540px;
  max-width: 150%;
  height: 1500px;             /* tall enough that the media region fills; footer clips */
  transform: translateX(-50%);
  border: 0;
  pointer-events: none;       /* decorative — clicks pass through to the chat */
}
.anim-custom .ctext {
  position: absolute; bottom: -8%;
  line-height: 1; font-weight: 700; color: #fff; white-space: nowrap;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.55);
  animation-name: heartFloat; animation-iteration-count: infinite; animation-timing-function: ease-in;
}
.anim-custom .ctext-big {
  position: absolute; left: 50%; top: 42%;
  transform: translate(-50%, -50%);
  font-size: clamp(28px, 6vw, 52px); font-weight: 800; color: #fff;
  text-align: center; max-width: 90%;
  text-shadow: 0 4px 18px rgba(0, 0, 0, 0.6);
  animation: ctextPulse 3s ease-in-out infinite;
}
@keyframes ctextPulse {
  0%, 100% { opacity: 0.82; transform: translate(-50%, -50%) scale(1); }
  50% { opacity: 1; transform: translate(-50%, -50%) scale(1.06); }
}

/* ---- Ambient floating hearts / falling petals / sparkles ---- */
.anim-hearts .heart,
.anim-petals .petal {
  position: absolute;
  line-height: 1;
  will-change: transform, opacity;
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.25));
}
.anim-hearts .heart {
  bottom: -8%;
  animation-name: heartFloat;
  animation-iteration-count: infinite;
  animation-timing-function: ease-in;
}
@keyframes heartFloat {
  0%   { transform: translateY(0) translateX(0) scale(0.7); opacity: 0; }
  12%  { opacity: 0.95; }
  50%  { transform: translateY(-200px) translateX(16px) scale(1); }
  85%  { opacity: 0.8; }
  100% { transform: translateY(-440px) translateX(-12px) scale(1.05); opacity: 0; }
}
.anim-petals .petal {
  top: -8%;
  animation-name: petalFall;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}
@keyframes petalFall {
  0%   { transform: translateY(0) translateX(0) rotate(0deg); opacity: 0; }
  12%  { opacity: 0.95; }
  100% { transform: translateY(460px) translateX(30px) rotate(360deg); opacity: 0; }
}
.anim-sparkles .spark {
  position: absolute;
  line-height: 1;
  opacity: 0;
  animation-name: sparkTwinkle;
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
}
@keyframes sparkTwinkle {
  0%, 100% { opacity: 0; transform: scale(0.4); }
  50% { opacity: 1; transform: scale(1.1); }
}

/* ---- Extra cute backgrounds: love letters, teddies, kitties, balloons, stars ---- */
.p {
  position: absolute;
  line-height: 1;
  will-change: transform, opacity;
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.25));
}
/* drift up with a wide sway + gentle tilt */
.p-sway {
  bottom: -8%;
  animation-name: pSway;
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
}
@keyframes pSway {
  0%   { transform: translateY(0) translateX(0) rotate(-8deg); opacity: 0; }
  12%  { opacity: 0.95; }
  50%  { transform: translateY(-230px) translateX(30px) rotate(8deg); }
  85%  { opacity: 0.85; }
  100% { transform: translateY(-470px) translateX(-18px) rotate(-6deg); opacity: 0; }
}
/* sit scattered and gently bob + wiggle in place */
.p-bob {
  animation-name: pBob;
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
}
@keyframes pBob {
  0%, 100% { transform: translateY(0) rotate(-6deg); opacity: 0.9; }
  50% { transform: translateY(-12px) rotate(6deg); opacity: 1; }
}
/* fade + scale in place */
.p-twinkle {
  opacity: 0;
  animation-name: pTwinkle;
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
}
@keyframes pTwinkle {
  0%, 100% { opacity: 0; transform: scale(0.4); }
  50% { opacity: 1; transform: scale(1.12); }
}

/* ---- Clickable love letters + the note card ---- */
.chat-anim.letters-interactive { z-index: 4; }   /* lift above messages so taps land */
.anim-letters .letter-note.clickable { pointer-events: auto; cursor: pointer; }
.anim-letters .letter-note.clickable:hover {
  filter: drop-shadow(0 0 9px rgba(255, 210, 230, 0.95)) drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
}
.letter-card-bg {
  position: fixed; inset: 0;
  z-index: 160;
  display: flex; align-items: center; justify-content: center;
  background: rgba(4, 6, 12, 0.5);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
.letter-card-bg.hidden { display: none; }
.letter-card {
  position: relative;
  width: min(92vw, 420px);
  padding: 24px 22px 20px;
  text-align: center;
  color: #5a2330;
  background: linear-gradient(160deg, #fff6fa, #ffe6ef);
  border: 1px solid rgba(244, 80, 107, 0.3);
  border-radius: 16px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
  animation: letterCardIn 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes letterCardIn {
  from { opacity: 0; transform: translateY(10px) scale(0.96); }
  to { opacity: 1; transform: none; }
}
.letter-card .lc-head { font-weight: 800; color: #e0407a; font-size: 14px; letter-spacing: 0.3px; margin-bottom: 12px; }
.letter-card .lc-text {
  font-size: 18px; line-height: 1.5; font-weight: 600;
  white-space: pre-wrap; word-wrap: break-word; min-height: 46px;
}
.letter-card .lc-foot { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 18px; }
.letter-card .lc-count { font-size: 12px; color: #b0476a; opacity: 0.85; font-variant-numeric: tabular-nums; }
.letter-card .lc-btn {
  border: 1px solid rgba(224, 64, 122, 0.45);
  background: #fff;
  color: #e0407a;
  border-radius: 999px;
  padding: 6px 14px;
  font-weight: 600;
}
.letter-card .lc-btn:hover { background: #ffe6ef; color: #e0407a; }
.letter-card .lc-close {
  position: absolute; top: 8px; right: 10px;
  border: none; background: transparent; color: #b0476a;
  font-size: 18px; padding: 4px 8px; line-height: 1;
}
.letter-card .lc-close:hover { background: transparent; color: #e0407a; }

/* Personalized name + message floating in the Heart Balloons scene */
.balloon-greeting {
  position: absolute;
  left: 50%; top: 40%;
  transform: translate(-50%, -50%);
  text-align: center;
  max-width: 88%;
  pointer-events: none;
  animation: balloonFloat 4s ease-in-out infinite;
}
.balloon-name {
  font-size: clamp(26px, 6vw, 52px);
  font-weight: 800;
  color: #fff;
  letter-spacing: 0.5px;
  text-shadow: 0 4px 18px rgba(244, 80, 107, 0.6), 0 2px 6px rgba(0, 0, 0, 0.45);
}
.balloon-msg {
  margin-top: 8px;
  font-size: clamp(14px, 2.6vw, 22px);
  font-weight: 600;
  color: #ffe3ec;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.55);
}
@keyframes balloonFloat {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50% { transform: translate(-50%, calc(-50% - 8px)) scale(1.03); }
}

/* ---- "Balloon Message": CSS balloons carrying the name + message ---- */
.note-balloon {
  position: absolute;
  bottom: -180px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 12px 16px;
  color: #fff;
  border-radius: 50% 50% 50% 50% / 46% 46% 54% 54%;
  box-shadow: inset -8px -12px 22px rgba(0, 0, 0, 0.14), 0 12px 26px rgba(0, 0, 0, 0.3);
  animation-name: balloonRise;
  animation-iteration-count: infinite;
  animation-timing-function: ease-in;
  will-change: transform, opacity;
}
/* string + knot */
.note-balloon::before {
  content: "";
  position: absolute;
  top: 100%; left: 50%;
  width: 1px; height: 64px;
  background: rgba(255, 255, 255, 0.55);
  transform: translateX(-50%);
}
.note-balloon::after {
  content: "";
  position: absolute;
  top: calc(100% - 2px); left: 50%;
  transform: translateX(-50%);
  border-left: 7px solid transparent;
  border-right: 7px solid transparent;
  border-top: 11px solid currentColor;
  opacity: 0.85;
}
.note-balloon .nb-text { max-height: 100%; overflow: hidden; }
.note-balloon .nb-name { font-weight: 800; font-size: clamp(15px, 1.6vw, 20px); line-height: 1.1; }
.note-balloon .nb-msg {
  margin-top: 4px;
  font-weight: 600;
  font-size: clamp(11px, 1.2vw, 13px);
  line-height: 1.15;
  opacity: 0.95;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* colour variants */
.note-balloon.nb-0 { color: #f4506b; background: radial-gradient(circle at 32% 26%, rgba(255,255,255,0.55), rgba(255,255,255,0) 42%), linear-gradient(160deg, #ff8fb6, #f4506b); }
.note-balloon.nb-1 { color: #7c5cff; background: radial-gradient(circle at 32% 26%, rgba(255,255,255,0.5), rgba(255,255,255,0) 42%), linear-gradient(160deg, #b9a7ff, #6d5efc); }
.note-balloon.nb-2 { color: #e0407a; background: radial-gradient(circle at 32% 26%, rgba(255,255,255,0.5), rgba(255,255,255,0) 42%), linear-gradient(160deg, #ff9ec4, #e0407a); }
.note-balloon.nb-3 { color: #3aa0ff; background: radial-gradient(circle at 32% 26%, rgba(255,255,255,0.5), rgba(255,255,255,0) 42%), linear-gradient(160deg, #8fd0ff, #3aa0ff); }
@keyframes balloonRise {
  0%   { transform: translateY(0) rotate(-3deg); opacity: 0; }
  10%  { opacity: 1; }
  50%  { transform: translateY(-360px) rotate(3deg); }
  90%  { opacity: 0.9; }
  100% { transform: translateY(-720px) rotate(-2deg); opacity: 0; }
}

/* Respect users who prefer less motion */
@media (prefers-reduced-motion: reduce) {
  body.app .msg { animation: none; }
  body.app .presence-dot.online { animation: none; }
  body.app .peer-item, body.app button { transition: none; }
  .typing-dots i, .rec-dot, .incoming-avatar { animation: none; }
  .svg-boy-inner, .svg-boy .leg-a, .svg-boy .leg-b, .svg-girl,
  .anim-hearts .heart, .anim-petals .petal, .anim-sparkles .spark,
  .anim-custom .ctext, .anim-custom .ctext-big, .custom-bg { animation: none; }
  .svg-boy { animation: none; transform: translateX(470px); }   /* show them together, static */
  .svg-hearts { animation: none; opacity: 0.9; }
  .anim-hug .sun, .anim-hug .cloud, .anim-hug .hug-fx { animation: none; }
  .anim-hug .hug-fx { opacity: 0.8; }
  .anim-hug .hug-message { animation: none; opacity: 1; }   /* keep the message visible, static */
  /* Shatter: show each message statically (it still cycles, just without motion). */
  .sh-l { transition: none !important; opacity: 1 !important; transform: none !important; }
  .sh-half { transition: none !important; transform: none !important; opacity: 1 !important; }
  .sh-shard { display: none; }
  .anim-sparkles .spark { opacity: 0.8; }
  .p { animation: none; }
  .p-bob, .p-twinkle { opacity: 0.85; }   /* keep them visible, just still */
  .balloon-greeting { animation: none; }
  .note-balloon { animation: none; bottom: 14%; opacity: 0.92; }
}

/* ---------- Crypto-ready / delivery state ---------- */
/* "Blocked" tick: recipient got it but can't read it (no shared passphrase). */
.msg.mine .meta .ticks.tick-blocked { color: #ffcf66; }
.msg .meta .ticks.tick-blocked { color: var(--danger); }

/* Recipient-side banner: messages arrived but no passphrase to read them. */
.crypto-banner {
  margin: 8px 16px 0;
  padding: 10px 14px;
  border-radius: 10px;
  background: var(--danger-soft);
  color: var(--danger);
  border: 1px solid rgba(180, 35, 24, 0.25);
  font-size: 13px;
  font-weight: 600;
}
.crypto-banner.hidden { display: none; }

/* Sender-side warning inside a chat: the selected peer has no passphrase. */
.peer-ready-warn {
  margin: 6px 0 0;
  padding: 8px 12px;
  border-radius: 8px;
  background: #fff6e6;
  color: #8a5a00;
  border: 1px solid #f0d28a;
  font-size: 12.5px;
}
.peer-ready-warn.hidden { display: none; }

/* Discreet duress marker for a contact. Deliberately low-key. */
.presence-dot.alert { background: #d98a00; }
.peer-alert {
  position: fixed;
  bottom: 12px;
  right: 14px;
  z-index: 9000;
  padding: 6px 10px;
  border-radius: 8px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
  font-size: 12px;
  opacity: 0.92;
}
.peer-alert.hidden { display: none; }

/* ---------- Read-PIN lock screen ---------- */
.lock-overlay {
  position: fixed;
  inset: 0;
  z-index: 9990;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
}
.lock-overlay.hidden { display: none; }
.lock-card {
  width: min(92vw, 340px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 28px 24px;
  text-align: center;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
}
.lock-card .logo {
  width: 44px; height: 44px; margin: 0 auto 12px;
  border-radius: 12px; background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center; font-weight: 800;
}
.lock-card h2 { margin: 0 0 4px; }
.lock-card input {
  width: 100%; margin: 14px 0 6px; padding: 12px;
  text-align: center; font-size: 20px; letter-spacing: 6px;
  border: 1px solid var(--border-strong); border-radius: 10px;
}
.lock-card .error { min-height: 16px; margin: 2px 0 10px; color: var(--danger); font-size: 13px; }
.lock-card button { width: 100%; }
.lock-hint { margin-top: 16px; font-size: 11px; line-height: 1.5; }

/* ---------- Duress cover: fake server console ---------- */
.duress-screen {
  position: fixed;
  inset: 0;
  z-index: 10000;          /* above everything, including the boss screen */
  background: #0a0e12;
  overflow: hidden;
  padding: 14px 16px;
}
.duress-screen.hidden { display: none; }
.duress-term {
  display: flex;
  flex-direction: column;
  width: 100%; height: 100%;
}
.duress-log {
  margin: 0;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  overflow-y: auto;
  color: #9ef0b0;
  background: transparent;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 12.5px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
}
/* Live command line — looks and behaves like a real shell prompt. */
.duress-cmdline {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  padding-top: 2px;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 12.5px;
}
.duress-ps1 { color: #7fd1a0; white-space: nowrap; }
.duress-input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  color: #9ef0b0;
  caret-color: #9ef0b0;
  font-family: inherit;
  font-size: inherit;
  padding: 0;
}

/* The header menu button only appears on mobile (see media query below). */
.more-btn { display: none; }

/* ---------- Mobile / responsive — a native-app feel (phones & small tablets) ----------
   Desktop is a sidebar + panel with a packed toolbar. On phones we turn it into
   a clean app shell: a slim glass header with an actions sheet (☰), a bottom tab
   bar with icons, a swipeable contact-avatar rail, and a polished chat + call. */
@media (max-width: 768px) {
  html, body { overflow-x: hidden; max-width: 100%; }
  :root { --nav-h: 60px; }

  body.app {
    grid-template-rows: auto 1fr;
    min-height: 100svh;            /* dynamic viewport height (mobile chrome aware) */
    background: radial-gradient(120% 80% at 50% -10%, #1a2440 0%, var(--bg) 55%);
  }

  /* ---- Slim header: logo (left) + ☰ menu (right) ----
     NOTE: no backdrop-filter here. A filtered ancestor becomes the containing
     block for position:fixed descendants, which would trap the bottom nav inside
     the header. A solid translucent background gives the same look safely. */
  body.app .topbar {
    position: sticky; top: 0; z-index: 40;
    display: flex; align-items: center; gap: 10px;
    padding: 10px 14px;
    padding-top: calc(10px + env(safe-area-inset-top));
    background: rgba(14, 19, 30, 0.97);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  }
  body.app .topbar .brand > span { display: none; }
  body.app .topbar .brand .logo { width: 34px; height: 34px; font-size: 13px; }
  body.app .more-btn {
    display: inline-flex; align-items: center; justify-content: center;
    margin-left: 8px;            /* sits just right of the always-on emergency buttons */
    width: 42px; height: 42px; border-radius: 13px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    background: rgba(255, 255, 255, 0.06);
    color: #fff; font-size: 19px;
  }

  /* SOS + Wipe stay visible in the header (pushed to the right, before ☰). */
  body.app .topbar-urgent { margin-left: auto; gap: 8px; }
  body.app .topbar-urgent .danger {
    padding: 9px 12px; font-size: 13px; font-weight: 700; border-radius: 12px; white-space: nowrap;
  }
  body.app .topbar-urgent .sos-btn { padding: 9px 11px; }

  /* ---- Actions sheet (the old toolbar, revealed by ☰) ---- */
  body.app .topbar .right {
    position: absolute; top: calc(100% + 6px); right: 10px;
    width: min(80vw, 290px); margin: 0;
    flex-direction: column; align-items: stretch; gap: 3px;
    padding: 8px;
    background: rgba(20, 26, 38, 0.98);
    -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 16px;
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
    opacity: 0; transform: translateY(-8px) scale(0.98); pointer-events: none;
    transition: opacity 160ms ease, transform 160ms ease;
  }
  body.app .topbar.menu-open .right { opacity: 1; transform: none; pointer-events: auto; }
  body.app .topbar .right > * {
    width: 100%; justify-content: flex-start; text-align: left;
    padding: 12px 12px; font-size: 14px; border-radius: 10px;
  }
  body.app .topbar .right .user-badge {
    background: transparent; color: var(--text-faint); font-size: 12px;
    pointer-events: none; margin-bottom: 2px;
  }

  /* ---- Bottom tab bar (Messages / Call) with icons ---- */
  body.app .topbar nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; margin: 0;
    display: flex;
    height: calc(var(--nav-h) + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: rgba(16, 21, 32, 0.94);
    -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
  }
  body.app .topbar nav .tab {
    position: relative; flex: 1 1 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    border-radius: 0; background: transparent;
    font-size: 11px; font-weight: 600; color: var(--text-faint);
  }
  body.app .topbar nav .tab::before { font-size: 21px; line-height: 1; }
  body.app .topbar nav .tab[data-tab="chat"]::before { content: "💬"; }
  body.app .topbar nav .tab[data-tab="call"]::before { content: "📞"; }
  body.app .topbar nav .tab.active { color: #fff; }
  body.app .topbar nav .tab.active::after {
    content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
    width: 30px; height: 3px; border-radius: 0 0 3px 3px; background: #6d5efc;
  }
  body.app .topbar nav .tab { -webkit-tap-highlight-color: transparent; }
  body.app .topbar nav .tab:focus { outline: none; }   /* active underline is the indicator */

  /* ---- Single column; leave room for the bottom tab bar ---- */
  main.work {
    grid-template-columns: 1fr; grid-template-rows: auto 1fr;
    padding-bottom: calc(var(--nav-h) + env(safe-area-inset-bottom));
  }

  /* ---- Contacts: a swipeable avatar rail (hide secondary sidebar sections) ---- */
  body.app aside.sidebar {
    border: none; border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    padding: 12px; max-height: none; overflow: visible;
  }
  body.app aside.sidebar h3,
  body.app #statusBtn, body.app #statusList,
  body.app #sessionInfo, body.app #fpInfo { display: none; }
  body.app #peerList {
    display: flex; gap: 16px; padding: 4px 4px 6px 8px;   /* left pad so the selected ring isn't clipped */
    overflow-x: auto; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  body.app #peerList::-webkit-scrollbar { display: none; }
  body.app .peer-item {
    flex: 0 0 auto; width: auto; flex-direction: column; gap: 6px;
    padding: 2px; margin: 0; background: transparent;
  }
  body.app .peer-item .peer-avatar { width: 56px; height: 56px; font-size: 21px; }
  body.app .peer-item .peer-name {
    flex: none; max-width: 66px; font-size: 11px; text-align: center;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  body.app .peer-item .presence-dot { display: none; }
  body.app .peer-item.selected { background: transparent; }
  body.app .peer-item.selected .peer-avatar {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18), 0 0 0 3px #6d5efc;
  }
  body.app .peer-item.selected .peer-name { color: #fff; font-weight: 700; }

  /* ---- Chat ---- */
  body.app section.panel { min-width: 0; padding: 0; }
  body.app .chat-header {
    flex-wrap: nowrap; gap: 8px; padding: 12px 14px; align-items: center;
  }
  body.app .chat-header > span:first-child { display: none; }   /* "Chat with" label */
  /* The contact name TRUNCATES so it can't push the timer button off-screen;
     the lock / fingerprint / ⏱ timer never shrink, so the timer is always tappable. */
  body.app .chat-header .who {
    font-size: 16px; font-weight: 700;
    flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  body.app .chat-header .lock { font-size: 11px; }
  body.app .chat-header .lock,
  body.app .chat-header .chat-fp,
  body.app .chat-header .ttl-btn { flex-shrink: 0; }
  body.app .chat-messages { padding: 12px 12px 16px; }
  body.app .msg { max-width: 86%; }
  body.app .msg-text { overflow-wrap: anywhere; word-break: break-word; }

  /* ---- Composer: pill input, round icon buttons, circular accent send ---- */
  body.app .chat-input { flex-wrap: wrap; gap: 8px; padding: 8px 12px 12px; align-items: center; }
  body.app .chat-input textarea {
    flex: 1 1 100%; order: -1; min-width: 0;
    height: 46px; padding: 12px 16px; border-radius: 20px;
  }
  body.app .chat-input .attach,
  body.app .chat-input .camera,
  body.app .chat-input .romance,
  body.app .chat-input .mic,
  body.app .chat-input .emoji {
    width: 42px; height: 42px; border-radius: 50%;
  }
  body.app #chatSend {
    margin-left: auto; flex: 0 0 auto;
    width: 46px; height: 46px; border-radius: 50%; padding: 0; font-size: 0;
  }
  body.app #chatSend::before { content: "➤"; font-size: 17px; }

  /* A backdrop-filter on the chat area makes it the containing block for the
     position:fixed background-options sheet below — which would trap the sheet
     inside the chat area so its top hides behind the contacts rail and the first
     option can't be tapped. Drop the filter on phones; a more opaque solid
     background keeps text legible without the blur. */
  body.app .chat-wrap {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: rgba(17, 23, 34, 0.92);
  }

  /* ---- Background-options menu: a scrollable bottom sheet (so every option,
     including the ones at the top of the list, is reachable on a phone) ---- */
  body.app .romance-menu {
    /* .chat-input (this menu's offset parent) is a z-index:1 stacking context
       that sits below the top bar / bottom nav, so the sheet can't reliably
       paint OVER the tab bar. Instead, seat it ABOVE the tab bar and cap its
       height with svh so its top also clears the header + contacts rail — then
       every option sits in clear space and is reachable. (svh, not vh: vh is the
       LARGE viewport and would push the top off-screen when the URL bar shows.) */
    position: fixed; left: 0; right: 0; top: auto;
    bottom: calc(var(--nav-h) + env(safe-area-inset-bottom));
    width: 100%; margin: 0;
    max-height: 60vh;            /* fallback for browsers without svh */
    max-height: calc(100svh - var(--nav-h) - env(safe-area-inset-bottom) - env(safe-area-inset-top) - 150px);
    border-radius: 18px 18px 0 0;
    padding: 10px 12px 12px;
    z-index: 60;
    overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
    box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.5);
  }
  body.app .romance-item { padding: 13px 12px; font-size: 14px; }

  /* ---- Call ---- */
  body.app .call-stage { padding: 0; }
  body.app .video-area { max-height: 56vh; border-radius: 16px; }
  body.app .call-card { padding: 16px; }
  body.app .call-controls { width: 100%; gap: 8px; }
  body.app .call-controls button { flex: 1 1 42%; padding: 13px; border-radius: 12px; }
}
