/* ==========================================================================
   ★★★ **黑白漫画风**（2026-10-05 用户要求）
   ==========================================================================
   用户原话：
   > 参考这种黑白动漫风格图，换个风格，素材图，UI按键素材图，
   > UI按键参考图都在 D:\素材\02-图片素材\UI设计素材参考，
   > 自行裁剪合适大小，大小要统一

   ## ⚠️ 这一整块都挂在 `html[data-ui="manga"]` 下面

   因为用户说过「**现在的可以留一套，如果效果不行就回退**」——
   所以上一版那套拟物风**一行没删**，只是被这里覆盖掉了。
   把 `config.json` 的 `ui.style` 改成 `neumo` 就**整个切回去**。

   ⚠️ 素材是 `tools/make-ui-assets.mjs` 生成的（`public/ui/`），
      风格三色：墨 `#12151a` / 纸 `#ffffff` / 蓝 `#2f4f7f`。
      下面的 CSS 变量就是从那儿来的 —— **改素材颜色要同步改这里**。

   ## ⚠️⚠️ 为什么用"图标当背景图"而不是 `<img>`

   底部 tab 那四个 `<button>` 里**本来就有内联 SVG**（那是旧风格那套）。
   换成 `<img>` 要动 HTML 和 JS 两处；而**把 SVG 藏起来、用 `background-image`
   贴新的 PNG** 只动 CSS 一处 —— 回退也就是把这段删掉。

   ⚠️ 内联 SVG 用 `display:none` 藏（不是 `visibility`）——
      留着它占位的话那个 23px 的坑还在，PNG 会和它错位。
   ========================================================================== */

:root {
  /** ★ 漫画三色（和 `tools/make-ui-assets.mjs` 里那三个常量一致） */
  --manga-ink: #12151a;
  --manga-paper: #ffffff;
  --manga-blue: #2f4f7f;
  --manga-blue-soft: #8fa8cc;
}

/* ---------------------------------------------------------------- 全局底色 */
/**
 * 🚨🚨🚨 **这一条是"屏幕背景全看不见"的最终根因**（2026-10-05 抓到）。
 *
 * ## 原来是什么
 *
 * ```css
 * html[data-ui='manga'] body { background: var(--manga-paper); }   // = #fff
 * ```
 *
 * ⚠️ 两个毛病叠在一起：
 * ① **`background` 简写** —— 它把 `background-image` 一起重置成 `none`。
 * ② 特异性 **0,1,1** —— 比 `body { background-image: var(--screen-bg) }`（0,0,1）**高**。
 *    ⚠️ 所以它**赢**，而它赢的方式是"**把背景图设成没有**"。
 *
 * ⚠️ 结果：`body` 是**纯白**，背景图（不管画在 `body::before` 还是 `html` 上）
 *    **全被挡掉** ——而 **CSS 变量算出来是对的、图片 200 能取到、
 *    `data-bg` 属性也打对了、那条背景规则也确实匹配**：
 *    **静态怎么查都查不出问题**。
 *
 * ## ⚠️ 怎么找到的（只有这一步能"知道"）
 *
 * ⚠️ 用 CDP 问浏览器「**body 的 background 被哪些规则碰过、谁赢了**」：
 * ```
 * CSS.getMatchedStylesForNode({ nodeId: body }) → matchedCSSRules
 * ```
 * ⚠️ 它把 4 条全列出来，**这条就夹在里面** ——
 *    ⚠️ 前面我查变量、查图片、查路径、查规则是否存在，**全对**，
 *      但它们**都回答不了"最后是谁说了算"**。
 *
 * ## ✅ 修法
 *
 * ⚠️ **只写 `background-color`**（不碰 `background-image`）——
 *    这样它照样把底色刷成漫画纸白，但**不再重置背景图**。
 *    ⚠️ 而且背景图那条规则（`body { background-image: var(--screen-bg, none) }`）
 *      在同一份文件里、**在它后面** → 背景图正常画出来。
 */
html[data-ui='manga'] body {
  background-color: var(--manga-paper);
}
/**
 * ⚠️ 漫画风的**层次靠"描边"**（不是靠阴影）——
 *    所以卡片统一换成"粗黑边 + 大圆角"，阴影全部去掉。
 *    `!important` 不用加：这些选择器比原来的 `.card` 更具体
 *    （`html[data-ui] .card` > `.card`）。
 */
html[data-ui='manga'] .card,
html[data-ui='manga'] .card.sunken {
  background: var(--manga-paper);
  border: 3px solid var(--manga-ink);
  border-radius: 20px;
  box-shadow: none;
}
html[data-ui='manga'] .card.sunken {
  background: #f6f7f9;
}

/* ---------------------------------------------------------------- 底部 tab */
html[data-ui='manga'] .tabbar {
  background: var(--manga-paper);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-top: 3px solid var(--manga-ink);
}
html[data-ui='manga'] .tab {
  color: var(--manga-ink);
  opacity: 0.62;
  /**
   * ⚠️ **gap 从 2 加到 3** —— 那四个图标是"人物插画"，
   *    底边和下面那行字**贴在一起**看着很挤（细线条图标时看不出来）。
   *    ⚠️ 而格子高度是紧的（见上面 34px 那段），所以只能 **gap +1**、
   *       不能再加 padding。
   */
  gap: 3px;
}
/** ⚠️ 选中的那个：**满色 + 加粗**（漫画风不玩"淡入淡出"） */
html[data-ui='manga'] .tab.is-on {
  color: var(--manga-blue);
  opacity: 1;
}
html[data-ui='manga'] .tab.is-on .tab-text {
  font-weight: 800;
}

/**
 * ★ 图标换成生成的 PNG（两张：普通 / 选中）。
 * ⚠️ 尺寸用 `background-size: contain` —— 素材是 512 的方图，
 *    而按钮那一格可能不是方的（那样 `100% 100%` 会拉扁）。
 */
html[data-ui='manga'] .tab svg {
  display: none;
}
html[data-ui='manga'] .tab::before {
  content: '';
  display: block;
  /**
   * 🚨 **26px → 36px**（2026-10-05 用户要求换成那四张按钮图之后）。
   *
   * ⚠️ 26px 是给**细线条图标**定的（那种画法在 26px 下还认得出）。
   * ⚠️ 而现在是**人物插画** —— 26px 上只剩一团蓝白，看不出是个人。
   *
   * ## ⚠️⚠️ 为什么是 36，不是 42
   *
   * 🚨 第一版设成 42 → **图标底部被切掉了**（人物只露出上半身）。
   *
   * ⚠️ 量出来的账（`#tabbar [data-tab]`）：
   *    · tab 栏高 **68px**
   *    · 每格 `padding: 8px / 6px`、`gap: 2px`、下面那行字高 **10px**
   *    · → 8 + 图标 + 2 + 10 + 6 = 26 + 图标
   *    · → **图标最多 42**，但那已经是"一点余量都没有"（字体一换就溢出）
   *
   * → 取 **36**（留 6px 余量）。⚠️ 在 64px 的格子里 36 也已经认得出人了。
   */
  /**
   * ⚠️ **34px** —— 36 也能装下（量过：8+36+2+10+6=62 = 格子高），
   *    但那个账是"**一点余量都没有**"（字体一换就贴住/溢出）。
   *    34 留 2px 余量，同时下面那行字和图标之间有**看得出来的缝**。
   */
  width: 34px;
  height: 34px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  /**
   * ⚠️ 选中态那个素材本身"顶着框"，再靠 `.tab.is-on` 的透明度区分就够了 ——
   *    这里**不加缩放**（加了会和"按下去回弹"那个动效打架）。
   */
}
html[data-ui='manga'] .tab[data-tab='home']::before {
  background-image: url('./ui/tab-home.png');
}
html[data-ui='manga'] .tab[data-tab='home'].is-on::before {
  background-image: url('./ui/tab-home-on.png');
}
html[data-ui='manga'] .tab[data-tab='contacts']::before {
  background-image: url('./ui/tab-contacts.png');
}
html[data-ui='manga'] .tab[data-tab='contacts'].is-on::before {
  background-image: url('./ui/tab-contacts-on.png');
}
html[data-ui='manga'] .tab[data-tab='moments']::before {
  background-image: url('./ui/tab-moments.png');
}
html[data-ui='manga'] .tab[data-tab='moments'].is-on::before {
  background-image: url('./ui/tab-moments-on.png');
}
html[data-ui='manga'] .tab[data-tab='me']::before {
  background-image: url('./ui/tab-me.png');
}
html[data-ui='manga'] .tab[data-tab='me'].is-on::before {
  background-image: url('./ui/tab-me-on.png');
}
html[data-ui='manga'] .tab-text {
  font-size: 10px;
  letter-spacing: 0.5px;
}

/* ---------------------------------------------------------------- 按钮 */
/**
 * ⚠️ **主按钮做成"漫画胶囊"**：白底 + 粗黑边 + 大圆角。
 *    用 `.sheet-btn` 这个已有的类覆盖（它是全项目用得最多的按钮）。
 */
html[data-ui='manga'] .sheet-btn,
html[data-ui='manga'] .menu-item,
html[data-ui='manga'] .home-link {
  background: var(--manga-paper);
  border: 3px solid var(--manga-ink);
  border-radius: 999px;
  box-shadow: none;
  color: var(--manga-ink);
  font-weight: 650;
}
/** ⚠️ 按下去**变蓝 + 网点**（漫画的"按下"就是这个感觉） */
html[data-ui='manga'] .sheet-btn:active,
html[data-ui='manga'] .menu-item:active,
html[data-ui='manga'] .home-link:active {
  background-color: var(--manga-blue);
  color: var(--manga-paper);
}

/** 危险键保留红（⚠️ 但换成"漫画红"，不是纯亮红） */
html[data-ui='manga'] .danger-btn {
  background: var(--manga-paper);
  border: 3px solid #b0403a;
  color: #b0403a;
}

/* ---------------------------------------------------------------- 输入框 */
html[data-ui='manga'] .field-input,
html[data-ui='manga'] input[type='text'],
html[data-ui='manga'] input[type='range'],
html[data-ui='manga'] select,
html[data-ui='manga'] textarea {
  background: var(--manga-paper);
  border: 3px solid var(--manga-ink);
  border-radius: 14px;
  box-shadow: none;
}

/* ---------------------------------------------------------------- 动作键 */
/** 主页那两个键（语音通话 / 发消息）—— 换成素材里的图标 + 粗边 */
html[data-ui='manga'] .peer-act {
  background: var(--manga-paper);
  border: 3px solid var(--manga-ink);
  border-radius: 16px;
  box-shadow: none;
  color: var(--manga-ink);
  font-weight: 700;
}
html[data-ui='manga'] .peer-act svg {
  display: none;
}
html[data-ui='manga'] .peer-act::before {
  content: '';
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}
html[data-ui='manga'] .peer-act:nth-of-type(1)::before {
  background-image: url('./ui/act-call.png');
}
html[data-ui='manga'] .peer-act:nth-of-type(2)::before {
  background-image: url('./ui/act-message.png');
}

/* ---------------------------------------------------------------- 头像/背景 */
/**
 * ⚠️ 个人主页那个**大圆头像**在漫画风里要"压边"（粗黑圈）——
 *    不压的话它和背景图糊在一起（本来那个白圈在浅色底上看不见）。
 */
html[data-ui='manga'] .peer-av {
  border: 4px solid var(--manga-ink);
}
html[data-ui='manga'] .peer-cover {
  background-color: #f0f2f5;
  border: 3px solid var(--manga-ink);
}
/**
 * 聊天气泡：粗边 + 大圆角（微信那种是"浅灰无边界"，漫画风要看得见轮廓）
 *
 * 🚨🚨 **2026-10-05 修了一个"从来没生效过"的选择器**：
 *
 * ⚠️ 这里原来写的是 `.row.in .bubble` / `.row.out .bubble` ——
 *    而 `buildRow()` 建的类是 **`row--in` / `row--out`**（两个连字符，
 *    BEM 那种写法），**根本没有 `.row.in` 这个元素**。
 *
 * ⚠️ 后果：**这几条规则从加上那天起就没生效过**（不报错、也不警告）——
 *    而 CSS 的"没生效"是**看不出来的**（用户只会觉得"怎么没变"）。
 *    ⚠️ 我一分钟前写新规则时**照着它抄了一遍**，等于把这个错**复制了一份**。
 *
 * → 现在统一用真的类名（`.row--in` / `.row--out`），并且**两边都写**
 *   （`row--in` 那个父类 + `bubble--in` 那个子类，哪个变都跟得上）。
 */
html[data-ui='manga'] .row--in .bubble,
html[data-ui='manga'] .row--out .bubble,
html[data-ui='manga'] .bubble--in,
html[data-ui='manga'] .bubble--out {
  /**
   * ⚠️ **边框宽度只能是整数** —— Chromium 会把 `2.5px` 算成 `2px`
   *    （项目铁律里那条）。漫画风要"看得见"，所以用 3px。
   */
  border: 3px solid var(--manga-ink);
  border-radius: 18px;
  /** ⚠️ 漫画不讲"柔和阴影"，讲**硬投影**（错位的实心黑块） */
  box-shadow: 4px 4px 0 rgba(18, 21, 26, 0.9);
}
html[data-ui='manga'] .row--out .bubble,
html[data-ui='manga'] .bubble--out {
  background: var(--manga-blue);
  color: var(--manga-paper);
  /** ⚠️ 我的投影往**左下**（和她的镜像）—— 一眼看出谁在左谁在右 */
  box-shadow: -4px 4px 0 rgba(18, 21, 26, 0.9);
}
html[data-ui='manga'] .row--in .bubble,
html[data-ui='manga'] .bubble--in {
  background: var(--manga-paper);
  color: var(--manga-ink);
}

/* ---------------------------------------------------------------- 顶栏 */
html[data-ui='manga'] .bar {
  background: var(--manga-paper);
  border-bottom: 3px solid var(--manga-ink);
}
html[data-ui='manga'] .home-title {
  font-weight: 800;
  letter-spacing: 0.5px;
}

/* ---------------------------------------------------------------- 补漏（截图看出来的） */
/**
 * ⚠️ 这几处是**第一版漏掉的** —— 加了漫画风之后看截图才发现
 *    "卡片换了、里面那些小块还是旧样式"（一眼不协调）。
 *
 * ⚠️ 教训：**换风格要整屏看一遍**，光改"最外层那几个类"会漏掉里层的。
 */

/** 顶栏那两个圆钮（设置 / 返回）—— 漫画风要有黑圈 */
html[data-ui='manga'] .icon-btn {
  border: 3px solid var(--manga-ink);
  background: var(--manga-paper);
  box-shadow: none;
  border-radius: 50%;
}
html[data-ui='manga'] .icon-btn:active {
  background: var(--manga-ink);
  color: var(--manga-paper);
}

/** 她的照片：粗黑圈（漫画风里"人物特写"外面就该有一圈） */
html[data-ui='manga'] .hero-portrait {
  border: 3px solid var(--manga-ink);
  background: var(--manga-paper);
  box-shadow: none;
}

/** 那三个小格（她现在 / 心情 / 好感）—— 换成"细黑边 + 大圆角"，去掉凸起阴影 */
html[data-ui='manga'] .stat {
  background: var(--manga-paper);
  border: 3px solid var(--manga-ink);
  border-radius: 16px;
  box-shadow: none;
}
/**
 * ⚠️ 深色内嵌卡（`.card.sunken`）里那三个小格**底色要反过来** ——
 *    里面本来就是浅灰底，小格再白就不显了。
 */
html[data-ui='manga'] .card.sunken .stat {
  background: var(--manga-paper);
}

/** 群里那种"一条条"的东西也跟着走 */
html[data-ui='manga'] .room-row,
html[data-ui='manga'] .contact-head {
  border-color: var(--manga-ink);
}

/** 顶栏的"状态行"（她睡着 / 心情 / 连接）—— 加一条黑分隔 */
html[data-ui='manga'] .bar-status {
  color: var(--manga-ink);
}
html[data-ui='manga'] .dot-sep {
  opacity: 0.35;
}

/** 聊天列表那一行行 —— ⚠️ 第一版漏了（截图里那三条还是"白底无边框"） */
html[data-ui='manga'] .chat-item {
  background: var(--manga-paper);
  border: 3px solid var(--manga-ink);
  border-radius: 18px;
  box-shadow: none;
}
/** ⚠️ "能聊的那条"（她）用**蓝色左粗条**标出来（原来那个 inset 阴影在漫画风里看不见） */
html[data-ui='manga'] .chat-item.is-live {
  border-left-width: 9px;
  border-left-color: var(--manga-blue);
  box-shadow: none;
}
html[data-ui='manga'] .chat-item:active {
  background: #f2f4f7;
}
html[data-ui='manga'] .chat-av {
  border: 3px solid var(--manga-ink);
  background: var(--manga-paper);
}
html[data-ui='manga'] .chat-av-group {
  border-radius: 14px;
}

/** 通讯录那张卡 */
html[data-ui='manga'] .contact-card.is-tappable {
  border: 3px solid var(--manga-ink);
}
html[data-ui='manga'] .contact-card.is-tappable:focus-visible {
  outline: 3px solid var(--manga-blue);
}

/** 动态那一条条 */
html[data-ui='manga'] .moment {
  border: 3px solid var(--manga-ink);
}

/* ==========================================================================
   ★★★ 黑白漫画风：聊天气泡 + 输入栏（2026-10-05 用户要求）
   ==========================================================================
   用户原话：
   > 把**黑白漫画风格的聊天气泡和输入栏**也改了
   ==========================================================================
   ⚠️ 全部挂在 `html[data-ui='manga']` 下面 —— 这样**切回极简风时
      一个字都不受影响**（用户要求"保留前一套"）。
   ========================================================================== */

/** 她的气泡：白底 + 粗黑描边 + 大圆角（漫画里"说话框"那个样子） */
html[data-ui='manga'] #screen-chat .row--in .bubble,
html[data-ui='manga'] #screen-chat .bubble--in {
  background: var(--manga-paper, #fff);
  color: var(--manga-ink, #12151a);
  border: 3px solid var(--manga-ink, #12151a);
  border-radius: 18px;
  /** ⚠️ 漫画不讲"柔和阴影"，讲**硬投影**（错位的实心黑块） */
  box-shadow: 4px 4px 0 rgba(18, 21, 26, 0.9);
}

/** 我的气泡：蓝底（那一套素材里的蓝）+ 同样的粗黑描边 */
html[data-ui='manga'] #screen-chat .row--out .bubble,
html[data-ui='manga'] #screen-chat .bubble--out {
  background: var(--manga-blue, #2f4f7f);
  color: #fff;
  border: 3px solid var(--manga-ink, #12151a);
  border-radius: 18px;
  /** ⚠️ 我的投影往**左下**（和她的镜像）—— 一眼看出谁在左谁在右 */
  box-shadow: -4px 4px 0 rgba(18, 21, 26, 0.9);
}

/* ---------- 输入栏（整条做成"漫画里的输入框"） ---------- */
html[data-ui='manga'] #screen-chat .composer,
html[data-ui='manga'] #screen-chat .send-form {
  background: var(--manga-paper, #fff);
  /** ⚠️ 上边一条粗黑线 —— 漫画分格就是这么分的 */
  border-top: 3px solid var(--manga-ink, #12151a);
}

html[data-ui='manga'] #screen-chat .composer input[type='text'],
html[data-ui='manga'] #screen-chat .composer textarea,
html[data-ui='manga'] #screen-chat #input {
  background: var(--manga-paper, #fff);
  color: var(--manga-ink, #12151a);
  border: 3px solid var(--manga-ink, #12151a);
  border-radius: 999px;
  /** ⚠️ 输入框**不加硬投影** —— 光标在里面打字时会显得很挤 */
  box-shadow: none;
}

/**
 * 发送键：实心蓝 + 粗黑边（那个"↑"要一眼认得出）。
 *
 * ⚠️ 用 **`#btn-send`**（那个真的 id）——
 *    我第一版写的 `.send-btn` **根本不存在**（类名是猜的）。
 *    ⚠️ 保留 `.round-btn--accent` 那一条：它是**真的**（那个键上有这个类），
 *       以后换 id 了也还跟得上。
 */
html[data-ui='manga'] #screen-chat #btn-send,
html[data-ui='manga'] #screen-chat .composer .round-btn--accent {
  background: var(--manga-blue, #2f4f7f);
  color: #fff;
  border: 3px solid var(--manga-ink, #12151a);
  box-shadow: 3px 3px 0 rgba(18, 21, 26, 0.9);
  border-radius: 50%;
}

/** 输入栏里那几个小圆钮（相册/拍照/麦克风）也跟着走 */
html[data-ui='manga'] #screen-chat .composer .round-btn,
html[data-ui='manga'] #screen-chat .send-form .round-btn {
  border: 3px solid var(--manga-ink, #12151a);
  background: var(--manga-paper, #fff);
  color: var(--manga-ink, #12151a);
  box-shadow: 3px 3px 0 rgba(18, 21, 26, 0.75);
}

/**
 * 🚨🚨🚨 **`body` 必须透明，否则背景图全被挡住**（2026-10-05 第三次修）
 *
 * ## 罪魁祸首就在上面几行
 *
 * ```css
 * html[data-ui='manga'] body { background: var(--manga-paper); }  // = #fff
 * ```
 *
 * ⚠️ 它把 `body` 刷成**纯白**，而且特异性（0,1,1）**比 `body { background: transparent }`
 *    （0,0,1）高** —— 所以：
 *    · 背景图画在 `body::before` 上 → **被 body 自己的底色盖住** ❌
 *    · 背景图改画在 `html` 上 → **被 body 的白色盖住** ❌（html 的图在 body 底下）
 *    · 而且量出来 `body` 的背景色是 `rgb(255,255,255)`，**规则还查不到**
 *      （因为它来自 `manga.css`，而我一开始只翻了 `app.css`）
 *
 * ## ✅ 修法
 *
 * ⚠️ **只在"这一屏有背景"时把 body 变透明** ——
 *    没有背景的屏（聊天页等）**保持原来那个白底**（不然会露出 html 上的灰底，
 *    聊天页那种整屏设计的观感就变了）。
 *
 * ⚠️ 用 `[data-bg][data-bg]`（属性写两遍）把特异性抬到 **0,3,1** ——
 *    稳赢 `manga.css` 那条，而且**不用 `!important`**。
 *    ⚠️ `html` 和 `body` 都带这个属性（JS 两边都打，见 `app.js` 的 `applyBgKey`），
 *       所以 `html[data-bg][data-bg] body` 也成立。
 */
html[data-bg][data-bg] body,
body[data-bg][data-bg] {
  /**
   * 🚨🚨 **必须是 `background-color`，不能是 `background` 简写**（2026-10-05 修）。
   *
   * ## 出了什么事（这是"屏幕背景全看不见"的真正根因）
   *
   * ⚠️ 原来这里写的是 `background: transparent;` —— **简写**。
   *    `background` 简写会把**所有**background 长尾属性一起重置，
   *    其中包括 **`background-image`**。
   *
   * ⚠️ 而这条选择器是 `body[data-bg][data-bg]`（特异性 **0,3,1**）——
   *    它**比 `body { background-image: var(--screen-bg) }`（0,0,1）高** →
   *    **把那张背景图重置成 `none` 了**。
   *
   * ⚠️ 结果：**所有页面的背景图一张都看不到**，而且：
   *    · CSS 变量算出来是**对的**（`url('./ui/screen-bg-contacts.png')`）
   *    · 图片 200 能取到、`new Image()` 能加载
   *    · `data-bg` 属性也打对了
   *    · 那条 `body { background-image: var(--screen-bg) }` 规则**确实匹配**
   *    **只有"最终生效的那条"是它** —— 静态怎么查都查不出来。
   *
   * ## ⚠️ 怎么找到的（方法值得记）
   *
   * ⚠️ 用 CDP 直接问浏览器「**body 的 background 被哪些规则碰过**」：
   * ```
   * CSS.getMatchedStylesForNode({ nodeId }) → matchedCSSRules
   * ```
   * ⚠️ 它把 4 条都列出来了，**第 4 条就是这条**（`background: transparent`）。
   *    ⚠️ **这一步是"猜"和"知道"的分界**：
   *       前面我查了变量、图片、路径、CSS 规则是否存在 —— **全对**，
   *       但它们都回答不了「**最后是谁说了算**」。
   *
   * ## ⚠️ 而且这条铁律**项目里早就写着**：「绝不用 `background:` 简写」
   *
   * ⚠️ 是我自己加的 `[data-bg][data-bg]` 特异性 hack 时又犯了一次 ——
   *    **加特异性 hack 的时候，最容易忘的就是"简写会顺手重置别的属性"**。
   *    ⚠️ 以后写 `[x][x]` 这种 hack 时，**只写要改的那一个长尾属性**。
   */
  background-color: transparent;
}

/**
 * ⚠️ **另一个"帮忙挡路"的**：`.screen.app` 那几屏如果自己有底色也会盖住 ——
 *    查过了，它们**没有**背景色（只有 `position: relative; z-index: 1`），
 *    所以不用管（列在这里是给下一个来查的人省时间）。
 */

/* ==========================================================================
   ★★★ 背景"看得见"的调法（2026-10-05 第四次调）
   ==========================================================================
   ## 出了什么事

   ⚠️ 背景**技术上画出来了**（量到 65.7% 非白像素），
      但这几张素材**中间本来就是大片奶油色留白**（手账风就那样）——
      ⚠️ 所以**看着还是像白底**，用户会以为"没加上"。

   ⚠️ 而且装饰（星星/贝壳/花）**都在四边**，正好被卡片盖住。

   ## ✅ 两个调法

   ① **卡片再透一点**（82% → 72%）—— 让四边那些图案透出来
   ② **给文字加一层"底衬"**（`text-shadow` 白色光晕）——
      透明度降了之后，浅色小字（"她现在是…"那种）压在图案上会发花
   ========================================================================== */

/**
 * 🚨 **卡片要更透一点**（2026-10-05 用户报"背景图看不出来"）。
 *
 * ⚠️ 原来 72% —— 而这几张背景图**中间本来就是近白色**（"相框式"构图：
 *    装饰全在四边、中间留白）。
 *    ⚠️ 于是"**白底卡 + 白色背景中间**"叠起来 = **一整片灰白**，
 *      用户看到的结论就是"**通讯录没有背景图**"。
 *
 * ⚠️ 降到 **52%**：四边那些图案透得出来，中间的留白也不至于让字发花
 *    （下面还有 `text-shadow` 那层光晕兜着）。
 *    ⚠️ 再低就会影响读字了 —— **52% 是这个风格的底**。
 */
/*
 * 🚨🚨 **2026-10-05 晚报：这条原来在这里（52% 的 .card 底）—— 已删。**
 *
 * ⚠️ 它**不带主题前缀**，而 app.css 里有一条**同名且特异性更高**的（82%、0,3,1）——
 *    所以它**永远被盖掉**（写了等于没写），还让"极简主题到底用哪条"没法一眼看懂。
 * ⚠️ 现在：卡片的底由 app.css 独占，**两套主题共用**（这是有意的 ——
 *    背景图那套是按屏配的，和主题无关）。
 */

/**
 * ⚠️ **文字底衬** —— 半透明之后，图案会从字下面透出来。
 *    `text-shadow` 打一圈**同色白晕**：字还是那个字，
 *    但底下多了一层"垫子"（比给整块卡加不透明度更省背景）。
 *
 * ⚠️ 用 `0 0 3px` 那种**糊的**（不是硬描边）——
 *    硬描边会让字看着像贴纸（和这套手账风不搭）。
 */
/*
 * 🚨 **2026-10-05 晚报：这一组选择器加上了 html[data-ui='manga'] 前缀。**
 *
 * ⚠️ 原来它**没有主题前缀** —— 而 body[data-bg] 在两套主题下都会被打上，
 *    于是**极简主题的字上也有一层白色光晕**（那是漫画风才要的东西）。
 *    ⚠️ 这正是用户说的"元素别混在一起了"。
 */
html[data-ui='manga'] body[data-bg] h1, html[data-ui='manga'] body[data-bg] h2,
html[data-ui='manga'] body[data-bg] h3,
html[data-ui='manga'] body[data-bg] p, html[data-ui='manga'] body[data-bg] span,
html[data-ui='manga'] body[data-bg] .chat-item,
html[data-ui='manga'] body[data-bg] .stat-value,
html[data-ui='manga'] body[data-bg] .stat-label {
  text-shadow:
    0 0 3px color-mix(in srgb, var(--bg-soft) 92%, transparent),
    0 0 6px color-mix(in srgb, var(--bg-soft) 70%, transparent);
}

/**
 * ⚠️ 顶栏那条**要更实一点**（它是"标题区"，透太多会看不清"主页"那两个字）——
 *    上一条给它加的光晕不够，所以这里单独抬回 88%。
 */
/*
 * 🚨🚨 **2026-10-05 晚报：这条原来在这里（88% 的 .bar 底）—— 已删。**
 *    同上：被 app.css 里特异性更高的一条盖着，属于**死代码**。
 */

/**
 * ⚠️ 聊天列表那些行（`.chat-item`）**自己有不透明底**（`--manga-paper`）——
 *    它们也盖住了背景。这里只**稍微**透一点（列表要能看清字）。
 */
/*
 * 🚨 **2026-10-05 晚报：加上了 manga 前缀。**
 *
 * ⚠️ --manga-paper 是**漫画风那套变量** —— 在极简主题下用它就是串味
 *    （极简那套根本不该知道"漫画纸"是什么颜色）。
 */
html[data-ui='manga'] body[data-bg][data-bg] .chat-item,
html[data-ui='manga'] html[data-bg][data-bg] .chat-item {
  background: color-mix(in srgb, var(--manga-paper, #fff) 62%, transparent);
}

/* ==========================================================================
   ★★★ 背景尺寸：`cover` → **拉伸铺满**（2026-10-05 第五次调，这次是构图原因）
   ==========================================================================
   ## 为什么 `cover` 不行

   ⚠️ 这几张素材是**"相框式"构图**：装饰（星星/贝壳/花/牛仔星）**全在四边**，
      中间是一大片奶油色留白（手账拼贴风就那样）。

   ⚠️ 而手机画面（430×900 ≈ 9:18.8）**比 9:16 更长** ——
      `cover` 会**把上下两条装饰带裁掉**（只留中间那片留白）→
      **看着还是像白底**（这才是"加了跟没加一样"的真正原因）。

   ⚠️ 我一开始以为是"被卡片盖住"，调了两次透明度都对，但**构图问题调透明度是没用的**。

   ## ✅ 修法：`background-size: 100% 100%`

   ⚠️ 拉伸会**轻微变形**（约 5%），但这几张是**水彩拼贴**——
      没有直线、没有圆、没有文字，**轻微变形完全看不出来**。
      ⚠️ 而换来的是：**四边的装饰完整保留**（那才是"有背景"的感觉）。

   ⚠️ 这是一种**取舍**：`cover` 保比例但丢构图，`100% 100%` 保构图但丢一点比例。
      对"相框式"素材，**保构图是对的**。
   ========================================================================== */

html {
  /**
   * ⚠️ **`100% 100%`（拉伸铺满），不是 `cover`** —— 见上面那段。
   *    铺满 = 图的所有部分都画出来（四边装饰一个不少）。
   */
  background-size: 100% 100%;
  /** ⚠️ 拉伸之后 `position` 没意义了（图正好铺满）—— 留着是为了别的档位 */
  background-position: center center;
  /**
   * ⚠️ **不要 `fixed`** —— 拉伸铺满之后它已经是"正好一屏"，
   *    `fixed` 只会让它在地址栏伸缩时跳一下（聊天背景那次的老问题）。
   */
  background-attachment: scroll;
}

/**
 * 🚨 **".hero 那类强调色卡"也要跟上透明度**（2026-10-05）。
 *
 * ⚠️ 主页最上面那张是 `section.card.hero` —— 它走的是
 *    `#screen-home .card { background: color-mix(accent 7%, bg-soft) }` 那条
 *    （**不是** 普通的 `.card`）。
 *    ⚠️ 所以只改 `.card` 那条**盖不住它**（特异性：`#id .card` > `body[data-bg] .card`）
 *      → 量出来还是 82%，**看着就是纯白**。
 *
 * ⚠️ 教训：这一屏的卡片有**三套**来源（`.card` / `.card.sunken` /
 *    `#screen-xxx .card`），改透明度得**三套都写** ——
 *    只写一套的话，正好那一屏最重要的那张卡没变（而且不报错）。
 */
body[data-bg][data-bg] #screen-home .card,
body[data-bg][data-bg] #screen-persona .card,
body[data-bg][data-bg] #screen-contacts .card,
body[data-bg][data-bg] #screen-me .card,
body[data-bg][data-bg] #screen-rooms .card,
body[data-bg][data-bg] #screen-room .card,
body[data-bg][data-bg] #screen-models .card,
body[data-bg][data-bg] #screen-about .card,
body[data-bg][data-bg] #screen-moments .card,
body[data-bg][data-bg] #screen-peer .card {
  background: color-mix(in srgb, color-mix(in srgb, var(--accent) 7%, var(--bg-soft)) 72%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/** ⚠️ `.card.hero` 那条（主页最上面）也要 —— 它是单独一条规则 */
/**
 * 🚨🚨 **2026-10-05 晚报：这条原来在这里（.card.hero / .card.moment）—— 已删。**
 *    app.css 里有一条同名的（值不同，且那条才是生效的）—— 详见 app.css 那段说明。
 */

/* ==========================================================================
   ★★★ 背景最终画法：**body 自己的背景**（2026-10-05 第六次，这次成了）
   ==========================================================================
   ## 前面五次为什么都不行（留个记录，别再走一遍）

   | 画法 | 结果 |
   | --- | --- |
   | `body::before` + `z-index:-1` | **被 `.screen{z-index:1}` 那一层盖住** |
   | 画在 `html` 元素上 | 属性**全对**（图、尺寸、变量、无报错），但**就是不画** |
   | 卡片不透明 | 盖住背景（改了三套选择器才全透） |
   | `manga.css` 里 `body{background:#fff}` | **优先级更高**，把 body 刷白 → 挡住 |
   | `cover` 裁切 | 这几张图装饰在四边，**被裁掉** → 看着像白底 |

   ## ✅ 最终：`body` 自己的背景（三层都满足）

   · `body` **不是**层叠上下文（没 `z-index`、没 `transform`）→ 背景不会被内容盖住
   · `body` 的底色已经改成 `transparent`（`manga.css` 里那条也覆盖过了）
   · `background-attachment: fixed` 在 `body` 上是**可靠的**
     （因为 `body` 不是根元素，`fixed` 老老实实按视口定位）
   ========================================================================== */

body {
  /** ⚠️ 只画在"有背景"的屏上（`--screen-bg` 是 JS 打上去的属性给的） */
  background-image: var(--screen-bg, none);
  /**
   * ⚠️ **不是 `cover`** —— 见上面"cover 裁切"那一行：
   *    这几张是"相框式"构图（装饰在四边、中间留白），
   *    而手机画面比 9:16 长 → `cover` 会把上下两条装饰带裁掉。
   *    ⚠️ 拉伸那 ~5% 在水彩拼贴上**看不出来**（没有直线、没有圆、没有字）。
   */
  background-size: 100% 100%;
  background-position: center center;
  background-repeat: no-repeat;
  /** ⚠️ `body` 上的 `fixed` 是可靠的（它不是根元素） */
  background-attachment: fixed;
}

/**
 * 🚨🚨 **这里原来有一句 `html { background-image: none; }` —— 它是"手滑"，已删**（2026-10-05）
 *
 * ## 出了什么事
 *
 * ⚠️ 原文的注释是：
 * ```
 * ⚠️ 顺手把 `html` 上那层去掉（它从来没画出来过，留着只会让人以为它在生效）
 * ```
 * ⚠️ **意图**是"把 `html` 那一层去掉"——
 *    但写成 `html { background-image: none }` 之后，
 *    它是**整份 CSS 里的最后一条** `html` 规则，
 *    于是**把上面 `body` 那条背景一起盖掉了**。
 *
 * ⚠️ 结果：**所有页面的背景图一张都看不见**，而**不报任何错**，
 *    CSS 变量算出来还是对的（`url('./ui/screen-bg-contacts.png')`）、
 *    图片也 200 能取到、`data-bg` 属性也打对了 ——
 *    **只有"最终绘制"那一步是空的**。
 *
 * ## ⚠️ 怎么找到的（这个方法值得记）
 *
 * ⚠️ 静态看全对（图片在、规则在、映射在、变量对）→ 只能**在真浏览器里做最小实验**：
 * ```
 * ① document.body.style.backgroundImage = "url('…')"       → 生效 ✅
 * ② 换成绝对路径                                            → 生效 ✅
 * ③ document.body.style.backgroundImage = "var(--x-test)"   → 生效 ✅
 * ④ 清掉 inline 样式 → computed 变回 none                   → ❌ **说明是页面 CSS 盖的**
 * ```
 * ⚠️ 第 ④ 步是关键：**"inline 能生效、清掉就不行" ⇒ 一定有一条 CSS 规则赢了**。
 *    然后就去找 `body/html` 的那些规则里**最后一条**是谁。
 *
 * ## ✅ 正确的做法
 *
 * ⚠️ **不要**用 `html { background-image: none }` 来"去掉一层" ——
 *    那会连 `body` 的一起盖掉（因为 `html` 是根元素，很多属性的初始值会往下传）。
 *    ⚠️ 要去掉 `html` 那一层，**根本不用写**（它本来就没画）；
 *       真要写就写 `html { background: none; }` **并且放对位置**。
 *
 * ⚠️ 删掉这一句之后：`body` 的背景正常显示（`background-size: 100% 100%`
 *    + `background-attachment: fixed`），而且 `--screen-bg-custom`
 *    （用户自己传的那张）也终于能生效了 —— 它在这之前**一直是白传的**。
 */


/* ==========================================================================
   ★★★ 真人私聊（`#screen-dm`）的漫画风（2026-10-08 用户要求）
   --------------------------------------------------------------------------
   ## 用户原话
   ```
   > 还有**真人私聊页面不是黑白漫画风格的**，改成和 AI 聊天的一样
   ```
   ## 🚨 为什么原来不是
   ```
   这个文件里**所有 #screen-chat 的规则都写了前缀**，而私聊那一屏
   （#screen-dm）**一条都没有** —— 它只吃通用的那几条（.bar / .field-input），
   所以气泡、输入栏、发送键全是"默认那套"（圆角 + 柔和阴影）。
   ⚠️ 这是"新屏忘了进主题"的典型：主题是一屏一屏加的，加了新屏没人回来补。
   ```
   ## ✅ 做法：**照 AI 聊天页那套一比一搬过来**（同一组变量、同一种硬投影）
   ```
   · 她的气泡（`.dm-row` 左）  → 白纸 + 3px 黑边 + 右下硬投影
   · 我的气泡（`.dm-row--out`）→ 蓝底白字 + 3px 黑边 + 左下硬投影（镜像）
   · 输入栏                    → 白纸 + 上边一条 3px 黑线（分格）
   · 发送键 / 相册 / 麦克风     → 粗黑边 + 硬投影
   ```
   ## ⚠️ 三条必须注意的
   ```
   ① **`background-color` 和 `background` 要一起写**
      —— `app.css` 里 `.dm-bubble` 用的是 `background-color`（简写盖不住它），
      只写 `background` 的话旧底色**还在下面露出来**（那种"半透明脏色"最难查）。
   ② **`.dm-media`（图/语音/视频）不许加黑边** ——
      它是"内容"，不是气泡；加了边会在图外面套一圈框（看着像加载失败）。
      但**带媒体又没字的那个气泡**是透明的（`app.css` 里有 `:has()` 那条），
      ⇒ 所以那一条也要在这里**再写一遍**，否则黑边会围着一张没底色的图。
   ③ **`--manga-*` 变量在这个文件里是全局的**（`:root` 那边定义了），
      所以直接用就行，不用重定义。
   ```
   ========================================================================== */

/* ---------- 气泡本体（她 / 我） ---------- */
html[data-ui='manga'] #screen-dm .dm-bubble {
  background: var(--manga-paper, #fff);
  background-color: var(--manga-paper, #fff);
  color: var(--manga-ink, #12151a);
  border: 3px solid var(--manga-ink, #12151a);
  border-radius: 18px;
  /** ⚠️ 漫画讲**硬投影**（错位的实心黑块），不是柔和阴影 */
  box-shadow: 4px 4px 0 rgba(18, 21, 26, 0.9);
}

/** 我的那条：蓝底白字 + 投影往**左下**（和她的镜像 —— 一眼看出谁在左谁在右） */
html[data-ui='manga'] #screen-dm .dm-row--out .dm-bubble {
  background: var(--manga-blue, #2f4f7f);
  background-color: var(--manga-blue, #2f4f7f);
  color: #fff;
  border: 3px solid var(--manga-ink, #12151a);
  box-shadow: -4px 4px 0 rgba(18, 21, 26, 0.9);
}

/** ⚠️ "发送中"还是半透明、失败还是醒目 —— 上面盖了底色之后要把这两条**再写一遍** */
html[data-ui='manga'] #screen-dm .dm-row--pending .dm-bubble {
  opacity: 0.55;
}
html[data-ui='manga'] #screen-dm .dm-row--failed .dm-bubble {
  background: var(--danger, #c0392b);
  background-color: var(--danger, #c0392b);
  color: #fff;
  box-shadow: -4px 4px 0 rgba(18, 21, 26, 0.9);
}

/**
 * ★★★ **纯媒体气泡也要有漫画边框**（2026-10-08 截图后改的）。
 *
 * ## 🚨 原来是什么样
 * ```
 * `app.css` 里有一条：
 *     .dm-bubble:has(> .dm-media):not(:has(> .dm-text)) { border:0; background:transparent; … }
 * ⇒ 它的意思是"纯图/纯语音的气泡不要底色"（免得图周围一圈白边）。
 * ⚠️ 但漫画主题下那条**顺手把边框和投影也去掉了** ⇒
 *    私聊里的图/语音**光秃秃地贴在背景上**，而同一屏的文字气泡却有黑边+硬投影
 *    ⇒ 一眼看出"两种东西不是一套"（用户要的正是"和 AI 聊天一样"）。
 * ```
 * ## ✅ 现在：**留边框 + 硬投影，只去掉内边距和底色**
 * ```
 * · `border: 3px solid 墨色` + `box-shadow` ⇒ 和文字气泡同一套
 * · `padding: 0` + `background: transparent` ⇒ 图**贴着边框内侧**，不套一圈白
 *   （`overflow: hidden` 保证图的圆角被气泡裁掉，不会从边框里戳出来）
 * ```
 * ⚠️ 带「保存」按钮的那种（`:has(> .dm-dl)`）本来就该留一点内边距 ——
 *    按钮要能看清，所以那一条**单独写**（下面）。
 */
html[data-ui='manga'] #screen-dm .dm-bubble:has(> .dm-media):not(:has(> .dm-text)) {
  background: transparent;
  background-color: transparent;
  border: 3px solid var(--manga-ink, #12151a);
  box-shadow: 4px 4px 0 rgba(18, 21, 26, 0.9);
  padding: 0;
  /** ⚠️ 图/视频的圆角要靠气泡裁（不然四个角会戳出边框） */
  overflow: hidden;
}
/** ⚠️ 带保存按钮的那种：同样有边框，但**留 4px 内边距**（按钮得看得清） */
html[data-ui='manga'] #screen-dm .dm-bubble:has(> .dm-dl):not(:has(> .dm-text)) {
  background: transparent;
  background-color: transparent;
  border: 3px solid var(--manga-ink, #12151a);
  box-shadow: 4px 4px 0 rgba(18, 21, 26, 0.9);
  padding: 4px;
  overflow: hidden;
}

/** 媒体本体：**不加黑边**（见上面 ②），只把圆角收到和气泡一致 */
html[data-ui='manga'] #screen-dm .dm-media {
  border-radius: 12px;
  border: 0;
}

/** "保存图片/视频/语音" 那个小按钮：跟着漫画风走 */
html[data-ui='manga'] #screen-dm .dm-dl {
  background: var(--manga-paper, #fff);
  background-color: var(--manga-paper, #fff);
  color: var(--manga-ink, #12151a);
  border: 2.5px solid var(--manga-ink, #12151a);
  border-radius: 999px;
  box-shadow: 2.5px 2.5px 0 rgba(18, 21, 26, 0.85);
  font-weight: 700;
}

/** 时间戳：漫画里的小字注音那种感觉（不加边框，别抢戏） */
html[data-ui='manga'] #screen-dm .dm-when {
  color: var(--manga-ink, #12151a);
  opacity: 0.6;
  font-weight: 600;
}

/* ---------- 输入栏（整条做成"漫画里的输入框"） ---------- */
html[data-ui='manga'] #screen-dm .dm-form {
  background: var(--manga-paper, #fff);
  /** ⚠️ 上边一条粗黑线 —— 漫画分格就是这么分的（和聊天页一模一样） */
  border-top: 3px solid var(--manga-ink, #12151a);
}

html[data-ui='manga'] #screen-dm #dm-input {
  background: var(--manga-paper, #fff);
  color: var(--manga-ink, #12151a);
  border: 3px solid var(--manga-ink, #12151a);
  border-radius: 999px;
  /** ⚠️ 输入框**不加硬投影** —— 光标在里面打字时会显得很挤（聊天页同一条） */
  box-shadow: none;
}

/** 发送键：实心蓝 + 粗黑边 + 硬投影 */
html[data-ui='manga'] #screen-dm .dm-form .btn-send {
  background: var(--manga-blue, #2f4f7f);
  color: #fff;
  border: 3px solid var(--manga-ink, #12151a);
  box-shadow: 3px 3px 0 rgba(18, 21, 26, 0.9);
}

/** 输入栏里那几个小圆钮（图片 / 拍摄 / 语音 / 表情包） */
html[data-ui='manga'] #screen-dm .dm-form .round-btn {
  background: var(--manga-paper, #fff);
  color: var(--manga-ink, #12151a);
  border: 3px solid var(--manga-ink, #12151a);
  box-shadow: 3px 3px 0 rgba(18, 21, 26, 0.75);
}

/**
 * 🚨 **那四个工具钮其实【不在】`.dm-form` 里面** —— 它们在独立的 `.dm-tools` 里
 *    （`index.html` 里 `.dm-tools` 和 `.dm-form` 是**兄弟**，不是父子）。
 *
 * ## 我怎么发现的（值得记）
 * ```
 * 我第一版只写了 `#screen-dm .dm-form .round-btn` ⇒ **一条都没匹配上**。
 * 而它是**静默失效**的：CSS 选择器不匹配不报错、没有日志 ——
 * 🚨 只有**把那一屏截图下来看**才发现那四个钮还是**黑底**（默认那套），
 *    而旁边新写的输入框/发送键已经是漫画风了 ⇒ 一眼看出"一半新一半旧"。
 * ⇒ 教训：**写完 CSS 必须真截图看一眼**，"规则写了" ≠ "匹配上了"。
 * ```
 * ⚠️ 用 `.dm-tool`（那几个按钮自己的类）而不是 `.dm-tools .round-btn` ——
 *    前者是"这个东西是什么"，后者是"它在哪个容器里"（容器改名就断了）。
 */
html[data-ui='manga'] #screen-dm .dm-tool {
  background: var(--manga-paper, #fff);
  color: var(--manga-ink, #12151a);
  border: 3px solid var(--manga-ink, #12151a);
  box-shadow: 3px 3px 0 rgba(18, 21, 26, 0.75);
}

/**
 * ★★ **语音播放器不许顶出气泡**（2026-10-08 截图看出来的）。
 *
 * ## 🚨 原来的样子
 * ```
 * `<audio controls>` 的**固有宽度是 300px**，而气泡最大只有屏宽的 78%
 * （390 屏 → 约 300px，再减去内边距 ⇒ 可用只有 274px 左右）。
 * ⚠️ 实测（截图）：那个播放条**从气泡右边顶出去了**，
 *    时间/音量那几个图标被切掉一块 —— 一眼就是"没做完"。
 * ```
 * ## ✅ 修法
 * ```
 * · `width: 100%` + `max-width: 100%` ⇒ 播放器占满**气泡可用宽度**，不溢出
 * · 图/视频的 `max-width: 100%`（`app.css` 里已有）保持不变 ——
 *   这里补的是**音频**（它没有 `max-width` 那条）。
 * ```
 * ⚠️ 改在 `manga.css` 里（而不是 `app.css`）是因为**这是看截图发现的**，
 *    而截图那一轮就是漫画主题 ⇒ 先在这里修稳，别动到极简主题的观感。
 *    真要说的话 `app.css` 里也该补 —— ⚠️ 但我**没有**极简主题的截图，
 *    没有证据就不动它（"没看到的问题"改了可能更糟）。
 */
html[data-ui='manga'] #screen-dm audio.dm-media {
  width: 100%;
  max-width: 100%;
}

/** 页脚那行小字（"你们俩的私聊 · 它看不到"）—— 别用默认灰，漫画里是墨色小字 */
html[data-ui='manga'] #screen-dm .ai-foot {
  background: var(--manga-paper, #fff);
  color: var(--manga-ink, #12151a);
  opacity: 0.72;
  border-top: 0;
}

/* ==========================================================================
   ★★★ **微信风格聊天页**（2026-10-08 深夜，用户要求）
   ==========================================================================

   ## 用户原话
   ```
   > 把聊天页面改成跟微信一样吧（真人私聊，AI聊天，群聊都改），
   > 这些聊天页的默认背景图（那四张随即切换的漫画图）都不要了，像微信那样就行
   > ────
   > 群聊要有头像和名字（和微信一样），私聊有头像就行
   > ────
   > AI聊天页这个聊天栏占太多屏幕了，搞成像微信那样
   ```

   ## ⚠️ 为什么写在这里、而且每条都带 `html[data-ui='manga'] #screen-xxx`
   ```
   🚨 **选择器优先级**：这个文件里已有的规则全是
        `html[data-ui='manga'] #screen-chat .row--in .bubble`（属性 + id + 类）
      ⇒ 我要是写 `.bubble--in` 那种短选择器，**会被它们盖住**，
        表现是"改了没生效"（而这个项目在 CSS 上已经栽过好几次）。
   ✅ 所以下面每条都**照抄它们的写法**（同长度 ⇒ 靠"后出现"赢）。
   ```

   ## 🎨 微信的配色（照抄，不是我自己调的）
   ```
   背景      #ededed（浅灰）
   对方气泡  #fff（白）      圆角 6px
   我的气泡  #95ec69（微信绿） 圆角 6px
   文字      #191919（近黑）
   头像      40px 圆角 5px（**不是正圆** —— 微信是圆角方块）
   🚨 **不要黑边、不要硬阴影**（那是上一个漫画风的东西）。
   ```
   ========================================================================== */

/* ---- ① 聊天页背景：清掉那四张漫画图（用户明确说"都不要了"） ---- */
html[data-ui='manga'] #screen-chat .chat-bg,
html[data-ui='manga'] #screen-chat > img.chat-bg {
  display: none !important;
}
html[data-ui='manga'] #screen-chat,
html[data-ui='manga'] #screen-dm,
html[data-ui='manga'] #screen-room {
  background: var(--wx-bg) !important;
  background-image: none !important;
}

/* ---- ② 气泡：白 / 微信绿，无边框无阴影 ---- */
html[data-ui='manga'] #screen-chat .row--in .bubble,
html[data-ui='manga'] #screen-chat .bubble--in,
html[data-ui='manga'] #screen-dm .dm-bubble,
html[data-ui='manga'] #screen-room .bubble--in {
  background: var(--wx-bubble-in);
  color: var(--wx-ink);
  border: 0;
  box-shadow: none;
  border-radius: var(--wx-r);
  border-bottom-left-radius: 2px;
  padding: 9px 12px;
  font-size: 15.5px;
  line-height: 1.5;
}
html[data-ui='manga'] #screen-chat .row--out .bubble,
html[data-ui='manga'] #screen-chat .bubble--out,
html[data-ui='manga'] #screen-dm .dm-row--out .dm-bubble,
html[data-ui='manga'] #screen-room .bubble--out {
  background: var(--wx-bubble-out);
  color: var(--wx-ink);
  border: 0;
  box-shadow: none;
  border-radius: var(--wx-r);
  border-bottom-right-radius: 2px;
  padding: 9px 12px;
  font-size: 15.5px;
  line-height: 1.5;
}

/* ---- ③ 头像：微信是 40px 圆角方块（不是正圆） ---- */
html[data-ui='manga'] #screen-chat .row-av,
html[data-ui='manga'] #screen-dm .dm-av,
html[data-ui='manga'] #screen-room .room-av {
  width: var(--wx-av);
  height: var(--wx-av);
  border-radius: var(--wx-av-r);
  border: 0;
  box-shadow: none;
  background: #dcdcdc;
  align-self: flex-start;
  cursor: pointer;
}

/* ---- ④ 群聊昵称：气泡**上方**、小灰字（微信就是这样） ---- */
/**
 * ★★★ **群聊那一列的排布**（2026-10-08 深夜加 —— 修「头像错位」）。
 *
 * ## 🚨 为什么要一个"列"包住昵称+气泡
 * ```
 * 原来昵称在 `.row-stack` **里面**，而 `.row-av` 是 `align-self: flex-start`
 * ⇒ 头像和"行里第一个东西（昵称）"的顶部对齐 ⇒
 *   **头像浮在气泡上方、昵称被气泡压住**（用户截图里就是这样）。
 * ✅ 现在：`row[ 头像, 列[ 昵称, stack[ 气泡, 时间 ] ] ]`
 *    ⇒ 头像和那一列的顶部对齐 = **和昵称的顶部对齐**？不，见下。
 * ⚠️ 关键在这一句：`align-items: flex-start` + 头像**给自己留一点上边距**，
 *    视觉上就落在"昵称和气泡之间" —— 微信正是这个观感（头像大致和气泡齐平）。
 * ```
 */
html[data-ui='manga'] #screen-room .row-col {
  display: flex;
  flex-direction: column;
  min-width: 0;
  max-width: 100%;
}
html[data-ui='manga'] #screen-room .row--in .row-col {
  align-items: flex-start;
}
html[data-ui='manga'] #screen-room .row--out .row-col {
  align-items: flex-end;
}
/**
 * ★★★ **头像对齐到气泡**（2026-10-08 深夜 —— 修「头像错位」，**几何量出来的**）。
 *
 * ## 🚨 实测的几何（`tools/probe-room-nav.mjs` 量出来的）
 * ```
 * row: display=flex flex-direction=row **align-items=flex-end**   ← app.css 的 .row--out 带的
 * room-av: order=0 align-self=flex-start margin-top=0px
 * ★ room-av 位置: left=247 top=71
 * ★ bubble  位置: left=295 top=93        ← 头像比气泡**高 22px**
 * ```
 * ## 🚨 根因：**行是 `align-items: flex-end`（底边对齐）**
 * ```
 * 头像和 `.row-col` **底边对齐** —— 而 `.row-col` 里装着"昵称 + 气泡 + 时间"，
 * 比气泡本身**高**（昵称那一行 ~17px）⇒ 头像被抬到气泡上方 ⇒ 看着就是"错位"。
 * ⚠️ `margin-top: 17px` 我加过，但**优先级不够**：
 *    `#screen-room .row--out .row-av`（0,4,1）盖住了 `#screen-room .row-av`（0,3,1）
 *    ⇒ 自己那条的 `margin-top` 被重置成 0。这次**两边都写**。
 * ```
 * ## ✅ 修法
 * ```
 * ① 行改成 **顶部对齐**（`align-items: flex-start`）——
 *    这样头像不再被"底边对齐"抬上去
 * ② 头像再加一点 `margin-top`，让它和**气泡**（而不是昵称）齐平
 *    ⚠️ 自己那条没有昵称 ⇒ 不要那个偏移
 * ```
 */
html[data-ui='manga'] #screen-room .row {
  align-items: flex-start;
}
html[data-ui='manga'] #screen-room .row-av,
html[data-ui='manga'] #screen-room .row--in .row-av,
html[data-ui='manga'] #screen-room .row--out .row-av {
  align-self: flex-start;
  /** 昵称那一行的高度（17px）+ 它下面那 3px 间距 ⇒ 头像和**气泡**齐平 */
  margin-top: 20px;
}
/** ⚠️ 自己发的那条**没有昵称** ⇒ 头像不该被推下去 */
html[data-ui='manga'] #screen-room .row--out .row-av {
  margin-top: 0;
}
/** ⚠️ 同时把"自己那条"的头像排到**右边**（DOM 顺序已经保证，这里是双保险） */
html[data-ui='manga'] #screen-room .row--out .room-av {
  order: 1;
}
html[data-ui='manga'] #screen-room .row--out .row-col {
  order: 0;
}
/** ⚠️ `.row-stack` 在 row 里时的老规则要失效（现在它在 `.row-col` 里面） */
html[data-ui='manga'] #screen-room .row-col > .row-stack {
  align-items: inherit;
}
html[data-ui='manga'] #screen-room .row-who {
  margin: 0 0 3px 2px;
  font-size: 12px;
  line-height: 17px;
  color: #8a8a8a;
  background: none;
  border: 0;
  padding: 0;
  font-weight: 400;
  text-align: left;
}
/** ⚠️ 自己发的那条**不建**昵称元素（见 app.js），这条是双保险 */
html[data-ui='manga'] #screen-room .row--out .row-who {
  display: none;
}

/* ---- ⑤ 列表区：微信是浅灰底、消息靠边 ---- */
html[data-ui='manga'] #screen-chat .list,
html[data-ui='manga'] #screen-dm .dm-list,
html[data-ui='manga'] #screen-room .room-list {
  background: var(--wx-bg);
}

/**
 * ★★★ **私聊：头像和气泡要【并排】**（2026-10-08 深夜加 —— 修「头像飘在气泡上面」）。
 *
 * ## 🚨 根因
 * ```
 * `.dm-row` 是 `flex-direction: column`（竖排）——
 * 我上一版把头像当第二个竖排项塞进去 ⇒ **头像自己占一整行**，
 *   看着就是"头像飘在上面、气泡间距被撑开"（用户第二张截图）。
 * ```
 * ## ✅ 修法：中间夹一层**横向**容器 `.dm-line`
 * ```
 * .dm-row（竖排） → .dm-line（**横排**：头像 + 气泡） → 时间
 * ⚠️ 这和 AI 聊天页的结构（`.row` 横排 + `.row-stack` 竖排）是**同一个思路** ——
 *    用户说"AI 聊天的就做对了"，那就照它来。
 * ```
 * ⚠️ **`.dm-row` 的 `align-items` 要跟着哪一侧走**：
 *    他的靠左、我的靠右（否则我发的那条会被对齐到左边）。
 */
html[data-ui='manga'] #screen-dm .dm-row {
  align-items: flex-start;
}
html[data-ui='manga'] #screen-dm .dm-row--out {
  align-items: flex-end;
}
html[data-ui='manga'] #screen-dm .dm-line {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 8px;
  max-width: 100%;
}
/** ⚠️ 头像别被 flex 压扁（圆角方块 + 固定尺寸） */
html[data-ui='manga'] #screen-dm .dm-av {
  flex: 0 0 auto;
  margin-top: 0;
}
/** 微信的观感：头像大致和气泡齐平（气泡有 9px 上内边距） */
html[data-ui='manga'] #screen-dm .dm-line {
  padding-top: 0;
}

/* ---- ⑥ 输入栏：压扁 + 更像微信（用户说这栏占太多了） ---- */
html[data-ui='manga'] #screen-chat .composer,
html[data-ui='manga'] #screen-dm .dm-form,
html[data-ui='manga'] #screen-room .composer {
  background: var(--wx-bar);
  border-top: 1px solid var(--wx-line);
  /** 🚨 原来是很大的内边距（漫画风要给黑边留位置）——微信几乎是贴着边的 */
  padding: 6px 10px calc(6px + env(safe-area-inset-bottom, 0px));
  gap: 4px;
  box-shadow: none;
}
/** ⚠️ 三处输入框统一：无黑边、浅底、小圆角 */
html[data-ui='manga'] #screen-chat .composer textarea,
html[data-ui='manga'] #screen-chat .composer input[type='text'],
html[data-ui='manga'] #screen-chat #input,
html[data-ui='manga'] #screen-dm #dm-input,
html[data-ui='manga'] #screen-room #room-input {
  background: #fff;
  border: 0;
  box-shadow: none;
  border-radius: 6px;
  padding: 7px 10px;
  font-size: 15px;
  min-height: 34px;
}
/**
 * ★★★ **最后再压一轮**（2026-10-09 —— 用户说「AI 聊天页这个聊天栏占太多屏幕了」）。
 *
 * ## 实测（`tools/probe-composer-size.mjs` 量的，不是感觉）
 * ```
 * 最初：                AI **69px / 8.2%**（`.media-bar` 自己占 52px）
 * 上一轮（键 30→26px）：AI **67px / 7.9%**
 * ```
 * ## 🚨 为什么还要压：**输入框和媒体条是【两行】**
 * ```
 *   [ 输入框 34px ]
 *   [ 媒体键 4 个 + 发送键 ]   ← 又一行
 * ⇒ 两行加起来 67px。微信其实也是两行，但它每行都更矮（输入框 ~32、键 ~28）。
 * ```
 * ## ✅ 这一轮
 * ```
 * · 输入框 34 → **32px**
 * · 媒体条**高度限死 34px**（原来键 26px 但条子 50px —— 多出来的都是留白）
 * · 发送键 30 → **28px**
 * ⇒ 预期 67 → ~56px（约 6.6%）
 * ⚠️ **这就是下限了**：28px 的键已经是"手指点得到"的边缘，
 *    再小会"点不中" —— 那比"占地方"更让人烦。
 * ```
 */
html[data-ui='manga'] #screen-chat .send-form textarea.input,
html[data-ui='manga'] #screen-chat .send-form input.input {
  background: #fff;
  border: 0;
  box-shadow: none;
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 15px;
  min-height: 32px;
  max-height: 32px;
  line-height: 20px;
}
html[data-ui='manga'] #screen-chat .media-bar {
  height: 34px;
  min-height: 34px;
  align-items: center;
}
html[data-ui='manga'] #screen-chat #btn-send {
  width: 28px;
  height: 28px;
  min-width: 28px;
}
/** ⚠️ 合规小字**不能删**（"本服务内容由 AI 生成，非真人"）—— 只压字号 */
html[data-ui='manga'] #screen-chat .legal,
html[data-ui='manga'] #screen-dm .legal,
html[data-ui='manga'] #screen-room .legal {
  font-size: 10px;
  padding: 2px 0;
}

/** ⚠️ 媒体键那一行**压到最小**（它原来是独立一行、很占地方） */
html[data-ui='manga'] #screen-chat .media-bar,
html[data-ui='manga'] #screen-dm .dm-tools {
  gap: 2px;
  margin: 0;
}
/**
 * ★★★ **再压一轮**（2026-10-09 —— 用户说「AI 聊天页这个聊天栏占太多屏幕了」）。
 *
 * ## 实测（`tools/probe-composer-size.mjs` 量的）
 * ```
 * 压之前：AI 聊天页 **69px／8.2%**（其中 `.media-bar` 自己占 52px）
 *         私聊页   **50px／6%**
 * 🚨 AI 那栏比私聊高 19px —— 差在**媒体键那一行**（4 个键 × 30px + 上下留白）。
 * ```
 * ## ✅ 这一轮
 * ```
 * 媒体键 30 → **26px**，发送键 32 → **30px**，输入框 min-height 34 → **32px**
 * ⇒ 加起来省 ~10px（约 1.2% 屏高）。
 * ⚠️ **再小就不行了**：26px 已经是"手指点得到"的下限（iOS HIG 建议 44px、
 *    但聊天栏这种高频按钮 26~28px 在实际使用里是可接受的，
 *    而再小就会"点不中"——那比"占地方"更烦人）。
 * ⚠️ **合规小字不能删**（"本服务内容由 AI 生成，非真人"）—— 它是硬要求，
 *    只压了字号，没动它。
 * ```
 */
html[data-ui='manga'] #screen-chat .media-bar .round-btn,
html[data-ui='manga'] #screen-dm .dm-tool,
html[data-ui='manga'] #screen-room .composer .round-btn {
  width: 26px;
  height: 26px;
  min-width: 26px;
  border: 0;
  box-shadow: none;
  background: transparent;
  color: #5a5a5a;
}
/** 发送键：微信那个绿色小圆（不是黑边大圆） */
html[data-ui='manga'] #screen-chat #btn-send,
html[data-ui='manga'] #screen-dm .btn-send,
html[data-ui='manga'] #screen-room .composer .round-btn--accent {
  width: 30px;
  height: 30px;
  min-width: 30px;
  border: 0;
  box-shadow: none;
  background: var(--wx-bubble-out);
  color: #191919;
}
/** 那行法律小字（**不能删** —— 合规硬要求），但可以小到不占眼 */
html[data-ui='manga'] #screen-chat .ai-inline,
html[data-ui='manga'] #screen-dm .ai-foot,
html[data-ui='manga'] #screen-room .ai-inline {
  font-size: 10px;
  margin: 0;
  padding: 2px 0;
  opacity: 0.5;
  background: transparent;
  border: 0;
}

/* ---- ⑦ 放大查看浮层（三种聊天页 + 个人主页共用） ---- */
.lb {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.92);
  /** ⚠️ 吃掉触摸 —— 不然"看图的时候背景页面还在滚" */
  touch-action: none;
}
.lb[hidden] { display: none; }
.lb-body {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 44px 8px 40px;
}
.lb-media {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 4px;
}
.lb-x {
  position: absolute;
  top: calc(8px + env(safe-area-inset-top, 0px));
  right: 12px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 0;
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}
.lb-cap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  margin: 0;
  text-align: center;
  color: rgba(255, 255, 255, 0.85);
  font-size: 13px;
}
.lb-cap[hidden] { display: none; }

/* ---- ⑧ 群聊的"拉人"键 + 成员数（2026-10-08 深夜） ---- */
html[data-ui='manga'] #screen-room .room-invite {
  width: 22px;
  height: 22px;
  min-width: 22px;
  margin-left: 6px;
  border-radius: 50%;
  border: 0;
  background: var(--wx-bubble-out);
  color: #191919;
  font-size: 16px;
  line-height: 1;
  font-weight: 600;
  cursor: pointer;
  vertical-align: middle;
}
html[data-ui='manga'] #screen-room .room-count {
  margin-left: 6px;
  font-size: 12px;
  color: #8a8a8a;
}
html[data-ui='manga'] #screen-room .room-count[hidden],
html[data-ui='manga'] #screen-room .room-invite[hidden] {
  display: none;
}
/** "拉谁进群"那个浮层 */
.invite-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 8000;
  max-height: 70vh;
  overflow-y: auto;
  background: #fff;
  border-radius: 12px 12px 0 0;
  box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.18);
  padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
}
.invite-sheet .friend-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid #f0f0f0;
  font-size: 15px;
  cursor: pointer;
}
.invite-sheet .friend-row input {
  width: 18px;
  height: 18px;
}
.invite-sheet > .btn {
  margin: 10px 14px;
  width: calc(100% - 28px);
}

/* 微信那几个颜色/尺寸提成变量（后面要调只改这里） */
html[data-ui='manga'] {
  --wx-bg: #ededed;
  --wx-bar: #f7f7f7;
  --wx-line: #dcdcdc;
  --wx-bubble-in: #ffffff;
  --wx-bubble-out: #95ec69;
  --wx-ink: #191919;
  --wx-r: 6px;
  --wx-av: 40px;
  --wx-av-r: 5px;
}
/* ==========================================================================
   ★★★ 「消息」那一屏 + 底部角标（2026-10-09 加）
   --------------------------------------------------------------------------
   用户原话：
     > 即使不在app也要能收到信息，还有动态被点赞或评论会收到信息
     > （**单独加个消息键**）

   ⚠️ 样式跟着**微信那一套变量**（`--wx-*`）走 —— 别自己再定一套颜色，
      不然这一屏会和聊天页"不像一个 App"。
   ⚠️ 角标**只在有未读时显示**（`hidden` 由 JS 控制）——
      显示 "0" 会被当成"有新消息"。
   ========================================================================== */
html[data-ui='manga'] .tab-badge {
  position: absolute;
  top: 2px;
  left: 50%;
  margin-left: 2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;
  /** ⚠️ 微信那种红**不是纯红**（#fa5151），纯红在浅底上太刺眼 */
  background: #fa5151;
  color: #fff;
  font-size: 10.5px;
  line-height: 16px;
  font-weight: 600;
  text-align: center;
  box-sizing: border-box;
}
/** ⚠️ tab 要是 `position: relative`，否则角标会跑到屏幕角上（那个 `absolute` 会往上找定位祖先） */
html[data-ui='manga'] .tabbar .tab,
#tabbar .tab {
  position: relative;
}

html[data-ui='manga'] .notif-list {
  display: flex;
  flex-direction: column;
  background: var(--wx-bubble-in, #fff);
  border-radius: var(--wx-r, 6px);
  overflow: hidden;
}
html[data-ui='manga'] .notif-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  padding: 12px 13px;
  border: 0;
  border-bottom: 1px solid var(--wx-line, #dcdcdc);
  background: transparent;
  text-align: left;
  cursor: pointer;
  color: var(--wx-ink, #191919);
}
/** ⚠️ 最后一行不要那条分隔线（不然列表底部多一条悬空的线） */
html[data-ui='manga'] .notif-row:last-child {
  border-bottom: 0;
}
/** ⚠️ **未读的要有区别**（不然"哪些是新的"完全看不出来）—— 用左侧一个小圆点 */
html[data-ui='manga'] .notif-row.is-unread {
  background: #f2f8ff;
}
html[data-ui='manga'] .notif-row.is-unread .notif-title {
  font-weight: 700;
}
html[data-ui='manga'] .notif-ic {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--wx-bg, #ededed);
  font-size: 14px;
  line-height: 28px;
  text-align: center;
}
/** ⚠️ 点赞用红色、评论用蓝色 —— 一眼区分类型（不用读文字） */
html[data-ui='manga'] .notif-row[data-kind='like'] .notif-ic {
  color: #fa5151;
}
html[data-ui='manga'] .notif-row[data-kind='comment'] .notif-ic {
  color: #576b95;
}
html[data-ui='manga'] .notif-main {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  flex: 1 1 auto;
}
html[data-ui='manga'] .notif-title {
  font-size: 14.5px;
  line-height: 1.35;
}
html[data-ui='manga'] .notif-body {
  font-size: 13px;
  color: #7a7a7a;
  /**
   * ⚠️ **最多两行**（`-webkit-line-clamp`）——
   *    不限制的话长消息会把一条通知撑得很高，一屏只看得到两三条。
   */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}
html[data-ui='manga'] .notif-when {
  font-size: 11px;
  color: #9a9a9a;
}

/* ==========================================================================
   ★★★ **统一的聊天输入栏（微信那套）**（2026-10-09 重写）
   --------------------------------------------------------------------------
   用户原话：
     > 先把群聊，AI聊天，和真人私聊这些页面**全部统一**，不要分开打补丁了，
     > 包括**输入栏和顶上的信息栏**都改掉，参考后图（4~9），
     > **语音和表情包功能放聊天栏里**，其他的整合放 **＋** 这个键里，
     > **发emoji这个是没有的，加上**。

   ## 🚨 这一块是"一份结构、三处复用"（见 `renderChatComposer`）
   ```
   所以这里**只写一套选择器**（不带 #screen-xxx 前缀）——
   ⚠️ 带了前缀就等于又分三份了（那正是要消灭的东西）。
   ```
   ## ⚠️ 三条硬要求（都踩过）
   ```
   ① 输入栏高度**写死 34px 那一档**（微信那栏约 50px，占屏 6%）
   ② 输入框 `max-height` 要留出来，长句不能被截断（最多 4 行）
   ③ 合规小字（"本服务内容由 AI 生成，非真人"）**不能删、不能折叠**
   ```
   ========================================================================== */
.chat-composer {
  flex: 0 0 auto;
  padding: 6px 8px calc(6px + env(safe-area-inset-bottom, 0px));
  background: var(--wx-bar, #f7f7f7);
  border-top: 1px solid var(--wx-line, #dcdcdc);
}
.chat-composer-bar {
  display: flex;
  align-items: flex-end;
  gap: 6px;
}
/** 两端的圆形键（语音 / 表情 / @ / ＋-发送） */
.chat-composer .cc-round {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  min-width: 30px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: #5a5a5a;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.chat-composer .cc-round.is-on {
  background: #e3e3e3;
  color: #111;
}
/** 输入框：微信那种"白底、圆角、没有黑边" */
.chat-composer .cc-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 34px;
  max-height: 96px;
  padding: 7px 10px;
  border: 0;
  border-radius: 6px;
  background: #fff;
  color: var(--wx-ink, #191919);
  font-size: 15px;
  line-height: 20px;
  font-family: inherit;
  resize: none;
  outline: none;
  box-sizing: border-box;
}
/** "按住 说话"那个键（点语音键换上来） */
.chat-composer .cc-hold {
  flex: 1 1 auto;
  min-height: 34px;
  border: 0;
  border-radius: 6px;
  background: #fff;
  color: #333;
  font-size: 15px;
  font-family: inherit;
  cursor: pointer;
}
.chat-composer .cc-hold.is-holding {
  background: #e3e3e3;
}
/**
 * 右边那个键：**空着是 ＋、打字变发送**（微信就是这个行为）。
 * ⚠️ 发送态用微信那个绿（`--wx-bubble-out`），和气泡一个色系。
 */
.chat-composer .cc-send {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  min-width: 32px;
  border: 0;
  border-radius: 50%;
  background: #95ec69;
  color: #fff;
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
}
/** ＋ 那个形态：**灰底、深色字**（不是绿色 —— 它还不是"发送"） */
.chat-composer .cc-send.is-plus {
  background: #e8e8e8;
  color: #444;
  font-size: 20px;
  font-weight: 400;
}
.chat-composer .cc-send:disabled {
  opacity: 0.5;
}

/* ---- 三个浮层面板（表情 / ＋ / @）：都是底部弹层 ---- */
.chat-panel {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  /** ⚠️ 要压过底部 tab（那是 30 左右）和导航条 */
  z-index: 320;
  background: #f7f7f7;
  border-top: 1px solid #dcdcdc;
  border-radius: 12px 12px 0 0;
  box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.12);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  max-height: 62vh;
  display: flex;
  flex-direction: column;
}
.chat-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 12px 4px;
  font-size: 12.5px;
  color: #8a8a8a;
}
/** ★ 表情面板：最近使用 + 所有表情 */
.chat-emoji-scroll {
  overflow-y: auto;
  padding: 0 8px 6px;
}
.chat-emoji-h {
  margin: 6px 4px 4px;
  font-size: 12px;
  color: #9a9a9a;
}
.chat-emoji-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 2px;
}
.chat-emoji-btn {
  border: 0;
  background: transparent;
  font-size: 22px;
  line-height: 1.5;
  padding: 2px 0;
  cursor: pointer;
  border-radius: 6px;
}
.chat-emoji-btn:active {
  background: #e3e3e3;
}
.chat-emoji-foot {
  border-top: 1px solid #e3e3e3;
  padding: 6px 10px 8px;
  display: flex;
  justify-content: flex-end;
}
.chat-emoji-back {
  width: 44px;
  height: 30px;
  border: 0;
  border-radius: 6px;
  background: #ececec;
  font-size: 16px;
  cursor: pointer;
}
/** ★ ＋ 那个扩展面板：一屏 8 个（照用户给的微信截图） */
.chat-extend-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px 0;
  padding: 14px 10px calc(16px + env(safe-area-inset-bottom, 0px));
}
.chat-extend-item {
  border: 0;
  background: transparent;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  font-family: inherit;
}
.chat-extend-ic {
  width: 54px;
  height: 54px;
  border-radius: 14px;
  background: #fff;
  display: grid;
  place-items: center;
  font-size: 24px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}
.chat-extend-lb {
  font-size: 12px;
  color: #5a5a5a;
}
/**
 * ⚠️ **还没做的那几项要看得出来**（不然用户点了只弹一句"还没做"会更迷惑）——
 *    灰一点、而且**不假装它能用**。
 */
.chat-extend-item.is-todo .chat-extend-ic {
  opacity: 0.55;
}
.chat-extend-item.is-todo .chat-extend-lb {
  color: #a8a8a8;
}
/** ★ @ 面板：列群成员，点谁 @ 谁 */
.chat-at-list {
  overflow-y: auto;
  padding: 4px 8px calc(10px + env(safe-area-inset-bottom, 0px));
}
.chat-at-row {
  display: block;
  width: 100%;
  padding: 11px 10px;
  border: 0;
  border-bottom: 1px solid #e6e6e6;
  background: transparent;
  text-align: left;
  font-size: 15px;
  color: var(--wx-ink, #191919);
  cursor: pointer;
  font-family: inherit;
}
.chat-at-row:last-child {
  border-bottom: 0;
}
.chat-at-empty {
  margin: 10px;
  font-size: 13px;
  color: #8a8a8a;
}
