/* ═══════════════════════════ 设计令牌 ═══════════════════════════
   跨境电商卖家后台的路子：冷灰画布托白卡片，橙色只给"要动手的地方"
   （主按钮、当前选中、数字重点），其余一律灰阶。这样满屏信息里
   橙色出现几次就是几个行动点，扫一眼就知道该点哪。

   颜色都跑过对比度：正文/语义色对各自底色 ≥4.5:1，白字压在 --accent-fill
   上 4.57:1。改色时别只挑好看的，先确认这两项还站得住。              */

:root {
  /* ── 表面：三层 ──
     画布(灰) → 卡片(白) → 次级面(浅灰填充，用在表头、输入框、标签底)。
     卡片和画布靠明度差自然分层，所以边框可以很轻。 */
  --bg: #f5f6f8;
  --bg-panel: #edeff3;
  --bg-elevated: #ffffff;
  --border: #e5e8ee;
  --border-strong: #d0d5de;

  /* ── 文字三级 ── */
  --text: #1d2129;        /* 16.1:1 */
  --text-soft: #4e5969;   /*  7.1:1 */
  /* 从 #6b7585 加深到 #5f6877。原来标的 4.7 是对着白卡量的，可这个令牌同样
     压在画布和次级面上（.composer-hint 在画布上，.count / .src-tag /
     .msg-collapsed 在次级面上），那两层只有 4.31 和 4.05 —— 底色越深，
     深色字的对比越小，必须按最差的那层来定。
     现在 卡片 5.63 / 画布 5.20 / 次级面 4.89，三层都有余量；对 --text-soft
     的 7.1 仍差着一档，三级文字的层次没有塌。别再往浅里调。 */
  --text-faint: #5f6877;

  /* ── 主色 ──
     accent 是"写在浅底上的橙字"，accent-fill 是"当底色的橙"。
     两者浅色档同值，深色档必须分开：深底上够亮的橙，白字压上去就糊了。 */
  --accent: #d6400f;
  --accent-fill: #d6400f;
  --on-accent: #ffffff;
  --accent-soft: #fff0ea;   /* 标签/选中项的淡橙底 */
  --accent-ink: #c7410c;    /* 压在 --accent-soft 上的字 */
  --brand: #ff5722;         /* 亮橙，只做装饰：进度条、图表、品牌标 —— 上面不压小字 */

  /* ── 语义色 ──
     每个都配一个 -soft 淡底，凑成状态胶囊（待处理/进行中/已完成/失败）。
     后台看的是状态流转，胶囊比纯文字快得多。 */
  --info: #165dff;   --info-soft: #eaf1ff;   --info-ink: #1550d6;
  --ok: #0c7c2e;     --ok-soft: #e8f7ec;
  --warn: #9c5400;   --warn-soft: #fff3e0;
  --danger: #d9302a; --danger-soft: #fdebea; --danger-ink: #c42822;

  --user-bubble: #eef1f6;

  /* ── 形状 ──
     比之前收了一档（12→8）。后台一屏几十个方块，圆角一大就全糊成
     圆饼，边界反而看不清。 */
  --radius-sm: 6px;
  --radius: 8px;
  --radius-lg: 12px;
  --pill: 999px;

  /* ── 投影 ──
     两级就够。卡片用 1 级（贴着画布），浮层用 2 级（真的浮起来）。
     冷灰画布上投影要带一点蓝，纯黑投影会显脏。 */
  --shadow-1: 0 1px 2px rgba(29, 33, 41, .04), 0 2px 8px rgba(29, 33, 41, .05);
  --shadow-2: 0 4px 12px rgba(29, 33, 41, .10), 0 12px 32px rgba(29, 33, 41, .10);
  --ring: 0 0 0 3px rgba(214, 64, 15, .14);   /* 聚焦光晕 */

  --sidebar-w: 268px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #161a20;
    --bg-panel: #1b2029;
    --bg-elevated: #1e242e;
    --border: #2c333f;
    --border-strong: #3a4250;

    --text: #e8eaf0;
    --text-soft: #a9b2c2;
    /* 从 #7c8598 提到 #8791a3。原来那一档只在最暗的画布上过线（4.71），
       但这个令牌绝大多数时候是压在卡片上的（.tile-sub / .card-sub / .msg-time /
       .session-meta 都是），那儿只有 4.21 —— 量的时候要对着它实际所在的
       那层表面量，不能只对画布。现在三层表面分别是 5.50 / 5.19 / 4.91，
       都站得住，同时仍比 --text-soft 暗一档，三级文字的层次没有塌。 */
    --text-faint: #8791a3;

    /* 橙字提亮到 #ff7a4d 才在深底上够亮(6.8:1)，但填充还得压回 #d6400f，
       否则白字只剩 2.8:1 —— 这就是 accent 和 accent-fill 分开的原因 */
    --accent: #ff7a4d;
    --accent-fill: #d6400f;
    --on-accent: #ffffff;
    --accent-ink: #ff9670;
    --brand: #ff5722;

    /* 这几个 -soft 淡底比"把浅色档调暗"要亮一档，是量过才定的：
       更暗的版本（#3a2118 那一档）和卡面 #1e242e 亮度几乎相同（对比 1.0），
       胶囊就只剩一团文字、看不出色块。现在每个淡底对卡面约 1.3，
       块的形状读得出来，压在上面的字仍有 4.9 以上。 */
    --accent-soft: #552e20;
    --info: #5e8cff;   --info-soft: #263657;   --info-ink: #8fadff;
    --ok: #3fbf5a;     --ok-soft: #1b3f26;
    --warn: #e8a13a;   --warn-soft: #483714;
    --danger: #f5645a; --danger-soft: #582a25; --danger-ink: #ff8a80;

    --user-bubble: #272e3a;

    /* 深色档靠明度分层，投影几乎看不见，只留一点点压住浮层的边 */
    --shadow-1: 0 1px 2px rgba(0, 0, 0, .28);
    --shadow-2: 0 8px 28px rgba(0, 0, 0, .46);
    --ring: 0 0 0 3px rgba(255, 122, 77, .18);
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.6 -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB",
        "Microsoft YaHei", "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

.app { display: flex; height: 100vh; overflow: hidden; }

/* ───────────────────────────── 侧边栏 ───────────────────────────── */

/* 导航条走白底：画布是灰的，白色侧栏自己就浮起来一层，
   不用再靠底色深浅去区分区域。 */
.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--bg-elevated);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  transition: margin-left .22s ease;
}
.sidebar.collapsed { margin-left: calc(-1 * var(--sidebar-w)); }

.sidebar-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 12px 12px 16px;
}
.brand { display: flex; align-items: center; gap: 9px; font-weight: 700; letter-spacing: .2px; }
/* 品牌标做成实心橙方块：电商后台的左上角基本都是一个色块 logo，
   比一个描边符号更像"平台"而不是"工具" */
.brand-mark {
  width: 22px; height: 22px; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-fill); color: var(--on-accent);
  border-radius: var(--radius-sm); font-size: 12px; line-height: 1;
}
.brand-text { font-size: 15px; }

/* 侧栏唯一的实心橙按钮 —— 整个左边就这一个主行动，不给它配对手 */
.new-chat {
  margin: 2px 12px 16px;
  padding: 10px 12px;
  background: var(--accent-fill);
  border: none;
  border-radius: var(--radius);
  color: var(--on-accent);
  font-size: 14px; font-weight: 600;
  cursor: pointer; text-align: left;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  box-shadow: var(--shadow-1);
  transition: filter .15s, box-shadow .15s, transform .06s;
}
.new-chat:hover { filter: brightness(1.08); box-shadow: var(--shadow-2); }
.new-chat:active { transform: translateY(1px); }
.new-chat:focus-visible { outline: none; box-shadow: var(--ring); }
.plus { font-size: 15px; font-weight: 700; }

.agent-picker { padding: 0 12px 14px; }
/* 分区标题不再全大写：中文标签套 uppercase 没有效果，
   letter-spacing 反而把"部门 Agent"撑散。改成小号粗体灰字。 */
.field-label {
  display: block; font-size: 11.5px; letter-spacing: .02em;
  color: var(--text-faint); margin-bottom: 6px; font-weight: 600;
}
#agent-select {
  width: 100%; padding: 8px 10px;
  background: var(--bg-panel); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: 13.5px; cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}
#agent-select:hover { border-color: var(--border-strong); }
#agent-select:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
.agent-theme {
  margin: 7px 2px 0; font-size: 11.5px; line-height: 1.5; color: var(--text-faint);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

.session-list-wrap { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.list-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 0 16px 6px; font-size: 11.5px;
  letter-spacing: .02em; color: var(--text-faint); font-weight: 600;
}
/* 数量做成小灰胶囊：它是个计数徽标，不是标题的一部分 */
.count {
  font-weight: 600; font-size: 11px; padding: 1px 7px;
  background: var(--bg-panel); border-radius: var(--pill);
  color: var(--text-faint); font-variant-numeric: tabular-nums;
}

.session-list { flex: 1; overflow-y: auto; padding: 0 8px 8px; }

.session-item {
  padding: 8px 10px 8px 12px; margin-bottom: 2px;
  border-radius: var(--radius-sm);
  cursor: pointer; position: relative;
  display: flex; flex-direction: column; gap: 2px;
  transition: background .13s;
}
.session-item:hover { background: var(--bg-panel); }
/* 选中态：淡橙底 + 左侧一条橙标。只靠底色的话，淡橙在灰白之间
   区分度不够；加根竖条，扫列表时一眼能定位到自己在哪。 */
.session-item.active { background: var(--accent-soft); }
.session-item.active::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--accent-fill);
}
.session-item.active .session-title { color: var(--accent-ink); font-weight: 600; }
.session-title {
  font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.session-meta {
  font-size: 11px; color: var(--text-faint); display: flex; gap: 7px;
  font-variant-numeric: tabular-nums;
}

/* 会话来源 —— 钉钉接管过来的和中台自建的要一眼分得开 */
.session-group {
  font-size: 11px; color: var(--text-faint); letter-spacing: .04em;
  padding: 12px 10px 5px; margin-top: 4px;
  border-top: 1px solid var(--border);
}
/* 来源标做成无框淡底胶囊。描边标签在密集列表里会织出一张网，
   淡底色块更安静，颜色本身就够把来源区分开。 */
.src-tag {
  display: inline-block; margin-right: 5px; padding: 0 7px;
  font-size: 10px; line-height: 16px; border-radius: var(--pill);
  vertical-align: 1px; font-weight: 600; border: none;
  background: var(--bg-panel); color: var(--text-faint);
}
/* 群会话只读，用更淡的样式提示"这条不能发消息" */
.src-tag.group { font-style: normal; background: var(--info-soft); color: var(--info-ink); }

/* 只读会话的输入区 */
.composer-note {
  margin: 0 24px 6px; font-size: 11.5px; color: var(--text-faint);
}
.composer.readonly {
  background: var(--bg-panel); opacity: .7;
}
.composer.readonly textarea { cursor: not-allowed; }

.sidebar-foot {
  border-top: 1px solid var(--border);
  padding: 8px 10px 9px; font-size: 11.5px; color: var(--text-faint);
}
.conn-line { display: flex; align-items: center; gap: 7px; padding: 6px 6px 0; }

.user-box { position: relative; }
.user-chip {
  width: 100%; display: flex; align-items: center; gap: 9px;
  background: transparent; border: none; cursor: pointer;
  padding: 7px 8px; border-radius: 9px; color: var(--text); text-align: left;
}
.user-chip:hover { background: var(--bg-panel); }
/* 头像用实心橙 + 白字：侧栏底部这一块信息最密，实心色块最先被看到，
   正好是"我是谁/切账号"的入口 */
.user-avatar {
  flex: 0 0 28px; height: 28px; border-radius: var(--radius-sm);
  background: var(--accent-fill); color: var(--on-accent);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
}
.user-info { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.user-name {
  font-size: 13px; font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.user-role { font-size: 10.5px; color: var(--text-faint); }
.chev { color: var(--text-faint); font-size: 10px; }

.user-menu {
  position: absolute; bottom: calc(100% + 4px); left: 6px; right: 6px;
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 5px; z-index: 30;
  box-shadow: var(--shadow-2);
}
.user-menu a, .user-menu button {
  display: block; width: 100%; text-align: left;
  padding: 7px 10px; border-radius: var(--radius-sm); border: none;
  background: transparent; color: var(--text); font: inherit;
  font-size: 13px; cursor: pointer; text-decoration: none;
}
.user-menu a:hover, .user-menu button:hover { background: var(--bg-panel); }
.user-menu button { color: var(--danger); }
.user-menu button:hover { background: var(--danger-soft); }
/* 状态点外面套一圈同色淡晕：纯 7px 圆点在灰底上几乎看不见，
   套晕之后视觉尺寸翻倍，但不占额外布局空间 */
.status-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--text-faint); flex: 0 0 auto;
  box-shadow: 0 0 0 3px var(--bg-panel);
}
.status-dot.ok { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); }
.status-dot.bad { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-soft); }

/* ───────────────────────────── 主区域 ───────────────────────────── */

/* min-width/min-height 都要显式压到 0：flex 子项默认是 auto，
   不能收缩到内容高度以下——消息一多就把整个容器撑开、顶掉输入框，
   而不是在消息区里出滚动条。 */
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0;
        position: relative; }

/* 顶栏也走白底 + 一条投影：和侧栏连成一个"L 形外壳"，中间灰色那块
   才是内容。后台界面靠这个 L 让人一眼分清"框架"和"数据"。 */
.topbar {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 20px; border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-1);
  z-index: 5;
}
.topbar-title { flex: 1; min-width: 0; }
.topbar-title h1 {
  margin: 0; font-size: 14.5px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.topbar-sub { font-size: 11.5px; color: var(--text-faint); }
.topbar-actions { display: flex; align-items: center; gap: 10px; }

/* min-width/height 28px 是给指针热区兜底的：原来 15px 字 + 4px 内边距只有
   ~29×23，高度差一点点够不上 WCAG 2.2 AA 的 24×24 下限。视觉大小没变，
   变的是能点中的范围。 */
.icon-btn {
  border: none; background: transparent; color: var(--text-soft);
  cursor: pointer; font-size: 15px; padding: 4px 7px;
  min-width: 28px; min-height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm); transition: background .13s, color .13s;
}
.icon-btn:hover { background: var(--bg-panel); color: var(--text); }
.icon-btn:focus-visible { outline: none; box-shadow: var(--ring); }
#expand-btn { display: none; }
#expand-btn.show { display: block; }

/* 次级按钮：白底描边。和实心橙的主按钮拉开层级 —— 一屏里只有一个
   实心橙，其余行动全长这样。 */
.ghost-btn {
  border: 1px solid var(--border-strong); background: var(--bg-elevated);
  color: var(--text-soft); border-radius: var(--radius-sm); padding: 5px 12px;
  font-size: 12px; font-weight: 500; cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.ghost-btn:hover {
  border-color: var(--accent); color: var(--accent); background: var(--accent-soft);
}
.ghost-btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* 整条都是 help 光标：这个百分比不自明，得让人知道"这儿能问" */
.context-meter { display: flex; align-items: center; gap: 7px; cursor: help; }
.meter-label { font-size: 11px; color: var(--text-faint); white-space: nowrap; }
.meter-bar {
  width: 82px; height: 6px; background: var(--bg-panel);
  border-radius: var(--pill); overflow: hidden;
}
.meter-fill {
  height: 100%; width: 0%; background: var(--ok);
  border-radius: var(--pill);
  transition: width .3s ease, background .3s;
}
/* 告警档用亮橙而不是 --warn：--warn 是给文字用的深棕橙，
   涂成 6px 细条就成了一根脏色；条状填充要的是饱和度。 */
.meter-fill.warn { background: var(--brand); }
.meter-fill.critical { background: var(--danger); }
.meter-text {
  font-size: 11px; color: var(--text-faint);
  font-variant-numeric: tabular-nums; font-weight: 600;
}

/* ───────────────────────────── 消息流 ───────────────────────────── */

/* 消息区做成浮在灰画布上的白卡片 —— 这是整套风格的主心骨：
   外壳(侧栏+顶栏)白、画布灰、内容白卡。三层一分，"框架"和"数据"
   就不会糊在一起。

   min-height:0 是滚动能生效的关键，理由见 .main 上的注释 */
.messages {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 26px 0 8px;
  margin: 14px 16px 0;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}

.empty-state {
  max-width: 440px; margin: 13vh auto 0; text-align: center; padding: 0 24px;
}
/* 空态标志：实心橙圆角方块，和侧栏品牌标同一个语言 */
.empty-mark {
  width: 46px; height: 46px; margin: 0 auto 16px;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; line-height: 1;
  background: var(--accent-soft); color: var(--accent);
  border-radius: var(--radius-lg);
}
.empty-state h2 { font-size: 20px; margin: 0 0 10px; font-weight: 700; }
.empty-state p { color: var(--text-soft); font-size: 14px; margin: 0; line-height: 1.7; }

.msg { max-width: 760px; margin: 0 auto 22px; padding: 0 24px; display: flex; gap: 13px; }
.msg-avatar {
  flex: 0 0 28px; height: 28px; border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 700; margin-top: 1px;
}
.msg.user .msg-avatar { background: var(--user-bubble); color: var(--text-soft); }
/* Agent 一侧用实心橙：一屏几十条消息，实心块是最快的"这是回答"的锚点 */
.msg.assistant .msg-avatar { background: var(--accent-fill); color: var(--on-accent); }
.msg-body { flex: 1; min-width: 0; }
.msg-role {
  font-size: 12px; font-weight: 600; color: var(--text-soft); margin-bottom: 3px;
  display: flex; align-items: baseline; gap: 7px;
}
/* 时间是辅助信息：比名字更小更淡，翻记录时想看就看得到，
   不看也不会跟名字抢注意力。tabular-nums 让上下行的时间对齐。 */
.msg-time {
  font-size: 10.5px; font-weight: 400; color: var(--text-faint);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.msg-content { white-space: pre-wrap; word-break: break-word; }

/* ── 提问：靠右、带底色气泡、头像和名字在右 ──
   问答一眼可辨，长会话往回翻时不用逐条读内容判断谁说的。 */
.msg.user { flex-direction: row-reverse; }

.msg.user .msg-body {
  /* flex:0 1 auto + align-items:flex-end：气泡按内容宽度收缩并靠右贴齐，
     短消息（"好"）就是个小气泡，不会拉成整行 */
  flex: 0 1 auto;
  max-width: 80%;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}
/* 提问那侧整体靠右，所以名字和时间的顺序也反过来（时间在左、名字贴边） */
.msg.user .msg-role { flex-direction: row-reverse; }

.msg.user .msg-content {
  background: var(--user-bubble);
  border: 1px solid var(--border);
  padding: 9px 14px;
  /* 右上角收成小圆角，指向头像一侧 */
  border-radius: var(--radius-lg) var(--radius-sm) var(--radius-lg) var(--radius-lg);
  text-align: left;
}
.msg.user .msg-files { justify-content: flex-end; }

/* ── 回答：靠左、无底色，正文直接铺开 ──
   报表和表格常常很宽，套气泡反而挤。 */
.msg.assistant .msg-content { max-width: 100%; }

/* 排队中的消息：灰显 + 一行小字说明，等当前回合结束会自动发出并点亮 */
.msg.queued { opacity: .5; }
.msg.user.queued .msg-body::after {
  content: "排队中 · 待当前回合完成";
  font-size: 11px; color: var(--text-faint); margin-top: 4px;
}

.msg-content p { margin: 0 0 10px; }
.msg-content p:last-child { margin-bottom: 0; }
.msg-content code {
  background: var(--bg-panel); padding: 1.5px 5px; border-radius: 4px;
  font-family: "SF Mono", ui-monospace, Menlo, monospace; font-size: 12.5px;
  color: var(--accent-ink);
}
.msg-content pre {
  background: var(--bg-panel); border: 1px solid var(--border);
  padding: 11px 13px; border-radius: var(--radius); overflow-x: auto; margin: 10px 0;
}
.msg-content pre code {
  background: transparent; padding: 0; font-size: 12.5px; line-height: 1.55;
  color: inherit;
}

/* 表格改成后台报表的样子：去掉竖线只留横线、表头压一层灰底、行级 hover。
   Agent 常常直接回一张报表，这里就是它最终被读的地方，值得按报表来排。 */
.msg-content table {
  border-collapse: collapse; margin: 12px 0; font-size: 13px; width: 100%;
  border: 1px solid var(--border); border-radius: var(--radius);
  overflow: hidden;
}
.msg-content th, .msg-content td {
  border: none; border-bottom: 1px solid var(--border);
  padding: 8px 11px; text-align: left;
}
.msg-content th {
  background: var(--bg-panel); font-weight: 600;
  color: var(--text-soft); font-size: 12px; white-space: nowrap;
}
.msg-content tbody tr:last-child td { border-bottom: none; }
.msg-content tbody tr:hover td { background: var(--bg-panel); }
/* 表格里的数字要竖向对齐才能比大小 */
.msg-content td { font-variant-numeric: tabular-nums; }

.msg-content ul, .msg-content ol { margin: 8px 0; padding-left: 22px; }
.msg-content li { margin: 3px 0; }
/* 链接用蓝不用橙：橙是"行动"，蓝是"跳转"，两种事分开 */
.msg-content a { color: var(--info); text-decoration: none; }
.msg-content a:hover { text-decoration: underline; }

.msg-files { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 7px; }
/* 附件做成可点的商品卡式 chip：hover 抬起一点 + 描边转橙，
   明确它是"能下载"的东西，不是一行文件名 */
.file-chip {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 6px 11px; font-size: 12.5px;
  text-decoration: none; color: var(--text); cursor: pointer;
  transition: border-color .15s, box-shadow .15s, transform .1s;
}
.file-chip:hover {
  border-color: var(--accent); box-shadow: var(--shadow-1);
  transform: translateY(-1px);
}
.file-chip .fi { color: var(--accent); }
.file-chip .fsize {
  color: var(--text-faint); font-size: 11px; font-variant-numeric: tabular-nums;
}

.working {
  max-width: 760px; margin: 0 auto 20px; padding: 0 24px 0 61px;
  color: var(--text-faint); font-size: 13px; display: flex; align-items: center; gap: 8px;
}
.dots { display: inline-flex; gap: 3px; }
.dots i {
  width: 4px; height: 4px; border-radius: 50%; background: var(--text-faint);
  animation: blink 1.3s infinite;
}
.dots i:nth-child(2) { animation-delay: .18s; }
.dots i:nth-child(3) { animation-delay: .36s; }
@keyframes blink { 0%, 60%, 100% { opacity: .25; } 30% { opacity: 1; } }

/* 提示条：淡底 + 同色左粗边。后台的报错要在满屏白卡里一眼跳出来，
   光靠一圈细描边不够。 */
.banner {
  max-width: 760px; margin: 0 auto 16px; padding: 10px 14px;
  border-radius: var(--radius); font-size: 13px;
  border: none; border-left: 3px solid;
  background: var(--bg-panel);
}
.banner.error {
  border-left-color: var(--danger); color: var(--danger-ink, var(--danger));
  background: var(--danger-soft);
}
.banner.warn {
  border-left-color: var(--brand); color: var(--warn);
  background: var(--warn-soft);
}

/* ───────────────────────────── 输入区 ───────────────────────────── */

.composer-wrap { padding: 12px 16px 16px; }

.attachments {
  max-width: 760px; margin: 0 auto 8px;
  display: flex; flex-wrap: wrap; gap: 7px;
}
.attachments:empty { margin: 0; }
.att-chip {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 5px 9px; font-size: 12px;
  box-shadow: var(--shadow-1);
}
.att-chip.pending { opacity: .6; }
.att-chip button {
  border: none; background: transparent; cursor: pointer;
  color: var(--text-faint); font-size: 13px; padding: 0 2px;
}
.att-chip button:hover { color: var(--danger); }

/* 输入框是消息卡之外的第二张白卡，浮在灰画布上。
   聚焦时橙边 + 光晕 —— 后台表单的标准反馈，告诉人"焦点在这儿"。 */
.composer {
  max-width: 760px; margin: 0 auto;
  display: flex; align-items: flex-end; gap: 8px;
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 8px 8px 8px 10px;
  box-shadow: var(--shadow-1);
  transition: border-color .15s, box-shadow .15s;
}
.composer:focus-within { border-color: var(--accent); box-shadow: var(--ring); }

#input {
  flex: 1; border: none; outline: none; resize: none;
  background: transparent; color: var(--text);
  font: inherit; line-height: 1.55; max-height: 190px; padding: 5px 2px;
}
#input::placeholder { color: var(--text-faint); }

/* 输入区那三个图标共用一套描边参数：18px 见方、2px 线宽、圆头圆角、
   颜色跟着 currentColor 走。改按钮文字色时图标自动跟上，不用单独维护。 */
.composer svg {
  width: 18px; height: 18px; display: block;
  fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}

.send-btn, .stop-btn {
  flex: 0 0 32px; height: 32px; border-radius: var(--radius-sm); border: none;
  cursor: pointer; font-size: 14px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  transition: filter .15s, background .15s;
}
.send-btn { background: var(--accent-fill); color: var(--on-accent); }
.send-btn:hover:not(:disabled) { filter: brightness(1.08); }
.send-btn:disabled { background: var(--bg-panel); color: var(--text-faint); cursor: not-allowed; }
.stop-btn { background: var(--danger); color: #fff; font-size: 10px; }
.stop-btn:hover:not(:disabled) { filter: brightness(1.08); }
/* 上面那条 display:flex 会盖掉浏览器给 [hidden] 的 display:none（作者样式压过 UA 样式），
   不补这一条，停止键就会在没有回合跑着的时候也一直挂在输入框上 */
.stop-btn[hidden] { display: none; }
.stop-btn:disabled { opacity: .6; cursor: default; }
.attach-btn { flex: 0 0 auto; font-size: 15px; padding: 5px 6px; }

.composer-hint {
  max-width: 760px; margin: 7px auto 0; font-size: 11.5px;
  color: var(--text-faint); text-align: center; min-height: 16px;
}
.composer-hint.warn { color: var(--warn); }
.composer-hint.critical { color: var(--danger); }

@media (max-width: 760px) {
  .sidebar { position: absolute; z-index: 20; height: 100%; box-shadow: var(--shadow-2); }
  .msg, .composer, .attachments, .composer-hint { padding-left: 14px; padding-right: 14px; }
  /* 窄屏上白卡贴边，别再为投影留外边距——横向空间比层次重要 */
  .messages { margin: 0; border-radius: 0; border-left: none; border-right: none; }
  .composer-wrap { padding: 10px 10px 12px; }
}

/* 从上游 *.jsonl.reset.* 捞回来的历史。这类会话在上游已被重置，
   Agent 不记得其中内容，只能查阅 —— 标记要和活跃的钉钉会话区分开。
   .src-tag 现在是无框胶囊，所以这里用一圈虚线描边单独标出来。 */
.src-tag.archive {
  border: 1px dashed var(--border-strong);
  line-height: 14px; background: transparent;
}

/* 跳转按钮。消息默认停在最新一条；接管过来的钉钉会话动辄几百条，
   想从头翻就点它跳到最早，到顶后按钮翻转成"回到最新"。
   放在 .main 上而不是 .messages 里——在滚动容器内部会跟着内容一起滚走。 */
.jump-btn {
  position: absolute; right: 30px; bottom: 132px; z-index: 6;
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--bg-elevated);
  color: var(--text-soft); cursor: pointer; font-size: 14px; line-height: 1;
  box-shadow: var(--shadow-2);
  display: flex; align-items: center; justify-content: center;
  transition: color .15s, border-color .15s;
}
.jump-btn:hover { color: var(--accent); border-color: var(--accent); }
.jump-btn[hidden] { display: none; }

/* ── 执行过程 ──
   长任务（翻译整本手册、跑一批报表）可能几分钟不出一个字。只挂一个
   "正在处理…"的话，人分不清它是在干活还是卡死了。这里把上游推来的
   每一步铺出来；出正文后自动收起，但保留可展开，方便回头看它做了什么。 */
.activity {
  max-width: 760px; margin: 4px auto 16px; padding: 0 24px;
}
.act-head {
  display: flex; align-items: center; gap: 7px; width: 100%;
  padding: 5px 0; border: none; background: transparent; cursor: pointer;
  color: var(--text-faint); font: inherit; font-size: 12px; text-align: left;
}
.act-head:hover { color: var(--text-soft); }
.act-caret { font-size: 9px; }
.act-count { margin-left: auto; font-variant-numeric: tabular-nums; }
.activity.collapsed .act-list { display: none; }

.act-list {
  border-left: 2px solid var(--border); padding: 2px 0 2px 12px; margin-left: 3px;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.act-row {
  display: flex; align-items: baseline; gap: 8px;
  padding: 3px 0; font-size: 12.5px; color: var(--text-soft);
}
.act-row.done { color: var(--text-faint); }
.act-mark { flex: 0 0 13px; font-size: 11px; color: var(--ok); }
.act-label { flex: none; }
.act-detail {
  color: var(--text-faint); font-size: 11.5px; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 转圈：正在进行的那一步 */
.act-spin {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  border: 1.5px solid var(--border-strong); border-top-color: var(--accent);
  animation: act-spin .7s linear infinite;
}
@keyframes act-spin { to { transform: rotate(360deg); } }

/* ── 后台任务 ──
   和"执行过程"不是一回事：执行过程属于某一个回合，回合一结束就收起来；
   后台任务是回合结束之后还在自己跑的活（翻整本手册要七八分钟），
   所以这张卡片跨回合常驻、不折叠——它是这段时间里唯一能看的东西。 */
/* 做成一张淡橙卡片。它常常是屏幕上唯一在动的东西，得像个"任务面板"
   而不是一行灰字——后台跑批处理时人就盯着这块看。 */
.job {
  max-width: 760px; margin: 10px auto; padding: 11px 14px;
  font-size: 12.5px; color: var(--text-soft);
  background: var(--accent-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
/* 跑完/跑挂了就退回中性底：淡橙是"正在进行"的信号，别一直亮着 */
.job.done, .job.failed, .job.stalled { background: var(--bg-panel); }
.job-head { display: flex; align-items: center; gap: 8px; }
.job-mark { flex: 0 0 13px; font-size: 11px; color: var(--accent); }
.job.done .job-mark { color: var(--ok); }
.job.failed .job-mark { color: var(--warn, #c2410c); }
.job.stalled .job-mark { color: var(--text-faint); }
.job-title { font-weight: 500; }
.job.stalled .job-title { color: var(--text-faint); }

/* 手动收起。平时几乎看不见——正常跑着的任务不需要人管；
   鼠标进到卡片上才亮出来，专给那些跑死了、赖着不走的卡片用。
   写"收起"而不是一个 ×：左边会话列表的删除键就是 ×，同一个符号会让人
   以为这一下删掉的是整条会话。 */
.job-close {
  margin-left: auto; padding: 1px 5px; border: none; background: transparent;
  color: var(--text-faint); font: inherit; font-size: 11.5px; line-height: 1.4;
  border-radius: 4px; cursor: pointer; opacity: 0;
  transition: opacity .15s, color .15s;
}
.job:hover .job-close, .job-close:focus-visible { opacity: 1; }
.job-close:hover { color: var(--text-soft); }
.job.failed .job-close, .job.stalled .job-close { opacity: 1; }
/* 触屏没有 hover，按钮就一直亮着——否则手机上那张卡片根本收不掉 */
@media (hover: none) { .job-close { opacity: 1; } }
.job-detail {
  margin: 3px 0 0 21px; color: var(--text-faint); font-size: 11.5px;
  white-space: pre-wrap; word-break: break-word;
}
.job-bar {
  margin: 8px 0 0 21px; height: 5px; border-radius: var(--pill);
  background: var(--bg-elevated); overflow: hidden;
}
.job-bar[hidden] { display: none; }
.job-bar i {
  display: block; height: 100%; width: 0; border-radius: var(--pill);
  background: var(--brand); transition: width .4s ease;
}
.job.done .job-bar i { background: var(--ok); }
/* 停住的进度条别再用高亮色：那根颜色是在说"正在往前走" */
.job.stalled .job-bar i, .job.failed .job-bar i { background: var(--border-strong); }

/* 群会话按人裁剪时，别人被折叠掉的轮次。刻意做得比消息弱：它是省略说明，
   不是对话内容，不能和真实气泡抢注意力。 */
.msg-collapsed {
  margin: 14px auto;
  padding: 4px 12px;
  max-width: fit-content;
  font-size: 12px;
  color: var(--text-faint);
  background: var(--bg-panel);
  border-radius: var(--pill);
  text-align: center;
  user-select: none;
}

/* 窗口级文件清单。默认折叠，展开后是一堆下载 chip。 */
.win-files {
  margin: 4px 4px 16px;
  padding: 8px 12px;
  font-size: 12.5px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.win-files > summary {
  cursor: pointer;
  color: var(--text-faint);
  user-select: none;
}
.win-files-body {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
  /* 三百多个文件时不让它无限长，自己滚 */
  max-height: 240px;
  overflow-y: auto;
}

/* ── 只给读屏软件的文字 ──
   视觉上完全不占位，但不能用 display:none 或 visibility:hidden ——
   那两个会把元素一起从无障碍树里摘掉，读屏就也读不到了。
   1px 裁剪盒是唯一既不占版面、又保留在无障碍树里的做法。 */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* 跳转到主内容。平时藏起来，Tab 第一下就把它顶出来 ——
   键盘用户不用挨个跳过侧栏里几十条会话才能摸到输入框。 */
.skip-link {
  position: absolute; top: 8px; left: 8px; z-index: 100;
  padding: 8px 14px; border-radius: var(--radius-sm);
  background: var(--accent-fill); color: var(--on-accent);
  font-size: 13px; font-weight: 600; text-decoration: none;
  transform: translateY(-200%);
  transition: transform .15s;
}
.skip-link:focus { transform: translateY(0); }

/* 上下文重置的断点。历史记录连续展示，但这条线必须看得见——否则用户会以为
   Agent 还记得上面的内容。用虚线而不是气泡：它是时间线上的刻度，不是消息。 */
.msg-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 20px 4px;
  font-size: 11.5px;
  color: var(--text-faint);
  text-align: center;
  user-select: none;
}
.msg-divider::before,
.msg-divider::after {
  content: "";
  flex: 1;
  border-top: 1px dashed var(--border-strong);
}

/* ═══════════════════════ 降低动态效果 ═══════════════════════
   系统里开了"减少动态效果"的人，看见位移、旋转、缩放会头晕。这里把这类
   运动一律掐掉。

   但不能一刀切成"全部不动"：转圈和跳点是这个界面里唯一在说"它还活着、
   没卡死"的东西——长任务可能几分钟不出一个字，静止的指示器和死掉的页面
   分不出来。所以做法是分开处理：

     位移/旋转/缩放 → 停（这类才是致晕的）
     透明度呼吸     → 留，但放慢（淡入淡出不引起前庭反应）

   旋转的小圈子改成整体明暗呼吸，语义不变，但不再有转动。 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }

  /* 两个"还在跑"的指示器单独放行，只保留明暗变化 */
  .dots i {
    animation: blink 2.2s infinite !important;
    animation-duration: 2.2s !important;
    animation-iteration-count: infinite !important;
  }
  .act-spin {
    animation: act-pulse 1.6s ease-in-out infinite !important;
    animation-duration: 1.6s !important;
    animation-iteration-count: infinite !important;
    border-top-color: var(--accent);
  }
}
@keyframes act-pulse { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
