:root{
  --bg:#ffffff; --bg-soft:#f9f9f9; --bg-side:#f9f9f9; --bg-hover:#ececec; --bg-input:#ffffff;
  --bg-card:#ffffff;   /* v3.38.0：补定义——cmd-dropdown / ms-bar 背景依赖此变量 */
  --panel:var(--bg);   /* 面板/浮层背景（原引用未定义，补上，跟随 --bg） */
  --bg-panel:var(--bg-soft);   /* 模态框/面板卡片背景（原引用未定义，补上，跟随 --bg-soft） */
  --border:#e5e5e5; --border-soft:#f0f0f0;
  --text:#202123; --text-sub:#6b6b6e; --text-faint:#9b9b9e;
  --text-soft:var(--text-sub);   /* 柔和文字（原引用未定义，补上，跟随 --text-sub） */
  --text-muted:var(--text-faint);   /* 弱化文字（原引用未定义，补上，跟随 --text-faint） */
  --accent:#10a37f; --accent-hover:#0e8f6f; --accent-soft:#e6f6f1;
  --danger:#ef4444; --danger-soft:#fdeaea;
  --code-bg:#1e1e1e; --code-text:#d4d4d4;
  --bubble-user:#10a37f; --bubble-user-text:#ffffff;
  --shadow:0 4px 16px rgba(0,0,0,.08);
  --radius:14px;
  /* v4.31.3：交互动效的统一节拍。各处手写的 .15s/.2s 保持原样不动，
     这两条只给**新增**规则用 —— 以后要整体调速只改这里。 */
  --dur-1:.14s; --dur-2:.22s; --ease-std:cubic-bezier(.4,0,.2,1);
  /* v4.31.3：让浏览器按当前主题绘制**原生控件**。
     原来深色主题下，滚动条、<select> 下拉、checkbox、日期选择器仍是白底 ——
     在手机上尤其突兀（一整块亮色从深色界面里跳出来）。 */
  color-scheme:light;
}
[data-theme="dark"]{
  --bg:#212121; --bg-soft:#2b2b2b; --bg-side:#171717; --bg-hover:#383838; --bg-input:#2f2f2f;
  --bg-card:#2b2b2b;   /* v3.38.0：补定义——cmd-dropdown / ms-bar 深色背景 */
  --panel:var(--bg);   /* 跟随 --bg（深色面板） */
  --bg-panel:var(--bg-soft);   /* 模态框/面板卡片背景（跟随 --bg-soft） */
  --border:#3a3a3a; --border-soft:#333;
  --text:#ececec; --text-sub:#a6a6a6; --text-faint:#777;
  --text-soft:var(--text-sub);   /* 跟随 --text-sub（深色柔和文字） */
  --text-muted:var(--text-faint);   /* 弱化文字（跟随 --text-faint） */
  --accent:#10a37f; --accent-hover:#19b78e; --accent-soft:#1e3430;
  --danger:#f87171; --danger-soft:#3a2323;
  --code-bg:#0d0d0d; --code-text:#d4d4d4;
  --bubble-user:#10a37f; --bubble-user-text:#ffffff;
  --shadow:0 4px 16px rgba(0,0,0,.4);
  /* v4.31.3：深色主题下原生控件也走深色（滚动条 / select / checkbox 等） */
  color-scheme:dark;
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html,body{height:100%}
body{
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",Roboto,sans-serif;
  background:var(--bg);color:var(--text);font-size:15px;line-height:1.65;
  overflow:hidden;
}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}
input,textarea,select{font-family:inherit;color:inherit}
svg{flex-shrink:0}
::-webkit-scrollbar{width:8px;height:8px}
::-webkit-scrollbar-thumb{background:rgba(128,128,128,.35);border-radius:8px}
::-webkit-scrollbar-track{background:transparent}

/* ===== 视图切换 ===== */
#view-login{display:flex;align-items:center;justify-content:center;height:100%;background:var(--bg-soft);padding:24px}
#view-app{display:none;height:100%}

/* ===== 登录页 ===== */
.login-card{background:var(--bg);border:1px solid var(--border);border-radius:18px;padding:40px 36px;width:100%;max-width:400px;box-shadow:var(--shadow)}
.login-logo{display:flex;align-items:center;gap:12px;justify-content:center;margin-bottom:8px}
.login-logo .logo-ic{width:44px;height:44px;border-radius:12px;background:var(--accent);display:flex;align-items:center;justify-content:center;color:#fff}
.login-card h1{font-size:20px;text-align:center;font-weight:700;margin-bottom:4px}
.login-card .sub{text-align:center;color:var(--text-sub);font-size:13px;margin-bottom:28px}
.field{margin-bottom:16px}
.field label{display:block;font-size:13px;color:var(--text-sub);margin-bottom:6px;font-weight:500}
.field input,.field textarea,.field select{
  width:100%;padding:12px 14px;font-size:16px;border:1px solid var(--border);border-radius:10px;
  background:var(--bg-input);outline:none;transition:border .15s;
}
.field input:focus,.field textarea:focus{border-color:var(--accent)}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:12px 20px;border-radius:10px;font-size:15px;font-weight:600;min-height:46px;transition:background .15s,opacity .15s}
.btn-primary{background:var(--accent);color:#fff;width:100%}
.btn-primary:hover{background:var(--accent-hover)}
.btn-ghost{background:var(--bg-hover);color:var(--text)}
.btn-ghost:hover{filter:brightness(.96)}
.btn-danger{background:var(--danger);color:#fff}
.btn[disabled]{opacity:.5;cursor:not-allowed}
.form-err{color:var(--danger);font-size:13px;min-height:20px;margin:4px 0 8px;text-align:center}
.login-tip{font-size:12px;color:var(--text-faint);text-align:center;margin-top:18px;line-height:1.6}
kbd{background:var(--bg-hover);border:1px solid var(--border);border-radius:4px;padding:1px 6px;font-size:11px;font-family:ui-monospace,monospace}

/* ===== 应用布局 ===== */
#view-app{display:none;flex-direction:column}
.app-body{display:flex;flex:1;min-height:0;position:relative}
.topbar{
  height:56px;display:flex;align-items:center;gap:10px;padding:0 14px;
  border-bottom:1px solid var(--border-soft);background:var(--bg);z-index:30;flex-shrink:0;
}
.topbar .brand{font-weight:700;font-size:16px;display:flex;align-items:center;gap:8px}
.icon-btn{width:40px;height:40px;border-radius:10px;display:inline-flex;align-items:center;justify-content:center;color:var(--text-sub);transition:background .15s}
/* v4.38.0：顶栏「API 余额」胶囊 —— 常驻显示、点击刷新。
   放在搜索图标左边；数字用等宽数字避免刷新时宽度跳动（tabular-nums）。*/
.balance-pill{
  display:inline-flex;align-items:center;justify-content:center;
  height:26px;padding:0 10px;margin-right:6px;border-radius:999px;
  border:1px solid var(--border);background:var(--bg-soft);
  color:var(--text);font-size:12px;line-height:1;
  font-variant-numeric:tabular-nums;
  white-space:nowrap;cursor:pointer;
  transition:background .15s,border-color .15s,color .15s;
}
.balance-pill:hover{background:var(--bg-hover)}
.balance-pill:active{transform:translateY(1px)}
/* 未刷新过 / 查询失败：弱化，别让它看起来像"确定的数字" */
.balance-pill.stale{color:var(--text-faint);border-color:var(--border-soft)}
/* 正在查：半透明 + 不可点，避免连点打外部接口 */
.balance-pill.busy{opacity:.55;pointer-events:none}
/* 余额偏低（<=10 元，与后端 format_accounts 的默认阈值一致）：给个温和的警示色 */
.balance-pill.low{color:var(--danger);border-color:var(--danger);background:var(--danger-soft)}
@media(max-width:520px){
  .balance-pill{height:24px;padding:0 8px;font-size:11px;margin-right:4px}
}
.icon-btn:hover{background:var(--bg-hover);color:var(--text)}
/* ---- ⋯ 更多菜单 ---- */
.more-wrap{position:relative}
.more-menu{position:absolute;right:0;top:calc(100% + 6px);min-width:220px;max-width:280px;
  background:var(--panel);border:1px solid var(--border);border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,.18);
  padding:6px;z-index:60;font-size:14px;
  /* v4.38.1：**菜单必须能滚**。手机上 20+ 项约 740px，原来没有 max-height，
     超出屏幕的部分直接看不见、也没法滚 —— 用户反馈「太长了，手机显示不开」。*/
  max-height:min(72vh,620px);overflow-y:auto;overscroll-behavior:contain}

/* v4.38.1：折叠分组 —— 把低频项收进 <details>，菜单从 20+ 行缩到 ~13 行。
   ⚠️ **只折叠、不删除**：展开后每一项照旧能点（按钮与功能不许悄悄消失）。*/
.mm-fold{margin:0}
.mm-fold>summary{list-style:none;cursor:pointer}
.mm-fold>summary::-webkit-details-marker{display:none}
.mm-fold>summary::after{content:"▸";margin-left:auto;font-size:11px;opacity:.55}
.mm-fold[open]>summary::after{content:"▾"}
.mm-fold-body{padding-left:6px;margin-left:10px;border-left:2px solid var(--border-soft)}
.more-menu[hidden]{display:none}
.mm-item{padding:9px 12px;border-radius:8px;cursor:pointer;display:flex;align-items:center;gap:8px;
  color:var(--text);user-select:none}
.mm-item:hover{background:var(--bg-hover)}
.mm-hint{font-size:12px;color:var(--text-faint);margin-right:2px}
.mm-item.mm-toggle{cursor:default;justify-content:space-between;padding:9px 12px}
.mm-item.mm-toggle:hover{background:transparent}
.mm-item.mm-toggle>span{flex:1}
.mm-item.mm-toggle input{width:16px;height:16px;cursor:pointer}
.mm-item.mm-danger{color:var(--danger)}
/* v4.38.1：手机上让 ⋯ 菜单更紧凑（行高压下来，配合 max-height 滚动，
   整份菜单一屏能看全，不用来回滚）。 */
@media(max-width:520px){
  .more-menu{min-width:200px;max-width:80vw;max-height:min(76vh,540px);font-size:13.5px;padding:5px}
  .mm-item{padding:7px 10px;border-radius:7px}
  .mm-item.mm-toggle{padding:7px 10px}
  .mm-fold-body{margin-left:6px;padding-left:5px}
}
.mm-item.mm-danger:hover{background:rgba(220,38,38,.08)}
.mm-sep{height:1px;background:var(--border);margin:4px 8px}

/* ---- Router 来源标签（聊天回复下） ---- */
.router-tags{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;padding-top:8px;border-top:1px dashed var(--border)}
.router-tag{font-size:11.5px;padding:3px 8px;border-radius:6px;background:var(--bg-soft);
  color:var(--text-soft);border:1px solid var(--border);display:inline-flex;align-items:center;gap:4px}
.router-tag.kb{color:#0a7d5e;background:#e6f7f1;border-color:#b8e6d4}
.router-tag.search{color:#7c3aed;background:#f3edff;border-color:#d6c2f7}
.router-tag.vps{color:#c2410c;background:#fff3eb;border-color:#fbd1b8}
.router-tag.memory{color:#1e6fdb;background:#e8f1ff;border-color:#bbd4f7}
.router-tag.router{color:#666;background:var(--bg-soft);border-color:var(--border)}



/* ===== 侧栏 ===== */
.sidebar{
  width:270px;background:var(--bg-side);border-right:1px solid var(--border-soft);
  display:flex;flex-direction:column;flex-shrink:0;transition:transform .25s ease,width .22s ease;z-index:40;
}
.side-top{padding:10px 10px 6px}
.new-chat-btn{
  display:flex;align-items:center;gap:10px;width:100%;padding:12px 14px;border-radius:12px;
  border:1px solid var(--border);background:var(--bg);font-size:14px;font-weight:600;min-height:46px;
  transition:background .15s,box-shadow .15s;
}
.new-chat-btn:hover{background:var(--bg-hover);box-shadow:var(--shadow)}
.conv-list{flex:1;overflow-y:auto;padding:6px 8px 12px;contain:content}
.conv-group{font-size:11px;font-weight:700;color:var(--text-faint);padding:12px 8px 4px;text-transform:uppercase;letter-spacing:.5px}
.conv-item{
  display:flex;align-items:center;gap:8px;padding:10px 10px;border-radius:10px;cursor:pointer;
  font-size:13.5px;color:var(--text-sub);transition:background .12s;min-height:44px;
}
.conv-item:hover{background:var(--bg-hover)}
.conv-item.active{background:var(--bg-hover);color:var(--text);font-weight:600}
.conv-item .t{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.conv-item .t mark{background:var(--accent);color:#fff;border-radius:3px;padding:0 2px;font-weight:600}
.conv-item .del{opacity:0;width:28px;height:28px;border-radius:7px;display:flex;align-items:center;justify-content:center;color:var(--text-faint)}
.conv-item:hover .del{opacity:1}
.conv-item .del:hover{color:var(--danger);background:rgba(239,68,68,.12)}
.side-foot{border-top:1px solid var(--border-soft);padding:8px;display:flex;flex-direction:column;gap:2px}
.side-foot button{display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:8px;font-size:13px;color:var(--text-sub);min-height:40px}
.side-foot button:hover{background:var(--bg-hover);color:var(--text)}
.overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:35}

/* ===== 聊天主区 ===== */
.chat-main{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--bg);position:relative}
.chat-scroll{flex:1;overflow-y:auto;scroll-behavior:auto;overscroll-behavior:contain}
.chat-inner{max-width:820px;margin:0 auto;padding:24px 20px 40px;display:flex;flex-direction:column;gap:22px}

/* ===== 对话大纲栏（右侧悬浮目录：列出本会话全部提问，点击跳转） ===== */
.chat-outline{position:absolute;right:16px;top:14px;width:212px;max-height:62vh;display:none;flex-direction:column;
  background:var(--bg-soft);border:1px solid var(--border);border-radius:12px;
  box-shadow:0 6px 22px rgba(0,0,0,.13);overflow:hidden;z-index:6}
.chat-outline.show{display:flex}
.ol-head{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:8px 10px;
  font-size:12px;color:var(--text-sub);border-bottom:1px solid var(--border);flex:none}
.ol-head b{font-weight:600}
.ol-toggle{width:22px;height:22px;border-radius:6px;display:flex;align-items:center;justify-content:center;
  color:var(--text-faint);font-size:15px;line-height:1}
.ol-toggle:hover{background:var(--bg-hover);color:var(--text)}
.ol-body{overflow-y:auto;padding:6px;display:flex;flex-direction:column;gap:2px}
.ol-item{display:block;width:100%;text-align:left;padding:6px 8px;border-radius:8px;
  font-size:12.5px;line-height:1.45;color:var(--text-sub);cursor:pointer;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ol-item:hover{background:var(--bg-hover);color:var(--text)}
.ol-item.active{background:var(--accent);color:#fff}
.ol-fab{position:absolute;right:16px;top:14px;z-index:6;display:none;width:34px;height:34px;border-radius:10px;
  align-items:center;justify-content:center;color:var(--text-sub);background:var(--bg-soft);
  border:1px solid var(--border);box-shadow:0 4px 14px rgba(0,0,0,.12)}
.ol-fab.show{display:flex}
.ol-fab:hover{background:var(--bg-hover);color:var(--text)}
/* 跳转定位时的高亮闪烁 */
.msg.jump-flash .bubble{animation:jumpFlash 1.3s ease}
@keyframes jumpFlash{0%,70%{outline:2px solid var(--accent);outline-offset:3px}100%{outline:2px solid transparent;outline-offset:3px}}
/* 窄屏空间不够，隐藏大纲栏，避免遮挡正文 */
@media (max-width:1080px){ .chat-outline,.ol-fab{display:none!important} }

/* 欢迎页 */
.welcome{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:60vh;text-align:center;padding:20px}
.welcome .logo-big{width:64px;height:64px;border-radius:18px;background:var(--accent);display:flex;align-items:center;justify-content:center;color:#fff;margin-bottom:20px;box-shadow:0 8px 24px rgba(16,163,127,.35)}
.welcome h2{font-size:24px;margin-bottom:8px;font-weight:800}
.welcome p{color:var(--text-sub);font-size:14px;margin-bottom:28px;max-width:460px}
.key-warn{margin-top:22px;padding:12px 16px;border-radius:12px;background:var(--danger-soft);color:var(--danger);font-size:13px;display:none;align-items:center;gap:8px;max-width:560px}

/* 墨墨背单词 */
.mm-check{display:flex;align-items:flex-start;gap:8px;font-size:13px;color:var(--text-sub);cursor:pointer;margin:2px 0 13px;line-height:1.6}
.mm-check input{margin-top:2px;flex-shrink:0}
/* 划词查词卡片 */
.mm-pop{position:fixed;z-index:80;width:330px;max-width:calc(100vw - 24px);background:var(--bg);border:1px solid var(--border);border-radius:14px;box-shadow:0 14px 44px rgba(0,0,0,.22);padding:14px 15px;font-size:13.5px;animation:fadein .16s ease}
.mm-pop-top{display:flex;align-items:center;gap:8px;margin-bottom:4px}
.mm-pop-word{font-size:18px;font-weight:800;letter-spacing:.2px}
.mm-pop-x{margin-left:auto;cursor:pointer;color:var(--text-sub);font-size:19px;line-height:1;padding:0 3px;user-select:none}
.mm-pop-x:hover{color:var(--text)}
.mm-pop-sec{margin-top:10px}
.mm-pop-sec .lb{font-size:11.5px;color:var(--text-sub);font-weight:700;margin-bottom:3px}
.mm-pop-sec .tx{line-height:1.7;word-break:break-word}
.mm-pop-ph{background:var(--bg-soft);border-radius:9px;padding:7px 10px;margin-top:6px;line-height:1.65}
.mm-pop-ph .en{font-weight:600}
.mm-pop-ph .cn{color:var(--text-sub);font-size:12.5px;margin-top:2px}
.mm-pop-empty{color:var(--text-sub);font-size:12.5px;line-height:1.7}
.mm-pop-act{display:flex;gap:8px;margin-top:13px}
.mm-pop-act .btn{flex:1}
/* 生词本页 */
.voc-prog{display:flex;gap:10px;margin-bottom:14px}
.voc-prog .pg{flex:1;background:var(--bg-soft);border-radius:12px;padding:11px 13px}
.voc-prog .n{font-size:21px;font-weight:800;line-height:1.2}
.voc-prog .l{font-size:11.5px;color:var(--text-sub);margin-top:3px}
.voc-chips{display:flex;flex-wrap:wrap;gap:7px;margin:11px 0 4px;min-height:4px}
.voc-chip{display:inline-flex;align-items:center;gap:6px;background:var(--bg-soft);border:1px solid var(--border-soft);border-radius:999px;padding:5px 6px 5px 11px;font-size:13px}
.voc-chip.ok{border-color:var(--accent);color:var(--accent)}
.voc-chip.bad{border-color:var(--danger);color:var(--danger)}
.voc-chip .x{cursor:pointer;opacity:.55;font-size:15px;line-height:1;padding:0 3px;user-select:none}
.voc-chip .x:hover{opacity:1}
.voc-today{font-size:12.5px;color:var(--text-sub);line-height:1.9}
.voc-today b{color:var(--text)}
.voc-empty{color:var(--text-sub);font-size:12.5px;line-height:1.8;padding:14px;background:var(--bg-soft);border-radius:10px;text-align:center}
/* 今日例句 */
.sent-item{border-top:1px solid var(--border-soft);padding:11px 0}
.sent-item:first-child{border-top:none;padding-top:2px}
.sent-word{display:flex;align-items:center;gap:8px;font-size:15px}
.sent-word b{letter-spacing:.2px}
.sent-from{font-size:11px;color:var(--text-sub);background:var(--bg-soft);border-radius:999px;padding:2px 8px}
.sent-en{margin-top:5px;line-height:1.7;font-size:13.5px;display:flex;align-items:flex-start;gap:6px}
.sent-cn{margin-top:3px;line-height:1.7;font-size:12.5px;color:var(--text-sub)}
.sent-spk{flex-shrink:0;background:none;border:none;cursor:pointer;font-size:14px;padding:1px 3px;opacity:.6;line-height:1.2}
.sent-spk:hover{opacity:1}
.sent-spk.playing{opacity:1;color:var(--accent)}
/* 助记短文：一段一个卡片，生词在文里描红 */
.sent-story{border-top:1px solid var(--border-soft);padding:12px 0}
.sent-story:first-child{border-top:none;padding-top:2px}
.sent-story-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.sent-story-no{font-size:12px;font-weight:600;color:var(--accent);
  background:var(--bg-soft);border-radius:999px;padding:2px 9px}
.sent-words{display:flex;flex-wrap:wrap;gap:5px;margin-top:7px;align-items:center}
.sent-w{font-size:11.5px;color:var(--text-sub);background:var(--bg-soft);
  border:1px solid var(--border-soft);border-radius:999px;padding:2px 8px;cursor:pointer;
  transition:all .15s;white-space:nowrap}
.sent-w:hover{color:var(--accent);border-color:var(--accent)}
.sent-hl{color:var(--accent);font-weight:600;background:rgba(255,196,0,.14);
  border-radius:3px;padding:0 2px}
.sent-story .sent-en{margin-top:7px;display:block}

/* 消息 */
.msg{display:flex;gap:12px;animation:fadein .25s ease}
@keyframes fadein{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.msg.user{flex-direction:row-reverse}
.avatar{width:32px;height:32px;border-radius:8px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700}
.msg.ai .avatar{background:var(--accent);color:#fff}
.msg.user .avatar{background:var(--bg-hover);color:var(--text-sub);order:2}
.msg-body{max-width:calc(100% - 100px);min-width:0}
.msg.user .msg-body{order:1;display:flex;flex-direction:column;align-items:flex-end}
.bubble{border-radius:var(--radius);padding:12px 16px;overflow-wrap:break-word;word-break:break-word}
.msg.user .bubble{background:var(--bubble-user);color:var(--bubble-user-text);border-bottom-right-radius:6px;white-space:pre-wrap}
.msg.ai .bubble{background:var(--bg-soft);border-bottom-left-radius:6px}
/* v4.46.11：消息操作按钮**常显**（原来 opacity:0，只有鼠标悬停在那条消息上才浮现，
   用户因此完全不知道有「引用 / 分支」这些功能）。现在默认半透明、悬停变实，
   并且按钮是「图标 + 文字」而不是光秃秃一个图标 —— 见 index.html 的 _mkActBtn。 */
.msg-actions{display:flex;flex-wrap:wrap;gap:2px;margin-top:6px;opacity:.5;transition:opacity .15s}
.msg:hover .msg-actions,.msg-actions:focus-within{opacity:1}
.msg-actions button{width:auto;height:26px;padding:0 8px;gap:5px;border-radius:7px;display:flex;align-items:center;justify-content:center;color:var(--text-faint);font-size:12px;line-height:1}
.msg-actions button:hover{background:var(--bg-hover);color:var(--text)}
.msg-actions .act-tx{white-space:nowrap}
/* AI 加词建议卡片 */
.add-words-card{margin-top:12px;padding:12px 14px;border:1px solid var(--border);border-radius:12px;background:var(--bg-soft)}
.add-words-card .aw-title{font-size:12.5px;color:var(--text-faint);margin-bottom:9px;line-height:1.5}
.add-words-card .aw-words{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:11px}
.add-words-card .aw-chip{font-size:13px;padding:3px 11px;border-radius:20px;background:var(--accent-soft);color:var(--accent);font-weight:600}
.add-words-card .aw-btn{width:auto;height:auto;padding:7px 16px;font-size:13.5px}
.typing-cursor{display:inline-block;width:7px;height:16px;background:var(--accent);vertical-align:-2px;margin-left:2px;animation:blink 1s steps(1) infinite;border-radius:1px}
@keyframes blink{50%{opacity:0}}
.thinking-wrap{font-size:12.5px;color:var(--text-faint);border-left:2px solid var(--border);padding:4px 6px 4px 12px;margin-bottom:10px;border-radius:6px;background:var(--bg-soft)}
.thinking-label{font-size:11px;font-weight:500;letter-spacing:.3px;display:flex;align-items:center;gap:6px;color:var(--text-faint);cursor:pointer;user-select:none;padding:2px 0}
.thinking-label:hover{color:var(--text-sub)}
.thinking-label .chev{margin-left:auto;transition:transform .15s}
.thinking-label .chev.open{transform:rotate(90deg)}
.thinking-body{white-space:pre-wrap;word-break:break-word;line-height:1.6;font-style:italic;max-height:300px;overflow-y:auto;margin-top:4px;display:none}
.thinking-wrap.open .thinking-body{display:block}
/* v4.46.12：**思考过程可见化**（用户原话：「等半天它也不显示任何东西……有时候都不知道
   它是在正常思考还是卡住了」）。三件事：① 首字到达前给一个**会动的**"正在思考"指示，
   让"在跑"和"卡死"能区分开；② 折叠时的标签必须**明说可以点开**（否则等于没内容）；
   ③ 刚答完的这一条**默认展开**思考，不让它"闪一下就没"。 */
.thinking-wrap.pending{border-left-color:var(--accent)}
.thinking-label .think-hint{font-size:11px;color:var(--text-faint);opacity:.8;margin-left:2px}
.thinking-label .think-secs{font-variant-numeric:tabular-nums;color:var(--text-sub);font-weight:500}
.think-dots{display:inline-flex;gap:3px;align-items:center}
.think-dots i{width:4px;height:4px;border-radius:50%;background:currentColor;animation:thinkBlink 1.2s infinite}
.think-dots i:nth-child(2){animation-delay:.2s}
.think-dots i:nth-child(3){animation-delay:.4s}
@keyframes thinkBlink{0%,80%,100%{opacity:.22}40%{opacity:1}}
.err-bubble{background:var(--danger-soft)!important;color:var(--danger)}
.empty-answer-tip{margin-top:10px;padding:8px 10px;font-size:12.5px;color:var(--text-faint);background:var(--bg-soft,#f6f6f6);border:1px dashed var(--border);border-radius:8px;line-height:1.5}

/* Markdown 渲染 */
.md{font-size:15px}
.md>*+*{margin-top:12px}
.md h1,.md h2,.md h3,.md h4{font-weight:700;line-height:1.4;margin-top:20px}
.md h1{font-size:1.35em}.md h2{font-size:1.22em}.md h3{font-size:1.1em}.md h4{font-size:1em}
.md ul,.md ol{padding-left:22px}
.md li+li{margin-top:4px}
.md a{color:var(--accent);text-decoration:none;border-bottom:1px solid transparent}
.md a:hover{border-bottom-color:var(--accent)}
.md blockquote{border-left:3px solid var(--accent);padding:2px 0 2px 14px;color:var(--text-sub)}
.md hr{border:none;border-top:1px solid var(--border);margin:16px 0}
.md code.inline{background:var(--bg-hover);padding:2px 6px;border-radius:5px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.88em}
.md table{border-collapse:collapse;width:100%;display:block;overflow-x:auto;font-size:.92em}
.md th,.md td{border:1px solid var(--border);padding:7px 12px;text-align:left}
.md th{background:var(--bg-hover);font-weight:600}
.md strong{font-weight:700}
.code-block-wrap{position:relative;margin:14px 0;border-radius:12px;overflow:hidden;border:1px solid rgba(255,255,255,.08)}
.code-head{display:flex;align-items:center;justify-content:space-between;background:#161616;padding:7px 12px}
.code-lang{color:#9b9b9b;font-size:11.5px;font-family:ui-monospace,monospace;text-transform:lowercase;letter-spacing:.4px}
.code-copy{display:flex;align-items:center;gap:5px;color:#9b9b9b;font-size:11.5px;padding:3px 8px;border-radius:6px;min-height:26px}
.code-copy:hover{background:rgba(255,255,255,.1);color:#fff}
.code-block-wrap pre{background:var(--code-bg);color:var(--code-text);padding:14px 16px;overflow-x:auto;font-size:13px;line-height:1.6}
.code-block-wrap code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
.tok-k{color:#569cd6}.tok-s{color:#ce9178}.tok-c{color:#6a9955}.tok-f{color:#dcdcaa}.tok-n{color:#b5cea8}.tok-t{color:#4ec9b0}

/* ===== 输入区 ===== */
.composer-wrap{padding:0 20px calc(14px + env(safe-area-inset-bottom));background:linear-gradient(transparent,var(--bg) 30%)}
.composer{max-width:820px;margin:0 auto;position:relative}
.mode-bar{display:flex;gap:6px;flex-wrap:wrap;margin:8px 2px 6px}
.mode-chip{font-size:12px;padding:4px 10px;border-radius:999px;border:1px solid var(--border);
  background:transparent;color:var(--text-sub);cursor:pointer;transition:all .15s;line-height:1.4}
.mode-chip:hover{border-color:var(--accent);color:var(--accent)}
.mode-chip.active{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}
.mode-bar-sep{width:1px;height:16px;background:var(--border);margin:0 2px}
.mode-chip.alarm-chip{border-color:var(--danger, #e05d5d);color:var(--danger, #e05d5d)}
.mode-chip.alarm-chip:hover{background:rgba(224,93,93,.08)}
/* 报警分析弹窗 */
.alarm-mask{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1200;display:flex;align-items:center;justify-content:center;padding:20px}
.alarm-panel{background:var(--bg);border:1px solid var(--border);border-radius:18px;width:100%;max-width:560px;max-height:86vh;display:flex;flex-direction:column;box-shadow:var(--shadow)}
.alarm-head{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--border)}
.alarm-head h3{margin:0;font-size:16px}
.alarm-body{padding:18px 20px;overflow-y:auto}
.alarm-actions{display:flex;gap:8px;margin:4px 0 14px}
.alarm-out{margin-top:6px}
.alarm-card{border:1px solid var(--border);border-radius:12px;padding:14px 16px;background:var(--bg-soft);display:flex;flex-direction:column;gap:10px}
.alarm-card .ac-head{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:6px}
.alarm-card .ac-code{font-size:15px;font-weight:700;color:var(--danger,#e05d5d)}
.alarm-card .ac-tag{font-size:11px;color:var(--text-faint);border:1px solid var(--border);border-radius:6px;padding:1px 7px}
.alarm-card .ac-sec{font-size:12px;font-weight:700;color:var(--text-sub);margin:2px 0 4px}
.alarm-card .ac-text{font-size:13px;line-height:1.7;color:var(--text)}
.alarm-card .ac-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}
.alarm-card .ac-list li{font-size:13px;line-height:1.6;padding-left:16px;position:relative;color:var(--text)}
.alarm-card .ac-list li::before{content:"▸";position:absolute;left:0;color:var(--accent)}
.alarm-card .ac-src{font-size:11px;color:var(--text-faint);margin-top:2px}
.alarm-card .ac-actions{display:flex;gap:8px;margin-top:4px;flex-wrap:wrap}
.alarm-loading{color:var(--text-sub);font-size:13px;text-align:center;padding:14px}
.alarm-err{color:var(--danger,#e05d5d);font-size:13px;text-align:center;padding:10px;background:rgba(224,93,93,.07);border-radius:8px}
.composer-box{
  display:flex;align-items:flex-end;gap:8px;background:var(--bg-soft);border:1px solid var(--border);
  border-radius:22px;padding:10px 12px;transition:border .15s,box-shadow .15s;
}
.composer-box:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px rgba(16,163,127,.12)}
#input{
  flex:1;min-width:0;border:none;background:transparent;resize:none;outline:none;font-size:16px;line-height:1.5;
  min-height:24px;max-height:180px;padding:6px 2px;color:var(--text);box-sizing:content-box;
}
#input::placeholder{color:var(--text-faint)}
.send-btn{width:44px;height:44px;border-radius:50%;background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:center;transition:background .15s,transform .1s;flex-shrink:0}
.send-btn:hover{background:var(--accent-hover)}
.send-btn:active{transform:scale(.94)}
.send-btn.stop{background:var(--text-sub)}
/* ===== v4.30.1：用量 + 模型说明 = **最下面那一行** =====
   用户原话：「token 放在最最下面，和显示的大模型放在一起，字体一样。」

   v4.30.0 我把它挪进了上面那排（● Auto / 联网），**理解错了** ——
   他说的「大模型显示的文字」是最底下这行「当前：Auto · 模型名」，
   不是上面那个模型按钮。而上面那排窄屏放不下会折行，于是 token 夹在
   「联网」和「✨自动 ⚡快速 🔍深度」中间 —— 就是他看到的那个别扭位置。

   现在：左边用量胶囊、右边模型说明，**同一行**，两段**字号完全相同** ——
   都取 `--note-fs`，改一个变量两边一起变，物理上不可能再"不一样大"。 */
.status-line{max-width:820px;margin:7px auto 0;--note-fs:12.5px}
.sl-row{display:flex;align-items:center;gap:10px;min-width:0}
.composer-note{flex:1;min-width:0;font-size:var(--note-fs);color:var(--text-faint);
  text-align:right;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.usage-bar{flex:0 0 auto;font-size:var(--note-fs);color:var(--text-sub);
  user-select:none;-webkit-user-select:none}
.usage-bar.empty{opacity:.55}
.ub-line{display:flex;align-items:center;gap:5px;flex-wrap:nowrap;white-space:nowrap;
  overflow:hidden;padding:3px 10px;border-radius:999px;background:var(--bg-soft);
  border:1px solid var(--border);cursor:pointer;transition:border-color .15s}
.ub-line:hover{border-color:var(--accent)}
.ub-body{display:flex;align-items:center;gap:5px;min-width:0;overflow:hidden;white-space:nowrap}
.ub-item{display:inline-flex;align-items:center;gap:4px}
.ub-k{color:var(--text-faint)}
.ub-v{color:var(--text);font-weight:700;font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum";letter-spacing:.2px}
.ub-sep{color:var(--border)}
.ub-unit{color:var(--text-faint)}
.ub-caret{flex-shrink:0;color:var(--text-faint);font-size:10px}
.ub-detail{margin-top:6px;padding:9px 12px;border-radius:12px;background:var(--bg-soft);
  border:1px solid var(--border);font-size:12px;line-height:1.9}
.ub-row{display:flex;gap:12px;flex-wrap:wrap;align-items:baseline}
.ub-rk{color:var(--text-faint);min-width:86px}
.ub-row b{color:var(--text);font-weight:700;font-variant-numeric:tabular-nums}
.ub-hint{margin-top:6px;padding-top:6px;border-top:1px dashed var(--border);
  font-size:11px;line-height:1.7;color:var(--text-faint)}
/* 引用回复条 */
.quote-bar{display:flex;align-items:center;gap:8px;background:var(--bg-soft);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:10px;padding:7px 10px;margin-bottom:8px;font-size:12.5px;color:var(--text-sub)}
.quote-bar svg{color:var(--text-faint);flex-shrink:0}
.quote-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-sub)}
.quote-close{width:20px;height:20px;border-radius:50%;background:var(--bg-hover);color:var(--text-faint);font-size:14px;line-height:1;display:flex;align-items:center;justify-content:center;padding:0;flex-shrink:0}
.quote-close:hover{color:var(--text)}
/* 图片上传 */
.img-preview-row{display:flex;gap:8px;padding:0 2px 8px;flex-wrap:wrap}
/* v4.29.1：**空着的时候不要占地方。**
   用户问「联网和底下的快速/深度之间为什么有个大的白空间」—— 就是这里：

     模型栏(margin-bottom 8) + 图片行(空，但 padding-bottom 8)
     + 文档行(空，但 padding-bottom 8) + 模式栏(margin-top 8) = **32px 纯白**

   这两行本来只在"选了图片/文档"时才该出现，却一直以 8px 内边距的形式占着位。
   原来的外层 margin 之间还能互相抵消，中间插进两个带 padding 的空盒子之后
   抵消不掉了，于是白得特别明显。

   用 `:empty` 而不是让 JS 去切 class：HTML 里它们是真空的、JS 清空时写的是
   `innerHTML = ""`，所以 `:empty` 永远跟真实状态一致 —— 不会出现
   "忘了同步 class，于是选了图反而不显示" 这种两处状态打架的问题。 */
.img-preview-row:empty,
.doc-chip-row:empty{display:none}
.img-thumb{position:relative;width:62px;height:62px;border-radius:10px;overflow:hidden;
  border:1px solid var(--border);background:var(--bg-soft);flex-shrink:0}
.img-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.img-thumb .x{position:absolute;top:2px;right:2px;width:18px;height:18px;border-radius:50%;
  background:rgba(0,0,0,.55);color:#fff;border:0;font-size:12px;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center;padding:0}
.img-thumb .x:hover{background:rgba(0,0,0,.75)}
.img-btn{width:40px;height:40px;border-radius:12px;border:1px solid var(--border);background:transparent;
  color:var(--text-sub);display:flex;align-items:center;justify-content:center;cursor:pointer;flex-shrink:0;
  transition:border-color .15s,color .15s,background .15s}
.img-btn:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
/* v4.30.0：单条强制联网按钮 —— 打开时**自己长出文字**。
   原来它是个孤零零的放大镜，用户问「到底是干嘛的？我也不知道是干嘛的」。
   打开时从 40×40 方块变成带字的小胶囊「🔍 本条联网」，关掉就缩回方块。 */
#web-force-btn.on{width:auto;min-width:40px;padding:0 10px;gap:5px}
.web-force-label{font-size:12px;line-height:1;white-space:nowrap;font-weight:600}
.web-force-label:empty{display:none}
/* v3.15.2：联网开关按钮 + 模式徽标（恢复 2026-09-04 移除的对话栏联网 UI） */
.web-btn{display:inline-flex;align-items:center;gap:4px;flex-shrink:0;padding:5px 10px;font-size:12px;
  border:1px solid var(--border);border-radius:8px;background:var(--bg-input);color:var(--text-soft);
  cursor:pointer;min-height:30px;transition:all .15s}
.web-btn:hover{border-color:var(--accent);color:var(--accent)}
.web-btn.on{background:var(--accent);border-color:var(--accent);color:#fff}
.web-btn.disabled{opacity:.4;pointer-events:none}
.img-btn.on{background:var(--accent);border-color:var(--accent);color:#fff}
.img-btn.disabled{opacity:.4;pointer-events:none}
/* v4.46.4：**联网按钮「二合一」** —— 状态直接长在按钮里。
   原来「联网」按钮旁边挂着一个独立的「自动/强制/关闭」徽标，但两者表达的
   **本来就是同一件事**（开=自动 / 关=关闭），并排显示只会让人以为是
   "两个功能互相影响"（用户原话：「我点了联网，那个自动就灭掉」）。
   现在只有一个控件，状态写在它自己身上；手机上也不再被隐藏（原来
   `.net-mode-badge` 在窄屏是 `display:none`，等于手机上根本看不到状态）。 */
.web-btn .web-btn-mode{
  font-size:10.5px;line-height:1.6;padding:0 6px;border-radius:8px;margin-left:1px;
  background:rgba(255,255,255,.24);color:inherit;white-space:nowrap;flex-shrink:0}
/* 关闭态：按钮本身是灰底，里面的标签也要跟着变"弱"，否则白底白字看不见 */
.web-btn:not(.on) .web-btn-mode{
  background:var(--bg-soft);color:var(--text-faint);border:1px solid var(--border)}
/* 强制联网（单条）：整个按钮换橙，一眼看出"这条一定会搜" */
.web-btn.force{background:#e08e0b;border-color:#e08e0b;color:#fff}
.web-btn.force:hover{border-color:#c97c06;color:#fff}
.msg-imgs{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.msg-imgs img{max-width:220px;max-height:220px;border-radius:10px;border:1px solid var(--border);display:block}
/* v4.39.1：消息里的**文件附件**（📎 名字 + 大小 + ↓ 下载）。
   让聊天记录里能看见"我发过这个文件" —— 用户反馈过「发了文件，历史对话里看不到」。 */
.msg-attach{display:inline-flex;align-items:center;gap:8px;margin-top:8px;padding:7px 10px;
  border:1px solid var(--border);border-radius:9px;background:var(--bg-soft);
  font-size:12.5px;max-width:100%;line-height:1.2}
.msg-attach .ic{flex-shrink:0;font-size:14px}
.msg-attach .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}
.msg-attach .sz{flex-shrink:0;color:var(--text-faint);font-size:11px;font-variant-numeric:tabular-nums}
.msg-attach .dl{flex-shrink:0;color:var(--accent);cursor:pointer;white-space:nowrap;font-size:11.5px}
.msg-attach .dl:hover{text-decoration:underline}
/* 文档问答 */
.doc-chip-row{display:flex;gap:8px;padding:0 2px 8px;flex-wrap:wrap}
/* 空的文档行同样不占地方（理由见上面 .img-preview-row 那段） */
.doc-chip-row:empty{display:none}
.doc-chip{display:inline-flex;align-items:center;gap:6px;max-width:100%;padding:5px 10px;border-radius:999px;
  background:var(--accent-soft);color:var(--accent);font-size:12.5px;border:1px solid var(--accent)}
.doc-chip b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
.doc-chip .x{width:18px;height:18px;border-radius:50%;background:rgba(0,0,0,.12);color:inherit;border:0;
  font-size:11px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;flex-shrink:0}
.doc-menu{position:absolute;bottom:calc(100% + 8px);right:0;z-index:60;min-width:280px;max-width:min(94vw,340px);
  background:var(--bg-panel);border:1px solid var(--border);border-radius:12px;
  box-shadow:0 12px 32px rgba(0,0,0,.18);padding:8px;display:none;max-height:60vh;overflow-y:auto}
.doc-menu.open{display:block}
.dm-head{font-size:11.5px;color:var(--text-faint);padding:4px 6px 8px;line-height:1.6}
.dm-up{width:100%;display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 10px;border-radius:8px;
  border:1px dashed var(--border);background:transparent;color:var(--text-sub);font-size:13px;cursor:pointer;
  transition:border-color .15s,color .15s;margin-bottom:6px}
.dm-up:hover{border-color:var(--accent);color:var(--accent)}
.dm-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;border-radius:8px;border:0;
  background:transparent;color:var(--text);font-size:13px;cursor:pointer;text-align:left;min-height:38px}
.dm-item:hover{background:var(--bg-hover)}
.dm-item.active{background:var(--accent-soft);color:var(--accent)}
.dm-item .t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dm-item .n{font-size:11px;color:var(--text-faint);flex-shrink:0}
/* v4.39.0：文档项的「↓ 下载原文件」按钮（只有存了原档才渲染）。仿 .del 的样式，
   悬停用 accent 色而不是 danger —— 下载是"正面"动作，别跟删除一个颜色。 */
.dm-item .dl{width:22px;height:22px;border-radius:6px;border:0;background:transparent;color:var(--text-faint);
  font-size:14px;line-height:1;cursor:pointer;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center}
.dm-item .dl:hover{color:var(--accent);background:var(--accent-soft)}
.dm-item .del{width:22px;height:22px;border-radius:6px;border:0;background:transparent;color:var(--text-faint);
  cursor:pointer;font-size:13px;flex-shrink:0;display:flex;align-items:center;justify-content:center}
.dm-item .del:hover{color:var(--danger);background:var(--danger-soft)}
.dm-empty{font-size:12px;color:var(--text-faint);padding:10px 6px;line-height:1.6}
/* ── v4.50.0：视频入口菜单。定位与 .doc-menu 完全同一套（祖先 .composer 是 position:relative），
      所以它和文档菜单不会一个贴边、一个飘。 ── */
.video-menu{position:absolute;bottom:calc(100% + 8px);right:0;z-index:60;width:min(94vw,340px);
  background:var(--bg-panel);border:1px solid var(--border);border-radius:12px;
  box-shadow:0 12px 32px rgba(0,0,0,.18);padding:10px;display:none}
.video-menu.open{display:block}
.vm-input{width:100%;box-sizing:border-box;padding:9px 10px;border-radius:8px;
  border:1px solid var(--border);background:var(--bg-soft);color:var(--text);
  font-size:13px;margin-bottom:8px;font-family:inherit}
.vm-input:focus{outline:none;border-color:var(--accent)}
/* ── v4.50.0：视频结果卡片 ── */
.video-card{margin-top:4px;padding:9px 10px;border-radius:10px;
  border:1px solid var(--border);background:var(--bg-soft)}
.vc-title{font-size:12.5px;color:var(--text);line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.vc-sub{font-size:11px;color:var(--text-faint);margin-top:3px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.vc-kb{font-size:11px;color:var(--text-faint);margin-top:5px;line-height:1.5;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.vc-kb.on{color:#0a7d5e}
.vc-link{display:inline-block;font-size:11.5px;color:var(--accent);margin-top:6px}
.vc-link:hover{text-decoration:underline}
/* ── v4.50.0：新对话首屏的能力提示 ──
   ⚠️ 选择器必须是 `.welcome p.cap-hint`（两个类 + 元素）：
     只写 `.cap-hint` 的话，`.welcome p`（0,1,1）的 `margin-bottom:28px` 会赢，
     这条提示就会被撑开一大截、把「尚未配置 API Key」那块挤下去。 */
.welcome p.cap-hint{font-size:12.5px;color:var(--text-faint);line-height:1.7;
  margin-bottom:6px;max-width:460px}
.welcome p.cap-hint b{color:var(--text-sub);font-weight:600}

/* ===== 模型选择器（贴合输入框上方） ===== */
.topbar-spacer{margin-left:auto}
.model-bar{position:relative;display:flex;align-items:center;gap:8px;margin-bottom:8px;flex-wrap:wrap}
.model-btn{
  display:inline-flex;align-items:center;gap:7px;max-width:min(360px,72vw);
  padding:6px 12px;border:1px solid var(--border);border-radius:999px;
  background:var(--bg-soft);color:var(--text);font-size:13px;cursor:pointer;
  transition:border-color .15s,background .15s;
}
.model-btn:hover{border-color:var(--accent)}
.model-btn.open{border-color:var(--accent);background:var(--accent-soft)}
.model-btn .chev{opacity:.55;flex-shrink:0;transition:transform .18s}
.model-btn.open .chev{transform:rotate(180deg)}
.model-btn-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tag-badge{display:inline-block;flex-shrink:0;font-size:10px;line-height:1.5;padding:1px 5px;border-radius:5px;
  font-weight:700;letter-spacing:.02em;border:1px solid transparent;white-space:nowrap}
.tag-badge[hidden]{display:none}
.tag-badge.paid{color:#b45309;background:rgba(245,158,11,.16);border-color:rgba(245,158,11,.42)}
.tag-badge.free{color:#15803d;background:rgba(34,197,94,.14);border-color:rgba(34,197,94,.38)}
.tag-badge.trial{color:#1d4ed8;background:rgba(96,165,250,.14);border-color:rgba(96,165,250,.38)}
.tag-badge.auto{color:#7c3aed;background:rgba(139,92,246,.15);border-color:rgba(139,92,246,.42)}
.mm-note{margin:0 10px 6px 30px;font-size:11px;line-height:1.5;color:var(--text-faint)}
.mm-sep{margin:8px 10px;border-top:1px solid var(--border)}
.img-btn.on{background:var(--accent);border-color:var(--accent);color:#fff}
.msg-sources{margin-top:10px;padding-top:9px;border-top:1px solid var(--border)}
.token-stats{margin-top:8px;padding-top:7px;border-top:1px dashed var(--border);
  font-size:12px;color:var(--text-faint);letter-spacing:.2px;line-height:1.5}
.token-stats b{color:var(--text-muted);font-weight:600}
.src-head{font-size:11px;color:var(--text-faint);margin-bottom:6px;display:flex;align-items:center;gap:5px}
.src-list{display:flex;flex-direction:column;gap:3px}
.src-item{display:flex;align-items:baseline;gap:6px;font-size:12px;color:var(--accent);
  text-decoration:none;padding:3px 5px;border-radius:6px;line-height:1.4}
.src-item:hover{background:var(--bg-hover)}
.src-n{flex-shrink:0;min-width:15px;height:15px;line-height:15px;text-align:center;font-size:10px;
  border-radius:4px;background:var(--accent-soft);color:var(--accent)}
.src-t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* v4.51.9：用户给的网址没读到 —— 必须让用户**看见**（别让一篇长文冒充"我读过了"）。
   用 --danger 而不是新开变量：它**浅色/深色两套都定义了**（#ef4444 / #f87171），
   新变量只会定义在 :root，深色主题下会变成一个看不清的颜色。 */
.read-failed{border-top-color:var(--danger)}
.read-failed .src-head{color:var(--danger);font-weight:600}
.src-dead{font-size:12px;color:var(--text-sub);word-break:break-all;
  padding:2px 5px;line-height:1.45}
.src-why{font-size:11px;color:var(--text-faint);margin-top:5px;line-height:1.5}
.src-eng{flex-shrink:0;font-size:10px;color:var(--text-faint);background:var(--bg-soft);
  border:1px solid var(--border);border-radius:4px;padding:0 5px;line-height:15px;white-space:nowrap}
.mm-chan-key{flex-shrink:0;font-size:11px;color:var(--text-faint);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  padding:1px 5px;border:1px solid var(--border);border-radius:5px;background:var(--bg-input)}
.status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--text-faint)}
.status-dot.ok{background:#22c55e;box-shadow:0 0 0 3px rgba(34,197,94,.16)}
.status-dot.bad{background:var(--danger);box-shadow:0 0 0 3px rgba(239,68,68,.16)}
.status-dot.checking{background:#f59e0b;animation:dotPulse 1s ease-in-out infinite}
@keyframes dotPulse{0%,100%{opacity:1}50%{opacity:.3}}
.recheck-btn{
  display:inline-flex;align-items:center;gap:5px;padding:6px 11px;font-size:12px;
  border:1px solid var(--border);border-radius:999px;background:transparent;
  color:var(--text-sub);cursor:pointer;transition:border-color .15s,color .15s;
}
.recheck-btn:hover{border-color:var(--accent);color:var(--accent)}
.recheck-btn[disabled]{opacity:.5;cursor:default}
.model-menu{
  display:none;position:absolute;left:0;bottom:calc(100% + 8px);
  width:min(440px,calc(100vw - 32px));max-height:min(430px,58vh);overflow-y:auto;
  background:var(--bg-soft);border:1px solid var(--border);border-radius:14px;
  box-shadow:var(--shadow);z-index:60;padding:6px;
}
.model-menu.open{display:block}
.mm-head{
  display:flex;align-items:center;gap:8px;padding:8px 10px 10px;
  font-size:12px;color:var(--text-sub);border-bottom:1px solid var(--border-soft);margin-bottom:4px;
}
.mm-head b{color:var(--text);font-size:12.5px}
.mm-head .legend{margin-left:auto;display:flex;gap:10px;font-size:11px}
.mm-head .legend span{display:inline-flex;align-items:center;gap:4px}
.mm-chan{display:flex;align-items:center;gap:8px;padding:9px 10px 5px;font-size:12.5px;font-weight:600;color:var(--text)}
.mm-chan .status-dot{margin-right:1px}
.mm-chan-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mm-chan-msg{margin-left:auto;font-size:11px;font-weight:400;color:var(--text-faint);flex-shrink:0;max-width:44%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mm-chan-msg.bad{color:var(--danger)}
.mm-chan-msg.ok{color:#22c55e}
.mm-chan-click{cursor:pointer;border-radius:8px;margin:0 2px;transition:background .12s}
.mm-chan-click:hover{background:var(--bg-hover)}
.mm-sec-title{padding:9px 10px 3px;font-size:11.5px;font-weight:600;color:var(--text-faint);letter-spacing:.03em}
.mm-fam{padding:7px 10px 3px 30px;font-size:11px;color:var(--text-faint)}
.mm-model-chan{margin-left:6px;font-size:10.5px;color:var(--text-faint);background:var(--bg-soft);border:1px solid var(--border);border-radius:6px;padding:1px 6px;vertical-align:1px}
/* v4.40.0：模型的**能力验证状态**图标（⏳ 未验证 / ✅ 已验证 / ❌ 失败）。
   新接入的模型默认没有 verify 记录 → 显示 ⏳ —— 用户要的「新模型默认未验证」就靠它一眼可见。 */
.mm-verify{flex-shrink:0;margin-right:4px;font-size:11px;font-style:normal;line-height:1;cursor:help}
.mm-verify.untested{opacity:.45}   /* 未测：弱化，别抢视线 */
.mm-verify.fail{opacity:.85}
/* v4.41.0：**模型能力对比表**（🧪 菜单 → 模型能力对比）。
   ✅ 已验证 / ❌ 失败 / ⏳ 已声明未测 / — 未声明。窄屏可横向滚动。 */
.ct-wrap{overflow-x:auto;margin-top:10px;-webkit-overflow-scrolling:touch}
.ct-table{width:100%;border-collapse:collapse;font-size:12.5px}
.ct-table th{text-align:center;font-weight:600;color:var(--text-sub);padding:6px 4px;
  border-bottom:1px solid var(--border);font-size:11.5px;white-space:nowrap}
.ct-table th:first-child{text-align:left}
.ct-table td{padding:7px 4px;text-align:center;border-bottom:1px solid var(--border-soft)}
.ct-table td.ct-model{text-align:left;line-height:1.35;word-break:break-all}
.ct-sub{display:block;font-size:10.5px;color:var(--text-faint);margin-top:2px}
.ct-none{color:var(--text-faint);opacity:.5}
.ct-un{opacity:.6}
.ct-btn{border:1px solid var(--border);background:var(--bg-soft);color:var(--text);
  border-radius:7px;padding:4px 10px;font-size:11.5px;cursor:pointer;white-space:nowrap}
.ct-btn:hover{border-color:var(--accent);color:var(--accent)}
/* v4.42.0：**用途推荐**（说一句要做的事 → 看该用哪个模型）。
   分段展示"已验证 / 未验证 / 自费"，让"该不该信它"一目了然；
   自费那段用虚线框 —— 与"推荐"在视觉上就该有区别。 */
.rec-box{margin-bottom:14px}
.rec-row{display:flex;gap:8px}
.rec-row input{flex:1;min-width:0;padding:8px 11px;border:1px solid var(--border);
  border-radius:8px;font-size:13px;background:var(--bg-input);color:var(--text)}
.rec-result{margin-top:10px}
.rec-loading{font-size:12.5px;color:var(--text-faint);padding:6px 2px}
.rec-cap{font-size:12.5px;color:var(--text-sub);margin-bottom:8px}
.rec-seg{margin-bottom:9px}
.rec-seg-t{font-size:11.5px;font-weight:600;color:var(--text-sub);margin-bottom:4px}
.rec-item{display:flex;align-items:baseline;gap:8px;padding:5px 8px;border-radius:7px;
  background:var(--bg-soft);margin-bottom:4px;font-size:12.5px;flex-wrap:wrap}
.rec-m{font-weight:600;color:var(--text)}
.rec-p{font-size:11px;color:var(--text-faint)}
.rec-w{font-size:11px;color:var(--text-faint);margin-left:auto}
.rec-note{font-size:12px;color:var(--text-sub);line-height:1.7;padding:6px 8px;
  background:var(--bg-soft);border-radius:7px}
.rec-seg.paid .rec-item{background:transparent;border:1px dashed var(--border)}
.mm-item{
  display:flex;align-items:center;gap:8px;padding:8px 10px 8px 30px;border-radius:8px;
  cursor:pointer;font-size:13px;color:var(--text);
}
.mm-item:hover{background:var(--bg-hover)}
.mm-item.active{background:var(--accent-soft);color:var(--accent);font-weight:600}
.mm-item .tick{margin-left:auto;flex-shrink:0;opacity:0}
.mm-item.active .tick{opacity:1}
.mm-empty{padding:16px 12px;text-align:center;font-size:12.5px;color:var(--text-faint)}
.dev-list{display:flex;flex-direction:column;gap:8px}
.dev-item{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:10px 12px;background:var(--bg-soft);border-radius:10px;border:1px solid var(--border)}
.dev-item .dev-left{min-width:0;flex:1}
.dev-item .dev-name{font-size:13px;font-weight:600;color:var(--text)}
.dev-item .dev-meta{font-size:11.5px;color:var(--text-faint);margin-top:2px;line-height:1.5;word-break:break-all}
.dev-item .tag-cur{font-size:11px;color:var(--accent);border:1px solid var(--accent);border-radius:6px;padding:1px 6px;margin-left:4px}
.dev-item .dev-note{font-size:11px;color:var(--text-faint);white-space:nowrap}
.btn-xs{padding:4px 10px;font-size:12px}

/* ===== 设置抽屉 ===== */
.drawer-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:50}
.drawer{
  position:fixed;top:0;right:0;bottom:0;width:480px;max-width:100vw;background:var(--bg);
  z-index:60;transform:translateX(100%);transition:transform .28s ease;display:flex;flex-direction:column;
  box-shadow:-8px 0 30px rgba(0,0,0,.18);
}
.drawer.open{transform:none}
.drawer-head{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--border-soft)}
.drawer-head h3{font-size:17px;font-weight:700}
.drawer-body{flex:1;overflow-y:auto;padding:16px 20px 40px}
.tabs{display:flex;gap:6px;background:var(--bg-soft);border-radius:12px;padding:4px;margin-bottom:18px}
.tabs button{flex:1;padding:9px;border-radius:9px;font-size:13.5px;font-weight:600;color:var(--text-sub);min-height:42px}
.tabs button.active{background:var(--bg);color:var(--text);box-shadow:var(--shadow)}

/* 渠道卡片 */
.prov-card{border:1px solid var(--border);border-radius:14px;padding:14px 16px;margin-bottom:12px;background:var(--bg)}
.prov-row{display:flex;align-items:center;gap:10px}
.prov-dot{width:9px;height:9px;border-radius:50%;background:var(--text-faint);flex-shrink:0}
.prov-dot.on{background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,.7)}
.prov-name{font-weight:700;font-size:14.5px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.prov-acts{display:flex;gap:2px}
.prov-acts button{width:34px;height:34px;border-radius:8px;display:flex;align-items:center;justify-content:center;color:var(--text-faint)}
.prov-acts button:hover{background:var(--bg-hover);color:var(--text)}
.prov-meta{font-size:12px;color:var(--text-faint);margin-top:6px;line-height:1.5;word-break:break-all}
.prov-models{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px;align-items:center}
.pm-label{font-size:11px;color:var(--text-faint);flex-shrink:0;margin-right:1px}
.model-chip{font-size:11px;line-height:1.6;padding:2px 7px;border-radius:6px;background:var(--bg-input);
  border:1px solid var(--border);color:var(--text-soft);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.model-chip.muted{opacity:.55;font-style:italic}
/* v4.33.0：模型能力标签 —— 「模型名 识图·工具」一目了然 */
.cap-tag{font-style:normal;font-size:10px;margin-left:5px;padding:0 4px;border-radius:4px;
  background:var(--accent-soft);color:var(--accent)}
/* v4.35.0：自动同步标出的「上游不认这个模型」—— 删除线 + ⚠，但**不删**、仍可选中 */
.model-chip.retired{text-decoration:line-through;text-decoration-color:var(--danger);
  border-color:var(--danger);opacity:.85}
.dead-tag{font-style:normal;font-size:10px;margin-left:5px;padding:0 4px;border-radius:4px;
  background:transparent;color:var(--danger);border:1px solid var(--danger)}
/* v4.35.0：预算可信度提示（金额是估算的 / 哪些模型没价格） */
.budget-note{font-size:12px;line-height:1.7;color:var(--text-soft);margin-top:8px;
  padding:6px 9px;border-radius:6px;background:var(--bg-input);border:1px solid var(--border)}
.budget-note b{color:var(--text)}
/* v4.36.0：企微会话的"受保护"锁标（列表里一眼看出它不可删） */
.conv-item .im-lock{font-size:10px;line-height:1;margin-left:5px;opacity:.75;flex-shrink:0}
/* v4.33.0：模型能力勾选表（编辑渠道时） */
.caps-box{margin-top:6px;max-height:260px;overflow:auto}
.caps-row{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:3px 0}
.caps-model{font-size:11px;color:var(--text-soft);min-width:120px;max-width:46%;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.caps-chip{display:inline-flex;align-items:center;gap:3px;font-size:11px;line-height:1.6;padding:2px 7px;
  border-radius:6px;background:var(--bg-input);border:1px solid var(--border);color:var(--text-soft);
  cursor:pointer;user-select:none}
.caps-chip input{margin:0;width:12px;height:12px;cursor:pointer}
.caps-chip.on{background:var(--accent-soft);border-color:var(--accent);color:var(--accent)}
.chip-more{font-size:11px;padding:3px 9px;border-radius:6px;background:transparent;border:1px dashed var(--border);
  color:var(--accent);cursor:pointer;min-height:auto;width:auto}
.chip-more:hover{background:var(--accent-soft);border-style:solid}
.edit-form{margin-top:12px;padding-top:12px;border-top:1px dashed var(--border)}
.edit-form .field{margin-bottom:12px}
.edit-form .field input,.edit-form .field textarea{font-size:16px}
.models-editor textarea{min-height:72px;font-size:16px;font-family:ui-monospace,monospace;line-height:1.6}
.hint{font-size:12px;color:var(--text-faint);line-height:1.6;margin-top:4px}
.form-actions{display:flex;gap:8px;margin-top:6px;flex-wrap:wrap}
.form-actions .btn{padding:10px 16px;min-height:42px;font-size:13.5px}
.link-btn{color:var(--accent);font-weight:600;font-size:13px;padding:8px 4px}
.sec-title{font-size:13px;font-weight:700;color:var(--text-sub);margin:20px 0 10px;text-transform:uppercase;letter-spacing:.5px}
.set-card{border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px}
.set-card h4{font-size:14.5px;margin-bottom:10px}
.set-card textarea{width:100%;min-height:110px;padding:12px;border:1px solid var(--border);border-radius:10px;background:var(--bg-input);outline:none;font-size:16px;resize:vertical}
.set-card textarea:focus{border-color:var(--accent)}
/* 长期记忆 */
.mem-add-row{display:flex;gap:8px;margin-bottom:10px}
.mem-add-row input{flex:1;min-width:0;font-size:16px;padding:10px 12px;border:1px solid var(--border);
  border-radius:10px;background:var(--bg-input);color:var(--text);outline:none}
.mem-add-row input:focus{border-color:var(--accent)}
.mem-add-row .btn{min-height:44px;white-space:nowrap}
.mem-list{display:flex;flex-direction:column;gap:6px}
.mem-item{display:flex;align-items:center;gap:8px;padding:8px 10px;border:1px solid var(--border);
  border-radius:10px;background:var(--bg-soft)}
.mem-item .t{flex:1;min-width:0;font-size:13px;line-height:1.5;color:var(--text);word-break:break-all}
.mem-item .del{width:26px;height:26px;border-radius:7px;border:0;background:transparent;color:var(--text-faint);
  cursor:pointer;font-size:14px;flex-shrink:0;display:flex;align-items:center;justify-content:center}
.mem-item .del:hover{color:var(--danger);background:var(--danger-soft)}
.mem-empty{font-size:12px;color:var(--text-faint);padding:6px 2px}
/* 记忆库增强：标签 / 搜索 / 置顶 / 启停 / 提炼 */
.mem-head{display:flex;align-items:center;gap:8px;margin-bottom:10px;flex-wrap:wrap}
.mem-hint-txt{flex:1;font-size:12px;color:var(--text-faint);line-height:1.6;min-width:200px}
.mem-extract-btn{display:inline-flex;align-items:center;gap:5px;padding:8px 12px;font-size:12.5px;
  border:1px dashed var(--accent);border-radius:9px;background:transparent;color:var(--accent);
  cursor:pointer;min-height:36px;transition:all .15s;white-space:nowrap}
.mem-extract-btn:hover{background:var(--accent-soft);border-style:solid}
.mem-extract-btn[disabled]{opacity:.5;cursor:default}
.mem-add-row select{flex-shrink:0;font-size:14px;padding:9px 10px;border:1px solid var(--border);
  border-radius:10px;background:var(--bg-input);color:var(--text);outline:none;min-height:44px;cursor:pointer}
.mem-add-row select:focus{border-color:var(--accent)}
.mem-filter-row{display:flex;gap:8px;margin-bottom:10px;flex-wrap:wrap;align-items:center}
#mem-search{flex:1;min-width:140px;font-size:14px;padding:8px 12px;border:1px solid var(--border);
  border-radius:10px;background:var(--bg-input);color:var(--text);outline:none;min-height:36px}
#mem-search:focus{border-color:var(--accent)}
#mem-search::placeholder{color:var(--text-faint)}
.mem-tags{display:flex;gap:6px;flex-wrap:wrap}
.mem-tag-chip{font-size:12px;padding:4px 11px;border-radius:999px;border:1px solid var(--border);
  background:var(--bg-soft);color:var(--text-sub);cursor:pointer;transition:all .15s;min-height:28px;line-height:1.4}
.mem-tag-chip:hover{border-color:var(--accent);color:var(--accent)}
.mem-tag-chip.on{background:var(--accent);border-color:var(--accent);color:#fff}
.mem-item{display:flex;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--border);
  border-radius:10px;background:var(--bg-soft);flex-wrap:wrap}
.mem-item .t{flex:1;min-width:0;font-size:13px;line-height:1.5;color:var(--text);word-break:break-all}
.mem-item.off{opacity:.62}
.mem-item.off .t{text-decoration:line-through}
.mem-item .ic{width:26px;height:26px;border-radius:7px;border:0;background:transparent;color:var(--text-faint);
  cursor:pointer;font-size:13px;flex-shrink:0;display:flex;align-items:center;justify-content:center;line-height:1;padding:0}
.mem-item .ic:hover{background:var(--bg-hover);color:var(--text)}
.mem-item .ic.on{color:var(--accent)}
.mem-tag{font-style:normal;font-size:10.5px;line-height:1.6;padding:1px 7px;border-radius:6px;flex-shrink:0;font-weight:700}
.mem-tag.personal{color:#1d4ed8;background:rgba(96,165,250,.14);border:1px solid rgba(96,165,250,.38)}
.mem-tag.project{color:#7c3aed;background:rgba(139,92,246,.15);border:1px solid rgba(139,92,246,.42)}
.mem-tag.pref{color:#b45309;background:rgba(245,158,11,.16);border:1px solid rgba(245,158,11,.42)}
.mem-tag.work{color:#15803d;background:rgba(34,197,94,.14);border:1px solid rgba(34,197,94,.38)}
.mem-tag.other{color:#6b6b6e;background:rgba(128,128,128,.12);border:1px solid rgba(128,128,128,.3)}
.mem-src{font-size:10px;color:var(--text-faint);border:1px solid var(--border);border-radius:5px;
  padding:0 5px;line-height:16px;flex-shrink:0;white-space:nowrap}
.mem-src.auto{color:#7c3aed;border-color:rgba(139,92,246,.42);background:rgba(139,92,246,.12)}
.mem-mt{font-size:11px;color:var(--text-faint);flex-shrink:0}
.mem-foot{font-size:12px;color:var(--text-faint);margin-top:10px;line-height:1.6}
/* ===== Memory Manager 记忆管理器面板 ===== */
.mem-mask{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:85;display:none}
.mem-mask.open{display:block}
.mem-manager{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:86;
  width:min(860px,94vw);max-height:84vh;display:none;flex-direction:column;
  background:var(--bg);border:1px solid var(--border);border-radius:16px;
  box-shadow:0 24px 60px rgba(0,0,0,.25)}
.mem-manager.open{display:flex}
.mm-head{display:flex;align-items:center;gap:10px;padding:14px 18px;border-bottom:1px solid var(--border)}
.mm-head h3{margin:0;font-size:16px}
.mm-stats{margin-left:4px;font-size:12px;color:var(--text-faint);flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mm-autolearn{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--text-sub);
  cursor:pointer;padding:6px 10px;border:1px solid var(--border);border-radius:999px;flex-shrink:0;user-select:none}
.mm-autolearn input{accent-color:var(--accent);cursor:pointer}
.mm-autolearn:has(input:checked){border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.mm-tabs{display:flex;gap:6px;padding:10px 18px 0;border-bottom:1px solid var(--border-soft)}
.mm-tabs button{padding:8px 16px;border-radius:9px 9px 0 0;font-size:13.5px;font-weight:600;
  color:var(--text-sub);border:1px solid transparent;border-bottom:none;min-height:38px}
.mm-tabs button.active{background:var(--bg-soft);color:var(--text);border-color:var(--border)}
.mm-tabs button:hover:not(.active){color:var(--text)}
.mm-toolbar{display:flex;gap:8px;align-items:center;padding:12px 18px 6px;flex-wrap:wrap}
.mem-search-box{position:relative;flex:1;min-width:160px}
.mem-search-box svg{position:absolute;left:11px;top:50%;transform:translateY(-50%);width:13px;height:13px;color:var(--text-faint);pointer-events:none}
#mem-search{width:100%;padding:8px 12px 8px 30px;font-size:13.5px;border:1px solid var(--border);
  border-radius:10px;background:var(--bg-input);color:var(--text);outline:none;min-height:36px}
#mem-search:focus{border-color:var(--accent)}
.mm-acts{display:flex;gap:6px;flex-wrap:wrap}
.mm-act-btn{display:inline-flex;align-items:center;gap:4px;padding:7px 12px;font-size:12.5px;
  border:1px solid var(--border);border-radius:9px;background:var(--bg-soft);color:var(--text-sub);
  cursor:pointer;min-height:36px;transition:all .15s;white-space:nowrap}
.mm-act-btn:hover{border-color:var(--accent);color:var(--accent)}
.mm-act-btn.primary{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.mm-act-btn.primary:hover{background:var(--accent);color:#fff}
.mm-act-btn[disabled]{opacity:.5;cursor:default}
.mem-manager .mem-add-row{padding:10px 18px 2px}
.mem-manager .mem-add-row input{flex:1}
.mm-list{flex:1;overflow-y:auto;padding:10px 18px 8px;display:flex;flex-direction:column;gap:6px;min-height:180px}
.mm-list .mem-empty{text-align:center;padding:26px 10px;font-size:13px}
.mm-foot{display:flex;align-items:center;gap:10px;padding:10px 18px 14px;border-top:1px solid var(--border-soft)}
.mm-foot span{flex:1;font-size:12px;color:var(--text-faint)}
.mm-danger{font-size:12px;color:var(--danger);border:1px solid rgba(239,68,68,.4);border-radius:8px;
  padding:6px 12px;background:transparent;cursor:pointer;min-height:32px}
.mm-danger:hover{background:var(--danger-soft)}
.mem-short .mem-head{background:var(--bg-soft);border:1px solid var(--border);border-radius:10px;padding:10px 12px;margin-bottom:8px}
.mem-conv-badge{font-size:10px;color:var(--text-faint);border:1px solid var(--border);border-radius:5px;
  padding:0 5px;line-height:16px;flex-shrink:0;white-space:nowrap;max-width:160px;overflow:hidden;text-overflow:ellipsis}
/* 四层记忆：用户画像 / 项目记忆 / 压缩摘要 */
.mm-sec-label{font-size:11.5px;font-weight:700;color:var(--text-faint);letter-spacing:.4px;
  margin:12px 0 6px;display:flex;align-items:center;gap:6px}
.prof-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}
.prof-row input{flex:1;min-width:0;font-size:13.5px;padding:8px 11px;border:1px solid var(--border);
  border-radius:9px;background:var(--bg-input);color:var(--text);outline:none;min-height:38px}
.prof-row input:focus{border-color:var(--accent)}
.prof-row input.prof-key{flex:0 0 30%;max-width:180px;font-weight:600}
.prof-row .ic{width:30px;height:30px;border-radius:8px;border:0;background:transparent;color:var(--text-faint);
  cursor:pointer;font-size:15px;flex-shrink:0;display:flex;align-items:center;justify-content:center;line-height:1;padding:0}
.prof-row .ic:hover{background:var(--bg-hover);color:var(--danger)}
.proj-card{border:1px solid var(--border);border-radius:12px;background:var(--bg-soft);padding:12px 14px;margin-bottom:10px}
.proj-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.proj-name{font-size:14px;font-weight:700;flex:1;min-width:120px;color:var(--text);cursor:pointer}
.proj-name:hover{color:var(--accent)}
.proj-desc{font-size:11.5px;color:var(--text-faint);line-height:1.5;margin-top:2px;flex-basis:100%;word-break:break-all}
.proj-items{margin-top:8px;display:flex;flex-direction:column;gap:4px}
.proj-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:8px;font-size:13px;color:var(--text-sub)}
.proj-item:hover{background:var(--bg-hover)}
.proj-item .t{flex:1;min-width:0;word-break:break-all}
.proj-item .x{width:22px;height:22px;border-radius:6px;border:0;background:transparent;color:var(--text-faint);
  cursor:pointer;font-size:12px;flex-shrink:0;display:flex;align-items:center;justify-content:center}
.proj-item .x:hover{color:var(--danger);background:var(--danger-soft)}
.proj-add{display:flex;gap:6px;margin-top:8px}
.proj-add input{flex:1;min-width:0;font-size:13px;padding:7px 10px;border:1px dashed var(--border);
  border-radius:8px;background:var(--bg-input);color:var(--text);outline:none;min-height:34px}
.proj-add input:focus{border-color:var(--accent);border-style:solid}
.proj-add button{flex-shrink:0;min-height:34px}
.sum-item{border-left:3px solid var(--accent);background:var(--accent-soft);border-radius:0 10px 10px 0;
  padding:8px 12px;margin-bottom:6px;display:flex;align-items:center;gap:8px;font-size:13px;flex-wrap:wrap}
.sum-item .t{flex:1;min-width:0;word-break:break-all;color:var(--text)}
/* 移动端记忆条目：文本占满整行，标签/按钮折到下方，避免逐字换行 */
@media (max-width:600px){
  .mem-item .t,.sum-item .t{flex-basis:100%;margin-bottom:2px}
  .mem-item,.sum-item{gap:6px}
  .prof-row{flex-direction:column;align-items:stretch}
  .prof-row input.prof-key{flex:1;max-width:none}
  .prof-row .ic{align-self:flex-end}
}
.sum-item .ic{width:24px;height:24px;border-radius:6px;border:0;background:transparent;color:var(--text-faint);
  cursor:pointer;font-size:12px;flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:0}
.sum-item .ic:hover{background:var(--bg-hover);color:var(--text)}
.mm-note{font-size:11.5px;color:var(--text-faint);line-height:1.6;padding:8px 12px;background:var(--bg-soft);
  border:1px dashed var(--border);border-radius:10px;margin-bottom:8px}
/* ===== 知识库面板（RAG） ===== */
.kb-mask{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:85;display:none}
.kb-mask.open{display:block}
.kb-panel{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:86;
  width:min(760px,94vw);max-height:84vh;display:none;flex-direction:column;
  background:var(--bg);border:1px solid var(--border);border-radius:16px;
  box-shadow:0 24px 60px rgba(0,0,0,.25)}
.kb-panel.open{display:flex}
.kb-head{display:flex;align-items:center;gap:10px;padding:14px 18px;border-bottom:1px solid var(--border)}
.kb-head h3{margin:0;font-size:16px}
.kb-toggle{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--text-sub);
  cursor:pointer;padding:6px 10px;border:1px solid var(--border);border-radius:999px;flex-shrink:0;user-select:none}
.kb-toggle input{accent-color:var(--accent);cursor:pointer}
.kb-toggle:has(input:checked){border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.kb-stats{margin-left:auto;font-size:12px;color:var(--text-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.kb-body{flex:1;overflow-y:auto;padding:14px 18px 20px}
.kb-upload{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}
.kb-up-btn{display:inline-flex;align-items:center;gap:8px;justify-content:center;padding:13px 16px;
  font-size:14px;border:2px dashed var(--border);border-radius:12px;background:var(--bg-soft);
  color:var(--text-sub);cursor:pointer;transition:border-color .15s,color .15s;min-height:52px}
.kb-up-btn:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.kb-hint{font-size:11.5px;color:var(--text-faint);text-align:center;line-height:1.6}
.upload-progress{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);z-index:220;
  background:var(--bg-input);border:1px solid var(--border);border-radius:14px;padding:14px 20px;
  box-shadow:var(--shadow);min-width:280px;max-width:calc(100% - 40px)}
.upload-progress .up-title{font-size:13px;font-weight:600;color:var(--text);margin-bottom:8px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.upload-progress .up-bar{width:100%;height:6px;background:var(--bg-soft);border-radius:3px;overflow:hidden}
.upload-progress .up-fill{height:100%;background:var(--accent);border-radius:3px;
  transition:width .2s ease;width:0%}
.upload-progress .up-info{display:flex;justify-content:space-between;align-items:center;
  margin-top:6px;font-size:11.5px;color:var(--text-faint)}
.upload-progress .up-pct{font-weight:600;color:var(--accent)}
.kb-search{display:flex;gap:8px;align-items:center;margin-bottom:10px}
.kb-search svg{flex-shrink:0;color:var(--text-faint)}
#kb-query{flex:1;min-width:0;font-size:13.5px;padding:9px 12px;border:1px solid var(--border);
  border-radius:10px;background:var(--bg-input);color:var(--text);outline:none;min-height:38px}
#kb-query:focus{border-color:var(--accent)}
.kb-result{margin-bottom:10px;display:flex;flex-direction:column;gap:6px}
.kb-hit{border:1px solid var(--border);border-radius:10px;background:var(--bg-soft);padding:9px 12px}
.kb-hit .h-name{font-size:12px;font-weight:700;color:var(--accent);margin-bottom:4px;display:flex;align-items:center;gap:6px}
.kb-hit .h-text{font-size:12.5px;color:var(--text-sub);line-height:1.6;max-height:96px;overflow:hidden;
  display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical}
.kb-file{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid var(--border);
  border-radius:11px;background:var(--bg-soft);margin-bottom:8px}
.kb-file .f-ic{width:34px;height:34px;border-radius:9px;background:var(--accent-soft);color:var(--accent);
  display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800;flex-shrink:0}
.kb-file .f-name{flex:1;min-width:0;font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kb-file .f-meta{font-size:11px;color:var(--text-faint);flex-shrink:0;white-space:nowrap}
/* v4.46.10：「疑似重复」角标（按内容指纹判定，与文件名无关） */
.kb-file .f-dup{font-size:10px;font-weight:700;padding:2px 6px;border-radius:6px;flex-shrink:0;
  background:var(--danger-soft);color:var(--danger);white-space:nowrap;cursor:help}
.kb-file .del{width:26px;height:26px;border-radius:7px;border:0;background:transparent;color:var(--text-faint);
  cursor:pointer;font-size:14px;flex-shrink:0;display:flex;align-items:center;justify-content:center}
.kb-file .del:hover{color:var(--danger);background:var(--danger-soft)}
.kb-empty{text-align:center;color:var(--text-faint);font-size:13px;padding:26px 10px;line-height:1.7}
.kb-loading{text-align:center;color:var(--text-faint);font-size:13px;padding:20px 10px}
.kb-up-row{display:flex;gap:8px;align-items:stretch}
.kb-up-row .kb-up-btn{flex:1}
.kb-folder-select{font-size:12.5px;padding:0 8px;border:1px solid var(--border);border-radius:10px;
  background:var(--bg-input);color:var(--text);outline:none;min-width:90px;max-width:130px;cursor:pointer}
.kb-folder-select:focus{border-color:var(--accent)}
.kb-folder-new{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:42px;
  border:1px solid var(--border);border-radius:10px;background:var(--bg-soft);color:var(--text-sub);cursor:pointer;transition:.15s}
.kb-folder-new:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.kb-folder-group{margin-bottom:10px}
.kb-folder-header{display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:10px;
  background:var(--bg-soft);cursor:pointer;user-select:none;margin-bottom:6px}
.kb-folder-header:hover{background:var(--accent-soft)}
.kb-folder-header .fh-icon{flex-shrink:0;color:var(--accent);display:flex;align-items:center;transition:transform .15s}
.kb-folder-header.collapsed .fh-icon{transform:rotate(-90deg)}
.kb-folder-header .fh-name{flex:1;font-size:13px;font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kb-folder-header .fh-count{font-size:11px;color:var(--text-faint);flex-shrink:0}
.kb-folder-header .fh-actions{display:flex;gap:2px;flex-shrink:0}
.kb-folder-header .fh-actions button{width:24px;height:24px;border-radius:6px;border:0;background:transparent;
  color:var(--text-faint);cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:.6;transition:.15s}
.kb-folder-header .fh-actions button:hover{opacity:1;color:var(--accent)}
.kb-folder-header .fh-actions .fh-del:hover{color:var(--danger)}
.kb-folder-group .kb-file{margin-left:20px}
.kb-folder-group.collapsed .kb-folder-body{display:none}
.kb-file .f-move{width:26px;height:26px;border-radius:7px;border:0;background:transparent;color:var(--text-faint);
  cursor:pointer;flex-shrink:0;display:flex;align-items:center;justify-content:center;opacity:.5;transition:.15s}
.kb-file .f-move:hover{opacity:1;color:var(--accent)}

/* ══════════ v4.46.4：窄屏下知识库文件**改成两排** ══════════════════════════
   用户原话：「手机屏幕上显示的知识库上传文件都看不到名字，只能看到后面的日期
   和一些按钮。能不能做成两排显示，上面是名字，底下是日期和按钮？」

   根因不是"名字太长"，而是**这一行里唯一可压缩的只有名字**：
     · `.f-ic`      34px  flex-shrink:0
     · `.f-name`    flex:1, **min-width:0**   ← 只有它会被压
     · `.f-meta`    flex-shrink:0（"N 段 · NK 字 · 日期"，约 150px）
     · 三个按钮     各 26px，flex-shrink:0
   固定部分合计约 310px + 内边距，在 360px 的手机上留给名字的只有二十几像素
   ⇒ 省略号吃掉一切，看着就像"名字根本不存在"。

   修法：窄屏改用 **grid**，第一行「图标 + 名字」，第二行「段数/日期 + 三个按钮」。
   为什么用 grid 而不是继续 flex：要的是"名字独占第一行、其余整体落到第二行"，
   这在 flex 里得靠 order + flex-basis 硬凑，还容易和按钮顺序打架；
   grid 能把"谁在哪一行哪一列"直接写出来。 */
@media (max-width:640px){
  .kb-file{
    display:grid;
    grid-template-columns:30px minmax(0,1fr) 26px 26px 26px;
    align-items:center;
    column-gap:6px;
    row-gap:3px;
  }
  .kb-file .f-ic{grid-area:1/1/2/2;width:30px;height:30px;font-size:10px}
  .kb-file .f-name{
    grid-area:1/2/2/6;                 /* 第一行，横跨到最右 */
    white-space:normal;                /* 允许换行，不再只靠省略号 */
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
    overflow:hidden;line-height:1.35;
  }
  .kb-file .f-meta{grid-area:2/2/3/3;font-size:11px;min-width:0;
                   overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* 三个按钮落到第二行右侧（DOM 里它们是 1、2、3 个 button，故用 nth-of-type） */
  .kb-file .f-move:nth-of-type(1){grid-area:2/3/3/4}
  .kb-file .f-move:nth-of-type(2){grid-area:2/4/3/5}
  .kb-file .del{grid-area:2/5/3/6}
  /* 文件夹缩进在窄屏是纯浪费（20px 换不来可读性），减半 */
  .kb-folder-group .kb-file{margin-left:10px}
}
/* 任务中心 */
.task-mask{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:90;display:none}
.task-mask.open{display:block}
.task-panel{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:91;width:min(680px,94vw);
  max-height:86vh;display:none;flex-direction:column;background:var(--bg-panel);border:1px solid var(--border);
  border-radius:16px;box-shadow:0 24px 60px rgba(0,0,0,.25)}
.task-panel.open{display:flex}
.task-head{display:flex;align-items:center;gap:10px;padding:14px 18px;border-bottom:1px solid var(--border)}
.task-head h3{margin:0;font-size:16px}
.task-head .icon-btn{margin-left:auto}
.task-body{padding:14px 18px;overflow-y:auto}
.task-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
.task-item{border:1px solid var(--border);border-radius:12px;padding:12px;background:var(--bg);cursor:pointer;
  text-align:left;transition:border-color .15s,background .15s;min-height:74px}
.task-item:hover{border-color:var(--accent);background:var(--bg-hover)}
.task-item b{display:flex;align-items:center;gap:6px;font-size:13.5px;margin-bottom:4px}
.task-item span{font-size:11.5px;color:var(--text-sub);line-height:1.5}
.task-item .t-dot{width:7px;height:7px;border-radius:50%;background:var(--accent);flex-shrink:0}
.task-out{margin-top:14px;border:1px solid var(--border);border-radius:12px;overflow:hidden}
.task-out-head{display:flex;align-items:center;gap:10px;padding:9px 12px;background:var(--bg-soft);
  border-bottom:1px solid var(--border);font-size:13px}
.task-out-head b{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#task-out-pre{margin:0;padding:12px;font-size:12px;line-height:1.6;max-height:300px;overflow:auto;
  white-space:pre-wrap;word-break:break-all;color:var(--text);font-family:ui-monospace,Menlo,Consolas,monospace}
.task-out .form-actions{padding:10px 12px;border-top:1px solid var(--border)}
.task-ai{margin-top:10px}
/* 执行确认弹窗 */
.exec-mask{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:95;display:none}
.exec-mask.open{display:block}
.exec-modal{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:96;width:min(560px,92vw);
  background:var(--bg-panel);border:1px solid var(--border);border-radius:16px;padding:20px;
  box-shadow:0 24px 60px rgba(0,0,0,.3);display:none}
.exec-modal.open{display:block}
.exec-modal h4{margin:0 0 10px;font-size:16px}
.exec-modal pre{margin:0 0 14px;padding:12px;border:1px solid var(--border);border-radius:10px;
  background:var(--bg-soft);font-size:12.5px;line-height:1.6;white-space:pre-wrap;word-break:break-all;
  max-height:220px;overflow:auto;color:var(--text)}
/* VPS 状态概览 */
.vps-status{border:1px solid var(--border);border-radius:12px;padding:12px;background:var(--bg)}
.vs-head{display:flex;align-items:center;gap:8px;font-size:13.5px;margin-bottom:8px}
.vs-head b{font-weight:700}
.vs-refresh{width:26px;height:26px;border-radius:7px;border:1px solid var(--border);background:transparent;
  color:var(--text-sub);cursor:pointer;font-size:14px;line-height:1;display:flex;align-items:center;justify-content:center}
.vs-refresh:hover{color:var(--accent);border-color:var(--accent)}
.vs-ts{margin-left:auto;font-size:11px;color:var(--text-faint)}
.vs-row{display:flex;align-items:center;gap:8px;font-size:12.5px;padding:3px 0}
.vs-label{color:var(--text-sub);flex-shrink:0;width:56px}
.vs-val{color:var(--text);word-break:break-all;line-height:1.5}
.vs-bar-row{display:flex;align-items:center;gap:8px;font-size:12.5px;padding:3px 0}
.vs-bar{flex:1;min-width:60px;height:8px;border-radius:99px;background:var(--bg-hover);overflow:hidden}
.vs-fill{height:100%;border-radius:99px;transition:width .4s}
.vs-loading{font-size:12.5px;color:var(--text-faint);padding:6px 0}
.danger-zone button{width:100%;margin-top:8px}

/* ===== Toast ===== */
#toasts{position:fixed;top:18px;left:50%;transform:translateX(-50%);z-index:200;display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none;width:calc(100% - 40px);max-width:420px}
.toast{
  background:var(--text);color:var(--bg);padding:11px 20px;border-radius:12px;font-size:13.5px;font-weight:500;
  box-shadow:var(--shadow);animation:toastIn .25s ease;max-width:100%;display:flex;align-items:center;gap:8px;
}
.toast.err{background:var(--danger);color:#fff}
.toast.ok{background:#16a34a;color:#fff}
@keyframes toastIn{from{opacity:0;transform:translateY(-12px)}to{opacity:1;transform:none}}

.empty-list{text-align:center;color:var(--text-faint);font-size:13px;padding:30px 10px}

/* ===== 增强：会话搜索 / 重命名 / 编辑重发 / 折叠 / 拖拽上传 ===== */
.conv-search-wrap{position:relative;padding:2px 10px 8px}
.conv-search-wrap>svg{position:absolute;left:20px;top:calc(50% + 2px);transform:translateY(-50%);width:14px;height:14px;color:var(--text-faint);pointer-events:none}
#conv-search{width:100%;padding:9px 30px 9px 32px;border:1px solid var(--border);border-radius:10px;background:var(--bg-input);font-size:13px;outline:none;color:var(--text);min-height:38px;transition:border-color .15s}
#conv-search:focus{border-color:var(--accent)}
#conv-search::placeholder{color:var(--text-faint)}
.conv-search-clear{position:absolute;right:16px;top:calc(50% + 2px);transform:translateY(-50%);width:20px;height:20px;border-radius:50%;background:var(--bg-hover);color:var(--text-faint);font-size:12px;line-height:1;display:none;align-items:center;justify-content:center;padding:0}
.conv-search-wrap.has-val .conv-search-clear{display:flex}
.conv-search-clear:hover{color:var(--text)}
.conv-item .rn{opacity:0;width:28px;height:28px;border-radius:7px;display:flex;align-items:center;justify-content:center;color:var(--text-faint)}
.conv-item:hover .rn{opacity:1}
.conv-item .rn:hover{color:var(--accent);background:rgba(16,163,127,.12)}
/* ===== 多选模式 ===== */
.conv-item .ms-check{width:20px;height:20px;border-radius:50%;border:2px solid var(--border);display:none;align-items:center;justify-content:center;flex-shrink:0;transition:border-color .15s}
.conv-item .ms-check::after{content:"";width:10px;height:10px;border-radius:50%;background:var(--accent);transform:scale(0);transition:transform .15s}
.conv-item.ms-selected .ms-check{border-color:var(--accent)}
.conv-item.ms-selected .ms-check::after{transform:scale(1)}
body.ms-mode .conv-item .ms-check{display:flex}
body.ms-mode .conv-item .rn,body.ms-mode .conv-item .del{display:none !important}
body.ms-mode .conv-item.active{background:transparent}
.ms-bar{position:fixed;bottom:0;left:0;right:0;background:var(--bg-card);border-top:1px solid var(--border);display:none;align-items:center;gap:6px;padding:8px 12px;z-index:100;box-shadow:0 -2px 12px rgba(0,0,0,.12);max-width:380px}
body.ms-mode .ms-bar{display:flex}
body.ms-mode .side-foot{display:none}
.ms-bar .ms-count{font-size:13px;color:var(--text-sub);flex:1;white-space:nowrap}
.ms-bar button{padding:8px 14px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;border:none;white-space:nowrap}
.ms-bar .ms-btn-all{background:var(--bg-hover);color:var(--text)}
.ms-bar .ms-btn-del{background:rgba(239,68,68,.12);color:var(--danger)}
.ms-bar .ms-btn-del:disabled{opacity:.4;cursor:not-allowed}
.ms-bar .ms-btn-exp{background:var(--accent);color:#fff}
.ms-bar .ms-btn-exp:disabled{opacity:.4;cursor:not-allowed}
.ms-bar .ms-btn-cancel{background:var(--bg-hover);color:var(--text-sub)}
.msg.editing .bubble{outline:2px dashed var(--accent);outline-offset:2px}
.composer.drag-over .composer-box{border-color:var(--accent);box-shadow:0 0 0 3px rgba(16,163,127,.18)}
.code-acts{display:flex;gap:2px;align-items:center}
.desktop-only{display:none}
@media (min-width:769px){
  .desktop-only{display:inline-flex!important}
  .sb-collapsed .sidebar{width:0;border-right:none;overflow:hidden}
  .sb-collapsed .side-top,.sb-collapsed .side-foot{display:none}
}

/* ===== 响应式 ===== */
@media (max-width:768px){
  .sidebar{position:fixed;top:0;bottom:0;left:0;transform:translateX(-100%);box-shadow:8px 0 30px rgba(0,0,0,.2)}
  .sidebar.open{transform:none}
  .overlay.show{display:block}
  .drawer{width:100vw}
  .chat-inner{padding:12px 10px 24px;gap:14px}
  .composer-wrap{padding:0 8px calc(8px + env(safe-area-inset-bottom))}
  .msg{gap:8px}
  .avatar{width:28px;height:28px;border-radius:7px;font-size:11px}
  .msg-body{max-width:calc(100% - 44px)}
  .bubble{padding:10px 12px}
  .md{font-size:16px}
  .topbar .brand span{display:none}
  .welcome h2{font-size:20px}
  .drawer-body{padding:14px 14px 40px}
  .code-block-wrap pre{font-size:12px}
  .msg-actions{opacity:1}   /* 移动端无 hover，复制/重试按钮永远显示 */
  /* 输入框更紧凑：缩小发送按钮、圆角与内边距，给正文多留空间 */
  /* v3.29: 消息操作按钮也永远显示 */
  .composer-box{border-radius:18px;padding:6px 8px;gap:6px}
  #input{font-size:16px;padding:6px 4px;min-height:22px}
  .send-btn{width:40px;height:40px}
  /* v4.31.0：最下面那一行 —— 用量总数 + 模型说明，**同一行、同一字号**。
     v4.30.0 我把渠道说明在手机上隐藏了、把用量挪到了上面那排；
     用户随后说明他要的是「token 放在最最下面，和显示的大模型放在一起，字体一样」——
     他说的「大模型显示的文字」就是这行渠道说明。所以现在：说明恢复显示，
     用量回到它旁边，两者共用 --note-fs 一个变量（改一处两边一起变）。 */
  .status-line{--note-fs:12px;margin-top:5px}
  .sl-row{gap:6px}
  .ub-line{padding:2px 9px;gap:4px}
  .ub-unit{font-size:11px}
  .ub-detail{font-size:12.5px;padding:8px 10px}
  .ub-rk{min-width:78px}
  /* v4.31.1：手机端**恢复显示「检测」**。
     它原来是 `.recheck-btn{display:none}`（早在 v4.27.2 之前就这样），
     理由是"低频 + 省地方"。但用户找不到它了：
       「手机上那个大模型的『检测』按钮没有了，我不知道是你设置了什么不需要了还是怎么样的」
     —— 一个按钮悄悄消失，比它占的那点地方更让人不安。
     而且当初挤的原因已经不存在：用量胶囊搬去了最下面那一行，
     现在这一排是 [模型] [检测] [联网]，实测宽度够（模型名"Auto"时约 220px / 可用 344px）。
     「复制会话」仍然隐藏 —— 它真的低频，而且手机上有"导出/打印"的替代路径。 */
  .model-btn{max-width:min(240px,58vw)}
  /* v4.31.3：手机端这一排只留「模型 / 检测 / 联网」。
     上面 v4.31.1 那句注释写着「复制会话仍然隐藏」，但它当时是被
     `.recheck-btn{display:none}` 顺带藏掉的 —— v4.31.1 删掉那条规则后，
     它跟着回来了，这一排就成了 4 个按钮；而 `.model-bar` 是 flex-wrap:wrap，
     窄屏上会**折成两行**，把用户要的正文空间又吃回去。
     现在按原意收掉它，同时**在 ⋯ 菜单里补了「复制当前会话（纯文本）」**，
     所以这是"挪个位置"，不是"按钮凭空消失"（历史上正是后者让用户以为坏了）。 */
  #copy-conv-btn{display:none}
  /* v4.29.0 曾在这里把「自动/强制/关闭」角标藏掉（理由：信息「联网」按钮上已经有了，
     一行里出现两个「自动」既占地方又容易看混）。
     v4.46.4：那个角标已经**彻底并进「联网」按钮**（二合一），所以这条规则连同
     角标本身一起去掉了 —— 桌面端同样受益（用户 2026-09-17 报的正是桌面端）。 */
  /* 模式栏一行横向滑动，不换行省高度 */
  .mode-bar{margin:6px 2px 4px;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .mode-bar::-webkit-scrollbar{display:none}
  .mode-chip{flex-shrink:0}
}
@media (min-width:769px){ .desktop-hide{display:none!important} }
/* v3.29: 触屏设备（手机/平板/触屏笔记本）无 hover 能力，操作按钮永远可见 */
@media (hover: none){ .msg-actions{opacity:1!important} }
/* ---- 记忆提炼结果通知（对话内） ---- */
.mem-result-notice {
  display:flex; gap:10px; align-items:flex-start;
  margin:12px 8px; padding:12px 14px;
  background:var(--bg-soft); border:1px solid var(--border);
  border-radius:10px; font-size:13px;
  animation:memFadeIn .3s ease;
}
@keyframes memFadeIn { from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:translateY(0)} }
.mem-notice-icon { font-size:20px; line-height:1.4; }
.mem-notice-body { flex:1; min-width:0; }
.mem-notice-title { font-weight:600; margin-bottom:6px; }
.mem-notice-list { color:var(--text-gray); line-height:1.6; }
.mem-notice-list .mem-tag {
  display:inline-block; font-size:11px; padding:0 5px;
  border-radius:3px; background:var(--bg-hover); margin-right:2px;
}
.mem-notice-acts { margin-top:8px; display:flex; gap:10px; }
/* ---- 扁平化记忆列表 ---- */
.mem-item { display:flex; align-items:center; gap:8px; padding:8px 10px; border-bottom:1px solid var(--border); font-size:13px; }
.mem-item.disabled { opacity:0.5; }
.mem-item.pinned { background:var(--bg-hover); }
.mem-type-tag { display:inline-block; font-size:10px; padding:1px 6px; border-radius:3px; color:#fff; white-space:nowrap; }
.mem-type-tag.tag-profile { background:#4a90d9; }
.mem-type-tag.tag-preference { background:#7c5cbf; }
.mem-type-tag.tag-project { background:#2ea97a; }
.mem-type-tag.tag-auto { background:#d9a44a; }
.mem-text { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.mem-ts { font-size:11px; color:var(--text-gray); white-space:nowrap; }
.mm-empty { text-align:center; padding:30px 16px; color:var(--text-gray); font-size:14px; }

/* ═══════════════════════ v3.43.0 追加 ═══════════════════════ */

/* iOS：输入框字号 <16px 时，聚焦会触发整页缩放。仅在触摸设备上放大，桌面保持紧凑。 */
@media (pointer: coarse){
  input, textarea, select{font-size:16px}
}

/* 顶部安全区：index.html 用了 viewport-fit=cover，但原先只处理了底部安全区 */
.topbar{padding-top:env(safe-area-inset-top)}

/* 深色模式下让原生控件（checkbox / select / 滚动条）跟随主题 */
:root{color-scheme:light}
[data-theme="dark"]{color-scheme:dark}

/* 打印 / 存 PDF：只留对话正文（手机端由系统打印面板生成 PDF，零依赖） */
@media print{
  .topbar, .sidebar, .ms-bar, .composer-wrap, .composer, .overlay,
  .alarm-mask, .task-mask, .mem-mask, .kb-mask, .exec-mask, .drawer-mask,
  .ol-fab, .ol-panel, .more-menu{display:none !important}
  html, body, #view-app, .app-body{height:auto !important; overflow:visible !important}
  .chat-scroll{overflow:visible !important; height:auto !important}
  .msg-actions, .code-copy{display:none !important}
}

/* ═══════════ v3.44.0 ═══════════ */
/* 回到顶部：fixed 定位，不依赖父级布局；滚过 600px 才出现 */
/* ⚠️ v4.46.14：bottom 不再写死 104px。
   真 Chrome 实测（`_probe_geom.py`）：平板 834 宽下箭头 (766,819,38×38) 与
   发送按钮 (741,856,44×44) **真的交叠 19×1 px**；手机 390 宽下虽未交叠也只差
   18px，输入框一长就压上去 —— 用户原话「发送按钮和置顶箭头重合在一起了」。
   根因：箭头钉在视口底边 104px，而输入区实测高 163~220px，箭头整颗**落在输入区里**。
   改成跟着输入区真实高度走：JS 把 .composer-wrap 的高度写进 --composer-h。 */
.to-top-btn{position:fixed;right:14px;bottom:calc(var(--composer-h,104px) + 14px);z-index:60;width:38px;height:38px;border-radius:50%;
  background:var(--bg-card);border:1px solid var(--border);color:var(--text);font-size:17px;line-height:1;
  box-shadow:0 2px 10px rgba(0,0,0,.16);display:none;cursor:pointer}
.to-top-btn.on{display:block}
.to-top-btn:active{transform:scale(.94)}

/* ═══════════ v3.45.1 ═══════════ */
/* 消息时间戳：只在有新消息的 ts 时出现，旧消息没有就不显示 */
/* v4.46.11：order:99 —— 时间戳排到按钮行最后（它是最先被塞进 .msg-actions 的，
   原来按钮隐身时看不出来，现在按钮常显，时间排在前面就碍眼了）。 */
.msg-time{font-size:11px;color:var(--text);opacity:.5;margin-left:8px;align-self:center;order:99;
  font-variant-numeric:tabular-nums;white-space:nowrap}
@media print{ .msg-time{opacity:.7} }

/* ═══════════════════════════════════════════════════════════════════════
   v4.31.3 — 交互反馈 / 可访问性 / 移动端打磨
   ───────────────────────────────────────────────────────────────────────
   这一段的规则**只做新增**，不改写上面任何既有选择器的行为：
   动效、焦点环、原生控件配色、手机手势与安全区。逐条都写了"为什么"。
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. 统一的按下反馈 ────────────────────────────────────────────────
   原来只有 `.send-btn` / `.to-top-btn` 写了 `:active`（它们出现得早），
   其余一排按钮按下去**毫无反应**：手机上手指点完没有任何确认感，
   于是会怀疑"我到底点上没有"而重复点。
   ⚠️ 必须把 transition 写全（transform/opacity + 原有的 border/color/background），
   只写自己那一份会把组件原有的过渡**整条顶掉**（后写的 transition 是覆盖而非追加）。 */
.btn, .icon-btn, .ol-fab, .to-top-btn,
.recheck-btn, .web-btn, .img-btn, .model-btn, .mode-chip, .send-btn, .mm-item{
  transition:transform var(--dur-1) var(--ease-std),
             opacity var(--dur-1) var(--ease-std),
             background-color var(--dur-1) var(--ease-std),
             border-color var(--dur-1) var(--ease-std),
             color var(--dur-1) var(--ease-std),
             box-shadow var(--dur-1) var(--ease-std);
}
.btn:active, .icon-btn:active, .ol-fab:active, .to-top-btn:active,
.recheck-btn:active, .web-btn:active, .img-btn:active, .model-btn:active,
.mode-chip:active, .send-btn:active{
  transform:scale(.94);          /* 与既有的 .send-btn:active / .to-top-btn:active 同款 */
}
/* 菜单项是整行，缩放在整行上很怪 —— 用背景变深代替 */
.mm-item:active{background:var(--bg-hover)}

/* ── 2. 键盘焦点可见 ──────────────────────────────────────────────────
   桌面端用 Tab 走一圈时，按钮只有浏览器默认的黑色轮廓（和主题不搭）；
   而一批输入框是 `outline:none` + 只把边框染成主题色，**太淡**。
   这里统一成主题色焦点环。
   ⚠️ 输入区（.composer-box）例外：它已有 `:focus-within` 光圈，
   再叠一层就是双环 —— 所以把里面的元素排除掉。 */
.btn:focus-visible, .icon-btn:focus-visible, .ol-fab:focus-visible,
.to-top-btn:focus-visible, .recheck-btn:focus-visible, .web-btn:focus-visible,
.model-btn:focus-visible, .mode-chip:focus-visible, .mm-item:focus-visible,
input:focus-visible:not(#input), select:focus-visible,
textarea:focus-visible:not(#input){
  outline:2px solid var(--accent);
  outline-offset:2px;
}
.composer-box :focus-visible{outline:none}   /* 容器光圈已经足够，避免双环 */

/* ── 3. 选中文字用主题色（原来是系统蓝，深色主题里很跳） ───────────── */
::selection{background:var(--accent-soft);color:var(--text)}

/* ── 4. 滚动条 ────────────────────────────────────────────────────────
   WebKit 那两条早就有了；补 `scrollbar-width/scrollbar-color`，
   让 Firefox 与新一代内核也用细滚动条，而不是默认的粗灰条。 */
*{scrollbar-width:thin;scrollbar-color:rgba(128,128,128,.45) transparent}

/* ── 5. 「减少动态效果」 ──────────────────────────────────────────────
   只关**装饰性**动效（进出场、滑动、缩放），
   **保留**信息性动画 —— `.status-dot.checking` 的呼吸点表示"正在检测"，
   `.typing-cursor` 的闪烁表示"正在输出"，关掉它们等于把状态藏起来。 */
@media (prefers-reduced-motion: reduce){
  .msg, .mem-result-notice, .toast, .drawer, .sidebar, .ol-panel, .modal,
  .msg-actions, .composer-box, .recheck-btn, .mode-chip, .img-btn, .send-btn{
    animation-duration:.001ms !important;
    transition-duration:.001ms !important;
  }
}

/* ── 6. 手机端手势与安全区 ──────────────────────────────────────────── */
@media (max-width:768px){
  /* 双击放大在手机上会把"连点两下"变成缩放；去掉它（双指缩放仍可用），
     顺手消掉 300ms 点击延迟 —— 按钮"按下去跟手"的体感来自这一条。 */
  button, [data-act], [data-act-change], .mode-chip, .mm-item, .conv-item,
  .recheck-btn, .web-btn, .model-btn{
    touch-action:manipulation;
  }
  /* iOS 横屏会把正文自动放大，同一份 CSS 在竖屏/横屏宽度对不上 —— 钉住 100% */
  html{-webkit-text-size-adjust:100%}
  /* 刘海屏横屏时左右也要留安全区，否则输入区贴边、圆角被切 */
  .composer-wrap{
    padding-left:calc(8px + env(safe-area-inset-left));
    padding-right:calc(8px + env(safe-area-inset-right));
  }
}

/* ── 7. 地址栏收起/展开时的高度 ───────────────────────────────────────
   手机浏览器上下滑动会隐藏地址栏，`100%` 不跟着变，于是底部常被切掉一截
   （输入框只露一半）。`dvh` 会跟着可视视口走；不支持的浏览器忽略这条，
   仍用上面原有的 `height:100%`。 */
@supports (height:100dvh){
  html, body{height:100dvh}
}

/* ═══════════════════════════════════════════════════════════════════════
   v4.46.14
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. 多选入口常显（原来只有 ⋯ 菜单里那一项 + 长按会话项） ─────────────
   用户原话：「手机和平板上没有这个功能，我没法针对我发的一些对话，挨个快速选中」。
   查完：功能在（`enterMultiSelect`），但两条入口一条要滚 ⋯ 菜单、一条是**没人知道的长按**
   —— 功能存在但发现不了 = 功能不存在（v4.46.11 立的判据）。
   这条按钮放在会话搜索框正下方，一开侧栏就看得见。 */
.ms-entry-btn{
  display:flex;align-items:center;justify-content:center;gap:7px;
  width:calc(100% - 20px);margin:0 10px 8px;padding:9px 12px;
  border:1px dashed var(--border);border-radius:10px;background:transparent;
  color:var(--text-sub);font-size:13px;font-weight:600;cursor:pointer;
  min-height:40px;transition:background .15s,color .15s,border-color .15s;
}
.ms-entry-btn:hover{background:var(--bg-hover);color:var(--text);border-color:var(--accent)}
.ms-entry-btn:active{transform:scale(.98)}
body.ms-mode .ms-entry-btn{display:none}   /* 已在多选态，入口自身让位给底部操作条 */

/* ── 2. 「上一轮被中断」提示条 ────────────────────────────────────────────
   用户原话：「生成对话的时候，如果切换模式（比如从手机模式换成桌面模式），
             生成就会中断，不给结果」。
   查完：这不是服务端的问题 —— 浏览器**换视图/刷新会重载页面**，进行中的 SSE 流被掐断，
   服务端日志原话：`[relay] client disconnected mid-stream — 前端未收完整轮，消息可能残缺`
   （今天 4 次，全部 content_chars=0，即只收到思考、正文一个字没到）。
   页面重载拦不住（浏览器行为），但可以让它**看得见、一键接上**，而不是悄悄留半句。 */
.interrupt-bar{
  display:flex;align-items:center;gap:8px;margin:0 0 8px;padding:9px 11px;
  border:1px solid rgba(217,119,6,.45);border-radius:10px;
  background:rgba(217,119,6,.10);color:var(--text);font-size:13px;line-height:1.45;
}
.interrupt-bar[hidden]{display:none}
.interrupt-bar .ib-text{flex:1;min-width:0}
.interrupt-bar .ib-btn{
  flex-shrink:0;padding:7px 13px;border:none;border-radius:8px;cursor:pointer;
  background:var(--accent);color:#fff;font-size:13px;font-weight:600;white-space:nowrap;
}
.interrupt-bar .ib-btn:active{transform:scale(.96)}
.interrupt-bar .ib-x{
  flex-shrink:0;width:24px;height:24px;padding:0;border:none;border-radius:50%;
  background:transparent;color:var(--text-sub);font-size:15px;line-height:1;cursor:pointer;
}
.interrupt-bar .ib-x:hover{background:var(--bg-hover);color:var(--text)}
@media (max-width:768px){
  .interrupt-bar{font-size:12.5px;padding:8px 9px;gap:6px}
  .interrupt-bar .ib-btn{padding:7px 10px;font-size:12.5px}
}


