/* @layer ui — Chat 工作区。
 *
 * 两个决定值得写下来：
 *   1. 助手的回答**不用气泡**。气泡适合短句，装不下带小标题、事实表和边界说明的长回答，
 *      而且视觉上幼稚。这里用编辑式排版：靠字阶、留白和一条极细的引导线建立层次。
 *      只有用户自己发的短消息用气泡——那是"我说的话"，短、要贴右、要有边界。
 *   2. 正文宽度锁在 42em 左右。再宽就不好读了，屏幕再大也一样。
 */

.chat-workspace {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 272px;
  height: 100%;
  min-height: 0;
  background: var(--bg);
}

.chat-stage {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  position: relative;
}

/* ---------------- 顶栏 ---------------- */

.chat-topbar {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 13px 22px;
  position: relative;
}
.chat-topbar::after {
  content: '';
  position: absolute; left: 22px; right: 22px; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--hairline) 8%, var(--hairline) 92%, transparent);
}

.chat-topbar__identity { display: flex; align-items: center; gap: 10px; min-width: 0; }
.chat-topbar__identity b {
  display: block;
  font-size: var(--fs-body);
  font-weight: 600;
  letter-spacing: var(--tracking-title);
}
.chat-topbar__identity small { display: block; font-size: var(--fs-micro); color: var(--text-faint); }

/* 品牌标记：用 logo 本体，不用三个方块拼一个"AI 图标" */
.chat-mark {
  width: 26px; height: 26px; flex: none;
  background: url('../../assets/logo.svg') center / contain no-repeat;
}

.chat-topbar__actions { display: flex; align-items: center; gap: 6px; }

.chat-model {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 10px 4px 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  max-width: 260px;
}
.chat-model i {
  width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: var(--text-faint);
}
.chat-model i.is-ready {
  background: var(--success);
  box-shadow: 0 0 0 2.5px color-mix(in srgb, var(--success) 20%, transparent);
}
.chat-model span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 显式钉住字号：<small> 的 UA 样式是 font-size: smaller，套在已经是 11px 的
   父级上会算成 9.17px —— 一个字阶表里根本不存在的尺寸，而且必然不过 AA。
   .chat-file small 同病。产品里其余的 <small> 都已经写了显式字号。 */
.chat-model small { font-size: var(--fs-micro); color: var(--text-faint); flex: none; }
.chat-model.is-actionable { cursor: pointer; font: inherit; }
.chat-model.is-actionable:hover { background: var(--surface-hover); color: var(--text); }
.chat-model.is-actionable:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.chat-model.is-actionable:disabled { cursor: wait; opacity: .72; }

.chat-icon-btn {
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-xs);
  color: var(--text-faint);
  font-size: var(--fs-small);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.chat-icon-btn:hover { background: var(--surface-hover); color: var(--text); }

/* ---------------- 消息流 ---------------- */

.chat-messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 26px 22px 8px;
  display: flex;
  flex-direction: column;
  gap: 26px;
}

.chat-message {
  width: 100%;
  max-width: var(--reading-w);
  margin: 0 auto;
  display: flex;
  gap: 12px;
}

/* 用户消息：贴右、用气泡、短 */
.chat-message.is-user { justify-content: flex-end; }
.chat-message.is-user .chat-avatar { display: none; }
.chat-message.is-user .chat-bubble {
  max-width: 82%;
  padding: 10px 14px;
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius-xs) var(--radius-lg);
  background: var(--accent-grad);
  color: var(--accent-text);
  box-shadow: var(--accent-glow);
}
.chat-message.is-user .chat-bubble__meta { display: none; }
.chat-message.is-user .chat-copy { color: inherit; }

/* 助手消息：编辑式排版，无气泡 */
.chat-message.is-assistant .chat-avatar {
  width: 26px; height: 26px; flex: none; margin-top: 1px;
  background: url('../../assets/logo.svg') center / contain no-repeat;
  font-size: 0;
}
.chat-message.is-assistant .chat-bubble { flex: 1; min-width: 0; }
.chat-message.is-assistant .chat-bubble__meta {
  display: flex; align-items: baseline; gap: 8px;
  margin-bottom: 6px;
}
.chat-bubble__meta span { font-size: var(--fs-tiny); font-weight: 600; color: var(--text-muted); }
.chat-bubble__meta time { font-size: var(--fs-micro); color: var(--text-faint); font-variant-numeric: tabular-nums; }

.chat-message.is-system { width: 100%; max-width: var(--reading-w); }
.chat-message.is-system .chat-avatar {
  width: 26px; height: 26px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: color-mix(in srgb, var(--success) 16%, transparent);
  color: var(--success);
  font-size: var(--fs-tiny);
}

.chat-copy { font-size: var(--fs-body); line-height: 1.75; white-space: pre-wrap; overflow-wrap: anywhere; }

.chat-message__tools { display: flex; gap: 10px; margin-top: 8px; align-items: center; }
/* 「已发送」压在强调色气泡上。原来是 --accent-text 的 72%：深色下 --accent-text
   是近黑的，压在 64% 明度的强调色上满不透明才 4.94:1，再打七折只剩 3.39:1。
   减淡的活交给字号（11px vs 正文 13.5px）与位置，不交给透明度。 */
.chat-delivery { font-size: var(--fs-micro); color: var(--accent-text); }
.chat-delivery.is-failed { color: var(--danger); }
.chat-speak,
.chat-save-progress {
  font-size: var(--fs-micro);
  color: var(--text-faint);
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
}
.chat-speak {
  opacity: 0;
  transition: opacity var(--dur) var(--ease), color var(--dur-fast) var(--ease);
}
.chat-save-progress {
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
/* 只在悬停时露出的按钮必须同时给键盘一条路，否则它在 Tab 序里是个隐形控件。
   .callist__edit 与 .task-card__remove 早就是这个写法，这里漏了。
   触摸设备没有悬停，一并常驻（与 .task-card__remove 的 @media (hover: none) 同例）。 */
.chat-message:hover .chat-speak,
.chat-speak:focus-visible { opacity: 1; }
@media (hover: none) {
  .chat-speak { opacity: 1; }
}
.chat-speak:hover,
.chat-save-progress:hover { color: var(--text); background: var(--surface-hover); }
.chat-save-progress:disabled { opacity: 0.48; cursor: wait; }

/* ---------------- 结构化回答：读起来像一份写好的文档 ---------------- */

.chat-answer { display: flex; flex-direction: column; gap: 14px; }
.chat-answer h3 {
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: 620;
  letter-spacing: var(--tracking-title);
  line-height: 1.35;
}
.chat-answer__lead { font-size: var(--fs-lead); line-height: 1.7; color: var(--text-muted); }

/* 事实表：左标签右值，靠发丝线分行，不用卡片堆叠 */
.chat-facts { display: flex; flex-direction: column; }
.chat-facts > div {
  display: grid;
  grid-template-columns: minmax(84px, 26%) 1fr;
  gap: 4px 14px;
  padding: 9px 0;
  border-top: 1px solid var(--hairline);
  align-items: baseline;
}
.chat-facts > div:last-child { border-bottom: 1px solid var(--hairline); }
.chat-facts dt { font-size: var(--fs-small); color: var(--text-faint); }
.chat-facts dd { font-size: var(--fs-body); font-weight: 500; }
.chat-facts small { grid-column: 2; font-size: var(--fs-micro); color: var(--text-faint); }

/* 分区：一条竖线 + 小号标签，颜色区分类型 */
.chat-answer__section {
  padding-left: 14px;
  border-left: 2px solid var(--border);
  display: flex; flex-direction: column; gap: 7px;
}
.chat-answer__section header { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.chat-answer__section header span {
  font-size: var(--fs-micro);
  font-weight: 620;
  letter-spacing: var(--tracking-caps);
  color: var(--text-faint);
}
.chat-answer__section h4 { font-size: var(--fs-body); font-weight: 600; }
.chat-answer__section p { font-size: var(--fs-body); line-height: 1.75; color: var(--text-muted); }
.chat-answer__section ul { display: flex; flex-direction: column; gap: 5px; }
.chat-answer__section li {
  font-size: var(--fs-body); line-height: 1.7; color: var(--text-muted);
  padding-left: 15px; position: relative;
}
.chat-answer__section li::before {
  content: ''; position: absolute; left: 2px; top: 0.68em;
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--text-faint);
}
.chat-answer__section.is-interpretation { border-left-color: var(--accent-line); }
.chat-answer__section.is-interpretation header span { color: var(--accent-ink); }
.chat-answer__section.is-recommendation { border-left-color: color-mix(in srgb, var(--success) 42%, transparent); }
.chat-answer__section.is-recommendation header span { color: var(--success); }
.chat-answer__section.is-warning { border-left-color: color-mix(in srgb, var(--warning) 52%, transparent); }
.chat-answer__section.is-warning header span { color: var(--warning); }

.chat-caveats {
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  display: flex; flex-direction: column; gap: 6px;
}
.chat-caveats b { font-size: var(--fs-micro); font-weight: 620; letter-spacing: var(--tracking-caps); color: var(--text-faint); }
.chat-caveats li { font-size: var(--fs-small); line-height: 1.65; color: var(--text-muted); }
.chat-caveats li + li { margin-top: 4px; }

.chat-next-question {
  font-size: var(--fs-small);
  color: var(--text-muted);
  padding-left: 14px;
  border-left: 2px dashed var(--border);
}

/* ---------------- 空状态：安静，不推销 ---------------- */

.chat-welcome {
  width: 100%;
  max-width: 42em;
  margin: auto;                 /* 空状态时垂直居中，比顶在上面从容 */
  padding: 32px 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.chat-welcome__mark {
  width: 44px; height: 44px;
  background: url('../../assets/logo.svg') center / contain no-repeat;
  margin-bottom: 4px;
}
.chat-welcome h2 {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 600;
  letter-spacing: var(--tracking-hero);
  line-height: 1.2;
}
.chat-welcome p { font-size: var(--fs-lead); color: var(--text-muted); }

/* Continuity 是一张可核对的工作检查点，不是第二套首页。它沿用计划确认卡的
   纸面层级，但不使用强调色大面积铺底，避免把“恢复上下文”误读成“已经执行”。 */
.chat-continuity {
  margin-top: 8px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-grad);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.chat-continuity > header {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
}
.chat-continuity > header span {
  font-size: var(--fs-micro); font-weight: 650; letter-spacing: var(--tracking-caps); color: var(--accent-ink);
}
.chat-continuity > header small,
.chat-continuity__scope { font-size: var(--fs-micro); color: var(--text-faint); line-height: 1.5; }
.chat-continuity h3 { font-size: var(--fs-title); font-weight: 620; line-height: 1.35; }
.chat-welcome .chat-continuity > p { font-size: var(--fs-body); line-height: 1.65; color: var(--text-muted); }
.chat-continuity dl {
  display: grid; grid-template-columns: 54px minmax(0, 1fr); gap: 9px;
  padding-top: 9px; border-top: 1px solid var(--hairline);
}
.chat-continuity dt { font-size: var(--fs-micro); color: var(--text-faint); }
.chat-continuity dd { font-size: var(--fs-small); line-height: 1.55; color: var(--text); }
.chat-continuity footer { display: flex; justify-content: flex-end; gap: 7px; margin-top: 3px; }

/* 新用户说明保持一段轻提示，不扩成能力卡片墙。 */
.chat-first-run {
  margin-top: 8px;
  padding: 12px 14px;
  border-left: 2px solid var(--accent-line);
  background: var(--surface-2);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  display: flex; flex-direction: column; gap: 5px;
}
.chat-first-run header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.chat-first-run header b { font-size: var(--fs-small); font-weight: 620; }
.chat-first-run header button { min-width: 28px; min-height: 28px; color: var(--text-faint); }
.chat-welcome .chat-first-run p { font-size: var(--fs-small); line-height: 1.55; color: var(--text-muted); }
.chat-first-run strong { color: var(--text); font-weight: 600; }

/* 起手式是一句话，不是一张卡片。
   等宽网格会把长短不一的句子拉成参差的方块，读起来像四个待办；
   换成随内容收缩、自然换行的一行文字，视线只需扫过去。 */
.chat-suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 18px;
}
.chat-suggestions button {
  max-width: 100%;
  text-align: left;
  padding: 7px 13px;
  border-radius: var(--radius-pill);
  /* 令牌表：--border 是"一个真实物体的边（卡、输入框、面板）"，
     --border-strong 才是"可交互物体的边"。这两枚是空屏上**唯一**能点的东西，
     实测 --border 压在纸上只有 1.18:1，够不着 WCAG 1.4.11 给界面组件的 3:1。 */
  border: 1px solid var(--border-strong);
  /* 透明底的芯片只剩一圈线，读不出"这是能点的"。给它一层底，与所在的面差一级。
     方向取决于那一面在梯子上的位置：芯片长在**内容面**上就往下沉一级（浮窗里就是这样，
     那里的地就是纸）；这里它长在 --bg 这块**地**上，只能往上浮——浮到 --surface，
     也就是"地不是白的，纸才是白的"里的那张纸。
     （--surface-2 也在地之上，但在浅色的白端只差 1.3 个 L*，几乎看不出来；
     --surface 在浅深两套里分别是 2.7 与 5.2 个 L*，两边都立得住。）
     hover 换成 --accent-soft：从"一片纸"变成"一片带色的纸"，不加投影。 */
  background: var(--surface);
  font-size: var(--fs-small);
  line-height: 1.4;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.chat-suggestions button:hover {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  color: var(--text);
}

/* ---------------- 思考中 ---------------- */

.chat-thinking { display: flex; align-items: center; gap: 4px; padding-top: 4px; }
.chat-thinking i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--text-faint);
  animation: chat-dot 1.3s ease-in-out infinite;
}
.chat-thinking i:nth-child(2) { animation-delay: 0.16s; }
.chat-thinking i:nth-child(3) { animation-delay: 0.32s; }
.chat-thinking span { font-size: var(--fs-small); color: var(--text-faint); margin-left: 7px; }
@keyframes chat-dot { 0%, 60%, 100% { opacity: 0.28; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-2.5px); } }

/* ---------------- 计划确认 ---------------- */

.chat-plan {
  width: 100%;
  max-width: 42em;
  margin: 0 auto;
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-lg);
  background: var(--surface-grad);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.chat-plan > header {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  padding: 14px 16px 12px;
  background: var(--accent-soft);
}
/* 这一行正压在 --accent-soft 的卡头上，深色下必须走 --accent-ink（见 themes.css）。 */
.chat-plan > header span { font-size: var(--fs-micro); font-weight: 620; letter-spacing: var(--tracking-caps); color: var(--accent-ink); }
.chat-plan > header h3 { font-size: var(--fs-body); font-weight: 600; margin-top: 3px; line-height: 1.5; }
/* 这一行也压在 --accent-soft 的卡头上。第三级墨压在被强调色拉过一层的地上
   实测最低 4.13:1（深色 / 墨色板），够不着 AA —— 升到 muted（最差 6.19:1）。
   同一张卡里 span 走 --accent-ink、b 走 --text-muted，两条都在"能读"的一侧。 */
.chat-plan > header b { font-size: var(--fs-small); color: var(--text-muted); font-variant-numeric: tabular-nums; flex: none; }

.chat-plan__items { display: flex; flex-direction: column; }
.chat-plan__item {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 16px;
  border-top: 1px solid var(--hairline);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.chat-plan__item:hover { background: var(--surface-hover); }
.chat-plan__item.is-selected { background: var(--accent-soft); }
.chat-plan__item input { margin-top: 2px; accent-color: var(--accent); }
.chat-plan__icon {
  width: 22px; height: 22px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-xs);
  background: var(--surface-sunken);
  font-size: var(--fs-tiny); color: var(--text-muted);
}
.chat-plan__item > span:last-child { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.chat-plan__item small { font-size: var(--fs-micro); color: var(--text-faint); letter-spacing: var(--tracking-caps); }
/* 选中行的地是 --accent-soft，第三级墨压上去掉到 4.13:1（深色）。
   与 .palette__item.is-active .palette__hint 同一个处理：换级，不换透明度。 */
.chat-plan__item.is-selected small { color: var(--text-muted); }
.chat-plan__item b { font-size: var(--fs-body); font-weight: 550; }
.chat-plan__item em { font-size: var(--fs-small); color: var(--text-muted); font-style: normal; }
.chat-plan__item q {
  font-size: var(--fs-small); color: var(--text-muted);
  border-left: 2px solid var(--border); padding-left: 9px; margin-top: 4px;
  quotes: none; display: block;
}
.chat-plan__warning { padding: 10px 16px; font-size: var(--fs-small); color: var(--warning); border-top: 1px solid var(--hairline); }
.chat-plan > footer {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--hairline);
  background: var(--surface-2);
}

/* ---------------- 输入区 ---------------- */

.chat-composer-wrap {
  flex: none;
  padding: 8px 22px 16px;
  display: flex; flex-direction: column; gap: 8px;
  background: linear-gradient(180deg, transparent, var(--bg) 26%);
}
.chat-composer-wrap > * { max-width: var(--reading-w); margin-left: auto; margin-right: auto; width: 100%; }

/* 这一块**不**按"表单域要下沉"处理，理由见下：
   编辑器里的域下沉，是因为它们长在 --surface 的内容面上，同色就只剩描边；
   而输入区浮在 --bg 这块"地"上——地本来就是浅色里最暗的一级。
   照着往下沉，就要沉到比地还暗，整屏最大的一块书写面会变成整屏最暗的东西，
   与"地不是白的，纸才是白的"正好相反。所以它仍然是一张**抬起来的纸**：
   --surface-grad（同一级明度 + 1% 行程的微渐变，把平色换成材质），
   加 --shadow-md 的接触影。聚焦时的柔光环与全局 :focus-visible 同一道。 */
.chat-composer {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface-grad);
  box-shadow: var(--shadow-md);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  overflow: hidden;
}
.chat-composer:focus-within {
  border-color: var(--accent);
  box-shadow: var(--shadow-md), 0 0 0 3.5px var(--accent-soft);
}
.chat-composer textarea {
  width: 100%;
  border: none;
  background: none;
  resize: none;
  padding: 13px 15px 6px;
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--text);
  outline: none;
  /* 这个上限的意思是"输入框最多吃掉四成**看得见的**高度，剩下的留给对话"。
     所以分母必须是当前真正能看见的那一段，而不是屏幕高：
       · 40vh（== lvh）量的是地址栏收起时的高度，Safari 标签页里超发；
         更要命的是它对键盘一无所知 —— 390×844 上 40vh = 338px，
         而键盘弹起后整个可视区只剩约 508px，输入框一涨到 338，
         下面那条控件栏（含发送键）连同上面的对话一起被挤出屏幕。
       · svh 是恒定的下界，不跟键盘走，同样漏掉键盘那一段。
       · dvh 会跟地址栏实时变 —— 对一个**增长上限**来说这正是想要的：
         它只在输入框已经顶到上限时才起作用，不会造成任何回流抖动。
     再减 --kb，把键盘那一段也算进去。写两行：第一行给不认 dvh 的浏览器兜底。 */
  max-height: 40vh;
  max-height: calc((100dvh - var(--kb)) * 0.4);
}
.chat-composer textarea::placeholder { color: var(--text-faint); }

.chat-composer__bar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 6px 8px 8px 10px;
}
.chat-composer__bar > div { display: flex; align-items: center; gap: 2px; }

.chat-tool {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 9px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-micro);
  color: var(--text-faint);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.chat-tool:hover { background: var(--surface-hover); color: var(--text-muted); }
.chat-tool.is-active { color: var(--accent-ink); background: var(--accent-soft); }
.chat-tool input[type='file'] { display: none; }
.chat-tool span[aria-hidden] { font-size: var(--fs-tiny); }
/* 上下文的价钱一直挂在按钮上——面板关着也看得见。
   看不见价钱的选择不是选择（app/domain/profile.js 的第四条前提）。 */
.chat-tool b { font-weight: 600; font-variant-numeric: tabular-nums; }
.chat-tool.is-active b { color: var(--accent-ink); }

/* 发送键。改了两处，两处都不是新设计，而是"这个仓库里已经有的做法"：
   1) 形状 999px → --radius-sm。这套令牌里胶囊是**芯片和输入域**的形状
      （顶栏搜索、模型芯片、标签、起手式芯片、task-follow-chip），
      按钮一律 --radius-sm（.btn / .btn--primary / .wg__send 都是 8px）。
      令牌表自己写着"圆角偏小 = 精密仪器；偏大 = 亲切模板，这里选前者"——
      一枚渐变胶囊发送键正好是所有 AI 聊天壳子的同一张脸。
   2) 静息（未输入 → disabled）态。原来是 opacity: 0.4 罩在实心强调色上：
      实测底色 rgb(162,174,225)、白字 rgb(248,249,250)，对比 2.09:1，
      "发送"两个字在默认状态下是读不出来的——而默认状态正是每次打开 Chat 看到的样子。
      浮窗里同一个按钮早就解决过（widget.css 的 .wg__send）：不可用时是一枚
      中性键（10% 墨底 + --text-muted），可用时才整块填成强调色。照抄那一条。
   填充改成实心 var(--accent) 也是对齐 .btn--primary 与 .wg__send.is-ready；
   --accent-grad 留给用户气泡（.chat-bubble），那里它是对的。 */
.chat-send, .chat-cancel {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 13px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-small);
  font-weight: 550;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease), transform var(--dur-press) var(--ease);
}
.chat-send { background: var(--accent); color: var(--accent-text); box-shadow: var(--accent-glow); }
.chat-send:hover:not(:disabled) { background: var(--accent-hover); }
.chat-send:active:not(:disabled) { transform: scale(0.97); }
.chat-send:disabled {
  opacity: 1;
  background: color-mix(in srgb, var(--text) 10%, transparent);
  color: var(--text-muted);
  box-shadow: none;
}
/* 箭头不靠 opacity 减淡：0.85 罩在 --accent-text 上实测 4.47:1（赭石色板），
   刚好跌破 AA —— 而它和"发送"两个字在同一枚键上，字号（11 vs 13）已经分好主次了。
   与 .chat-delivery 同一条：减淡的活交给字号，不交给透明度。 */
.chat-send span { font-size: var(--fs-micro); }
.chat-cancel { background: var(--surface-hover); color: var(--text-muted); }

.chat-capability { font-size: var(--fs-micro); color: var(--text-faint); text-align: center; line-height: 1.6; }

/* 底原来是 color-mix(--danger 10%, transparent)：透明底意味着它继承脚下那块**地**
   （输入区长在 --bg 上，浅色里最暗的一级），于是红字压在"红 + 地"上只有 4.27:1。
   同一种"淡红提示面"在编辑器里是 color-mix(--danger 6%, var(--surface))——混的是**纸**。
   两处本该是同一个物体：按 UI_PATTERNS §0 推论二，长在地上的面要抬起成纸。
   混进 --surface 后实测浅色最差 4.70:1、深色 5.58:1。 */
.chat-error {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  background: var(--danger-surface);
  border: 1px solid var(--danger-line);
  color: var(--danger-ink);
  font-size: var(--fs-small);
  box-shadow: var(--shadow-inset);
}
.chat-error span {
  min-width: 0;
  max-height: min(5.1em, 22dvh);
  overflow: auto;
  line-height: 1.65;
  overflow-wrap: anywhere;
}
.chat-error button {
  flex: none;
  align-self: flex-start;
  width: 28px;
  height: 28px;
  color: inherit;
  font-size: var(--fs-lead);
  border-radius: var(--radius-xs);
}
.chat-error button:hover { background: color-mix(in srgb, var(--danger) 10%, transparent); }

.chat-files { display: flex; gap: 7px; flex-wrap: wrap; }
.chat-file {
  display: flex; align-items: center; gap: 7px;
  padding: 5px 8px 5px 5px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  font-size: var(--fs-micro);
  max-width: 220px;
}
.chat-file img { width: 26px; height: 26px; border-radius: var(--radius-xs); object-fit: cover; flex: none; }
.chat-file > span {
  width: 26px; height: 26px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-xs);
  background: var(--surface-sunken);
  font-size: var(--fs-micro); color: var(--text-faint);
}
.chat-file b { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-file small { font-size: var(--fs-micro); color: var(--text-faint); flex: none; }
.chat-file button { color: var(--text-faint); font-size: var(--fs-small); flex: none; }
.chat-file button:hover { color: var(--danger); }

/* 附件外发确认。它从"上下文"面板里搬了出来：那里面现在是两把管范围的刻度尺，
   而附件是一次性的、只有选了文件才存在的一道**是非题**，不是范围。
   （搬出来还顺手治好一件事：这道确认原先只长在那块打不开的面板里，
     于是附件其实一直发不出去——send() 会拦下没勾过的附件。） */
.chat-share-files {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 12px;
  border-radius: var(--radius);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: var(--fs-small);
  color: var(--text-muted);
  cursor: pointer;
}
.chat-share-files input { accent-color: var(--accent); flex: none; }
@media (max-width: 820px) { .chat-share-files { min-height: 44px; } }

/* ---------------- 右栏：今天 ---------------- */

/* 与待办面的 .tasks-rail 是同一个组件（272px、发丝线左边、--surface-2 的面、
   自己滚动）。此前左右内边距 16 vs 20、分区间距 16 vs 24 —— 两个人各排了一次。
   横向内边距与分区间距归到待办那一套；只有**上内边距**保留差异，
   那一个是有理由的：对话面上面还有一条 13px 内边距的 .chat-topbar，
   右栏的第一行要和顶栏里的名字对齐，待办面没有这条栏。 */
.chat-pulse {
  border-left: 1px solid var(--hairline);
  background: var(--surface-2);
  padding: 14px 20px;
  overflow-y: auto;
  display: flex; flex-direction: column; gap: 24px;
}
.chat-pulse > header { display: flex; align-items: center; justify-content: space-between; }
.chat-pulse > header span {
  font-size: var(--fs-micro); font-weight: 620;
  letter-spacing: var(--tracking-caps); color: var(--text-faint);
}
.chat-pulse > header button { font-size: var(--fs-micro); color: var(--accent-ink); }
.chat-pulse > header button:hover { text-decoration: underline; }

.chat-pulse__hero {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 14px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--hairline);
}
.chat-pulse__hero strong {
  font-family: var(--font-display);
  font-size: var(--fs-display); font-weight: 600; line-height: 1;
  letter-spacing: var(--tracking-hero);
  font-variant-numeric: tabular-nums;
}
.chat-pulse__hero.is-alert { border-color: color-mix(in srgb, var(--today) 30%, transparent); }
.chat-pulse__hero.is-alert strong { color: var(--today); }
.chat-pulse__hero b { display: block; font-size: var(--fs-small); font-weight: 550; }
.chat-pulse__hero small { display: block; font-size: var(--fs-micro); color: var(--text-faint); line-height: 1.5; margin-top: 1px; }

.chat-pulse__section { display: flex; flex-direction: column; gap: 7px; }
.chat-pulse__section h3 {
  font-size: var(--fs-micro); font-weight: 620;
  letter-spacing: var(--tracking-caps); color: var(--text-faint);
}
.chat-pulse__section p { font-size: var(--fs-small); color: var(--text-faint); }
.chat-pulse__section ol { display: flex; flex-direction: column; gap: 5px; }
.chat-pulse__section li { display: flex; gap: 9px; font-size: var(--fs-small); align-items: baseline; }
.chat-pulse__section time { color: var(--text-faint); font-variant-numeric: tabular-nums; flex: none; width: 38px; }
.chat-pulse__section li span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.chat-pulse__stats { display: flex; gap: 6px; }
.chat-pulse__stats span {
  flex: 1;
  display: flex; flex-direction: column; gap: 1px;
  padding: 8px 9px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--hairline);
  font-size: var(--fs-micro); color: var(--text-faint);
}
.chat-pulse__stats b { font-size: var(--fs-lead); font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.chat-pulse__stats .is-alert b { color: var(--today); }

.chat-brief-btn {
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);   /* 同上：这是按钮，不是面板 */
  background: var(--surface);
  font-size: var(--fs-small);
  color: var(--text);
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.chat-brief-btn:hover { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent-ink); }

/* ---------------- 语音 ----------------

   一条状态行，长在撰写卡**上面**（和附件条、上下文面板同一列，共用 42em 的中线）。
   为什么不把状态塞进麦克风按钮里：语音有五种状态（用不了 / 没授权 / 在听 /
   正在识别 / 听完等确认），一枚按钮最多表达两种。而"现在到底在不在听"
   正是这个功能唯一要回答的问题——答不清楚，用户就会对着一个没在录的窗口说完一整句。

   材质跟 .chat-composer 一份（抬起来的纸 + 接触影）：它是撰写卡在这一刻多长出来的一截，
   不是另一个物体。所以它不上色——上色的只有那颗 5px 的点。 */
/* 语音条的插槽：一直在，空的时候不占位。
   它存在的理由不是样式，是为了让语音状态能就地重画而不用整体重绘——
   整体重绘会把正在被指针捕获的麦克风键换掉，"松开说完了"就再也收不到。
   **不能写 display: contents**：上面那条 `.chat-composer-wrap > *` 的 42em 槽宽
   就落在这枚插槽身上，而 contents 不生成盒子，于是语音条会比撰写卡宽一截。 */
.chat-voice-slot:empty { display: none; }

.chat-voice {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px 7px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-grad);
  box-shadow: var(--shadow-sm);
  font-size: var(--fs-small);
  color: var(--text-muted);
  min-width: 0;
}
.chat-voice__label {
  flex: none;
  display: inline-flex; align-items: baseline; gap: 5px;
  color: var(--text); font-weight: 560;
}
.chat-voice__label small { font-size: var(--fs-micro); font-weight: 400; color: var(--text-faint); }
/* 中途结果。一行、超出省略：它是"我说的话正在被听见"的凭据，不是最终稿，
   让它换行会把整条状态行撑成一块会跳动的面。 */
.chat-voice__text {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text);
}
.chat-voice.is-listening .chat-voice__text,
.chat-voice.is-finalizing .chat-voice__text { color: var(--text-muted); }
.chat-voice__acts { flex: none; display: flex; align-items: center; gap: 6px; }

/* 录音指示：一颗 5px 的点，不是跳动的大红点。
   尺寸与做法照 widget.css 的 .wg__ailamp（那盏"模型已接入"的绿灯）——
   同一个角色（一盏指示灯）在两个窗口只能有一种长相。
   红色只用在这一颗点上：它要一眼与"绿=已接入"分开，而"正在录音"是全世界都认得红。
   呼吸 2.4s 且只在明暗之间走，不缩放——会变大的点会把视线从正在上屏的字上拽走。 */
.chat-voice__dot,
.chat-tool__dot {
  flex: none;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--text) 30%, transparent);
}
.chat-voice__dot {
  background: var(--danger);
  box-shadow: 0 0 0 2.5px color-mix(in srgb, var(--danger) 14%, transparent);
}
.chat-voice.is-finalizing .chat-voice__dot {
  background: var(--text-faint);
  box-shadow: none;
}
.chat-tool.is-active .chat-tool__dot {
  background: var(--danger);
  box-shadow: 0 0 0 2.5px color-mix(in srgb, var(--danger) 14%, transparent);
}
@media (prefers-reduced-motion: no-preference) {
  .chat-voice.is-listening .chat-voice__dot,
  .chat-tool.is-active .chat-tool__dot { animation: chat-voice-breath 2.4s var(--ease) infinite; }
}
@keyframes chat-voice-breath {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}

/* 入口在，但这一次用不了（没授权 / 拔了麦克风 / 外壳太老）。
   不用 disabled：禁用的按钮不会解释自己，而这几种状态恰恰是用户**能做点什么**的。
   点下去会把原因写在上面那条状态行里，所以它必须看得出可以点。 */
.chat-tool.is-muted { color: var(--text-faint); }
.chat-tool.is-muted .chat-tool__dot { background: color-mix(in srgb, var(--text) 18%, transparent); }

/* 正在朗读的那一条：按钮常驻（不再只在悬停时出现），因为它此刻是"停"。 */
.chat-speak.is-on {
  opacity: 1;
  color: var(--accent-ink);
  background: var(--accent-soft);
  border-color: var(--accent-line);
}

/* 语速与音色：只在正在朗读的那一条底下出现。
   常驻一排调速控件是把设置摊在对话里，而用户想调速的时刻只有一个——
   就是正听着这一条觉得太快的时候。 */
.chat-speech { display: inline-flex; align-items: center; gap: 4px; }
.chat-speech__rate {
  font-size: var(--fs-micro);
  color: var(--text-faint);
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.chat-speech__rate:hover { color: var(--text); background: var(--surface-hover); }
.chat-speech__rate.is-on { color: var(--accent-ink); background: var(--accent-soft); border-color: var(--accent-line); }
.chat-speech__voice {
  font-size: var(--fs-micro);
  color: var(--text-muted);
  max-width: 12em;
  padding: 2px 4px;
  border-radius: var(--radius-xs);
  border: 1px solid var(--hairline);
  background: var(--surface);
}

/* ---------------- 窄屏 ---------------- */

@media (max-width: 720px) {
  /* 16px 与 tasks.css 的 .tasks-main 同一个数：两个工作面在手机上要有同一条左边线。 */
  .chat-messages, .chat-composer-wrap { padding-left: 16px; padding-right: 16px; }
  .chat-continuity > header { align-items: flex-start; flex-direction: column; gap: 3px; }
  .chat-continuity footer { display: grid; grid-template-columns: 1fr 1fr 1.25fr; }
  .chat-continuity footer .btn { min-height: 44px; }
  .chat-save-progress, .chat-speak { min-height: 32px; }
}

@media (max-width: 560px) {
  .chat-topbar { padding: 10px 16px; gap: 8px; }
  .chat-topbar__identity > div { min-width: 0; }
  .chat-topbar__identity b,
  .chat-topbar__identity small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .chat-model { max-width: min(132px, 34vw); }
  .chat-composer__bar { align-items: flex-end; flex-wrap: wrap; }
  .chat-composer__bar > div {
    flex: 1 1 100%;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .chat-composer__bar > div::-webkit-scrollbar { display: none; }
  .chat-tool { flex: none; min-height: var(--touch-target); }
  .chat-send, .chat-cancel { min-height: var(--touch-target); margin-left: auto; }
}

/* 左栏在三个界面里都保留：它是"我的东西"（浮窗开关、日历分类、接下来），
   与主区在看什么无关。宽度不够时先收右栏，再收左栏。 */
/* 1100 与 tasks.css 的 .tasks-rail 断点是同一个数：两个面的右栏是同一个组件，
   不该在两个不同的宽度上各自消失（此前是 1240 / 1100，1100–1240 这一段
   待办有右栏、对话没有，用户看到的是"这个面少了点东西"）。
   注：待办面在这一档把右栏折成顶部一条横的，对话面直接隐藏——**这一条还没统一**，
   见交接报告；断点先对齐，行为的统一要连 .chat-pulse 的内部排版一起重做。 */
@media (max-width: 1100px) {
  .chat-workspace { grid-template-columns: minmax(0, 1fr); }
  .chat-pulse { display: none; }
}


/* 「按住说话」滑开到取消区。见 app/ui/press-to-talk.js —— 松开时会取消而不是提交。
   只换颜色：按住时指针就压在按钮上，位移或跳动会让人以为自己按歪了。 */
.chat-tool.is-cancelling {
  background: color-mix(in srgb, var(--danger) 14%, transparent);
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 38%, transparent);
}
.chat-tool.is-cancelling .chat-tool__dot { background: var(--danger); }
