/* room · 多人房间（文字 + 按住说话 + 实时语音）
 * TUI 主题，与 tools 站其他页面同源。
 * 布局：上聊天区（滚动），下输入区固定；右侧（宽屏）成员栏。
 */
:root {
  --bg: #0d1117;
  --panel: #000000;
  --panel-alt: #11161d;
  --panel-head: #11161d;
  --ink: #7fe0a8;
  --ink-soft: #4e9f74;
  --line: #2f6b4d;
  --accent: #ffd24a;
  --accent-soft: #d9ae2e;
  --link: #78ffaa;
  --danger: #ff5555;
  --ok: #78ffaa;
  --radius: 0px;
  --font-mono: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono",
    "Noto Sans Mono CJK SC", "Noto Sans CJK SC", "Noto Sans SC",
    "PingFang SC", "Microsoft YaHei", monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; overflow: hidden; }
body {
  min-height: 100dvh;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 14px;
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
  display: flex;
  flex-direction: column;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}

/* ---------- 顶栏 ---------- */
.topbar {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .6rem 1rem;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
  position: sticky;
  top: 0;
  z-index: 10;
}
.topbar .room-name {
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;              /* 连接状态已移到输入区，房间名可占满剩余宽度 */
  min-width: 0;
}
/* 顶栏按钮组：窄屏放不下时允许换行（room-name/sub 会截断让位） */
.topbar .btns { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .3rem; }
.btn {
  font: inherit;
  background: var(--panel-alt);
  color: var(--ink);
  border: 1px solid var(--line);
  padding: .25rem .6rem;
  cursor: pointer;
  border-radius: var(--radius);
  white-space: nowrap;
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn.on { border-color: var(--ok); color: var(--ok); }
.btn.rec { border-color: var(--danger); color: var(--danger); }

/* ---------- 大厅（加入前） ---------- */
/* 三个面板的可见性只靠 .hidden 类控制。
 * - 启动无 token:   gate 默认显示（HTML 初始无 hidden），lobby/app 都 hidden
 * - 有 site token:  gate hidden，lobby 默认显示
 * - 进房后:         gate/lobby 都 hidden，app 默认显示
 * 任何时刻保证只有一个面板可见（不会有「两个同现」）。
 * HTML 初始 gate 不带 hidden：即使 JS 未运行也显示——渐进增强。
 */
.lobby, .gate {
  max-width: 30rem;
  width: 100%;
  margin: auto;
  padding: 1rem;
}
/* .hidden 放最后：同优先级时靠 source order 胜出。靠「原 panel 主动加 hidden、
 * 目标 panel 主动 remove hidden」的 JS 规则保证一次只一个可见。
 * 不加 !important，避免「add('show')」与「add('hidden')」同时留造成页白屏。
 */
.lobby.hidden, .app.hidden, .gate.hidden { display: none; }
.lobby .panel, .gate .panel {
  border: 1px solid var(--line);
  background: var(--panel);
  padding: 1.2rem;
}
.lobby h1, .gate h1 { font-size: 1.1rem; margin: 0 0 .4rem; }
.lobby .desc, .gate .desc { color: var(--ink-soft); font-size: 12px; margin: 0 0 1rem; }
.field { margin-bottom: .9rem; }
.field label { display: block; font-size: 12px; color: var(--ink-soft); margin-bottom: .25rem; }
.field input {
  width: 100%;
  font: inherit;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--line);
  padding: .45rem .6rem;
  border-radius: var(--radius);
}
.field input:focus { outline: none; border-color: var(--accent); }
.btn-primary {
  width: 100%;
  font: inherit;
  font-weight: 700;
  background: var(--accent);
  color: #000000;
  border: none;
  padding: .6rem;
  cursor: pointer;
  border-radius: var(--radius);
}
.btn-primary:disabled { opacity: .5; cursor: not-allowed; }
.btn-logout {
  flex: 1;
  font-size: 12px;
  color: var(--ink-soft);
  background: transparent;
  border: 1px dashed var(--line);
  padding: .4rem;
}
.btn-logout:hover { color: var(--danger); border-color: var(--danger); }
/* 大厅底部工具排：Nat 检测 / 注销 */
.lobby-tools { display: flex; gap: .5rem; margin-top: .6rem; }
.btn-nat {
  flex: 1;
  font-size: 12px;
  border: 1px solid var(--line);
  background: var(--panel-alt);
  color: var(--ink);
  padding: .4rem;
  cursor: pointer;
}
.btn-nat:hover { border-color: var(--accent); color: var(--accent); }
.btn-nat:disabled { opacity: .45; cursor: wait; }
.btn-nat.off { color: var(--danger); border-color: var(--danger); }

/* ---------- 聊天主区 ---------- */
.chat-wrap {
  flex: 1;
  display: flex;
  min-height: 0;
}
.chat-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
.msgs {
  flex: 1;
  overflow-y: auto;
  padding: .8rem 1rem;
  display: flex;
  flex-direction: column;
  gap: .55rem;
  overscroll-behavior: contain;
}
.msg { max-width: 92%; word-break: break-word; }
.msg .meta { font-size: 11px; color: var(--ink-soft); }
.msg .meta .nick { color: var(--accent); font-weight: 700; }
.msg .meta .t { margin-left: .5rem; }
.msg.sys {
  align-self: center;
  color: var(--ink-soft);
  font-size: 12px;
}
.msg .bubble {
  background: var(--panel);
  border: 1px solid var(--line);
  padding: .35rem .6rem;
  margin-top: .15rem;
}
.msg.mine { align-self: flex-end; }
.msg.mine .bubble { background: var(--panel-alt); border-color: var(--accent-soft); }
.msg.mine .meta { text-align: right; }

/* 语音条 */
.voice {
  display: flex;
  align-items: center;
  gap: .5rem;
  cursor: pointer;
  user-select: none;
}
.voice .play {
  width: 26px; height: 26px;
  border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  flex: none;
  background: var(--bg);
}
.voice .play .tri {
  width: 0; height: 0;
  border-left: 9px solid var(--ink-soft);
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  margin-left: 3px;
}
/* 播放中：▶ 换成两根跳动的竖杠 */
.voice .play .bars { display: none; align-items: center; gap: 3px; }
.voice .play .bars b {
  width: 3px; height: 11px;
  background: var(--accent);
  animation: barHop .8s ease-in-out infinite;
}
.voice .play .bars b:nth-child(2) { animation-delay: .2s; }
.voice.playing .play { border-color: var(--accent); }
.voice.playing .play .tri { display: none; }
.voice.playing .play .bars { display: flex; }
@keyframes barHop {
  0%, 100% { transform: scaleY(.35); }
  50% { transform: scaleY(1); }
}
.voice .dur { font-size: 12px; color: var(--ink-soft); flex: none; min-width: 30px; text-align: right; }
/* 进度轨道：底纹 wave + 高亮 fill（同串字符，fill 容器按 % 裁剪 → 已播段变亮） */
.voice .bar {
  position: relative;
  flex: 1;
  height: 16px;
  min-width: 70px;
  cursor: crosshair;
  overflow: hidden;
}
.voice .bar .wave, .voice .bar .fill {
  position: absolute;
  left: 0; top: 2px;
  white-space: nowrap;
  font-size: 12px;
  letter-spacing: 2px;
}
.voice .bar .wave { color: var(--ink-soft); opacity: .55; }
.voice .bar .fill {
  color: var(--accent);
  width: 0%;
  overflow: hidden;
  pointer-events: none;
}
/* 播放中整轨高亮一点 */
.voice.playing .bar .wave { opacity: .9; }
.voice .bar::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 1px;
  background: var(--line);
  opacity: .25;
  pointer-events: none;
}
.voice.playing .bar { cursor: pointer; }
/* 播放中波形闪烁改到底纹（fill 恒定亮） */
.voice.playing .bar .wave { animation: waveFade .5s linear infinite alternate; }
@keyframes waveFade { from { opacity: .35; } to { opacity: 1; } }

/* ---------- 底部输入区 ---------- */
.composer {
  border-top: 1px solid var(--line);
  background: var(--panel);
  padding: .55rem .8rem;
  padding-bottom: calc(.55rem + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: .45rem;
}
.composer .row { display: flex; gap: .45rem; }
.composer input[type="text"] {
  flex: 1;
  min-width: 0;
  font: inherit;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--line);
  padding: .45rem .6rem;
}
.composer input[type="text"]:focus { outline: none; border-color: var(--accent); }

/* 按住说话大按钮 + 手机用户列表按钮 */
.composer .row.ptt-row { display: flex; gap: .45rem; align-items: stretch; }
.composer .row.ptt-row .ptt { flex: 1; }
.composer .row.ptt-row #btn-users { flex: none; }
#btn-users { display: inline-flex; align-items: center; }
@media (min-width: 720px) {
  #btn-users { display: none; }
}

/* 按住说话大按钮 */
.ptt {
  flex: 1;
  font: inherit;
  font-weight: 700;
  padding: .6rem;
  border: 1px solid var(--line);
  background: var(--panel-alt);
  color: var(--ink);
  cursor: pointer;
  user-select: none;
  touch-action: none;
}
.ptt:active, .ptt.hold {
  background: var(--danger);
  border-color: var(--danger);
  color: #000000;
}
.ptt:disabled { opacity: .45; cursor: not-allowed; }

/* ---------- 成员栏（宽屏侧栏 / 手机抽屉） ---------- */
.members {
  position: fixed;
  inset: 0 0 0 auto;   /* 贴右 */
  width: 70%;
  max-width: 16rem;
  border-left: 1px solid var(--line);
  background: var(--panel);
  display: flex;
  flex-direction: column;
  z-index: 150;
  transform: translateX(100%);
  transition: transform .2s ease;
}
.members.show { transform: translateX(0); }
.members h3 {
  margin: 0;
  padding: .5rem .75rem;
  font-size: 12px;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--line);
  font-weight: 400;
  display: flex;
  align-items: center;
  gap: .5rem;
}
.members h3 span { flex: 1; }
.members-close {
  flex: none;
  border: 1px solid var(--line);
  background: var(--panel-alt);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  line-height: 1;
  padding: .1rem .45rem;
  cursor: pointer;
}
.members-close:hover { border-color: var(--danger); color: var(--danger); }
.members ul { list-style: none; margin: 0; padding: .4rem .75rem; overflow-y: auto; flex: 1; }
.members li { padding: .15rem 0; font-size: 13px; display: flex; align-items: center; gap: .4rem; }
.members li .m-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.members li .kick-x {
  margin-left: auto;
  flex: none;
  border: 0;
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  padding: .25rem .35rem;
  border-radius: 3px;
  opacity: .8;
  min-height: 36px;
  min-width: 44px;
  transition: opacity .12s, color .12s;
}
.members li .kick-x:hover { opacity: 1; color: var(--danger); }
.members li .dot {
  width: 7px; height: 7px; flex: none;
  background: var(--ok);
}
.members li .dot.talking { background: var(--accent); animation: pulse .6s infinite alternate; }
@keyframes pulse { from { opacity: .4; } to { opacity: 1; } }

/* 手机抽屉遮罩 */
.members-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  z-index: 149;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s;
}
.members-overlay.show { opacity: 1; pointer-events: auto; }

@media (min-width: 720px) {
  .members {
    position: static;
    inset: auto;
    transform: none;
    width: 12rem;
    max-width: none;
    z-index: auto;
    transition: none;
  }
  .members.show { transform: none; }
  .members-close { display: none; }
  .members-overlay { display: none; }
}

/* ---------- 实时语音状态条 ---------- */
.live-bar {
  display: none;
  align-items: center;
  gap: .5rem;
  padding: .35rem .8rem;
  border-top: 1px solid var(--line);
  background: var(--panel-alt);
  font-size: 12px;
  color: var(--ink-soft);
}
.live-bar.show { display: flex; }
.live-bar .lvl {
  width: 44px; height: 8px;
  border: 1px solid var(--line);
  display: inline-flex;
  align-items: stretch;
  overflow: hidden;
}
.live-bar .lvl i { flex: 1; background: var(--line); }
.live-bar .lvl i.on { background: var(--accent); }
.btn.off { color: #ff5555; border-color: #ff5555; }

/* ---------- Nat 检测状态（大厅内联 / 房间 live-bar 下方） ---------- */
.nat-box { display: flex; gap: .5rem; align-items: flex-start; padding: .5rem .8rem; }
.nat-box.hidden { display: none; }
.nat-detail {
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-soft);
  white-space: pre-wrap;
  word-break: break-word;
  min-width: 0;
  flex: 1;
}
.nat-close {
  border: 1px solid var(--line);
  background: var(--panel-alt);
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  line-height: 1;
  padding: .15rem .45rem;
  cursor: pointer;
  flex: none;
}
.nat-close:hover { border-color: var(--danger); color: var(--danger); }

/* ---------- Toast ---------- */
.toast {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: 5.5rem;
  background: var(--panel);
  border: 1px solid var(--accent);
  color: var(--ink);
  padding: .45rem .9rem;
  font-size: 13px;
  /* 必须高于 .modal(100)：邀请弹层内触发的 toast（作废成功/失败等）
     否则被弹层盖住，用户看不到任何反馈（2026-09-05 真实故障） */
  z-index: 200;
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s;
}
.toast.show { opacity: 1; }

/* ---------- 邀请弹层 ---------- */
.modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 1rem;
}
.modal.hidden { display: none !important; }
.modal-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  padding: 1.2rem;
  width: 100%;
  max-width: 28rem;
  max-height: 90dvh;
  overflow-y: auto;
}
.modal-panel h2 { font-size: 1rem; margin: 0 0 .5rem; }
.modal-panel .desc { color: var(--ink-soft); font-size: 12px; margin: 0 0 .9rem; line-height: 1.5; }
.modal-panel .desc strong { color: var(--accent); }
.btn-row { display: flex; gap: .5rem; margin-top: .5rem; }
.btn-row .btn-primary { flex: 1; }
.btn-row .btn { flex: none; min-width: 5rem; }
.modal-panel input[type="number"] {
  width: 100%;
  font: inherit;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--line);
  padding: .45rem .6rem;
}
.modal-panel input[type="number"]:focus { outline: none; border-color: var(--accent); }
.invite-result.hidden { display: none; }
.invite-link-row {
  display: flex;
  gap: .4rem;
  margin: .4rem 0;
}
.invite-link-row input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 12px;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--line);
  padding: .4rem .5rem;
}

/* ---------- 历史邀请列表 ---------- */
.invite-sep { border: 0; border-top: 1px solid var(--line); margin: 1rem 0 .7rem; }
.invite-list-title { font-size: 14px; margin: 0 0 .2rem; }
.invite-list-hint { margin: 0 0 .6rem; }
.invite-list { display: flex; flex-direction: column; gap: .5rem; max-height: 40vh; overflow-y: auto; }
.invite-list-empty { margin: .5rem 0; }
.invite-item {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: .5rem .6rem;
  background: var(--bg);
}
.invite-item.revoked, .invite-item.expired { opacity: .62; }
.invite-item-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.invite-item-label { font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.invite-item-badge {
  flex: none; font-size: 11px; padding: .1rem .45rem; border-radius: 999px;
  background: var(--line); color: var(--ink);
}
.invite-item.revoked .invite-item-badge { background: var(--danger); color: #000; }
.invite-item.expired .invite-item-badge { background: var(--line); color: var(--panel); }
.invite-item:not(.revoked):not(.expired) .invite-item-badge { background: var(--accent); color: #000; }
.invite-item-sub { font-size: 11px; color: var(--ink-soft); margin-top: .25rem; }
.invite-item-dead { display: block; font-size: 11px; color: var(--danger); margin-top: .3rem; }
.invite-item-actions { display: flex; gap: .4rem; margin-top: .45rem; }
.invite-item-actions .btn { font-size: 12px; padding: .2rem .6rem; }
.btn.danger { color: var(--danger); border-color: var(--danger); }

/* 连接状态行（输入区顶部，左对齐小字）。
 * 曾经上方还有 .mode-row（"文字 + 按住说话" + 录音提示），已整行删除。 */
.conn-row { justify-content: flex-start; align-items: center; gap: .5rem; }

/* 实时语音可用性徽章：紧跟连接状态，颜色编码 NAT 探测结论。
 * 是个 button（可点击看详情/重测），但样式做成纯文字标签。 */
.live-badge {
  font: inherit;
  font-size: 11px;
  padding: 0 .35rem;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-soft);
  cursor: pointer;
  white-space: nowrap;
  flex: none;
}
.live-badge:hover { color: var(--ink); }
.live-badge[hidden] { display: none; }
.live-badge.ok { border-color: var(--ok); color: var(--ok); }
.live-badge.warn { border-color: var(--accent); color: var(--accent); }
.live-badge.bad { border-color: var(--danger); color: var(--danger); }
.live-badge.testing { opacity: .7; }

/* E2EE 状态徽章 */
.e2ee-badge {
  font-size: 11px;
  padding: 0 .35rem;
  border: 1px solid var(--ok);
  color: var(--ok);
  white-space: nowrap;
  flex: none;
  cursor: help;
}
.e2ee-badge[hidden] { display: none; }
.e2ee-badge.off { border-color: var(--danger); color: var(--danger); }
/* 表单字段下的说明小字（邀请弹层的"可用设备数"解释） */
.hint {
  margin: .3rem 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-soft);
}
/* 系统消息里的行内操作按钮（缺密钥时的"输入口令恢复"入口） */
.sys-action {
  display: inline-block;
  margin-left: .25rem;
  padding: .15rem .5rem;
  font: inherit;
  font-size: .85em;
  color: var(--bg);
  background: var(--accent);
  border: 0;
  border-radius: 4px;
  cursor: pointer;
}
.sys-action:hover { opacity: .85; }
/* 派生中：Argon2id 64MB 要约 2 秒，给个明确的"在忙"态 */
.e2ee-badge.pending { border-color: var(--accent); color: var(--accent); opacity: .8; }

/* 解不开的消息：视觉上明确区分，别让用户以为是乱码消息 */
.bubble.undecryptable {
  border: 1px dashed var(--danger);
  color: var(--danger);
  font-style: italic;
}
.conn-row .sub {
  color: var(--ink-soft);
  font-size: 11px;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

/* app 占满视口，内部不滚动，只有消息框滚动 */
.app {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  height: 100dvh;
  overflow: hidden;
}


/* ---------- 加载占位（boot-hint） ----------
 * 样式必须放这里而非 inline style：站点 CSP 是 style-src 'self'，
 * index.html 里的 style= 属性会被浏览器拦截（CF JSD challenge
 * 等待期 1-8s 会看到无样式的裸文本）。 */
#boot-hint {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-soft);
  font: 14px/1.6 'Courier New', Courier, monospace;
  background: var(--bg);
  text-align: center;
  padding: 1rem;
  z-index: 999;
}
#boot-hint .bh-title { font-size: 1.05rem; color: var(--ink); margin-bottom: .4rem; }
#boot-hint noscript { display: block; margin-top: .6rem; color: #ff5555; }

/* 键盘焦点指示：所有可交互元素在 Tab 焦点时可见 */
*:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 1px;
}
/* 按钮用 accent 更明显 */
.btn:focus-visible,
.btn-primary:focus-visible,
.ptt:focus-visible,
.members-close:focus-visible,
.nat-close:focus-visible,
.kick-x:focus-visible,
.sys-action:focus-visible,
.live-badge:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- 滚动条（主题化） ----------
 * 浏览器默认滚动条是浅色的，在 CRT 深色底（#0d1117 / #000）上就是一条刺眼白条。
 * 聊天区、成员栏、弹窗都会滚动，统一改成细的、跟主题同色。
 * 参照 kbtest 的同款处理。*/
.msgs,
.members ul,
.modal-panel,
.invite-list {
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
.msgs::-webkit-scrollbar,
.members ul::-webkit-scrollbar,
.modal-panel::-webkit-scrollbar,
.invite-list::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
.msgs::-webkit-scrollbar-track,
.members ul::-webkit-scrollbar-track,
.modal-panel::-webkit-scrollbar-track,
.invite-list::-webkit-scrollbar-track {
  background: transparent;
}
.msgs::-webkit-scrollbar-thumb,
.members ul::-webkit-scrollbar-thumb,
.modal-panel::-webkit-scrollbar-thumb,
.invite-list::-webkit-scrollbar-thumb {
  background: var(--accent-soft);
  border-radius: 0;
}
.msgs::-webkit-scrollbar-thumb:hover,
.members ul::-webkit-scrollbar-thumb:hover,
.modal-panel::-webkit-scrollbar-thumb:hover,
.invite-list::-webkit-scrollbar-thumb:hover {
  background: var(--ink);
}
.msgs::-webkit-scrollbar-corner,
.members ul::-webkit-scrollbar-corner,
.modal-panel::-webkit-scrollbar-corner,
.invite-list::-webkit-scrollbar-corner {
  background: transparent;
}

/* ---------------- 图片消息 ---------------- */
.msg .bubble.img-bubble { padding: 4px; }
.imgwrap {
  position: relative;
  display: block;
  width: 240px;
  max-width: 100%;
  border-radius: 8px;
  overflow: hidden;
  cursor: zoom-in;
  background: var(--panel-alt);
}
.imgwrap:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.imgwrap img { display: block; width: 100%; height: auto; border-radius: 8px; }
/* 占位：用元数据里的 w/h 算出的高度撑住，图到了不跳版 */
.imgph {
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--ph-h, 180px);
  font-size: 12px;
  color: var(--ink-soft);
}
.imgph.failed { color: #ff6b6b; }
.imgph .spin {
  width: 18px; height: 18px;
  border: 2px solid var(--accent-soft);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: img-spin .8s linear infinite;
}
@keyframes img-spin { to { transform: rotate(360deg); } }
.imgwrap.failed { cursor: not-allowed; }

/* 拖拽进聊天区时的提示 */
#msgs.dragging {
  outline: 2px dashed var(--accent);
  outline-offset: -4px;
  background: var(--accent-soft);
}

/* ---------------- 图片灯箱 ---------------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1rem;
  background: rgba(0, 0, 0, .88);
}
.lightbox[hidden] { display: none; }
.lightbox img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 6px;
}
.lb-close {
  position: absolute;
  top: .5rem; right: .75rem;
  width: 40px; height: 40px;
  font-size: 26px;
  line-height: 1;
  color: #fff;
  background: rgba(0, 0, 0, .5);
  border: 1px solid rgba(255, 255, 255, .25);
  border-radius: 50%;
  cursor: pointer;
}
.lb-close:hover { background: rgba(0, 0, 0, .75); }

/* iOS 在 font-size < 16px 时会缩放页面；统一输入框字体 */
input, select, textarea { font-size: 16px; }

