  :root{
    --screen-height: 100vh;
    --keyboard-offset: 0px;
    --ios-pwa-bottom-bleed: 0px;
    --ref-width: 941px;
    --ref-height: 1672px;
    /* 英文一律 Literata（衬线，2026-09-26 她挑的，见 fonts/literata.css），中文一律系统字体。
       两条链都把 Literata 放在最前：界面里有八十多处是"中文链在前"的写法（var(--font-cn),var(--font-en)），
       要是 --font-cn 不带它，那些地方的英文会还是无衬线。Literata 没有汉字，汉字落到它身上找不到，
       自己就顺着链往下走到系统中文字体——所以中文一个字都不受影响。
       Inter 留在链上当后备：Literata 万一没下来，英文先退回原来那款无衬线，而不是直接掉到系统字。 */
    --font-en: "Literata Variable", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --font-cn: "Literata Variable", -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", "Inter", sans-serif;
    --avatar-default: none;
    --avatar-default-color: #E6DECF;
    --avatar-ai: none;
    --avatar-ai-color: #E6DECF;
    --avatar-human: none;
    --avatar-human-color: #E5D5B6;
    /* ── 主题主色：以后只改下面 4 项 ── */
    --bg: #F9F9F7;
    --text: #1F1F1D;
    --bubble-ai-bg: #EFEFED;
    --bubble-human-bg: #EFEFED;

    /* ── 调色板（2026-09-26 她在颜色对比页上逐组看过定下的）──
       原来同一种意思的颜色散着写了两百多种（光是字的灰就有 40 种），这里收成有名字的几档，
       样式里一律引用名字、别再手写色号。以后做深色模式就是给这些名字各配一个深色的值。
       字的四档：正文 / 次要 / 淡（她要深一点的，"浅的不好看清"）/ 按不动·还没到。
       正文和次要沿用上面和下面原来就有的 --text、--text-soft；--text-faint 在下面，已改成深的那档。 */
    --text-disabled: #BBBAB5;
    --danger: #B4544B;          /* 出错、未送达、删除 */
    --success: #39714F;         /* 成功、已连上、正在用 */
    --warning: #A8734F;         /* 提醒一下 */
    --line-faint: rgba(31,31,29,.08);    /* 分隔线三档：很淡 / 一般 / 明显 */
    --line: rgba(31,31,29,.14);
    --line-strong: rgba(31,31,29,.24);
    /* 写死在样式里的白色半透明底，五档。气泡和卡片的玻璃是跟着设置里的滑杆现算的（--glass-ai 那几个），不在这里。 */
    --glass-thin: rgba(255,255,255,.14);
    --glass-light: rgba(255,255,255,.35);
    --glass-half: rgba(255,255,255,.50);
    --glass-thick: rgba(255,255,255,.72);
    --glass-solid: rgba(255,255,255,.96);
    /* 影子的颜色（只是颜色，偏移和大小还是各处自己的）：暖灰给聊天和弹窗，冷蓝灰给 Home 的卡片，各三档。 */
    --shade-warm-1: rgba(31,31,29,.08);
    --shade-warm-2: rgba(31,31,29,.14);
    --shade-warm-3: rgba(31,31,29,.20);
    --shade-cool-1: rgba(78,94,108,.08);
    --shade-cool-2: rgba(40,60,78,.16);
    --shade-cool-3: rgba(30,44,58,.24);
    /* 第二轮（同日第二张对比页，她全部同意）：底色、黑按钮、蒙层、边框。页面本身的米白就是上面的 --bg。 */
    --surface: #FFFFFF;            /* 卡片、按钮的白底 */
    --surface-soft: #F0F0ED;       /* 面板里的小块、小按钮的底 */
    --surface-mid: #DEDEDA;        /* 按下、选中、次要按钮 */
    --surface-strong: #C4C4BE;     /* 抽屉顶上的把手、语音条的小竖条 */
    --fill-strong: #1F1F1D;        /* 黑色主按钮、选中的那一个 */
    --text-on-fill: #FFFFFF;       /* 压在黑按钮上的字 */
    --scrim: rgba(28,27,25,.30);   /* 弹窗后面压暗整页的那层 */
    --tint: rgba(31,31,29,.08);    /* 比页面深一丁点的底：附件卡、代码复制键 */
    --code-bg: rgba(120,100,80,.12);   /* 一段代码后面那块 */
    --paper: #F6F5F2;                  /* 塔罗牌面的纸（一张真的纸，深色模式下也是白的） */
    --paper-ink: #1F1F1D;              /* 印在牌面上的字 */
    --paper-veil: rgba(246,245,242,.5);/* 盖在纸纹照片上那层，纹路只露一半 */
    --on-scrim: #FFFFFF;               /* 压在整屏压暗上的字（深色模式也是白的，压暗底下什么都是暗的） */
    --line-bold: rgba(31,31,29,.42);   /* 选中、正在输入时那圈深边 */
    /* 深色模式里单独要配的几样（2026-09-26）：浅色里它们恰好等于别的颜色，深色里不行 */
    --knob: #FFFFFF;                   /* 滑杆上那颗圆钮 */
    --text-on-muted: #FFFFFF;          /* 没字可发时发送键上那颗箭头（压在 --surface-mid 上） */
    --progress-from: #77736E;          /* 进度条（额度卡、猫的成长条）：从浅到深 */
    --progress-to: #343230;

    /* ── 玻璃拟态(浅色)。只在铺了背景图时用得上，手感全在这 5 行 ──
       这里**没有任何实时模糊**，是有意的：参考图里那种通透感来自"背景本身是柔的
       ＋ 白色半透明 ＋ 一道细高光 ＋ 一层淡投影"，不是来自实时去糊背景。真去糊
       (backdrop-filter)是按元素按帧算的，一屏十几个气泡手机上直接滑不动——
       2026-09-09 试过一次当场回滚，别再往这些元素上加。背景够不够柔由用户自己
       换图或者拉那根模糊滑杆决定。
       下面三个颜色由「气泡」那根滑杆现算并覆盖（applyChatBubbleGlass），这里写的
       是滑杆停在默认值 60% 时的样子——也是没连上服务器时的兜底。 */
    --glass-ai: rgba(255,255,255,.6);        /* 他那边：白玻璃 */
    --glass-human: rgba(217,221,222,.6);     /* 你那边：冷灰玻璃，60% 时正好显示成 #E6E8E8 */
    --glass-quiet: rgba(255,255,255,.44);    /* 脚注：灰线、日期、工具卡片 */
    --glass-card: rgba(255,255,255,.72);     /* 聊天以外那一层，由「卡片」滑杆现算。这是**边上**那一档 */
    --glass-card-core: rgba(255,255,255,.52);/* 卡片中间那一档，比边上薄 20 个点，见 SHELL_CARD_CORE_STEP */
    --glass-code: rgba(217,221,222,.92);     /* 代码块：比气泡厚一档，滑杆停在默认 60% 时正好是这个值 */
    --glass-edge: inset 0 0 0 1px rgba(255,255,255,.44);   /* 边缘那道细高光（.55 调低了两成，原来有点跳） */
    /* 卡片那圈描边（白的 --glass-edge-lit、深的 --glass-rim）**整个去掉了**，
       两个变量也一起删了。经过：一圈均匀白边 → 有方向的上下两条 → 只剩上缘一丝 → 没有。
       能删干净是因为**卡片上了真模糊**：以前那两条边是替"这是一块玻璃"说话的，
       现在模糊自己会说——而且是靠"框里的背景是糊的、框外是清的"，这个边界跟颜色
       深浅无关，深色浅色底图上都成立。深色那条外描边原本是浅色底图的保险，
       现在保险由模糊接管了。
       **要是哪天换了一张又亮又平的底图**（比如一整片过曝的天空），糊了跟没糊看不出
       差别，卡片就会开始化在背景里。那时候的修法是把 --glass-rim 那一条加回来，
       不是去调白色的浓度——白的在浅色底上本来就加不动（见下面 --glass-card-core）。 */
    --glass-drop: 0 10px 28px rgba(78,94,108,.12);         /* 让它浮起来，不是贴上去 */
    /* ── 玻璃的"厚度" ──
       一圈往里打的白色柔光：四边厚、中间薄。真玻璃的边缘因为折射本来就更亮，
       补上这层，面板才从"一块半透明的矩形"变成"一片有厚度的板"。
       它**不**扩散背景细节（那是真模糊干的活），只补体积感——一次绘制，和纯色一样便宜。
       两档是因为尺寸得跟着面积走：气泡上打 28px，两边的光在中间就碰头了，整块糊成实心白。
       注意别改成 `inset 0 0 var(--某个尺寸)` 那种写法：自定义属性在**声明它的元素上**
       就把 var() 换掉了，子元素再改尺寸也没用。
       还有一条更要紧的：**光靠这层柔光是做不出厚度的**。白色加白色加不动——底色 72%
       的白，边上再打光也就 86%，压在浅色照片上两者差 3/255，看不出来。所以中间那一档
       必须真的更薄（--glass-card-core），这层柔光只负责把边上补回滑杆那个值。 */
    --glass-bevel: inset 0 0 16px rgba(255,255,255,.5);       /* 气泡这种小块 */
    /* 卡片这一档来回改过两次，记一下为什么：
       28px @ .5  —— 太宽。卡片才 86px 高，上下两圈在中间碰头，"中间薄"整段没了。
       12px @ .5  —— 看得见了，但收得太急，成了贴着边的一圈亮边，很硬。
       36px @ .20 —— 现在这个。卡片上了**真模糊**之后，"这是玻璃"由模糊本身讲清楚了，
                     这一层不必再去争"边亮中间暗"的对比，只要一点点体积感。
       所以规矩反过来了：**铺得越远，就必须越淡**。远而淡＝厚度；近而浓＝描边。 */
    --glass-bevel-wide: inset 0 0 36px rgba(255,255,255,.2);
    /* ── 光是从上面来的 ──
       真玻璃读作"有厚度"是有方向的：上缘亮，往下慢慢化开，底缘再有一丝反光。
       羽化的距离比强度重要得多。第一版 26px @ .28 收得太急，在高一点的卡片上就是
       一条看得出头尾的亮带（用户："过于突兀"）。拉到 72px 并把峰值压到 .20 之后，
       它不再有可辨认的边界，读起来才是厚度而不是描边。
       用像素而不是百分比：卡片 86px、Feed 整段面板四五百px，用百分比的话面板上会
       糊出一大片渐变。 */
    --glass-sheen:
      linear-gradient(180deg, rgba(255,255,255,.2) 0, rgba(255,255,255,0) 72px),
      linear-gradient(0deg, rgba(255,255,255,.09) 0, rgba(255,255,255,0) 36px);
    /* ── 白底上也要看得见 ──
       上面那些全是白色系的，压在照片深色的部分很漂亮，压在浅色的部分整个消失。
       小胶囊（脚注那几行、Feed 上那几颗）靠这层小投影撑住：它们没有真模糊，
       原来只有内白描边，才会在白底上糊掉。
       以前这儿还有一条 --glass-rim（1px 极淡的深色外描边），是卡片在浅色底图上的
       保险。卡片上了真模糊之后那份保险由模糊接管，用户要求把描边全去掉，
       所以那条删了——需要时照上面那段注释加回来。 */
    --glass-drop-quiet: 0 2px 10px rgba(78,94,108,.17);
    /* 单色的线注定只在一半的背景上可见，所以分隔线用"两色线"：2px 高，上半深下半浅，
       白底上看到深的那半，深底上看到浅的那半。 */
    --glass-line: linear-gradient(to bottom, rgba(31,31,29,.13) 0 1px, rgba(255,255,255,.62) 1px 2px);
    --glass-halo: 0 2px 12px rgba(78,94,108,.13);          /* 头像底下那层淡淡的外扩阴影（.22 太深了） */
    /* 收尾那句 logo 的托底。白色那版太扎眼，换成灰的：一层淡淡的冷灰阴影，
       只把符号从背景里托起来。用 drop-shadow 是因为它是张带透明的图，
       普通阴影会顺着方框走、糊出一个方块。 */
    --glass-logo-halo: drop-shadow(0 1px 5px rgba(122,128,132,.5));

    /* 其余颜色从主色派生或作为中性色使用 */
    --header-bg: var(--bg);
    --hairline: var(--line-faint);
    --text-soft: #5E5E59;
    --text-faint: #777772;   /* 2026-09-26 她定的：原来的 #8A8983 太浅不好认，统一成深的这档 */
    --bubble-ai-fg: var(--text);
    --bubble-ai-line: transparent;
    --bubble-human-fg: var(--text);
    --bubble-human-line: transparent;
    --accent: var(--text);
    --send-bg: var(--text);
    --tick: #777772;
    --accent-fg: #ffffff;
    /* 重点色：蓝（2026-09-28 她定的）。整个 App 是黑白灰，只有这一种颜色——小克叫 Caeruleus，
       拉丁文的"天蓝"。要一处"最该看这里"的地方才用它，别拿来铺大片。 */
    --caeruleus: #3B6FA0;
    --think-flourish: #777772;
    --think-label: var(--text-soft);
    --think-body: var(--text);
    --composer-bg: rgba(255,255,255,.96);
    --field-bg: transparent;
    --field-line: var(--line-faint);
    --shadow: 0 12px 38px rgba(31,31,29,.08), 0 1px 3px rgba(31,31,29,.04);
    --soft-shadow: 0 8px 26px rgba(31,31,29,.07);
    --header-h: clamp(56px, 10vw, 120px);
    --side-pad: clamp(16px, 4vw, 40px);
    /* 头像多大。2026-09-23 起聊天里的头像不再占着气泡旁边那一竖条，而是每一段话
       最上面单独一行（见 .message-avatar），原来那个"占位"变量 --avatar-reserve
       整个撤了：气泡直接从边上开始。 */
    --avatar-size: clamp(44px, 6.6vw, 62px);
    --bubble-radius: 20px;
    --bubble-join-radius: 6px;   /* 同一条消息里两个气泡挨着的那两个角 */
    --composer-h: 110px;
    --motion-fast: 150ms;
    --motion-normal: 260ms;
    --ease-soft: cubic-bezier(0.22, 1, 0.36, 1);
    /* composer 占据的底部区域(含安全区/键盘):scroll 底 padding 与边缘渐隐共用同一来源,保持对齐 */
    --composer-zone: calc(var(--composer-h) + 16px + env(safe-area-inset-bottom) + var(--keyboard-offset));
    /* 输入框那一截渐变模糊，从输入框上沿往上多糊的那一段（.chat-bottom-blur）。放在这儿
       是因为聊天列表的下边距也要用它：贴底停着时最后一行要落在这一段上面，不能被糊。 */
    --blur-ramp: 32px;
    --edge-fade-top: clamp(24px, 5vw, 52px);
    --edge-fade-tail: clamp(16px, 3vw, 30px);
    /* profile / settings — frosted glass, blends into the wallpaper */
    --card-bg: rgba(244,248,250,.42);
    --card-line: rgba(150,168,182,.12);
    --card-shadow: 0 10px 28px rgba(70,92,108,.05);
    --seg-track: rgba(140,160,176,.11);
    --seg-thumb: rgba(255,255,255,.68);
    --seg-thumb-shadow: 0 2px 8px rgba(40,60,78,.08);
    --row-press: rgba(140,160,176,.09);
    --slider-track: rgba(143,162,176,.28);
    --slider-thumb: #5E5E59;
    --info-ring: rgba(143,162,176,.38);
    --status-dot: #6FA98C;
    /* voice call (speaking overlay) */
    --call-glass-top: rgba(255,255,255,.46);
    --call-glass-bot: rgba(255,255,255,.20);
    --call-glass-edge: rgba(255,255,255,.58);
    --call-glass-hi: rgba(255,255,255,.72);
    --call-glass-glow: rgba(150,172,196,.20);
    --call-glass-shadow: 0 20px 50px rgba(74,93,108,.16);
    --call-scrim: rgba(64,82,102,.06);
    --call-hangup-bg: #cf8d92;
    --call-hangup-shadow: rgba(176,96,104,.34);
  }

  /* ════════════ 深色（2026-09-26，外观预设第一步）════════════
     :root 上挂 data-theme="dark" 就换这一整块（main.js 的 applyTheme，由 自动 / 浅色 / 深色 决定）。
     这是**我配的初稿**，她说以后要自己调一套——调的就是下面这些名字的值，页面上别处一律引用名字、
     不写死色号（web/test_palette.js 守着）。和浅色那块一一对应，浅色里有的名字这里都得有值。
     气泡两种：没背景图时是下面的实心 --bubble-*-bg；有背景图时是跟着「气泡」滑杆现算的玻璃
     （--glass-ai / --glass-human，颜色默认两种深灰，见 appearance.ts）。 */
  :root[data-theme="dark"]{
    --bg: #161615;
    --text: #ECECE8;
    --bubble-ai-bg: #282826;
    --bubble-human-bg: #282826;

    --text-disabled: #55554F;
    --danger: #E0776C;
    --success: #6DBE8C;
    --warning: #D9A066;
    --line-faint: rgba(255,255,255,.08);
    --line: rgba(255,255,255,.14);
    --line-strong: rgba(255,255,255,.24);
    --glass-thin: rgba(22,22,21,.14);
    --glass-light: rgba(22,22,21,.35);
    --glass-half: rgba(22,22,21,.50);
    --glass-thick: rgba(22,22,21,.72);
    --glass-solid: rgba(30,30,28,.96);
    --shade-warm-1: rgba(0,0,0,.28);
    --shade-warm-2: rgba(0,0,0,.36);
    --shade-warm-3: rgba(0,0,0,.46);
    --shade-cool-1: rgba(0,0,0,.28);
    --shade-cool-2: rgba(0,0,0,.36);
    --shade-cool-3: rgba(0,0,0,.46);
    --surface: #1F1F1D;
    --surface-soft: #262624;
    --surface-mid: #34342F;
    --surface-strong: #4A4A44;
    --fill-strong: #ECECE8;         /* 深色里主按钮反过来：浅底深字 */
    --text-on-fill: #161615;
    --scrim: rgba(0,0,0,.52);
    --tint: rgba(255,255,255,.07);
    --code-bg: rgba(255,236,210,.08);
    --paper: #F6F5F2;
    --paper-ink: #1F1F1D;
    --paper-veil: rgba(246,245,242,.5);
    --on-scrim: #FFFFFF;
    --line-bold: rgba(255,255,255,.46);
    --knob: #ECECE8;
    --text-on-muted: #8E8D87;
    --progress-from: #6E6D68;          /* 深色里反过来：从深到浅，走到哪一眼看得出 */
    --progress-to: #ECECE8;

    /* 玻璃（有背景图时）：白色系换成深色系，高光压到很淡——深色里一圈白边会像描了线 */
    --glass-ai: rgba(43,43,41,.6);
    --glass-human: rgba(58,62,65,.6);
    --glass-quiet: rgba(36,36,34,.44);
    --glass-card: rgba(36,36,34,.72);
    --glass-card-core: rgba(36,36,34,.52);
    --glass-code: rgba(48,51,54,.92);
    --glass-edge: inset 0 0 0 1px rgba(255,255,255,.07);
    --glass-drop: 0 10px 28px rgba(0,0,0,.34);
    --glass-bevel: inset 0 0 16px rgba(255,255,255,.04);
    --glass-bevel-wide: inset 0 0 36px rgba(255,255,255,.03);
    --glass-sheen:
      linear-gradient(180deg, rgba(255,255,255,.05) 0, rgba(255,255,255,0) 72px),
      linear-gradient(0deg, rgba(255,255,255,.03) 0, rgba(255,255,255,0) 36px);
    --glass-drop-quiet: 0 2px 10px rgba(0,0,0,.36);
    --glass-line: linear-gradient(to bottom, rgba(0,0,0,.36) 0 1px, rgba(255,255,255,.12) 1px 2px);
    --glass-halo: 0 2px 12px rgba(0,0,0,.34);
    --glass-logo-halo: drop-shadow(0 1px 5px rgba(0,0,0,.5));

    --text-soft: #B3B2AC;
    --text-faint: #8E8D87;
    --tick: #8E8D87;
    --accent-fg: #161615;
    --caeruleus: #8AB4E0;
    --think-flourish: #8E8D87;
    --composer-bg: rgba(31,31,29,.96);
    --shadow: 0 12px 38px rgba(0,0,0,.34), 0 1px 3px rgba(0,0,0,.2);
    --soft-shadow: 0 8px 26px rgba(0,0,0,.3);
    --card-bg: rgba(40,40,38,.42);
    --card-line: rgba(255,255,255,.08);
    --card-shadow: 0 10px 28px rgba(0,0,0,.28);
    --seg-track: rgba(255,255,255,.08);
    --seg-thumb: rgba(74,74,68,.9);
    --seg-thumb-shadow: 0 2px 8px rgba(0,0,0,.3);
    --row-press: rgba(255,255,255,.06);
    --slider-track: rgba(255,255,255,.16);
    --slider-thumb: #B3B2AC;
    --info-ring: rgba(255,255,255,.22);
  }
  *{ box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
  .ph{ display:inline-flex; align-items:center; justify-content:center; line-height:1; }
  .topbtn .ph{ font-size:24px; }
  .topbtn.more .ph{ font-size:22px; }
  .session-expand .ph{ font-size:16px; transition:transform .18s ease; }
  .session-item.expanded .session-expand .ph{ transform:rotate(180deg); }
  .claude-md-entry-icon .ph,.claude-md-entry-chevron .ph{ font-size:20px; }
  .memory-library-link .ph{ font-size:18px; }
  .home-dock-item .ph{ font-size:23px; }
  .terminal-back .ph{ font-size:21px; }
  .terminal-send .ph{ font-size:18px; }
  .att-file-ic .ph{ font-size:20px; opacity:.85; }
  .pending-remove .ph{ font-size:13px; }
  .think-star .ph{ font-size:24px; }
  .floatbtn .ph{ font-size:clamp(20px,2.8vw,28px); }
  .emojibtn .ph{ font-size:clamp(22px,3vw,30px); }
  .newmsg-pill .ph{ font-size:17px; flex:none; }
  .profile-back .ph{ font-size:24px; }
  .status-copy .ph{ font-size:15px; }
  .legacy-import-close .ph,.runtime-picker-close .ph,.instructions-editor-close .ph,.mcp-manager-close .ph,.thought-close .ph{ font-size:22px; }
  .instructions-editor-save .ph{ font-size:23px; }
  .call-star .ph{ font-size:16px; }
  .call-minimize-top .ph{ font-size:18px; }
  .call-hangup .ph,.incoming-call-btn .ph{ font-size:clamp(26px,5.6vw,31px); }
  .msg-act .ph{ font-size:18px; opacity:.82; flex:none; }
  html, body{ margin:0; padding:0; height:100%; overflow:hidden; overscroll-behavior:none; }
  body{ position: fixed; inset: 0; width: 100%;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-cn);
    font-size: clamp(14px, 1.45vw, 16px);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overscroll-behavior: none;
  }

  .app{
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1;
    width: min(100vw, var(--ref-width));
    margin: 0 auto;
    overflow: hidden;
  }
  .topbar, .scroll, .composer{ position: relative; z-index: 1; }

  /* ── Header (floating frosted pill + corner avatar) ── */
  .topbar{
    position: sticky; top: 0; z-index: 10;
    display: flex; align-items: center; justify-content: center;
    height: calc(var(--header-h) + env(safe-area-inset-top));
    padding: calc(env(safe-area-inset-top) + 8px) var(--side-pad) 10px;
    border-bottom: 1px solid var(--hairline);
    pointer-events: none;
  }
  .topbar > *{ pointer-events: auto; }
  .sidebar-trigger{
    position:absolute;
    left:calc(var(--side-pad) - 2px);
    top:calc(env(safe-area-inset-top) + clamp(14px, 2.5vw, 36px));
  }
  .peerpill{
    display:flex; flex-direction:column; align-items:center; line-height:1.15;
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0 76px;
  }
  .peerpill .name{
    font-family: var(--font-cn);
    font-size: clamp(18px, 3vw, 28px);
    font-weight: 500;
    color: var(--text);
    letter-spacing: 0;
    text-shadow: 0 1px 18px rgba(255,255,255,0.3);
  }
  .peerpill .status{
    font-family: var(--font-en), var(--font-cn);
    font-size: clamp(12px, 1.8vw, 16px);
    color: var(--text-soft);
    margin-top: 4px;
    letter-spacing: 0;
  }
  .app[data-conn="reconnecting"] .peerpill .status{ color:var(--text-faint); }
  /* 「syncing…」＝屏幕上这份是手机里存着的，新的还在路上。和 reconnecting 同一个
     灰度：都属于"正在办，还没办完"，不该比 online 更抢眼。 */
  .app[data-conn="syncing"] .peerpill .status{ color:var(--text-faint); }
  .peerpill .status.typing{
    color: var(--text-soft);
    font-weight: 500;
    text-shadow: 0 0 16px rgba(79,159,218,.24);
    display: inline-flex; align-items: center;
  }
  .typing-dots{ display:inline-flex; align-items:center; gap:3px; margin-left:6px; }
  .typing-dots i{ width:4px; height:4px; border-radius:50%; background:currentColor; animation: typingDot 1.25s ease-in-out infinite; }
  .typing-dots i:nth-child(2){ animation-delay:.16s; }
  .typing-dots i:nth-child(3){ animation-delay:.32s; }
  @keyframes typingDot{ 0%,70%,100%{ transform:translateY(0); opacity:.4; } 35%{ transform:translateY(-3px); opacity:1; } }
  .header-actions{
    position:absolute;
    right: calc(var(--side-pad) - 2px);
    top: calc(env(safe-area-inset-top) + clamp(14px, 2.5vw, 36px));
    display:flex;
    align-items:center;
    justify-content:flex-end;
    gap: clamp(24px, 4vw, 42px);
    height:36px;
  }
  .topbtn{
    width:36px;
    height:36px;
    border:0;
    border-radius:50%;
    padding:0;
    background:transparent;
    color: var(--text);
    display:grid;
    place-items:center;
    cursor:pointer;
    transition: transform .15s ease;
  }
  .topbtn:active{ transform: scale(.9); }
  .topbtn svg{ width:24px; height:24px; display:block; }
  .topbtn.more svg{ width:22px; height:22px; }
  .topbtn.terminal.active{ color:var(--accent); }
  /* 长文模式开着的时候这颗按钮整个填满：空心＝关，实心＝开，一眼看得出来。
     两个类名一起写是为了压过后面那条给 .topbtn 定颜色的规则。 */
  /* 常用功能（2026-09-26，原来那颗长文模式按钮收进了这个框）：框里有开着的东西时，角上亮一个小点。 */
  .topbtn.tools{ position:relative; }
  .topbtn.tools.has-on::after{
    content:""; position:absolute; top:8px; right:8px; width:7px; height:7px; border-radius:50%;
    background:var(--accent);
  }
  .session-pop.chat-tools-pop{ width:min(82vw,280px); }
  .chat-tools-list{ display:flex; flex-direction:column; gap:2px; }
  .chat-tools-row{ display:flex; align-items:center; gap:12px; padding:10px 9px; border-radius:12px; }
  .chat-tools-copy{ min-width:0; display:flex; flex-direction:column; gap:3px; }
  .chat-tools-name{ font-size:15px; line-height:1.3; color:var(--text); }
  .chat-tools-hint{ font-size:11.5px; line-height:1.3; color:var(--text-faint); }
  .session-pop{
    position:absolute;
    right:calc(var(--side-pad) + 34px);
    top:calc(env(safe-area-inset-top) + 54px);
    z-index:30;
    width:min(82vw, 320px);
    max-height:min(58vh, 480px);
    overflow:auto;
    padding:10px;
    border:1px solid var(--card-line);
    border-radius:18px;
    background:var(--glass-solid);   /* 原来写的 --panel-bg 根本没定义过 */
    color:var(--text);
    box-shadow:0 18px 50px var(--shade-cool-2);
    -webkit-backdrop-filter:blur(18px);
    backdrop-filter:blur(18px);
  }
  .session-pop[hidden]{ display:none !important; }
  .session-head{ display:flex; align-items:center; justify-content:space-between; gap:8px; padding:4px 2px 8px; }
  .session-title{ font-size:12px; color:var(--text-faint); font-family:var(--font-en), var(--font-cn); }
  .session-new{
    border:1px solid var(--seg-line); border-radius:999px; padding:5px 9px;
    background:var(--seg-track); color:var(--text-soft); font:inherit; font-size:11.5px; cursor:pointer;
  }
  .session-list{ display:flex; flex-direction:column; gap:2px; }
  .session-item{
    border:0; width:100%; background:transparent; color:var(--text);
    display:grid; grid-template-columns:1fr auto; align-items:center; gap:8px;
    padding:10px 9px; border-radius:12px; text-align:left; cursor:pointer; font:inherit;
  }
  .session-item.active{ background:var(--seg-track); }
  .session-item:active{ transform:scale(.992); }
  .session-main{ min-width:0; display:flex; flex-direction:column; align-items:flex-start; gap:3px; }
  .session-name{ font-size:14px; line-height:1.25; }
  .session-meta{ font-size:11px; color:var(--text-faint); font-family:var(--font-en), var(--font-cn); }
  .session-expand{
    border:0; background:transparent; color:var(--text-faint); width:28px; height:28px;
    border-radius:50%; display:grid; place-items:center; cursor:pointer; padding:0;
  }
  .session-expand:hover{ color:var(--accent); background:var(--seg-track); }
  .session-expand svg{ width:16px; height:16px; display:block; transition:transform .18s ease; }
  .session-item.expanded .session-expand svg{ transform:rotate(180deg); }
  .session-actions{
    grid-column:1/-1; display:flex; justify-content:flex-end; gap:7px; padding-top:4px;
  }
  .session-action{
    min-height:32px; border:0; border-radius:16px; padding:0 12px; cursor:pointer;
    background:var(--seg-track); color:var(--text-soft); font:500 12px/1 var(--font-cn),var(--font-en);
  }
  .session-action.delete{ background:rgba(186,66,54,.09); color:var(--danger); }
  .session-action:active{ transform:scale(.97); }

  /* Archora-style home shell: Chat plus four quiet placeholder views. */
  .home-shell{
    position:fixed; inset:0; z-index:5; display:grid; grid-template-rows:minmax(0,1fr) auto;
    background:var(--bg); color:var(--text);
  }
  .home-stage{ position:relative; min-height:0; overflow:hidden; }
  .home-view{ position:absolute; inset:0; display:grid; place-items:center; padding:32px; }
  .home-view[hidden]{ display:none; }
  .home-view-copy{ text-align:center; }
  .home-view-copy h1{ margin:0; font:500 clamp(26px,5vw,44px)/1.15 var(--font-en),var(--font-cn); }
  .home-view-copy p{ margin:10px 0 0; color:var(--text-faint); font-size:13px; }
  .home-view.feed-view:not([hidden]){
    display:flex; flex-direction:column; place-items:stretch; padding:0; overflow:hidden;
  }
  .feed-topbar{
    position:relative; z-index:2; flex:none; height:calc(72px + env(safe-area-inset-top));
    display:flex; align-items:center; justify-content:center;
    padding:calc(env(safe-area-inset-top) + 10px) var(--side-pad) 8px;
    border-bottom:0; background:var(--bg);
  }
  .feed-weather{
    position:absolute; left:var(--side-pad); top:calc(env(safe-area-inset-top) + 2px);
    min-width:44px; height:44px; max-width:min(52vw,260px); padding:0;
    display:flex; align-items:center; gap:7px; overflow:hidden;
    border:0; background:transparent; color:var(--text);
    font:500 13px/1 var(--font-cn),var(--font-en); white-space:nowrap;
  }
  /* Home 已经有自己的安全区内边距，天气就跟着内容排在左上角。 */
  .home-weather{ position:static; height:auto; margin:0 0 14px; }
  .feed-weather .ph{ flex:none; font-size:18px; color:var(--text-soft); }
  .feed-weather-text{ min-width:0; overflow:hidden; text-overflow:ellipsis; line-height:1.65; }   /* 同 .runtime-model-name：行高 1 又裁字，Literata 的下伸部会被切 */
  .feed-back{
    position:absolute; left:calc(var(--side-pad) - 8px); top:calc(env(safe-area-inset-top) + 2px);
    width:44px; height:44px; padding:0; display:grid; place-items:center;
    border:0; border-radius:50%; background:transparent; color:var(--text); cursor:pointer;
  }
  .feed-back .ph{ font-size:21px; }
  .feed-back:active{ transform:scale(.94); }
  .feed-date-picker{
    position:relative; display:flex; align-items:center; gap:5px; min-height:44px;
    color:var(--text); cursor:pointer;
  }
  .feed-date{
    color:var(--text); font:500 clamp(18px,3vw,24px)/1 var(--font-cn);
    letter-spacing:.04em; font-variant-numeric:tabular-nums;
  }
  .feed-date-picker .ph{ color:var(--text-faint); font-size:12px; }
  .feed-date-input{
    position:absolute; inset:0; width:100%; height:100%; margin:0; opacity:0; cursor:pointer;
  }
  .feed-topbar-actions{ display:flex; align-items:center; gap:14px; }
  .feed-scroll{
    flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior-y:contain;
    padding:10px clamp(18px,4.5vw,42px) 34px; scrollbar-width:none;
  }
  .feed-scroll::-webkit-scrollbar{ display:none; }
  .feed-timeline{
    width:min(100%,680px); min-height:100%; margin:0 auto; display:flex; flex-direction:column;
  }
  /* 老 Feed 页的大时钟。2026-09-28 首页改版时从 Home 上拿掉了（她不要）——之前它在 Home 上字是藏着的，只拿来给
     浮在上面的头像行和额度卡占位；现在那两样走正常流，用不着它了。样式留着，Feed 那边以后想要可以再用。 */
  .feed-hero{ padding:16px 4px 26px; }
  .feed-hero-note{ display:flex; align-items:center; gap:8px; color:var(--text-faint); font-size:12px; }
  .feed-hero-note::before{ content:""; width:30px; height:7px; background:var(--surface-soft); }
  .feed-clock-row{ display:flex; align-items:flex-end; gap:12px; margin-top:18px; }
  .feed-clock-ghost{
    color:rgba(31,31,29,.055); font:500 clamp(72px,18vw,116px)/.78 var(--font-en);
    letter-spacing:-.08em; font-variant-numeric:tabular-nums;
  }
  .feed-clock-main{
    margin-left:clamp(-58px,-9vw,-34px); color:var(--text);
    font:500 clamp(43px,10vw,70px)/.9 var(--font-cn);
    font-variant-numeric:tabular-nums;
  }
  .feed-duration{ margin:10px 0 0 72px; color:var(--text-faint); font:400 17px/1.2 var(--font-cn); }
  .feed-content-head{ display:flex; align-items:center; justify-content:space-between; padding:22px 4px 10px; }
  .feed-content-title{ margin:0; font:500 17px/1.2 var(--font-cn); }
  .feed-content-count{ color:var(--text-faint); font-size:11px; }
  .feed-content{ display:flex; min-height:240px; flex:1; flex-direction:column; }
  .feed-history-status{
    flex:none; min-height:24px; padding:2px 0 12px; color:var(--text-faint);
    font:400 11px/1.4 var(--font-cn),var(--font-en); text-align:center;
  }
  .feed-list{ margin-top:auto; display:flex; flex-direction:column; gap:10px; }
  .feed-card{
    display:grid; grid-template-columns:44px minmax(0,1fr) auto; align-items:center; gap:13px;
    min-height:72px; padding:14px 4px; border:0; border-bottom:1px solid var(--line-faint);
    border-radius:0; background:transparent !important; color:var(--text);
  }
  .feed-card.fresh{ animation:feedCardIn .34s var(--ease-soft) both; }
  @keyframes feedCardIn{
    from{ opacity:0; transform:translateY(10px) scale(.985); }
    to{ opacity:1; transform:none; }
  }
  .feed-card-icon{
    width:44px; height:44px; display:grid; place-items:center; flex:none;
    border-radius:50%; border:1px solid var(--line-faint); background:transparent !important; color:var(--text-faint);
  }
  .feed-card-icon .ph{ font-size:21px; }
  .feed-card-copy{
    min-width:0; display:flex; align-items:baseline; flex-wrap:wrap; gap:0 5px;
    font-size:14px; line-height:1.55;
  }
  .feed-card-actor,.feed-card-app{ color:var(--text); font-weight:600; }
  .feed-card-action{ color:var(--text-faint); font-weight:400; }
  .feed-card-app{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .feed-card-duration{ flex-basis:100%; color:var(--text-faint); font-size:11.5px; font-weight:400; }
  .feed-card-time{
    align-self:start; padding-top:3px; color:var(--text-faint);
    font:500 11px/1 var(--font-en),var(--font-cn); font-variant-numeric:tabular-nums; white-space:nowrap;
  }
  /* 按 App 合起来的那一行（照着 iOS 屏幕使用时间的排法）：名字一行，
     下面一条占比条 + 总时长，最后一行是"上次关闭 / 正在使用"。 */
  .feed-app{
    display:grid; grid-template-columns:44px minmax(0,1fr); align-items:center; gap:13px;
    min-height:72px; padding:14px 4px; border-bottom:1px solid var(--line-faint);
    background:transparent !important; color:var(--text);
  }
  .feed-app.fresh{ animation:feedCardIn .34s var(--ease-soft) both; }
  .feed-app-body{ min-width:0; display:flex; flex-direction:column; gap:5px; }
  .feed-app-name{
    color:var(--text); font-size:14px; font-weight:600; line-height:1.35;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .feed-app-meter{ display:flex; align-items:center; gap:9px; }
  /* 条的长度按"扣掉右边那段时长字之后剩下的宽度"算：原来直接占整行的百分之几，
     最长那条是 100%，把后面的「31min」挤出了卡片（2026-09-26 她截图报的）。
     76px 够放最长的「12h 30min」加上中间的空隙，还留一点余量。 */
  .feed-app-bar{
    flex:none; width:calc((100% - 76px) * var(--ratio, 1)); height:5px; min-width:6px; border-radius:999px;
    background:var(--surface-strong);   /* 原来写死 rgba(31,31,29,.26)，浅色下几乎一样；深色里那个会看不见 */
  }
  .feed-app-total{
    color:var(--text-soft); font:500 12.5px/1 var(--font-en),var(--font-cn);
    font-variant-numeric:tabular-nums; white-space:nowrap;
  }
  .feed-app-last{
    color:var(--text-faint); font-size:11.5px; line-height:1.4;
    font-variant-numeric:tabular-nums;
  }
  .feed-app.is-active .feed-app-bar{ background:var(--success); }
  .feed-app.is-active .feed-app-last{ color:var(--success); }
  .feed-empty{
    margin:auto 0; padding:42px 20px; color:var(--text-faint); text-align:center;
    font-size:13px; line-height:1.7;
  }
  .feed-empty .ph{ display:flex; margin:0 auto 10px; font-size:26px; color:var(--text-disabled); }
  .home-view.diary-view:not([hidden]){
    display:block; place-items:stretch; min-height:0; overflow-y:auto; overscroll-behavior-y:contain;
    padding:calc(env(safe-area-inset-top) + 30px) clamp(18px,5vw,48px) calc(42px + env(safe-area-inset-bottom));
    scrollbar-width:none;
  }
  .diary-view::-webkit-scrollbar{ display:none; }
  .diary-inner{ width:min(100%,720px); margin:0 auto; }
  .diary-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:20px; }
  .diary-back{ position:static; margin:0 0 6px -12px; }
  .diary-head h1{ margin:0; font:600 clamp(38px,8vw,58px)/.96 var(--font-en),var(--font-cn); letter-spacing:-.045em; }
  .diary-head-actions{ display:flex; align-items:center; gap:16px; }
  .diary-prompt-entry{
    margin-top:15px; padding:0; display:flex; align-items:center; gap:6px; border:0; background:transparent;
    color:var(--text-faint); font:500 12px/1 var(--font-cn),var(--font-en); cursor:pointer;
  }
  .diary-prompt-entry .ph{ font-size:14px; }
  .diary-calendar{ margin-top:42px; }
  .diary-calendar-toolbar{ display:flex; align-items:center; justify-content:space-between; gap:16px; }
  .diary-month-picker{
    position:relative; min-width:126px; height:40px; padding:0 16px; display:flex; align-items:center; justify-content:center; gap:7px;
    border-radius:999px; background:var(--fill-strong); color:var(--text-on-fill); cursor:pointer;
    font:600 13px/1 var(--font-cn),var(--font-en); font-variant-numeric:tabular-nums;
  }
  .diary-month-picker .ph{ font-size:12px; }
  .diary-month-picker input{ position:absolute; inset:0; width:100%; height:100%; margin:0; opacity:0; cursor:pointer; }
  .diary-month-nav{ display:flex; gap:8px; }
  .diary-month-nav button{
    width:40px; height:40px; padding:0; display:grid; place-items:center; border:1px solid var(--line);
    border-radius:50%; background:transparent; color:var(--text); cursor:pointer;
  }
  .diary-month-nav button:disabled{ color:var(--text-disabled); cursor:default; }
  .diary-weekdays,.diary-days{ display:grid; grid-template-columns:repeat(7,minmax(0,1fr)); }
  .diary-weekdays{ margin-top:28px; color:var(--text-faint); font:500 11px/1 var(--font-cn),var(--font-en); text-align:center; }
  .diary-days{ margin-top:14px; row-gap:11px; }
  .diary-day-space{ min-height:36px; }
  .diary-day{
    width:36px; height:36px; margin:auto; padding:0; display:grid; place-items:center;
    border:0; border-radius:50%; background:var(--surface-soft); color:var(--text);
    font:500 12px/1 var(--font-en),var(--font-cn); font-variant-numeric:tabular-nums; cursor:pointer;
  }
  .diary-day.has-diary{ width:40px; border-radius:11px; background:var(--surface-mid); color:var(--text); font-weight:650; }
  .diary-day.future{ color:var(--text-disabled); cursor:default; }
  .diary-day.selected{ width:40px; border-radius:11px; background:var(--fill-strong); color:var(--text-on-fill); }
  /* 回顾坐在日历和当天日记中间：先看见这一段时间是什么样子，再往下读某一天。
     一篇都没有时整节收起来，不留一块写着"暂无"的空地。 */
  .diary-review{ margin-top:34px; padding-top:24px; border-top:1px solid var(--hairline); }
  .diary-review.empty{ display:none; }
  .diary-review-head{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
  .diary-review-title{ margin:0; color:var(--text-faint); font:500 11px/1 var(--font-en),var(--font-cn); letter-spacing:.08em; }
  .diary-review-body{ margin-top:16px; color:var(--text); }
  .diary-review-item{ padding:20px 0; border-top:1px solid var(--hairline); }
  .diary-review-item:first-child{ padding-top:0; border-top:0; }
  .diary-review-item-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px; margin-bottom:10px; }
  .diary-review-label{ color:var(--text-faint); font:500 10.5px/1.55 var(--font-en),var(--font-cn); font-variant-numeric:tabular-nums; }
  .diary-review-label .diary-review-flag{ display:block; margin-top:3px; color:var(--warning); }
  .diary-review-actions{ display:flex; align-items:center; gap:6px; flex-shrink:0; }
  .diary-review-text{ overflow-wrap:anywhere; font:400 clamp(15px,3.7vw,18px)/1.85 var(--font-cn); }
  .diary-review-state{ color:var(--text-faint); font:400 13px/1.7 var(--font-cn); }
  .diary-reading{ margin-top:38px; padding-top:26px; border-top:1px solid var(--hairline); }
  .diary-reading-date{ color:var(--text-faint); font:500 11px/1 var(--font-en),var(--font-cn); font-variant-numeric:tabular-nums; }
  .diary-reading-head{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
  .diary-day-btn{
    border:1px solid var(--line-faint); background:transparent; border-radius:999px;
    padding:4px 12px; color:var(--text-soft); font:500 11px/1 var(--font-cn); cursor:pointer;
  }
  .diary-day-btn:disabled{ opacity:.5; cursor:default; }
  .diary-reading-actions{ display:flex; align-items:center; gap:6px; }
  .diary-import-body{
    width:100%; box-sizing:border-box; margin-top:12px; padding:12px 14px;
    border:1px solid var(--line-faint); border-radius:14px; background:var(--surface);
    color:var(--text); font:400 14px/1.75 var(--font-cn); resize:vertical;
  }
  .diary-import-dialog{
    width:min(calc(100vw - 32px),420px); max-height:min(72vh,560px); padding:0;
    border:1px solid var(--line-faint); border-radius:20px; background:var(--surface);
    color:var(--text); box-shadow:0 18px 46px var(--shade-warm-2);
  }
  .diary-import-dialog::backdrop{ background:var(--scrim); }
  .diary-import-shell{ display:flex; flex-direction:column; max-height:min(72vh,560px); padding:18px; }
  .diary-import-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:14px; }
  .diary-import-title{ margin:0; font:600 17px/1.25 var(--font-cn),var(--font-en); }
  .diary-import-note{ margin:5px 0 0; color:var(--text-faint); font:400 11.5px/1.55 var(--font-cn),var(--font-en); }
  .diary-import-close{
    display:grid; place-items:center; width:32px; height:32px; padding:0; border:0;
    border-radius:50%; background:transparent; color:var(--text-faint); cursor:pointer; font-size:18px;
  }
  .diary-import-save{
    min-width:60px; height:39px; padding:0 14px; border:0; border-radius:11px;
    background:var(--fill-strong); color:var(--text-on-fill); cursor:pointer; font:600 12px/1 var(--font-cn),var(--font-en);
  }
  .diary-reading-body{
    margin-top:17px; color:var(--text);
  }
  .diary-entry{ padding:22px 0; border-top:1px solid var(--hairline); }
  .diary-entry:first-child{ padding-top:0; border-top:0; }
  .diary-entry-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px; margin-bottom:12px; }
  .diary-entry-range{ color:var(--text-faint); font:500 10.5px/1.55 var(--font-en),var(--font-cn); font-variant-numeric:tabular-nums; }
  /* 换行交给 .markdown（它把 white-space 设回 normal），这里只管字号和行距。
     日记比 Code 的正文更大更松，是特意的：它是拿来读的，不是拿来扫的。 */
  .diary-entry-text{ overflow-wrap:anywhere; font:400 clamp(17px,4.2vw,21px)/1.9 var(--font-cn); }
  .diary-entry-state{ color:var(--text-faint); font:400 14px/1.7 var(--font-cn); }
  @media (max-width:420px){
    .feed-weather{ max-width:36vw; font-size:12px; }
    .home-weather{ max-width:100%; }
    .feed-topbar-actions{ gap:8px; }
    .feed-scroll{ padding-left:16px; padding-right:16px; }
    .feed-card{ grid-template-columns:40px minmax(0,1fr) auto; gap:11px; padding:13px 4px; }
    .feed-app{ grid-template-columns:40px minmax(0,1fr); gap:11px; padding:13px 4px; }
    .feed-card-icon{ width:40px; height:40px; }
    .feed-card-copy{ font-size:13.5px; }
  }
  .home-view.home-dashboard{ place-items:start center; overflow:auto; padding:clamp(28px,6vh,54px) 22px 32px; }
  .home-dashboard-inner{ position:relative; width:min(100%,680px); }
  .home-notice{
    position:relative; z-index:3; width:min(100%,520px); min-height:54px; margin:0 auto 18px; padding:13px 44px 13px 42px;
    display:flex; align-items:center; border:1px solid var(--line); border-radius:16px; background:var(--bg); color:var(--text);
  }
  .home-notice.hidden{ display:none; }
  .home-notice > .ph{ position:absolute; left:15px; top:17px; color:var(--text-faint); font-size:18px; }
  .home-notice p{ margin:0; font-size:12.5px; line-height:1.55; }
  .home-notice button{ position:absolute; right:10px; top:10px; width:32px; height:32px; padding:0; border:0; background:transparent; color:var(--text-faint); cursor:pointer; }
  /* 2026-09-28 首页改版起它在「用量」页最上面，走正常流（原来绝对定位浮在首页的隐形时钟上）。 */
  .claude-quota-card{
    position:relative; width:100%; margin:0;
    padding:16px 15px 15px; border-radius:20px;
    border:1px solid var(--hairline); background:transparent; box-shadow:none;
  }
  .claude-quota-head{ display:flex; align-items:baseline; justify-content:space-between; gap:16px; }
  .claude-quota-title{ margin:0; color:var(--text); font:500 16px/1.3 var(--font-en),var(--font-cn); }
  .claude-quota-updated{ color:var(--text-faint); font-size:11px; white-space:nowrap; }
  .claude-quota-window{ margin-top:14px; }
  .claude-quota-window + .claude-quota-window{ margin-top:15px; }
  .claude-quota-label{ display:flex; align-items:center; justify-content:space-between; gap:14px; color:var(--text); font-size:13px; }
  .claude-quota-value{ color:var(--text); font-variant-numeric:tabular-nums; }
  .claude-quota-track{ height:5px; margin-top:8px; overflow:hidden; border-radius:999px; background:var(--surface-mid); }
  .claude-quota-fill{ display:block; width:0; height:100%; border-radius:inherit; background:linear-gradient(90deg,var(--progress-from),var(--progress-to)); transition:width .45s ease; }
  .claude-quota-reset{ min-height:17px; margin:6px 0 0; color:var(--text-faint); font-size:12px; text-align:right; white-space:nowrap; }
  .bisca-home-card{
    width:100%; min-height:86px; margin:24px 0 0; padding:16px 14px; border:1px solid var(--hairline); border-radius:20px;
    background:transparent; color:var(--text); display:grid; grid-template-columns:48px minmax(0,1fr) 28px; align-items:center; gap:13px;
    text-align:left; cursor:pointer; font-family:var(--font-cn),var(--font-en);
  }
  .bisca-home-card:active{ transform:scale(.985); }
  .bisca-home-icon{ width:48px; height:48px; display:grid; place-items:center; border:1px solid var(--hairline); border-radius:50%; color:var(--text); }
  .bisca-home-icon .ph{ font-size:24px; }
  .bisca-home-copy{ min-width:0; }
  .bisca-home-copy strong{ display:block; font-size:16px; font-weight:600; line-height:1.3; }
  .bisca-home-copy span{ display:block; margin-top:5px; color:var(--text-faint); font-size:12px; line-height:1.45; }
  .bisca-home-card > .ph{ color:var(--text-faint); font-size:18px; justify-self:end; }
  .image-library-home-card{ margin-top:12px; }
  /* ════════════ 首页改版（2026-09-28，照她手画的草图）════════════
     卡片还是 .bisca-home-card（点击、玻璃、测试都认这个名字），按放在哪一块改长相：
     竖长的猫卡、右上的点子本、三个小方块（日记 / SVG / 图库，以后合成"储藏室"）、Play 那排方块。
     剩下的（生活 Feed、音乐）保持原来的长卡。
     第二版（同日，她嫌第一版"太紧凑不好看"，让我按自己的审美来）：少画框、多留白——
     那句话和通知不装框，字直接落在底图上（和她要的日期分隔线一个道理）；猫的照片铺满卡片上半截，不再框里套框；
     小方块里的图标不再套圆圈；块与块之间留得更开。 */
  /* 那句话：横着一行小字，从左写到右（她 2026-09-28 画的）。Happiness 和 What-Ifs 斜体加粗、大一号当重点。
     字号跟着屏幕宽走，保证一行放得下；落在照片上要看得清，垫一层很淡的影子（--bg 跟着深浅色走）。 */
  .home-quote-line{
    margin:40px 0 0; text-align:center; white-space:nowrap; color:var(--text-soft);
    font:400 clamp(10px,2.85vw,13px)/1.2 var(--font-en); letter-spacing:.01em;
    text-shadow:0 0 14px var(--bg), 0 0 3px var(--bg);
  }
  .home-quote-line em{ color:var(--text); font-style:italic; font-weight:600; font-size:1.22em; letter-spacing:-.01em; }
  /* 下面一排：左边空着（她"没想好"），底下一行通知；右边 USAGE，中间一根细竖线（USAGE 的左边框）。 */
  .home-top-row{ display:grid; grid-template-columns:minmax(0,1fr) minmax(112px,.55fr); gap:18px; align-items:stretch; margin-top:30px; }
  .home-top-left{ min-width:0; display:flex; flex-direction:column; justify-content:flex-end; }
  .home-top-open{ flex:1; }
  /* USAGE 不装框，字直接落在底图上；整块是一颗按钮，点哪儿都进「用量」页。行距收得紧一点（她要的）。 */
  .home-usage-mini{
    position:relative; padding:2px 2px 2px 18px; border:0; border-left:1px solid var(--line-strong); border-radius:0; background:transparent; color:var(--text);
    display:flex; flex-direction:column; align-items:stretch; gap:2px;
    text-align:left; cursor:pointer; font-family:var(--font-en),var(--font-cn); text-shadow:0 0 14px var(--bg), 0 0 3px var(--bg);
  }
  .home-usage-mini:active{ transform:scale(.985); }
  .home-usage-mini-title{ color:var(--text-faint); font-size:11px; letter-spacing:.14em; }
  .home-usage-mini-group{ margin-top:9px; font-size:13.5px; font-weight:600; }
  .home-usage-mini-row{ display:flex; align-items:baseline; justify-content:space-between; gap:8px; color:var(--text-soft); font-size:12px; line-height:1.35; }
  .home-usage-mini-row strong{ color:var(--text); font-size:14.5px; font-weight:500; font-variant-numeric:tabular-nums; }
  .home-usage-mini-go{ margin-top:8px; align-self:flex-end; color:var(--text-faint); font-size:14px; }
  /* 通知：不装框，一行浅浅的小字。以后真有通知了再让它亮起来。 */
  .home-notice-bar{
    display:flex; align-items:center; gap:7px;
    color:var(--text-faint); font-size:12px; text-shadow:0 0 12px var(--bg);
  }
  .home-notice-bar .ph{ font-size:15px; }
  .home-mid-row{ display:grid; grid-template-columns:minmax(0,.95fr) minmax(0,1.45fr); gap:14px; align-items:stretch; margin-top:30px; }
  .home-mid-row .bisca-home-card,
  .home-play-row .bisca-home-card{ margin:0; }
  .home-mid-row .bisca-home-card > .ph-caret-right,
  .home-play-row .bisca-home-card > .ph-caret-right{ display:none; }
  .home-mid-row .bisca-home-card[hidden]{ display:none; }
  /* 竖长的猫卡：照片铺满上半截（没照片时一个大爪印），下面名字和那一行近况。 */
  #catHomeCard{ min-height:0; padding:0; overflow:hidden; display:flex; flex-direction:column; align-items:stretch; gap:0; }
  #catHomeCard .bisca-home-icon{ width:100%; height:auto; aspect-ratio:1; border:0; border-radius:0; background:var(--tint); }
  #catHomeCard .bisca-home-icon .ph{ font-size:38px; color:var(--text-soft); }
  #catHomeCard .bisca-home-copy{ padding:12px 14px 14px; }
  /* 右边一列和猫卡一样高、底边对齐（她 2026-09-28 画圈要的），上下对半分：上半点子本，下半三个小方块，都拉长填满。 */
  .home-mid-side{ min-width:0; display:grid; grid-template-rows:minmax(0,1fr) minmax(0,1fr); gap:14px; }
  #ideasHomeCard{ min-height:0; height:100%; padding:12px 13px; grid-template-columns:36px minmax(0,1fr); gap:10px; }
  #ideasHomeCard .bisca-home-icon{ width:36px; height:36px; }
  #ideasHomeCard .bisca-home-icon .ph{ font-size:19px; }
  #ideasHomeCard .bisca-home-copy span{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .home-storage-row{ min-height:0; display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:10px; }
  /* 小方块（储藏室那三个、Play 那一排）：图标在上、名字在下，不写小字，图标不套圈。 */
  .home-storage-row .bisca-home-card,
  .home-play-row .bisca-home-card{
    min-height:0; aspect-ratio:1; padding:8px 6px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:8px;
    text-align:center; border-radius:18px;
  }
  .home-storage-row .bisca-home-card{ aspect-ratio:auto; height:100%; }
  .home-storage-row .bisca-home-icon,
  .home-play-row .bisca-home-icon{ width:auto; height:auto; border:0; border-radius:0; }
  .home-storage-row .bisca-home-icon .ph{ font-size:21px; }
  .home-play-row .bisca-home-icon .ph{ font-size:24px; }
  .home-storage-row .bisca-home-copy strong{ font-size:12px; font-weight:600; line-height:1.25; }
  .home-play-row .bisca-home-copy strong{ font-size:13px; font-weight:600; line-height:1.25; }
  .home-storage-row .bisca-home-copy span,
  .home-play-row .bisca-home-copy span{ display:none; }
  .home-section-title{
    margin:34px 4px 12px; color:var(--text-faint); font:500 12px/1 var(--font-en),var(--font-cn); letter-spacing:.16em; text-transform:uppercase;
    text-shadow:0 0 12px var(--bg);
  }
  .home-play-row{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:14px; }
  .home-play-row + .bisca-home-card{ margin-top:34px; }
  .home-play-row ~ .bisca-home-card + .bisca-home-card{ margin-top:14px; }
  /* 「用量」页：骨架照点子本（顶上一条返回 · 标题，下面整页滚）。 */
  .home-view.usage-view:not([hidden]){ place-items:stretch; padding:0; overflow:hidden; display:flex; flex-direction:column; }
  .usage-scroll{ flex:1; min-height:0; overflow:auto; padding:4px 22px calc(32px + env(safe-area-inset-bottom)); -webkit-overflow-scrolling:touch; }
  .usage-scroll > *{ width:min(100%,680px); margin-left:auto; margin-right:auto; }
  .usage-group{ padding:14px 16px 12px; border:1px solid var(--hairline); border-radius:20px; }
  .usage-group + .usage-group{ margin-top:12px; }
  .usage-group h2{ margin:0 0 6px; color:var(--text); font:600 15px/1.3 var(--font-en),var(--font-cn); }
  .usage-line{ margin:0; padding:7px 0; display:flex; align-items:baseline; justify-content:space-between; color:var(--text-soft); font-size:13px; }
  .usage-line strong{ color:var(--text); font:500 17px/1 var(--font-en),var(--font-cn); font-variant-numeric:tabular-nums; }
  .usage-note{ margin:4px 0 0; color:var(--text-faint); font-size:11.5px; }
  .usage-scroll .claude-quota-card + .usage-group{ margin-top:12px; }
  /* 「收藏」页（2026-09-28）：骨架照用量页，分类照点子本那排胶囊；每段不加框，字落在底图上，段与段之间一条细线。 */
  .home-view.favorites-view:not([hidden]){ place-items:stretch; padding:0; overflow:hidden; display:flex; flex-direction:column; }
  .favorites-tabs{ flex:none; display:flex; gap:6px; padding:0 22px 10px; }
  .favorites-tab{
    flex:none; min-height:34px; padding:0 14px; border:1px solid var(--hairline); border-radius:17px;
    background:transparent; color:var(--text-faint); cursor:pointer; font:600 12.5px/1 var(--font-cn),var(--font-en);
  }
  .favorites-tab[aria-selected="true"]{ border-color:var(--line-bold); background:var(--fill-strong); color:var(--text-on-fill); }
  .favorites-scroll{ flex:1; min-height:0; overflow:auto; padding:0 22px calc(32px + env(safe-area-inset-bottom)); -webkit-overflow-scrolling:touch; }
  .favorites-scroll > *{ width:min(100%,680px); margin-left:auto; margin-right:auto; }
  .favorite-item{ padding:16px 0 18px; }
  .favorite-item + .favorite-item{ border-top:1px solid var(--line-faint); }
  .favorite-item-head{ display:flex; align-items:center; gap:8px; margin-bottom:8px; }
  .favorite-item-kind{ color:var(--text-soft); font:600 11px/1 var(--font-en),var(--font-cn); letter-spacing:.12em; text-transform:uppercase; }
  .favorite-item-date{ color:var(--text-faint); font:500 11.5px/1 var(--font-en); font-variant-numeric:tabular-nums; }
  .favorite-item-star{
    margin-left:auto; width:34px; height:34px; border:0; border-radius:50%; padding:0; display:grid; place-items:center;
    background:transparent; color:var(--text); cursor:pointer; -webkit-tap-highlight-color:transparent;
  }
  .favorite-item-text{ color:var(--text); font:400 15.5px/1.75 var(--font-cn),var(--font-en); overflow-wrap:anywhere; }
  .favorite-item.is-inner .favorite-item-text{ color:var(--text-soft); font-style:italic; }
  .favorites-empty{ margin:40px 0 0; color:var(--text-faint); font-size:13px; line-height:1.7; text-align:center; }
  .home-dashboard .xposter-card{ margin-top:14px; }
  /* Same visual language as the Claude quota card, but in normal flow with the
     other Home cards rather than floating over the hero. */
  .xposter-card{ width:100%; margin:12px 0 0; padding:16px 15px 15px; border:1px solid var(--hairline); border-radius:20px; background:transparent; }
  .xposter-card.hidden{ display:none; }
  .xposter-card .claude-quota-window{ margin-top:12px; }
  .xposter-card .claude-quota-window + .claude-quota-window{ margin-top:12px; }
  .xposter-refresh{ display:inline-flex; align-items:center; gap:5px; padding:0; border:0; background:transparent; color:var(--text-faint); font-size:11px; font-family:inherit; cursor:pointer; }
  .xposter-refresh .ph{ font-size:12px; }
  .xposter-refresh:active{ opacity:.6; }
  .xposter-note{ min-height:16px; margin:10px 0 0; color:var(--text-faint); font-size:11.5px; line-height:1.5; }
  .home-shell.bisca-open{ grid-template-rows:minmax(0,1fr); }
  .home-shell.bisca-open .home-dock{ display:none; }
  .home-shell.bar-open{ grid-template-rows:minmax(0,1fr); }
  .home-shell.bar-open .home-dock{ display:none; }
  .home-shell.candy-open{ grid-template-rows:minmax(0,1fr); }
  .home-shell.candy-open .home-dock{ display:none; }
  .home-shell.gallery-open{ grid-template-rows:minmax(0,1fr); }
  .home-shell.gallery-open .home-dock{ display:none; }
  .home-shell.code-open{ grid-template-rows:minmax(0,1fr); }
  .home-shell.code-open .home-dock{ display:none; }
  .home-view.bisca-view:not([hidden]){ display:flex; flex-direction:column; place-items:stretch; padding:0; overflow:hidden; background:var(--bg); }
  .bisca-embed-bar{
    flex:none; min-height:calc(58px + env(safe-area-inset-top)); padding:calc(env(safe-area-inset-top) + 8px) 12px 8px;
    border-bottom:1px solid var(--hairline); display:grid; grid-template-columns:44px minmax(0,1fr) 44px; align-items:center;
  }
  .bisca-embed-title{ margin:0; font:600 16px/1.2 var(--font-cn),var(--font-en); text-align:center; }
  .bisca-embed-action{ width:44px; height:42px; padding:0; border:0; background:transparent; color:var(--text); display:grid; place-items:center; cursor:pointer; }
  .bisca-embed-action .ph{ font-size:22px; }
  .bisca-embed-frame{ flex:1; width:100%; min-height:0; border:0; background:var(--surface); }
  /* 吧台：顶上那条和 Bisca 一样；框里的吧台网页自己是米色纸底。框在 iPhone 上拿不到底部横条的尺寸，
     所以底下那截由这一层垫出来，颜色跟吧台的纸一样，接缝看不出来。 */
  .home-view.bar-view:not([hidden]){
    display:flex; flex-direction:column; place-items:stretch; padding:0 0 env(safe-area-inset-bottom);
    overflow:hidden; background:#eee8dc;
  }
  .home-view.bar-view .bisca-embed-bar{ background:var(--bg); }
  .bar-embed-frame{ flex:1; width:100%; min-height:0; border:0; background:#eee8dc; }
  .bar-embed-error{ flex:none; margin:0; padding:10px 16px; color:var(--danger); font-size:13px; line-height:1.5; background:var(--bg); }
  .bar-embed-error[hidden]{ display:none; }
  /* 糖罐：整屏就是它自己的网页（它自带返回键）。框在 iPhone 上拿不到刘海和底部横条的尺寸，
     上下两截由这一层垫出来，颜色是糖罐那张纸的颜色（上游 --c-paper），接缝看不出来。 */
  .home-view.candy-view:not([hidden]){
    display:flex; flex-direction:column; place-items:stretch;
    padding:env(safe-area-inset-top) 0 env(safe-area-inset-bottom); overflow:hidden; background:#f7ead7;
  }
  .candy-embed-frame{ flex:1; width:100%; min-height:0; border:0; background:#f7ead7; }
  .candy-embed-error{ flex:none; display:flex; align-items:center; gap:4px; padding:6px 8px; background:var(--bg); }
  .candy-embed-error[hidden]{ display:none; }
  .candy-embed-error p{ flex:1; margin:0; color:var(--danger); font-size:13px; line-height:1.5; }
  .home-view.gallery-view:not([hidden]){ display:flex; flex-direction:column; place-items:stretch; padding:0; overflow:hidden; background:var(--bg); }
  .gallery-bar{
    flex:none; min-height:calc(58px + env(safe-area-inset-top)); padding:calc(env(safe-area-inset-top) + 8px) 12px 8px;
    border-bottom:1px solid var(--hairline); display:grid; grid-template-columns:64px minmax(0,1fr) 64px; align-items:center;
  }
  .gallery-title{ margin:0; font:600 16px/1.2 var(--font-cn),var(--font-en); text-align:center; }
  .gallery-bar-action{ min-width:44px; height:42px; padding:0 8px; border:0; background:transparent; color:var(--text); cursor:pointer; font:500 14px/1 var(--font-cn),var(--font-en); }
  .gallery-bar-action:first-child{ justify-self:start; font-size:22px; }
  .gallery-bar-action:last-child{ justify-self:end; }
  .gallery-scroll{ flex:1; min-height:0; overflow:auto; overscroll-behavior:contain; padding:16px 16px calc(24px + env(safe-area-inset-bottom)); }
  .gallery-summary{ min-height:22px; margin:0 0 12px; color:var(--text-faint); font:500 12px/1.45 var(--font-cn),var(--font-en); }
  .gallery-filter{ flex:none; display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:6px; padding:0 16px 12px; }
  .gallery-filter-tab{ height:34px; padding:0 6px; border:1px solid var(--hairline); border-radius:17px; background:transparent; color:var(--text-faint); cursor:pointer; font:600 12px/1 var(--font-cn),var(--font-en); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .gallery-filter-tab.is-on{ border-color:var(--line-bold); background:var(--fill-strong); color:var(--text-on-fill); }
  .gallery-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(124px,1fr)); gap:14px 10px; }
  .gallery-photo{ min-width:0; padding:0; border:0; background:transparent; color:var(--text); text-align:left; cursor:pointer; }
  .gallery-thumb{ position:relative; width:100%; aspect-ratio:1; overflow:hidden; border:1px solid var(--hairline); border-radius:16px; display:grid; place-items:center; background:transparent; }
  .gallery-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }
  .gallery-placeholder{ padding:10px; color:var(--text-faint); font:500 12px/1.45 var(--font-cn),var(--font-en); text-align:center; }
  .gallery-photo.selected .gallery-thumb{ outline:3px solid var(--line-bold); outline-offset:-3px; }
  .gallery-select-mark{ position:absolute; right:8px; top:8px; width:24px; height:24px; border:1.5px solid var(--line-bold); border-radius:50%; display:none; place-items:center; background:var(--bg); color:var(--text-on-fill); font-size:15px; }
  .gallery-selecting .gallery-select-mark{ display:grid; }
  .gallery-photo.selected .gallery-select-mark{ border-color:var(--line-bold); background:var(--fill-strong); }
  .gallery-photo-time{ display:block; margin:7px 2px 0; color:var(--text-faint); font:500 11px/1.35 var(--font-cn),var(--font-en); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .gallery-actions{ flex:none; min-height:66px; padding:9px 14px calc(9px + env(safe-area-inset-bottom)); border-top:1px solid var(--hairline); display:grid; grid-template-columns:minmax(0,1fr) auto auto; align-items:center; gap:10px; background:var(--bg); }
  .gallery-actions[hidden]{ display:none; }
  .gallery-selected-count{ color:var(--text-faint); font:500 12px/1.4 var(--font-cn),var(--font-en); }
  .gallery-action-button{ min-width:68px; height:40px; padding:0 14px; border:1px solid var(--hairline); border-radius:20px; background:transparent; color:var(--text); cursor:pointer; font:600 13px/1 var(--font-cn),var(--font-en); }
  .gallery-action-button.danger{ border-color:var(--line-bold); background:var(--fill-strong); color:var(--text-on-fill); }
  .gallery-action-button:disabled{ opacity:.4; cursor:default; }
  @media (max-width:420px){
    .gallery-grid{ grid-template-columns:repeat(3,minmax(0,1fr)); gap:11px 7px; }
    .gallery-scroll{ padding-left:10px; padding-right:10px; }
  }
  /* ════════════ 点子本（2026-09-27）════════════
     骨架照猫页：顶上一条（返回 · 标题），下面整页一个滚动区。多一个顶上的"丢进来"框和一排五档标签。
     第一版只有前端，没接后端之前只在演示模式里露出来（见 main.js 的「点子本」）。 */
  .home-view.ideas-view:not([hidden]){ place-items:stretch; padding:0; overflow:hidden; display:flex; flex-direction:column; }
  .ideas-bar{
    flex:none; display:grid; grid-template-columns:44px minmax(0,1fr) 44px; align-items:center;
    padding:calc(10px + env(safe-area-inset-top)) 8px 6px;
  }
  .ideas-bar-action{
    width:44px; height:44px; border:0; border-radius:50%; background:transparent;
    color:var(--text); display:grid; place-items:center; font-size:20px; cursor:pointer;
  }
  .ideas-bar-title{ margin:0; font:600 16px/1 var(--font-cn),var(--font-en); text-align:center; }
  /* ════════════ 作品册（2026-09-30）════════════
     和点子本同一副骨架：顶上一条（返回 · 上传）、大字标题、一道细线，下面整页一个滚动区。
     卡片两列：图、标题、「模型全名 · 日期」。少框：图下面的字直接落在底上，不另外套框。 */
  .home-view.works-view:not([hidden]){ place-items:stretch; padding:0; overflow:hidden; display:flex; flex-direction:column; }
  .works-scroll{ padding-top:14px; }
  .works-series{ display:flex; gap:6px; flex-wrap:wrap; margin:0 2px 14px; }
  .works-series[hidden]{ display:none; }
  .works-series-tab{
    padding:6px 14px; border:1px solid var(--line); border-radius:999px; background:transparent;
    color:var(--text-soft); font:500 13px/1.2 var(--font-cn),var(--font-en); cursor:pointer;
  }
  .works-series-tab.is-on{ border-color:var(--text); color:var(--text); font-weight:600; }
  .works-grid{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:18px 12px; }
  .works-card{ position:relative; min-width:0; }
  .works-thumb{
    display:block; width:100%; aspect-ratio:3/4; padding:0; border:1px solid var(--line-faint); border-radius:14px;
    overflow:hidden; background:var(--surface); cursor:zoom-in;
  }
  .works-thumb img{ width:100%; height:100%; object-fit:contain; display:block; }
  .works-card-text{ display:flex; flex-direction:column; gap:3px; padding:8px 30px 0 2px; }
  .works-card-title{ color:var(--text); font:600 14px/1.35 var(--font-cn),var(--font-en); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .works-card-meta{ color:var(--text-faint); font:500 11.5px/1.35 var(--font-cn),var(--font-en); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .works-card-more{
    position:absolute; right:-4px; bottom:-2px; width:34px; height:34px; border:0; background:none; border-radius:50%;
    color:var(--text-faint); font-size:20px; display:grid; place-items:center; cursor:pointer;
  }
  .works-field{ display:flex; flex-direction:column; gap:6px; margin:0 0 14px; }
  .works-field > span{ color:var(--text-faint); font:500 12px/1 var(--font-cn),var(--font-en); letter-spacing:.1em; }
  .works-field input{
    width:100%; padding:10px 12px; border:1px solid var(--line); border-radius:12px; background:transparent;
    color:var(--text); font:16px/1.4 var(--font-cn),var(--font-en);
  }
  /* 故事那一块（2026-10-01）：他的故事和她的留言借点子本留言那套样子（.idea-comment）。 */
  .works-story .idea-comment.is-his{ margin-bottom:4px; }
  .works-story-empty{ color:var(--text-faint); font:400 13.5px/1.6 var(--font-cn),var(--font-en); }
  .works-comment-remove{ margin-left:8px; padding:0; border:0; background:none; color:var(--text-faint); font:400 11.5px/1.5 var(--font-cn),var(--font-en); cursor:pointer; }
  .works-field .idea-reply-box textarea{ max-height:30dvh; }
  .works-model-options{ display:flex; flex-wrap:wrap; gap:6px; }
  .works-model-options .ideas-tag-option{ flex:0 0 auto; padding:7px 12px; }
  /* 以前的样子：横着一排，现在这版在最左，往右越来越早。 */
  .works-history[hidden]{ display:none; }
  .works-history-row{ display:flex; gap:12px; overflow-x:auto; overflow-y:hidden; padding-bottom:4px; scrollbar-width:none; overscroll-behavior-x:contain; }
  .works-history-row::-webkit-scrollbar{ display:none; }
  .works-version{ flex:0 0 108px; margin:0; display:flex; flex-direction:column; gap:6px; }
  .works-version-thumb{
    display:block; width:100%; aspect-ratio:3/4; padding:0; border:1px solid var(--line-faint); border-radius:10px;
    overflow:hidden; background:var(--surface); cursor:zoom-in;
  }
  .works-version.is-current .works-version-thumb{ border-color:var(--caeruleus); }
  .works-version-thumb img{ width:100%; height:100%; object-fit:contain; display:block; }
  .works-version figcaption{ display:flex; flex-direction:column; gap:3px; min-width:0; }
  .works-version-meta{ color:var(--text-soft); font:500 11px/1.35 var(--font-cn),var(--font-en); }
  .works-version-note{ color:var(--text-faint); font:400 11px/1.4 var(--font-cn),var(--font-en); display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }
  .works-version-now{ color:var(--caeruleus); font:600 11px/1.6 var(--font-cn),var(--font-en); }
  /* 「改代码」那颗：在「以前的样子」下面、两颗大按钮上面，一行小字，不抢眼。 */
  .works-code-entry{
    display:inline-flex; align-items:center; gap:6px; margin:0 0 14px; padding:8px 14px; border:1px solid var(--line);
    border-radius:999px; background:none; color:var(--text); font:500 13px/1.2 var(--font-cn),var(--font-en); cursor:pointer;
  }
  .works-code-entry[hidden]{ display:none; }
  .works-code-entry i{ font-size:16px; }
  /* 改代码那一页：几乎占满整屏；上面预览，下面代码。代码自动折行（手机上左右滑着找太累），字用等宽的。 */
  .instructions-editor-sheet.work-code-sheet{ height:calc(100dvh - env(safe-area-inset-top) - 10px); min-height:0; }
  .work-code-preview{ position:relative; flex:0 0 34%; min-height:0; margin-top:8px; border-radius:20px; background:var(--surface); overflow:hidden; }
  /* 百分比高度在网格里算不出来，图会撑出框被切掉；钉在框里四周留 8px，整张牌永远看得全。 */
  .work-code-preview img{ position:absolute; inset:8px; width:calc(100% - 16px); height:calc(100% - 16px); object-fit:contain; display:block; }
  .work-code-status{ min-height:18px; margin:6px 4px 0; color:var(--text-soft); font:500 12px/1.5 var(--font-cn),var(--font-en); text-align:center; }
  .work-code-status.is-bad{ color:var(--danger); }
  .instructions-editor-text.work-code-text{
    margin-top:6px; padding:14px 4px; max-height:none; white-space:pre-wrap; word-break:break-all; overflow:auto;   /* max-height：全局 textarea 那条 110px 是给聊天输入框的 */
    font:400 16px/1.55 ui-monospace,SFMono-Regular,Menlo,monospace; tab-size:2;   /* 小于 16 的话 iPhone 一点进去整页放大 */
  }
  .works-version-restore{
    align-self:flex-start; margin-top:2px; padding:4px 10px; border:1px solid var(--line); border-radius:999px; background:none;
    color:var(--text); font:500 11px/1.4 var(--font-cn),var(--font-en); cursor:pointer;
  }
  /* 猫眼 Oracle（2026-10-01）：纯黑白灰，全走调色板。入口页三扇门，塔罗页一副摊开的牌。 */
  .home-view.oracle-view:not([hidden]),
  .home-view.tarot-view:not([hidden]){ place-items:stretch; padding:0; overflow:hidden; display:flex; flex-direction:column; }
  .oracle-doors{ display:flex; flex-direction:column; gap:12px; padding-top:18px; }
  .oracle-view .ideas-hero-rule i{ color:var(--text-faint); }   /* 纯黑白灰：点子本那只图标是蓝的，这里不要 */
  .oracle-door{
    display:grid; grid-template-columns:auto 1fr; align-items:baseline; gap:4px 12px; width:100%; padding:18px 20px;
    border:1px solid var(--line); border-radius:22px; background:none; color:var(--text); text-align:left; cursor:pointer;
  }
  .oracle-door-name{ font:600 20px/1.2 var(--font-cn),var(--font-en); letter-spacing:.12em; }
  .oracle-door-en{ color:var(--text-faint); font:500 11px/1 var(--font-en); letter-spacing:.3em; }
  .oracle-door-note{ grid-column:1 / -1; color:var(--text-soft); font:400 13px/1.5 var(--font-cn),var(--font-en); }
  .oracle-door.is-soon{ border-style:dashed; color:var(--text-disabled); cursor:default; }
  .oracle-door.is-soon .oracle-door-note,.oracle-door.is-soon .oracle-door-en{ color:var(--text-disabled); }

  .tarot-stage{ position:relative; flex:1 1 auto; min-height:0; display:flex; flex-direction:column; align-items:center; overflow:hidden; padding-bottom:12px; }
  .tarot-hint{ margin:10px 0 8px; color:var(--text); font:400 16px/1.4 var(--font-cn),var(--font-en); letter-spacing:.08em; }
  .tarot-rule{ display:flex; align-items:center; gap:10px; width:70%; color:var(--text-faint); }
  .tarot-rule span{ flex:1; height:1px; background:var(--line); }
  .tarot-rule i{ font-size:18px; }
  /* 扇形：每张绕着下方很远的一个点转，所以摊开是一道弧。拖动时只改 --a，不重画。 */
  .tarot-fan{ position:relative; flex:1 1 auto; width:100%; min-height:220px; touch-action:none; user-select:none; -webkit-user-select:none; }
  .tarot-card{
    /* 整副放在页面靠下（2026-10-01 她画了红线），高到「解牌」落在牌下面、不压着牌：牌高 178、按钮连底边约 70，再留点给两边往下弯的牌。 */
    position:absolute; left:50%; top:max(70px, calc(100% - 275px)); width:104px; height:178px; margin-left:-52px; padding:0; border:0; background:none;
    transform-origin:50% 500px; cursor:pointer; will-change:transform;
    transition:transform .32s cubic-bezier(.22,.8,.24,1);
  }
  .tarot-fan.is-dragging .tarot-card{ transition:none; }
  /* 抽中的那张：顺着它自己的方向往外凸出来（不是拿走），再点一下缩回去——两下都走上面那条 transition。 */

  /* 转到两边看不见的：干脆不画（原来只是透明，手机照样在画）。 */
  .tarot-card.is-far{ visibility:hidden; pointer-events:none; }
  /* 不加阴影（2026-10-01 她说拖起来一卡一卡的）：78 张每一下都要重画阴影，是转动时最费的一块。 */
  .tarot-card .tarot-back{ width:100%; height:100%; display:block; }
  /* 牌背是小克画的原图（一张 <img>）：照原样放，不裁，手指按住也不会拖出一张图来。 */
  img.tarot-back{ object-fit:contain; -webkit-user-drag:none; user-select:none; pointer-events:none; }
  .tarot-foot{ position:absolute; z-index:500; left:0; right:0; bottom:14px; display:flex; flex-direction:column; align-items:center; gap:10px; pointer-events:none; }   /* 浮在牌上面 */
  .tarot-read{
    /* 浮在黑牌上面：一道浅边，浅色模式下黑按钮才不和黑牌糊在一起。 */
    pointer-events:auto; padding:11px 34px; border:1px solid var(--line-strong); border-radius:999px; background:var(--fill-strong); color:var(--text-on-fill);
    font:600 15px/1.2 var(--font-cn),var(--font-en); letter-spacing:.3em; cursor:pointer;
  }
  .tarot-read[hidden]{ display:none; }
  /* 想问的事（2026-10-01）：只有一道底线，不加框；字 16 号，小了 iPhone 一点进去整页放大。摆上桌以后就只读。
     一行写不下就往下长（她要问题能整句显示出来），高度由 main.js 的 fitTarotQuestion 量。
     全局给 textarea 定的几样（撑满一行、最高 110、窄屏 15 号字）在这里都改掉；
     选中时那圈粗框也不要（她叫它"雷霆大白框"）——那条是 input/textarea:focus-visible，比单写一个类名更"重"，得带上 :focus-visible 才压得住。 */
  .tarot-question{
    flex:none; display:block; width:min(82%,340px); max-height:none; min-height:0; margin:14px 0 0; padding:6px 2px; overflow:hidden; resize:none;
    border:0; border-bottom:1px solid var(--line); border-radius:0; background:none;
    color:var(--text); text-align:center; font:400 16px/1.5 var(--font-cn),var(--font-en); letter-spacing:.06em; outline:none;
  }
  .tarot-question:focus-visible{ outline:none; }
  .tarot-question[hidden]{ display:none; }   /* 上面写了 display:block，不补这一句 hidden 就不管用 */
  .tarot-question::placeholder{ color:var(--text-faint); }
  .tarot-question:read-only{ border-bottom-color:transparent; }
  /* 摆上桌（2026-10-01）：按「解牌」后扇形沉下去淡掉，抽到的牌落到正中，背朝上，一张一张点开翻。 */
  .tarot-fan{ transition:opacity .45s ease, transform .55s cubic-bezier(.22,.8,.24,1); }
  .tarot-stage.is-table .tarot-fan{ opacity:0; transform:translateY(90px); pointer-events:none; }
  .tarot-table{ position:absolute; z-index:400; left:0; right:0; top:30%; display:flex; justify-content:center; gap:14px; padding:0 18px; }
  .tarot-table[hidden]{ display:none; }
  .tarot-laid{ position:relative; width:min(29vw,118px); aspect-ratio:350 / 600; padding:0; border:0; background:none; cursor:pointer; perspective:900px; }
  .tarot-table.is-one .tarot-laid{ width:min(44vw,170px); }
  .tarot-laid-inner{ position:absolute; inset:0; transform-style:preserve-3d; transition:transform .6s cubic-bezier(.22,.8,.24,1); }
  .tarot-laid.is-flipped .tarot-laid-inner{ transform:rotateY(180deg); }
  .tarot-laid .tarot-back,.tarot-laid .tarot-face{ backface-visibility:hidden; -webkit-backface-visibility:hidden; }
  .tarot-laid .tarot-back{ position:absolute; inset:0; width:100%; height:100%; }
  .tarot-laid .tarot-face{ transform:rotateY(180deg); }
  .tarot-laid.no-anim .tarot-laid-inner{ transition:none; }
  /* 翻开的牌面：她找的那张纸，淡一半（和 3D 那张一样），黑字；深色模式下也是一张白纸。
     版面照 3D 那张占位牌（tarot3d.ts 的 placeholderFront，1050×1800）一比一换算成牌宽的百分比（cqw），
     所以多大都长一个样：桌上那张、飞起来的替身、3D 的那张，换来换去看不出来。 */
  .tarot-face{
    position:absolute; inset:0; container-type:inline-size; border-radius:4.6% / 2.7%; overflow:hidden;
    background:linear-gradient(var(--paper-veil), var(--paper-veil)), url("./textures/tarot-paper.jpg") center / cover, var(--paper);
    box-shadow:inset 0 0 0 1px var(--line-faint), 0 6px 18px var(--shade-warm-2);   /* 白纸放在米白的页面上：一圈极淡的边和一点影子，不然化在页面里 */
    color:var(--paper-ink);
  }
  .tarot-face-art{ position:absolute; inset:0; }
  .tarot-face.is-reversed .tarot-face-art{ transform:rotate(180deg); }
  .tarot-face-art::before,.tarot-face-art::after{ content:""; position:absolute; border:0 solid var(--paper-ink); pointer-events:none; }
  .tarot-face-art::before{ inset:3% 5.14%; border-width:.38cqw; }
  .tarot-face-art::after{ inset:4% 6.86%; border-width:.19cqw; }
  .tarot-face-num,.tarot-face-name,.tarot-face-foot{ position:absolute; left:0; right:0; transform:translateY(-50%); text-align:center; font-family:var(--font-cn); line-height:1; white-space:nowrap; }
  .tarot-face-num{ top:16.67%; font-size:9.14cqw; font-weight:600; }
  .tarot-face-name{ top:50%; font-size:11.43cqw; font-weight:600; }
  .tarot-face-foot{ top:83.33%; font-size:4.38cqw; font-weight:400; opacity:.45; }
  /* 桌上翻开的牌底下写名字：字正着（逆位的牌面倒着，名字照样读得出来），比牌宽一点也不换行。 */
  .tarot-laid-name{
    position:absolute; left:50%; top:calc(100% + 12px); transform:translateX(-50%); white-space:nowrap; pointer-events:none;
    color:var(--text); font:500 13px/1.3 var(--font-cn),var(--font-en); letter-spacing:.12em; text-indent:.12em;
  }
  .tarot-table.is-one .tarot-laid-name{ font-size:15px; letter-spacing:.2em; text-indent:.2em; }
  .tarot-ask{ display:flex; flex-direction:column; align-items:center; gap:10px; pointer-events:auto; }
  .tarot-ask[hidden]{ display:none; }
  .tarot-ask-alt{
    padding:11px 34px; border:1px solid var(--line-strong); border-radius:999px; background:none; color:var(--text);
    font:600 15px/1.2 var(--font-cn),var(--font-en); letter-spacing:.3em; cursor:pointer;
  }
  /* 两颗一样大（2026-10-01 她说一大一小不好看）：同宽、同高、同字号，只差实心和描边。
     字距拉开以后最后一个字后面也多一截，用 text-indent 补在前面，字才在正中。 */
  .tarot-ask .tarot-read,.tarot-ask .tarot-ask-alt{ box-sizing:border-box; width:184px; padding:11px 0; text-indent:.3em; text-align:center; }
  .tarot-drag{ margin:0; text-align:center; color:var(--text-faint); font:400 12px/1 var(--font-cn),var(--font-en); letter-spacing:.1em; }
  /* 拿在手里的那张（2026-10-01）：整屏一层压暗，和编辑 CLAUDE.md 时那层一样（--scrim、.42 秒淡入），底下的页面透得过来。
     桌上那张先以一张"替身"（.tarot-proxy，平面的）飞到正中长大，3D 的那张画好了再露出来（is-live），放下时反过来。 */
  .tarot-3d{ position:fixed; inset:0; z-index:380; }
  .tarot-3d[hidden]{ display:none; }
  .tarot-3d-scrim{ position:absolute; inset:0; background:var(--scrim); opacity:0; transition:opacity .42s ease; }
  .tarot-3d.is-open .tarot-3d-scrim{ opacity:1; }
  .tarot-3d-stage{ position:absolute; inset:0; touch-action:none; }
  .tarot-3d-stage canvas{ display:block; opacity:0; }
  .tarot-3d.is-live .tarot-3d-stage canvas{ opacity:1; }
  .tarot-3d-hint{ opacity:0; transition:opacity .3s ease; }
  .tarot-3d.is-open .tarot-3d-hint{ opacity:1; }
  /* 「拖着转一转」挂在牌底下（--rest-bottom 是牌下沿，main.js 量好填进来）：放屏幕最底下会压着底栏的字。
     字一律白的（--on-scrim）：压暗那层底下是什么都是暗的。原来用的 --text-on-fill 在深色模式里是黑的，
     黑字压在暗底上，名字浮出来了她也看不见（10-01 她截图里那行几乎透明的「权杖五」）。 */
  .tarot-3d-hint{ position:absolute; z-index:1; left:0; right:0; top:calc(var(--rest-bottom, 75%) + 18px); color:var(--on-scrim); text-shadow:0 1px 8px var(--shade-warm-3); pointer-events:none; }
  /* 翻开那一刻，牌下面逐字浮出这张牌叫什么（「权杖三·逆位」）：每个字晚一点点，从下面一点、有点糊，升上来变清楚。
     名字出来时「拖着转一转」那行让开（同一个位置）。再拿起已经翻开的牌，名字直接在（is-instant），不重播。 */
  .tarot-3d-name{
    position:absolute; z-index:1; left:0; right:0; top:calc(var(--rest-bottom, 75%) + 12px); margin:0; text-align:center; pointer-events:none;
    color:var(--on-scrim); text-shadow:0 1px 8px var(--shade-warm-3); font:500 17px/1.4 var(--font-cn),var(--font-en); letter-spacing:.24em; text-indent:.24em; white-space:pre;
    opacity:0; transition:opacity .3s ease;
  }
  .tarot-3d.is-open .tarot-3d-name{ opacity:1; }
  .tarot-glyphs span{ display:inline-block; opacity:0; animation:tarotGlyph .85s cubic-bezier(.22,.8,.24,1) forwards; animation-delay:calc(var(--base, 0ms) + var(--i) * 150ms); }
  .tarot-glyphs.is-instant span{ animation:none; opacity:1; }
  @keyframes tarotGlyph{
    from{ opacity:0; transform:translateY(7px); filter:blur(5px); }
    to{ opacity:1; transform:none; filter:none; }
  }
  .tarot-3d.has-name .tarot-3d-hint{ opacity:0; }
  /* 猫眼说的话（2026-10-01）：底下升起一块，纯黑白灰（猫眼的规矩）。等老猫开口时那行字轻轻呼吸。 */
  .oracle-sheet{ position:fixed; inset:0; z-index:380; }
  .oracle-sheet[hidden]{ display:none; }
  .oracle-sheet-scrim{ position:absolute; inset:0; background:var(--scrim); opacity:0; transition:opacity .42s ease; }
  .oracle-sheet.is-open .oracle-sheet-scrim{ opacity:1; }
  .oracle-sheet-panel{
    position:absolute; left:0; right:0; bottom:0; max-height:74vh; overflow:auto; -webkit-overflow-scrolling:touch;
    padding:20px 24px calc(env(safe-area-inset-bottom, 0px) + 28px); border-radius:26px 26px 0 0;
    background:var(--surface); color:var(--text); box-shadow:0 -10px 30px var(--shade-warm-2);
    transform:translateY(100%); transition:transform .42s cubic-bezier(.22,.8,.24,1);
  }
  .oracle-sheet.is-open .oracle-sheet-panel{ transform:none; }
  .oracle-sheet-head{ display:flex; align-items:center; gap:6px; margin:0 0 14px; color:var(--text-faint); font:600 12.5px/1.3 var(--font-cn),var(--font-en); letter-spacing:.2em; }
  .oracle-sheet-head i{ font-size:15px; }
  .oracle-sheet-body{ font:400 15.5px/1.85 var(--font-cn),var(--font-en); white-space:pre-wrap; word-break:break-word; }
  .oracle-sheet-body em{ color:var(--text-soft); }
  .oracle-sheet-body.is-waiting,.oracle-sheet-body.is-error{ color:var(--text-faint); text-align:center; padding:18px 0; }
  .oracle-sheet-body.is-waiting{ animation:oracleBreath 2.4s ease-in-out infinite; }
  @keyframes oracleBreath{ 0%,100%{ opacity:.45; } 50%{ opacity:1; } }
  @media (prefers-reduced-motion: reduce){ .oracle-sheet-body.is-waiting{ animation:none; } }
  /* 老猫说了"回去也跟你家那只橘猫说说吧"：「让小克看看」那颗轻轻亮一下（小克的主意） */
  .tarot-read.is-nudged{ box-shadow:0 0 0 3px var(--bg), 0 0 0 4px var(--line-bold); }
  .tarot-proxy{ position:absolute; z-index:3; transform-origin:0 0; pointer-events:none; will-change:transform; }
  .tarot-proxy .tarot-back{ position:absolute; inset:0; width:100%; height:100%; }
  /* 点子本的头（2026-09-28，照她刷到的「工程板」）：大字标题、一行字距拉开的小字、一道中间带星星的细线。 */
  .ideas-hero{ flex:none; margin:-30px 0 6px; text-align:center; pointer-events:none; }
  .ideas-hero-title{ margin:0; color:var(--text); font:500 30px/1.2 var(--font-cn),var(--font-en); letter-spacing:.3em; text-indent:.3em; }
  .ideas-hero-sub{ margin:8px 0 0; color:var(--text-faint); font:500 11.5px/1 var(--font-en); letter-spacing:.24em; }
  .ideas-hero-sub b{ color:var(--caeruleus); font-weight:700; }
  .ideas-hero-rule{ display:flex; align-items:center; justify-content:center; gap:10px; margin:12px auto 0; width:min(72%,340px); color:var(--caeruleus); }
  .ideas-hero-rule span{ flex:1; height:1px; background:linear-gradient(90deg, transparent, var(--line-strong)); }
  .ideas-hero-rule span:last-child{ background:linear-gradient(90deg, var(--line-strong), transparent); }
  .ideas-hero-rule i{ font-size:13px; }
  .ideas-compose{
    flex:none; margin:4px 16px 12px; padding:12px 12px 10px; border-radius:20px;
    background:var(--surface); border:1px solid var(--line-faint);
  }
  .ideas-compose textarea{
    width:100%; min-height:44px; max-height:140px; resize:none; border:0; padding:2px 2px 6px; background:transparent;
    color:var(--text); font:16px/1.5 var(--font-cn),var(--font-en);
  }
  .ideas-compose textarea:focus{ outline:none; }
  .ideas-compose-shots,.idea-sheet-shots{ display:flex; gap:8px; flex-wrap:wrap; padding:4px 0 8px; }
  .ideas-compose-shots[hidden]{ display:none; }
  .ideas-shot{ position:relative; width:64px; height:64px; border-radius:12px; overflow:hidden; background:var(--tint); flex:none; }
  .ideas-shot img{ width:100%; height:100%; object-fit:cover; display:block; }
  .ideas-shot-remove{
    position:absolute; top:3px; right:3px; width:22px; height:22px; border:0; border-radius:50%;
    background:var(--scrim); color:var(--text-on-fill); display:grid; place-items:center; font-size:12px; cursor:pointer;
  }
  .ideas-compose-row{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
  .ideas-compose-clip{
    min-height:34px; padding:0 12px; border:1px solid var(--line); border-radius:999px; background:transparent;
    color:var(--text-soft); display:inline-flex; align-items:center; gap:6px; cursor:pointer; font:500 13.5px/1 var(--font-cn),var(--font-en);
  }
  .ideas-compose-send{
    min-height:34px; padding:0 16px; border:0; border-radius:999px; background:var(--fill-strong); color:var(--text-on-fill);
    cursor:pointer; font:600 14px/1 var(--font-cn),var(--font-en);
  }
  .ideas-compose-send:disabled{ opacity:.35; cursor:default; }
  /* 只许左右滑、不许上下滑（2026-09-30 她发现能被推上去）：iPhone 上 overflow-x:auto 会把上下也一起放开，
     而里面的字比这一排高一点点。overflow-y 关死、手势也只认横着的。 */
  .ideas-tabs{
    flex:none; display:flex; gap:0; margin:0 16px 12px; border-bottom:1px solid var(--line-faint);
    overflow-x:auto; overflow-y:hidden; touch-action:pan-x; overscroll-behavior:contain; scrollbar-width:none;
  }
  .ideas-tabs::-webkit-scrollbar{ display:none; }
  /* 这一排是点子本顶上那五档：工程板的样子，中文 + 条数，下面一行英文，选中的底下一道细线。
     详情里「挪到」那排也叫 ideas-tab，还是原来的胶囊（见下面 .idea-sheet-status）。 */
  .ideas-tabs .ideas-tab{
    flex:1 0 auto; min-width:62px; padding:6px 4px 9px; border:0; background:transparent; position:relative;
    color:var(--text-faint); cursor:pointer; display:flex; flex-direction:column; align-items:center; gap:4px;
  }
  .ideas-tab-main{ display:inline-flex; align-items:baseline; gap:4px; font:600 14.5px/1 var(--font-cn),var(--font-en); }
  .ideas-tab-en{ font:600 9.5px/1 var(--font-en); letter-spacing:.2em; opacity:.75; }
  .ideas-tab-count{ font:500 11.5px/1 var(--font-en); opacity:.8; }
  .ideas-tabs .ideas-tab.is-on{ color:var(--text); background:transparent; border-color:transparent; }
  .ideas-tabs .ideas-tab.is-on::after{
    content:""; position:absolute; left:22%; right:22%; bottom:-1px; height:2px; border-radius:2px; background:var(--caeruleus);
  }
  .ideas-tab{
    flex:none; min-height:34px; padding:0 13px; border:1px solid var(--hairline); border-radius:17px;
    background:transparent; color:var(--text-faint); cursor:pointer; font:600 12.5px/1 var(--font-cn),var(--font-en);
    display:inline-flex; align-items:center; gap:5px;
  }
  .ideas-tab.is-on{ border-color:var(--line-bold); background:var(--fill-strong); color:var(--text-on-fill); }
  /* 点选那几排（丢点子时 / 点开一条时）：左边一个小标签，右边一条分段按钮，点亮的是白底描边。 */
  .ideas-tag-rows{ display:flex; flex-direction:column; gap:7px; padding:4px 0 10px; }
  .ideas-tag-rows[hidden]{ display:none; }
  .ideas-tag-rows.in-sheet{ margin:2px 0 6px; }
  .ideas-tag-row{ display:grid; grid-template-columns:36px minmax(0,1fr); align-items:center; gap:8px; }
  .ideas-tag-label{ color:var(--text-faint); font:500 12px/1 var(--font-cn),var(--font-en); letter-spacing:.1em; }
  .ideas-tag-options{ display:flex; gap:3px; padding:3px; border-radius:12px; background:var(--tint); }
  .ideas-tag-row.is-wrap .ideas-tag-options{ flex-wrap:wrap; }
  .ideas-tag-option{
    flex:1 1 0; min-height:30px; padding:0 8px; border:1px solid transparent; border-radius:9px; background:transparent;
    color:var(--text-soft); cursor:pointer; font:500 13px/1 var(--font-cn),var(--font-en); white-space:nowrap;
  }
  .ideas-tag-row.is-wrap .ideas-tag-option{ flex:0 0 auto; }
  .ideas-tag-option.is-on{ background:var(--surface); border-color:var(--line-bold); color:var(--text); }
  /* 模块那排最后一颗「＋」：加一个她自己的模块。 */
  .ideas-tag-option.is-add{ flex:0 0 auto; min-width:34px; border:1px dashed var(--line-strong); color:var(--text-faint); }
  .ideas-scroll{ flex:1; min-height:0; overflow:auto; padding:0 16px calc(24px + env(safe-area-inset-bottom)); -webkit-overflow-scrolling:touch; }
  .ideas-plan{
    margin:0 0 10px; padding:12px 14px; border-radius:18px; background:var(--tint);
    color:var(--text); font:500 13.5px/1.6 var(--font-cn),var(--font-en);
  }
  .ideas-plan[hidden]{ display:none; }
  .ideas-plan-head{ display:flex; align-items:center; gap:6px; margin-bottom:4px; color:var(--text-soft); font-size:12px; font-weight:600; }
  .ideas-list{ display:flex; flex-direction:column; gap:10px; }
  .ideas-card{
    width:100%; padding:13px 14px; border-radius:18px; border:1px solid var(--line-faint); background:var(--surface);
    color:var(--text); text-align:left; cursor:pointer; display:flex; flex-direction:column; gap:7px;
  }
  .ideas-card{ position:relative; }
  .ideas-card-top{ display:flex; align-items:flex-start; justify-content:space-between; gap:8px; min-height:18px; }
  .ideas-card-tags{ display:flex; align-items:center; flex-wrap:wrap; gap:8px; min-width:0; }
  .ideas-kind{ display:inline-flex; align-items:center; gap:5px; font:600 12px/1 var(--font-cn),var(--font-en); }
  /* 黑白灰里分三种，靠形状不靠颜色：Bug 蓝色实心点（唯一带颜色的，因为它最该先看），需求黑色实心点，杂活空心圈。 */
  .ideas-kind{ color:var(--text-soft); }
  .ideas-kind i{ width:7px; height:7px; border-radius:50%; background:currentColor; box-sizing:border-box; }
  .ideas-kind.is-bug{ color:var(--caeruleus); }
  .ideas-kind.is-feature{ color:var(--text); }
  .ideas-kind.is-chore i{ background:transparent; border:1.3px solid currentColor; }
  .ideas-card-id{ color:var(--text-disabled); font:500 11.5px/1 ui-monospace, SFMono-Regular, Menlo, monospace; }
  .ideas-area{ padding:3px 8px; border:1px solid var(--line); border-radius:999px; color:var(--text-soft); font:500 11px/1 var(--font-cn),var(--font-en); }
  /* 优先级圆章：一圈细边再套一圈，像盖上去的印。P0 蓝底白字（最急），P1 蓝圈，P2 深灰圈，P3 浅灰圈。 */
  .ideas-stamp{
    flex:none; width:38px; height:38px; margin:-4px -4px 0 0; border-radius:50%; display:grid; place-items:center;
    border:1.5px solid currentColor; box-shadow:inset 0 0 0 2.5px var(--surface), inset 0 0 0 3.5px currentColor;
    color:var(--text-faint); font:700 12px/1 var(--font-en);
  }
  .ideas-stamp.is-p0{ color:var(--accent-fg); background:var(--caeruleus); border-color:var(--caeruleus); box-shadow:inset 0 0 0 2.5px var(--caeruleus), inset 0 0 0 3.5px var(--accent-fg); }
  .ideas-stamp.is-p1{ color:var(--caeruleus); }
  .ideas-stamp.is-p2{ color:var(--text-soft); }
  .ideas-card-text{ font:500 15px/1.5 var(--font-cn),var(--font-en); white-space:pre-wrap; word-break:break-word; }
  .ideas-card-shots{ display:flex; gap:6px; }
  .ideas-card-shots .ideas-shot{ width:48px; height:48px; border-radius:10px; }
  .ideas-card-note{
    padding:8px 10px; border-radius:12px; background:var(--tint); color:var(--text-soft);
    font:400 12.5px/1.55 var(--font-cn),var(--font-en);
  }
  .ideas-card-note b,.idea-sheet-note b,.idea-sheet-done b{ color:var(--text); font-weight:600; }
  /* 超过三行先折起来（2026-09-29）：「展开」在框外右下，淡字，点了看全文。 */
  .ideas-card-note-wrap{ display:block; }
  .ideas-card-note{ display:block; }
  /* 折的是框里那层字：折在灰框上的话，第四行会从框的下边距里露出半截。 */
  .ideas-card-note-text{ display:block; }
  .ideas-card-note-text.is-folded{ display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:3; line-clamp:3; overflow:hidden; }
  .ideas-card-note-toggle{ display:block; margin-top:4px; text-align:right; color:var(--text-faint); font:500 12px/1.4 var(--font-cn),var(--font-en); cursor:pointer; }
  .ideas-card-note-toggle[hidden]{ display:none; }
  .ideas-card-meta{ display:flex; align-items:center; gap:6px; color:var(--text-faint); font-size:11.5px; padding-top:9px; border-top:1px dashed var(--line); }
  .ideas-card-ago{ margin-left:auto; }
  .ideas-size{ display:inline-flex; gap:3px; margin-right:2px; }
  .ideas-size i{ width:6px; height:6px; border-radius:50%; border:1px solid var(--text-faint); }
  .ideas-size i.on{ background:var(--text-soft); border-color:var(--text-soft); }
  .ideas-card-meta .ideas-secret{ display:inline-flex; align-items:center; gap:3px; color:var(--text-faint); font-size:10.5px; }
  .ideas-card-meta .ideas-by-cc{ padding:2px 7px; border-radius:999px; background:var(--fill-strong); color:var(--text-on-fill); font-size:10.5px; font-weight:600; }
  /* 筛选（2026-09-30）：一颗淡淡的小按钮，筛上了变深、带个数；点开是和丢点子时一样的点选。 */
  .ideas-filter-bar{ display:flex; align-items:center; justify-content:flex-end; gap:12px; margin:0 2px 8px; }
  .ideas-filter-toggle,.ideas-filter-clear{
    display:inline-flex; align-items:center; gap:4px; padding:4px 0; border:0; background:none; cursor:pointer;
    color:var(--text-faint); font:500 12.5px/1.4 var(--font-cn),var(--font-en);
  }
  .ideas-filter-toggle.is-on{ color:var(--text); font-weight:600; }
  .ideas-filter-toggle i{ font-size:14px; }
  .ideas-filter-clear[hidden]{ display:none; }
  .ideas-filter-rows{ margin:0 0 14px; }
  .ideas-empty{ padding:40px 10px; color:var(--text-faint); text-align:center; font:500 13px/1.7 var(--font-cn),var(--font-en); }
  .idea-sheet-meta{ margin:2px 4px 8px; color:var(--text-faint); font-size:12.5px; }
  .idea-sheet-text{
    width:100%; min-height:88px; padding:12px; border:1px solid var(--line); border-radius:14px; background:var(--surface);
    color:var(--text); resize:vertical; font:16px/1.55 var(--font-cn),var(--font-en);
  }
  .idea-sheet-text:focus{ outline:none; border-color:var(--line-bold); }
  .idea-sheet-shots .ideas-shot{ width:84px; height:84px; cursor:zoom-in; }
  .idea-sheet-note,.idea-sheet-done{
    margin:4px 0 10px; padding:10px 12px; border-radius:14px; background:var(--tint); color:var(--text-soft);
    font:400 13.5px/1.6 var(--font-cn),var(--font-en);
  }
  .idea-sheet-note[hidden],.idea-sheet-done[hidden]{ display:none; }
  .idea-sheet-label{ margin:6px 4px 6px; color:var(--text-faint); font-size:12px; }
  /* 他的留言（2026-09-29）：左边一道蓝线是他的颜色；她回的缩在下面。 */
  .idea-sheet-comments{ margin:2px 0 10px; }
  .idea-sheet-comments[hidden]{ display:none; }
  .idea-comment{ margin:0 0 10px; color:var(--text); font:400 14px/1.6 var(--font-cn),var(--font-en); white-space:pre-wrap; }
  .idea-comment.is-his{ padding-left:10px; border-left:2px solid var(--caeruleus); }
  .idea-comment.is-her{ margin:6px 0 0; padding-left:10px; border-left:1px solid var(--line-strong); color:var(--text-soft); font-size:13.5px; }
  .idea-comment-who{ display:block; color:var(--text-faint); font-size:11.5px; line-height:1.5; white-space:normal; }
  .idea-comment-reply{ margin-top:4px; padding:0; border:0; background:none; color:var(--text-faint); font:500 12px/1.4 var(--font-cn),var(--font-en); cursor:pointer; }
  .idea-reply-box{ display:flex; gap:8px; align-items:flex-end; margin-top:6px; }
  .idea-reply-box textarea{
    flex:1; min-height:40px; padding:8px 10px; border:1px solid var(--line); border-radius:12px; background:transparent;
    color:var(--text); resize:vertical; font:16px/1.5 var(--font-cn),var(--font-en);
  }
  .idea-reply-box button{
    flex:none; padding:9px 12px; border:0; border-radius:999px; background:var(--fill-strong); color:var(--text-on-fill);
    font:600 13px/1 var(--font-cn),var(--font-en); cursor:pointer;
  }
  /* 卡片上的留言，像朋友圈评论：一句一行，他的名字用他的蓝。 */
  .ideas-card-comments{ display:block; padding:8px 10px; border-radius:12px; background:var(--tint); }
  .ideas-card-comment{ display:block; color:var(--text-soft); font:400 12.5px/1.55 var(--font-cn),var(--font-en); white-space:pre-wrap; }
  .ideas-card-comment b{ color:var(--text); font-weight:600; }
  .ideas-card-comment b.is-xiaoke{ color:var(--caeruleus); }
  .ideas-card-time{ margin-left:6px; color:var(--text-faint); font-size:11px; white-space:nowrap; }
  .idea-sheet-status{ display:flex; flex-wrap:wrap; gap:6px; }
  .idea-sheet-actions{ margin-top:10px; }
  .code-idea-notice{ align-self:flex-end; margin-top:4px; color:var(--text-faint); font-size:11.5px; line-height:1.4; }
  .code-xiaoke-mail{ align-self:flex-end; max-width:86%; margin-top:6px; padding-left:10px; border-left:2px solid var(--caeruleus); }
  .code-xiaoke-mail-head{ color:var(--text-faint); font-size:11.5px; line-height:1.4; }
  .code-msg.xiaoke-letter{ display:flex; }
  .code-msg.xiaoke-letter .code-xiaoke-mail{ align-self:flex-start; max-width:86%; margin:6px 0; }
  .code-xiaoke-mail-text{ margin-top:4px; color:var(--text-soft); font-size:13px; line-height:1.55; white-space:pre-wrap; }
  .idea-handoff{
    width:100%; min-height:46px; margin-top:16px; border:1px solid var(--line-strong); border-radius:23px;
    background:transparent; color:var(--text); cursor:pointer; display:flex; align-items:center; justify-content:center; gap:8px;
    font:600 15px/1 var(--font-cn),var(--font-en);
  }

  /* ════════════ 共同养猫（docs/CAT_SYSTEM_DESIGN.md）════════════
     一整页，顶上三个标签：猫 / 记录 / 档案。它是 Home 的子页面，所以
     铺底图那一层复用 shell 那套 data-shell-bg，只是图换成猫自己那张——
     不另开一套 CSS，否则每加一个卡片样式都要写两遍。 */
  /* `:not([hidden])` 不是装饰：`.home-view[hidden]{display:none}` 和这条同样是两个
     选择器，权重打平，而这条在后面——不带这个否定就会**反过来赢**，于是猫页面
     永远显示着，糊在 Home 上面。这一页的所有邻居都带着它，照抄。 */
  /* padding:0 别漏：.home-view 默认四周 32px，邻居们都清掉了，猫这页漏了——整页缩在屏幕中间一圈，
     底下那排「喂 / 摸 / 玩」还被切掉一截（2026-09-26 她截图报的）。 */
  .home-view.cat-view:not([hidden]){ place-items:stretch; padding:0; overflow:hidden; display:flex; flex-direction:column; }
  .cat-bar{
    flex:none; display:grid; grid-template-columns:44px minmax(0,1fr) 44px; align-items:center;
    padding:calc(10px + env(safe-area-inset-top)) 8px 6px;
  }
  .cat-bar-action{
    width:44px; height:44px; border:0; border-radius:50%; background:transparent;
    color:var(--text); display:grid; place-items:center; font-size:20px; cursor:pointer;
  }
  .cat-bar-title{ margin:0; font:600 16px/1 var(--font-cn),var(--font-en); text-align:center; }
  .cat-tabs{ flex:none; display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:6px; padding:0 16px 12px; }
  .cat-tab{
    height:34px; padding:0 6px; border:1px solid var(--hairline); border-radius:17px;
    background:transparent; color:var(--text-faint); cursor:pointer;
    font:600 12px/1 var(--font-cn),var(--font-en);
  }
  .cat-tab.is-on{ border-color:var(--line-bold); background:var(--fill-strong); color:var(--text-on-fill); }
  .cat-scroll{ flex:1; min-height:0; overflow:auto; padding:0 16px calc(24px + env(safe-area-inset-bottom)); -webkit-overflow-scrolling:touch; }
  .cat-pane[hidden]{ display:none; }

  /* ── 出生：一辈子只有一次，所以给它一个停顿，别按完就翻到仪表盘 ── */
  .cat-birth{ min-height:60vh; display:grid; place-items:center; gap:22px; text-align:center; }
  .cat-birth-slot{
    width:min(72vw,240px); aspect-ratio:1; border-radius:36px;
    background:var(--glass-half); display:grid; place-items:center;
    color:var(--text-faint); font-size:44px;
  }
  .cat-birth-lines{ min-height:96px; display:grid; align-content:start; gap:8px; font:500 15px/1.5 var(--font-cn),var(--font-en); }
  .cat-birth-line{ opacity:0; transform:translateY(6px); animation:catLineIn .5s ease forwards; }
  @keyframes catLineIn{ to{ opacity:1; transform:none; } }
  .cat-birth-btn{
    min-width:150px; height:46px; padding:0 22px; border:0; border-radius:23px;
    background:var(--fill-strong); color:var(--text-on-fill); cursor:pointer; font:600 15px/1 var(--font-cn),var(--font-en);
  }
  .cat-birth-btn:disabled{ opacity:.45; cursor:default; }

  /* ── 猫那一页 ── */
  .cat-hero{
    position:relative; width:100%; aspect-ratio:4/3; overflow:hidden;
    border-radius:26px; background:var(--glass-half);
    display:grid; place-items:center;
  }
  .cat-hero img{ width:100%; height:100%; object-fit:cover; display:block; }
  .cat-hero-empty{ color:var(--text-faint); font:600 20px/1.4 var(--font-en),var(--font-cn); letter-spacing:.04em; }
  /* 睡着了压一行淡字。不用图标：它就是一个状态，不是一个按钮。 */
  .cat-hero-sleep{
    position:absolute; left:0; right:0; bottom:0; padding:28px 16px 12px;
    background:linear-gradient(0deg, rgba(31,31,29,.42) 0, rgba(31,31,29,0) 100%);
    color:var(--text-on-fill); font:600 13px/1 var(--font-cn),var(--font-en); text-align:center;
  }
  .cat-headline{ display:flex; align-items:baseline; gap:8px; margin:14px 2px 10px; }
  .cat-headline strong{ font:600 21px/1.2 var(--font-en),var(--font-cn); }
  .cat-headline span{ color:var(--text-faint); font:500 13px/1.3 var(--font-cn),var(--font-en); }
  /* 五个小圆牌。**不做百分比条**：条会把它变成一个要管理的指标，而猫的行为只分
     四档，条上多出来的精度是假的。要紧的那个靠**字本身的轻重**跳出来。
     这些胶囊不上真模糊（同屏五个，而且它们很小，糊了也看不出来），
     靠 --glass-drop-quiet 在浅色底图上撑住边界。 */
  .cat-chips{ display:flex; flex-wrap:wrap; gap:7px; margin:0 0 16px; }
  .cat-chip{
    padding:6px 12px; border-radius:15px; background:var(--glass-half);
    color:var(--text-faint); font:500 12.5px/1.2 var(--font-cn),var(--font-en);
  }
  html[data-shell-bg="on"] .cat-chip{ box-shadow:var(--glass-drop-quiet); }
  .cat-chip[data-band="2"]{ color:var(--text); font-weight:600; }
  .cat-chip[data-band="3"]{ color:var(--text); font-weight:700; background:var(--glass-thick); }
  /* 上一次它的反应。两行分开是有意的：上面那行是规则定的事实，下面那行是演出来的。
     页面上让你看得见这个区别。 */
  .cat-said{ margin:0 0 18px; }
  .cat-fact{ margin:0 0 6px; color:var(--text-faint); font:500 12.5px/1.5 var(--font-cn),var(--font-en); }
  .cat-reply{
    margin:0; padding:12px 14px; border-radius:18px 18px 18px 6px;
    background:var(--glass-ai, var(--glass-thick));
    font:500 14.5px/1.65 var(--font-cn),var(--font-en); white-space:pre-wrap; word-break:break-word;
  }
  html[data-shell-bg="on"] .cat-reply{ box-shadow:var(--glass-edge), var(--glass-drop); }
  .cat-reply.is-waiting{ color:var(--text-faint); }
  /* ── 输入区：一排类型 + 两个框 ── */
  .cat-compose{ padding:14px; border-radius:22px; background:var(--glass-half); }
  .cat-kinds{ display:flex; gap:7px; margin:0 0 10px; }
  .cat-kind{
    flex:1; height:32px; border:1px solid var(--hairline); border-radius:16px;
    background:transparent; color:var(--text-faint); cursor:pointer;
    font:600 12.5px/1 var(--font-cn),var(--font-en);
  }
  .cat-kind.is-on{ border-color:var(--line-bold); background:var(--fill-strong); color:var(--text-on-fill); }
  .cat-field{
    width:100%; margin:0 0 9px; padding:10px 12px; border:1px solid var(--hairline);
    border-radius:14px; background:var(--glass-half); color:var(--text);
    font:500 14px/1.5 var(--font-cn),var(--font-en); resize:none;
    -webkit-appearance:none; appearance:none;
  }
  .cat-field:focus{ outline:none; border-color:var(--line-bold); }
  .cat-send{
    width:100%; height:44px; border:0; border-radius:22px; background:var(--fill-strong); color:var(--text-on-fill);
    cursor:pointer; font:600 14.5px/1 var(--font-cn),var(--font-en);
  }
  .cat-send:disabled{ opacity:.4; cursor:default; }
  /* ── 记录：整段一块玻璃，不是一行一块（一行一块十几行就是十几块，太碎）── */
  .cat-records{ border-radius:22px; }
  .cat-day{ margin:16px 2px 8px; color:var(--text-faint); font:600 11.5px/1 var(--font-cn),var(--font-en); }
  .cat-record{ padding:12px 2px; border-bottom:1px solid var(--hairline); }
  .cat-record:last-child{ border-bottom:0; }
  .cat-record-head{ display:flex; gap:8px; align-items:baseline; margin:0 0 5px; }
  .cat-record-time{ color:var(--text-faint); font:500 11.5px/1 var(--font-en),var(--font-cn); }
  .cat-record-who{ font:600 12.5px/1 var(--font-cn),var(--font-en); }
  .cat-record-said{ margin:0 0 4px; font:500 13.5px/1.6 var(--font-cn),var(--font-en); }
  .cat-record-fact{ margin:0 0 4px; color:var(--text-faint); font:500 12.5px/1.55 var(--font-cn),var(--font-en); }
  /* 它的反应保留换行：提示词允许它写一到三行。 */
  .cat-record-reply{ margin:0; font:500 13.5px/1.6 var(--font-cn),var(--font-en); white-space:pre-wrap; word-break:break-word; }
  .cat-empty{ padding:36px 0; color:var(--text-faint); font:500 13px/1.6 var(--font-cn),var(--font-en); text-align:center; }
  .cat-more{
    display:block; width:100%; height:40px; margin:12px 0 0; border:1px solid var(--hairline);
    border-radius:20px; background:transparent; color:var(--text-faint); cursor:pointer;
    font:600 12.5px/1 var(--font-cn),var(--font-en);
  }
  /* 上面那条 display:block 会盖掉 hidden 属性——和猫页面糊在 Home 上是同一种错。
     只有四条记录时「看更早的」也一直露着，就是它。 */
  .cat-more[hidden]{ display:none; }
  /* ── 档案 ── */
  .cat-file{ padding:16px; border-radius:22px; background:var(--glass-half); }
  .cat-file-row{ display:flex; justify-content:space-between; gap:14px; padding:9px 0; border-bottom:1px solid var(--hairline); }
  .cat-file-row:last-child{ border-bottom:0; }
  .cat-file-key{ color:var(--text-faint); font:500 13px/1.4 var(--font-cn),var(--font-en); }
  .cat-file-val{ font:500 13px/1.4 var(--font-cn),var(--font-en); text-align:right; }
  /* 成长这根条是**可以**做的：它只增不减、你也左右不了，看它涨是件高兴事，
     不是一个待办。五项状态不一样，所以那边只有字。 */
  .cat-grow{ margin:14px 0 0; }
  .cat-grow-label{ display:flex; justify-content:space-between; margin:0 0 7px; font:500 12.5px/1 var(--font-cn),var(--font-en); }
  .cat-grow-track{ height:6px; border-radius:3px; background:var(--tint); overflow:hidden; }
  .cat-grow-fill{ display:block; height:100%; border-radius:3px; background:var(--progress-to); }
  .cat-file-note{ margin:14px 0 0; color:var(--text-faint); font:500 12.5px/1.6 var(--font-cn),var(--font-en); }
  /* 它说话用的模型（2026-10-01）：档案下面单独一块。字 16 号：小了 iPhone 一点进去整页放大。 */
  .cat-model{ margin-top:14px; }
  .cat-model-title{ margin:0 0 4px; font:600 14px/1.4 var(--font-cn),var(--font-en); }
  .cat-model-note{ margin:0 0 12px; color:var(--text-faint); font:500 12.5px/1.6 var(--font-cn),var(--font-en); }
  .cat-model-label{ display:block; margin:0 0 5px; color:var(--text-faint); font:500 12.5px/1.4 var(--font-cn),var(--font-en); }
  .cat-model-field{ font-size:16px; }
  .cat-model .cat-send{ margin-top:4px; }
  .cat-model-status{ min-height:1.6em; margin:8px 0 0; color:var(--text-faint); font:500 12.5px/1.6 var(--font-cn),var(--font-en); text-align:center; }
  .cat-model-status.is-error{ color:var(--danger); }
  /* 小本子：一整块能写的纸。字号 16 是为了 iPhone 点进去不自动放大。 */
  .cat-memory-text{ min-height:260px; font-size:16px; line-height:1.7; }
  .cat-memory-last{ margin:0 0 10px; color:var(--text-faint); font:500 12.5px/1.6 var(--font-cn),var(--font-en); }
  .cat-home-thumb{ overflow:hidden; }
  .cat-home-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }

  .home-view.settings-view{ place-items:start center; overflow:auto; padding:48px 24px 32px; }
  .home-settings{ width:min(100%,520px); margin:auto 0; }
  .home-settings h1{ margin:0; font:500 clamp(26px,5vw,40px)/1.15 var(--font-en),var(--font-cn); text-align:center; }
  .home-settings-sub{ margin:9px 0 22px; color:var(--text-faint); font-size:13px; text-align:center; }
  .data-manage-card{
    padding:18px; border:1px solid var(--line-faint); border-radius:20px;
    background:var(--glass-thick); box-shadow:0 10px 30px var(--shade-cool-1);
  }
  /* 2026-09-28 首页改版起走正常流（原来绝对定位浮在隐形时钟上）。 */
  .home-avatar-controls{
    position:relative; z-index:2; margin:40px auto 0; display:grid; grid-template-columns:minmax(0,1fr) auto minmax(0,1fr); align-items:center;
    width:min(calc(100% - 24px),620px);
  }
  .home-avatar-button{ padding:0; border:0; border-radius:50%; background:transparent; cursor:pointer; }
  .home-avatar-button:first-child{ justify-self:start; }
  .home-avatar-button:last-child{ justify-self:end; }
  .home-avatar-button:active{ transform:scale(.96); }
  .home-avatar-preview{
    display:block; width:clamp(66px,16vw,93px); height:clamp(66px,16vw,93px); border-radius:50%;
    background-color:transparent; background-position:center; background-size:cover; background-repeat:no-repeat;
    box-shadow:none;
  }
  .home-avatar-preview[data-avatar-preview="ai"]{ background-color:var(--avatar-ai-color); background-image:var(--avatar-ai); }
  .home-avatar-preview[data-avatar-preview="human"]{ background-color:var(--avatar-human-color); background-image:var(--avatar-human); }
  .together-counter{ min-width:132px; color:var(--text); text-align:center; pointer-events:none; }
  .together-counter-label{ display:block; font:500 12px/1 var(--font-en),var(--font-cn); letter-spacing:.08em; }
  .together-counter-days{ display:block; margin-top:5px; font:600 clamp(42px,10vw,58px)/.9 var(--font-en),var(--font-cn); font-variant-numeric:tabular-nums; letter-spacing:-.045em; }
  .together-counter-since{ display:block; margin-top:9px; color:var(--text-faint); font:500 11px/1.2 var(--font-en),var(--font-cn); white-space:nowrap; }
  .data-manage-title{ color:var(--text); font-size:15px; font-weight:500; }
  .data-manage-copy{ margin:6px 0 15px; color:var(--text-faint); font-size:12px; line-height:1.55; }
  .session-data-actions{ display:grid; grid-template-columns:1fr 1fr; gap:9px; }
  .session-data-btn{
    min-height:42px; border:1px solid var(--line-faint); border-radius:14px;
    background:var(--surface); color:var(--text-soft); cursor:pointer; font:500 13px/1 var(--font-cn),var(--font-en);
  }
  .session-data-btn:active{ transform:scale(.97); }
  .session-data-btn:disabled{ opacity:.48; cursor:default; }
  .session-data-btn.legacy-import-entry{ grid-column:1/-1; }
  .session-data-hint{ grid-column:1/-1; min-height:16px; color:var(--text-faint); font-size:11px; line-height:1.4; text-align:center; }
  .legacy-import-dialog{ position:fixed; inset:0; z-index:260; display:grid; align-items:end; }
  .legacy-import-scrim{ position:absolute; inset:0; border:0; background:var(--scrim); }
  .legacy-import-sheet{
    position:relative; width:min(100%,620px); max-height:min(82vh,760px); margin:0 auto;
    padding:16px 18px calc(20px + env(safe-area-inset-bottom)); border-radius:28px 28px 0 0;
    background:var(--bg); box-shadow:0 -18px 60px var(--shade-warm-3); overflow:auto;
  }
  .legacy-import-head{ display:grid; grid-template-columns:44px 1fr 64px; align-items:center; gap:8px; }
  .legacy-import-title{ color:var(--text); font-size:18px; font-weight:600; text-align:center; }
  .legacy-import-close,.legacy-import-confirm{
    min-height:40px; border:0; border-radius:20px; background:transparent; color:var(--text-soft);
    cursor:pointer; font:600 14px/1 var(--font-cn),var(--font-en);
  }
  .legacy-import-close{ font-size:25px; font-weight:400; }
  .legacy-import-confirm{ background:var(--fill-strong); color:var(--text-on-fill); }
  .legacy-import-confirm:disabled{ opacity:.45; cursor:default; }
  .legacy-import-summary{ margin:16px 0 12px; color:var(--text-soft); font-size:13px; line-height:1.65; }
  .legacy-import-preview{ display:flex; flex-direction:column; gap:9px; padding:14px; border-radius:18px; background:var(--surface-soft); }
  .legacy-preview-message{ max-width:82%; padding:9px 12px; border-radius:16px; color:var(--text); font-size:13px; line-height:1.55; white-space:pre-wrap; }
  .legacy-preview-message.ai{ align-self:flex-start; background:var(--surface); }
  .legacy-preview-message.human{ align-self:flex-end; background:var(--surface-mid); }
  .legacy-import-status{ min-height:18px; margin-top:12px; color:var(--text-faint); font-size:12px; text-align:center; }
  .claude-md-entry{
    width:100%; min-height:66px; margin-top:14px; padding:12px 16px; border:1px solid var(--line-faint);
    border-radius:18px; background:var(--glass-thick); color:var(--text); cursor:pointer;
    display:flex; align-items:center; gap:13px; text-align:left; box-shadow:0 10px 30px var(--shade-cool-1);
  }
  .claude-md-entry:active{ transform:scale(.985); }
  .claude-md-entry-icon{ width:22px; height:22px; flex:none; color:var(--text-soft); }
  .claude-md-entry-icon svg,.claude-md-entry-chevron svg{ width:100%; height:100%; display:block; }
  .claude-md-entry-copy{ min-width:0; display:grid; gap:3px; }
  .claude-md-entry-copy strong{ font-size:15px; font-weight:500; }
  .claude-md-entry-copy span{ color:var(--text-faint); font-size:11.5px; line-height:1.4; }
  .claude-md-entry-chevron{ width:18px; height:18px; margin-left:auto; flex:none; color:var(--text-disabled); }
  .memory-library-link{
    margin:20px auto 0; min-height:46px; padding:0 20px; border:1px solid var(--line-faint); border-radius:23px;
    display:inline-flex; align-items:center; justify-content:center; gap:9px;
    color:var(--text); text-decoration:none; font:500 15px/1 var(--font-cn),var(--font-en);
    transition:transform .15s ease;
  }
  .memory-library-link:active{ transform:scale(.97); }
  .memory-library-link:focus-visible{ outline:2px solid currentColor; outline-offset:3px; }
  /* 高度从 3+58+18=79 收到 8+46+2=56（约 −30%）。底下原来那 18px 是让开 home indicator
     用的，但 env(safe-area-inset-bottom) 本来就已经让开了一次，等于白空一块。
     上下这两个数**加起来固定是 10**：总高不变，把它们对调就是把整排图标上下挪。
     现在 8/2 是"再往下放一点"那一版。安全区那份不算在内，不能砍。 */
  .home-dock{
    position:relative; z-index:2; width:100%; padding:8px max(8px,calc((100vw - 640px)/2)) calc(2px + env(safe-area-inset-bottom));
    border-top:1px solid var(--line-faint); background:rgba(249,249,247,.84);
    -webkit-backdrop-filter:blur(30px) saturate(1.28); backdrop-filter:blur(30px) saturate(1.28);
  }
.home-dock-items{ display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); min-height:46px; }
  .home-dock-item{
    position:relative; min-width:0; border:0; background:transparent; color:var(--text-faint); padding:2px 2px;
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px; cursor:pointer;
    font:400 12px/1 var(--font-en),var(--font-cn);
  }
  .home-dock-item svg{ width:23px; height:23px; display:block; }
  .home-dock-item[aria-current="page"]{ color:var(--text); }
  .home-dock-item:active{ transform:scale(.96); }
  .terminal-panel{
    position:fixed;
    inset:0;
    z-index:260;
    display:flex;
    flex-direction:column;
    background:#050607;
    color:#d7f7df;
    font-family:"SFMono-Regular", Consolas, "Cascadia Mono", monospace;
    transform:translateX(100%);
    transition:transform .42s cubic-bezier(.2,.8,.2,1);
  }
  .terminal-panel.open{ transform:translateX(0); }
  .terminal-top{
    flex:none;
    min-height:calc(52px + env(safe-area-inset-top));
    display:flex;
    align-items:center;
    gap:10px;
    padding:calc(env(safe-area-inset-top) + 8px) 12px 8px;
    border-bottom:1px solid rgba(157,255,188,.18);
    background:#080a0b;
  }
  .terminal-back{
    flex:none;
    width:34px;
    height:34px;
    border:0;
    border-radius:50%;
    background:transparent;
    color:#d7f7df;
    display:grid;
    place-items:center;
    padding:0;
    cursor:pointer;
  }
  .terminal-back:active{ transform:scale(.9); }
  .terminal-back svg{ width:21px; height:21px; display:block; }
  .terminal-title{ min-width:0; display:flex; flex-direction:column; gap:2px; line-height:1.15; }
  .terminal-title strong{ font-size:14px; font-weight:600; color:#effff4; }
  .terminal-title span{
    font-size:11px;
    line-height:1.65;               /* 父级 1.15 装不下 Literata 的上下伸部，这一格又会裁字 */
    color:rgba(215,247,223,.62);
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
  }
  .terminal-log{
    flex:1 1 auto;
    overflow:auto;
    padding:14px 14px 18px;
    font-size:13px;
    line-height:1.55;
    white-space:pre-wrap;
    overflow-wrap:anywhere;
  }
  .term-entry{ margin:0 0 13px; }
  .term-user{ color:#9dffbc; }
  .term-assistant{ color:#d7f7df; }
  .term-tool{
    color:#E7E7E3;
    border-left:2px solid rgba(126,174,255,.45);
    padding-left:10px;
  }
  .term-muted{ color:rgba(215,247,223,.48); }
  .term-cmd{ color:#9dffbc; }
  .term-err{ color:#ffb0a3; }
  .terminal-form{
    flex:none;
    display:flex;
    align-items:flex-end;
    gap:9px;
    padding:10px 12px calc(10px + env(safe-area-inset-bottom));
    border-top:1px solid rgba(157,255,188,.18);
    background:#080a0b;
  }
  .terminal-prompt{ flex:none; color:#9dffbc; font-size:15px; line-height:34px; }
  .terminal-input{
    flex:1 1 auto;
    min-width:0;
    max-height:120px;
    border:0;
    outline:0;
    resize:none;
    background:transparent;
    color:#effff4;
    font:inherit;
    font-size:15px;
    line-height:1.45;
    padding:6px 0;
  }
  .terminal-input::placeholder{ color:rgba(215,247,223,.34); }
  .terminal-send{
    flex:none;
    width:34px;
    height:34px;
    border:1px solid rgba(157,255,188,.34);
    border-radius:50%;
    background:rgba(157,255,188,.1);
    color:#d7f7df;
    display:grid;
    place-items:center;
    padding:0;
    cursor:pointer;
  }
  .terminal-send:active{ transform:scale(.92); }
  .terminal-send svg{ width:18px; height:18px; display:block; }
  .avatar{
    position:absolute; right: calc(var(--side-pad) - 3px); top: calc(env(safe-area-inset-top) + clamp(14px, 2.5vw, 36px));
    width: var(--avatar-size); height: var(--avatar-size); border-radius:50%; padding:0; flex:none; cursor:pointer;
    border: none;
    background-image: var(--avatar-default);
    background-color: var(--avatar-default-color);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    overflow: hidden;
    box-shadow: 0 12px 24px var(--shade-cool-2);
  }
  .avatar:focus-visible,
  button:focus-visible,
  textarea:focus-visible,
  input:focus-visible{
    outline: 2px solid var(--accent);
    outline-offset: 3px;
  }

  /* ── Messages ── */
  .scroll{
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    overflow-anchor: none;
    padding: clamp(14px, 2.4vw, 28px) var(--side-pad) var(--composer-zone);
    display: flex; flex-direction: column;
    transition: padding-bottom .28s cubic-bezier(.2,.8,.2,1);
    /* 边缘渐隐:顶部一段、底部对齐 composer 上沿一段,消息滚到边缘自然淡出 */
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--edge-fade-top), #000 calc(100% - var(--composer-zone)), transparent calc(100% - var(--composer-zone) + var(--edge-fade-tail)));
    mask-image: linear-gradient(to bottom, transparent 0, #000 var(--edge-fade-top), #000 calc(100% - var(--composer-zone)), transparent calc(100% - var(--composer-zone) + var(--edge-fade-tail)));
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  }
  .scroll::-webkit-scrollbar{ width:0; height:0; }
  .v-spacer{
    flex: 0 0 auto;
    width: 100%;
    min-height: 0;
    pointer-events: none;
  }

  /* 换日那条线（2026-09-26 改的）：和他没说话那条同一个样子——两侧细线、中间一行字、不垫胶囊，
     字直接落在底图上。上下都比两条消息之间宽得多：它的意思是"这里断开了"，贴着上面的时间和下面的
     头像就读不出来。上面 30px；下面那一行的间距见 .day + .row。改了记得改 DEFAULT_DAY_HEIGHT。 */
  .day{
    width:100%; margin:30px 0 0; padding:0;
    display:flex; align-items:center; gap:clamp(10px,2vw,16px);
    font-family:var(--font-cn),var(--font-en);
    font-size:clamp(12.5px,1.5vw,14px); line-height:1.5; color:var(--text-faint);
    border:0; border-radius:0; background:transparent;
  }
  .day::before,.day::after{ content:""; flex:1; height:1px; background:var(--hairline); }

  .row{ display:flex; position:relative; margin-top: clamp(14px, 2.2vw, 28px); }
  /* 分隔线下面也多留一截（手机上一般的换人是 16px）。 */
  .day + .row,.no-reply-row + .row{ margin-top:26px; }
  .continuity-divider{
    width:100%; margin:24px 0 4px; display:flex; align-items:center; gap:12px;
    color:var(--text-faint); font:500 11px/1 var(--font-en),var(--font-cn);
    letter-spacing:.08em; text-transform:lowercase;
  }
  .continuity-divider::before,.continuity-divider::after{ content:""; flex:1; height:1px; background:var(--hairline); }
  /* 弹弹乐留下的那条灰线:"你把 Claude 弹飞了"。不是气泡,居中一行小字。 */
  .poke-line{
    align-self:center; max-width:78vw; margin:clamp(10px,1.6vw,18px) 0 0;
    font-family:var(--font-cn); font-size:clamp(13px,1.6vw,15px); line-height:1.5;
    color:var(--text-faint); text-align:center;
  }
  .poke-line .poke-undelivered{ opacity:.7; }
  /* 他想过、最后决定不说话留下的那条线。形态是分隔线：两侧各一道细线、中间一行字，
     和日期分隔线同一套语言——这个形态天然读作旁白，线本身给了结构感，
     所以平时一块底都不用垫。有思考链时整行可点，点开就是他没说出口的那些。 */
  .no-reply-line{
    width:100%; margin:30px 0 0;   /* 和换日那条一样宽的空，理由见 .day */
    display:flex; align-items:center; gap:clamp(10px,2vw,16px);
    border:0; background:none; padding:0;
    font-family:var(--font-cn); font-size:clamp(12.5px,1.5vw,14px); line-height:1.5;
    color:var(--text-faint); text-align:center;
  }
  .no-reply-line::before,.no-reply-line::after{ content:""; flex:1; height:1px; background:var(--hairline); }
  /* 中间那截字：理由整句显示，长了就折成几行、居中（2026-10-02 她嫌省略号把他的话截断了）。
     最宽到八成，两边的细线总留着一截，还读作一条分隔线。 */
  .no-reply-copy{
    min-width:0; flex:0 1 auto; max-width:82%;
    white-space:normal; overflow-wrap:anywhere; text-wrap:balance;
  }
  .no-reply-copy .no-reply-reason{ margin-left:.34em; }
  .no-reply-line[data-openable="1"]{ cursor:pointer; }
  /* 灰线外面那一层：只负责让收尾那句签名能横跨整行挂在灰线下面。 */
  .no-reply-row{ align-self:stretch; display:flex; flex-direction:column; }
  /* 签名平时挂在气泡那一摞里，宽度按整屏算；挂在灰线下面时跟着灰线那一行走。 */
  .no-reply-row .ai-love-signature{ width:100%; margin-left:0; }
  .no-reply-line .no-reply-reason{ color:var(--text); opacity:.82; }
  /* 有思考链时才有这颗星星——它同时也是"这一轮到底有没有留下思考"的答案，
     所以别让它太淡，那是要拿来看的。 */
  .no-reply-line .no-reply-star{ margin-left:.35em; opacity:.72; }
  .row.grouped{ margin-top: clamp(4px, 0.8vw, 8px); }
  .row.human{ justify-content: flex-end; }
  .row.ai{ justify-content: flex-start; }
  /* min-width:0 是必须的：它是 .row 这个 flex 里的一项，flex 项目默认 min-width:auto，
     而 min-width 的优先级**高于 max-width**——里面只要有一段断不开的东西（长代码、
     长链接），它就会顶开上面那个 max-width，整块横着捅出屏幕。 */
  .message-stack{ display:flex; flex-direction:column; align-items:flex-start; gap:6px; min-width:0; max-width:min(78vw,720px); }
  .row.human .message-stack{ align-items:flex-end; }
  /* gap 原来 12px，和他与你之间的 25px 只差一倍，一口气说的几个气泡看着像几条（2026-09-24 收到 4px）。 */
  .message-bubbles{ display:flex; flex-direction:column; align-items:flex-start; gap:4px; position:relative; }
  .row.human .message-bubbles{ align-items:flex-end; }
  /* 星星不占位。以前它和气泡并排在一个 flex 里，横着吃掉气泡 25px 的可用宽度，
     于是同一段话里带星星的那条就比别的窄一截、右边对不齐（老毛病）。现在让它
     脱离布局浮在气泡右上角外侧：气泡该多宽还是多宽。 */
  .bubble-with-thought{ position:relative; display:flex; align-items:flex-start; max-width:100%; }
  .bubble-with-thought > .thought-entry{
    position:absolute; top:3px; left:calc(100% + 3px); margin-top:0;
  }
  /* 一段思考后面紧跟着的是工具调用、或者干脆没有正文时，星星自己占一行，
     停在它当初发生的位置上。 */
  .thought-standalone{ display:flex; align-items:center; padding:1px 0; }
  .thought-standalone .thought-entry{ margin-top:0; }
  /* 手写思考链还在写时的占位气泡：三个点自己闪，不随流式增量重建。 */
  .bubble.typing-bubble{ padding-top:14px; padding-bottom:14px; }
  .bubble-typing{ display:inline-flex; align-items:center; gap:5px; height:9px; }
  .bubble-typing i{
    width:7px; height:7px; border-radius:50%; background:currentColor; opacity:.34;
    animation:bubbleTypingDot 1.3s ease-in-out infinite;
  }
  .bubble-typing i:nth-child(2){ animation-delay:.18s; }
  .bubble-typing i:nth-child(3){ animation-delay:.36s; }
  @keyframes bubbleTypingDot{
    0%,72%,100%{ transform:translateY(0); opacity:.28; }
    36%{ transform:translateY(-4px); opacity:.78; }
  }
  @media (prefers-reduced-motion:reduce){
    .bubble-typing i{ animation:none; opacity:.45; }
  }
  /* ── 通用工具事件卡 ── Chat / 后续 Code 页面可共同喂入同一份 tool event 数据。 */
  /* 工具那行、插在正文中间的思考那行，和气泡之间空 10px（气泡之间是 4px 的 gap，这里再各加 6px）。
     先试过和气泡一样的 4px，她说"有一点点拥挤"（2026-09-24）。这两行自己挨着时不加，还是 4px——
     它们是同一段旁白，拉开了像两件事。顶上那一格思考（.thought-lines）和第一个气泡之间同样是 10px。 */
  .message-bubbles > :is(.tool-call, .thought-line){ margin-block:6px; }
  .message-bubbles > :is(.tool-call, .thought-line) + :is(.tool-call, .thought-line){ margin-top:-6px; }
  .message-bubbles > :is(.tool-call, .thought-line):first-child{ margin-top:0; }
  .message-bubbles > :is(.tool-call, .thought-line):last-child{ margin-bottom:0; }
  .tool-call{
    width:min(100%, 620px);
    animation: pop .24s cubic-bezier(.2,.8,.2,1) both;
  }
  /* 聊天里一整轮工具收成的那一行。它是旁白不是说话：字更小更轻、没有卡片底、
     圆角也小一档，和气泡拉开层级。点开才是下面那些完整的卡片。 */
  .tool-run{ width:min(100%,620px); }
  /* 贴着文字收窄靠 fit-content，不靠 inline-flex：行内的胶囊会被外面那一行的行高垫着，
     压在基线上，上面多空出十来 px、下面反而顶进下一个气泡（2026-09-24 量过：上 14px、下 -3px）。 */
  .tool-run > summary{
    display:flex; width:fit-content; max-width:100%;   /* 铺了背景图时底色胶囊才不会拉成一条 */
    align-items:center; gap:8px; min-height:26px; padding:2px 2px;
    list-style:none; cursor:pointer;
    color:var(--text-faint); font:400 clamp(11.5px,1.24vw,13px)/1.5 var(--font-cn),var(--font-en);
  }
  .tool-run > summary::-webkit-details-marker{ display:none; }
  .tool-run-text{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .tool-run-note{ flex:none; }
  .tool-run.failed > summary{ color:var(--danger); }
  .tool-run[open] > summary{ margin-bottom:6px; }
  .tool-run-detail{ display:grid; gap:6px; }
  .tool-event-card{ border:1px solid color-mix(in srgb, var(--think-flourish) 22%, transparent); border-radius:12px; overflow:hidden; background:color-mix(in srgb, var(--bubble-ai-bg) 72%, transparent); }
  .tool-event-card > summary{ display:flex; align-items:center; gap:8px; min-height:34px; padding:7px 11px; cursor:pointer; list-style:none; color:var(--think-label); font:500 clamp(12px, 1.32vw, 13.5px)/1.46 var(--font-en),var(--font-cn); }
  .tool-event-card > summary::-webkit-details-marker{ display:none; }
  .tool-event-arrow{ color:var(--think-flourish); font-size:1.06em; }
  .tool-event-state{ margin-left:auto; font-family:var(--font-cn); font-size:.9em; }
  .tool-event-card.succeeded .tool-event-state{ color:var(--success); }
  .tool-event-card.failed .tool-event-state{ color:var(--danger); }
  .tool-event-card.running .tool-event-state{ color:var(--text-faint); }
  .tool-event-count{ color:var(--text-faint); font-family:var(--font-en); font-size:.9em; }
  .tool-event-detail{ display:grid; gap:9px; padding:0 11px 11px; border-top:1px solid color-mix(in srgb, var(--think-flourish) 15%, transparent); }
  .tool-event-group > .tool-event-detail{ gap:6px; padding:9px; }
  .tool-event-group .tool-event-card{ background:color-mix(in srgb, var(--bubble-ai-bg) 92%, transparent); }
  .tool-event-field{ display:grid; gap:3px; }
  .tool-event-field label{ color:var(--text-faint); font:500 11px/1.35 var(--font-cn); }
  .tool-event-field pre{ max-height:260px; margin:0; overflow:auto; white-space:pre-wrap; overflow-wrap:anywhere; color:var(--text); font:12px/1.55 var(--font-en),var(--font-cn); }
  .tool-event-error pre{ color:var(--danger); }
  .thought-entry{
    flex:none; width:22px; height:22px; margin-top:3px; padding:0; border:0; background:transparent;
    color:var(--text-faint); display:grid; place-items:center; cursor:pointer;
    font-size:16px; line-height:1;
  }
  .thought-entry:active{ transform:scale(.9); }
  .message-time{
    display:block; margin-top:1px; padding:0 5px;
    color:var(--text-faint); font:500 11px/1.2 var(--font-en),var(--font-cn);
    letter-spacing:.01em; opacity:.82;
  }
  .row.streaming .message-time{ display:none; }
  .ai-love-signature{
    width:calc(100vw - 36px); margin-top:clamp(14px,2.2vw,22px);
    /* 两头各往里收一点，logo 和那句话不贴着屏幕边（box-sizing 是 border-box，
       所以这个 padding 不会把整条撑宽，只是把两端往中间挪）。
       第一版收多了，这是那时候的一半。 */
    padding:0 clamp(9px,2.2vw,17px);
    /* 左边那颗 logo 再往左一点点（2026-09-24，她要的）：手机上 9px → 4px，右边那句话不动。 */
    padding-left:clamp(4px,1.1vw,12px);
    display:flex; align-items:center; gap:clamp(12px,2.2vw,20px);
    color:var(--text); font:500 clamp(14px,1.65vw,17px)/1.35 var(--font-en),var(--font-cn);
  }
  .ai-love-signature img{ flex:0 0 auto; width:clamp(28px,4.2vw,38px); height:clamp(28px,4.2vw,38px); object-fit:contain; }
  .ai-love-signature span{ flex:1; text-align:right; }

  .bubble{
    max-width: min(61vw, 506px);
    padding: clamp(8px, 1.05vw, 12px) clamp(13px, 1.65vw, 18px) clamp(8px, 1.1vw, 13px);
    border-radius: var(--bubble-radius);
    position: relative;
    font-family: var(--font-cn);
    font-size: clamp(14px, 1.55vw, 16px); line-height: 1.58;
    word-wrap: break-word;
    overflow-wrap: break-word;
    animation: pop .24s cubic-bezier(.2,.8,.2,1) both;
  }
  .row[data-vkey] .bubble,
  .row[data-vkey] .think-block{ animation: none; }
  @keyframes pop{ from{ transform: translateY(5px) scale(.99);} to{ transform:none;} }
  /* 新消息入场:轻微弹性,只对刚发/刚收到那条播一次(虚拟列表复用不重播,JS 控 enter class) */
  .row[data-vkey].enter-human .bubble{ transform-origin: bottom right; animation: enterHuman .44s cubic-bezier(.34,1.46,.5,1) both; }
  .row[data-vkey].enter-ai .bubble{ transform-origin: bottom left; animation: enterAi .44s cubic-bezier(.34,1.46,.5,1) both; }
  /* 头像以前住在气泡里，跟着气泡一起弹进来；搬到气泡上面之后得自己跟上，不然它是"啪"地出现的。 */
  .row[data-vkey].enter-human .message-avatar{ transform-origin: bottom right; animation: enterHuman .44s cubic-bezier(.34,1.46,.5,1) both; }
  .row[data-vkey].enter-ai .message-avatar{ transform-origin: bottom left; animation: enterAi .44s cubic-bezier(.34,1.46,.5,1) both; }
  @keyframes enterHuman{ from{ transform: translate(6px, 9px) scale(.95); opacity:0; } 55%{ opacity:1; } to{ transform:none; opacity:1; } }
  @keyframes enterAi{ from{ transform: translate(-6px, 9px) scale(.95); opacity:0; } 55%{ opacity:1; } to{ transform:none; opacity:1; } }
  .row.ai .bubble{
    background: var(--bubble-ai-bg);
    color: var(--bubble-ai-fg);
    border: 0;
    box-shadow: 0 10px 28px var(--shade-cool-1);
  }
  .row.human .bubble{
    background: var(--bubble-human-bg);
    color: var(--bubble-human-fg);
    border: 0;
    box-shadow: 0 10px 28px var(--shade-cool-1);
  }
  /* 每段最后一条:外下角收一个小尖 */
  .row.ai.tail .bubble{ border-bottom-left-radius: 2px; }
  .row.human.tail .bubble{ border-bottom-right-radius: 2px; }

  .bubble .txt{ white-space: normal; }
  .markdown{ white-space:normal; }
  .markdown > :first-child{ margin-top:0; }
  .markdown > :last-child{ margin-bottom:0; }
  .markdown p{ margin:0 0 .72em; }   /* 原来手滑写成 `0 0:.72em`，整条是废的，段距一直吃的是浏览器默认 */
  .markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{
    margin:1em 0 .48em; line-height:1.3; font-weight:700;
  }
  .markdown h1{ font-size:1.55em; }.markdown h2{ font-size:1.38em; }.markdown h3{ font-size:1.22em; }.markdown h4{ font-size:1.1em; }
  .markdown ul,.markdown ol{ margin:.5em 0 .72em; padding-left:1.45em; }
  .markdown li{ margin:.2em 0; }.markdown li > ul,.markdown li > ol{ margin:.2em 0; }
  .markdown blockquote{ margin:.7em 0; padding:.12em 0 .12em .85em; border-left:3px solid currentColor; opacity:.78; }
  .markdown blockquote p{ margin:.36em 0; }
  .markdown hr{ height:1px; margin:1em 0; border:0; background:currentColor; opacity:.34; }
  /* 代码块**折行**，不横向滚。手机上横向滚是坏体验：它套在一个纵向滚动的列表里，
     手指往右一划多半被外层抢走，划不动就等于那半行永远读不到（用户报的就是这个）。
     pre-wrap 保留缩进，只把超长的那一行折下来；anywhere 让它连一长串没有空格的
     符号也能断——这一条还顺带治了布局：折得动，min-content 宽度就只有一个字符，
     外面的 max-width 才管得住它。不然 flex 项目那个 min-width:auto 会顶开 max-width，
     整块横着捅出屏幕。overflow:auto 留着兜底，给表格那种实在折不了的。 */
  /* 代码块是浅灰的，跟气泡一套。**这一条推翻过一次，别再按原样翻回去**：
     以前的结论是"浅色块在浅色照片上必然消失，所以必须深色"。那个结论的证据是
     rgba(120,100,80,.12)——12% 的一层暖褐薄雾，没有边、没有投影。它确实会化掉，
     但那是"12% 没有结构"化掉的，不是"浅色"化掉的。
     反证就在 Code 页上：`.code-msg.human .bubble` 是 --glass-human，一块浅灰玻璃，
     直接铺在同一张底图上，配 edge + bevel + drop 三件套，从来没消失过。
     所以这里走同一条路：**实度**（.92，浅底图上化不掉）＋ 气泡那套投影（浮起来，
     不是贴上去）。比气泡深一档是必须的——气泡是 #EFEFED，同色就等于没有这块面板。
     真要再往浅里调，先看它在一张过曝的天空照上还立不立得住，那是最难的一张。 */
  .markdown pre{
    margin:.72em 0; padding:12px 14px; max-width:100%; overflow:auto;
    border-radius:12px; background:var(--glass-code); color:var(--text);
    box-shadow:var(--glass-edge), var(--glass-drop);
    -webkit-overflow-scrolling:touch;
  }
  .markdown pre code{ padding:0; background:transparent; font: .88em/1.58 ui-monospace,"SF Mono",Menlo,monospace; white-space:pre-wrap; overflow-wrap:anywhere; }
  /* 代码块右上角那颗复制键。它挂在外面那层 wrapper 上，不是塞进 <pre> 里：
     <pre> 自己是滚动容器，按钮放进去会跟着内容一起滑走。
     让出来的是【顶上】一截空当，不是右边——这里的代码是自动换行的（pre-wrap），
     右边每少一点，ASCII 图就早一个字换行，而竖着的空间不值钱。 */
  .markdown .code-block{ position:relative; }
  .markdown .code-block > pre{ padding-top:38px; }
  .code-copy{
    position:absolute; top:8px; right:8px; width:30px; height:30px; padding:0; border:0;
    display:grid; place-items:center; border-radius:8px; cursor:pointer;
    background:var(--tint); color:var(--text);
  }
  /* Phosphor 是细描边字体，小字号下第一版那个 --text-soft 在浅灰底上几乎看不见。
     颜色拉到正文同级，字号也加一号——这颗按钮不显眼就等于没有。 */
  .code-copy i{ font-size:17px; }
  /* 左上角那行语言名。只有围栏写了语言才出现，裸 ``` 不硬编一个 "plain" 上去。
     和按钮同高同顶，两边一左一右对齐；pointer-events 关掉，免得挡住选词。 */
  .code-lang{
    position:absolute; top:8px; left:14px; height:30px; display:grid; place-items:center;
    color:var(--text-faint); font:500 11px/1 ui-monospace,"SF Mono",Menlo,monospace;
    letter-spacing:.04em; pointer-events:none; user-select:none;
  }
  .markdown-table-wrap{ width:100%; max-width:100%; margin:.72em 0; overflow-x:auto; -webkit-overflow-scrolling:touch; }
  .markdown table{ border-collapse:collapse; min-width:max-content; font-size:.9em; }
  .markdown th,.markdown td{ padding:.45em .62em; border:1px solid color-mix(in srgb,currentColor 20%,transparent); text-align:left; }
  .markdown th{ font-weight:700; }
  .markdown th[style*="right"],.markdown td[style*="right"]{ text-align:right; }
  .markdown th[style*="center"],.markdown td[style*="center"]{ text-align:center; }
  .row.streaming .bubble:last-of-type .txt:last-child::after{
    content:""; display:inline-block; width:.38em; height:.38em; margin-left:.28em;
    border-radius:50%; background:currentColor; vertical-align:.12em;
    animation:streamPulse 1s ease-in-out infinite;
  }
  @keyframes streamPulse{ 0%,100%{ opacity:.24; } 50%{ opacity:.78; } }
  .bubble.has-att{ display:flex; flex-direction:column; gap:8px; }
  .bubble.attachment-bubble{ background:transparent !important; padding:0 !important; box-shadow:none !important; }
  .att-img-link{
    display:block; width:148px; height:148px; padding:0; border:0; border-radius:14px;
    overflow:hidden; line-height:0; background:transparent; cursor:zoom-in;
  }
  .att-img{ display:block; width:100%; height:100%; object-fit:cover; border-radius:14px; }
  /* 照片裁成方块是对的——缩略图本来就该取中间，你一眼认出是哪张就够了。
     但他画的 SVG 是**一张要读的卡片**，裁一刀就只剩中间一条。 */
  .att-img-svg{ object-fit:contain; background:var(--tint); }
  /* 尺寸已知（上传时读了 viewBox）就让框贴着画的比例走，宽高由内联样式写死。
     **于是没有留白，也就不需要托底**——上面那层浅灰只在尺寸不明时（老消息）
     还兜着底，那时候框只能是方的。 */
  .att-img-link.att-img-fit{ width:auto; height:auto; }
  .att-img-fit .att-img-svg{ background:transparent; }
  .att-file{ display:flex; align-items:center; gap:10px; padding:9px 11px; min-width:170px; max-width:250px; text-decoration:none; color:inherit; background:var(--tint); border-radius:12px; }
  .att-file-ic{ flex:0 0 auto; width:36px; height:36px; display:grid; place-items:center; border-radius:9px; background:rgba(125,128,135,.20); }
  .att-file-ic svg{ width:20px; height:20px; opacity:.85; }
  .att-file-meta{ display:flex; flex-direction:column; min-width:0; }
  .att-file-name{ font-size:13px; font-weight:600; line-height:1.3; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .att-file-size{ font-size:11px; opacity:.6; margin-top:2px; }
  .att-uploading{ opacity:.62; }
  .att-img-dead img{ display:none; }
  .att-img-dead::before{ content:"\e4e0"; margin-right:5px; font-family:"Phosphor"; font-size:14px; color:var(--text-faint); }
  .att-img-dead::after{ content:"图片已失效"; display:inline-block; padding:16px 20px 16px 0; font-size:12px; color:var(--text-faint); background:transparent; }
  .att-failed{ outline:1.5px solid var(--danger); outline-offset:1px; }
  .pending-attachments{
    position:absolute; z-index:4; left:var(--side-pad); bottom:calc(100% + 8px);
    display:flex; gap:10px; width:max-content; max-width:calc(100% - var(--side-pad) - var(--side-pad));
    overflow-x:auto; overflow-y:hidden; padding:5px 4px;
    scrollbar-width:none; -webkit-overflow-scrolling:touch;
  }
  .pending-attachments::-webkit-scrollbar{ display:none; }
  .pending-attachments.hidden{ display:none; }
  .pending-att{
    position:relative; flex:0 0 82px; -webkit-flex:0 0 82px;
    width:82px; min-width:82px; max-width:82px; height:96px; overflow:hidden;
    border:1px solid var(--hairline); border-radius:17px;
    background-color:var(--bg); box-shadow:0 6px 18px var(--shade-cool-1);
    isolation:isolate;
  }
  .pending-att.image{ background-color:var(--surface-mid); }
  .pending-att.image:not(.failed){ cursor:zoom-in; }   /* 点一下看大图（2026-09-30） */
  /* 点子详情开着的时候，Code 页的输入框整个藏起来（见 main.js 的 setIdeaSheet：iPhone 上毛玻璃会盖到详情上面）。 */
  body.idea-sheet-open .code-composer,
  body.idea-sheet-open .code-voice-anchor{ visibility:hidden; }
  .idea-handoff[hidden]{ display:none; }
  /* 从点子本带过来的那条（2026-09-30）：比图片那格宽，两行字，点一下展开看。 */
  .pending-att.idea-ref{
    flex:0 0 210px; -webkit-flex:0 0 210px; width:210px; min-width:210px; max-width:210px;
    display:flex; flex-direction:column; justify-content:center; gap:3px;
    padding:8px 30px 8px 11px; background:var(--tint); cursor:pointer; text-align:left;
  }
  .idea-ref-head{ display:flex; align-items:center; gap:4px; color:var(--text-faint); font:600 11px/1.3 var(--font-cn),var(--font-en); }
  .idea-ref-head i{ font-size:13px; }
  .idea-ref-text{
    color:var(--text); font:500 13px/1.45 var(--font-cn),var(--font-en);
    display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; line-clamp:2; overflow:hidden;
  }
  .pending-att-preview{ width:100%; height:100%; object-fit:cover; display:block; }
  .pending-file-ext{
    position:absolute; left:10px; top:12px; max-width:52px; padding:4px 7px;
    border:1px solid var(--hairline); border-radius:8px; background-color:var(--surface);
    color:var(--text); font:700 12px/1 var(--font-en),sans-serif; text-transform:uppercase;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .pending-file-name{
    position:absolute; left:10px; right:9px; bottom:12px; color:var(--text);
    font:600 13px/1.2 var(--font-en),var(--font-cn); white-space:nowrap;
    overflow:hidden; text-overflow:ellipsis;
  }
  .pending-remove{
    position:absolute; z-index:3; right:6px; top:6px; width:25px; height:25px;
    display:grid; place-items:center; border:0; border-radius:50%; padding:0;
    color:var(--text-on-fill); background:rgba(15,18,20,.86); cursor:pointer; box-shadow:0 2px 8px var(--shade-warm-3);
  }
  .pending-remove svg{ width:13px; height:13px; }
  .pending-att.uploading::after{
    content:""; position:absolute; z-index:1; inset:0; background:rgba(17,22,26,.38);
  }
  .pending-spinner{
    display:none; position:absolute; z-index:2; left:50%; top:50%; width:24px; height:24px;
    margin:-12px 0 0 -12px; border:3px solid rgba(255,255,255,.45);
    border-top-color:#fff; border-radius:50%; animation:pendingSpin .8s linear infinite;
  }
  .pending-att.uploading .pending-spinner{ display:block; }
  /* 传失败那张：一层灰遮罩压上去，中间一个重试图标，整格可点。
     原来是一圈红边——红边只说了"这里错了"，没说"能怎么办"，而这件事最该说的
     恰恰是后者：以前只能先删掉、再回相册重新选一张。
     遮罩比 .uploading 那层厚一点（.46 对 .38），两个状态一眼能分开。 */
  .pending-att.failed{ cursor:pointer; }
  .pending-att.failed::after{
    content:""; position:absolute; z-index:1; inset:0; background:rgba(17,22,26,.46);
  }
  .pending-retry{
    position:absolute; z-index:2; inset:0; display:grid; place-items:center; color:var(--text-on-fill);
  }
  .pending-retry i{ font-size:24px; }
  @keyframes pendingSpin{ to{ transform:rotate(360deg); } }
  .bubble .txt a{ color: inherit; text-decoration: underline; text-underline-offset: 2px; }
  .bubble .txt code{
    font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .92em;
    background: var(--code-bg); padding: 1px 5px; border-radius: 5px;
  }
  .bubble .txt strong{ font-weight: 700; }
  /* 动作描写（*…* 变成的斜体）看着轻一点（2026-09-24，她要的；要不要换别的区分方式另说）。
     中文没有真斜体，手机是把正常的字硬掰歪，掰歪的字显得又黑又挤。还是斜的，只是字重降到
     苹方的细体（300）、颜色淡三成（跟着气泡自己的字色走，两边、有没有背景图都适用），
     字号小一点点（.94em，她看了这一版说"效果真好"，又要小那么一点点）。 */
  .app .row .bubble .txt em{ font-weight:300; font-size:.94em; color:color-mix(in srgb, currentColor 70%, transparent); }
  .app .row .bubble .txt strong em,.app .row .bubble .txt em strong{ font-weight:700; }
  .meta{
    display:inline; margin-left: clamp(10px, 1.4vw, 16px); white-space: nowrap;
    font-family: var(--font-en), var(--font-cn);
    font-size: clamp(11px, 1.3vw, 14px); color: var(--text-faint); user-select:none;
    vertical-align: baseline;
  }
  .meta .state{ color: var(--accent); }
  .meta .delivery{ color: var(--text-faint); }
  .meta .fail{ color:var(--danger); cursor:pointer; }
  .row.human .meta,
  .row.ai .meta{ color: var(--text-faint); }

  /* ── legacy thinking block (kept for older standalone layouts) ── */
  .row.think{
    justify-content: flex-start;
    padding-left: 0;
    padding-right: 0;
    margin-top: clamp(7px, 1.2vw, 12px);
    margin-bottom: clamp(10px, 1.8vw, 18px);
  }
  .row.think.think-open{
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
    margin-top: clamp(20px, 3.2vw, 34px);
    margin-bottom: clamp(18px, 2.8vw, 28px);
  }
  .think-block{
    width: min(61vw, 506px);
    max-width: min(61vw, 506px);
    color: var(--think-body);
    text-align: left;
    animation: pop .24s cubic-bezier(.2,.8,.2,1) both;
  }
  .think-block.open{
    width: 100%;
    max-width: min(100%, 760px);
    text-align: center;
  }
  .think-toggle{
    appearance: none;
    -webkit-appearance: none;
    width: auto;
    max-width: 100%;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
  }
  .think-block.open .think-toggle{
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(9px, 1.8vw, 14px);
  }
  .think-toggle:hover .think-caption{ color: var(--accent); }
  .think-toggle:active{ transform: translateY(1px); }
  .think-rule{
    display: none;
    position: relative;
    width: 100%;
    height: 1px;
    color: var(--think-flourish);
  }
  .think-block.open .think-rule{ display: block; }
  .think-rule::before{
    content: "";
    position: absolute;
    left: clamp(22px, 6vw, 64px);
    right: clamp(22px, 6vw, 64px);
    top: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--think-flourish) 16%, var(--think-flourish) 84%, transparent);
    opacity: .46;
  }
  .think-caption{
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    gap: 6px;
    color: var(--think-label);
    font-family: var(--font-en), var(--font-cn);
    font-size: clamp(12px, 1.38vw, 14px);
    line-height: 1.1;
    letter-spacing: .08em;
    transition: color var(--motion-fast) var(--ease-soft);
  }
  .think-caption-star,
  .think-state{
    color: var(--think-flourish);
    font-size: 1.18em;
    line-height: 1;
    transform: translateY(-.02em);
  }
  .think-body[hidden]{ display: none !important; }
  .think-body{
    margin-top: clamp(12px, 2.2vw, 20px);
  }
  .think-text{
    width: min(82%, 520px);
    margin: 0 auto clamp(16px, 2.6vw, 24px);
    color: var(--think-body);
    font-family: var(--font-cn);
    font-size: clamp(12px, 1.25vw, 13.5px);
    line-height: 1.72;
    text-align: center;
    white-space: normal;
    overflow-wrap: break-word;
  }
  .think-starline{
    position: relative;
    width: 100%;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--think-flourish);
  }
  .think-starline::before,
  .think-starline::after{
    content: "";
    position: absolute;
    top: 50%;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--think-flourish) 15%, var(--think-flourish) 85%, transparent);
    opacity: .5;
  }
  .think-starline::before{ left: 0; right: calc(50% + 34px); }
  .think-starline::after{ left: calc(50% + 34px); right: 0; }
  .think-star{
    position: relative;
    z-index: 1;
    color: var(--think-flourish);
    display: grid;
    place-items: center;
  }
  .think-star svg{ width: 24px; height: 24px; display: block; }
  .think-copy{ min-width: 0; }
  .think-copy a{ color: inherit; text-decoration: underline; text-underline-offset: 2px; }
  .think-copy code{
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: .9em;
    background: var(--code-bg);
    padding: 1px 5px;
    border-radius: 5px;
  }

  /* ── act ── the AI's action chip: a quiet "what it just did", optionally expand to see raw tool calls ──
     视觉与 thinking 同一族(--think-* 配色),但更小、更收,贴在头像缝隙里,不抢气泡 ── */
  .row.act{
    justify-content: flex-start;
    padding-left: 0;
    padding-right: clamp(12px, 4vw, 40px);
    margin-top: clamp(4px, 0.9vw, 9px);
    margin-bottom: clamp(4px, 0.9vw, 9px);
  }
  .act-block{
    max-width: min(80vw, 470px);
    animation: pop .24s cubic-bezier(.2,.8,.2,1) both;
  }
  .act-toggle{
    appearance: none; -webkit-appearance: none;
    margin: 0; padding: 2px 0; border: 0; background: transparent;
    color: inherit; font: inherit; cursor: pointer; text-align: left;
    max-width: 100%;
    display: inline-flex; align-items: baseline; gap: 7px;
  }
  .act-toggle.bare{ cursor: default; }
  .act-toggle:focus-visible{ outline: none; }
  .act-glyph{
    flex: none;
    color: var(--think-flourish);
    font-size: 1.04em; line-height: 1;
    transform: translateY(.06em);
  }
  .act-label{
    color: var(--think-label);
    font-family: var(--font-cn);                /* 显式指定:--font-en 末尾的通用 serif 会先吃掉 CJK→iOS 回退黑体 */
    font-size: clamp(12px, 1.32vw, 13.5px);
    line-height: 1.46;
    letter-spacing: .02em;
  }
  /* 展开指示:沿用 thinking 的空心星 ✧(收起)→ 实心 ✦(展开),比"· 展开"文字更轻、不突兀 */
  .act-state{
    flex: none;
    color: var(--think-flourish);
    font-size: 1.1em;
    line-height: 1;
    transform: translateY(.02em);
    transition: color var(--motion-fast) var(--ease-soft);
  }
  .act-state .ph{ transition:transform var(--motion-fast) var(--ease-soft); }
  .act-block.open .act-state .ph{ transform:rotate(90deg); }
  .act-toggle:hover .act-state{ color: var(--accent); }
  .act-toggle:hover .act-label{ color: var(--think-body); }
  .act-toggle:active{ transform: translateY(1px); }
  .act-detail[hidden]{ display: none !important; }
  .act-detail{
    margin-top: 8px;
    border-radius: 12px;
    background: var(--tint);
    border: 1px solid var(--field-line);
    padding: clamp(9px, 1.6vw, 13px) clamp(11px, 1.8vw, 14px);
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 12px; line-height: 1.6;
    color: var(--think-body);
    overflow-x: auto;
    animation: pop .2s cubic-bezier(.2,.8,.2,1) both;
  }
  .act-step + .act-step{
    margin-top: 7px; padding-top: 7px;
    border-top: 1px dashed var(--field-line);
  }
  .act-line{ white-space: pre-wrap; overflow-wrap: anywhere; }
  .act-k{ color: var(--text-faint); user-select: none; }
  .act-v{ color: var(--think-body); }


  /* ── Composer ── */
  /* ══ 语音条（按住说话） ══════════════════════════════════════════════
     三块东西：①顶替输入框的那条「按住 说话」；②按住时浮在上面、字一个一个
     出来的那一大块；③松手之后停在输入框上方的那一小条录音（只给她自己回放）。
     长按在 iOS 网页上会弹放大镜和选字菜单，所以这几块一律关掉选中和长按菜单，
     `touch-action:none` 是让上滑取消那个手势不被页面滚动抢走。 */
  .hold-to-talk{
    flex:1 1 auto; min-width:0; min-height:clamp(42px, 5.5vw, 56px);
    border:1px solid var(--field-line); border-radius:999px;
    background:var(--field-bg); box-shadow:var(--shadow);
    color:var(--text); font:600 clamp(15px,2vw,17px)/1 var(--font-cn),var(--font-en);
    cursor:pointer; padding:0 16px;
    -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
    touch-action:none;
  }
  .hold-to-talk.hidden{ display:none; }
  .hold-to-talk.is-holding{ background:var(--surface-mid); }
  .composer.voice-mode .field{ display:none; }
  #micBtn .keyboard-icon,#codeMicBtn .keyboard-icon{ display:none; }
  .composer.voice-mode #micBtn .keyboard-icon,.composer.voice-mode #codeMicBtn .keyboard-icon{ display:block; }
  .composer.voice-mode #micBtn .mic-icon,.composer.voice-mode #codeMicBtn .mic-icon{ display:none; }
  /* Code 页那块浮层挂在自己那条零高度的座上（.code-voice-anchor，和「回到底部」那条座一样贴着输入框上沿），
     所以不用 fixed、不用量高度：座往上 12px 就是它的底。提示胶囊照样落进输入框空着的那一截（见 .voice-live-hint）。
     Code 输入框里那个上下文圆圈在「按住 说话」时照留着。 */
  /* 层级要比输入框（.composer 的 z-index:100）高：提示胶囊落在输入框里面，低了就被那块毛玻璃糊住。 */
  .code-voice-anchor{ position:relative; z-index:110; flex:none; height:0; margin:0 clamp(12px,3vw,28px); }
  .code-workspace:has(.code-composer[hidden]) .code-voice-anchor{ display:none; }
  .code-voice-anchor .code-voice-live{ position:absolute; left:0; right:0; bottom:12px; width:auto; margin:0; }

  .voice-live{
    position:fixed; z-index:130; left:var(--side-pad); right:var(--side-pad);
    /* 字那一块跟着输入框的真高度走（--composer-live-h，main.js 量的），在它上沿往上空 12px。
       原来写死 84px，几乎贴着输入框，取消一缩就挤上去了（2026-09-25 她嫌挤）。算法和"回到底部"那颗的座一样。
       提示胶囊不跟着这块走，见 .voice-live-hint。 */
    bottom:calc(10px + env(safe-area-inset-bottom) + var(--keyboard-offset) + var(--composer-live-h, 104px) + 12px);
    width:min(calc(100vw - 2 * var(--side-pad)), var(--ref-width));
    margin:0 auto; display:grid; gap:10px; justify-items:center;
    pointer-events:none;
  }
  .voice-live.hidden{ display:none; }
  .voice-live-bubble{
    max-width:100%; min-width:120px; min-height:56px; box-sizing:border-box;
    display:flex; align-items:center; gap:12px;
    padding:14px 18px; border-radius:22px;
    /* 和输入框同一块毛玻璃（2026-09-25 她要的；先试过模型选择器那个浅灰实底，她嫌不好看）。
       底色和模糊和 .composer 一个字都不差，看上去是从输入框里浮上来的同一种材质；只是**不描边**——
       .composer 那圈 .5px 的细线她上一轮刚让这里去掉。
       它只在按住说话时出现、全屏只有一块，多这一层 backdrop-filter 付得起——别拿它当先例去给气泡磨砂。 */
    border:0;
    background:var(--glass-half); box-shadow:none;
    -webkit-backdrop-filter:blur(10px) saturate(1); backdrop-filter:blur(10px) saturate(1);
    color:var(--text); font:500 clamp(16px,2.1vw,19px)/1.45 var(--font-cn),var(--font-en);
    text-align:left; word-break:break-word;
    transform-origin:center;
    transition:opacity .18s ease, transform .18s ease;
  }
  /* 上滑取消（2026-09-25 她选的"褪色划掉 + 收走"，原来是整块变粉、字变红）：不加新颜色，
     里面的字淡下去、划一道线，整块原地轻轻缩一点——这段话要被划掉了。松手时**顺着手指往上飘走**、
     淡没（is-leaving）。第一版是往下沉，一沉就挤到输入框上，而且手指往上、它往下，方向是反的。 */
  /* 淡的是里面的字和波形，不是整块：整块半透明的话底下的聊天会透上来，和划掉的字叠成一团。 */
  .voice-live.is-cancelling .voice-live-bubble{ transform:scale(.96); }
  .voice-live-text,.voice-live-wave{ transition:opacity .18s ease; }
  .voice-live.is-cancelling .voice-live-text,.voice-live.is-cancelling .voice-live-wave{ opacity:.4; }
  .voice-live.is-cancelling .voice-live-text{ text-decoration:line-through; text-decoration-thickness:1.5px; }
  .voice-live.is-leaving .voice-live-bubble{ opacity:0; transform:translateY(-28px) scale(.92); }
  .voice-live.is-leaving .voice-live-hint{ opacity:0; }
  .voice-live-hint{ transition:opacity .18s ease; }
  .voice-live-text:empty::after{ content:"在听…"; color:var(--text-faint); }
  /* 还在猜的那半句是灰的，一句说完定下来才变成正常颜色（main.js 的 paintText）。和"在听…"同一个灰。 */
  .voice-live-guess{ color:var(--text-faint); }
  /* 松手到字落进来之间：输入框里的字换成一个转圈 + "识别中…"，占的正是输入框那一格，
     样子照着输入框的字写（位置、内边距、字号），转圈借发送键那个动画。 */
  .composer .field .voice-recognizing{ display:none; }
  .composer .field.is-recognizing textarea{ display:none; }
  .composer .field.is-recognizing .voice-recognizing{
    grid-column:1/-1; grid-row:1; align-self:center;
    display:flex; align-items:center; gap:8px;
    min-height:42px; padding:5px 14px 6px 13px; box-sizing:border-box;
    color:var(--text-soft); font:500 clamp(16px,2vw,19px)/1.4 var(--font-cn),var(--font-en);
  }
  .voice-recognizing .ph{ font-size:18px; animation:send-spin .9s linear infinite; }
  @media (prefers-reduced-motion: reduce){ .voice-recognizing .ph{ animation:none; } }
  /* 七根跳动的小竖条。高度由 JS 按真实音量写进 --vu，静音时它们自己缩回去，
     所以"没声音"和"在听"从屏幕上就能分出来。 */
  .voice-live-wave{ display:flex; align-items:center; gap:3px; flex:none; height:22px; }
  .voice-live-wave i{
    display:block; width:3px; border-radius:2px; background:var(--fill-strong);
    height:calc(4px + var(--vu, 0) * 18px);
    transition:height .09s linear;
  }
  .voice-live-wave i:nth-child(2n){ height:calc(4px + var(--vu, 0) * 13px); }
  .voice-live-wave i:nth-child(3n){ height:calc(4px + var(--vu, 0) * 22px); }
  /* 提示胶囊放在输入框里空着的那一截（「按住 说话」那一排上面）。试过夹在字和输入框中间，
     它会压在底下的聊天上，一行字从胶囊后面穿过去，很乱。20px = 上面那 12px 空隙 + 进输入框 8px。 */
  .voice-live-hint{
    position:absolute; top:calc(100% + 20px); left:50%; transform:translateX(-50%);
    white-space:nowrap;
    padding:5px 12px; border-radius:999px; background:rgba(31,31,29,.82); color:var(--text-on-fill);
    font:600 12px/1 var(--font-cn),var(--font-en);
  }

  .pending-voice{
    position:absolute; z-index:4; left:var(--side-pad); bottom:calc(100% + 8px);
    max-width:calc(100% - var(--side-pad) - var(--side-pad));
  }
  .pending-voice.hidden{ display:none; }
  .voice-chip{
    display:flex; align-items:center; gap:9px; padding:7px 9px 7px 7px;
    border:0; border-radius:999px;
    background:var(--bubble-ai-bg); box-shadow:0 6px 18px var(--shade-cool-1);
    color:var(--text); font:600 13px/1 var(--font-en),var(--font-cn);
  }
  .voice-chip-play{
    width:28px; height:28px; flex:none; display:grid; place-items:center; padding:0;
    border:0; border-radius:50%; background:var(--fill-strong); color:var(--text-on-fill); cursor:pointer;
  }
  .voice-chip-play .ph{ font-size:14px; }
  .voice-chip-bars{ display:flex; align-items:center; gap:2px; height:14px; flex:none; }
  .voice-chip-bars i{ display:block; width:2px; border-radius:1px; background:var(--surface-strong); height:6px; }
  .voice-chip-bars i:nth-child(3n){ height:12px; }
  .voice-chip-bars i:nth-child(2n){ height:9px; }
  .voice-chip.is-working .voice-chip-bars i{ animation:voice-bars 1s ease-in-out infinite; }
  .voice-chip.is-working .voice-chip-bars i:nth-child(2n){ animation-delay:.12s; }
  .voice-chip.is-working .voice-chip-bars i:nth-child(3n){ animation-delay:.24s; }
  @keyframes voice-bars{ 0%,100%{ transform:scaleY(.5); } 50%{ transform:scaleY(1.5); } }
  @media (prefers-reduced-motion: reduce){
    .voice-chip.is-working .voice-chip-bars i{ animation:none; }
    .voice-live-wave i{ transition:none; }
    .voice-live-bubble,.voice-live-hint,.voice-live-text,.voice-live-wave{ transition:none; }
  }
  .voice-chip-note{ color:var(--text-faint); font-weight:500; white-space:nowrap; }
  .voice-chip-remove{
    width:22px; height:22px; flex:none; display:grid; place-items:center; padding:0;
    border:0; border-radius:50%; background:var(--surface-soft); color:var(--text-soft); cursor:pointer;
  }
  .voice-chip-remove .ph{ font-size:12px; }
  /* 整段录音没传上去（2026-09-28）：录音留在手机里，点这颗再传一次。 */
  .voice-chip-retry{
    width:26px; height:26px; flex:none; display:grid; place-items:center; padding:0;
    border:0; border-radius:50%; background:var(--fill-strong); color:var(--text-on-fill); cursor:pointer;
  }
  .voice-chip-retry .ph{ font-size:14px; }

  /* 聊天里那条已经发出去的语音，整条在一个气泡里（2026-09-25 她画的）：
     录音那一行 → 一条灰线 → 她的话，后面跟着灰色小字的语气。
     **语气是有意露出来的**——不然他听错了她永远不知道。 */
  .bubble.voice-bubble{ min-width:min(230px, 64vw); }
  .voice-bubble-head{
    display:flex; align-items:center; gap:10px;
    padding:2px 0 9px; margin-bottom:9px;
    border-bottom:1px solid var(--line);
  }
  /* 一排小竖条撑满中间，秒数靠右。高矮是固定的花纹，不是这条录音真的波形。 */
  .voice-bubble-bars{
    flex:1 1 auto; min-width:0; overflow:hidden;
    display:flex; align-items:center; gap:3px; height:18px;
  }
  .voice-bubble-bars i{ display:block; flex:none; width:2px; height:6px; border-radius:1px; background:var(--surface-strong); }
  .voice-bubble-bars i:nth-child(2n){ height:10px; }
  .voice-bubble-bars i:nth-child(3n){ height:15px; }
  .voice-bubble-bars i:nth-child(5n){ height:8px; }
  /* 秒数和下面那行语气：跟着气泡自己的字色走、只淡一点，不用固定的淡灰（2026-09-27）。
     深色模式铺了照片时她那边的气泡是浅的玻璃，固定的淡灰落在上面几乎看不见；
     跟着字色走的话，气泡底什么颜色、正文看得清，这两样就看得清。 */
  .voice-bubble-seconds{
    flex:none; color:inherit; opacity:.72; white-space:nowrap;
    font:600 13px/1 var(--font-en),var(--font-cn);
  }
  .voice-bubble-text{ white-space:pre-wrap; word-break:break-word; }
  /* 语气另起一行、斜体、比正文小一圈（2026-09-25 她要的；第一版接在正文末尾，读着像正文的一部分）。
     中文字体多半没有真斜体，浏览器会把字压斜——要的就是这个"旁白"的感觉。 */
  .voice-bubble-tone{
    display:block; margin-top:5px; color:inherit; opacity:.72;
    font-size:.72em; font-weight:500; font-style:italic; line-height:1.45;
  }

  .composer{
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 100;
    width: min(100vw, var(--ref-width));
    margin: 0 auto;
    display:flex; align-items:center; gap: clamp(6px, 1vw, 12px);
    background: transparent; border:none;
    padding: 0 var(--side-pad) clamp(10px, 1.6vw, 18px);
    padding-bottom: calc(clamp(10px, 1.6vw, 18px) + env(safe-area-inset-bottom));
    transform: translate3d(0, calc(-1 * var(--keyboard-offset)), 0);
    -webkit-transform: translate3d(0, calc(-1 * var(--keyboard-offset)), 0);
    transition: transform .28s cubic-bezier(.2,.8,.2,1);
  }
  .app.archive-view .composer,.app.context-selecting .composer,
  .app.archive-view .chat-pill-anchor,.app.context-selecting .chat-pill-anchor{ display:none; }
  .legacy-context-bar{
    position:fixed; z-index:120; left:var(--side-pad); right:var(--side-pad);
    bottom:calc(14px + env(safe-area-inset-bottom)); width:min(calc(100vw - 2 * var(--side-pad)),560px);
    margin:0 auto; padding:10px; border:1px solid var(--line-faint); border-radius:24px;
    background:var(--glass-solid); box-shadow:0 12px 42px var(--shade-warm-2);
    -webkit-backdrop-filter:blur(20px); backdrop-filter:blur(20px);
  }
  .legacy-context-start,.legacy-context-create,.legacy-context-cancel{
    min-height:44px; border:0; border-radius:22px; cursor:pointer;
    font:600 14px/1 var(--font-cn),var(--font-en);
  }
  .legacy-context-start{ width:100%; background:var(--fill-strong); color:var(--text-on-fill); }
  .legacy-context-selecting{ display:grid; gap:9px; }
  .legacy-context-summary{ display:grid; grid-template-columns:minmax(0,1fr) auto; align-items:center; gap:8px; }
  .legacy-context-count{ color:var(--text-soft); font-size:12px; line-height:1.45; text-align:left; }
  .legacy-context-select-all{
    min-height:32px; padding:0 12px; border:0; border-radius:16px; background:var(--surface-soft); color:var(--text-soft);
    cursor:pointer; font:600 12px/1 var(--font-cn),var(--font-en); white-space:nowrap;
  }
  .legacy-context-select-all:disabled{ opacity:.45; cursor:default; }
  .legacy-context-select-all:active{ transform:scale(.97); }
  .legacy-context-actions{ display:grid; grid-template-columns:92px 1fr; gap:8px; }
  .legacy-context-cancel{ background:var(--surface-soft); color:var(--text-soft); }
  .legacy-context-create{ background:var(--fill-strong); color:var(--text-on-fill); }
  .legacy-context-create:disabled{ opacity:.4; cursor:default; }
  .grow-result-overlay{ position:fixed; inset:0; z-index:95; display:grid; place-items:center; padding:20px; }
  .grow-result-overlay.hidden{ display:none; }
  .grow-result-scrim{ position:absolute; inset:0; border:0; background:var(--scrim); }
  .grow-result-card{ position:relative; width:min(420px,100%); max-height:min(70vh,620px); overflow:auto; border-radius:20px; background:var(--surface); padding:22px; box-shadow:0 18px 52px var(--shade-warm-3); }
  .grow-result-card h2{ margin:0 0 12px; font-size:18px; }
  .grow-result-body{ color:var(--text); font-size:14px; line-height:1.75; white-space:pre-wrap; }
  .grow-result-confirm{ float:right; margin-top:20px; border:0; border-radius:12px; background:var(--fill-strong); color:var(--text-on-fill); padding:10px 24px; font-weight:650; }
  .grow-failed-error{ margin:0 0 12px; border-radius:12px; background:var(--surface-soft); color:var(--text-soft); padding:10px 12px; font-size:13px; line-height:1.6; word-break:break-word; }
  .grow-failed-actions{ display:flex; flex-wrap:wrap; justify-content:flex-end; gap:8px; margin-top:20px; }
  .grow-failed-actions button{ min-height:40px; border:0; border-radius:12px; padding:0 18px; font-weight:650; cursor:pointer; }
  .grow-failed-cancel{ background:var(--surface-soft); color:var(--text-soft); }
  .grow-failed-success{ background:#e7ece7; color:var(--success); }
  .grow-failed-retry{ background:var(--fill-strong); color:var(--text-on-fill); }
  .dream-window-label{ display:grid; gap:8px; color:var(--text); font-size:14px; line-height:1.55; }
  .dream-window-input{ width:100%; min-height:46px; border:1px solid var(--line); border-radius:12px; background:var(--surface); color:var(--text); padding:0 14px; font:600 16px/1 var(--font-cn),var(--font-en); }
  .dream-window-hint{ margin:10px 0 0; color:var(--text-faint); font-size:12px; line-height:1.55; }
  .dream-window-actions{ display:flex; justify-content:flex-end; gap:8px; margin-top:20px; }
  .dream-window-cancel,.dream-window-start{ min-height:40px; border:0; border-radius:12px; padding:0 20px; font-weight:650; cursor:pointer; }
  .dream-window-cancel{ background:var(--surface-soft); color:var(--text-soft); }
  .dream-window-start{ background:var(--fill-strong); color:var(--text-on-fill); }
  .row.legacy-selectable{ position:relative; cursor:pointer; }
  .row.legacy-selectable::after{
    content:""; position:absolute; top:50%; width:20px; height:20px; border:1.5px solid var(--line-bold);
    border-radius:50%; background:var(--glass-solid); opacity:0; transform:translateY(-50%); transition:.16s ease;
  }
  .app.context-selecting .row.context-selectable::after{ opacity:1; }
  .row.legacy-selectable.ai::after{ right:0; }
  .row.legacy-selectable.human::after{ left:0; }
  .row.legacy-selected .bubble{ box-shadow:0 0 0 2px rgba(69,92,110,.32); }
  .row.legacy-selected::after{ content:"\e182"; display:grid; place-items:center; color:var(--text-on-fill); border-color:#5E5E59; background:#5E5E59; font-family:"Phosphor"; font-size:13px; }
  .floatbtn{
    flex:none; width: clamp(36px, 5vw, 48px); height: clamp(36px, 5vw, 48px); border-radius:50%;
    border: none; background: transparent;
    color: var(--accent); display:grid; place-items:center; cursor:pointer; padding:0;
    transition: transform .15s ease, color .2s ease;
  }
  .floatbtn:active{ transform: scale(.9); color: var(--text); }
  .floatbtn:hover{ color: var(--text); }
  .floatbtn svg{ width: clamp(20px, 2.8vw, 28px); height: clamp(20px, 2.8vw, 28px); display:block; }
  .floatbtn.send{
    background: var(--send-bg);
    color:var(--text-on-fill);
    box-shadow: 0 16px 32px var(--shade-cool-3);
  }
  .floatbtn.send:hover{ color:var(--text-on-fill); }
  .floatbtn.send:active{ transform: scale(.97); }      /* 发送键按压:轻收 3%(比通用 .floatbtn 的 .9 克制) */
  @keyframes send-go{ from{ transform: scale(.96); } to{ transform: scale(1); } }
  .floatbtn.send.send-go{ animation: send-go .22s cubic-bezier(.2,.8,.2,1); }
  @media (prefers-reduced-motion: reduce){ .floatbtn.send.send-go{ animation: none; } }
  /* 发送键三态：空输入框和"正在回复"都是灰的，灰的时候按钮是 disabled，真的按不动。 */
  .floatbtn.send.is-idle,.floatbtn.send.is-busy{ background:var(--surface-mid); color:var(--text-on-muted); box-shadow:none; }
  .floatbtn.send.is-idle:hover,.floatbtn.send.is-busy:hover{ color:var(--text-on-muted); }
  .floatbtn.send:disabled{ cursor:default; opacity:1; }
  .floatbtn.send:disabled:active{ transform:none; }
  .floatbtn.send .send-spin{ display:none; }
  .floatbtn.send.is-busy .send-arrow{ display:none; }
  .floatbtn.send.is-busy .send-spin{ display:block; animation:send-spin .9s linear infinite; }
  @keyframes send-spin{ to{ transform:rotate(360deg); } }
  @media (prefers-reduced-motion: reduce){ .floatbtn.send.is-busy .send-spin{ animation:none; } }
  .composer .field{
    flex:1 1 auto; display:flex; align-items:center; gap:clamp(4px, 0.8vw, 10px);
    min-width:0;
    background: var(--field-bg);
    border: 1px solid var(--field-line);
    border-radius: 999px;
    padding: clamp(4px, 0.6vw, 8px) clamp(8px, 1.2vw, 14px) clamp(4px, 0.6vw, 8px) clamp(10px, 1.5vw, 16px);
    min-height: clamp(42px, 5.5vw, 56px);
    box-shadow: var(--shadow);
    transition: border-color .2s ease;
  }
  .composer .field:focus-within{ border-color: var(--field-line); }
  .composer textarea:focus,
  .composer textarea:focus-visible,
  .composer button:focus-visible{
    outline: none;
  }
  textarea{
    flex:1 1 auto; border:none; outline:none; resize:none; background:transparent;
    min-width:0;
    color: var(--text); font-family: var(--font-en), var(--font-cn); font-size: clamp(15px, 2vw, 18px); line-height:1.35;
    max-height: 110px; padding: 6px 0; margin:0;
  }
  textarea::placeholder{ color: var(--text-faint); opacity: 1; }
  .emojibtn{
    flex:none; width: clamp(28px, 3.8vw, 38px); height: clamp(28px, 3.8vw, 38px); border:none; background:transparent;
    color: var(--accent); display:grid; place-items:center; cursor:pointer; padding:0;
    transition: transform .15s ease, color .2s ease;
  }
  .emojibtn:active{ transform: scale(.85); color: var(--text); }
  .emojibtn:hover{ color: var(--text); }
  .emojibtn svg{ width: clamp(22px, 3vw, 30px); height: clamp(22px, 3vw, 30px); display:block; }
  /* ── 回到底部 · 上滑阅读历史约三条消息后出现 ── */
  /* 「回到底部」钉在输入框的上沿，**不写死一个离屏幕底的距离**。
     写死过一版：药丸 122px、输入框最矮时上沿在 114px——只差 8px，空着的时候刚好
     躲过去，所以一直没人发现。而那个文本框是会自动长高的（最多 120px），打三四行
     字输入框就有 180 高、上沿跑到 190px，药丸整颗埋在它后面。Code 那颗更惨：抄的是
     这条规则被覆盖**之前**的 96px，从一开始就压着，一次都没露出来过。
     挂进 .composer 里面按它的上沿算（.composer 是 fixed，本身就是定位上下文），
     输入框长多高药丸就浮多高。
     键盘那份 --keyboard-offset 也一起删了：输入框自己就跟着键盘走（见 .composer 的
     transform），药丸钉在它身上，不用再自己算一遍。 */
  .newmsg-pill{
    position: absolute; left: 50%; bottom: calc(100% + 10px); z-index: 4;
    display: grid; place-items: center;
    width: 36px; height: 36px; padding: 0; border: none; border-radius: 50%;
    background: rgba(34, 46, 60, .72); color: var(--text-on-fill);
    -webkit-backdrop-filter: blur(10px) saturate(1.2); backdrop-filter: blur(10px) saturate(1.2);
    box-shadow: 0 8px 24px var(--shade-cool-3);
    cursor: pointer; opacity: 0; pointer-events: none;
    transform: translate3d(-50%, 8px, 0);
    transition: opacity .2s ease, transform .28s cubic-bezier(.2,.8,.2,1);
  }
  .newmsg-pill.show{ opacity: 1; pointer-events: auto; transform: translate3d(-50%, 0, 0); }
  .newmsg-pill svg{ width: 20px; height: 20px; flex: none; }
  @media (prefers-reduced-motion: reduce){ .newmsg-pill{ transition: opacity .2s ease; } }

  /* ── 还在装的那条线 ─────────────────────────────────────────────
     2026-09-19。2026-09-18 把"本地存的那份先上屏"改上去之后，开机不再对着密码框
     干等了——可屏幕一打开就是满的，于是换了个问题：**看不出这份是不是全部**。
     聊天、Home、Code 三处一模一样：看着像好了，其实网络那趟还在后台跑。
     这条线就是那个答案，三个页面共用一条：在走 = 还在等东西回来，没有 = 就是全部了。

     钉在 safe-area 下面，不是屏幕物理顶端——iPhone 上那一截是状态栏，画在那儿
     等于没画。 */
  .loading-line{
    position: fixed; z-index: 400; left:0; right:0; top: env(safe-area-inset-top);
    height: 2px; overflow: hidden; pointer-events: none;
    background: var(--tint);
    transition: opacity .42s ease;
  }
  .loading-line[hidden]{ display:none; }
  .loading-line > span{
    display:block; width:38%; height:100%;
    background: var(--accent);
    animation: loadingSweep 1.15s cubic-bezier(.4,0,.2,1) infinite;
  }
  /* 装完了：先填满一整条再淡掉。直接藏起来的话，快的那几次根本看不出发生过什么，
     而"看着它走完"正是这条线要给的那个交代。 */
  .loading-line.done{ opacity:0; }
  .loading-line.done > span{ width:100%; animation:none; }
  @keyframes loadingSweep{
    0%{ transform: translateX(-105%); }
    100%{ transform: translateX(268%); }
  }
  /* 关掉动画效果的人看到的是一整条静止的线。信息一个字没少：在 = 还在装，
     没了 = 装完了，只是不动。 */
  @media (prefers-reduced-motion: reduce){
    .loading-line > span{ width:100%; animation:none; }
  }

  /* ── Login ── */
  .login{
    position: fixed; inset:0; z-index: 50;
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap: 22px; padding: 28px;
    padding-top: calc(28px + env(safe-area-inset-top));
    background-color: var(--bg);
  }
  .login h1{ margin:0; font-size:34px; font-weight:500; letter-spacing:0; }
  .login .sub{ margin:-12px 0 0; color: var(--text-soft); font-size:16px; text-align:center; }
  .login form{ display:flex; flex-direction:column; gap:11px; width:100%; max-width:320px; }
  .login input{
    width:100%; padding: 14px 16px; font: inherit; color: var(--text);
    background: var(--field-bg); border:1px solid var(--field-line); border-radius:18px; outline:none;
    transition: border-color .2s ease;
    box-shadow: var(--soft-shadow);
  }
  .login input:focus{ border-color: var(--accent); }
  .login button{
    width:100%; padding: 14px; font: inherit; font-weight:600;
    background: var(--accent); color: var(--accent-fg); border:none; border-radius:18px; cursor:pointer;
  }
  .login button:active{ transform: scale(.99); }
  .login .err{ color:var(--danger); font-size:13px; min-height:16px; text-align:center; margin:0; }
  /* 自动连接时：说明和密码框都收起来，只留一行状态。 */
  .login.connecting .sub,
  .login.connecting form{ display:none; }
  .login-status{
    margin:0; color: var(--text-soft); font-size:15px; text-align:center;
    animation: loginBreathe 1.8s ease-in-out infinite;
  }
  .login-status[hidden]{ display:none; }
  @keyframes loginBreathe{ 0%,100%{ opacity:.55; } 50%{ opacity:1; } }
  @media (prefers-reduced-motion: reduce){ .login-status{ animation:none; } }

  /* ── 开屏贴纸 ──
     底色就是 var(--bg)，和 iPhone 那张启动图同一个颜色——所以从系统交接到这一屏
     是看不见的，不需要额外做启动图。盖在所有东西上面（音乐播放器是 720）。 */
  .splash{
    position:fixed; inset:0; z-index:900; overflow:hidden;
    display:grid; place-items:center;
    background: var(--bg);
    transition: opacity .5s ease;
  }
  .splash[hidden]{ display:none; }
  .splash.fading{ opacity:0; pointer-events:none; }
  /* 贴纸的画布铺满整屏（2026-09-26 起）。撕下来之后贴纸跟着手指走、再飞出去，画布小了
     拖出去的部分会被画布边齐刷刷切掉——她看到的"边框"。贴纸本身多大由 main.js 的
     splashDisplaySize 直接告诉库，和画布多大无关。
     touch-action:none 是撕得动的前提：不关掉的话这一下会被当成滚动手势收走。 */
  .splash-sticker{ position:absolute; inset:0; touch-action:none; }
  /* 库给 canvas 挂了 tabindex="0"（它还支持方向键撕），手指一按就套上一圈黑框——
     而且 role="slider" 让 Chrome 把指针拖动也算成 :focus-visible，所以
     `:not(:focus-visible)` 挡不住它。只能默认压掉，真按了键才把它放出来：
     方向键是这一屏唯一的非触摸入口，不能连框都不给。 */
  .splash-sticker canvas:focus{ outline:none; }
  .splash.keyed .splash-sticker canvas:focus{ outline:revert; }
  /* 撕下来之后怎么走由贴纸库自己画（2026-09-26 起），这里不再用 CSS 拖整块画布——
     那样画布上卷着的贴纸和底下那片灰影会一起僵硬地滑下去。 */

  .hidden{ display:none !important; }
  .app.kb .composer{ padding-bottom: 8px; }

  /* ── Profile page (full-screen settings) ── */
  .profile-panel{
    position: fixed;
    inset: 0;
    z-index: 200;
    pointer-events: none;
    transform: translateX(100%);
    opacity: 0;
    transition: transform .42s var(--ease-soft), opacity .42s ease;
  }
  .profile-panel.open{ transform: none; opacity: 1; pointer-events: auto; }
  /* Solid settings page fully covers the chat behind. */
  .profile-page{
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    background-color: var(--bg);
    overflow: hidden;
  }
  .profile-topbar{
    position: relative; z-index:1;
    flex: 0 0 auto;
    display:flex; align-items:center; gap:10px;
    height: calc(56px + env(safe-area-inset-top));
    padding: env(safe-area-inset-top) var(--side-pad) 0;
  }
  .profile-back{
    width:40px; height:40px; flex:none;
    border:0; border-radius:50%; padding:0; margin-left:-6px;
    background: transparent; color: var(--text);
    display:grid; place-items:center; cursor:pointer;
    transition: transform .15s ease;
  }
  .profile-back:active{ transform: scale(.9); }
  .profile-back svg{ width:24px; height:24px; display:block; }
  .profile-scroll{
    position: relative; z-index:1;
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding: 10px var(--side-pad) calc(30px + env(safe-area-inset-bottom));
    display:flex; flex-direction:column; gap:24px;
  }
  .profile-scroll::-webkit-scrollbar{ width:0; height:0; }
  .profile-scroll > *{ flex:none; }

  .rolling-panel{
    position:fixed; inset:0; z-index:210; pointer-events:none;
    transform:translateX(100%); opacity:0;
    transition:transform .42s var(--ease-soft),opacity .42s ease;
  }
  .rolling-panel.open{ transform:none; opacity:1; pointer-events:auto; }
  .rolling-page{ position:absolute; inset:0; display:flex; flex-direction:column; background:var(--bg); color:var(--text); }
  .rolling-title{ margin:0; font:600 18px/1.2 var(--font-en),var(--font-cn); }
  .rolling-scroll{
    flex:1 1 auto; overflow-y:auto; padding:10px var(--side-pad) calc(30px + env(safe-area-inset-bottom));
    display:flex; flex-direction:column; gap:16px; overscroll-behavior:contain;
  }
  .rolling-card{
    padding:16px; border:1px solid var(--card-line); border-radius:18px;
    background:var(--card-bg); box-shadow:var(--card-shadow);
  }
  .rolling-card h3{ margin:0 0 5px; font:600 16px/1.35 var(--font-en),var(--font-cn); }
  .rolling-card-note,.rolling-meta,.rolling-status{ margin:0; color:var(--muted); font-size:12px; line-height:1.55; }
  .rolling-textarea{
    width:100%; min-height:220px; margin-top:13px; padding:13px; resize:vertical;
    border:1px solid var(--line); border-radius:14px; background:var(--surface); color:var(--text);
    font:400 14px/1.7 var(--font-cn),var(--font-en); outline:none;
  }
  .rolling-summary-text{ min-height:260px; }
  .rolling-textarea:focus{ border-color:var(--line-bold); }
  .rolling-actions{ display:flex; justify-content:flex-end; gap:9px; margin-top:10px; }
  .rolling-button{
    min-height:38px; padding:0 15px; border:1px solid var(--line); border-radius:19px;
    background:var(--surface); color:var(--text); font:500 13px/1 var(--font-cn),var(--font-en); cursor:pointer;
  }
  .rolling-button.primary{ border-color:var(--line-bold); background:var(--fill-strong); color:var(--text-on-fill); }
  .rolling-button:disabled{ opacity:.45; cursor:default; }

  /* setting card */
  .settings-card{
    background: var(--card-bg);
    border: 1px solid var(--card-line);
    border-radius:18px;
    box-shadow: var(--card-shadow);
    padding:15px 16px;
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
  }
  .settings-label{
    display:flex; align-items:center; gap:6px;
    color: var(--text-soft); font-size:12.5px;
    margin-bottom:11px; letter-spacing:.01em;
  }
  .info-i{
    width:14px; height:14px; flex:none; border-radius:50%;
    border:1px solid var(--info-ring); color: var(--text-faint);
    display:inline-grid; place-items:center;
    font-size:9px; font-style:normal; line-height:1;
    font-family: var(--font-en), var(--font-cn);
    cursor:help; user-select:none;
  }
  .push-hint{
    margin-top:9px; font-size:11.5px; line-height:1.55;
    color: var(--text-faint); letter-spacing:.01em;
  }

  /* segmented control */
  .segmented{
    display:grid; grid-auto-flow:column; grid-auto-columns:1fr;
    gap:3px; background: var(--seg-track);
    border-radius:13px; padding:3px;
  }
  .segmented button{
    border:0; background:transparent; color: var(--text-soft);
    border-radius:10px; padding:8px 3px;
    font: inherit; font-size: clamp(10.5px, 2.9vw, 12.5px);
    letter-spacing:0; white-space:nowrap; cursor:pointer;
    transition: background .22s ease, color .22s ease, box-shadow .22s ease;
  }
  .segmented button.active{
    background: var(--seg-thumb); color: var(--text);
    box-shadow: var(--seg-thumb-shadow); font-weight:500;
  }

  .tool-list{ display:grid; gap:2px; }
  .tool-row{ min-height:54px; display:flex; align-items:center; gap:14px; padding:8px 2px; border-bottom:1px solid var(--card-line); cursor:pointer; }
  .tool-row:last-child{ border-bottom:0; }
  .tool-copy{ min-width:0; display:grid; gap:2px; }
  .tool-copy strong{ color:var(--text); font-size:14px; font-weight:500; }
  .tool-copy span{ color:var(--text-faint); font-size:11.5px; line-height:1.35; }
  .tool-switch{ position:relative; width:42px; height:24px; margin-left:auto; flex:none; }
  .tool-switch input{ position:absolute; opacity:0; pointer-events:none; }
  .tool-switch-track{ position:absolute; inset:0; border-radius:999px; background:var(--slider-track); transition:background .2s ease; }
  .tool-switch-track::after{ content:""; position:absolute; width:20px; height:20px; left:2px; top:2px; border-radius:50%; background:var(--surface); box-shadow:none; transition:transform .2s var(--ease-soft); }
  .tool-switch input:checked + .tool-switch-track{ background:var(--accent); }
  .tool-switch input:checked + .tool-switch-track::after{ transform:translateX(18px); }
  .tool-apply{ width:100%; min-height:42px; margin-top:12px; border:0; border-radius:14px; background:var(--accent); color:var(--accent-fg); font:500 13px var(--font-cn); cursor:pointer; }
  .tool-apply:disabled{ opacity:.42; cursor:default; }
  .tool-hint{ min-height:17px; margin-top:8px; color:var(--text-faint); font-size:11.5px; text-align:center; }

  /* action rows */
  .action-row{
    display:flex; align-items:center; gap:13px;
    width:100%; text-align:left;
    background: var(--card-bg);
    border:1px solid var(--card-line);
    border-radius:16px; box-shadow: var(--card-shadow);
    padding:13px 16px; color: var(--text); font: inherit; cursor:pointer;
    -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
    transition: background .18s ease, transform .12s ease;
  }
  button.action-row:active{ background: var(--row-press); transform: scale(.992); }
  .action-icon{ width:21px; height:21px; flex:none; color: var(--accent); display:grid; place-items:center; }
  .action-icon svg{ width:19px; height:19px; display:block; }
  .action-name{ font-family: var(--font-en), var(--font-cn); font-size:14.5px; color: var(--text); flex:none; }
  .action-value{
    margin-left:auto; color: var(--text-soft); font-size:12.5px;
    text-align:right; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .action-chevron{ flex:none; color: var(--text-faint); display:grid; place-items:center; margin-left:2px; }
  .action-chevron svg{ width:16px; height:16px; display:block; }
  .action-row.status{ cursor:default; }
  .action-row.status{ align-items:flex-start; }
  .swap-settings{ display:grid; gap:8px; }
  .swap-turns-control{
    display:flex; align-items:center; gap:12px; min-height:46px; padding:8px 16px;
    border-radius:16px; background:var(--bubble-ai-bg); color:var(--text); font-size:13px;
  }
  .swap-turns-field{ margin-left:auto; display:flex; align-items:center; gap:6px; color:var(--text-soft); }
  .swap-turns-input{
    width:58px; height:32px; border:0; border-radius:10px; padding:0 8px;
    background:var(--glass-half); color:var(--text); text-align:center;
    font:500 13px/1 var(--font-en),var(--font-cn); font-variant-numeric:tabular-nums;
  }
  .action-row.status .status-main{ margin-left:auto; flex:1; max-width:310px; display:grid; gap:7px; min-width:0; }
  .status-metric{ display:flex; align-items:baseline; justify-content:space-between; gap:10px; color:var(--text-faint); font-size:11.5px; }
  .status-metric strong{ color:var(--text); font:500 12px/1.35 var(--font-en),var(--font-cn); text-align:right; font-variant-numeric:tabular-nums; }
  .status-sid{ display:flex; align-items:center; gap:6px; color: var(--text-faint); font-size:11.5px; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
  .status-copy{
    width:24px; height:24px; flex:none; border:0; border-radius:8px; padding:0;
    background:transparent; color: var(--text-soft);
    display:grid; place-items:center; cursor:pointer;
    transition: color .2s ease, transform .15s ease;
  }
  .status-copy:active{ transform: scale(.85); }
  .status-copy svg{ width:15px; height:15px; display:block; }

  /* toast */
  .toast{
    position: fixed; left:50%; bottom: calc(40px + env(safe-area-inset-bottom));
    transform: translate(-50%, 12px); z-index:300;
    border:0; background:var(--send-bg); background-image:none; color:var(--text-on-fill);
    font:600 clamp(16px,2vw,18px)/1.3 var(--font-cn),var(--font-en);
    padding:12px 20px; border-radius:999px;
    box-shadow:none;
    opacity:0; pointer-events:none;
    transition: opacity .24s ease, transform .24s ease;
  }
  .toast.show{ opacity:1; transform: translate(-50%, 0); }
  .toast.is-long{
    width:max-content; max-width:min(88vw, 420px);
    border-radius:18px; white-space:pre-line; text-align:left;
    font-size:15px; line-height:1.45;
  }

  @media (max-width: 520px){
    :root{
      --side-pad: 16px;
      --header-h: 56px;
      --avatar-size: 50px;
    }
    .peerpill{ padding: 0 44px; }
    .peerpill .name{ font-size: 18px; }
    .peerpill .status{ font-size: 12px; margin-top: 3px; }
    .header-actions{ right: 16px; top: calc(env(safe-area-inset-top) + 16px); gap: 26px; height:32px; }
    .topbtn{ width:32px; height:32px; }
    .topbtn svg{ width:22px; height:22px; }
    .topbtn.more svg{ width:20px; height:20px; }
    .avatar{ right: 16px; top: calc(env(safe-area-inset-top) + 16px); }
    .row{ margin-top: 18px; }
    .row.grouped{ margin-top: 8px; }
    .bubble{ max-width: min(63vw, 520px); font-size: 13.5px; line-height: 1.56; padding: 8px 13px 8px; }
    .meta{ font-size: 11px; margin-left: 8px; }
    .composer{ gap: 5px; padding-left: 16px; padding-right: 16px; }
    .floatbtn{ width: 36px; height: 36px; }
    .floatbtn svg{ width: 20px; height: 20px; }
    .composer .field{ min-height: 42px; padding: 4px 8px 4px 12px; }
    textarea{ font-size: 15px; }
    .emojibtn{ width: 28px; height: 28px; }
    .emojibtn svg{ width: 22px; height: 22px; }
    .row.think{ padding-left: 42px; padding-right: 0; }
    .think-block{ width: min(63vw, 520px); max-width: min(63vw, 520px); }
    .think-block.open{ width: 100%; max-width: 100%; }
    .row.think.think-open{ padding-left: 0; padding-right: 0; }
    .think-caption{ font-size: 12.5px; letter-spacing: .07em; }
    .think-caption-star, .think-state{ font-size: 1.2em; }
    .think-body{ margin-top: 12px; }
    .think-text{ width: min(86%, 360px); font-size: 12px; line-height: 1.66; }
    .think-star svg{ width: 22px; height: 22px; }
    .settings-card{ padding:14px 15px; }
    .action-row{ padding:12px 15px; }
    .profile-scroll{ gap:22px; }
  }

  /* ── Voice call (speaking overlay · 假按键 / 纯 UI,后端以后接) ── */
  .call-overlay{
    position: fixed; inset: 0; z-index: 150;
    pointer-events: none;
  }
  .call-scrim{
    position: absolute; inset: 0;
    background: linear-gradient(180deg, var(--glass-half) 0%, var(--glass-light) 40%, var(--glass-half) 100%);
    pointer-events: none;
    opacity: 0;
    transition: opacity .42s ease;
  }
  .call-overlay.open .call-scrim{ opacity: 1; }
  .call-sheet{
    position: absolute; inset: 0;
    display: flex; flex-direction: column; align-items: center;
    justify-content: flex-start;
    padding: calc(env(safe-area-inset-top) + clamp(50px, 10vw, 84px)) var(--side-pad) calc(env(safe-area-inset-bottom) + 26px);
    text-align: center;
    background-color: var(--bg);
    opacity: 0; pointer-events: none;
    transform: translateY(12px);
    transition: opacity .42s var(--ease-soft), transform .42s var(--ease-soft);
    overflow: hidden;
  }
  .call-overlay.open .call-sheet{ opacity: 1; pointer-events: auto; transform: translateY(0); }

  /* ── Avatar stage: 头像 + 两翼声纹 ── */
  .call-avatar-stage{
    display: flex; align-items: center; justify-content: center;
    width: 100%;
    gap: clamp(8px, 2.2vw, 16px);
    margin-top: clamp(4px, 3vh, 30px);
    flex-shrink: 0;
  }
  .call-vu{
    --vu-level: 0;
    flex: 1 1 0; min-width: 0;
    height: clamp(70px, 17vw, 100px);
    display: flex; align-items: center;
    gap: clamp(2.5px, 0.8vw, 4px);
  }
  .call-vu-left{ flex-direction: row-reverse; }
  .call-vu i{
    flex: 0 0 auto;
    width: clamp(2px, 0.65vw, 3px);
    height: calc(100% * var(--bar, .4) * (0.46 + 0.54 * var(--vu-level)));
    min-height: 2px;
    border-radius: 99px;
    background: var(--accent);
    opacity: calc(var(--bar-op, .4) * (0.6 + 0.4 * var(--vu-level)));
    animation: callVuIdle var(--vu-dur, 1.6s) var(--ease-soft) infinite alternate;
    animation-delay: var(--vu-delay, 0s);
    will-change: transform, opacity;
  }
  @keyframes callVuIdle{ from{ transform: scaleY(.55); } to{ transform: scaleY(1); } }
  @media (prefers-reduced-motion: reduce){ .call-vu i{ animation: none; } }

  /* ── Avatar ring ── */
  .call-avatar-ring{
    --ring-level: 0;
    position: relative;
    width: clamp(128px, 37vw, 168px); height: clamp(128px, 37vw, 168px);
    border-radius: 50%;
    display: grid; place-items: center;
    flex: 0 0 auto;
    box-shadow:
      0 10px 34px rgba(40,60,78,.16),
      0 0 calc(16px + 34px * var(--ring-level)) calc(2px + 12px * var(--ring-level)) color-mix(in srgb, var(--accent) 30%, transparent);
    transition: box-shadow .14s ease;
  }
  .call-avatar-img{
    width: 100%; height: 100%;
    border-radius: 50%;
    background-image: var(--avatar-default);
    background-color: var(--avatar-default-color);
    background-size: cover; background-position: center;
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
  }

  /* ── Name / status / timer ── */
  .call-name{
    margin-top: clamp(18px, 4vw, 28px);
    color: var(--text);
    font-family: var(--font-cn);
    font-size: clamp(27px, 7vw, 36px);
    font-weight: 500;
    line-height: 1.2;
  }
  .call-status{
    display: inline-flex; align-items: center; gap: 11px;
    color: var(--think-label);
    font-family: var(--font-en), var(--font-cn);
    font-size: clamp(13px, 1.8vw, 15.5px);
    letter-spacing: .16em;
    line-height: 1;
    margin-top: 8px;
  }
  .call-status .call-star{ color: var(--think-flourish); display: grid; place-items: center; }
  .call-status .call-star svg{ width: 16px; height: 16px; display: block; }
  .call-timer{
    font-family: var(--font-en), var(--font-cn);
    font-variant-numeric: tabular-nums;
    font-size: clamp(19px, 5vw, 25px);
    font-weight: 500;
    letter-spacing: .04em;
    line-height: 1;
    color: var(--text-soft);
    margin-top: 9px;
  }

  /* ── Quote (the AI's last spoken line) ── */
  .call-quote{
    flex: 1 1 auto;
    min-height: 0;                 /* 让 flex 能真正约束它,长文本不再撑破/盖住头像与字幕 */
    display: flex; align-items: center; justify-content: center;
    width: min(88vw, 400px);
    padding: clamp(8px, 2vw, 18px) clamp(8px, 2vw, 16px);
    overflow: hidden;              /* 兜底:绝不溢出到相邻区域 */
  }
  .call-quote-mark{
    color: var(--text-faint);
    font-family: var(--font-en);
    font-size: clamp(40px, 9.5vw, 56px);
    line-height: 1;
    user-select: none;
    flex-shrink: 0;
    align-self: flex-start;
    opacity: .5;
  }
  .call-quote-mark:last-child{ align-self: flex-end; }
  .call-quote-text{
    max-height: 100%;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;                 /* Firefox 隐藏滚动条 */
    color: var(--text);
    font-family: var(--font-cn);
    font-size: clamp(20px, 5.2vw, 27px);
    line-height: 1.52;
    text-align: center;
    padding: 0 clamp(6px, 1.5vw, 12px);
    overflow-wrap: break-word;
  }
  .call-quote-text::-webkit-scrollbar{ display: none; }   /* WebKit 隐藏滚动条 */
  /* 仅当文字真的溢出时(由 JS 加 .clip)才底部渐隐(顶部保持清晰,因为总是从头读起,
     渐隐只用来暗示"下面还有,全文在字幕条里") */
  .call-quote-text.clip{
    -webkit-mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 22px), transparent 100%);
            mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 22px), transparent 100%);
  }
  .call-quote-text.hint{
    color: var(--text-soft);
    font-size: clamp(18px, 4.8vw, 24px);
  }
  .call-quote-text.lyric-mode{
    font-size: clamp(14px, 3.8vw, 19px);
    text-align: center;
  }
  .lyric-line{
    display: block;
    opacity: 0.28;
    transition: opacity 0.45s ease, transform 0.45s ease;
    transform: scale(0.96);
    padding: 3px 0;
  }
  .lyric-line.active{
    opacity: 1;
    transform: scale(1);
  }

  /* ── Transcript section ── */
  .call-transcript-section{
    width: min(92vw, 440px);
    display: flex; flex-direction: column; align-items: center;
    gap: 10px;
    flex-shrink: 0;
  }
  .call-transcript-label{
    position: relative;
    display: flex; align-items: center; justify-content: center;
    width: 100%;
    color: var(--text-faint);
    font-family: var(--font-en), var(--font-cn);
    font-size: clamp(12px, 1.5vw, 13px);
    letter-spacing: .06em;
  }
  .call-transcript-cap{ display: inline-flex; align-items: center; gap: 7px; }
  .call-transcript-cap::before{
    content: ""; display: inline-block;
    width: 16px; height: 14px;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'%3E%3Cline x1='4' y1='9' x2='4' y2='15'/%3E%3Cline x1='9' y1='4.5' x2='9' y2='19.5'/%3E%3Cline x1='14' y1='7.5' x2='14' y2='16.5'/%3E%3Cline x1='19' y1='10.5' x2='19' y2='13.5'/%3E%3C/svg%3E") center/contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'%3E%3Cline x1='4' y1='9' x2='4' y2='15'/%3E%3Cline x1='9' y1='4.5' x2='9' y2='19.5'/%3E%3Cline x1='14' y1='7.5' x2='14' y2='16.5'/%3E%3Cline x1='19' y1='10.5' x2='19' y2='13.5'/%3E%3C/svg%3E") center/contain no-repeat;
  }
  /* 「我在想 …」跳动点(引号区,贴心提示) */
  .call-dots{ display: inline-flex; align-items: center; gap: 4px; }
  .call-dots i{
    width: 4px; height: 4px; border-radius: 50%;
    background: currentColor;
    animation: callTypingDot 1.25s ease-in-out infinite;
  }
  .call-dots i:nth-child(2){ animation-delay: .16s; }
  .call-dots i:nth-child(3){ animation-delay: .32s; }
  @keyframes callTypingDot{ 0%,70%,100%{ transform: translateY(0); opacity:.4; } 35%{ transform: translateY(-3px); opacity:1; } }
  .call-dots-quote{ margin-left: 10px; vertical-align: middle; gap: 5px; }
  .call-dots-quote i{ width: 6px; height: 6px; }
  .call-transcript-bar{
    width: 100%;
    min-height: 2em;
    padding: clamp(11px, 2.2vw, 15px) clamp(18px, 4vw, 26px);
    border-radius: clamp(18px, 3.4vw, 24px);
    background: linear-gradient(157deg, var(--call-glass-top), var(--call-glass-bot));
    border: 1px solid var(--call-glass-edge);
    box-shadow: var(--call-glass-shadow), inset 0 1px 0 var(--call-glass-hi);
    -webkit-backdrop-filter: blur(24px) saturate(1.6);
    backdrop-filter: blur(24px) saturate(1.6);
    color: var(--text);
    font-family: var(--font-cn);
    font-size: clamp(14.5px, 2vw, 16.5px);
    line-height: 1.6;
    text-align: center;
    overflow-wrap: break-word;
    max-height: clamp(72px, 16vh, 132px);   /* 长字幕也封顶,不再把控制键/挂断顶出屏外 */
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;
  }
  .call-transcript-bar::-webkit-scrollbar{ display: none; }
  .call-transcript-bar .caret{
    display: inline-block; width: 1px; height: 1.04em; margin-left: 2px;
    background: currentColor; opacity: .55;
    vertical-align: -0.14em;
    animation: callCaret 1s steps(1) infinite;
  }
  @keyframes callCaret{ 0%,49%{ opacity:.55; } 50%,100%{ opacity:0; } }

  /* ── Controls row ── */
  .call-controls{
    display: flex; align-items: flex-start; justify-content: center;
    gap: clamp(30px, 9vw, 50px);
    margin-top: clamp(22px, 4vw, 34px);
    flex-shrink: 0;
  }
  .call-ctrl-btn{
    display: flex; flex-direction: column; align-items: center; gap: 9px;
    border: 0; padding: 0; cursor: pointer;
    background: transparent;
    color: var(--text-soft);
    -webkit-tap-highlight-color: transparent;
  }
  .call-ctrl-btn > svg,.call-ctrl-btn > .ph{
    width: clamp(58px, 14.5vw, 70px); height: clamp(58px, 14.5vw, 70px);
    padding: clamp(15px, 3.4vw, 19px);
    border-radius: 50%;
    background: linear-gradient(157deg, var(--call-glass-top), var(--call-glass-bot));
    border: 1px solid var(--call-glass-edge);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    backdrop-filter: blur(20px) saturate(1.6);
    box-shadow: 0 8px 22px rgba(40,60,78,.10), inset 0 1px 0 var(--call-glass-hi);
    transition: background .15s ease, transform .12s ease, color .15s ease;
  }
  .call-ctrl-btn:active > svg,.call-ctrl-btn:active > .ph{ transform: scale(.92); }
  .call-ctrl-btn > span{
    font-family: var(--font-cn);
    font-size: clamp(12px, 1.6vw, 13.5px);
    color: var(--text-faint);
  }
  .call-ctrl-btn.active > svg,.call-ctrl-btn.active > .ph{
    background: var(--accent);
    color: var(--accent-fg);
    border-color: transparent;
  }

  /* ── Hangup ── */
  .call-hangup{
    margin-top: clamp(20px, 4vw, 32px);
    width: clamp(64px, 15.5vw, 74px); height: clamp(64px, 15.5vw, 74px);
    border: 0; border-radius: 50%; padding: 0; cursor: pointer;
    background: var(--call-hangup-bg);
    color: #fff;
    display: grid; place-items: center;
    box-shadow: 0 10px 26px var(--call-hangup-shadow);
    transition: transform .15s ease, filter .2s ease;
    flex-shrink: 0;
  }
  .call-hangup:hover{ filter: brightness(1.05); }
  .call-hangup:active{ transform: scale(.92); }
  .call-hangup svg{ width: clamp(26px, 5.6vw, 31px); height: clamp(26px, 5.6vw, 31px); display: block; transform: rotate(135deg); }

  /* ── Minimize (top-left) ── */
  .call-minimize-top{
    position: absolute;
    top: calc(env(safe-area-inset-top) + clamp(10px, 2vw, 16px));
    left: clamp(10px, 2vw, 16px);
    width: 36px; height: 36px;
    border: 0; border-radius: 50%; padding: 0; cursor: pointer;
    background: var(--card-bg);
    border: 1px solid var(--card-line);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    color: var(--text-soft);
    display: grid; place-items: center;
    z-index: 2;
    -webkit-tap-highlight-color: transparent;
    transition: background .15s ease, transform .12s ease;
  }
  .call-minimize-top:active{ transform: scale(.9); }
  .call-minimize-top svg{ width: 18px; height: 18px; display: block; }

  /* ── Hide old wave (no longer visible) ── */
  .call-wave{ display: none; }

  /* ── cc老师托系统带给小克的话（2026-09-28）：居中一张小卡片，不是她的气泡、也不是他的。 ── */
  .cc-letter{
    align-self:center; width:min(86%,420px); margin:14px auto 10px; padding:10px 14px 12px;
    border:1px dashed var(--line-strong); border-radius:16px; background:var(--glass-thin); color:var(--text);
  }
  .cc-letter-head{ color:var(--text-faint); font:600 11.5px/1.3 var(--font-en),var(--font-cn); letter-spacing:.04em; margin-bottom:4px; }
  .cc-letter-body{ font:400 14px/1.6 var(--font-cn),var(--font-en); white-space:pre-wrap; word-break:break-word; }

  /* ── 从猫眼带着牌来的那条（2026-10-01）：她那句话上面一张小卡片（同一条消息里，像附件）。纯黑白灰（猫眼的规矩）。 ── */
  .oracle-card{
    align-self:flex-end; width:fit-content; max-width:min(78vw,360px); margin:0 0 4px; padding:9px 14px 11px;
    border:1px solid var(--line-strong); border-radius:16px; background:var(--glass-thin); color:var(--text); text-align:left;
  }
  .row.ai .oracle-card{ align-self:flex-start; }
  .oracle-card-head{ display:flex; align-items:center; gap:5px; color:var(--text-faint); font:600 11.5px/1.3 var(--font-cn),var(--font-en); letter-spacing:.04em; margin-bottom:5px; }
  .oracle-card-head i{ font-size:13px; }
  .oracle-card-question{ font:400 14px/1.55 var(--font-cn),var(--font-en); margin-bottom:6px; word-break:break-word; }
  .oracle-card-cards{ display:flex; flex-wrap:wrap; gap:4px 12px; font:500 13px/1.5 var(--font-cn),var(--font-en); letter-spacing:.08em; }
  /* 他去猫眼问牌（2026-10-01）：他那边（靠左）同一种卡片，下面多一段老猫的话 */
  .oracle-card.is-his{ align-self:flex-start; margin:2px auto 2px 0; max-width:min(86vw,420px); }
  .oracle-card-cards b{ font-weight:500; color:var(--text-faint); margin-right:2px; }
  .oracle-ask-note{ margin-top:4px; color:var(--text-faint); font:400 13px/1.6 var(--font-cn),var(--font-en); }
  .oracle-ask-reading{ margin-top:10px; padding-top:9px; border-top:1px solid var(--line); }
  .oracle-ask-label{ margin-bottom:4px; color:var(--text-faint); font:600 11.5px/1.3 var(--font-cn),var(--font-en); letter-spacing:.04em; }
  .oracle-ask-text{ font:400 14px/1.75 var(--font-cn),var(--font-en); white-space:pre-wrap; word-break:break-word; }
  .oracle-ask-text em{ color:var(--text-soft); }
  /* 输入框上面那张（还没发）：比点子那张多一行牌名，高一点；底色实一点，不然后面的聊天透过来 */
  .pending-att.oracle-ref{ background:var(--surface); box-shadow:0 4px 14px var(--shade-warm-1); }
  .pending-att.oracle-ref .idea-ref-text{ -webkit-line-clamp:3; line-clamp:3; }

  /* ── 糖罐倒计时（2026-09-28）：顶栏下面居中一颗小胶囊，谁中了什么、还剩多久，一行一个。点它进糖罐页。 ── */
  .candy-timer{
    position:fixed; z-index:140; left:50%; top:calc(var(--header-h) + env(safe-area-inset-top) + 6px); transform:translateX(-50%);
    max-width:calc(100vw - 32px); display:flex; align-items:center; gap:8px; padding:6px 12px 6px 9px;
    border:1px solid var(--card-line); border-radius:999px; background:var(--card-bg); color:var(--text);
    box-shadow:var(--card-shadow), 0 8px 24px var(--shade-warm-1);
    -webkit-backdrop-filter:blur(18px) saturate(1.3); backdrop-filter:blur(18px) saturate(1.3);
    font:500 12.5px/1.3 var(--font-cn),var(--font-en); cursor:pointer;
  }
  .candy-timer[hidden]{ display:none; }
  .candy-timer-icon{ font-size:17px; line-height:1; color:var(--text-soft); }
  .candy-timer-rows{ display:flex; flex-direction:column; gap:3px; min-width:0; }
  .candy-timer-row{ display:flex; align-items:baseline; gap:6px; min-width:0; white-space:nowrap; }
  .candy-timer-who{ color:var(--text-faint); font-size:11.5px; }
  .candy-timer-name{ min-width:0; max-width:10em; overflow:hidden; text-overflow:ellipsis; }
  .candy-timer-left{ margin-left:auto; padding-left:6px; font-family:var(--font-en); font-variant-numeric:tabular-nums; font-weight:600; }

  /* ── Call mini-bar (WeChat-style green strip) ── */
  .call-mini{
    display: none;
    position: fixed;
    left: 0; right: 0;
    top: calc(var(--header-h) + env(safe-area-inset-top));
    height: 34px;
    background: var(--accent);
    color: var(--accent-fg);
    font-family: var(--font-cn);
    font-size: 13px;
    align-items: center; justify-content: center;
    gap: 8px;
    z-index: 152;
    cursor: pointer;
    pointer-events: auto;
    -webkit-tap-highlight-color: transparent;
    transition: opacity .2s ease;
  }
  .call-mini:active{ filter: brightness(.88); }
  .call-mini-dot{
    width: 7px; height: 7px;
    border-radius: 50%;
    background: currentColor;
    animation: callMiniPulse 1.4s ease-in-out infinite;
  }
  @keyframes callMiniPulse{
    0%,100%{ opacity: 1; }
    50%{ opacity: .35; }
  }
  .call-mini-timer{
    font-family: var(--font-en);
    font-variant-numeric: tabular-nums;
    letter-spacing: .04em;
  }
  .call-overlay.open.minimized .call-scrim{ opacity: 0; pointer-events: none; }
  .call-overlay.open.minimized .call-sheet{ opacity: 0; pointer-events: none; transform: translateY(12px); }
  .call-overlay.open.minimized .call-mini{ display: flex; }
  .call-overlay.open.minimized{ pointer-events: none; }

  /* 来电:全屏(与通话中同一张画布,接听后无缝衔接,不再是顶部小卡片) */
  .incoming-call-overlay{ z-index: 151; }
  .incoming-call-overlay .call-scrim{ background: var(--call-scrim); }
  .incoming-call-overlay .call-sheet{
    justify-content: flex-start;
    gap: clamp(12px, 2.6vw, 20px);
  }
  /* caption 行(✦ incoming call ✦)——与 .call-status 同款横排 */
  .call-caption{
    display: inline-flex; align-items: center; gap: 11px;
    color: var(--think-label);
    font-family: var(--font-en), var(--font-cn);
    font-size: clamp(13px, 1.8vw, 15.5px);
    letter-spacing: .16em; line-height: 1;
    margin-top: clamp(2px, 2vh, 14px);
  }
  .call-caption .call-star{ color: var(--think-flourish); display: grid; place-items: center; }
  .call-caption .call-star svg{ width: 16px; height: 16px; display: block; }
  /* 来电大头像 + 呼吸光环 */
  .incoming-call-avatar{
    width: clamp(132px, 40vw, 184px); height: clamp(132px, 40vw, 184px);
    border-radius: 50%;
    background-image: var(--avatar-default);
    background-color: var(--avatar-default-color);
    background-size: cover; background-position: center;
    box-shadow: 0 12px 38px rgba(40,60,78,.18), inset 0 0 0 1px rgba(255,255,255,.14);
    margin-top: clamp(10px, 4vh, 36px);
    animation: incomingPulse 2.4s var(--ease-soft) infinite;
  }
  @keyframes incomingPulse{
    0%   { box-shadow: 0 12px 38px rgba(40,60,78,.18), 0 0 0 0 color-mix(in srgb, var(--accent) 34%, transparent), inset 0 0 0 1px rgba(255,255,255,.14); }
    70%  { box-shadow: 0 12px 38px rgba(40,60,78,.18), 0 0 0 22px color-mix(in srgb, var(--accent) 0%, transparent), inset 0 0 0 1px rgba(255,255,255,.14); }
    100% { box-shadow: 0 12px 38px rgba(40,60,78,.18), 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent), inset 0 0 0 1px rgba(255,255,255,.14); }
  }
  @media (prefers-reduced-motion: reduce){ .incoming-call-avatar{ animation: none; } }
  /* 来电动作区:推到底部,拒接/接听左右分开(iOS 式) */
  .incoming-call-actions{
    margin-top: auto;
    margin-bottom: calc(env(safe-area-inset-bottom) + clamp(14px, 5vh, 52px));
    display: flex; align-items: flex-end; justify-content: center;
    gap: clamp(46px, 22vw, 108px);
    width: 100%;
  }
  .incoming-call-slot{ display: flex; flex-direction: column; align-items: center; gap: 11px; }
  .incoming-call-label{
    font-family: var(--font-cn);
    font-size: clamp(12px, 1.6vw, 13.5px);
    color: var(--text-faint);
  }
  .incoming-call-title{
    margin-top: clamp(4px, 2vw, 12px);
    color: var(--text);
    font-family: var(--font-cn);
    font-size: clamp(27px, 6.6vw, 36px);
    line-height: 1.2;
    font-weight: 500;
  }
  .incoming-call-text{
    width: min(80vw, 360px);
    min-height: 1.6em;
    color: var(--text-soft);
    font-family: var(--font-cn);
    font-size: clamp(14px, 1.9vw, 16px);
    line-height: 1.6;
    text-align: center;
    overflow-wrap: break-word;
  }
  .incoming-call-actions{
    display: flex; align-items: center; justify-content: center;
    gap: clamp(18px, 6vw, 34px);
    width: 100%;
  }
  .incoming-call-btn{
    width: clamp(62px, 15.5vw, 74px); height: clamp(62px, 15.5vw, 74px);
    border: 0; border-radius: 50%; padding: 0; cursor: pointer;
    color: #fff;
    display: grid; place-items: center;
    transition: transform .15s ease, filter .2s ease;
  }
  .incoming-call-btn:hover{ filter: brightness(1.05); }
  .incoming-call-btn:active{ transform: scale(.92); }
  .incoming-call-btn svg{ width: clamp(26px, 6vw, 30px); height: clamp(26px, 6vw, 30px); display: block; }
  .incoming-call-btn.accept{
    background: #5aa77a;
    box-shadow: 0 10px 26px rgba(69,132,96,.34);
  }
  .incoming-call-btn.decline{
    background: var(--call-hangup-bg);
    box-shadow: 0 10px 26px var(--call-hangup-shadow);
  }
  .incoming-call-btn.decline svg{ transform: rotate(135deg); }
  .topbtn.call.active{ color: var(--accent); }

  /* ── 长按气泡 · 复制菜单 (TG 式抬起+遮罩) ── */
  /* 长按由我们接管 → 彻底屏蔽聊天区(#scroll)的系统选择/放大镜/callout,否则和我们的菜单打架。
     用 !important 压过一切(含 iOS 误报 hover/pointer 的情况)。输入框在 #scroll 外,单独保持可选可编辑;
     气泡里要复制文字走长按菜单的 Copy。 */
  #scroll, #scroll *{
    -webkit-user-select:none !important; user-select:none !important;
    -webkit-touch-callout:none !important;
  }
  textarea, input, .composer, .composer *{
    -webkit-user-select:text !important; user-select:text !important;
    -webkit-touch-callout:default !important;
  }

  .msg-menu{ position:fixed; inset:0; z-index:250; opacity:0; pointer-events:none; }
  .msg-menu.open{ opacity:1; pointer-events:auto; }
  .msg-menu-scrim{
    position:absolute; inset:0;
    background:var(--scrim);
    -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px);
    opacity:0; transition:opacity .26s var(--ease-soft);
  }
  .msg-menu.open .msg-menu-scrim{ opacity:1; }
  .msg-menu-clone{
    position:fixed !important; margin:0 !important; animation:none !important;
    pointer-events:none; box-sizing:border-box;
    box-shadow:0 22px 50px var(--shade-cool-3);
    transform:scale(1); transition:transform .26s var(--ease-soft); will-change:transform;
  }
  .msg-menu.open .msg-menu-clone{ transform:scale(1.02); }
  .msg-menu-clone.clone-human{ background:var(--bubble-human-bg) !important; color:var(--bubble-human-fg) !important; }
  .msg-menu-clone.clone-ai{ background:var(--bubble-ai-bg) !important; color:var(--bubble-ai-fg) !important; }
  /* 抬起整条消息（一组气泡）：外层只管位置，影子和颜色给里面每个气泡。
     菜单不在 .app 里面，聊天页那几条带 .app 的气泡颜色够不着，所以这里再写一遍。 */
  .msg-menu-clone.msg-menu-clone-row{ box-shadow:none; }
  .msg-menu-clone-row .message-bubbles{ width:100%; }
  .msg-menu-clone-row .bubble{ box-shadow:0 16px 38px var(--shade-cool-3); animation:none !important; }
  .msg-menu-clone-row.group-human .bubble{ background:var(--bubble-human-bg) !important; color:var(--bubble-human-fg) !important; }
  .msg-menu-clone-row.group-ai .bubble{ background:var(--bubble-ai-bg) !important; color:var(--bubble-ai-fg) !important; }
  .msg-menu-actions{
    position:fixed; display:flex; flex-direction:column; min-width:150px; padding:5px;
    border-radius:16px; background:var(--composer-bg); border:1px solid var(--hairline);
    box-shadow:var(--shadow);
    -webkit-backdrop-filter:blur(20px) saturate(1.4); backdrop-filter:blur(20px) saturate(1.4);
    opacity:0; transform:translateY(8px) scale(.96); transform-origin:top center;
    transition:opacity .2s var(--ease-soft) .05s, transform .26s var(--ease-soft) .05s;
  }
  .msg-menu.open .msg-menu-actions{ opacity:1; transform:none; }
  .msg-act{
    appearance:none; -webkit-appearance:none; border:0; background:transparent; color:var(--text);
    font-family:var(--font-en), var(--font-cn); font-size:15px; display:flex; align-items:center; gap:11px;
    padding:10px 14px; border-radius:12px; cursor:pointer; text-align:left; width:100%;
    transition:background var(--motion-fast);
  }
  .msg-act:hover{ background:var(--row-press); }
  .msg-act:active{ background:var(--row-press); transform:scale(.98); }
  .msg-act svg{ width:18px; height:18px; opacity:.82; flex:0 0 auto; }
  .msg-act[hidden]{ display:none; }
  .msg-act-star{ display:grid; place-items:center; width:18px; height:18px; flex:none; }

  /* ── reaction chips (AI poke) ── */
  .row.has-reactions{ flex-direction:column; gap:5px; }
  .row.human.has-reactions{ align-items:flex-end; }
  .row.ai.has-reactions{ align-items:flex-start; }
  .reactions{ display:flex; flex-wrap:wrap; gap:5px; max-width:min(61vw,506px); }
  .reaction{
    display:inline-flex; align-items:center; justify-content:center;
    font-size:15px; line-height:1; padding:4px 9px; border-radius:13px;
    background:var(--bubble-ai-bg); border:1px solid var(--hairline);
    box-shadow:0 4px 12px var(--shade-cool-2);
    -webkit-user-select:none; user-select:none;
  }
  .reaction.pop-in{ animation:reactionPop .52s cubic-bezier(.34,1.56,.5,1) both; }
  @keyframes reactionPop{
    0%{ transform:scale(0) rotate(-16deg); opacity:0; }
    55%{ transform:scale(1.22) rotate(5deg); opacity:1; }
    100%{ transform:none; opacity:1; }
  }

  @media (prefers-reduced-motion: reduce){
    *,
    *::before,
    *::after{
      animation: none !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }
    /* 通话声纹是"对方正在说话"的功能性反馈,即便系统减弱动态也保留(细窄低位移,不刺激) */
    .call-wave i{
      animation: callWave var(--dur, 1s) var(--ease-soft) var(--d, 0s) infinite alternate !important;
    }
  }

  /* Current layout uses the single theme block at the top of this file. */
  html,body{ background:var(--bg); }
  body{ color:var(--text); font-family:var(--font-cn); letter-spacing:-.01em; }
  .app{ background:var(--bg); }

  /* ── 聊天背景 ──
     只有 Chat 有背景。Home / Feed / Code / Settings 那一层(.home-shell)是不透明的、
     盖在 .app 上面，所以不需要任何判断，它们天然看不到这张图。
     模糊会让图去采样画面外的空白、四周透出一圈米白雾边，所以这一层比屏幕大出
     两倍模糊半径,多出来的部分由 .app 自己的 overflow:hidden 裁掉;模糊为 0 时
     四边退化成 0,一个像素都不裁。
     2026-09-09：这一层原来是 .app::before，手机上整片不画（面板里的缩略图用同一个
     变量却是好的）。改成两个真的元素：外面那层负责裁，里面那层才是图。和面板里
     那块预览是一模一样的结构，两边要坏一起坏、要好一起好，好判断。 */
  .chat-bg-layer{
    position:absolute;
    top:0; left:0; right:0;
    bottom:calc(-1 * var(--ios-pwa-bottom-bleed));
    z-index:0;
    pointer-events:none;
    overflow:hidden;   /* 自己裁自己，不指望 .app 的 overflow */
  }
  .chat-bg-layer-image{
    position:absolute;
    top:calc(-2 * var(--chat-bg-blur, 0px));
    left:calc(-2 * var(--chat-bg-blur, 0px));
    right:calc(-2 * var(--chat-bg-blur, 0px));
    bottom:calc(-2 * var(--chat-bg-blur, 0px));
    background-image:var(--chat-bg-image, none);
    background-position:center;
    background-size:cover;
    background-repeat:no-repeat;
    opacity:var(--chat-bg-opacity, 1);
  }
  /* 聊天以外那一层的底图。结构和上面一模一样，只是换一组变量——两张各调各的。 */
  .shell-bg-layer-image{
    position:absolute;
    top:calc(-2 * var(--shell-bg-blur, 0px));
    left:calc(-2 * var(--shell-bg-blur, 0px));
    right:calc(-2 * var(--shell-bg-blur, 0px));
    bottom:calc(-2 * var(--shell-bg-blur, 0px));
    background-image:var(--shell-bg-image, none);
    background-position:center;
    background-size:cover;
    background-repeat:no-repeat;
    opacity:var(--shell-bg-opacity, 1);
  }
  html[data-shell-bg-blurred] .shell-bg-layer-image{ filter:blur(var(--shell-bg-blur, 0px)); }
  /* 铺了 App 底图时，那一层的米白底要让开，否则底图被它整块盖住。 */
  html[data-shell-bg="on"] .home-shell{ background:transparent; }

  /* 卡片本身的玻璃写在下面「Cards use their own flat surface」那条之后——
     那条是 !important 的，压在这里会被它盖掉。 */
  /* 模糊为 0 时干脆不挂 filter：不糊的时候这一层就退化成一张最普通的背景图，
     手机上少一层合成，也少一个可能出问题的地方。 */
  html[data-chat-bg-blurred] .chat-bg-layer-image{ filter:blur(var(--chat-bg-blur, 0px)); }
  /* 面板里那块预览用自己一组变量：它显示的是**面板这次在编辑的那一张**，
     不是聊天那张。写死成 --chat-bg-* 的那版，在 App 背景面板里会显示聊天的图。 */
  .chat-bg-preview-image{
    position:absolute;
    top:calc(-2 * var(--preview-bg-blur, 0px));
    left:calc(-2 * var(--preview-bg-blur, 0px));
    right:calc(-2 * var(--preview-bg-blur, 0px));
    bottom:calc(-2 * var(--preview-bg-blur, 0px));
    background-image:var(--preview-bg-image, none);
    background-position:center;
    background-size:cover;
    background-repeat:no-repeat;
    opacity:var(--preview-bg-opacity, 1);
    filter:blur(var(--preview-bg-blur, 0px));
    /* Safari 里 overflow:hidden 的圆角裁不住带 filter 的子层，四个角会露出没被裁到的
       图（看着像四块深色三角）。所以这一层自己也带圆角：它比容器外扩了 2 倍模糊
       半径，圆角就补上同样的量，弧线才和容器那 26px 对得上。 */
    border-radius:calc(26px + 2 * var(--preview-bg-blur, 0px));
  }

  .topbar{
    height:calc(72px + env(safe-area-inset-top));
    padding:calc(env(safe-area-inset-top) + 10px) var(--side-pad) 8px;
    border-bottom:0;
    background:linear-gradient(180deg,var(--bg) 72%,transparent);
  }
  /* 有背景时顶栏那道米白渐变会变成一条压在照片上的横条。按钮自己有白底药丸，
     去掉它照样看得清；顶上那道米白挡不住消息了，改让消息在顶栏高度里就淡完。
     必须带 `.app`：Code 页的头也叫 .topbar，不限定的话它会跟着一起变透明。 */
  html[data-chat-bg="on"] .app .topbar{ background:transparent; }
  html[data-chat-bg="on"] .app .scroll{
    -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 calc(58px + env(safe-area-inset-top)));
    mask-image:linear-gradient(to bottom,transparent 0,#000 calc(58px + env(safe-area-inset-top)));
  }

  /* ── 铺了背景图之后：气泡改成浅色玻璃拟态 ──
     全部规则都写死在 .app 里面，也就是只作用于聊天页。别图省事去掉 `.app`：
     Code 页和聊天共用 .message-time、.tool-event-card 这些类名，挂在整个文档上
     的话，一设背景图 Code 页也跟着变（2026-09-09 踩过）。 */
  html[data-chat-bg="on"] .app .row.ai .bubble{
    background:var(--glass-ai);
    box-shadow:var(--glass-edge), var(--glass-bevel), var(--glass-drop);
  }
  html[data-chat-bg="on"] .app .row.human .bubble{
    background:var(--glass-human);
    box-shadow:var(--glass-edge), var(--glass-bevel), var(--glass-drop);
  }
  /* 图片气泡不受影响：它自己那条 .bubble.attachment-bubble 全是 !important，
     背景和投影都会被按回透明——图自己就是内容，不该再糊一层白。 */
  /* 勾选旧聊天时那圈选中框，别被上面的玻璃投影盖掉 */
  html[data-chat-bg="on"] .app .row.legacy-selected .bubble{
    box-shadow:0 0 0 2px rgba(69,92,110,.32), var(--glass-drop);
  }
  /* 独立成行的那几条小字：弹飞、续接、思考链那行。
     它们原来是光秃秃的灰字压在照片上，背景一深就整行看不见——垫一颗玻璃胶囊才稳。
     日期和他没说话那两条 2026-09-26 起不垫了（她要字直接落在底图上），见下面。
     时间戳**不给**胶囊（用户明确要求）：它跟在每一组消息屁股后面，颗颗都垫一个
     太碎。只把颜色压实一点，深色照片上仍然会吃力，这是知情的取舍。 */
  html[data-chat-bg="on"] .app .poke-line,
  html[data-chat-bg="on"] .app .continuity-divider span,
  html[data-chat-bg="on"] .app .think-caption,
  html[data-chat-bg="on"] .app .tool-run > summary{
    background:var(--glass-quiet);
    border-radius:999px;
    /* 压在照片上时字要比平时实：这些行本来字号就小，再用淡灰就整行糊进背景里 */
    color:var(--text);
    /* 内白高光(深底上看得见) + 一层灰色柔和托底(白底上把它托起来)。
       深色外描边试过，小胶囊上太硬，去掉了。 */
    box-shadow:var(--glass-edge), var(--glass-drop-quiet);
  }
  html[data-chat-bg="on"] .app .poke-line{ padding:5px 13px; }
  html[data-chat-bg="on"] .app .continuity-divider span{ padding:3px 11px; }
  html[data-chat-bg="on"] .app .think-caption{ padding:4px 12px; }
  html[data-chat-bg="on"] .app .tool-run > summary{ padding:4px 13px; }
  /* 他没说话、换日这两条：原来铺了背景图时给中间那截字垫一颗小胶囊，2026-09-26 她说去掉、
     让字直接落在底图上（和思考那一行一样）。只把字压实一点，线换成两色的。 */
  html[data-chat-bg="on"] .app .no-reply-copy{ color:var(--text); }
  html[data-chat-bg="on"] .app .day{ color:var(--text-soft); }
  /* 分隔线上的那两道线：单色线注定只在一半的背景上可见，换成两色线（见 --glass-line）。 */
  html[data-chat-bg="on"] .app .no-reply-line::before,
  html[data-chat-bg="on"] .app .no-reply-line::after,
  html[data-chat-bg="on"] .app .day::before,
  html[data-chat-bg="on"] .app .day::after,
  html[data-chat-bg="on"] .app .continuity-divider::before,
  html[data-chat-bg="on"] .app .continuity-divider::after{
    height:2px; background:var(--glass-line);
  }
  html[data-chat-bg="on"] .app .message-time{ color:var(--text-soft); opacity:1; }
  html[data-chat-bg="on"] .app .ai-love-signature{ color:var(--text); }
  /* 工具卡片是脚注，比气泡再淡一档 */
  html[data-chat-bg="on"] .app .tool-event-card,
  html[data-chat-bg="on"] .app .tool-event-group .tool-event-card{
    background:var(--glass-quiet);
    box-shadow:var(--glass-edge);
  }
  /* 头像的托底 = 底下一层淡淡的外扩阴影，不是垫一块白圆片：头像自己该长什么样
     还长什么样，只是浮起来一点。头像是圆形的 div，box-shadow 会跟着圆走。 */
  html[data-chat-bg="on"] .app .row.ai .message-stack>.message-avatar,
  html[data-chat-bg="on"] .app .row.human .message-stack>.message-avatar{
    box-shadow:var(--glass-halo);
  }
  /* 收尾那句 logo 的托底，配方见 :root 的 --glass-logo-halo。
     必须用 filter 的 drop-shadow 而不是 box-shadow：logo 是一张带透明的图，
     box-shadow 会顺着它那个方框走，糊出一个方块。 */
  html[data-chat-bg="on"] .app .ai-love-signature img{ filter:var(--glass-logo-halo); }

  .peerpill{ display:none; }
  .sidebar-trigger{
    left:var(--side-pad); top:calc(env(safe-area-inset-top) + 2px);
    width:44px; height:44px; background:var(--glass-solid);
    box-shadow:0 7px 24px var(--shade-warm-1);
  }
  .header-left{
    position:absolute; left:var(--side-pad); top:calc(env(safe-area-inset-top) + 2px);
    display:flex; align-items:center; gap:8px;
  }
  .header-left .sidebar-trigger{ position:static; }
  /* 右边那三颗按钮共用一颗白药丸（.header-actions 自带），左边这颗是单独的圆。
     Code 那颗返回也归这条管：顶栏透明之后它是直接浮在正文上的，没有底就糊进字里。 */
  .chat-exit,
  .code-workspace .header-left .topbtn{
    width:44px; height:44px; background:var(--glass-solid);
    box-shadow:0 7px 24px var(--shade-warm-1);
  }
  .header-actions{
    right:var(--side-pad); top:calc(env(safe-area-inset-top) + 2px);
    height:44px; gap:2px; padding:0 5px;
    border-radius:22px; background:var(--glass-solid);
    box-shadow:0 7px 24px var(--shade-warm-1);
  }
  .topbtn{ width:40px; height:40px; color:var(--text); }
  .topbtn svg{ width:21px; height:21px; }
  .scroll{
    /* 下边距多出的 (--blur-ramp - 24px)：渐变模糊的起点往上挪了多少，贴底停着的最后一行就
       跟着往上挪多少，不被糊。24px 是渐变区第一版的高度，那时候这里刚好是 --composer-zone。 */
    padding:12px clamp(24px,5vw,52px) calc(var(--composer-zone) + var(--blur-ramp) - 24px);
    -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 24px);
    mask-image:linear-gradient(to bottom,transparent 0,#000 24px);
  }
  .row{ margin-top:clamp(22px,3.5vw,36px); }
  .row.grouped{ margin-top:10px; }
  .row.ai{ padding-right:clamp(18px,5vw,54px); }
  .bubble{
    max-width:min(78vw,720px); padding:11px 16px;
    font-size:clamp(15px,1.8vw,18px); line-height:1.66;
    letter-spacing:0; box-shadow:none;
  }
  .row.ai .bubble{
    max-width:min(78vw,560px); padding:10px 16px; border-radius:var(--bubble-radius);
    background:var(--bubble-ai-bg); color:var(--bubble-ai-fg);
    box-shadow:none;
  }
  .row.human .bubble{
    max-width:min(78vw,560px); background:var(--bubble-human-bg); color:var(--bubble-human-fg); box-shadow:none;
    border-radius:20px; padding:10px 16px;
  }
  .row.ai.tail .bubble{ border-bottom-left-radius:20px; }
  .row.human.tail .bubble{ border-bottom-right-radius:20px; }
  /* 同一条消息拆出来的几个气泡叠成一组（2026-09-24）：头像那一侧挨着的角收小，外侧不动。
     必须排在上面两行后面：同样重的选择器，靠后的才算数。join 类由 main.js 的 makeMessage 挂。 */
  .row.ai .bubble.join-up{ border-top-left-radius:var(--bubble-join-radius); }
  .row.ai .bubble.join-down{ border-bottom-left-radius:var(--bubble-join-radius); }
  .row.human .bubble.join-up{ border-top-right-radius:var(--bubble-join-radius); }
  .row.human .bubble.join-down{ border-bottom-right-radius:var(--bubble-join-radius); }
  .message-stack{ max-width:min(78vw,560px); }
  .message-time{ color:var(--text-faint); }
  .meta{ margin-left:8px; color:var(--text-faint); font-size:11px; }
  .row.ai .meta,.row.human .meta{ display:none; }
  .row.human .meta:has(.fail),.row.human .meta:has(.delivery){ display:inline; }

  .row.think{ width:100%; padding:0; margin-top:28px; margin-bottom:0; }
  .row.think + .row.ai{ margin-top:0; }
  .row.think.think-open{ justify-content:flex-start; margin-top:28px; margin-bottom:18px; }
  .think-block,.think-block.open{ width:100%; max-width:min(100%,760px); text-align:left; }
  .think-toggle,.think-block.open .think-toggle{
    width:100%; min-height:34px; display:flex; flex-direction:row;
    align-items:center; gap:10px; color:var(--text-soft);
  }
  .think-rule{ display:none !important; }
  .think-caption{
    width:auto; justify-content:flex-start; gap:7px;
    color:var(--think-label); font-size:16px; font-weight:400;
  }
  .think-caption-star{
    flex:none; color:var(--think-flourish);
    font-family:var(--font-cn); font-size:1.04em; line-height:1; transform:translateY(.06em);
  }
  .think-caption-text{
    color:var(--think-label); font-family:var(--font-cn);
    font-size:clamp(12px,1.32vw,13.5px); font-weight:400;
    line-height:1.46; letter-spacing:.02em;
  }
  .think-block.is-streaming .think-caption-text{
    color:transparent;
    background:linear-gradient(90deg,#666660 18%,#DADAD5 45%,#666660 72%);
    background-size:220% 100%;
    -webkit-background-clip:text; background-clip:text;
    animation:thinkingShimmer 1.35s linear infinite;
  }
  @keyframes thinkingShimmer{
    from{ background-position:200% 0; }
    to{ background-position:-20% 0; }
  }
  .think-body{ margin-top:14px; }
  .think-text{
    width:100%; margin:0; padding:0 0 0 24px;
    color:var(--text-soft); font-size:14px; line-height:1.7; text-align:left;
  }
  .think-starline{ display:none; }

  .composer{
    left:clamp(12px,3vw,28px); right:clamp(12px,3vw,28px);
    bottom:calc(10px + env(safe-area-inset-bottom));
    width:auto; min-height:104px; padding:10px;
    gap:6px; align-items:flex-end;
    border:.5px solid var(--line-faint); border-radius:28px;
    background:var(--glass-half); box-shadow:none;
    -webkit-backdrop-filter:blur(10px) saturate(1); backdrop-filter:blur(10px) saturate(1);
  }
  /* 输入框那一截的渐变模糊（2026-09-24，照她在截图上用红框框出来的那一块）。
     聊天照常从输入框后面滑过去，**不淡掉**（她明确不要淡掉）；从输入框上沿往上一点
     开始，越往下越糊，输入框底下那一截——原来能清清楚楚看见半句话的地方——糊得最厉害。
     两层叠着才叫"渐变"：第一层轻、从最上沿就开始；第二层重、晚一点才出来。
     **别往上加层数**：backdrop-filter 是按层、按帧算的，2026-09-09 给每个气泡磨砂就是
     这么把手机卡到滑不动的（CONTEXT.md 同日那条）。它和输入框一样是固定不动、全屏
     只有一处的东西，这点开销才付得起。
     高度跟着输入框的真高度走（--composer-live-h，main.js 里量的；字多了输入框会长高），
     键盘弹起来跟着 --keyboard-offset 一起抬；往下伸进 iPhone 多出来的那截底边
     （--ios-pwa-bottom-bleed），和聊天背景那层同一个做法。
     --blur-ramp 是输入框上沿往上多糊的那一截（定义在 :root）。在预览里来回调过：24px 她嫌
     短，72px、48px 都嫌"溢出来太多"，现在是 32px；同一轮她还嫌"糊得太厉害"，两层从 3/12px
     收到 2/6px。聊天列表的下边距跟着多出 (ramp - 24px)（见 .scroll）：贴底停着时最后一行
     还是离渐变起点只差几个像素、不被糊。 */
  .chat-bottom-blur{
    position:absolute; left:0; right:0; z-index:50; pointer-events:none;
    bottom:calc(-1 * var(--ios-pwa-bottom-bleed));
    height:calc(var(--ios-pwa-bottom-bleed) + 10px + env(safe-area-inset-bottom) + var(--keyboard-offset) + var(--composer-live-h, 100px) + var(--blur-ramp));
  }
  /* 「回到底部」那颗的座（2026-09-24）：一条零高度的线，正好压在输入框上沿。药丸还是
     .newmsg-pill 那条规则定位（bottom:calc(100% + 10px)），只是"上沿"换成了这条线。
     为什么不留在输入框里面，见 index.html 那段注释：玻璃套玻璃，里面那块不糊。
     这条线的算法和 .composer 那条一模一样（底边 10px + 安全区，高度是量出来的真高度），
     键盘那份用 bottom 跟而不用 transform：父元素上挂 transform 在有的浏览器里会把它变成
     "只糊得到自己"的那种容器，刚修好的毛玻璃又没了。
     z-index 夹在底部模糊（50）和输入框（100）之间：压在模糊上面，它糊的才是已经糊过一层的
     聊天，看着和输入框是同一块玻璃。 */
  .chat-pill-anchor{
    position:fixed; left:0; right:0; z-index:60; height:0; pointer-events:none;
    bottom:calc(10px + env(safe-area-inset-bottom) + var(--keyboard-offset) + var(--composer-live-h, 104px));
    transition:bottom .28s cubic-bezier(.2,.8,.2,1);
  }
  .chat-bottom-blur > i{ position:absolute; inset:0; }
  .chat-bottom-blur > i:first-child{
    -webkit-backdrop-filter:blur(2px); backdrop-filter:blur(2px);
    -webkit-mask-image:linear-gradient(to bottom, transparent 0, #000 var(--blur-ramp));
    mask-image:linear-gradient(to bottom, transparent 0, #000 var(--blur-ramp));
  }
  .chat-bottom-blur > i:last-child{
    -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
    -webkit-mask-image:linear-gradient(to bottom, transparent calc(var(--blur-ramp) * .5), #000 calc(var(--blur-ramp) + 72px));
    mask-image:linear-gradient(to bottom, transparent calc(var(--blur-ramp) * .5), #000 calc(var(--blur-ramp) + 72px));
  }
  .composer .field{
    display:grid; grid-template-columns:40px minmax(0,1fr) 40px;
    grid-template-rows:minmax(42px,auto) 40px; gap:2px;
    flex:1 1 0; min-width:0; min-height:82px; padding:0; border:0; border-radius:0;
    background:transparent; box-shadow:none;
  }
  .composer textarea{
    grid-column:1/-1; grid-row:1; align-self:center;
    width:100%; min-width:0; min-height:42px; padding:5px 14px 6px 13px;
    color:var(--text); font:500 clamp(16px,2vw,19px)/1.4 var(--font-en),var(--font-cn);
  }
  textarea::placeholder{ color:var(--text-soft); }
  .clip-in-field{ grid-column:1; grid-row:2; align-self:end; background:var(--bubble-ai-bg); color:var(--text); }
  .runtime-picker-trigger{
    grid-column:2; grid-row:2; align-self:end; justify-self:start;
    min-width:0; max-width:100%; height:40px; border:0; border-radius:20px;
    padding:0 14px; background:var(--bubble-ai-bg); color:var(--text); cursor:pointer;
    display:inline-flex; align-items:center; gap:7px;
    font:600 16px/1 var(--font-en),var(--font-cn);
  }
  .runtime-picker-trigger:disabled{ cursor:default; color:var(--text-faint); }
  /* 行高给到 1.65：外面那颗按钮是 font:…/1（行高 = 字号），这一格又要裁掉放不下的字（名字太长时
     显示"…"）。换成 Literata 之后 p、g、y 往下伸得比 Inter 多，行高 1 的格子装不下，"Opus" 的 p
     尾巴被裁掉了（2026-09-26 她截图问的）。1.65 是量出来的：Literata 自己给字留的上下空间约 1.6 个字号。
     按钮本身是固定 40px 高、内容居中，行高变大不影响排版。 */
  .runtime-model-name{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; line-height:1.65; }
  .runtime-effort-name{ flex:none; color:var(--text-soft); font-weight:500; }
  .emojibtn{ grid-column:3; grid-row:2; align-self:end; width:40px; height:40px; color:var(--text-soft); }
  /* 麦克风和笑脸同一个灰（2026-09-25）：两颗挨着，一深一浅看着像出了错。发送键才是这一排最重的。 */
  #micBtn,#codeMicBtn{ color:var(--text-soft); }
  .floatbtn.send{ width:44px; height:44px; margin:0; background:var(--fill-strong); box-shadow:none; }
  /* 位置不在这儿定了（见上面那条：钉在输入框上沿）。这里只管长相。
     原来这一行还写着 `bottom:calc(122px + safe)`——就是它把药丸埋进输入框的。
     2026-09-24 起和输入框是同一块玻璃（她要的：「和输入框一样的毛玻璃材质」），
     以前是一颗白药丸 + 投影。下面这几样和 .composer 那条一个字都不许差，
     test_code_scroll.js 对着比。Code 页那颗复用这一条，那边的输入框也是同一块玻璃。 */
  .newmsg-pill{
    color:var(--text);
    border:.5px solid var(--line-faint);
    background:var(--glass-half); box-shadow:none;
    -webkit-backdrop-filter:blur(10px) saturate(1); backdrop-filter:blur(10px) saturate(1);
  }

  .runtime-picker{
    position:fixed; inset:0; z-index:360; display:flex; align-items:flex-end; justify-content:center;
  }
  .runtime-picker.hidden{ display:none; }
  .runtime-picker-scrim{
    position:absolute; inset:0; border:0; background:var(--scrim);
    opacity:0; transition:opacity .42s ease;
  }
  .runtime-picker-sheet{
    position:relative; width:min(100%,620px); max-height:min(82vh,760px); overflow:auto;
    padding:10px 18px calc(22px + env(safe-area-inset-bottom));
    border-radius:32px 32px 0 0; background:var(--bg); color:var(--text);
    box-shadow:0 -16px 48px var(--shade-warm-2);
    opacity:.98; transform:translateY(100%);
    transition:transform .42s cubic-bezier(.22,.8,.24,1),opacity .42s ease;
  }
  .runtime-picker.open .runtime-picker-scrim{ opacity:1; }
  .runtime-picker.open .runtime-picker-sheet{ opacity:1; transform:translateY(0); }
  .runtime-picker-handle{ width:42px; height:5px; margin:0 auto 8px; border-radius:99px; background:var(--surface-strong); }
  .runtime-picker-head{ position:relative; min-height:58px; display:flex; align-items:center; justify-content:center; }
  .runtime-picker-title{ font:650 20px/1.2 var(--font-en),var(--font-cn); }
  .runtime-picker-close{
    position:absolute; left:0; width:46px; height:46px; border:0; border-radius:50%;
    background:var(--surface); color:var(--text); font:400 34px/1 var(--font-en),var(--font-cn); cursor:pointer;
    box-shadow:0 7px 22px var(--shade-warm-1);
  }
  .runtime-model-list,.runtime-effort-card{
    margin-top:14px; padding:5px 18px; border-radius:26px; background:var(--surface-soft);
  }
  .runtime-model-option{
    width:100%; min-height:78px; padding:14px 4px; border:0; border-bottom:1px solid var(--line-faint);
    background:transparent; color:inherit; text-align:left; cursor:pointer;
    display:flex; align-items:center; justify-content:space-between; gap:16px;
  }
  .runtime-model-option:last-child{ border-bottom:0; }
  .runtime-model-copy{ min-width:0; display:flex; flex-direction:column; gap:5px; }
  .runtime-model-label{ font:650 19px/1.25 var(--font-en),var(--font-cn); }
  .runtime-model-check{ flex:none; width:18px; height:18px; border:1.5px solid #AAA9A3; border-radius:50%; }
  .runtime-model-option.active .runtime-model-check{ border:5px solid var(--line-bold); }
  .runtime-effort-card{ padding:14px 18px 18px; }
  .runtime-effort-head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; }
  .runtime-effort-label{ font:650 18px/1.3 var(--font-en),var(--font-cn); }
  .runtime-effort-hint{ color:var(--text-soft); font:500 14px/1.3 var(--font-en),var(--font-cn); }
  .runtime-effort-options{ margin-top:13px; display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:6px; }
  .runtime-effort-option{
    min-width:0; height:42px; padding:0 4px; border:0; border-radius:21px;
    background:var(--surface); color:var(--text-soft); font:600 14px/1 var(--font-en),var(--font-cn); cursor:pointer;
  }
  .runtime-effort-option.active{ background:var(--fill-strong); color:var(--text-on-fill); }
  .runtime-picker-status{ min-height:20px; padding:10px 6px 0; color:var(--text-soft); text-align:center; font-size:14px; }

  /* ── 聊天背景调节面板 ──
     结构照抄上面的模型选择器，但没有压暗的遮罩：面板升起来的时候上面露着真正的
     聊天，拖滑杆时背景实时跟着变，看得见才调得准。 */
  .chat-bg-sheet-wrap{
    position:fixed; inset:0; z-index:360; display:flex; align-items:flex-end; justify-content:center;
    pointer-events:none;
  }
  .chat-bg-sheet-wrap.hidden{ display:none; }
  /* 只负责挡住后面的聊天，点它什么都不发生：手滑碰到空白处不该把刚拖好的东西弄丢。 */
  .chat-bg-scrim{
    position:absolute; inset:0; border:0; background:transparent;
    pointer-events:auto;
  }
  .chat-bg-sheet{
    position:relative; width:min(100%,620px); max-height:min(86vh,700px); overflow:auto;
    padding:10px 18px calc(22px + env(safe-area-inset-bottom));
    border-radius:32px 32px 0 0; background:var(--bg); color:var(--text);
    box-shadow:0 -16px 48px var(--shade-warm-2);
    opacity:.98; transform:translateY(100%); pointer-events:auto;
    transition:transform .42s cubic-bezier(.22,.8,.24,1),opacity .42s ease;
  }
  .chat-bg-sheet-wrap.open .chat-bg-sheet{ opacity:1; transform:translateY(0); }
  /* 面板里的预览：和聊天用同一套变量，所以拖滑杆时这里也实时在变。
     它是自带的，不依赖面板上方那片聊天——那儿很可能正好是一段空白。 */
  .chat-bg-preview{
    position:relative; margin-top:4px; height:118px;
    border-radius:26px; overflow:hidden; background:var(--bg);
  }
  /* 标题那一行压矮一点：面板里东西不少，整屏放不下就要滚，很难用 */
  .chat-bg-sheet .runtime-picker-head{ min-height:40px; }
  /* .chat-bg-preview-image 的样式和聊天那层写在一起（见上面的 .chat-bg-layer-image），
     两边必须一模一样，不然预览里好看、贴上去变样。 */
  .chat-bg-preview-rows{
    position:relative; height:100%;
    display:flex; flex-direction:column; justify-content:center; gap:8px; padding:0 16px;
  }
  .chat-bg-preview-bubble{
    max-width:72%; padding:8px 13px; border-radius:16px;
    font-size:14px; line-height:1.5;
  }
  .chat-bg-preview-bubble.ai{ align-self:flex-start; background:var(--bubble-ai-bg); color:var(--bubble-ai-fg); }
  .chat-bg-preview-bubble.human{ align-self:flex-end; background:var(--bubble-human-bg); color:var(--bubble-human-fg); }
  /* 有背景图时预览里也用真正的玻璃，「气泡」那根滑杆拖起来才看得见自己在调什么 */
  .chat-bg-preview[data-scope] .chat-bg-preview-bubble.ai{
    background:var(--glass-ai); box-shadow:var(--glass-edge), var(--glass-drop);
  }
  .chat-bg-preview[data-scope] .chat-bg-preview-bubble.human{
    background:var(--glass-human); box-shadow:var(--glass-edge), var(--glass-drop);
  }
  .chat-bg-preview-empty{
    position:absolute; inset:0; display:grid; place-items:center;
    color:var(--text-faint); font-size:14px;
  }
  /* 没选图时预览里只写一句话，不摆样例气泡（那会像是真有背景） */
  /* 预览里放什么，跟着面板这次编辑的那一张走：聊天看气泡，App 看卡片。
     空的时候两样都不摆，只写一句话（摆着会像"真有背景"）。 */
  .chat-bg-preview-cards{ position:relative; height:100%; display:flex; align-items:center; padding:0 16px; }
  /* 只管形状和字。它的"面"（玻璃那一层）写在下面通杀那条之后——类名里带 card，
     在这儿写多少都会被通杀按平。真卡片高六七十上下，样例太扁的话那圈宽柔光会
     从两边一直糊到中间，看着比真卡片白得多，所以垫到差不多的个头。 */
  .chat-bg-preview-card{
    width:100%; padding:26px 14px; border-radius:16px;
    color:var(--text); font-size:14px; line-height:1.5;
  }
  .chat-bg-preview[data-scope="chat"] .chat-bg-preview-cards{ display:none; }
  /* 猫页和 App 一样看卡片：那一页上没有"我"和"他"两侧之分。 */
  .chat-bg-preview[data-scope="shell"] .chat-bg-preview-rows,
  .chat-bg-preview[data-scope="cat"] .chat-bg-preview-rows{ display:none; }
  .chat-bg-preview[data-empty] .chat-bg-preview-rows,
  .chat-bg-preview[data-empty] .chat-bg-preview-cards{ display:none; }
  .chat-bg-preview:not([data-empty]) .chat-bg-preview-empty{ display:none; }
  /* 取色器那一行的 display:flex 会盖掉 hidden 属性自带的 display:none，
     所以 App 那张的面板里它照样显示了出来。必须显式关掉。 */
  .chat-bg-colors[hidden]{ display:none; }
  .chat-bg-picked{
    margin-top:8px; display:flex; align-items:center; gap:14px;
    padding:12px 14px; border-radius:26px; background:var(--surface-soft);
  }
  .chat-bg-picked-copy{ min-width:0; flex:1 1 auto; display:flex; flex-direction:column; gap:4px; }
  .chat-bg-picked-title{ font:650 17px/1.25 var(--font-en),var(--font-cn); }
  .chat-bg-picked-hint{ color:var(--text-soft); font-size:13.5px; line-height:1.4; }
  .chat-bg-pick{
    flex:none; min-height:38px; padding:0 15px; border:0; border-radius:19px;
    background:var(--fill-strong); color:var(--text-on-fill); font:600 14px/1 var(--font-cn),var(--font-en); cursor:pointer;
  }
  .chat-bg-pick:active{ transform:scale(.97); }
  /* 「重新取图」比「换一张」轻一档：它是补救，不是主操作。 */
  .chat-bg-pick.ghost{ background:var(--surface-mid); color:var(--text); }
  .chat-bg-pick[disabled]{ opacity:.5; }
  .chat-bg-sliders{ margin-top:12px; padding:6px 18px 14px; border-radius:26px; background:var(--surface-soft); }
  .chat-bg-slider-row{ padding:12px 0 4px; }
  .chat-bg-slider-row + .chat-bg-slider-row{ border-top:1px solid var(--line-faint); }
  .chat-bg-slider-head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; }
  .chat-bg-slider-label{ font:650 17px/1.3 var(--font-cn),var(--font-en); }
  .chat-bg-slider-value{ color:var(--text-soft); font:500 15px/1.3 var(--font-en),var(--font-cn); font-variant-numeric:tabular-nums; }
  /* 轨道左边填到当前位置：--fill 由 JS 跟着拖动改 */
  .chat-bg-range{
    -webkit-appearance:none; appearance:none;
    display:block; width:100%; height:30px; margin:6px 0 0; padding:0;
    background:transparent; cursor:pointer;
  }
  .chat-bg-range::-webkit-slider-runnable-track{
    height:5px; border-radius:99px;
    background:linear-gradient(to right,var(--slider-thumb) var(--fill,0%),var(--slider-track) var(--fill,0%));
  }
  .chat-bg-range::-webkit-slider-thumb{
    -webkit-appearance:none; appearance:none;
    width:24px; height:24px; margin-top:-9.5px; border:0; border-radius:50%;
    background:var(--knob); box-shadow:0 2px 10px var(--shade-warm-3);
  }
  .chat-bg-range::-moz-range-track{ height:5px; border-radius:99px; background:var(--slider-track); }
  .chat-bg-range::-moz-range-progress{ height:5px; border-radius:99px; background:var(--slider-thumb); }
  .chat-bg-range::-moz-range-thumb{
    width:24px; height:24px; border:0; border-radius:50%;
    background:var(--knob); box-shadow:0 2px 10px var(--shade-warm-3);
  }
  /* 两个取色器：点一下就是系统自带的调色盘。 */
  .chat-bg-colors{
    display:flex; align-items:center; justify-content:space-between; gap:12px;
    padding-top:14px; padding-bottom:10px;
  }
  .chat-bg-color-picks{ display:flex; align-items:center; gap:14px; }
  .chat-bg-color{ display:flex; align-items:center; gap:7px; cursor:pointer; }
  .chat-bg-color input[type="color"]{
    -webkit-appearance:none; appearance:none;
    width:32px; height:32px; padding:0; border:0; border-radius:50%;
    background:transparent; cursor:pointer;
  }
  .chat-bg-color input[type="color"]::-webkit-color-swatch-wrapper{ padding:0; }
  .chat-bg-color input[type="color"]::-webkit-color-swatch{
    border:1px solid var(--line); border-radius:50%;
  }
  .chat-bg-color input[type="color"]::-moz-color-swatch{
    border:1px solid var(--line); border-radius:50%;
  }
  .chat-bg-color-name{ color:var(--text-soft); font-size:13.5px; }
  .chat-bg-color-reset{
    min-height:30px; padding:0 11px; border:0; border-radius:15px; cursor:pointer;
    background:var(--surface-soft); color:var(--text-soft); font:500 13px/1 var(--font-cn),var(--font-en);
  }
  .chat-bg-color-reset:active{ transform:scale(.96); }
  .chat-bg-sheet-actions{ margin-top:14px; display:flex; gap:10px; }
  .chat-bg-sheet-btn{
    flex:1 1 0; min-height:48px; border:0; border-radius:24px; cursor:pointer;
    background:var(--surface-soft); color:var(--text); font:600 16px/1 var(--font-cn),var(--font-en);
  }
  .chat-bg-sheet-btn.primary{ background:var(--fill-strong); color:var(--text-on-fill); }
  .chat-bg-sheet-btn:active{ transform:scale(.98); }
  .chat-bg-sheet-btn[disabled]{ opacity:.45; cursor:default; }
  .chat-bg-sheet-status{ min-height:18px; padding:9px 6px 0; color:var(--text-soft); text-align:center; font-size:13.5px; }

  /* ── 外观页（2026-09-26）：和背景面板同一个壳。它的遮罩点了就关（选了就当场存，没有要撤回的），
     所以带一层淡淡的压暗，看得出点空白处会走。 ── */
  .appearance-sheet-wrap{ z-index:365; }
  .appearance-scrim{ background:var(--scrim); opacity:0; transition:opacity .42s ease; cursor:pointer; }
  .appearance-sheet-wrap.open .appearance-scrim{ opacity:1; }
  .appearance-modes{
    display:grid; grid-template-columns:repeat(3,1fr); gap:6px; margin-top:6px; padding:5px;
    border-radius:20px; background:var(--surface-soft);
  }
  .appearance-mode{
    min-height:40px; border:0; border-radius:15px; cursor:pointer; background:transparent; color:var(--text-soft);
    display:flex; align-items:center; justify-content:center; gap:6px; font:500 15px/1 var(--font-cn),var(--font-en);
  }
  .appearance-mode .ph{ font-size:17px; }
  .appearance-mode.is-on{ background:var(--surface); color:var(--text); box-shadow:0 2px 8px var(--shade-warm-1); }
  .appearance-hint{ margin:10px 4px 2px; color:var(--text-faint); font-size:13px; line-height:1.5; }
  .appearance-presets{ display:grid; grid-template-columns:repeat(2,1fr); gap:12px; margin-top:12px; }
  .appearance-card{ min-width:0; }
  .appearance-thumb{
    position:relative; height:132px; border-radius:22px; overflow:hidden;
    border:1px solid var(--line-faint); display:flex; flex-direction:column; justify-content:center; gap:8px; padding:0 12px;
  }
  .appearance-card.is-active .appearance-thumb{ outline:2px solid var(--text); outline-offset:2px; }
  .appearance-thumb-image{ position:absolute; inset:0; background-size:cover; background-position:center; }
  .appearance-thumb-bubble{ position:relative; display:block; height:22px; border-radius:11px; }
  .appearance-thumb-bubble.ai{ width:62%; align-self:flex-start; }
  .appearance-thumb-bubble.human{ width:48%; align-self:flex-end; }
  .appearance-card-name{
    margin:10px 4px 4px; display:flex; align-items:center; gap:8px; font:600 15px/1.3 var(--font-cn),var(--font-en);
  }
  .appearance-card-tag{
    padding:3px 8px; border-radius:999px; background:var(--fill-strong); color:var(--text-on-fill);
    font:500 11px/1.2 var(--font-cn),var(--font-en);
  }
  .appearance-card-rows{ display:flex; flex-direction:column; gap:2px; border-radius:16px; overflow:hidden; background:var(--surface); }
  .appearance-card-row{
    display:grid; grid-template-columns:1fr auto; grid-template-rows:auto auto; align-items:center; column-gap:6px;
    padding:9px 10px 9px 12px; border:0; background:transparent; color:var(--text); text-align:left; cursor:pointer;
    font:500 13.5px/1.3 var(--font-cn),var(--font-en);
  }
  .appearance-card-row + .appearance-card-row{ border-top:1px solid var(--line-faint); }
  .appearance-card-row .ph{ grid-row:1 / span 2; grid-column:2; color:var(--text-faint); font-size:14px; }
  .appearance-card-value{ grid-column:1; color:var(--text-faint); font-size:11.5px; }
  .appearance-card-row:active{ background:var(--row-press); }
  /* 一种模式下好几套（2026-09-28）：浅色一组、深色一组，每组末尾一张「＋ 新建一套」。 */
  .appearance-group-title{ grid-column:1 / -1; margin:10px 4px -2px; color:var(--text-soft); font:600 13px/1.3 var(--font-cn),var(--font-en); }
  button.appearance-thumb{ width:100%; font:inherit; cursor:pointer; text-align:left; background-clip:padding-box; }
  .appearance-card-title{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .appearance-card-tools{ display:flex; gap:14px; margin:8px 6px 0; }
  .appearance-card-tools button{ padding:0; border:0; background:transparent; color:var(--text-faint); font:500 12.5px/1.3 var(--font-cn),var(--font-en); cursor:pointer; }
  .appearance-card-tools button.is-danger{ color:var(--danger); }
  .appearance-add{
    min-height:132px; border:1px dashed var(--line-strong); border-radius:22px; background:transparent; color:var(--text);
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; padding:12px; cursor:pointer;
    font:600 14px/1.3 var(--font-cn),var(--font-en); text-align:center; align-self:start;
  }
  .appearance-add .ph{ font-size:20px; }
  .appearance-add small{ color:var(--text-faint); font:400 11.5px/1.4 var(--font-cn),var(--font-en); }

  /* ── 连接方式（2026-09-27）：和外观页同一个壳。一行一条线路：左边选中的圆点、名字和那一小行说明，
     右边「测试」「编辑」；测试结果在这一行下面单独一行。 ── */
  .route-list{ display:flex; flex-direction:column; gap:2px; margin-top:10px; border-radius:18px; overflow:hidden; background:var(--surface); }
  .route-item{ padding:11px 12px; }
  .route-item + .route-item{ border-top:1px solid var(--line-faint); }
  .route-item-main{ display:grid; grid-template-columns:minmax(0,1fr) auto; align-items:center; column-gap:10px; }
  .route-choose{
    min-width:0; display:grid; grid-template-columns:22px minmax(0,1fr); align-items:center; column-gap:10px;
    padding:0; border:0; background:transparent; color:inherit; text-align:left; cursor:pointer; font:inherit;
  }
  .route-dot{ width:18px; height:18px; border-radius:50%; border:1.5px solid var(--line-strong); }
  .route-item.is-active .route-dot{ border:5.5px solid var(--text); }
  .route-copy{ min-width:0; display:flex; flex-direction:column; gap:3px; }
  .route-name{ font:600 15px/1.3 var(--font-cn),var(--font-en); color:var(--text); }
  .route-meta{ color:var(--text-faint); font-size:12px; line-height:1.35; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .route-buttons{ display:flex; gap:6px; }
  .route-btn{
    min-height:32px; padding:0 11px; border:1px solid var(--line); border-radius:999px; background:transparent;
    color:var(--text); cursor:pointer; font:500 13px/1 var(--font-cn),var(--font-en);
  }
  .route-btn[disabled]{ opacity:.45; cursor:default; }
  .route-result{ margin:8px 0 0 32px; color:var(--text-soft); font-size:12.5px; line-height:1.5; word-break:break-word; }
  .route-result.is-bad{ color:var(--danger); }
  .route-add{
    width:100%; min-height:46px; margin-top:10px; border:1px dashed var(--line-strong); border-radius:16px;
    background:transparent; color:var(--text); cursor:pointer; display:flex; align-items:center; justify-content:center; gap:6px;
    font:500 14.5px/1 var(--font-cn),var(--font-en);
  }
  .route-form{ margin-top:12px; padding:14px; border-radius:18px; background:var(--surface); display:flex; flex-direction:column; gap:10px; }
  .route-form.hidden,.route-add.hidden{ display:none; }
  .route-form-title{ font:600 15px/1.3 var(--font-cn),var(--font-en); }
  .route-field{ display:flex; flex-direction:column; gap:5px; color:var(--text-soft); font-size:12.5px; }
  .route-field input{
    min-height:42px; padding:0 12px; border:1px solid var(--line); border-radius:12px; background:var(--bg);
    color:var(--text); font:16px/1.3 var(--font-cn),var(--font-en);
  }
  .route-field input:focus{ outline:none; border-color:var(--line-bold); }
  .route-form-note{ margin:0; color:var(--text-faint); font-size:12px; line-height:1.5; }
  .route-form-actions{ display:flex; gap:8px; justify-content:flex-end; }
  .route-form-actions .route-delete{ margin-right:auto; color:var(--danger); }
  /* 试聊（2026-09-28）：和「连接方式」同一个壳，叠在它上面。中间一段能滚的对话，下面输入框、结束 / 就用它。 */
  .sandbox-sheet-wrap{ z-index:370; }
  .sandbox-sheet{ display:flex; flex-direction:column; height:min(86vh,700px); overflow:hidden; }
  .sandbox-list{ flex:1; min-height:120px; overflow:auto; margin-top:10px; padding:12px 10px; border-radius:18px; background:var(--surface); display:flex; flex-direction:column; gap:10px; -webkit-overflow-scrolling:touch; }
  .sandbox-row{ display:flex; flex-direction:column; gap:5px; max-width:86%; }
  .sandbox-row.is-human{ align-self:flex-end; align-items:flex-end; }
  .sandbox-row.is-ai{ align-self:flex-start; align-items:flex-start; }
  .sandbox-bubble{ padding:9px 12px; border-radius:16px; background:var(--glass-solid); color:var(--text); font-size:14.5px; line-height:1.55; word-break:break-word; }
  .sandbox-row.is-human .sandbox-bubble{ background:var(--fill-strong); color:var(--text-on-fill); }
  .sandbox-row.is-ai .sandbox-bubble{ background:var(--surface-strong); }
  .sandbox-bubble p{ margin:0; }
  .sandbox-bubble p + p{ margin-top:6px; }
  .sandbox-failed{ color:var(--danger); font-size:11.5px; }
  .sandbox-thought{ color:var(--text-faint); font-size:12.5px; }
  .sandbox-thought summary{ cursor:pointer; list-style:none; }
  .sandbox-thought summary::before{ content:"✦ "; }
  .sandbox-thought-body{ margin-top:4px; padding-left:10px; border-left:2px solid var(--line); color:var(--text-soft); line-height:1.55; }
  .sandbox-status{ min-height:18px; margin:8px 4px 0; color:var(--text-soft); font-size:12.5px; line-height:1.45; }
  .sandbox-compose{ margin-top:8px; display:flex; align-items:flex-end; gap:8px; }
  .sandbox-compose textarea{
    flex:1; min-height:42px; max-height:120px; padding:10px 12px; border:1px solid var(--line); border-radius:18px; resize:none;
    background:var(--bg); color:var(--text); font:16px/1.4 var(--font-cn),var(--font-en);
  }
  .sandbox-compose textarea:focus{ outline:none; border-color:var(--line-bold); }
  .sandbox-send{ width:42px; height:42px; flex:none; border:0; border-radius:50%; background:var(--fill-strong); color:var(--text-on-fill); display:grid; place-items:center; font-size:18px; cursor:pointer; }
  .sandbox-send[disabled]{ opacity:.4; cursor:default; }
  /* 思考标题那一块（2026-09-28）：一排小药丸，选中的那颗涂黑。 */
  .route-title-block{ margin-top:12px; padding:14px; border-radius:18px; background:var(--surface); display:flex; flex-direction:column; gap:8px; }
  .route-title-chips{ display:flex; flex-wrap:wrap; gap:6px; margin-top:2px; }
  .route-title-chips .route-btn[aria-pressed="true"]{ background:var(--fill-strong); border-color:var(--fill-strong); color:var(--text-on-fill); }

  .instructions-editor{
    position:fixed; inset:0; z-index:380; display:flex; align-items:flex-end; justify-content:center;
  }
  .instructions-editor.hidden{ display:none; }
  .instructions-editor-scrim{
    position:absolute; inset:0; border:0; background:var(--scrim); opacity:0; transition:opacity .42s ease;
  }
  .instructions-editor-sheet{
    position:relative; width:min(100%,620px); height:min(86dvh,820px); min-height:420px;
    padding:10px 18px calc(16px + env(safe-area-inset-bottom)); border-radius:32px 32px 0 0;
    background:var(--bg); color:var(--text); box-shadow:0 -16px 48px var(--shade-warm-2);
    display:flex; flex-direction:column; opacity:.98; transform:translateY(100%);
    transition:transform .42s cubic-bezier(.22,.8,.24,1),opacity .42s ease;
  }
  .instructions-editor.open .instructions-editor-scrim{ opacity:1; }
  .instructions-editor.open .instructions-editor-sheet{ opacity:1; transform:translateY(0); }
  .instructions-editor-handle{ width:42px; height:5px; margin:0 auto 8px; border-radius:99px; background:var(--surface-strong); }
  .instructions-editor-head{ position:relative; min-height:58px; display:flex; align-items:center; justify-content:center; }
  .instructions-editor-title{ font:650 20px/1.2 var(--font-en),var(--font-cn); }
  .instructions-editor-close,.instructions-editor-save{
    position:absolute; width:46px; height:46px; border:0; border-radius:50%; cursor:pointer;
    display:grid; place-items:center; box-shadow:0 7px 22px var(--shade-warm-1);
  }
  .instructions-editor-close{ left:0; background:var(--surface); color:var(--text); font:400 34px/1 var(--font-en),var(--font-cn); }
  /* 「下载源码」搬到放大这一层了：缩略图上它占了快五分之一、直接压在画上，
     而想拿源码的时候人本来就会先点开看。只有 SVG 才有源码可拿，别的图这颗是藏着的。 */
  .image-viewer-source{
    position:absolute; right:0; width:46px; height:46px; border:0; border-radius:50%;
    display:grid; place-items:center; cursor:pointer;
    background:var(--surface); color:var(--text); box-shadow:0 7px 22px var(--shade-warm-1);
  }
  .image-viewer-source i{ font-size:21px; }
  .image-viewer-source.hidden{ display:none; }
  .instructions-editor-save{ right:0; background:var(--fill-strong); color:var(--text-on-fill); }
  .instructions-editor-save:disabled{ background:var(--surface-mid); cursor:default; box-shadow:none; }
  .instructions-editor-save svg{ width:23px; height:23px; }
  .instructions-editor-text{
    flex:1 1 auto; min-height:0; width:100%; resize:none; margin-top:8px; padding:18px;
    border:1px solid var(--line-faint); border-radius:24px; outline:none;
    background:var(--surface-soft); color:var(--text); font:400 16px/1.65 var(--font-cn),var(--font-en);
    caret-color:var(--text); -webkit-overflow-scrolling:touch;
  }
  .instructions-editor-text:focus{ border-color:var(--line); }
  /* 只有「轮次注入」用得上这一条：每几轮挂一次。滑块和背景那几根是同一套。 */
  .instructions-editor-rhythm{ flex:0 0 auto; margin-top:8px; padding:8px 18px 12px; border-radius:26px; background:var(--surface-soft); }
  /* 提示词自己带的那几颗开关（日记的"上一篇"、Compact 的"原文"和"思考链"）。 */
  .instructions-editor-toggle{
    flex:0 0 auto; margin-top:8px; padding:13px 18px; border-radius:26px; background:var(--surface-soft);
    display:flex; align-items:center; gap:13px;
  }
  .instructions-editor-toggle .tool-copy strong{ color:var(--text); font:650 15px/1.3 var(--font-cn),var(--font-en); }
  .instructions-editor-toggle .tool-copy span{ color:var(--text-soft); font-size:12px; }
  /* 上面那颗关着时，跟着它的这颗现在什么也管不着——淡一层，说明里也写清楚。 */
  .instructions-editor-toggle.blocked{ opacity:.45; }
  .instructions-editor-status{ min-height:22px; padding:9px 6px 0; color:var(--text-soft); text-align:center; font-size:12px; }
  .image-viewer-sheet{ height:min(86dvh,820px); }
  .image-viewer-stage{
    flex:1 1 auto; min-height:0; margin-top:8px; overflow:hidden; display:grid; place-items:center;
    touch-action:none; overscroll-behavior:contain;
  }
  .image-viewer-image{
    display:block; max-width:100%; max-height:100%; object-fit:contain;
    transform:translate3d(0,0,0) scale(1); transform-origin:center; will-change:transform;
    user-select:none; -webkit-user-select:none; -webkit-user-drag:none;
  }
  /* 他做的网页（2026-09-23）。和图片查看器同一块底板，只是几乎占满整屏、左右不留边：
     网页是照手机宽度排的，两边各让 18px，就等于让它在一台更窄的手机上跑。
     宽度要写成两个类：后面那段统一改底板的规则（width:min(calc(100% - 16px),620px)）
     和一个类名一样重，又排在后面，只写一个类会被它盖掉。 */
  .instructions-editor-sheet.page-viewer-sheet{
    width:min(100%,820px); height:calc(100dvh - env(safe-area-inset-top) - 10px); min-height:0;
    padding:10px 0 env(safe-area-inset-bottom);
  }
  .page-viewer-head{ padding:0 14px; }
  .page-viewer-head .instructions-editor-close{ left:14px; }
  .page-viewer-head .image-viewer-source{ right:14px; }
  .page-viewer-title{ max-width:calc(100% - 128px); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* 框底铺白：网页没写背景色时默认就是白底，框要是透明的，米色底板会透上来。 */
  .page-viewer-stage{ position:relative; flex:1 1 auto; min-height:0; margin-top:8px; background:var(--surface); }
  .page-viewer-frame{ display:block; width:100%; height:100%; border:0; background:var(--surface); }
  .page-viewer-status{
    position:absolute; inset:0; margin:0; padding:28px; border:0; border-radius:0;
    display:grid; place-items:center; background:var(--surface); color:var(--text-soft); text-align:center;
    font:400 15px/1.7 var(--font-cn),var(--font-en); -webkit-tap-highlight-color:transparent;
  }
  /* 上面写了 display:grid，hidden 属性就不管用了——猫页的「看更早的」踩过同一个坑。 */
  .page-viewer-status[hidden]{ display:none; }
  .page-viewer-status:disabled{ cursor:default; color:var(--text-soft); opacity:1; }
  .mcp-manager{ position:fixed; inset:0; z-index:390; display:flex; align-items:flex-end; justify-content:center; }
  .mcp-manager.hidden{ display:none; }
  .mcp-manager-scrim{ position:absolute; inset:0; border:0; background:var(--scrim); opacity:0; transition:opacity .42s ease; }
  .mcp-manager-sheet{
    position:relative; width:min(100%,620px); height:min(90dvh,860px); padding:10px 18px calc(18px + env(safe-area-inset-bottom));
    border-radius:32px 32px 0 0; background:var(--bg); color:var(--text); box-shadow:0 -16px 48px var(--shade-warm-2);
    display:flex; flex-direction:column; transform:translateY(100%); transition:transform .42s cubic-bezier(.22,.8,.24,1);
  }
  .mcp-manager.open .mcp-manager-scrim{ opacity:1; }
  .mcp-manager.open .mcp-manager-sheet{ transform:translateY(0); }
  .mcp-manager-head{ position:relative; min-height:58px; display:flex; align-items:center; justify-content:center; }
  .mcp-manager-title{ font:650 20px/1.2 var(--font-en),var(--font-cn); }
  .mcp-manager-close{ position:absolute; left:0; width:46px; height:46px; border:0; border-radius:50%; background:var(--surface); color:var(--text); font:400 34px/1 var(--font-en); cursor:pointer; box-shadow:0 7px 22px var(--shade-warm-1); }
  .mcp-manager-refresh{ position:absolute; right:0; border:0; background:transparent; color:var(--text-soft); font:600 14px/1 var(--font-cn); cursor:pointer; }
  .mcp-manager-scroll{ overflow:auto; display:grid; gap:14px; padding:8px 0; }
  .mcp-card{ padding:17px; border:1px solid var(--line-faint); border-radius:22px; background:var(--surface-soft); }
  .mcp-card-head{ display:flex; align-items:center; justify-content:space-between; gap:12px; }
  .mcp-card-title{ font:650 17px/1.3 var(--font-en),var(--font-cn); }
  .mcp-card-copy,.mcp-status{ margin:6px 0 0; color:var(--text-soft); font-size:13px; line-height:1.55; }
  .mcp-fields{ display:grid; gap:9px; margin-top:14px; }
  .mcp-input{ width:100%; min-height:46px; padding:11px 14px; border:1px solid var(--line-faint); border-radius:14px; outline:none; background:var(--surface); color:var(--text); font:400 15px/1.4 var(--font-en),var(--font-cn); }
  .mcp-input:focus{ border-color:var(--line-strong); }
  .mcp-actions{ display:flex; gap:9px; margin-top:11px; }
  .mcp-primary,.mcp-secondary{ min-height:42px; padding:0 16px; border:0; border-radius:21px; font:600 14px/1 var(--font-cn); cursor:pointer; }
  .mcp-primary{ background:var(--fill-strong); color:var(--text-on-fill); }
  a.mcp-primary{ display:inline-flex; align-items:center; justify-content:center; text-decoration:none; }
  .mcp-secondary{ background:var(--surface); color:var(--text-soft); }
  .mcp-primary:disabled,.mcp-secondary:disabled{ opacity:.5; cursor:default; }
  .mcp-readonly{ display:flex; align-items:center; gap:9px; margin-top:12px; color:var(--text-soft); font-size:14px; }
  .mcp-server-list{ display:grid; gap:8px; margin-top:12px; }
  .mcp-server{ display:flex; align-items:center; gap:10px; padding:12px; border-radius:15px; background:var(--surface); }
  .mcp-server-copy{ min-width:0; flex:1; display:grid; gap:2px; }
  .mcp-server-copy strong{ font-size:14px; overflow-wrap:anywhere; }
  .mcp-server-copy span{ color:var(--text-soft); font-size:11.5px; overflow-wrap:anywhere; }
  .mcp-server-copy .mcp-server-health{ margin-top:4px; font-weight:650; }
  .mcp-server-health[data-state="connected"]{ color:var(--success); }
  .mcp-server-health[data-state="error"],
  .mcp-server-health[data-state="missing"]{ color:var(--danger); }
  .mcp-server-health[data-state="pending"],
  .mcp-server-health[data-state="auth_required"]{ color:var(--warning); }
  .mcp-server-actions{ flex:none; display:flex; align-items:center; gap:5px; }
  .mcp-edit,
  .mcp-remove,
  .mcp-test{ flex:none; border:0; background:transparent; color:var(--danger); font:600 13px/1 var(--font-cn); cursor:pointer; }
  .mcp-edit{ color:var(--text-soft); }
  .mcp-test{ color:var(--success); }
  .mcp-oauth{ flex:none; border:0; background:transparent; color:var(--text-soft); font:600 13px/1 var(--font-cn); cursor:pointer; }
  .mcp-oauth-panel{ padding:17px; border:1px solid var(--line-faint); border-radius:22px; background:var(--surface-soft); }
  .mcp-oauth-panel.hidden{ display:none; }
  .mcp-oauth-link{ display:flex; align-items:center; justify-content:center; min-height:44px; margin-top:12px; border-radius:22px; background:#5E5E59; color:var(--text-on-fill); text-decoration:none; font:600 14px/1 var(--font-cn); }
  .mcp-empty{ color:var(--text-soft); font-size:13px; padding:4px 0; }
  @media (prefers-reduced-motion:reduce){
    .runtime-picker-scrim,.runtime-picker-sheet,.instructions-editor-scrim,.instructions-editor-sheet,.mcp-manager-scrim,.mcp-manager-sheet{ transition:none; }
  }

  .session-pop{ right:calc(var(--side-pad) + 42px); width:min(82vw,300px); background:var(--glass-solid); color:var(--text); }
  .session-title{ color:var(--text-soft); }
  .session-list{ gap:3px; }
  .session-item{ padding:10px 11px; border-radius:13px; color:var(--text); }
  .session-item.active{ background:var(--surface-soft); }
  .session-name{ font-size:15px; line-height:1.35; }
  .session-meta{ display:none; }
  .session-item.archive .session-meta{ display:block; }

  .home-shell,.login{ background-color:var(--bg); background-image:none; color:var(--text); }
  .home-dock{ border-top-color:var(--line-faint); background:var(--bg); }
  .home-dock-item{ color:var(--text-faint); font-family:var(--font-en),var(--font-cn); }
  .home-dock-item[aria-current="page"]{ color:var(--text); }
  .settings-card,.action-row{ border-color:var(--line-faint); }

  .profile-scroll{ gap:14px; }
  .settings-disclosure,.settings-menu-card{ padding:0 !important; overflow:hidden; }
  .settings-disclosure > .settings-menu-row{ border-bottom:0; }
  .settings-menu-row{
    width:100%; min-height:58px; padding:0 16px; border:0;
    border-bottom:1px solid var(--line-faint); background:transparent;
    color:var(--text); display:flex; align-items:center; gap:12px;
    text-align:left; font:500 16px/1.35 var(--font-cn),var(--font-en);
  }
  button.settings-menu-row{ cursor:pointer; }
  .settings-menu-card > .settings-menu-row:last-child{ border-bottom:0; }
  .settings-menu-static{ cursor:default; }
  .settings-menu-meta{ margin-left:auto; height:24px; display:flex; align-items:center; gap:8px; color:var(--text-soft); }
  .settings-menu-meta > span:first-child{ display:flex; align-items:center; height:24px; font:400 16px/24px var(--font-en); }
  .settings-chevron{ flex:none; width:18px; height:24px; display:grid; place-items:center; color:var(--text-soft); font-size:18px; line-height:1; transition:transform .42s ease; }
  .settings-menu-row > .settings-chevron{ margin-left:auto; }
  .settings-menu-row[aria-expanded="true"] .settings-chevron{ transform:rotate(90deg); }
  .settings-detail{ padding:4px 16px 16px; border:0 !important; border-radius:0 !important; background:transparent !important; box-shadow:none !important; }
  .stackchan-controls{ display:grid; gap:0; padding-top:10px; }
  .stackchan-status{
    min-height:44px; margin-bottom:4px; padding:11px 14px; border-radius:14px;
    background:var(--bubble-ai-bg); color:var(--text-soft);
    display:flex; align-items:center; gap:9px; font-size:14px; line-height:1.45;
  }
  .stackchan-status::before{ content:""; width:8px; height:8px; flex:none; border-radius:50%; background:var(--text-disabled); }
  .stackchan-status[data-state="ready"]::before{ background:var(--success); }
  .stackchan-status[data-state="pending"]::before{ background:var(--warning); }
  .stackchan-status[data-state="offline"]::before{ background:var(--danger); }
  .stackchan-control-group{ display:grid; gap:10px; padding:15px 0; border-bottom:1px solid var(--line-faint); }
  .stackchan-control-group:last-child{ padding-bottom:0; border-bottom:0; }
  .stackchan-control-label{ color:var(--text); font:500 15px/1.35 var(--font-cn),var(--font-en); }
  .stackchan-control-note{ margin:-3px 0 0; color:var(--text-faint); font-size:12px; line-height:1.5; }
  .stackchan-control-row{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
  .stackchan-control-row select{
    flex:1; min-width:120px; height:44px; padding:0 13px; border:0; border-radius:14px;
    outline:none; background:var(--bubble-ai-bg); color:var(--text);
    font:400 15px/1 var(--font-cn),var(--font-en);
  }
  .stackchan-control-row input[type="range"]{ flex:1; min-width:120px; accent-color:var(--accent); }
  .stackchan-control-btn{
    min-height:42px; padding:0 15px; border:0; border-radius:999px;
    background:var(--bubble-ai-bg); color:var(--text);
    font:500 14px/1.2 var(--font-cn),var(--font-en); cursor:pointer;
    transition:transform .12s ease,background .18s ease,opacity .18s ease;
  }
  .stackchan-control-btn.primary{ background:var(--accent); color:var(--accent-fg); }
  .stackchan-control-btn:active{ transform:scale(.96); }
  .stackchan-control-btn:disabled{ opacity:.45; cursor:default; transform:none; }
  .stackchan-move-row{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); }
  .stackchan-move-row .stackchan-control-btn{ width:100%; padding:0 8px; }
  .stackchan-move-row .stackchan-control-btn:nth-child(1){ grid-column:2; grid-row:1; }
  .stackchan-move-row .stackchan-control-btn:nth-child(2){ grid-column:1; grid-row:2; }
  .stackchan-move-row .stackchan-control-btn:nth-child(3){ grid-column:2; grid-row:2; }
  .stackchan-move-row .stackchan-control-btn:nth-child(4){ grid-column:3; grid-row:2; }
  .stackchan-move-row .stackchan-control-btn:nth-child(5){ grid-column:2; grid-row:3; }
  .stackchan-color{ width:44px; height:42px; padding:3px; border:0; border-radius:50%; background:var(--bubble-ai-bg); }
  .settings-inline-segmented{ margin-left:auto; flex:none; }

  @media (max-width:520px){
    :root{ --side-pad:16px; --header-h:72px; --composer-h:110px; }
    body{ font-size:20px; line-height:1.58; -webkit-text-size-adjust:100%; }
    .header-actions{ right:16px; top:calc(env(safe-area-inset-top) + 2px); gap:2px; height:44px; }
    .header-left{ left:16px; top:calc(env(safe-area-inset-top) + 2px); }
    .topbtn{ width:40px; height:40px; }
    /* 18 → 24px（2026-09-24）：头像撤到气泡上面、气泡放宽之后，头像和气泡都贴着屏幕边，她要"远一些些"。 */
    .scroll{ padding-left:24px; padding-right:24px; }
    /* 换人说话时的间距 25 → 16px（2026-09-24，她怀疑"我的话和他的话之间间距太大"）。
       现在是三档：同一条消息里的气泡 4px < 同一个人连着的几条 10px < 换人 16px。 */
    .row{ margin-top:16px; }
    .row.ai{ padding-right:18px; }
    .bubble{ max-width:84vw; font-size:17px; line-height:1.62; padding:10px 15px; }
    .row.ai .bubble{ max-width:82vw; padding:9px 15px; }
    .row.human .bubble{ max-width:82vw; padding:9px 15px; }
    .row.think,.row.think.think-open{ padding:0; margin-top:28px; }
    .think-block,.think-block.open{ width:100%; max-width:100%; }
    .day{ font-size:14px; line-height:1.5; }
    .poke-line{ font-size:15px; }        /* 手机上 11px 太小了,跟日期分隔线看齐 */
    .think-caption{ font-size:20px; }
    .think-caption-text{ font-size:17.5px; line-height:1.52; }
    .stackchan-status{ font-size:15px; }
    .stackchan-control-label{ font-size:16px; }
    .stackchan-control-note{ font-size:13px; }
    .stackchan-control-btn{ min-height:44px; font-size:15px; }
    .think-body{ margin-top:12px; }
    .think-text{ width:100%; padding-left:23px; font-size:18px; line-height:1.68; }
    .act-label{ font-size:17px; line-height:1.55; }
    .tool-event-card > summary{ min-height:42px; font-size:17px; }
    .tool-event-field label{ font-size:15px; }
    .tool-event-field pre{ font-size:15px; }
    .act-detail{ font-size:16px; line-height:1.65; }
    .att-file-name{ font-size:18px; }
    .att-file-size{ font-size:16px; }
    .reaction{ font-size:19px; }
    .meta .fail,.meta .delivery{ font-size:16px; }
    .newmsg-pill{ width:36px; height:36px; }   /* 原来 44，她说改小一点 */
    .session-name{ font-size:16px; line-height:1.4; }
    .composer{ left:12px; right:12px; padding:9px; }
    .pending-attachments{ left:9px; max-width:calc(100% - 18px); }
    .composer .field{ min-height:82px; padding:0; }
    .composer textarea{ font-size:20px; line-height:1.48; }
    .runtime-picker-trigger{ font-size:19px; padding:0 14px; }
    .floatbtn,.emojibtn{ width:40px; height:40px; }
    .floatbtn.send{ width:44px; height:44px; }
    .runtime-picker-sheet{ max-height:84vh; padding-left:14px; padding-right:14px; border-radius:30px 30px 0 0; }
    .runtime-picker-title{ font-size:23px; }
    .runtime-model-list{ padding-left:16px; padding-right:16px; }
    .runtime-model-label{ font-size:21px; }
    .runtime-effort-label{ font-size:20px; }
    .runtime-effort-hint,.runtime-picker-status{ font-size:16px; }
    .runtime-effort-option{ font-size:15px; }
  }

  /* 头像：每一段话只在最上面放一个（2026-09-23 起，照项目主人画的那张图）。
     从上往下是 头像 → 气泡 → 时间；头像和气泡一样靠边对齐——他那边靠左，你这边靠右。
     以前是每个气泡旁边各挂一个、还给头像空出一竖条：一段话拆成三个气泡，就是三个
     一模一样的头像摞在那儿。现在那一竖条撤了，气泡直接从边上开始。
     "一段"就是成组那条规矩：同一个人、前后隔不到 5 分钟（GROUP_GAP）。隔久了、中间
     夹了灰线或日期，下一条重新带头像——判断在 makeMessage 里，看的是 rowData.grouped。
     头像必须是真元素：弹弹乐要抓住它、藏起来、再让它冒回来（很早以前是 ::before 画的
     装饰，抓不到）。别用 transform 摆它的位置，transform 要留给冒回来和入场的动画。 */
  .row.ai,.row.human{ position:relative; }
  .row.ai .message-bubbles,.row.human .message-bubbles{ width:fit-content; max-width:min(72vw,560px); }
  .row.ai .bubble,.row.human .bubble{ width:fit-content; box-sizing:border-box; }
  .row.ai .bubble.attachment-bubble,.row.human .bubble.attachment-bubble{ width:auto; }
  .message-stack>.message-avatar{
    flex:none; display:block; width:var(--avatar-size); height:var(--avatar-size); border-radius:50%;
    background-color:transparent; background-position:center; background-size:cover; background-repeat:no-repeat;
    box-shadow:none; touch-action:none;
    /* 头像和第一个气泡之间：.message-stack 的 gap 是 6px（它也管气泡和时间之间），头像这里吃掉
       1px，剩 5px。2px 试过，她说"远一点点"。改了记得改 main.js 的 AVATAR_LINE_HEIGHT。 */
    margin-bottom:-1px;
  }
  /* 他那段话的思考链星星挂在头像右边（2026-09-24，她要的），和头像竖着居中。只有每段第一条
     有这一格（main.js 的 headThoughts）；没头像的那几条星星照旧在气泡右上角。浮在外面，
     不占那一摞的高度，头像那一行不会被它撑高。 */
  .message-stack{ position:relative; }
  .message-stack>.message-head-thoughts{
    position:absolute; top:calc((var(--avatar-size) - 22px) / 2);
    left:calc(var(--avatar-size) + 6px); display:flex; gap:2px;
  }
  .message-head-thoughts:empty{ display:none; }
  /* 他的思考（2026-09-24，照 Claude.ai）：气泡上面单独一行，星星 + 他想的第一句 + ›，两种排版都这样。
     旁白不是说话，字小一号、颜色淡。**不垫胶囊**，直接写在背景上（她要的）——铺了背景图时只把
     字压实一点（见下面 data-chat-bg 那条）。想了几次就几行。 */
  .thought-lines{ display:flex; flex-direction:column; align-items:flex-start; gap:4px; max-width:100%; margin-bottom:4px; }
  .thought-lines:empty{ display:none; }
  .thought-line{
    display:inline-flex; align-items:center; gap:7px; max-width:100%; min-height:26px; padding:2px 2px;
    border:0; background:transparent; color:var(--text-faint); cursor:pointer; text-align:left;
    font:400 clamp(12.5px,1.35vw,14px)/1.5 var(--font-cn),var(--font-en);
  }
  .thought-line .ph{ flex:none; font-size:14px; }
  .thought-line-text{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .thought-line.streaming .thought-line-text{ animation:thoughtLinePulse 1.4s ease-in-out infinite; }
  @keyframes thoughtLinePulse{ 0%,100%{ opacity:.5; } 50%{ opacity:1; } }
  html[data-chat-bg="on"] .app .thought-line{ color:var(--text-soft); }
  .message-head-thoughts .thought-entry{ margin-top:0; }
  .row.ai .message-stack>.message-avatar{ background-color:var(--avatar-ai-color); background-image:var(--avatar-ai); }
  /* 她那边的头像往上提一点点（2026-09-26 她要的）：他那边头像底下还有一行思考，显得松；她这边直接贴着
     气泡，显得挤。用 top 挪而不是加 margin——只挪画的位置、不改这一行的高度，估高（AVATAR_LINE_HEIGHT）
     不用跟着改；也不用 transform，那是留给入场和弹弹乐冒回来的动画的。 */
  .row.human .message-stack>.message-avatar{ position:relative; top:-3px; background-color:var(--avatar-human-color); background-image:var(--avatar-human); }

  /* ── 这里以前有一条"通杀"，现在整条没了 ──
     这条以前是三个通配选择器
     [class*="card"] / [class*="sheet"] / [class*="panel"]：按**类名里带没带这三个
     字母**决定长相，一律刷成不透明的 #EFEFED、去掉边和投影。它是"禁止灰色渐变兜底"
     那条老规矩的执行部分；规矩早作废了，它还留着，而且一直在误伤——都是同一个原因，
     名字里碰巧有那三个字母：
       .chat-bg-sheet-wrap    整屏的容器，被刷成不透明灰盖住全屏。背景面板一开，
                              身后的 Settings 和底图就整个不见了
       .chat-bg-preview-cards 装样例卡的那层 height:100%，把面板里的预览整块盖住
       .terminal-panel        终端本来是 #050607，被刷成浅灰，浅绿的字直接看不见
       .music-card 一家       整张卡和里面每个 -title / -info / -disc 都被垫了灰
       .ph-cards-three        这是个**图标**，图标背后也给垫了一块灰
     还有 .settings-card / .mcp-card / .grow-result-card / .tool-event-card / 面板
     底下那两个按钮……各自写好的底色、边、投影全被压死。

     现在按名字点名，不再按字符串猜。逐个查过一遍，没有一个元素真的靠它兜底：
     .profile-panel 和 .rolling-panel 里面各有一层 .profile-page / .rolling-page
     铺满并自带底色；.session-pop 在后面有一条真的白底（它开头那个 --panel-bg
     从来没定义过，顺手换成实色了）。

     点名的那份名单后来也清空了。名单上每一个都自己写着底色，只是被压死了，
     摘掉就是各自本来的样子：
       .pending-att      待发的附件。它有 .image / .uploading / .failed 三个变体。
                         （.failed 当初是一圈红边，被 `border:0 !important` 连着抹掉过；
                          现在改成压一层灰遮罩加重试图标，不再靠边框说话，
                          所以这一条从"会被压死的功能"变成了只是好看而已）
       .newmsg-pill      「回到底部」，本来是白药丸 + 投影
       .msg-menu-actions 长按弹出的那排操作，本来有边和投影
       .reaction / .att-file / .mcp-server / .session-data-btn / .runtime-model-list
                         各自的白底、浅灰底、边框回来了
       .home-avatar-button Home 上那两个头像的按钮壳，本来就该透明
                         （它被垫的那块灰一直藏在不透明的头像图后面）
     只有「个人信息」那一页例外，见下面那条。 */
  /* 「个人信息」这一页还没做（要等它自己的底图那一层），先原样钉住：
     上面那条摘掉之后，.action-row 会露出自己那层淡蓝白 + 投影，压在这一页
     不透明的米白底上会糊成一片。等这一页真正改造时再一起处理。 */
  .profile-panel .action-row,
  .profile-panel .settings-card{
    border:0;
    background:var(--bubble-ai-bg);
    box-shadow:none;
  }
  .call-transcript-bar,
  .call-ctrl-btn > svg,
  .call-ctrl-btn > .ph{
    border:0;
    background:var(--bubble-ai-bg);
    box-shadow:none;
  }

  /* ── 铺了 App 底图之后：卡片改成和聊天气泡同一套玻璃 ──
     三层边的道理和聊天那边一样：内白只在深色背景上起作用，外深和小投影只在浅色
     背景上起作用，两边都留着才能在任何一张图上都有边界。厚度由「卡片」那根滑杆管
     （--glass-card），默认比气泡厚一档——Home 上有进度条、百分比、小字说明，
     同样的透明度更难读。
     这里的 !important 和顺序是历史包袱：上面那条点名的规则带 !important，
     .claude-md-entry 还在它名单里。等那份名单也清空了，这里的 !important 就能一起去掉。 */
  html[data-shell-bg="on"] .home-notice,
  html[data-shell-bg="on"] .bisca-home-card,
  html[data-shell-bg="on"] .xposter-card,
  html[data-shell-bg="on"] .claude-quota-card,
  html[data-shell-bg="on"] .usage-group,
  html[data-shell-bg="on"] .data-manage-card,
  html[data-shell-bg="on"] .memory-library-link,
  html[data-shell-bg="on"] .cat-hero,
  html[data-shell-bg="on"] .cat-compose,
  html[data-shell-bg="on"] .cat-file,
  html[data-shell-bg="on"] .ideas-compose,
  html[data-shell-bg="on"] .ideas-card,
  html[data-shell-bg="on"] .claude-md-entry{
    background:var(--glass-sheen), var(--glass-card-core) !important;
    border-color:transparent !important;
    box-shadow:var(--glass-bevel-wide), var(--glass-drop) !important;
  }
  /* ── 试验：卡片也上**真**毛玻璃（2026-09-10，随时可整条删掉回退）──
     以前的结论是"跟着列表滚的东西不能用真模糊"，那是从聊天气泡那次得出的：十几个
     气泡跟着一个长列表连续滚，每帧每个都要把身后重新截图再糊一遍，当场滑不动。
     但这一层的情况不一样，值得单独试一次：
       · Home 是短页面，一屏放得下大半，几乎不滚；
       · Feed 和日记是**整段一块**玻璃，不是一行一块——各自只有 1～2 个元素；
       · Settings 最多，同屏五六个，而且是慢滚。
     同屏最多十来个、大部分时间静止，和聊天那次不是一个量级。

     祖先链查过了：卡片到 .home-shell 之间没有任何 filter / mask / opacity，
     所以不会变成"backdrop root"把壁纸挡在采样范围外（那样模糊会糊出一片空气）。

     底色不用动：52% 白后面还露着一半照片，模糊看得见。**聊天气泡不在此列**，
     那条禁令继续有效，测试里也钉着。
     卡了就整条删掉——只有这一条，删了自动回到假玻璃。 */
  html[data-shell-bg="on"] .home-notice,
  html[data-shell-bg="on"] .bisca-home-card,
  html[data-shell-bg="on"] .xposter-card,
  html[data-shell-bg="on"] .claude-quota-card,
  html[data-shell-bg="on"] .usage-group,
  html[data-shell-bg="on"] .data-manage-card,
  html[data-shell-bg="on"] .memory-library-link,
  html[data-shell-bg="on"] .claude-md-entry,
  html[data-shell-bg="on"] .feed-list,
  html[data-shell-bg="on"] .diary-calendar,
  /* 猫页同屏最多四块玻璃（图、输入区、记录整段、档案），和 Home 一个量级。
     那五个小胶囊**不在此列**：它们太小，糊了也看不出来，白花每帧的钱。 */
  html[data-shell-bg="on"] .cat-hero,
  html[data-shell-bg="on"] .cat-compose,
  html[data-shell-bg="on"] .cat-file,
  html[data-shell-bg="on"] .cat-records,
  .chat-bg-preview-card{
    -webkit-backdrop-filter:blur(18px) saturate(1.2);
    backdrop-filter:blur(18px) saturate(1.2);
  }
  /* 底栏是**真**毛玻璃，和输入框一样：它钉在屏幕底部、身后基本只有壁纸，那张背景
     快照能一直缓存着复用，所以这块实时模糊几乎不花钱——贵的是滚动列表里那种，
     每帧每个元素身后都换了一块图。模糊本身在上面 .home-dock 那条里就有了。
     白必须压到 50% 上下模糊才看得出来：72% 那一档等于把模糊糊在一块几乎不透明的
     白后面，真模糊白做了。所以它**不**跟「卡片」那根滑杆走。 */
  html[data-shell-bg="on"] .home-dock{
    background:var(--glass-half);
    border-top-color:rgba(255,255,255,.4);
  }
  /* Feed 和日记是"一列开放的行"，不是一张张卡片：所以给整段套一块玻璃，
     行还是行、分隔线还是分隔线（就像参考图里那张 Upcoming）。一行一块玻璃的话
     十几行就是十几块，太碎。 */
  html[data-shell-bg="on"] .feed-list,
  html[data-shell-bg="on"] .diary-calendar,
  html[data-shell-bg="on"] .cat-records{
    padding:6px 14px 10px;
    background:var(--glass-sheen), var(--glass-card-core) !important;
    box-shadow:var(--glass-bevel-wide), var(--glass-drop) !important;
  }
  html[data-shell-bg="on"] .feed-list,
  html[data-shell-bg="on"] .diary-calendar{ border-radius:22px; }
  /* 套上玻璃之后，最后一行那道分隔线就贴着面板底边了，去掉 */
  html[data-shell-bg="on"] .feed-card:last-child{ border-bottom:0; }
  html[data-shell-bg="on"] .feed-app:last-child{ border-bottom:0; }
  html[data-shell-bg="on"] .diary-calendar{ margin-top:22px; }
  /* 日记正文**不**套玻璃：和 Code 的正文一样，字直接铺在底图上（用户点名要的）。
     日历那块留着玻璃——它是一格一格的控件，需要一块底才拎得清。
     两段之间那条横线也去掉：上面就是玻璃面板的边，已经分开了。 */
  html[data-shell-bg="on"] .diary-reading{ margin-top:26px; padding-top:0; border-top:0; }
  /* 正文一旦铺在照片上，里面这几样原来的浅灰就撑不住了，压实一档。 */
  html[data-shell-bg="on"] .diary-reading-date,
  html[data-shell-bg="on"] .diary-entry-range,
  html[data-shell-bg="on"] .diary-review-title,
  html[data-shell-bg="on"] .diary-review-label,
  html[data-shell-bg="on"] .diary-review-state,
  html[data-shell-bg="on"] .diary-entry-state{ color:var(--text-soft); }
  html[data-shell-bg="on"] .diary-review{ margin-top:26px; padding-top:0; border-top:0; }
  html[data-shell-bg="on"] .diary-review-item{ border-top:0; padding-top:20px; background:var(--glass-line) top/100% 2px no-repeat; }
  html[data-shell-bg="on"] .diary-review-item:first-child{ padding-top:0; background:none; }
  /* 每篇之间那条线：单色的只在一半的背景上看得见，换成两色线（和 Code 的 hr 同一套）。 */
  html[data-shell-bg="on"] .diary-entry{ border-top:0; padding-top:24px; background:var(--glass-line) top/100% 2px no-repeat; }
  html[data-shell-bg="on"] .diary-entry:first-child{ padding-top:0; background:none; }
  /* Feed 的顶栏原来铺一块不透明的米白，压在照片上就是一条横条。和聊天页同一个办法：
     顶栏自己透明，浮在照片上的那几样各自戴一颗玻璃药丸。日记那边同理——返回、两个
     写作入口、翻月份的圆钮，本来都是光秃秃的字或一圈浅描边，照片一深就整个不见了。
     用 --glass-card 而不是聊天那边的 --glass-quiet：这一层的厚薄归「卡片」那根滑杆管，
     一个旋钮管一整层，不跟着聊天的滑杆走。 */
  /* 面板里那块预览为什么是空的：上面那条通杀是按类名里**带没带 card** 抓的，
     而装样例卡的那层叫 .chat-bg-preview-cards——"cards" 里就有 "card"。于是它被刷成
     一块不透明的灰，铺满整个预览框（height:100%），把底图整块盖在了下面。
     聊天那边的 .chat-bg-preview-rows 不带这三个词，所以只有 App 这一档中招。
     里面那张样例卡也一样被按平，得把玻璃还给它——它的作用就是"卡片长这样"，
     所以配方必须和真卡片一模一样（中间薄的那一档 + 宽柔光）。 */
  .chat-bg-preview-cards{ background:transparent !important; box-shadow:none !important; }
  .chat-bg-preview-card{
    background:var(--glass-sheen), var(--glass-card-core) !important;
    box-shadow:var(--glass-bevel-wide), var(--glass-drop) !important;
  }
  html[data-shell-bg="on"] .feed-topbar{ background:transparent; }
  html[data-shell-bg="on"] .feed-back,
  html[data-shell-bg="on"] .feed-date-picker,
  html[data-shell-bg="on"] .feed-history-status:not(:empty),
  html[data-shell-bg="on"] .diary-prompt-entry,
  html[data-shell-bg="on"] .diary-day-btn,
  html[data-shell-bg="on"] .diary-month-nav button{
    border-color:transparent;
    background:var(--glass-card);
    box-shadow:var(--glass-edge), var(--glass-drop-quiet);
  }
  /* 药丸上的字要比平时实，道理和聊天那几行小字一样。翻月份那两个钮不在这儿：
     它们的 :disabled 是靠颜色变灰表示的，压实了就分不出能不能点。 */
  html[data-shell-bg="on"] .feed-history-status:not(:empty),
  html[data-shell-bg="on"] .diary-prompt-entry{ color:var(--text); }
  /* 这两样原来没有自己的形状（就是一段字），戴药丸得先把形状给出来 */
  html[data-shell-bg="on"] .feed-date-picker{ padding:0 15px; border-radius:999px; }
  html[data-shell-bg="on"] .diary-prompt-entry{ padding:7px 13px; border-radius:999px; }
  html[data-shell-bg="on"] .feed-history-status:not(:empty){
    align-self:center; min-height:0; margin:2px 0 12px; padding:4px 12px; border-radius:999px;
  }
  .thought-overlay{
    position:fixed; inset:0; z-index:430; display:flex; align-items:flex-end; justify-content:center;
    pointer-events:none; visibility:hidden;
  }
  .thought-overlay.open{ pointer-events:auto; visibility:visible; }
  .thought-overlay.closing{ pointer-events:none; visibility:visible; }
  .thought-scrim{
    position:absolute; inset:0; border:0; padding:0; background:var(--scrim);
    opacity:0; transition:opacity .42s ease;
  }
  .thought-overlay.open .thought-scrim{ opacity:1; }
  .thought-sheet{
    position:relative; width:min(calc(100% - 20px),620px); min-height:min(48dvh,460px); max-height:78dvh;
    padding:12px 20px calc(28px + env(safe-area-inset-bottom)); border-radius:32px 32px 0 0;
    color:var(--text); transform:translateY(104%); transition:transform .42s cubic-bezier(.22,.8,.24,1);
    display:flex; flex-direction:column; overflow:hidden;
    background:var(--bg) !important;
  }
  .thought-overlay.open .thought-sheet{ transform:translateY(0); }
  .thought-handle{ width:42px; height:5px; margin:0 auto 8px; border-radius:99px; background:var(--surface-strong); }
  .thought-head{ position:relative; min-height:56px; display:flex; align-items:center; justify-content:center; }
  .thought-title{ margin:0; font:650 20px/1.2 var(--font-en),var(--font-cn); }
  .thought-close{
    position:absolute; left:0; width:44px; height:44px; border:0; border-radius:50%;
    padding:0; display:grid; place-items:center;
    -webkit-appearance:none; appearance:none; outline:none; -webkit-tap-highlight-color:transparent;
    background:var(--bubble-ai-bg) !important; color:var(--text); font:300 34px/1 var(--font-en); cursor:pointer;
    box-shadow:none !important;
  }
  .thought-close:focus,.thought-close:focus-visible{ outline:none; box-shadow:none; }
  /* 收藏这段 inner：和左边的关闭键对称，放右边。空心 = 没收，实心 = 收了。 */
  .thought-favorite{
    position:absolute; right:0; width:44px; height:44px; border:0; border-radius:50%;
    padding:0; display:grid; place-items:center; cursor:pointer;
    -webkit-appearance:none; appearance:none; outline:none; -webkit-tap-highlight-color:transparent;
    background:var(--bubble-ai-bg) !important; color:var(--text-soft); box-shadow:none !important;
  }
  .thought-favorite.on{ color:var(--text); }
  .thought-favorite[hidden]{ display:none; }
  .thought-favorite svg{ display:block; width:21px; height:21px; }
  .thought-close svg{ display:block; width:22px; height:22px; }
  .thought-content{
    flex:1 1 auto; min-height:0; overflow:auto; padding:18px 2px 8px;
    color:var(--text); font-family:var(--font-cn),var(--font-en);
    font-size:clamp(16px,2vw,20px); font-weight:400; line-height:1.72;
    white-space:normal; overflow-wrap:anywhere; -webkit-overflow-scrolling:touch;
  }
  /* 还在写的时候留一个光标，抽屉里也看得出是实时的。 */
  .thought-content.streaming::after{
    content:""; display:inline-block; width:2px; height:1em; margin-left:3px;
    vertical-align:-.14em; background:currentColor; opacity:.55;
    animation:thoughtCaret 1s steps(1,end) infinite;
  }
  @keyframes thoughtCaret{ 0%,49%{ opacity:.55; } 50%,100%{ opacity:0; } }
  @media (prefers-reduced-motion:reduce){
    .thought-content.streaming::after{ animation:none; }
  }
  .legacy-import-sheet,
  .runtime-picker-sheet,
  .instructions-editor-sheet,
  .mcp-manager-sheet{
    width:min(calc(100% - 16px),620px);
    border-radius:32px 32px 0 0;
    background:var(--bg) !important;
    color:var(--text);
    font-family:var(--font-cn),var(--font-en);
    font-size:clamp(16px,2vw,20px);
    font-weight:400;
    line-height:1.72;
  }
  .legacy-import-scrim,
  .runtime-picker-scrim,
  .instructions-editor-scrim,
  .mcp-manager-scrim{ background:var(--scrim); }
  .runtime-picker-handle,
  .instructions-editor-handle{ background:var(--surface-strong); }
  .legacy-import-title,
  .runtime-picker-title,
  .instructions-editor-title,
  .mcp-manager-title{
    color:var(--text); font:650 20px/1.2 var(--font-en),var(--font-cn);
  }
  .legacy-import-close,
  .runtime-picker-close,
  .instructions-editor-close,
  .mcp-manager-close{
    width:44px; height:44px; min-height:44px; padding:0; border:0; border-radius:50%;
    display:grid; place-items:center; -webkit-appearance:none; appearance:none;
    background:var(--bubble-ai-bg) !important; color:var(--text); cursor:pointer;
    box-shadow:none !important; outline:none; -webkit-tap-highlight-color:transparent;
    font-size:0;
  }
  .legacy-import-close:focus,.legacy-import-close:focus-visible,
  .runtime-picker-close:focus,.runtime-picker-close:focus-visible,
  .instructions-editor-close:focus,.instructions-editor-close:focus-visible,
  .mcp-manager-close:focus,.mcp-manager-close:focus-visible{ outline:none; box-shadow:none; }
  .legacy-import-close svg,
  .runtime-picker-close svg,
  .instructions-editor-close svg,
  .mcp-manager-close svg{ display:block; width:22px; height:22px; }
  .legacy-import-summary,
  .instructions-editor-text,
  .mcp-card-copy,
  .mcp-status{
    color:var(--text); font-family:var(--font-cn),var(--font-en);
    font-size:clamp(16px,2vw,20px); font-weight:400; line-height:1.72;
  }
  .instructions-editor-view,
  .instructions-editor-text{
    flex:1 1 auto; min-height:0; width:100%; margin-top:8px; padding:18px 2px 8px;
    border:0 !important; border-radius:0; outline:none; background:transparent !important;
    color:var(--text); font-family:var(--font-cn),var(--font-en);
    font-size:clamp(16px,2vw,20px); font-weight:400; line-height:1.72;
    white-space:pre-wrap; overflow-wrap:anywhere; overflow-y:auto; -webkit-overflow-scrolling:touch;
  }
  .instructions-editor-view{ cursor:text; }
  .instructions-editor-view:empty::before{ content:"Type Something..."; color:var(--text-faint); }
  .appearance-editor-content{ cursor:default; }
  .instructions-editor-body{
    position:relative; flex:1 1 auto; min-height:0; width:100%; margin-top:8px;
  }
  .instructions-editor-text{
    resize:none; cursor:text; caret-color:var(--text); -webkit-appearance:none; appearance:none;
    -webkit-tap-highlight-color:transparent; box-shadow:none !important;
  }
  .instructions-editor-body .instructions-editor-text{
    position:absolute; inset:0; width:100%; height:100%; min-height:0; margin:0;
    overflow-y:auto; touch-action:pan-y; overscroll-behavior:contain;
    -webkit-user-select:text; user-select:text;
  }
  .instructions-editor-body .instructions-editor-text:empty::before{
    content:attr(data-placeholder); color:var(--text-faint); pointer-events:none;
  }
  .instructions-editor-text:focus,
  .instructions-editor-text:focus-visible{
    border:0 !important; outline:0 !important; outline-offset:0 !important; box-shadow:none !important;
  }
  .instructions-editor-text::placeholder{ color:var(--text-faint); opacity:1; }
  .composer textarea{ font-size:clamp(14px,1.8vw,17px); font-weight:400; }
  .composer textarea::placeholder{ color:var(--text-soft); opacity:1; }
  .runtime-picker-trigger{ font-size:15px; font-weight:500; }
  .runtime-model-name{ font-weight:500; }
  .runtime-effort-name{ color:var(--text-faint); font-weight:400; }
  @media (max-width:520px){
    /* 手机上真正说了算的是这一块——上面那个 520 的块被它压在下面。
       头像 38px（44 试过太大；2026-09-24 缩到 30 试过，她说"缩小了不好看"，回到 38）。
       气泡的**右边界**一个像素没动：以前气泡从头像那一竖条后面开始（左边让出
       32 + 8px），宽 82vw - 32px；2026-09-23 那一竖条撤了，让出来的 40px 整个给了
       气泡，所以是 82vw + 8px。他那条气泡右边照旧留着星星的位置。 */
    :root{ --avatar-size:38px; }
    /* 气泡两边一样宽（2026-09-24，她要的）：原来最宽只到 82vw + 8px，再加上他那一行右边给
       星星留的 18px，他的气泡右边空 42px、左边只有 24px；她的气泡反过来。现在两边都只剩
       聊天列表自己那 24px 边距，长消息从左铺到右。星星早就挪到头像旁边了，只有还挂着
       气泡旁星星的那几行（分段排版里没头像的后几条）右边照旧留位置，见下面那条。 */
    .message-stack,.row.ai .bubble,.row.human .bubble{ max-width:100%; }
    .row.ai .message-bubbles,.row.human .message-bubbles{ max-width:100%; }
    /* 她自己那边不用顶格（她说的），长消息左边空一截。82vw + 8px 她还嫌顶格太多，收到 72vw
       （今天改动之前的宽度）。 */
    .row.human .message-stack,.row.human .bubble,.row.human .message-bubbles{ max-width:72vw; }
    .row.ai{ padding-right:0; }
    .row.ai:has(.bubble-with-thought, .thought-standalone){ padding-right:18px; }
    /* Code 页你那边的气泡也吃上面这两个类名，但那一页不在这次改动里：宽度钉回原样
       （以前是跟着聊天的头像占位一起算出来的 82vw - 32px）。 */
    .code-msg.human .message-stack,.code-msg.human .bubble{ max-width:calc(82vw - 32px); }
    .thought-sheet{ width:calc(100% - 16px); min-height:58dvh; padding-left:18px; padding-right:18px; }
    .thought-content{ font-size:20px; line-height:1.66; }
    .composer textarea{ font-size:17px; }
    .runtime-picker-trigger{ font-size:15px; }
  }

  /* Feed rows stay open and paper-like; never add a gray fallback panel here. */
  .home-view.feed-view .feed-card{ background-color:transparent !important; background-image:none !important; box-shadow:none !important; }
  .home-view.feed-view .feed-card-icon{ border-radius:50% !important; background-color:transparent !important; background-image:none !important; }
  .home-view.feed-view .feed-card-copy{ background-color:transparent !important; background-image:none !important; }
  .home-view.feed-view .feed-card-copy > *{ background-color:transparent !important; background-image:none !important; }
  .home-view.feed-view .feed-app,
  .home-view.feed-view .feed-app-body,
  .home-view.feed-view .feed-app-body > *{ background-color:transparent !important; background-image:none !important; box-shadow:none !important; }
  /* 卡片本身不在这条里了：它自己就是 background:transparent，摘掉不改变现在的样子，
     但铺了 App 底图时那条玻璃规则才压得住它。内层这几个继续保持透明。 */
  .usage-view .claude-quota-head,
  .usage-view .claude-quota-window,
  .usage-view .claude-quota-label,
  .usage-view .claude-quota-reset{
    background-color:transparent !important; background-image:none !important; box-shadow:none !important;
  }
  /* Bisca table activity is live page state, never a chat row. Keep it light
     enough to sit above the composer and draggable when it covers something useful. */
  .bisca-activity-float{
    position:fixed; z-index:195;
    left:50%; bottom:calc(var(--composer-zone) + 14px);
    width:min(310px, calc(100vw - 24px)); padding:11px 12px 12px;
    border:1px solid var(--card-line); border-radius:17px;
    background:var(--bg); color:var(--text); box-shadow:none;
    transform:translateX(-50%);
    transition:opacity var(--motion-normal) var(--ease-soft), transform var(--motion-normal) var(--ease-soft);
  }
  .bisca-activity-float[hidden]{ display:none; }
  .bisca-activity-float.enter{ opacity:0; transform:translateX(-50%) translateY(8px) scale(.98); }
  .bisca-activity-float.drag-position{ transform:none; }
  .bisca-activity-float.drag-position.enter{ transform:translateY(8px) scale(.98); }
  .bisca-activity-float.dragging{ transition:none; }
  .bisca-activity-head{ display:flex; align-items:center; gap:7px; cursor:grab; touch-action:none; user-select:none; -webkit-user-select:none; }
  .bisca-activity-float.dragging .bisca-activity-head{ cursor:grabbing; }
  .bisca-activity-mark{ width:8px; height:8px; border-radius:50%; background:var(--danger); flex:none; }
  .bisca-activity-title{ min-width:0; flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font:600 13px/1.35 var(--font-cn),var(--font-en); }
  .bisca-activity-hand{ flex:none; color:var(--text-faint); font-size:10px; white-space:nowrap; }
  .bisca-activity-grip{ flex:none; color:var(--text-faint); font-size:14px; }
  .bisca-activity-status{ margin:7px 0 0; font:500 13px/1.45 var(--font-cn),var(--font-en); }
  .bisca-activity-line{ margin:3px 0 0; color:var(--text-faint); font:400 11px/1.45 var(--font-cn),var(--font-en); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .bisca-activity-line[hidden]{ display:none; }
  .bisca-activity-present .task-timer-float:not(.drag-position){ bottom:calc(var(--composer-zone) + 130px); }
  /* ── Task timer — a task the AI issued, counting down ───────────────
     Sits above the chat but below every sheet and overlay (those start at
     250), so opening settings never leaves a countdown floating on top. */
  .task-timer-float{
    position:fixed; z-index:200;
    left:50%; bottom:calc(var(--composer-zone) + 14px);
    width:min(320px, calc(100vw - 24px));
    padding:11px 12px 10px;
    border-radius:17px;
    background:var(--card-bg);
    border:1px solid var(--card-line);
    box-shadow:var(--card-shadow), 0 14px 40px var(--shade-warm-1);
    backdrop-filter:blur(20px) saturate(1.4);
    -webkit-backdrop-filter:blur(20px) saturate(1.4);
    color:var(--text);
    transform:translateX(-50%);
    transition:opacity var(--motion-normal) var(--ease-soft),
               transform var(--motion-normal) var(--ease-soft);
  }
  .task-timer-float[hidden]{ display:none; }
  .task-timer-float.enter{ opacity:0; transform:translateX(-50%) translateY(10px) scale(.98); }
  .task-timer-float.drag-position{ transform:none; }
  .task-timer-float.drag-position.enter{ transform:translateY(8px) scale(.98); }
  .task-timer-float.dragging{ transition:none; }

  .task-timer-head{
    display:flex; align-items:center; gap:7px; margin-bottom:1px;
    cursor:grab; touch-action:none; user-select:none; -webkit-user-select:none;
  }
  .task-timer-float.dragging .task-timer-head{ cursor:grabbing; }
  .task-timer-icon{ font-size:14px; color:var(--text-faint); flex:none; }
  .task-timer-title{
    font-family:var(--font-cn); font-size:14px; font-weight:600; line-height:1.3;
    flex:1 1 auto; min-width:0;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .task-timer-queue{
    flex:none; font-size:11px; color:var(--text-faint);
    padding:1px 7px; border-radius:99px; background:var(--seg-track);
  }
  .task-timer-sub{ font-size:11px; color:var(--text-faint); margin-bottom:6px; }
  .task-timer-sub:empty{ display:none; }

  .task-timer-time{
    /* tabular-nums keeps 1 and 8 the same width; without it the whole row
       jitters sideways once a second. */
    font-variant-numeric:tabular-nums; font-feature-settings:"tnum" 1;
    font-family:var(--font-en);
    font-size:27px; font-weight:300; letter-spacing:.4px; line-height:1.05;
    margin:5px 0 8px;
  }
  .task-timer-float.overtime .task-timer-time{ color:var(--warning); }

  .task-timer-track{
    height:3px; border-radius:99px; background:var(--slider-track);
    overflow:hidden; margin-bottom:9px;
  }
  .task-timer-bar{
    height:100%; width:100%; border-radius:99px; background:var(--text-soft);
    /* scaleX composites on the GPU; animating width would relayout every frame. */
    transform:scaleX(0); transform-origin:left center;
  }
  .task-timer-float.overtime .task-timer-bar{ background:var(--warning); }

  .task-timer-actions{ display:flex; gap:7px; }
  .task-timer-btn{
    flex:1 1 0; padding:7px 0; border-radius:11px; cursor:pointer;
    font-family:var(--font-cn); font-size:12px; font-weight:500;
    border:1px solid transparent; transition:opacity var(--motion-fast) var(--ease-soft);
  }
  .task-timer-btn:active{ opacity:.62; }
  .task-timer-btn[disabled]{ opacity:.45; pointer-events:none; }
  .task-timer-btn.done{ background:var(--accent); color:var(--accent-fg); }
  .task-timer-btn.drop{ background:transparent; color:var(--text-faint); border-color:var(--hairline); }

  /* ── NetEase music — 聊天卡片 / 悬浮球 / 全屏播放器 / 歌单抽屉 ──────────────
     层级规则(2026-09 重写时定下的,别改回去):这一整块里不用 isolation、不用
     负 z-index、不用 backdrop-filter。旧版把背景层写成 z-index:-1 且带 filter,
     外层又 isolation:isolate;iOS 上这套组合会让父元素的背景色整片不绘制 ——
     于是播放器和歌单只剩白字浮在浅色首页上,就是那两张"什么都看不清"的截图。
     现在:背景层 z-index:0、内容 z-index:1,歌单抽屉直接挪到播放器外面自成一层,
     并且每一层都有不透明实底,不依赖任何合成特效。 */

  /* 聊天里的音乐卡片:整卡是深色的,封面只是叠在上面的氛围层,掉了也不影响可读性 */
  .music-card-shell{ width:min(430px, calc(100vw - 84px)); margin:3px 0; }
  .music-card{
    position:relative; min-height:118px; overflow:hidden; border:0; border-radius:22px;
    width:100%; padding:0; cursor:pointer; color:#fff; text-align:left;
    background:#232128; box-shadow:0 10px 32px var(--shade-warm-2);
  }
  .music-card-cover-bg{
    position:absolute; inset:0; z-index:0; width:100%; height:100%; object-fit:cover;
    filter:blur(26px) brightness(.5) saturate(1.3); transform:scale(1.25);
  }
  .music-card-inner{ position:relative; z-index:1; display:flex; align-items:center; gap:14px; min-height:118px; padding:18px; }
  .music-card-info{ flex:1; min-width:0; }
  .music-card-kicker{ font-size:11px; letter-spacing:.08em; opacity:.55; margin-bottom:9px; }
  .music-card-title{ font:650 21px/1.2 var(--font-cn); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .music-card-artist{ margin-top:5px; font-size:13px; opacity:.55; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .music-card-note{ margin-top:9px; font-size:12px; line-height:1.45; opacity:.7; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
  .music-card-play{ position:relative; flex:none; width:42px; height:42px; border-radius:50%; border:0; background:var(--glass-thin); color:#fff; display:grid; place-items:center; font-size:18px; cursor:pointer; }
  .music-card-progress{ position:absolute; z-index:2; left:0; right:0; bottom:0; height:3px; background:var(--glass-thin); }
  .music-card-progress > i{ display:block; width:0; height:100%; background:var(--glass-thick); }

  /* 黑胶:黑碟身 + 一圈淡纹路 + 中心孔,封面嵌在中间约 60% */
  .music-disc{ position:relative; flex:none; border-radius:50%; overflow:hidden; background:#0b0b0d; box-shadow:inset 0 0 0 1px rgba(255,255,255,.09); }
  .music-disc::before{ content:""; position:absolute; inset:9%; border-radius:50%; border:1px solid rgba(255,255,255,.05); }
  .music-disc::after{ content:""; position:absolute; left:50%; top:50%; width:10%; height:10%; transform:translate(-50%,-50%); border-radius:50%; background:#0b0b0d; box-shadow:0 0 0 1px rgba(255,255,255,.12); }
  .music-disc img{ position:absolute; inset:20%; width:60%; height:60%; border-radius:50%; object-fit:cover; }
  .music-card-disc{ width:72px; height:72px; }
  .music-player-disc{ width:104px; height:104px; box-shadow:inset 0 0 0 1px rgba(255,255,255,.09),0 6px 22px rgba(0,0,0,.45); }
  .music-player.playing .music-player-disc img{ animation:music-spin 12s linear infinite; }
  @keyframes music-spin{ to{ transform:rotate(360deg); } }

  /* 悬浮球 */
  .music-pill{
    position:fixed; z-index:205; right:14px; bottom:calc(var(--composer-zone) + 22px);
    display:flex; align-items:center; gap:9px; max-width:min(240px, calc(100vw - 28px));
    padding:5px 9px 5px 5px; border-radius:28px; border:1px solid var(--card-line);
    background:var(--card-bg); box-shadow:var(--card-shadow),0 8px 26px rgba(31,31,29,.12);
    touch-action:none; user-select:none; -webkit-user-select:none; cursor:grab;
  }
  .music-pill[hidden]{ display:none; }
  .music-pill.dragging{ cursor:grabbing; transition:none; }
  .music-pill-cover{ width:38px; height:38px; border-radius:50%; object-fit:cover; flex:none; background:rgba(31,31,29,.08); }
  .music-pill-info{ min-width:0; flex:1; }
  .music-pill-title,.music-pill-artist{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .music-pill-title{ font-size:12px; font-weight:650; }
  .music-pill-artist{ margin-top:2px; font-size:10px; color:var(--text-faint); }
  .music-pill-eq{ display:flex; align-items:flex-end; gap:2px; height:14px; flex:none; }
  .music-pill-eq i{ width:2px; height:4px; border-radius:2px; background:var(--text-soft); animation:music-eq .72s ease-in-out infinite alternate; }
  .music-pill-eq i:nth-child(2){ animation-duration:.54s; animation-delay:.15s; }
  .music-pill-eq i:nth-child(3){ animation-duration:.66s; animation-delay:.28s; }
  .music-pill.paused .music-pill-eq i{ animation-play-state:paused; }
  .music-pill-toggle{ width:30px; height:30px; border:0; border-radius:50%; background:transparent; color:var(--text); display:grid; place-items:center; cursor:pointer; flex:none; }
  /* 播放器的 ✕ 是收起来，气泡的 ✕ 是整个关掉。所以它画得更轻，不抢主按钮。 */
  .music-pill-close{ width:24px; height:24px; border:0; border-radius:50%; background:transparent; color:var(--text-faint); display:grid; place-items:center; font-size:13px; cursor:pointer; flex:none; margin-left:-3px; }
  @keyframes music-eq{ from{ height:3px; } to{ height:14px; } }

  /* 全屏播放器 */
  .music-player{ position:fixed; inset:0; z-index:720; display:none; overflow:hidden; color:#fff; background:#0f0e13; }
  .music-player.open{ display:flex; }
  .music-player-bg{ position:absolute; inset:0; z-index:0; background-size:cover; background-position:center; filter:blur(58px) brightness(.42) saturate(1.4); transform:scale(1.2); }
  .music-player-inner{ position:relative; z-index:1; width:min(100%,520px); height:100%; margin:auto; display:flex; flex-direction:column; padding:calc(env(safe-area-inset-top) + 12px) 20px calc(env(safe-area-inset-bottom) + 10px); }
  .music-player-top{ display:flex; align-items:center; justify-content:space-between; min-height:44px; gap:12px; }
  .music-icon-btn{ flex:none; width:40px; height:40px; border:0; border-radius:50%; background:var(--glass-thin); color:rgba(255,255,255,.8); display:grid; place-items:center; font-size:18px; cursor:pointer; }
  .music-icon-btn[hidden]{ display:none; }
  .music-player-top-actions{ display:flex; gap:8px; }
  .music-player-chip{ min-height:32px; padding:0 12px; border:0; border-radius:18px; background:var(--glass-thin); color:rgba(255,255,255,.78); font:500 12px var(--font-cn); cursor:pointer; }
  .music-player-head{ display:flex; align-items:center; gap:18px; margin:18px 0 16px; }
  .music-player-meta{ flex:1; min-width:0; }
  .music-player-kicker{ font-size:11px; letter-spacing:.08em; color:rgba(255,255,255,.45); }
  .music-player-title{ margin-top:9px; font:700 25px/1.15 var(--font-cn); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .music-player-artist{ margin-top:6px; font-size:13px; color:rgba(255,255,255,.5); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .music-progress-hit{ height:24px; display:flex; align-items:center; cursor:pointer; touch-action:none; }
  .music-progress-track{ width:100%; height:3px; border-radius:3px; background:var(--glass-thin); }
  .music-progress-fill{ position:relative; width:0; height:100%; border-radius:inherit; background:#fff; }
  .music-progress-thumb{ position:absolute; right:-6px; top:50%; width:12px; height:12px; border-radius:50%; background:#fff; transform:translateY(-50%); opacity:0; }
  .music-progress-hit.dragging .music-progress-thumb{ opacity:1; }
  .music-time{ display:flex; justify-content:space-between; margin-top:1px; color:rgba(255,255,255,.4); font:11px var(--font-en); font-variant-numeric:tabular-nums; }
  .music-controls{ display:flex; align-items:center; justify-content:center; gap:27px; margin:10px 0; }
  .music-control{ width:40px; height:40px; border:0; background:transparent; color:rgba(255,255,255,.65); display:grid; place-items:center; font-size:22px; cursor:pointer; }
  .music-control.primary{ width:54px; height:54px; border-radius:50%; background:#fff; color:var(--text); font-size:24px; box-shadow:0 4px 18px rgba(0,0,0,.4); }
  .music-lyrics{ flex:1; min-height:0; overflow-y:auto; overscroll-behavior:contain; scrollbar-width:none; scroll-behavior:smooth; padding:26vh 0 32vh; }
  .music-lyrics::-webkit-scrollbar{ display:none; }
  /* 每行歌词是 <button>。不清默认外观的话 iOS 会画成一颗左对齐的灰胶囊,
     整屏歌词变成一串灰药丸 —— 这是旧版最刺眼的一处。 */
  .music-lyric-line{
    display:block; width:100%; margin:0; padding:11px 10px; border:0; background:none;
    -webkit-appearance:none; appearance:none; text-align:center;
    font:400 16px/1.55 var(--font-cn); color:rgba(255,255,255,.3);
    cursor:pointer; transition:color .22s,transform .22s;
  }
  .music-lyric-line.active{ color:#fff; transform:scale(1.04); font-weight:650; }
  .music-lyric-main{ display:inline-block; position:relative; }
  .music-lyric-line.active .music-lyric-main::before{ content:"▶"; position:absolute; left:-17px; top:50%; transform:translateY(-50%); font-size:9px; font-weight:400; color:rgba(255,255,255,.5); }
  .music-lyric-trans{ display:block; margin-top:4px; font-size:12.5px; color:rgba(255,255,255,.38); font-weight:400; }
  .music-player-search{ display:flex; gap:9px; align-items:center; padding-top:8px; }
  .music-player-search input{ flex:1; min-width:0; height:42px; border:1px solid rgba(255,255,255,.16); border-radius:22px; background:rgba(0,0,0,.28); color:#fff; padding:0 16px; font:14px var(--font-cn); outline:none; }
  .music-player-search input::placeholder{ color:rgba(255,255,255,.35); }
  .music-player-search button{ flex:none; width:42px; height:42px; border-radius:50%; border:0; background:#fff; color:var(--text); display:grid; place-items:center; cursor:pointer; }

  /* 歌单 / 听感 / 搜索结果:整页,顶到最上面。做成底部抽屉时内容一少就缩成屏幕
     底下一小条,上面一大片空白,很难看。
     刻意用【浅色】—— 和播放器的沉浸深色分开:原项目的歌单页本身就是浅色的;
     更要紧的是万一背景层再出问题,深色字压在浅底上仍然读得出来。 */
  .music-sheet{
    position:fixed; inset:0; z-index:741;
    display:flex; flex-direction:column; color:var(--text); background:var(--bg);
    padding:calc(env(safe-area-inset-top) + 10px) 20px calc(env(safe-area-inset-bottom) + 16px);
  }
  .music-sheet[hidden]{ display:none; }
  .music-sheet .music-icon-btn{ background:var(--bubble-ai-bg); color:var(--text-soft); }
  .music-sheet-head{ display:flex; align-items:center; gap:12px; min-height:44px; }
  .music-sheet-title{ flex:1; min-width:0; font:700 18px/1.3 var(--font-cn); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .music-sheet-body{ flex:1; min-height:0; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:10px 0 6px; }
  .music-sheet .music-panel-state{ color:var(--text-faint); }

  .music-playlist-grid{ display:grid; grid-template-columns:1fr 1fr; gap:14px; }
  .music-playlist-card{ border:1px solid var(--hairline); border-radius:16px; background:transparent; color:var(--text); padding:10px; text-align:left; cursor:pointer; overflow:hidden; }
  .music-playlist-cover{ position:relative; display:grid; place-items:center; width:100%; aspect-ratio:1/1; border-radius:11px; overflow:hidden; background:var(--bubble-ai-bg); color:var(--text-faint); font-size:26px; }
  .music-playlist-cover img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
  .music-playlist-card strong{ display:block; margin-top:9px; font:600 13.5px/1.35 var(--font-cn); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .music-playlist-card span{ display:block; margin-top:3px; font-size:11px; color:var(--text-faint); }
  .music-playlist-new{ border-style:dashed; }
  .music-playlist-new .music-playlist-cover{ font-size:30px; font-weight:300; }

  .music-song-row{ display:flex; align-items:center; gap:13px; padding:11px 2px; border-bottom:1px solid var(--hairline); cursor:pointer; }
  .music-song-row:last-child{ border-bottom:0; }
  .music-song-thumb{ position:relative; display:grid; place-items:center; width:52px; height:52px; flex:none; border-radius:10px; overflow:hidden; background:var(--bubble-ai-bg); color:var(--text-faint); font-size:17px; }
  .music-song-thumb img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
  .music-song-row-info{ min-width:0; flex:1; }
  .music-song-row-info strong{ display:block; font:600 15px/1.3 var(--font-cn); color:var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .music-song-sub{ display:flex; align-items:center; gap:7px; margin-top:5px; }
  .music-song-artist{ min-width:0; font-size:12px; color:var(--text-faint); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .music-song-count{ flex:none; padding:2px 7px; border-radius:7px; background:var(--bubble-ai-bg); color:var(--text-soft); font-size:10px; }
  /* 备注也是 <button>(点一下能改),所以同样要把浏览器默认外观清掉 ——
     不清的话 iOS 又会画成一颗灰胶囊,和当初歌词那个坑一模一样。 */
  /* 一首歌下面挂的一串留言。每条都是 <button>(碳碳自己那几句点得动),
     所以照例把浏览器默认外观清干净 —— 不清 iOS 会画成一排灰胶囊。 */
  .music-remarks{ display:flex; flex-direction:column; align-items:flex-start; gap:3px; margin-top:6px; }
  .music-remark{
    display:block; max-width:100%; margin:0; padding:0; border:0; background:none;
    -webkit-appearance:none; appearance:none; text-align:left;
    font:italic 12px/1.5 var(--font-cn); color:var(--text-faint);
  }
  .music-remark[disabled]{ opacity:1; }
  .music-remark.mine{ cursor:pointer; }
  .music-remark-who{ margin-right:6px; font-style:normal; font-weight:600; font-size:10.5px; color:var(--text-soft); opacity:.75; }
  .music-remark.add{ font-style:normal; font-size:11.5px; opacity:.5; cursor:pointer; }
  .music-sheet-actions{ display:flex; flex-wrap:wrap; gap:8px; padding:2px 0 12px; }
  .music-sheet-chip{ min-height:30px; padding:0 11px; border:1px solid var(--hairline); border-radius:16px; background:transparent; color:var(--text-soft); font:500 12px var(--font-cn); cursor:pointer; }
  .music-sheet-chip.danger{ color:var(--danger); border-color:rgba(180,84,75,.28); }
  .music-song-drop{ flex:none; width:30px; height:30px; border:0; border-radius:50%; background:transparent; color:var(--text-faint); display:grid; place-items:center; font-size:14px; cursor:pointer; }
  .music-song-play{ flex:none; width:34px; height:34px; border-radius:50%; background:var(--bubble-ai-bg); color:var(--text-soft); display:grid; place-items:center; font-size:15px; }
  .music-song-row.current .music-song-play{ background:var(--text); color:var(--bg); }
  .music-song-row.current .music-song-row-info strong{ font-weight:700; }

  .music-analysis-text{ white-space:pre-wrap; color:var(--text-soft); font-size:15px; line-height:1.8; }
  /* 这条同时用在播放器的歌词区(深色)和抽屉里(浅色),默认按深色写,抽屉那边上面已覆盖。 */
  .music-panel-state{ color:rgba(255,255,255,.45); background-color:transparent !important; background-image:none !important; text-align:center; padding:52px 16px; line-height:1.7; }

  @media(max-width:520px){
    .music-card-shell{ width:calc(100vw - 68px); }
    .music-card-inner{ padding:15px; min-height:106px; }
    .music-card{ min-height:106px; }
    .music-card-disc{ width:64px; height:64px; }
    .music-card-play{ width:38px; height:38px; }
    .music-player-inner{ padding-left:17px; padding-right:17px; }
    .music-player-disc{ width:92px; height:92px; }
    .music-player-title{ font-size:23px; }
  }

  @media (prefers-reduced-motion: reduce){
    .task-timer-float{ transition:none; }
    .music-pill-eq i,.music-player.playing .music-player-disc img{ animation:none; }
  }

  /* ── Code workstation: reuse Chat's shell while keeping its service isolated. */
  .code-workspace{ height:100%; min-height:0; display:flex; flex-direction:column; align-items:stretch; padding:0; }
  .code-workspace[hidden]{ display:none; }
  /* 顶栏浮在内容上面，和聊天一样。原来它是 flex 里实打实的一行，把内容整块往下推，
     于是顶栏和第一行字之间白空一条——用户要的是"文字顶到上面去"。
     改成绝对定位之后，内容能一直铺到屏幕最上面，滚过去时在顶栏那一段里淡完。
     不铺底图时沿用 .topbar 自带的那道米白渐变（下缘是透明的，所以不会切出硬边），
     铺了底图就整个让开，不然是压在照片上的一条横条。 */
  .code-workspace .code-head{ position:absolute; top:0; left:0; right:0; z-index:3; flex:none; }
  html[data-shell-bg="on"] .code-workspace .code-head{ background:transparent; }
  .code-changes{ position:absolute; z-index:4; inset:58px 0 0; display:flex; flex-direction:column; background:var(--bg); overflow:hidden; }
  .code-changes[hidden]{ display:none; }
  .code-changes-head{ display:flex; align-items:center; justify-content:space-between; padding:14px var(--side-pad); border-bottom:1px solid var(--hairline); }
  .code-changes-title{ margin:0; font:600 16px/1.2 var(--font-cn),var(--font-en); }
  .code-git-summary{ display:flex; flex-wrap:wrap; gap:8px 14px; padding:12px var(--side-pad); color:var(--text-faint); font:500 12px/1.4 var(--font-cn),var(--font-en); }
  .code-git-summary strong{ color:var(--text); font-weight:650; }
  .code-git-actions{ display:flex; gap:8px; padding:0 var(--side-pad) 12px; }
  .code-git-actions button,.code-commit button{ min-height:36px; padding:0 12px; border:1px solid var(--hairline); border-radius:10px; background:transparent; color:var(--text); font:600 12px/1 var(--font-cn),var(--font-en); cursor:pointer; }
  .code-git-actions button:disabled,.code-commit button:disabled{ opacity:.42; cursor:default; }
  .code-git-main{ display:grid; grid-template-columns:minmax(180px,.8fr) minmax(0,1.7fr); flex:1; min-height:0; border-top:1px solid var(--hairline); border-bottom:1px solid var(--hairline); }
  .code-git-files{ overflow:auto; border-right:1px solid var(--hairline); }.code-git-files button{ display:flex; width:100%; gap:8px; border:0; background:transparent; color:var(--text); padding:10px var(--side-pad); text-align:left; cursor:pointer; }.code-git-files button.active{ background:var(--code-bg); }.code-git-files b{ flex:none; width:20px; font:600 12px/1.2 ui-monospace,monospace; }.code-git-files span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font:500 12px/1.2 ui-monospace,monospace; }
  .code-git-diff{ min-width:0; overflow:auto; margin:0; padding:14px; color:var(--text); font:12px/1.55 ui-monospace,monospace; white-space:pre-wrap; overflow-wrap:anywhere; }.code-git-empty{ padding:12px var(--side-pad); color:var(--text-faint); font-size:12px; }
  .code-commit{ display:grid; grid-template-columns:minmax(0,1fr) auto; gap:8px; padding:12px var(--side-pad); }.code-commit textarea{ min-height:38px; padding:9px; border:1px solid var(--hairline); border-radius:10px; background:transparent; color:var(--text); font:13px/1.35 var(--font-cn),var(--font-en); resize:vertical; }.code-commit p{ grid-column:1/-1; margin:0; color:var(--text-faint); font-size:11px; }
  @media(max-width:600px){ .code-git-main{ grid-template-columns:1fr; }.code-git-files{ max-height:180px; border-right:0; border-bottom:1px solid var(--hairline); } }
  .code-workspace .code-session-pop{ top:calc(env(safe-area-inset-top) + 58px); right:var(--side-pad); }
  /* 「常用」小框：现在在哪位老师这里（2026-09-29）。选中的那位前面一颗蓝点，没选的是空心圈。 */
  .code-workspace .code-tools-pop{ top:calc(env(safe-area-inset-top) + 58px); right:var(--side-pad); }
  .code-teacher-list{ display:flex; flex-direction:column; gap:2px; }
  .code-teacher{
    display:flex; align-items:center; gap:12px; width:100%; padding:10px 9px; border:0; border-radius:12px;
    background:transparent; color:var(--text); text-align:left; cursor:pointer;
  }
  .code-teacher:active{ background:var(--row-press); }
  .code-teacher[aria-checked="true"]{ background:var(--tint); }
  .code-teacher-dot{ width:9px; height:9px; flex:none; border-radius:50%; border:1.4px solid var(--text-faint); box-sizing:border-box; }
  .code-teacher[aria-checked="true"] .code-teacher-dot{ background:var(--caeruleus); border-color:var(--caeruleus); }
  .code-teacher-empty{ margin:22vh auto 0; max-width:280px; text-align:center; }
  .code-teacher-empty[hidden]{ display:none; }
  .code-teacher-empty-title{ margin:0 0 8px; color:var(--text); font:600 15px/1.4 var(--font-cn),var(--font-en); }
  .code-teacher-empty-hint{ margin:0; color:var(--text-faint); font:400 13px/1.7 var(--font-cn),var(--font-en); }
  .code-workspace.teacher-codex .code-empty{ display:none; }
  /* codex老师的登录（2026-09-29）：一次性码大字、点一下复制；链接一颗细边胶囊；按钮是黑底那颗。 */
  .codex-login-code{ margin:18px auto 0; display:flex; flex-direction:column; align-items:center; gap:6px; }
  .codex-login-code[hidden],.codex-login-link[hidden],.codex-login-btn[hidden]{ display:none; }
  .codex-login-code-label{ color:var(--text-faint); font:500 11.5px/1 var(--font-cn),var(--font-en); letter-spacing:.14em; }
  .codex-login-code-value{
    border:1px dashed var(--line-strong); border-radius:14px; padding:10px 18px; background:transparent; cursor:pointer;
    color:var(--caeruleus); font:700 24px/1 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing:.12em;
  }
  .codex-login-link{
    margin:14px auto 0; display:inline-flex; align-items:center; gap:6px; padding:9px 16px; border:1px solid var(--line);
    border-radius:999px; color:var(--text); text-decoration:none; font:500 14px/1 var(--font-cn),var(--font-en);
  }
  .codex-login-btn{
    margin:18px auto 0; display:block; min-height:40px; padding:0 22px; border:0; border-radius:999px;
    background:var(--fill-strong); color:var(--text-on-fill); cursor:pointer; font:600 14px/1 var(--font-cn),var(--font-en);
  }
  .codex-login-btn:disabled{ opacity:.4; cursor:default; }
  .codex-login-btn.is-quiet{ background:transparent; color:var(--text-faint); min-height:32px; font-weight:500; font-size:13px; }
  .code-session-head{ align-items:flex-end; }
  .code-project-field{ min-width:0; flex:1; display:grid; gap:4px; color:var(--text-faint); font:500 11px/1.2 var(--font-cn); }
  .code-project-select{
    width:100%; min-height:34px; padding:0 28px 0 10px; appearance:none;
    border:0; border-radius:13px; background:var(--seg-track); color:var(--text);
    font:500 13px/1 var(--font-cn); overflow:hidden; text-overflow:ellipsis;
  }
  .code-session-item .session-name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .code-scroll{
    flex:1; min-height:0; overflow-y:auto; overflow-x:hidden; -webkit-overflow-scrolling:touch;
    overscroll-behavior:contain;
    scrollbar-width:none;
    /* 两头本来都是硬切：滚到顶栏底下、滚到输入框上沿，都是一刀切断，半行字挂在那儿。
       聊天那边靠 .scroll 的遮罩渐隐，这里补同一套。
       顶上这一段照抄聊天：顶栏现在也是浮在内容上面的，所以渐隐正好落在顶栏那一段里，
       内容一直铺到屏幕最上面、在顶栏底下淡完。上内边距按**顶栏整高**留，
       这样滚到头时第一条消息落在顶栏下面，不会被压住也不会半透明。
       底下那段不一样：Code 的输入框是 flex 里实打实的一行（不像聊天那样浮在上面），
       所以只要收一小段，并且把它加进下内边距——不加的话内容滚不出渐隐区，
       最后一行会永远半透明。 */
    --code-head-h:calc(72px + env(safe-area-inset-top));
    /* 顶上那段渐隐分两截，不是一条直着淡过来的斜线：
       先**整段全透**盖到按钮上沿（状态栏 + 一点），这一段里内容是彻底不画的；
       再从那儿一路淡到顶栏下沿。只用一条斜线的话，按钮周围那一圈内容还有大半亮度，
       挤在一起看着很乱——用户："遮罩不明显"。 */
    --code-fade-clear:calc(30px + env(safe-area-inset-top));
    --code-fade-top:calc(92px + env(safe-area-inset-top));
    --code-fade-tail:24px;
    padding:calc(clamp(14px,2.4vw,28px) + var(--code-head-h)) var(--side-pad) calc(20px + var(--code-fade-tail));
    -webkit-mask-image:linear-gradient(to bottom,transparent 0,transparent var(--code-fade-clear),#000 var(--code-fade-top),#000 calc(100% - var(--code-fade-tail)),transparent 100%);
    mask-image:linear-gradient(to bottom,transparent 0,transparent var(--code-fade-clear),#000 var(--code-fade-top),#000 calc(100% - var(--code-fade-tail)),transparent 100%);
    -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  }
  .code-scroll::-webkit-scrollbar{ width:0; height:0; }
  /* Push / Pull 那颗小药丸（2026-09-30）：顶栏里退出键右边那块空地，和右边那排按钮同高同底。
     右边那排按钮最多四颗，这颗最多占到剩下的地方，字太长就省略号。 */
  .code-git-notice{
    position:absolute; z-index:4; left:calc(var(--side-pad) + 52px); top:calc(env(safe-area-inset-top) + 2px);
    display:flex; align-items:center; gap:5px; height:44px; padding:0 14px;
    max-width:calc(100vw - var(--side-pad) * 2 - 52px - 188px);
    border:0; border-radius:22px; background:var(--glass-solid); box-shadow:0 7px 24px var(--shade-warm-1);
    color:var(--text); font:600 12.5px/1 var(--font-cn),var(--font-en); cursor:pointer; white-space:nowrap;
  }
  .code-git-notice span{ overflow:hidden; text-overflow:ellipsis; }
  .code-git-notice i{ flex:none; font-size:15px; }
  .code-git-notice[hidden]{ display:none; }
  /* 手机预览那颗。没有预览时整颗不出现；.topbtn 写了 display:grid，hidden 属性要自己补。
     新的一份刚送到、还没点开看过时，右上角亮一个小点。 */
  #codePreviewBtn{ position:relative; }
  #codePreviewBtn[hidden]{ display:none; }
  #codePreviewBtn.fresh::after{
    content:""; position:absolute; top:7px; right:7px; width:7px; height:7px;
    border-radius:50%; background:var(--accent);
  }
  /* 手机预览（2026-09-24）。整屏盖住，顶上一条细栏放关闭和重新载入，其余全给那个框。
     框里的页面拿不到刘海和底部横条的尺寸（那组数只给最外层的页面），所以框让开这两截：
     上面从细栏底下开始，下面停在横条上方——它就当自己跑在一台没有刘海的手机上。 */
  .code-preview{ position:fixed; inset:0; z-index:385; display:flex; flex-direction:column; background:var(--bg); }
  .code-preview.hidden{ display:none; }
  .code-preview-head{
    flex:none; display:flex; align-items:center; gap:10px;
    padding:calc(env(safe-area-inset-top) + 4px) var(--side-pad) 8px;
  }
  .code-preview-head .topbtn{ flex:none; width:40px; height:40px; background:var(--surface); box-shadow:0 7px 24px var(--shade-warm-1); }
  .code-preview-title{ flex:1; min-width:0; display:grid; justify-items:center; gap:2px; text-align:center; }
  .code-preview-title strong{ color:var(--text); font:650 15px/1.25 var(--font-cn),var(--font-en); }
  .code-preview-title span{
    max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
    color:var(--text-soft); font:500 11px/1.3 var(--font-en),var(--font-cn);
  }
  .code-preview-stage{
    position:relative; flex:1 1 auto; min-height:0;
    margin-bottom:env(safe-area-inset-bottom); border-top:1px solid var(--hairline);
  }
  .code-preview-frame{ display:block; width:100%; height:100%; border:0; background:var(--bg); }
  .code-preview-status{
    position:absolute; inset:0; display:grid; place-items:center; padding:28px;
    background:var(--bg); color:var(--text-soft); text-align:center; font:400 15px/1.7 var(--font-cn),var(--font-en);
  }
  .code-preview-status[hidden]{ display:none; }
  .code-empty{ display:none; }
  .code-msg{ width:100%; max-width:760px; margin-left:auto; margin-right:auto; }
  .code-msg.assistant{ justify-content:flex-start; padding:0; }
  .code-msg.assistant .message-stack{ width:100%; max-width:min(86vw,720px); }
  .code-assistant-text{
    width:100%; padding:0; color:var(--text); overflow-wrap:anywhere;
    font:400 clamp(15px,1.65vw,17px)/1.78 var(--font-cn),var(--font-en);
  }
  /* Code 的正文是直接铺在底图上的（没有气泡兜着），所以一条单色的分隔线注定只在
     一半的背景上看得见——压在灰色的岩石上就整个没了。换成两色线：2px 高，上半深
     下半浅，深底看到浅的那半、浅底看到深的那半。和聊天里那两条分隔线同一套。 */
  html[data-shell-bg="on"] .code-assistant-text hr{
    height:2px; opacity:1; background:var(--glass-line);
  }
  .code-msg.assistant.streaming .code-assistant-text::after{
    content:""; display:inline-block; width:.38em; height:.38em; margin-left:.28em;
    border-radius:50%; background:currentColor; vertical-align:.12em; animation:streamPulse 1s ease-in-out infinite;
  }
  /* Code 页面不显示用户头像,气泡直接贴右边界。聊天页仍保留头像。 */
  .code-msg.human{ justify-content:flex-end; padding-right:0; }
  .code-msg.human .bubble{ white-space:normal; }
  .code-msg.human .bubble::after{ content:none; }
  /* 「我说的话」跟着聊天走：同一块玻璃、同一个颜色、同一根滑杆（--glass-human 是
     聊天那边「气泡」滑杆现算出来的）。条件挂在 data-shell-bg 上，因为 Code 身后铺的
     是 App 那张底图——聊天那张跟这儿没关系。
     不能直接复用聊天那条规则：它写死在 `html[data-chat-bg="on"] .app` 里面，
     而 Code 不在 .app 下（那个 `.app` 是上次踩过坑之后特意加的，别去掉）。 */
  html[data-shell-bg="on"] .code-msg.human .bubble{
    background:var(--glass-human);
    box-shadow:var(--glass-edge), var(--glass-bevel), var(--glass-drop);
  }
  .code-tool-events{ width:min(100%,620px); margin-top:10px; }
  .code-status{ max-width:760px; min-height:18px; margin:12px auto 0; color:var(--text-faint); text-align:center; font-size:12px; }
  .code-workspace .code-composer{
    position:relative; left:auto; right:auto; bottom:auto; flex:none; width:auto;
    margin:0 clamp(12px,3vw,28px) calc(10px + env(safe-area-inset-bottom));
  }
  .code-workspace .code-composer[hidden]{ display:none; }
  /* 「回到底部」那颗的座：输入框前面一条零高度的线，左右和输入框一样宽，所以药丸
     （.newmsg-pill 的 bottom:calc(100% + 10px)）还是浮在输入框上沿正中。开 Changes 时
     输入框整个 hidden，药丸原来跟着消失；挪出来之后这件事得自己写。 */
  .code-pill-anchor{ position:relative; flex:none; height:0; margin:0 clamp(12px,3vw,28px); }
  .code-workspace:has(.code-composer[hidden]) .code-pill-anchor{ display:none; }
  /* Code 这颗的**位置和样子整个复用 .newmsg-pill**——那条现在也钉在输入框上沿了
     （2026-09-14 聊天那颗被发现是同一个病：写死 122px，输入框一长高就埋进去）。
     所以这里只剩 Code 独有的那一件事：生成中换成三个点。
     顺带一个好处：开 Changes 时输入框整个 hidden，药丸跟着消失，不用自己管。 */
  /* 正在生成时这颗键换成三个跳动的点，动画就是聊天里那个占位气泡那份。
     它本来就只在人往上翻走之后才出现，所以这三个点回答的正好是那一刻的问题：
     "我翻上来了，它还在写吗"。贴着底的时候不用问——字就在眼前流。 */
  .code-newmsg-pill .bubble-typing{ display:none; }
  .code-newmsg-pill.is-busy .ph{ display:none; }
  .code-newmsg-pill.is-busy .bubble-typing{ display:inline-flex; }
  .code-composer .runtime-picker-trigger{ grid-column:2; grid-row:2; }
  .code-composer .floatbtn.send{ flex:none; }
  .code-context-ring{
    position:relative; flex:none; width:24px; height:24px; margin:0 0 10px 1px; padding:2px;
    border:0; border-radius:50%; background:transparent; color:var(--text-faint); cursor:pointer;
  }
  .code-context-ring svg{ display:block; width:20px; height:20px; transform:rotate(-90deg); }
  .code-context-track,.code-context-value{ fill:none; stroke-width:2.4; }
  .code-context-track{ stroke:var(--line-strong); }   /* 原来写死深色 .16，深色模式下黑上画黑，整圈看不见 */
  .code-context-value{ stroke:var(--text); stroke-linecap:round; stroke-dasharray:100; stroke-dashoffset:100; transition:stroke-dashoffset .25s ease; }
  .code-context-tip{
    position:absolute; right:-48px; bottom:calc(100% + 10px); width:232px; padding:10px 12px;
    border-radius:14px; background:#111; color:var(--text-on-fill); text-align:center; pointer-events:none;
    opacity:0; visibility:hidden; transform:translateY(4px); transition:.16s ease;
    font:500 12px/1.45 var(--font-cn),var(--font-en); box-shadow:0 8px 24px var(--shade-warm-3);
  }
  .code-context-tip strong{ display:block; margin:2px 0; font-size:14px; }
  .code-context-cache{ display:block; margin-top:5px; color:rgba(255,255,255,.72); }
  .code-context-ring:hover .code-context-tip,
  .code-context-ring:focus-visible .code-context-tip,
  .code-context-ring[aria-expanded="true"] .code-context-tip{ opacity:1; visibility:visible; transform:translateY(0); }
  @media(max-width:520px){
    .code-workspace .code-session-pop{ top:calc(env(safe-area-inset-top) + 50px); }
    .code-workspace .code-tools-pop{ top:calc(env(safe-area-inset-top) + 50px); }
    .code-scroll{ padding-left:18px; padding-right:18px; }
    .code-msg.assistant .message-stack{ max-width:100%; }
    .code-assistant-text{ font-size:17px; line-height:1.72; }
    .code-workspace .code-composer{ margin-left:12px; margin-right:12px; padding:9px; }
  }
