/* style.css —— adapter-web 的样式。
 *
 * ★ 2026-10-10 重构：配色改用 DeepSeek Harness 的设计 token（vendor/ 里那两份）。
 *   原先的 --bg/--fg/--ai/--me 是粗粒度手调的，现在换成它的三层体系：
 *     --dsw-static-*    原始色板
 *     --dsw-alias-*     语义（bg-layer / label / border / state）
 *     --dsw-specific-*  组件级（bubble / input-major / sidebar / menu）
 *   ★ 好处：暗/亮两套它都备好了，我们不用自己调第二遍。
 *
 * 布局是三栏（学它的 ui-layout）：
 *   侧栏 260px（收起 56px）| 主内容 | 弹窗
 *   ★ 窗口 <1024px 侧栏变抽屉；手机同理。
 */

/* ─────────── 我们自己的尺寸变量（颜色都用 --dsw-*）─────────── */

:root {
  --sb-w: 260px;          /* 侧栏展开宽（它默认 280，我们窄一点够用） */
  --sb-w-collapsed: 56px; /* 收起后留一条控制栏 */
  --radius: var(--dsw-radius-md, 12px);
  --radius-lg: var(--dsw-radius-lg, 16px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
  --ease: var(--ds-ease-in-out, cubic-bezier(.4, 0, .2, 1));
  --dur: var(--ds-transition-duration, .2s);

  /* ★ 输入区两层底色（主人 2026-10-12：想单独调，所以提出来）
   *   --composer-bg  卡片【外面】那一圈（#composer 的底）
   *   --card-bg      卡片【本身】的底
   * ★ 主人 10-12 定的分工（浏览器实测确认）：
   *   卡片外那一圈要【透明】、卡片自己要【保留白底】。
   *   所以 --card-bg 不能是 transparent —— 那会让卡片也变透（亮色下就成一片白）。
   * ★ 暗色下 --dsw-specific-input-major = bluish-850（比页面底 bluish-950 亮一档）；
   *   亮色下 = bluish-00 = 纯白 —— 跟页面底同色，所以亮色下卡片靠【边框】显形。
   */
  --composer-bg: transparent;
  --card-bg: var(--dsw-specific-input-major);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  height: 100%; margin: 0; overflow: hidden;
  -webkit-text-size-adjust: 100%; text-size-adjust: 100%;
  overscroll-behavior: none;
}

body {
  background: var(--dsw-alias-bg-base);
  color: var(--dsw-alias-label-primary);
  font-family: var(--dsw-font-family);
  font-size: 15px; line-height: 1.6;
}

input, textarea, button, select { font-family: inherit; }
input, textarea { font-size: 16px; }   /* ★ ≥16px：不然 iOS 聚焦时会自动放大整页 */

button { cursor: pointer; border: 0; background: none; color: inherit; }

/* ─────────── 通用小件 ─────────── */

.btn {
  padding: 7px 12px; border-radius: var(--dsw-radius-sm, 8px);
  font-size: 13px; color: var(--dsw-alias-label-secondary);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.btn:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
.btn.primary { background: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-inverted); }
.btn.primary:hover { background: var(--dsw-alias-button-primary-hover); }
.btn.icon { padding: 7px 9px; font-size: 15px; line-height: 1;
            display: inline-flex; align-items: center; justify-content: center; }
.btn.icon .ic-i { width: 16px; height: 16px; display: block; }

/* ─────────── 三栏骨架 ─────────── */

#app { display: flex; height: 100vh; }
@supports (height: 100dvh) { #app { height: 100dvh; } }

/* ── 侧栏 ── */
#sidebar {
  flex: none; width: var(--sb-w);
  display: flex; flex-direction: column;
  background: var(--dsw-specific-sidebar-fill);
  border-right: 1px solid var(--dsw-alias-border-l1);
  padding-top: var(--safe-t);
  transition: width var(--dur) var(--ease);
  overflow: hidden;
}
#app.collapsed #sidebar { width: var(--sb-w-collapsed); }

.brand {
  display: flex; align-items: center; gap: 9px;
  padding: 16px 16px 12px; font-size: 15px; font-weight: 600;
  white-space: nowrap;
}
.brand .logo {
  flex: none; width: 26px; height: 26px; border-radius: 8px;
  background: var(--dsw-alias-brand-primary-new-colorprimary-new-color);
  display: grid; place-items: center; color: #fff; font-size: 13px;
}
#app.collapsed .brand span { display: none; }

.nav { flex: 1; overflow-y: auto; padding: 4px 8px; }
.nav .lbl {
  font-size: 11px; color: var(--dsw-alias-label-caption);
  /* ★ 上大下小（2026-10-12 分组之后调的）：
     分组标签要"跟上一组断开、跟下面这组贴近"—— 那才是小标题的读法。
     上面 14px（隔开上一组）+ 下面 4px（贴住自己那组）。 */
  padding: 14px 8px 4px; white-space: nowrap;
}
#app.collapsed .nav .lbl { opacity: 0; }

.item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 10px; margin-bottom: 2px;
  border-radius: var(--dsw-radius-sm, 8px);
  font-size: 13.5px; color: var(--dsw-alias-label-secondary);
  white-space: nowrap; text-align: left;
  transition: background var(--dur) var(--ease);
}
.item:hover { background: var(--dsw-alias-interactive-bg-hover); }
.item.active { background: var(--dsw-specific-sidebar-nav-item-active); color: var(--dsw-alias-label-primary); }
.item .ic { flex: none; width: 18px; height: 18px; display: block;
            color: currentColor; opacity: .9; }
.item.active .ic { opacity: 1; }
#app.collapsed .item span { display: none; }

.sb-foot {
  flex: none; padding: 8px;
  border-top: 1px solid var(--dsw-alias-border-l1);
  padding-bottom: calc(8px + var(--safe-b));
}

/* ── 主区 ── */
#main { flex: 1; display: flex; flex-direction: column; min-width: 0; }

#topbar {
  flex: none; height: 52px; display: flex; align-items: center; gap: 6px;
  padding: 0 12px; padding-top: var(--safe-t);
  border-bottom: 1px solid var(--dsw-alias-border-l1);
}
#topbar .title { flex: 1; font-size: 13px; color: var(--dsw-alias-label-tertiary); }
#topbar .title b { color: var(--dsw-alias-label-primary); font-weight: 500; }
#dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--dsw-alias-state-idle-primary); margin-right: 7px;
  transition: background var(--dur) var(--ease);
}
#dot.on { background: var(--dsw-alias-state-success-primary); }

/* ─────────── 内容列限宽（主人 2026-10-12）───────────
 *
 * 「手机端 100% 没问题，PC 端 100% 有点过于宽了，压到大概 1000px」
 *
 * 为什么：PC 上 #main 会跟着窗口一路变宽（1920 屏就是 ~1660px），
 * 而一行字拉到 1600px —— 眼睛读到行尾要回头找下一行，很累。
 * 1000px 是主流聊天界面的量级。
 *
 * ★ 用 padding 做居中，【不动 DOM】：
 *   加一层容器会牵动 app.js 里对 #list 的引用（多处）。
 *   padding 是纯视觉的，JS 一个字不用改。
 * ★ 顶栏【不跟着缩】—— 它该铺满（状态条/连接点在最右边）。
 * ★ 手机上自动失效：100% - 1000px 是负数，max() 取 18px。
 */
#main { --col-w: 1000px; --pad-x: max(18px, calc((100% - var(--col-w)) / 2)); }

/* ─────────── 页签（主人 2026-10-13）───────────
 *
 * 一条页签 = 一条【独立的消息流】：
 *   主页签         —— 和我对话
 *   子 agent 页签   —— 直接跟它对话（发消息自动带 /sub <id> 前缀）
 *
 * ★ 为什么放 #list 上面、不进侧栏：它是"看哪条流"的开关 —— 该跟着内容走；
 *   侧栏是"去哪"（功能区）。而且手机上侧栏默认收起，放里面就用不上了。
 * ★ 一直显示（哪怕只有主页签）：位置稳定，眼睛不用每次重新找。
 * ★ 窄屏横滑（overflow-x）—— 页签会变多，让它滚而不是挤成一坨。
 */
#tabbar-wrap {
  display: flex; align-items: flex-end; flex: none;
  padding: 6px var(--pad-x) 0;
  /* ★ 底线（主人 2026-10-13："页签栏不明显，加个底边线"）——
   *   它把"页签区"和"消息区"分开，也是当前页签那条高亮线的落点。
   *   ★ 10-13 挪到 wrapper 上：这样那条线也盖到右边的 ＋（否则 ＋ 底下缺一截）。 */
  border-bottom: 1px solid var(--dsw-alias-border-l1);
}
#tabbar {
  display: flex; align-items: flex-end; gap: 2px;
  flex: 1; min-width: 0;              /* ★ min-width:0 才能让下面的 overflow 生效（flex 子项默认不肯缩） */
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
#tabbar::-webkit-scrollbar { display: none; }

/* ＋ —— 页签栏右侧那个"打开对话"（主人 2026-10-13）。
 * ★ 尺寸跟一个页签等高（28px = .tab 的 border 1 + padding 7+7 + 行高 13）——
 *   不然它会比一排页签矮一截，看着像另一个控件。 */
#tabadd {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0;
  border: 1px solid transparent; border-bottom: 0;
  border-radius: 9px 9px 0 0;
  background: none; color: var(--dsw-alias-label-secondary);
  font: inherit; cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
#tabadd:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
#tabadd .ic-i { width: 15px; height: 15px; }

.tab {
  position: relative;                 /* ★ ::after 的定位父（那条高亮线） */
  display: inline-flex; align-items: center; gap: 7px; flex: none;
  padding: 7px 10px;
  /* ★ 边框（主人要的）—— 用 transparent 占位，激活时换色 → 不跳。
   *   底边留 0：它跟 #tabbar 的底线重合，那条由 ::after 画。 */
  border: 1px solid transparent; border-bottom: 0;
  background: none; cursor: pointer;
  border-radius: 9px 9px 0 0;
  font: inherit; font-size: 13px; line-height: 1;
  color: var(--dsw-alias-label-secondary);
  white-space: nowrap;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.tab:hover { background: var(--dsw-alias-interactive-bg-hover); }

/* ★ 当前页签（主人："分不清当前是哪个页签"）—— 三件事一起做，亮暗两色都分得出：
 *   ① 底色（暗色有效：卡片色比页面底浅一档）
 *   ② 文字转主要色（两种主题都有效）
 *   ③ 底下一条高亮线（两种主题都有效 —— 这条最硬）
 *   ★ 只靠底色的话亮色下等于没变（input-major 和页面底都是白的）。
 *   ★ 边框也一起给：不然激活时"只有底下有标记"，看着像半个控件。 */
.tab.on {
  background: var(--dsw-specific-input-major);
  border-color: var(--dsw-alias-border-l2);
  color: var(--dsw-alias-label-primary);
}
.tab.on::after {
  content: ''; position: absolute; left: 8px; right: 8px; bottom: 0;
  height: 2px; border-radius: 2px 2px 0 0;
  background: var(--dsw-alias-state-primary, #3b82f6);
}
.tab .tn { max-width: 130px; overflow: hidden; text-overflow: ellipsis; }
.tab .ic-i { width: 14px; height: 14px; flex: none; opacity: .85; }

/* 关闭按钮：只有【当前页签】上才有它（主人 2026-10-13）
 *
 * ★ 这条修了三次，前两次都错在"藏起来 ≠ 点不到"：
 *   ① `opacity: 0` + `pointer-events: none`                → 主人："不行"
 *   ② ② + 把 :hover 关进 `@media (hover: hover)`           → 主人："还是不行"
 *      原因：手机上"点一下"会触发 :hover，而**部分手机浏览器照样匹配 hover:hover**
 *      （华为/平板的浏览器为了显示桌面版站点，会这么报）→ 那条 hover 规则还在生效。
 * ★ 主人的正解：`display: none` —— **不在渲染树里，就绝对不可能被点到**。
 *   它不依赖 pointer-events、不依赖媒体查询、不依赖 :hover 怎么算。**最不容易错。**
 * ★ 因此不做"悬停显示"（就是主人要的"统一"）：桌面和手机一样，两步 ——
 *   先点它（成了当前页签，× 才出来）→ 再点 ×。
 * ★ 代价（说清）：切页签时 × 的出现/消失会让页签宽度变 ~23px（一排标签动一下）。
 *   要消掉这个抖动得改成"绝对定位 + 右边固定留白"，但那又绕回去了 —— 先按主人说的来。
 */
.tab .tx {
  display: none;                      /* ★ 非当前页签：这个元素根本不存在 */
  align-items: center; justify-content: center;
  width: 16px; height: 16px; flex: none; padding: 0;
  border: 0; background: none; cursor: pointer;
  border-radius: 4px;
  color: inherit;
}
.tab.on .tx { display: inline-flex; opacity: .6; }   /* ★ 只有当前页签：显示它、也才能点它 */
.tab .tx:hover { opacity: 1; background: var(--dsw-alias-interactive-bg-hover); }
.tab .tx .ic-i { width: 11px; height: 11px; }

/* ── 页签状态（主人 2026-10-13 要的三态）──
 *   转圈 = 这一轮在跑 · 红点 = 有未读 · 绿点 = 空闲可用
 * ★ 一个元素 + 三个变体类（不是三套元素）：位置固定，眼睛不用重新找。
 * ★ 主页签也带点 —— 它同样"在跑 / 有未读"，语义一致。
 */
.tab .ts { width: 7px; height: 7px; flex: none; border-radius: 50%; }
.tab .ts.idle  { background: var(--dsw-alias-state-success-primary, #22c55e); }
.tab .ts.unread{ background: var(--dsw-alias-state-error-primary); }
.tab .ts.run {
  background: none; width: 12px; height: 12px;
  border: 1.5px solid var(--dsw-alias-border-l3, rgba(128,128,128,.4));
  border-top-color: var(--dsw-alias-label-secondary);
  animation: tabspin .7s linear infinite;
}
@keyframes tabspin { to { transform: rotate(360deg); } }

#list { flex: 1; overflow-y: auto; padding: 18px var(--pad-x); -webkit-overflow-scrolling: touch; }

.m { display: flex; margin-bottom: 16px; }
/* ★★ 2026-10-12 修（主人报"手机端有左右滚动条，这个不好"）：
 *
 *   `.m` 是 flex 容器，它的直接子 div 是 flex item ——
 *   而 flex item 的【默认 min-width 是 auto】= 不许收缩到比内容窄。
 *   → 气泡里有长内容（深路径 D:\super-no-die-team\... / 长 URL / 长代码词）时，
 *     那个 div 被撑到 581px，把整个 #list 顶出横向滚动条。
 *
 *   实测：修之前 div 宽 581 / 父 364（超出 217px）；min-width: 0 之后自动收缩。
 *
 * ★ 顺带把宽度限制挪到这一层 —— 原来 `.b { max-width: 76% }` 是相对【那个 flex item】
 *   的宽度算的，而那个宽度本身由内容决定（自相矛盾：内容越宽、76% 越大）。
 *   限在这一层，才是"气泡最多占容器的 76%"。
 */
.m > div { min-width: 0; max-width: 76%; }
.m .b {
  padding: 10px 14px; border-radius: var(--radius-lg);
  /* ★ 主人 10-12：「agent 回复气泡的背景色调成透明/或者和背景色一致，
     看着大气点」。 ── 对：agent 的回话本来就长（表格/代码/分点），
     给它一块底色反而显得像"引用块"。透明之后它只是【正文】，读起来松。
     ★ 但留一点点左右内边距：不然文字跟头像/边缘贴死。 */
  background: transparent; white-space: pre-wrap;
  word-break: break-word; overflow-wrap: anywhere;
  line-height: 1.58; user-select: text; -webkit-user-select: text;
}
/* agent 的气泡填满内容列（主人 10-12：「agent 的回复气泡宽度拉成 100%」）。
 * ★ 用 :not(.me) 而不是改默认值 —— 我自己那条要留着窄（短句多，铺满反而难读）。
 * ★ 手机上也铺满：聊天区本来就 100%，多留白只会让长消息更高。 */
.m:not(.me) > div { max-width: 100%; }

.m.me { justify-content: flex-end; }
/* ★ 我的气泡用它的品牌蓝 deepseek-500（65,118,230）。
   为什么不沿用它给的 button-info-fill：
   那个在暗色下是 deepseek-400 = rgb(122,170,255) —— 白字配它对比度只有 2:1，
   字会看不清。deepseek-500 两个主题下都够（白字约 4.6:1）。 */
.m.me .b { background: var(--dsw-static-deepseek-500); color: #fff; border-bottom-right-radius: 6px; }
.m:not(.me) .b { border-bottom-left-radius: 6px; }
.m .meta { font-size: 11px; color: var(--dsw-alias-label-caption); margin-top: 5px; padding: 0 4px; }

/* ── 通知 / 错误（主人 2026-10-13）──
 *
 * ★ 它们是 core 外发的 8 种 type 里最容易被漏掉的两种
 *   （前端原来落到最后那句 return 上，【静默丢了】）。
 *   notify = 主动告知（soulnote 生成 / memory 注入）；error = 出错。
 *
 * ★ 它们【不是对话里的一句话】—— 所以居中、不给气泡、不署名，
 *   跟左右两边的对话气泡在视觉上分开（一眼看出"这是一件事"不是"谁说的"）。
 */
.m-notice {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  margin: 9px auto; padding: 4px 10px;
  max-width: 92%; width: fit-content;
  font-size: 12px; line-height: 1.5; text-align: center;
  border-radius: 6px;
}
.m-notice .ic-i { width: 12px; height: 12px; flex: none; }
.m-notice .nc-emoji { flex: none; }

.m-notice.is-notify {
  color: var(--dsw-alias-label-caption);
  opacity: .85;
}

/* error：红字 + 淡红底 + 细边 —— 要一眼看见（出错是最该被知道的事） */
.m-notice.is-error {
  color: var(--dsw-alias-state-error-primary);
  background: var(--dsw-alias-state-error-bg, rgba(229, 72, 77, .10));
  border: 1px solid var(--dsw-alias-state-error-border, rgba(229, 72, 77, .30));
}

/* 转发来的（这句话不是在这个平台上说的）—— 左边一条细线，跟本地消息分开。
   ★ 标头（[来自 x] / [x 处理]）已经在显示时剥掉了，所以要有别的东西说明来处。 */
.m.fw .b { border-left: 2px solid var(--dsw-alias-border-l2); }

/* ★ 亮色下它对 AI 气泡给的是 deepseek-50（rgb 237,243,254）——
   跟白底几乎分不开 —— 于是原来"换成软灰，看得见又不抢眼"。
   ★ 2026-10-12 17:53（snow）：447618f 已把 agent 气泡统一定成透明
   （上面 .m .b 那条），但这条亮色覆盖忘了同步 —— 亮色下还留着灰底。
   这里补齐，让两套主题都是透明。
   回退：把 background 改回 var(--dsw-static-neutral-bluish-75)。 */
html[data-theme="light"] .m:not(.me) .b { background: transparent; }

/* ─────────── 中间过程（思考 / 工具调用 / 结果）───────────
 *
 * ★ 2026-10-12（主人）：这些原来【压根不显示】（core 一直在推，前端丢了）。
 *   现在收进一个折叠块 —— 默认折叠，点开看。
 *
 * 为什么不是 [open]：一轮里可能几十条（4 万条工具消息的库），
 * 全展开会把对话冲没。而折叠标题里带摘要（"file_read ×3"），
 * 不点开也知道它干了什么。
 *
 * 为什么用原生 <details>：默认折叠 + 点击展开 + 键盘可达，
 * 都不用写 JS（这个体量引组件库是杀鸡用牛刀）。
 */
.trace {
  margin: 0 0 14px 2px;
  border-left: 2px solid var(--dsw-alias-border-l2);
  padding-left: 10px;
}
.trace > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--dsw-alias-label-caption);
  padding: 3px 0; user-select: none;
}
.trace > summary::-webkit-details-marker { display: none; }
.trace > summary:hover { color: var(--dsw-alias-label-secondary); }
.trace > summary .ic-i { width: 13px; height: 13px; flex: none; }
/* 进行中：一个小呼吸点（它是"还在干活"的唯一信号） */
.trace.live > summary { color: var(--dsw-alias-label-secondary); }
.trace.live > summary .ic-i { animation: tr-pulse 1.4s ease-in-out infinite; }
@keyframes tr-pulse { 0%,100% { opacity: .35; } 50% { opacity: 1; } }
.trace[open] > summary { margin-bottom: 4px; }

/* 展开块【最下面】的"收起"（主人 2026-10-12）——
 * 「展开后如果滑到最下方、想再折叠起来要滑上去，能不能在展开信息的最下方
 *   也加个折叠功能、点击可以收回去」
 * ★ 它不是 summary 的子元素 → 点它【不会】触发原生 details 的展开/折叠，
 *   收起动作由 app.js 显式做（顺便把这一块拉回视野）。
 * ★ 只在展开时有意义；折叠时整块内容都不渲染（details 原生行为），不用管。 */
.tr-foot { display: flex; justify-content: center; padding: 7px 0 1px; }
.tr-close {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 11px; border-radius: 999px;
  font-size: 11.5px; color: var(--dsw-alias-label-caption);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.tr-close:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-secondary); }
/* 没有 i-chevron-up，把 chevron-right 转上来（sprite 里只有 right） */
.tr-close .ic-i { width: 12px; height: 12px; transform: rotate(-90deg); }

.tr { display: flex; gap: 7px; padding: 3px 0; font-size: 12.5px; }
.tr .tr-k { flex: none; width: 14px; padding-top: 2px; opacity: .5; }
.tr .tr-k .ic-i { width: 12px; height: 12px; }
.tr .tr-v { min-width: 0; flex: 1; color: var(--dsw-alias-label-secondary); line-height: 1.5; }
.tr-pre { white-space: pre-wrap; word-break: break-word; overflow-wrap: anywhere; }
.tr-call .tr-v b { font-weight: 600; color: var(--dsw-alias-label-primary); }
.tr-call .tr-args { opacity: .65; margin-left: 6px; word-break: break-all; }
.tr-result .tr-v { opacity: .9; }
.tr-think .tr-v { font-style: italic; opacity: .8; }

/* ── 参数 / 结果：一行摘要 + 折叠看全文 ──
 *
 * ★ 2026-10-12（主人两轮反馈）：
 *   ① "参数显示成了 [object Object]" —— 数据里 arguments 是【对象】，
 *      我原来按字符串 JSON.parse → 成了 "[object Object]"。修在 app.js。
 *   ② "file_read 的响应 + exec 的响应太长了、能否默认折叠" —— 这条就是。
 *
 * 结构：<summary> 是【一行摘要】（默认状态就能看明白），
 *       点开是完整内容（参数是格式化 JSON，结果是截断后的原文）。
 */
.tr-more { display: block; min-width: 0; }
.tr-more > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: baseline; gap: 6px;
  padding: 1px 0; border-radius: 4px;
}
.tr-more > summary::-webkit-details-marker { display: none; }
.tr-more > summary:hover { background: var(--dsw-alias-interactive-bg-hover); }
/* ★ 小三角自己画（原生 marker 在 flex 里位置很怪） */
.tr-more > summary::before {
  content: '▸'; flex: none; width: 9px; opacity: .45; font-size: 10px;
}
.tr-more[open] > summary::before { content: '▾'; }
.tr-more[open] > summary { margin-bottom: 4px; }

.tr-call .tr-more > summary { color: var(--dsw-alias-label-secondary); }
.tr-result .tr-brief { opacity: .75; min-width: 0; flex: 1;
                       overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tr-size { flex: none; opacity: .45; font-size: 11px; }

/* 折叠里的完整内容（限高 + 可滚 —— 别把页面撑爆） */
.tr-more > .tr-pre {
  margin: 2px 0 6px 15px; padding: 7px 9px;
  background: var(--dsw-alias-markdown-code-block-banner);
  border-radius: 6px; font-size: 11.5px; line-height: 1.5;
  /* overflow:auto 是纵向限高（220px）；横向靠 overflow-wrap 断长串，
     别让手机上的横滚条从这儿冒出来。 */
  max-height: 220px; overflow-y: auto; overflow-x: hidden;
  overflow-wrap: anywhere;
  font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  color: var(--dsw-alias-label-secondary);
}

/* ── 段（seg）：一轮过程里的一段（主人 2026-10-13）──
 *
 * 折叠块里不再平铺一行行，而是「段」：
 *   text  段 = 思考 + 说话（合成一行）
 *   tools 段 = 连续的工具调用（摘要 = 工具名 × 次数）
 * ★ 摘要常显、详情点击才展开 —— 一眼看到节奏，要细节点进去。
 *   （结构：.trace > .tr-body > .seg > summary + .seg-more）
 */
/* ★ 10-13 修：这条必须带 `.tr-body >` 作用域。
 *
 *   原因：`.seg` 这个名字【被别人用了】——
 *     设置弹框里的主题切换是 `<div class="seg">`（app.js:2136），
 *     而它的 CSS 原来【漏写了 #modal 前缀】→ 变成一条【全局】`.seg { display: flex }`。
 *     → 同特异性、后写的赢 → 我的段（`<details>`）被撑成 flex：
 *       手机上 summary 和详情【左右并排】（summary 被压得又窄又高、详情撑出横滚条）。
 *
 *   ★ 修了两处：① 这条加作用域 ② 下面 "#modal .seg" 那组补前缀。
 *   ★ 判据：起类名之前先 grep 一遍有没有人用 —— `.seg` 这么通用的名字最容易撞。
 */
.tr-body > .seg { display: block; margin: 1px 0; }
.seg > summary {
  display: flex; align-items: baseline; gap: 6px;
  padding: 2px 5px; border-radius: 5px; cursor: pointer;
  font-size: 12.5px; color: var(--dsw-alias-label-secondary);
  list-style: none;
}
.seg > summary::-webkit-details-marker { display: none; }
.seg > summary:hover { background: var(--dsw-alias-interactive-bg-hover); }
.seg > summary .seg-k { flex: none; width: 14px; text-align: center; opacity: .5; }
.seg > summary .seg-k .ic-i { width: 12px; height: 12px; }
.seg > summary .seg-brief {
  min-width: 0; flex: 1;
  /* ★ 主人 10-13：不裁剪、完整展示 ——
     去掉 nowrap/ellipsis（那会截成一行 + "…"），允许换行。
     长串（URL / 无空格）也要能断，否则窄屏上撑出横向滚动条。 */
  white-space: pre-wrap; word-break: break-word; overflow-wrap: anywhere;
}
.seg[open] > summary { color: var(--dsw-alias-label-primary); }
/* ★ 10-13：段里【没有详情】时（如 text 段只有"说话"、没有"思考"，而说话已在摘要里全文显示）
 *   —— 别让它"点开是个空的"。
 *   ★ 用 pointer-events 而不是 display：摘要行本身是内容，要留着。
 *   （跟 .tab .tx 那次不同：这里没有别的规则会把它重新打开 —— summary:hover 只改背景色。） */
.seg.no-more > summary { cursor: default; pointer-events: none; }
/* 详情缩进一点 —— 视觉上"挂在"上面那行下面 */
.seg-more { padding-left: 19px; }

/* ─────────── 输入卡片（主人 2026-10-12）───────────
 *
 * 「输入框、发送按钮整理成一个偏卡片的样式，把 /status /usage 的信息统计放进来」
 *
 * 结构（index.html）：
 *   .cm-card
 *     .cm-in     输入 + 发送（上行）
 *     .cm-meta   状态 · 用量（下行，两个都可点开看完整的）
 *
 * 为什么做成卡片：输入区原来是一条"线"（textarea + 一个圆按钮），
 * 而这块地方其实承载两件事 —— 说话、看状态。卡片把这两件事收进一个视觉单元。
 */
#composer {
  flex: none;
  /* ★ 卡片外面那一圈的底 —— 提成变量，好单独调（默认 transparent）。
   *   ★ 它是透明的 = 显示的是 body 底色。所以"把它改透明"在视觉上不会有变化 ——
   *     这块底【本来】就透。要让它看起来不一样，得改页面背景或后面那层。 */
  background: var(--composer-bg);
  /* ★ position: relative —— 给 #tobottom 当定位上下文：
     它 absolute + bottom:100% 浮在【卡片上方】，不占文档流（见下面 #tobottom）。
     ★ padding-top 为 0（主人 10-12 报：那 10px 显示的是页面底色，亮色下 = 一条白边）。 */
  position: relative;
  /* ★ --cm-pad = 卡片到窗口边缘的横向距离。
   *   凡是"要跟卡片/发送按钮同列"的绝对定位元素都用它，别直接用 --pad-x。
   *   理由（主人 10-13 在手机上报）：
   *     --pad-x 是【消息列】的缩进（手机上 min 18px），而 #composer 在 ≤520px 时
   *     padding 是 12px —— 两者不是一回事。混用会让 #tobottom / .addmenu 偏 6px。
   *   → 手机上由 media query 把它覆盖成 12px（跟 #composer 的 padding 对齐）。 */
  --cm-pad: var(--pad-x);
  padding: 0 var(--cm-pad) calc(12px + var(--safe-b));
}

/* ── 运行中读秒（主人 2026-10-12）──
 *
 * 「消息发送成功后、在发送框这个卡片的上方加一个运行中+读秒之类的机制，
 *   收到最终回复后取消」
 *
 * ★ 它补的是一个真空白：从"发出去"到"收到 final"之间，界面是【完全静止】的
 *   —— 中间过程在折叠块里、状态条也不动。这段最让人怀疑"它到底收到没有"。
 *   读秒 = 一个"它还活着、已经跑了多久"的证据。
 * ★ 数字用 tabular-nums：不然每秒宽度在变，整行会抖。
 */
/* ── 卡片上方那一行：两个子元素现在【都是浮层】──
 * ★ 这一行本身【永远 0 高度】—— 卡片直接贴消息区，上方不留任何空白。
 *   （主人 10-12 报的"白边"就是它曾经占过的那条：那里显示的是页面底色，
 *     而 #composer 是透明的，所以亮色下 = 一条纯白，改背景色也去不掉。）
 */
.cm-top { display: flex; align-items: center; }

/* ★ #runbar（卡片上方的「运行中 3.4s」胶囊）在 2026-10-12 撤掉了 ——
 *   主人："发送消息后就显示那个折叠栏：进行中 xxS，收到别的再按当前逻辑累计进来"。
 *   → 读秒并进了消息流里的 .trace 块（见 app.js 的 paintLive / startClock）。
 *   现在卡片上方只剩 #tobottom 一个浮层，见下面。 */

/* 折叠块的标题：读秒数字用等宽（见 app.js paintLive —— 每 100ms 重画一次）。
   ★ 不加这个，数字宽度一跳，后面的工具名就跟着左右晃。 */
.tr-title { font-variant-numeric: tabular-nums; }

/* ── 回到最新（主人 2026-10-12）──
 *
 * 「聊天框不在底部的时候、发送卡片右侧往上一点提供一个滑到底部按钮，
 *   参考发送按钮样式」
 * 后续：「想要一样大，最好距离右侧的距离跟发送按钮在同一列上」
 * 再后续：「跑到发送框里面去了」→ 移回卡片外面
 * 再后续（★ 最终形态）：「我怎么感觉绝对定位浮着才是正解啊？试试？」
 *
 * ★ 它就是【浮在卡片右上方】的一个浮动按钮 —— 不占文档流，盖在消息区下缘，
 *   像微信 / ChatGPT 的"回到底部"。加阴影让它从内容里浮出来（不然会像"薄薄一层
 *   东西糊在字上"，主人 10-12 报过）。
 * ★ 尺寸/配色/圆角/图标全跟 #send 一样（36×36）。
 * ★ 定位：relative 的祖先是 #composer（见上）。所以——
 *     right:  var(--cm-pad) + 8px   卡片右边缘 8px 处（= 卡片边框 1px + .cm-in 右内边距 7px，
 *                                   跟 #send 同一列）
 *   ★ 用 --cm-pad 【不是】--pad-x（主人 10-13 报：手机上跟发送按钮差 6px ——
 *     因为手机的 --pad-x 是 18px 而 #composer 的 padding 是 12px）。
 *     bottom: 100% + 7px           底边在 #composer 顶边上方 7px —— 即浮在卡片上方一隙
 *   ★ 为什么不用 top/left：bottom 相对 #composer 顶边，而卡片就贴在那儿
 *     （padding-top:0）—— 卡片换行长高时它也不会跑偏。
 */
#tobottom {
  position: absolute;
  right: calc(var(--cm-pad) + 8px);
  bottom: calc(100% + 7px);
  width: 36px; height: 36px;
  border-radius: var(--dsw-radius-sm, 8px);
  background: var(--dsw-static-deepseek-500); color: #fff;
  display: grid; place-items: center;
  /* ★ 浮层该有的阴影 —— 让它在盖住的文字上面有"浮起来"的层次 */
  box-shadow: 0 2px 10px rgba(0,0,0,.28);
  transition: filter var(--dur) var(--ease);
}
/* ★ display:grid 也会盖掉 hidden 属性自带的 display:none —— 必须补回来 */
#tobottom[hidden] { display: none; }
/* sprite 里没有 chevron-up/down —— 把 chevron-right 转 90° 朝下 */
#tobottom .ic-i { width: 17px; height: 17px; transform: rotate(90deg); }
#tobottom:hover { filter: brightness(1.12); }

.cm-card {
  display: flex; flex-direction: column;
  border: 1px solid var(--dsw-alias-border-l2);
  border-radius: var(--dsw-radius-lg, 16px);
  /* ★ 卡片的底 —— 同 --card-bg（默认 transparent）。
   *   暗色下它原本是 --dsw-specific-input-major = bluish-850，
   *   比页面底（--dsw-alias-bg-base = bluish-950）亮一档，就是"卡片看得见"的原因。
   * ★ 亮色下两层本来就是同一个值（都是 bluish-00），改动看不出来 ——
   *   别以为没生效。 */
  background: var(--card-bg);
  transition: border-color var(--dur) var(--ease);
  overflow: hidden;
}
/* 聚焦时整个卡片亮一下（而不是单个 textarea 描边）—— 视觉上更"这是一个输入区" */
.cm-card:focus-within { border-color: var(--dsw-alias-button-info-fill); }

.cm-in { display: flex; align-items: flex-end; gap: 8px; padding: 7px 7px 7px 14px; }

/* 加号（主人 2026-10-13）—— 次要动作：透明底 + 一圈细边，悬停才出头。
 *  ★ 尺寸跟 #send 【严格一致】：都是 36×36（全局 box-sizing:border-box，
 *    所以这 1px 边框不会把它撑成 38 —— 撑大了就跟发送按钮错位了）。
 *  ★ 边框色用 --dsw-alias-border-l2：跟 .cm-card 自己的边框同一个值（一套）。
 *  ★ 图标也改成 17px，跟 #send 一样 —— 原来 19px 会让"＋"显得比"➤"大一号。
 *  ★ 不给主色：两个蓝按钮会互相抢，加号是次要动作。 */
#add {
  flex: none; width: 36px; height: 36px;
  border: 1px solid var(--dsw-alias-border-l2);
  border-radius: var(--dsw-radius-sm, 8px);
  background: transparent; color: var(--dsw-alias-label-secondary);
  display: grid; place-items: center;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
#add .ic-i { width: 17px; height: 17px; }
#add:hover, #add.on {
  background: var(--dsw-alias-interactive-bg-hover);
  border-color: var(--dsw-alias-border-l3);
  color: var(--dsw-alias-label-primary);
}
/* ★ 输入区跟着内容列（不然宽屏下输入框铺满、消息居中，对齐会错）
   —— 放在 #composer 主规则【之后】，才能覆盖它的 padding-left/right。 */
#composer { padding-left: var(--cm-pad); padding-right: var(--cm-pad); }
#in {
  flex: 1; min-width: 0;
  padding: 9px 0; border: 0; background: transparent;
  color: var(--dsw-alias-label-primary);
  resize: none; outline: none; line-height: 1.5;
  min-height: 36px; max-height: 130px;
  /* ★ 字号仍走上面那条 `input, textarea { font-size: 16px }` ——
     16px 是【防 iOS 聚焦时自动放大页面】的底线，别为了好看调小。 */
}
/* ★ 换成图标按钮（主人：「这个发送按钮你写得好随意哈哈哈，就一个字：发…换图标？」）
   —— 那个"发"是 10-10 随手写的。换成 i-send（Lucide 的 send 箭头）。 */
#send {
  flex: none; width: 36px; height: 36px;
  border-radius: var(--dsw-radius-sm, 8px);
  background: var(--dsw-static-deepseek-500); color: #fff;
  display: grid; place-items: center;
  transition: filter var(--dur) var(--ease);
}
#send .ic-i { width: 17px; height: 17px; }
#send:hover { filter: brightness(1.12); }

/* 停止这一轮（主人 2026-10-13）—— 发送后出现、收到 final 消失。
 *
 * ★ 红是【状态色】（--dsw-alias-state-error-primary）不是主色：
 *   它只在"这一轮还在跑"时存在，天然是个临时动作 —— 用状态红提醒"这会打断它"。
 * ★ 尺寸跟 #send #add 一致（36×36 + 同样圆角），三个按钮一条线。
 * ★ 图标 15px（比 17 小一号）：方块是【实心块】，17px 会显得比箭头重。
 * ★ 动画【两段分开】：
 *     入场  stopIn   —— 淡入 + 从右边 6px 滑进来 + 微微放大（像"挤"出来）
 *     退场  stopOut  —— 反向（比入场稍快，消失不拖沓）
 *   入场靠 `:not([hidden])` 触发：display 从 none 变 grid 时动画自动重跑。
 *   退场靠 .off 加动画，播完（160ms）JS 才真正 hidden —— 不然 display:none 会当场剪掉动画。
 * ★ 只做 opacity / transform —— 不碰 width，所以【不会把输入框挤来挤去】。
 *   （发送时输入框本来就空了，但没必要动布局。）
 */
#stop {
  flex: none; width: 36px; height: 36px;
  border: 0; border-radius: var(--dsw-radius-sm, 8px);
  background: var(--dsw-alias-state-error-primary); color: #fff;
  display: grid; place-items: center;
}
#stop[hidden] { display: none; }
#stop .ic-i { width: 15px; height: 15px; }
#stop:hover { filter: brightness(1.12); }
/* 已经点过 /stop —— 变暗 + 不再响应（防连点）。下一个回合 startClock 会重置。 */
#stop.busy { opacity: .5; pointer-events: none; }

#stop:not([hidden]) { animation: stopIn .20s var(--ease); }
#stop.off { animation: stopOut .16s var(--ease) forwards; }

@keyframes stopIn {
  from { opacity: 0; transform: translateX(6px) scale(.88); }
  to   { opacity: 1; transform: none; }
}
@keyframes stopOut {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateX(6px) scale(.88); }
}

/* ─────────── 附件（主人 2026-10-13）───────────
 *
 * 两个地方用同一套 .attach 单元：
 *   ① 卡片里的【待发预览条】(.cm-atts) —— 64×64，带移除按钮
 *   ② 消息流里的【已发附件】(.m-atts)  —— 108×108，点开看大图
 * 缩略图来源：/api/file?path=…（同源、带 cookie）
 */
.cm-atts {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 10px 12px 0;
  overflow-x: auto;
  scrollbar-width: thin;
}
/* ★ display:flex 会盖掉 hidden 自带的 display:none —— 不加这句，预览条永远显示。
   （今天在 #runbar / #tobottom 上已经栽过。） */
.cm-atts[hidden] { display: none; }

.attach {
  position: relative; flex: none;
  width: 64px; height: 64px;
  border-radius: 10px; overflow: hidden;
  border: 1px solid var(--dsw-alias-border-l1);
  background: var(--dsw-alias-interactive-bg-hover);
}
.attach a { display: block; width: 100%; height: 100%; }
.attach img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 非图片：图标 + 文件名（名字可能很长 → 截 3 行） */
.attach .fi {
  width: 100%; height: 100%; padding: 4px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; text-align: center;
}
.attach .fn {
  font-size: 9.5px; line-height: 1.2; color: var(--dsw-alias-label-secondary);
  word-break: break-all; max-width: 100%; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
}
.attach .ic-i { width: 18px; height: 18px; flex: none; color: var(--dsw-alias-label-tertiary); }
/* 移除按钮（只出现在预览条里）—— 浮在右上角 */
.attach .rm {
  position: absolute; top: 3px; right: 3px;
  width: 18px; height: 18px; border-radius: 50%;
  background: rgba(0,0,0,.62); color: #fff;
  display: grid; place-items: center;
}
.attach .rm .ic-i { width: 11px; height: 11px; color: #fff; }
.attach .rm:hover { background: rgba(0,0,0,.82); }

/* 消息流里的附件：同一套单元，大一号 + 换行排列 */
.m-atts { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.m-atts .attach { width: 108px; height: 108px; }
.m-atts .attach .ic-i { width: 22px; height: 22px; }
.m-atts .attach .fn { font-size: 10.5px; }

/* 加号菜单 —— 绝对定位相对 #composer（★ 不能放 .cm-card 里：它有 overflow:hidden，
   会把菜单裁掉）。位置：卡片上方 7px、左缘跟加号按钮对齐。 */
.addmenu {
  position: absolute;
  /* ★ --cm-pad（不是 --pad-x）—— 跟 #tobottom 同一条理由，手机上才跟加号按钮对齐 */
  left: calc(var(--cm-pad) + 14px);
  bottom: calc(100% + 7px);
  z-index: 4;
  display: flex; flex-direction: column; gap: 2px;
  padding: 4px; min-width: 112px;
  background: var(--dsw-alias-bg-layer-2, var(--dsw-specific-menu));
  border: 1px solid var(--dsw-alias-border-l2);
  border-radius: 10px;
  box-shadow: 0 6px 20px rgba(0,0,0,.28);
}
.addmenu[hidden] { display: none; }
.addmenu button {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 10px; border-radius: 7px;
  font-size: 13px; color: var(--dsw-alias-label-primary); text-align: left;
}
.addmenu button:hover { background: var(--dsw-alias-interactive-bg-hover); }
.addmenu .ic-i { width: 16px; height: 16px; flex: none; color: var(--dsw-alias-label-secondary); }

/* ── 弹窗 ── */
#mask {
  position: fixed; inset: 0; z-index: 50;
  background: var(--dsw-alias-bg-mask-1);
  display: none; align-items: center; justify-content: center;
  padding: 24px;
}
#mask.open { display: flex; }
#modal {
  /* ★ 主人说"这个弹框有点小气，太窄了" —— 560 → 880，
     而且高度放到 85vh（表格多的时候少滚一点） */
  /* ★ 再调（主人 10-12）：880 → 1100 —— 表格列一多，880 就得横向滚了。 */
  width: min(1100px, 100%); max-height: 85vh; overflow-y: auto;
  background: var(--dsw-alias-bg-layer-2, var(--dsw-specific-menu));
  border: 1px solid var(--dsw-alias-border-l2);
  border-radius: var(--radius-lg); padding: 20px;
  box-shadow: 0 12px 40px rgba(0,0,0,.28);
}
#modal h2 { font-size: 15px; font-weight: 600; margin: 0 0 4px; }
#modal .sub { font-size: 12px; color: var(--dsw-alias-label-tertiary); margin-bottom: 16px; }
#modal .row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 10px 0; border-top: 1px solid var(--dsw-alias-border-l1);
}
#modal .row .k { font-size: 13.5px; }
#modal .row .d { font-size: 11.5px; color: var(--dsw-alias-label-tertiary); margin-top: 2px; }
#modal pre {
  background: var(--dsw-alias-markdown-code-block); padding: 12px;
  border-radius: var(--dsw-radius-sm, 8px); font-size: 12px; overflow-x: auto;
}
/* ★ 10-13 修：加 `#modal` 作用域 —— 它一直就是【弹框里】的分段选择器
 *   （设置弹框的主题切换 <div class="seg">，app.js:2136），
 *   原来漏了前缀 → 变成全局 `.seg { display: flex }`，
 *   把消息流里的折叠段（.trace > .tr-body > .seg，是 <details>）也撑成了 flex：
 *   手机上 summary 和详情左右并排、详情撑出横向滚动条。
 *   ★ 同一天同一个文件里两条 `.seg` 撞车 —— 起名/加规则前先 grep。 */
#modal .seg { display: flex; gap: 4px; background: var(--dsw-specific-selector); padding: 3px; border-radius: 9px; }
#modal .seg button { padding: 5px 11px; border-radius: 7px; font-size: 12.5px; color: var(--dsw-alias-label-secondary); }
#modal .seg button.on { background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary); }

/* ─────────── 手机 / 窄屏 ─────────── */

#scrim { display: none; }

@media (max-width: 1024px) {
  #sidebar {
    position: fixed; z-index: 40; height: 100%;
    transform: translateX(-100%); width: var(--sb-w) !important;
    transition: transform var(--dur) var(--ease);
  }
  #app.sb-open #sidebar { transform: none; }
  #app.collapsed #sidebar { width: var(--sb-w) !important; }
  #scrim {
    display: block; position: fixed; inset: 0; z-index: 39;
    background: var(--dsw-alias-bg-mask-1); opacity: 0; pointer-events: none;
    transition: opacity var(--dur) var(--ease);
  }
  #app.sb-open #scrim { opacity: 1; pointer-events: auto; }
  #menu-btn { display: inline-flex !important; }
}
@media (min-width: 1025px) { #menu-btn { display: none; } }

@media (max-width: 520px) {
  #list { padding: 14px 12px; }
  .m > div { max-width: 88%; }
  .m-atts .attach { width: 92px; height: 92px; }   /* 窄屏缩略图小一号 */
  /* ★ --cm-pad 和 padding 用【同一个】12px：写两份的话，以后改一个忘一个，
   *   又会出现"按钮跟发送框不同列"（主人 10-13 报的那个）。 */
  #composer { --cm-pad: 12px; padding: 10px var(--cm-pad); padding-bottom: calc(10px + var(--safe-b)); }
  #modal { padding: 16px; }
}



/* ─────────── 卡片下半行：状态 · 用量（主人 2026-10-12）───────────
 *
 * 这两条原来在【右上角】（状态条）。主人要把它们收进输入卡片。
 * 两行都可点开看完整的（/status /usage）—— 所以它们是 button，不是 span。
 */
.cm-meta {
  display: flex; align-items: center; gap: 2px;
  /* ★ padding-left 7 不是随手写的：.cm-stat 自己有 7px 左内边距，
     7+7 = 14 = .cm-in 的 padding-left —— 于是状态文字跟输入框文字【左对齐】
     （实测差 4px → 调平） */
  /* ★ 2026-10-13：7px → 51px。因为 .cm-in 里多了个 36px 的加号（+ gap 8）——
     输入文字起点成了 14+36+8 = 58px；51+7 = 58，两条线才对得上。 */
  padding: 3px 6px 4px 51px;
  border-top: 1px solid var(--dsw-alias-border-l1);
  min-height: 26px;
}
/* ★ 手机（≤520px）把左缩进改回 7px —— 主人 2026-10-13 在手机上报：
 *   "发送框下方的 /status 那块没有顶到左边，而 /usage 顶右挺正常"。
 *
 *   根因：上面那 51px 是为"跟输入文字对齐"算的。桌面卡片宽 1000px，58px 只占 5%，
 *   看着是排版；手机卡片 ~336px，58px 占 1/6 —— 就成了"没顶格"。
 *   而 #usage 是 margin-left:auto 顶右的，一边顶一边缩，对比之下更明显。
 *
 *   改 7px 之后：7 + .cm-stat 自己的 7 = 14 = .cm-in 的 padding-left
 *   → 状态文字跟【＋ 按钮】左对齐（跟 #usage 顶右正好对称）。
 *   ★ 顺带解决：窄屏两段统计本来就不够放，腾出这 51px 就不挤了。
 *
 * ★ 必须放在 .cm-meta 规则【之后】：同特异性下源码顺序决定胜负，
 *   放到前面（比如 L636 那个 media 块里）会被上面那条覆盖 —— 看着像没生效。
 */
@media (max-width: 520px) {
  .cm-meta { padding-left: 7px; }
}
.cm-stat {
  display: flex; align-items: center; gap: 1px;
  min-width: 0; flex: 0 1 auto;
  padding: 4px 7px; border-radius: 6px;
  font-size: 11.5px; color: var(--dsw-alias-label-caption);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.cm-stat:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-secondary); }
.cm-stat i { font-style: normal; opacity: .35; margin: 0 2px; }
.cm-stat .warn { color: var(--dsw-alias-state-warn-label); }
/* 用量靠右（它跟左边的状态不是一类东西：一个是"我脑子里多满"，一个是"花了多少"） */
#usage { margin-left: auto; }
.conn { font-size: 12px; color: var(--dsw-alias-label-tertiary); white-space: nowrap; }


/* ─────────── 弹窗：头/尾 + 数据表 ─────────── */

.mhead { margin-bottom: 14px; }
.mhead h2 { font-size: 16px; font-weight: 600; margin: 0 0 3px; }
.mhead .sub { font-size: 12px; color: var(--dsw-alias-label-tertiary); word-break: break-all; }
.mfoot { display: flex; justify-content: flex-end; margin-top: 16px;
  padding-top: 12px; border-top: 1px solid var(--dsw-alias-border-l1); }

.sec { font-size: 13px; font-weight: 600; margin: 16px 0 7px;
  color: var(--dsw-alias-label-secondary); }
.sec:first-child { margin-top: 0; }

/* 键值表：名字在左、值在右（比一串 JSON 好读太多） */
.kv {
  display: grid; grid-template-columns: minmax(120px, max-content) 1fr;
  gap: 1px 16px; font-size: 13px;
}
.kvk { color: var(--dsw-alias-label-tertiary); padding: 4px 0; }
.kvv { color: var(--dsw-alias-label-primary); padding: 4px 0; word-break: break-all; }

/* 数据表 */
.tw { overflow-x: auto; border: 1px solid var(--dsw-alias-border-l1);
  border-radius: var(--dsw-radius-sm, 8px); }
.dt { border-collapse: collapse; width: 100%; font-size: 13px; }

/* ─────────── 长文本截断（主人 2026-10-12）───────────
 *
 * 「现在涉及长文本的比较丑，比如 prompt，能不能做成默认就一行、
 *   指上去用 prop 显示完整内容捏」
 *
 * 做法：全文照放 DOM，由 CSS 截成一行；悬停用原生 title 提示。
 * ★ 为什么不先截字符串：截了之后 hover 也没全文了。
 * ★ 为什么不用 JS 做 tooltip：原生 title 零代码、零维护，
 *   而且各平台行为一致（移动端长按也能看）。
 */
.trunc {
  display: inline-block; max-width: 24em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  vertical-align: bottom;
}
/* 表格里更紧一点（一列太宽会把其他列挤扁） */
.dt td .trunc { max-width: 19em; }

/* 任务列的主次两行：id 是主角，desc 是它的说明 */
.tid { font-weight: 500; }
.sti { width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px; opacity: .9; }
.sti.ok  { color: var(--dsw-alias-state-success-primary, #22c55e); }
.sti.warn{ color: var(--dsw-alias-state-warn-primary, #f59e0b); }
.sti.bad { color: var(--dsw-alias-state-error-primary, #ec1313); }
.sti.dim { opacity: .45; }
/* muted —— "这个不用点了"的次要说明（如 已打开 / 已暂停）。跟 .sti.dim 一个色。 */
.muted { opacity: .45; }
/* "启动中"的箭头转起来 —— 静态图标看不出"正在进行"（10-12） */
.sti.spin { animation: stspin 1.2s linear infinite; }
@keyframes stspin { to { transform: rotate(360deg); } }
.stt { font-size: 12.5px; }

/* 用量的合计行：一行、放最下面、标粗（主人 10-12） */
/* 表格的合计行（tfoot）—— 主人 10-12：「total 做成表格的一行、放最下面标粗」 */
.dt tfoot td {
  font-weight: 600;
  color: var(--dsw-alias-label-primary);
  border-top: 2px solid var(--dsw-alias-border-l2);
  background: var(--dsw-alias-bg-layer-1, transparent);
}

.tdesc { font-size: 11.5px; color: var(--dsw-alias-label-caption); margin-top: 2px; }
/* 相对时间（"+18h"）用小字跟在绝对时间后面 —— 一个给"什么时候"，一个给"还多久" */
.rel { font-size: 11.5px; color: var(--dsw-alias-label-caption); margin-left: 3px; }
/* 操作列里两个按钮之间留点空 */
.dt td .tbtn + .tbtn { margin-left: 6px; }

/* ─────────── 表格里的操作按钮（面板专属渲染用）───────────
   ★ 它是"面板才知道的交互"的落点：cron 的停用/启用、
     skill 的删除、sub 的派活 —— 都会长这样。 */
.tbtn {
  padding: 2px 10px; border-radius: 6px; font-size: 12px; line-height: 1.7;
  border: 1px solid var(--dsw-alias-border-l2);
  color: var(--dsw-alias-label-secondary); background: transparent;
  white-space: nowrap; cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.tbtn:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
/* 主操作（比如"启用"—— 那是把它打开，是个正向动作） */
.tbtn.on { color: var(--dsw-static-deepseek-500); border-color: currentColor; }
.tbtn:active { transform: translateY(1px); }
.dt th, .dt td { padding: 8px 12px; text-align: left; vertical-align: top;
  border-bottom: 1px solid var(--dsw-alias-border-l1); }
.dt th { background: var(--dsw-alias-markdown-code-block-banner); font-weight: 600;
  font-size: 12px; color: var(--dsw-alias-label-secondary); white-space: nowrap; }
.dt tr:last-child td { border-bottom: 0; }
.dt td .d { font-size: 11.5px; color: var(--dsw-alias-label-tertiary); margin-top: 2px; }
.dt td.r { text-align: right; white-space: nowrap; }

.empty { padding: 20px; text-align: center; font-size: 13px;
  color: var(--dsw-alias-label-tertiary); }

/* 长文本（比如 /skill 现在只给 text） */
.md-pre {
  margin: 0; padding: 12px 14px; border-radius: var(--dsw-radius-sm, 8px);
  background: var(--dsw-alias-markdown-code-block);
  font-family: var(--dsw-font-family, monospace); font-size: 12.5px;
  line-height: 1.65; overflow-x: auto; white-space: pre-wrap; word-break: break-word;
  color: var(--dsw-alias-label-primary);
}

/* ★ .pill（状态小标签）已于 2026-10-12 删除 —— 它只服务 MCP 面板，
   而 MCP 现在跟插件一样走 stateCell（图标 + 文字）；JS 侧 STATE_CN/STATE_CLS/
   statePill 也一起删了。留着的死 CSS 会让人以为"还有另一条路"。 */

.warn { color: var(--dsw-static-red-400); }

/* 深嵌套折叠 */
.deep { margin: 8px 0; }
.deep > summary {
  cursor: pointer; font-size: 13px; padding: 6px 0;
  color: var(--dsw-alias-label-secondary);
}
.deep > summary:hover { color: var(--dsw-alias-label-primary); }

/* ─────────── 气泡里的 Markdown ─────────── */
/* （渲染器在 markdown.js —— 它先把整段转义再做标记替换，
    所以这里只需管"长什么样"。） */

.b.md > *:first-child { margin-top: 0; }
.b.md > *:last-child  { margin-bottom: 0; }
.b.md p { margin: 0 0 8px; }
.b.md .md-h {
  font-size: 14.5px; font-weight: 600; margin: 12px 0 6px;
  padding-bottom: 3px; border-bottom: 1px solid var(--dsw-alias-border-l1);
}
.b.md h1.md-h { font-size: 16px; }
.b.md h2.md-h { font-size: 15px; }

.b.md ul, .b.md ol { margin: 0 0 8px; padding-left: 20px; }
.b.md li { margin: 2px 0; }

.b.md code {
  font-family: var(--dsw-font-family, monospace);
  font-size: 12.5px; padding: 1.5px 5px; border-radius: 5px;
  background: var(--dsw-alias-markdown-inline-code);
}
.b.md .md-code {
  margin: 8px 0; padding: 10px 12px; border-radius: var(--dsw-radius-sm, 8px);
  background: var(--dsw-alias-markdown-code-block);
  font-family: var(--dsw-font-family, monospace);
  font-size: 12.5px; line-height: 1.5; overflow-x: auto; white-space: pre;
  position: relative;
}
.b.md .md-code .md-lang {
  position: absolute; top: 6px; right: 10px; font-size: 10.5px;
  color: var(--dsw-alias-label-caption); text-transform: uppercase;
}
.b.md blockquote {
  margin: 8px 0; padding: 4px 0 4px 11px;
  border-left: 3px solid var(--dsw-alias-border-l3);
  color: var(--dsw-alias-label-secondary);
}
.b.md hr { border: 0; border-top: 1px solid var(--dsw-alias-border-l2); margin: 12px 0; }
.b.md a { color: var(--dsw-alias-link); text-decoration: none; }
.b.md a:hover { text-decoration: underline; }
.b.md .md-table {
  border-collapse: collapse; margin: 8px 0; font-size: 12.5px;
  display: block; overflow-x: auto; max-width: 100%;
}
.b.md .md-table th, .b.md .md-table td {
  border: 1px solid var(--dsw-alias-border-l2); padding: 5px 9px; text-align: left;
}
.b.md .md-table th { background: var(--dsw-alias-markdown-code-block-banner); font-weight: 600; }

/* ─────────── 滚动条 ───────────
 *
 * ★ 2026-10-12（主人："所有滚动条好像是默认样式，很丑"）
 *
 * 两层写（渐进增强）：
 *   ① 标准属性 scrollbar-width / scrollbar-color —— 新 Chrome / Edge / Firefox
 *   ② ::-webkit-scrollbar —— 旧 Chrome / Safari / Android WebView
 *
 * ★ 为什么两个都写而不是删一个：规范里【标准属性优先】——
 *   设了 scrollbar-color 之后，Chrome 会忽略 ::-webkit-scrollbar（不是冲突，是设计）。
 *   于是：新浏览器走 ①，旧浏览器走 ②，各拿各的。
 * ⚠️ iOS Safari 两个都不支持（系统限制：滚动条只在滑动时淡入）—— 改不了，也不该改。
 *
 * 手法：thumb 用 border + background-clip 收窄 2px —— 滚动条整体更细、不挡路；
 *       track 透明（不要那条灰底）。
 */
/* ★★ 2026-10-12 实测修正：vendor 的 --dsw-* 变量定义在【body】上
 *   （选择器是 `html[data-theme="dark"] body`），不是 :root。
 *   → 原来写在 `html {}` 里的 scrollbar-color 读不到变量 = 那条声明【无效】。
 *   → scrollbar-width / scrollbar-color 都是【继承属性】，挂在 body 上，
 *     所有后代（#list / .nav / .tr-pre / #modal）自动继承。
 *
 * 为什么用 @supports 隔离（实测踩过）：
 *   规范规定 —— 一旦 scrollbar-color/scrollbar-width 不是 auto，
 *   Chrome 会【忽略 ::-webkit-scrollbar】。而下面那段精细的自定义
 *   （收窄 2px + 圆角）比系统细条更好看。
 *   所以：Firefox 走标准属性，Chrome/Safari/Android 走 ::-webkit-scrollbar。
 */
@supports not selector(::-webkit-scrollbar) {
  body { scrollbar-width: thin; }
}
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb {
  background: var(--dsw-alias-scrollbar-bg-l1);
  border-radius: 99px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--dsw-alias-scrollbar-hover-l1);
  background-clip: padding-box;
}
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-corner { background: transparent; }

/* ── ★ 折叠块里的 markdown 也要防溢出（主人 2026-10-13 报的横滚条）──
 *
 * 根因：markdown 的规则【全都是 `.b.md`】—— 那是限定在消息气泡 `.b` 里的。
 *   而折叠块里我说的话是 `.tr-v.md`，【不在 `.b` 里】→ 那些规则一条都不生效：
 *   代码块没有 max-width、表格没有横向容器、手机上也不换行 →
 *   ★ 手机上就冒横向滚动条（长 content 尤其明显）。
 *
 * 这里给折叠块一份【防溢出最小集】—— 只做"不断破布局"，
 * 不动字号/间距（折叠块有自己的一套，比气泡小一号）。
 */
.tr-v.md { min-width: 0; }
.tr-v.md .md-code,
.tr-v.md pre {
  max-width: 100%;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.tr-v.md code { overflow-wrap: anywhere; word-break: break-word; }
/* 表格：宽表不撑破容器 —— 给它自己的横向滚动（而不是让整块溢出） */
.tr-v.md .md-table { display: block; max-width: 100%; overflow-x: auto; }

/* ★ 手机上让【代码块】也换行 —— 横滚条在手机上格外碍事。
   （代价：代码不再保持缩进对齐；但手机上"能读"比"对齐"重要。） */
@media (max-width: 520px) {
  .b.md .md-code { white-space: pre-wrap; overflow-wrap: anywhere; }
  .b.md .md-table { font-size: 12px; }
  /* ★ 折叠块在窄屏上更娇气：19px 的段详情缩进 + 7px 的图标间距一起挤，
     内容可用宽度就剩不下多少了 —— 手机上都收一点。 */
  .seg-more { padding-left: 9px; }
  .tr { gap: 5px; }
}

/* ── 注入折叠（记忆全文之类，2026-10-13）──
   ★ 它每轮都在、一条 16 KB —— 折叠成一行，点开才看。
   判据：它确实发生过（所以不隐藏），但它不是"谁说的话"（所以不占正屏）。 */
.inject {
  margin: 8px 0; border: 1px dashed var(--dsw-alias-border-l3);
  border-radius: 10px; background: var(--dsw-alias-bg-layer-1);
  font-size: 12.5px; opacity: .82;
}
.inject > summary {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 10px; cursor: pointer; list-style: none;
  color: var(--dsw-alias-label-tertiary);
}
.inject > summary::-webkit-details-marker { display: none; }
.inject .ic-i { width: 13px; height: 13px; flex: none; }
.inject .inj-t { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inject .inj-s { flex: none; font-variant-numeric: tabular-nums; }
.inject .inj-b {
  margin: 0; padding: 8px 10px; max-height: 240px; overflow: auto;
  border-top: 1px dashed var(--dsw-alias-border-l3);
  white-space: pre-wrap; word-break: break-word;
  font-family: ui-monospace, monospace; font-size: 11.5px; line-height: 1.5;
}
