/* ==========================================================================
   AI 对话模块样式
   主题：默认跟随系统，可用顶栏的半圆按钮手动切换（写在 <html data-theme> 上）

   配色与尺度跟米粒论期（mymili）一致（2026-10-14）：那边是 Tailwind，这里没有构建，
   所以把它用到的几个值抄成变量——
     主色 #1e40af（mymili 的 primary，即 Tailwind blue-800）
     文字 / 边框 / 底色用 slate 灰阶：正文 slate-800、次要 slate-500、边框 slate-200、页底 slate-50
     圆角 控件 8px、卡片与对话框 12px（mymili 定制过的 rounded / rounded-lg）
   深色模式 mymili 没有，这里按同一套 slate 灰阶往深处取。改颜色先改这几个变量。

   2026-10-30 改版（随 mymili 一起，按 landing-page-design 视觉规范）：
     字体 Geist（web/fonts/ 自托管，只含拉丁字母和数字，中文仍走系统字体）
     圆角 控件 8px、卡片与对话框 16px，嵌套的按「外圆角 − 间距」算
     顶栏是离开顶边、半透明加背景模糊的浮动条，消息从它下面滚过
     深色底色只用 #000 / #181818 / #1F1F1F / #272727 / #313131 几档
     动效一律 var(--ease) 减速曲线，颜色 300ms、位移 500ms；只动 transform 和 opacity
     卡片不用单边框（引用、思考过程、设置分组标题都改成整框或底色）
   ========================================================================== */

@font-face {
  font-family: "Geist";
  src: url("./fonts/Geist-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --bg: #f8fafc;          /* 页底（对话区），slate-50 */
  --surface: #ffffff;     /* 顶栏、输入栏、助手消息、对话框 */
  --fg: #1e293b;          /* slate-800 */
  --strong: #0f172a;      /* 标题，slate-900 */
  --sub: #64748b;         /* slate-500 */
  --line: #e2e8f0;        /* slate-200 */
  --field: #cbd5e1;       /* 输入框边框，slate-300 */
  --card: #f1f5f9;        /* 次级块（工具条、代码条），slate-100 */
  --hover: #f1f5f9;
  --accent: #1e40af;      /* 链接、强调文字 */
  --accent-bg: #1e40af;   /* 主按钮、用户消息底色 */
  --accent-hover: #1e3a8a;
  --accent-soft: rgba(30, 64, 175, .08);   /* mymili 的 bg-primary/10 一档 */
  --on-accent: #ffffff;
  --danger: #dc2626;
  --ok: #16a34a;
  --warn: #b45309;
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, .06);
  --shadow: 0 10px 30px rgba(15, 23, 42, .14);
  --ring: 0 0 0 3px rgba(30, 64, 175, .15);
  --glass: rgba(255, 255, 255, .75);      /* 浮动顶栏的半透明底 */
  --hero-from: #000000;                   /* 问候语大标题的文字渐变 */
  --hero-to: #666666;
  /* 行情涨跌色。国内习惯是涨红跌绿，与欧美相反，别照抄国外图表库的默认值 */
  --up: #e04a3f;
  --down: #159a72;
  /* 用户消息：mymili 的主按钮那种实底主色 */
  --mine: var(--accent-bg);
  --mine-fg: var(--on-accent);

  /*
   * 对话列的最大宽度。宽屏上不收窄的话，助手气泡贴左边、用户气泡贴右边，
   * 中间空出一大片，两边的话像是在各说各的。
   *
   * 960 原本是照气泡上限 min(86%, 820px) 倒推的。2026-10-14 起助手消息改成占满整列的卡片
   * （不再是 86% 的气泡），820 那个约束没了，但卡片里的指标块列数是照约 820px 宽真机校准的
   *（见下面 .card-tiles 的注释），所以列宽仍保持 960：减掉卡片内边距后正文区大约 900。
   * 收进这一列的是消息行和输入栏，**不含顶栏**——工具条横贯整个窗口是惯例。
   */
  --col: 960px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #181818;
    --surface: #1F1F1F;
    --fg: #e5e5e5;
    --strong: #fafafa;
    --sub: #a3a3a3;
    --line: #313131;
    --field: #414141;
    --card: #272727;
    --hover: #272727;
    --glass: rgba(31, 31, 31, .75);
    --hero-from: #FFFFFF;
    --hero-to: #9B9B9B;
    --accent: #7aa2ff;
    --accent-bg: #2f5bd3;
    --accent-hover: #3b6ae6;
    --accent-soft: rgba(122, 162, 255, .12);
    --danger: #ef5350;
    --ok: #4ade80;
    --warn: #fbbf24;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow: 0 10px 30px rgba(0, 0, 0, .5);
    --ring: 0 0 0 3px rgba(122, 162, 255, .22);
    --up: #f2645a;
    --down: #2fb98d;
  }
}

:root[data-theme="dark"] {
  --bg: #181818;
  --surface: #1F1F1F;
  --fg: #e5e5e5;
  --strong: #fafafa;
  --sub: #a3a3a3;
  --line: #313131;
  --field: #414141;
  --card: #272727;
  --hover: #272727;
  --glass: rgba(31, 31, 31, .75);
  --hero-from: #FFFFFF;
  --hero-to: #9B9B9B;
  --accent: #7aa2ff;
  --accent-bg: #2f5bd3;
  --accent-hover: #3b6ae6;
  --accent-soft: rgba(122, 162, 255, .12);
  --danger: #ef5350;
  --ok: #4ade80;
  --warn: #fbbf24;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow: 0 10px 30px rgba(0, 0, 0, .5);
  --ring: 0 0 0 3px rgba(122, 162, 255, .22);
  --up: #f2645a;
  --down: #2fb98d;
}

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

/* hidden 属性必须压过下面各处写的 display（.icon-btn 是 inline-flex）：浏览器默认的
   [hidden]{display:none} 优先级最低，一写 display 就失效。实测踩过：公开版关掉的结算单按钮又冒了出来 */
[hidden] { display: none !important; }

html, body { height: 100%; margin: 0; }

body {
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--fg);
  /* Geist 自托管（同源，不引外部字体），中文落到后面的系统字体 */
  font: 16px/1.75 "Geist", -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

button { font: inherit; cursor: pointer; }

/* 线条图标：一律 24×24、跟随文字颜色。.fill 是图标里需要实心的那部分 */
.ic {
  width: 20px;
  height: 20px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ic .fill { fill: currentColor; stroke: none; }

/* 只有图标的按钮：顶栏、输入栏都用这一种 */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  flex: none;
  height: 36px;
  min-width: 36px;
  padding: 0 8px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--sub);
  transition: color 300ms var(--ease), background-color 300ms var(--ease);
}
.icon-btn:hover { color: var(--accent); background: var(--hover); }
.icon-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.icon-btn .lbl { font-size: 14px; }

/* ---------- 顶栏 ----------
   照 mymili 的顶栏：白底、底边 slate-200、一点阴影，左边主色方块标志 + 站名。
   横贯窗口的是这条分隔线，控件收进 --col 跟对话列对齐（同 footer 的 .composer）。 */
header#bar {
  position: absolute;
  top: 12px;
  left: 16px;
  right: 16px;
  z-index: 2;
  max-width: var(--col);
  margin: 0 auto;
  padding: 0 8px 0 12px;
  background: var(--glass);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: var(--shadow-sm);
}
.bar-inner {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 56px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
  color: var(--accent);
  text-decoration: none;
  margin-right: 12px;
}
a.brand[href]:hover .brand-name { text-decoration: underline; text-underline-offset: 3px; }
/* mymili 的标志：w-8 h-8 bg-primary rounded-lg，里面一个白色粗体字 */
.brand-mark {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: var(--accent-bg);
  color: var(--on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 14px;
  line-height: 1;
}
.brand-mark .ic { width: 18px; height: 18px; stroke-width: 2; }
.brand-name { font-weight: 600; font-size: 16px; letter-spacing: -.01em; color: var(--strong); white-space: nowrap; }

/* 会话标题与状态叠成两行：一行放不下标题 + 「免费试用 · 今天剩 3 轮」，手机上标题总被截断 */
.bar-title {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  line-height: 1.3;
}
header .title {
  font-weight: 600;
  font-size: 14px;
  color: var(--strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
header .model {
  font-size: 12px;
  color: var(--sub);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
header .model:empty { display: none; }

/* ---------- 消息区 ---------- */
#log { flex: 1; overflow-y: auto; padding: 96px 16px 8px; scroll-behavior: smooth; }

.msg { margin: 0 auto 18px; display: flex; max-width: var(--col); }
.msg.user { justify-content: flex-end; }
.bubble {
  min-width: 0;
  word-break: break-word;
}
/* 用户消息：主色实底，右下角收尖一点，看得出是「我说的」 */
.msg.user .bubble {
  max-width: min(80%, 680px);
  padding: 8px 16px;
  border-radius: 16px 16px 4px 16px;
  background: var(--mine);
  color: var(--mine-fg);
  white-space: pre-wrap;
}
/* 助手消息：占满整列的白卡片（mymili 的 bg-white rounded-xl shadow-sm 那种）。
   以前是 86% 宽的灰气泡，手机上右边白白空出一截，表格和卡片还要横滚 */
.msg.assistant .bubble {
  flex: 1;
  padding: 16px 24px;
  border-radius: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}
.msg.err .bubble {
  background: color-mix(in srgb, var(--danger) 8%, var(--surface));
  border-color: color-mix(in srgb, var(--danger) 30%, var(--line));
  color: var(--danger);
  font-size: 14px;
}
.msg.sys .bubble {
  background: transparent;
  border: 1px dashed var(--line);
  box-shadow: none;
  color: var(--sub);
  font-size: 13px;
}

/* 等第一个字回来之前的「正在想」：三个点轮流亮。
   以前这时只有一个空的灰气泡，看不出是在等还是卡住了（ui.js 的 pending 类，有内容就摘掉） */
.bubble.pending::after {
  content: "";
  display: block;
  width: 36px;
  height: 10px;
  background:
    radial-gradient(circle closest-side, var(--sub) 90%, transparent) 0 50% / 10px 10px no-repeat,
    radial-gradient(circle closest-side, var(--sub) 90%, transparent) 13px 50% / 10px 10px no-repeat,
    radial-gradient(circle closest-side, var(--sub) 90%, transparent) 26px 50% / 10px 10px no-repeat;
  animation: dots 1.2s infinite var(--ease);
}
@keyframes dots {
  0%   { opacity: .35; }
  50%  { opacity: 1; }
  100% { opacity: .35; }
}

/* ---------- 空会话的问候语 ----------
   不是消息，所以不走 .bubble 那套。照 mymili 介绍页的版式：大标题、灰色导语、
   能力清单带勾、范句做成可点的卡片 */
.welcome {
  max-width: 720px;
  margin: 6vh auto 0;
  padding: 0 4px;
  color: var(--sub);
  font-size: 16px;
  line-height: 1.75;
}
.welcome-mark {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: var(--accent-bg);
  color: var(--on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 24px;
  margin-bottom: 16px;
}
.welcome-mark .ic { width: 26px; height: 26px; stroke-width: 2; }
/* 大标题：从左到右的文字渐变（浅色 #000 → #666，深色 #fff → #9B9B9B），整页唯一一处渐变 */
.welcome-title {
  font-size: 36px;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -.02em;
  max-width: 680px;
  text-wrap: balance;
  margin-bottom: 12px;
  padding-bottom: 4px;
  background-image: linear-gradient(90deg, var(--hero-from), var(--hero-to));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
@media (max-width: 600px) { .welcome-title { font-size: 30px; } }
.welcome p { margin: 0 0 12px; }
.welcome ul { margin: 0 0 18px; padding: 0; list-style: none; }
.welcome li {
  position: relative;
  padding-left: 24px;
  margin-bottom: 4px;
  color: var(--fg);
}
/* 勾：主色圆点里一个白勾，用两层渐变画，不额外放图标 */
.welcome li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .45em;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent);
}
.welcome li::after {
  content: "";
  position: absolute;
  left: 5px;
  top: calc(.45em + 3px);
  width: 4px;
  height: 7px;
  border: solid var(--accent);
  border-width: 0 1.8px 1.8px 0;
  transform: rotate(45deg);
}
/* 范句：两列卡片（手机一列）。点一下填进输入框，不直接发送 */
.welcome-examples {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 8px;
  margin: 0 0 16px;
}
.welcome-example {
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
  text-align: left;
  color: var(--fg);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 16px;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color 300ms var(--ease), color 300ms var(--ease), transform 500ms var(--ease);
}
.welcome-example:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-2px); }
.welcome-example:active { transform: scale(.98); }
.welcome-example:focus-visible { outline: none; box-shadow: var(--ring); }
.welcome-hint {
  display: inline-block;
  font-size: 13px;
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: 999px;
  padding: 3px 12px;
}

.think {
  font-size: 13px;
  color: var(--sub);
  background: var(--card);
  border-radius: 8px;
  padding: 8px 12px;
  margin-bottom: 10px;
  white-space: pre-wrap;
}
.think summary { cursor: pointer; color: var(--sub); font-size: 12.5px; }

/*
 * 流式光标。挂在**最后一个块元素**上，不是挂在 .md 容器上——
 * 正文现在是边收边渲染的（ui.js 的 paintStream），容器的 ::after 会生成在
 * 最后一段之后、自己占一行；挂到 :last-child 上才跟在正在写的那句话尾巴上。
 * 容器还空着（第一个 token 还没到）时用 :empty 那条兜底。
 */
.cursor:empty::after,
.cursor > :last-child::after {
  content: "▍";
  color: var(--accent);
  animation: blink 1s steps(2) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* token 用量是给开发者看的，公众用户不需要（ui.js 照常写，只是不显示；排查时在开发者工具里看） */
.usage { display: none; }
.empty-note { font-size: 13px; color: var(--sub); }

/* ---------- 工具调用 ----------
   一行小字「✓ 查行情」，点开是参数和原始结果（排查用）。名字是中文的（ui.js 的 TOOL_LABELS），
   原始工具名放在 title 里 */
.tool-chip {
  margin: 4px 0;
  font-size: 12.5px;
}
.tool-chip > summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: 999px;
  background: var(--card);
  cursor: pointer;
  color: var(--sub);
  list-style: none;
  max-width: 100%;
}
.tool-chip > summary:hover { color: var(--fg); }
.tool-chip > summary::-webkit-details-marker { display: none; }
/* 状态点：执行中转圈，完成打勾，失败打叉。都用 CSS 画，ui.js 只换类名 */
.tool-chip .dot {
  position: relative;
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 50%;
  border: 1.6px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-top-color: var(--accent);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.tool-chip.done .dot, .tool-chip.fail .dot { animation: none; border: 0; }
.tool-chip.done .dot { background: var(--ok); }
.tool-chip.fail .dot { background: var(--danger); }
.tool-chip.done .dot::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 2px;
  width: 3px;
  height: 6px;
  border: solid #fff;
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}
.tool-chip.fail .dot::after {
  content: "×";
  position: absolute;
  inset: 0;
  color: #fff;
  font-size: 11px;
  line-height: 12px;
  text-align: center;
  font-weight: 700;
}
.tool-chip .state { color: var(--sub); }
.tool-chip pre {
  margin: 6px 0 2px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  max-height: 260px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 11.5px;
  color: var(--sub);
}

/* ---------- Markdown ---------- */
.md > :first-child { margin-top: 0; }
.md > :last-child { margin-bottom: 0; }
.md strong { color: var(--strong); }
.md-p { margin: 8px 0; }
.md-h { margin: 16px 0 8px; line-height: 1.45; color: var(--strong); }
h1.md-h { font-size: 1.3em; }
h2.md-h { font-size: 1.18em; }
h3.md-h { font-size: 1.06em; }
h4.md-h, h5.md-h, h6.md-h { font-size: 1em; }
.md-list { margin: 8px 0; padding-left: 22px; }
.md-list li { margin: 2px 0; }
.md-list li::marker { color: var(--sub); }
.md-list .md-list { margin: 2px 0; }
.md-quote {
  margin: 8px 0;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--card);
  color: var(--sub);
}
.md hr { border: 0; border-top: 1px solid var(--line); margin: 16px 0; }
.md-code-inline {
  background: var(--card);
  padding: 1px 5px;
  border-radius: 4px;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: .9em;
}
.md-code { margin: 10px 0; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.md-code-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 3px 6px 3px 10px;
  background: var(--card);
  font-size: 11px;
  color: var(--sub);
}
.md-code-bar button {
  border: 0;
  background: transparent;
  color: var(--sub);
  padding: 2px 7px;
  border-radius: 4px;
}
.md-code-bar button:hover { color: var(--accent); }
.md-code pre { margin: 0; padding: 10px; overflow-x: auto; background: var(--bg); }
.md-code code {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 12.5px;
  line-height: 1.55;
  white-space: pre;
}
.md-table-wrap { overflow-x: auto; margin: 10px 0; }
.md-table { border-collapse: collapse; font-size: 13.5px; }
.md-table th, .md-table td { border: 1px solid var(--line); padding: 6px 10px; }
.md-table th { background: var(--card); font-weight: 600; color: var(--strong); }
.md-link { color: var(--accent); text-underline-offset: 2px; }

/* ---------- 会话抽屉 ---------- */
#mask {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, .45);
  opacity: 0;
  pointer-events: none;
  transition: opacity 300ms var(--ease);
  z-index: 2;
}
#mask.open { opacity: 1; pointer-events: auto; }

#drawer {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: min(300px, 84vw);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--line);
  transform: translateX(-100%);
  transition: transform 500ms var(--ease);
  z-index: 3;
}
#drawer.open { transform: none; box-shadow: var(--shadow); }

.drawer-head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 56px;
  padding: 0 12px 0 16px;
  border-bottom: 1px solid var(--line);
  font-weight: 700;
  color: var(--strong);
}
/* 新对话是抽屉里唯一的主动作，用主色实底（mymili 的主按钮样式） */
.drawer-head button {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border: 0;
  background: var(--accent-bg);
  color: var(--on-accent);
  font-size: 13px;
  font-weight: 500;
  padding: 6px 12px 6px 9px;
  border-radius: 8px;
  transition: background-color 300ms var(--ease);
}
.drawer-head button:hover { background: var(--accent-hover); }
.drawer-head button:active, #send:active, .dlg-btns button:active, .icon-btn:active { transform: scale(.98); }
.drawer-head button .ic { width: 16px; height: 16px; stroke-width: 2.2; }
#sessList { flex: 1; overflow-y: auto; padding: 8px; }
.sess {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 8px 9px 12px;
  border-radius: 8px;
  margin-bottom: 2px;
  cursor: pointer;
  transition: background-color 300ms var(--ease);
}
.sess:hover { background: var(--hover); }
/* 当前会话：mymili 移动菜单里「当前页」那种 bg-primary/10 text-primary */
.sess.cur { background: var(--accent-soft); }
.sess.cur .nm { color: var(--accent); font-weight: 600; }
.sess .meta { flex: 1; min-width: 0; }
.sess .nm { display: block; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sess .tm { display: block; font-size: 11.5px; color: var(--sub); margin-top: 1px; }
.sess .del {
  flex: none;
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  color: var(--sub);
  padding: 5px;
  border-radius: 6px;
  opacity: .7;
}
.sess .del .ic { width: 17px; height: 17px; }
.sess:hover .del { opacity: 1; }
.sess .del:hover { color: var(--danger); background: color-mix(in srgb, var(--danger) 10%, transparent); }
/* 二次确认用同一个按钮变形，不弹 confirm()——嵌在客户端 WebView 里时原生弹窗行为不可控 */
.sess .del.armed { color: #fff; background: var(--danger); font-size: 12px; padding: 4px 8px; opacity: 1; }
.drawer-tip {
  flex: none;
  padding: 12px 16px;
  font-size: 13px;
  color: var(--sub);
  line-height: 1.5;
}

/* ---------- 输入区 ----------
   输入框和按钮装在同一个圆角框里（.composer），聚焦时整框描边 + 主色光晕。
   跟着对话列一起收窄：只收消息的话，满宽的输入框配居中的对话，更不协调 */
footer {
  flex: none;
  background: var(--bg);
  padding: 8px 16px calc(8px + env(safe-area-inset-bottom));
}
.composer {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  max-width: var(--col);
  margin: 0 auto;
  padding: 8px;
  background: var(--surface);
  border: 1px solid var(--field);
  border-radius: 16px;
  box-shadow: var(--shadow-sm);
  transition: border-color 300ms var(--ease), box-shadow 300ms var(--ease);
}
.composer:focus-within { border-color: var(--accent); box-shadow: var(--ring); }
#input {
  flex: 1;
  min-width: 0;
  resize: none;
  max-height: 160px;
  padding: 7px 8px;
  font: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  outline: none;
}
#input::placeholder { color: var(--sub); opacity: .8; }
#send {
  flex: none;
  height: 36px;
  padding: 0 12px;
  border: 0;
  border-radius: 8px;
  background: var(--accent-bg);
  color: var(--on-accent);
  font-size: 14px;
  font-weight: 600;
  transition: background-color 300ms var(--ease);
}
#send:hover { background: var(--accent-hover); }
#send.stop { background: var(--danger); }
/* 结算单按钮。已导入时变主题色——不打开弹框也能看出有没有数据 */
#btnStatement.on { color: var(--accent); background: var(--accent-soft); }

/* 结算单弹框里的「清除」是次要动作，别做成醒目按钮 */
#stmtClear, #stmtSyncOff {
  margin-top: 8px;
  padding: 5px 12px;
  font-size: 12.5px;
  color: var(--sub);
  background: transparent;
  border: 1px solid var(--field);
  border-radius: 8px;
}
#stmtClear:hover, #stmtSyncOff:hover { color: var(--accent); border-color: var(--accent); }
#stmtSyncOff { margin: 0 0 0 4px; }
#stmtFile { font-size: 13px; margin-top: 8px; max-width: 100%; }
.hint {
  margin: 6px auto 0;
  max-width: var(--col);
  padding: 0 4px;
  font-size: 12px;
  color: var(--sub);
  min-height: 1.2em;
}
.hint.warn { color: var(--warn); }

/* ---------- 对话框 ---------- */
dialog {
  width: min(520px, 94vw);
  max-height: 88vh;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--surface);
  color: var(--fg);
  box-shadow: var(--shadow);
}
dialog::backdrop { background: rgba(15, 23, 42, .45); }
dialog form { display: flex; flex-direction: column; max-height: 88vh; }
.dlg-title {
  flex: none;
  padding: 16px 20px;
  font-size: 17px;
  font-weight: 700;
  color: var(--strong);
  border-bottom: 1px solid var(--line);
}
.dlg-scroll { flex: 1; overflow-y: auto; padding: 4px 20px 16px; font-size: 14px; }
#auth .note, #auth input { margin: 14px 20px 0; width: calc(100% - 40px); }

fieldset { border: 0; padding: 0; margin: 18px 0 0; }
/* 分组标题：mymili 卡片标题的样式（slate-900、半粗），左边一道主色短条 */
legend {
  font-size: 14px;
  color: var(--strong);
  font-weight: 600;
  padding: 0;
  line-height: 1.2;
}

dialog label { display: block; font-size: 13px; color: var(--sub); margin: 12px 0 5px; }
dialog label.ck {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  color: var(--fg);
  font-size: 14px;
  line-height: 1.55;
}
dialog label.ck input { width: auto; margin-top: 4px; flex: none; accent-color: var(--accent-bg); }

dialog input, dialog select, dialog textarea {
  width: 100%;
  padding: 8px 11px;
  font: inherit;
  font-size: 14px;
  color: inherit;
  background: var(--surface);
  border: 1px solid var(--field);
  border-radius: 8px;
  transition: border-color 300ms var(--ease), box-shadow 300ms var(--ease);
}
dialog input:focus, dialog select:focus, dialog textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
dialog textarea { resize: vertical; }
dialog select option { color: #000; }

.lead { font-size: 14px; line-height: 1.65; margin: 14px 0 0; }
.note { font-size: 12.5px; color: var(--sub); margin: 6px 0 0; line-height: 1.6; }
.note.warn { color: var(--warn); }
.note a { color: var(--accent); }

.dlg-btns {
  flex: none;
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  padding: 12px 20px;
  border-top: 1px solid var(--line);
}
.dlg-btns button {
  padding: 8px 20px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  transition: background-color 300ms var(--ease), color 300ms var(--ease), border-color 300ms var(--ease);
}
.dlg-btns .ok { border: 1px solid transparent; background: var(--accent-bg); color: var(--on-accent); }
.dlg-btns .ok:hover { background: var(--accent-hover); }
.dlg-btns .cancel { border: 1px solid var(--field); background: var(--surface); color: var(--fg); }
.dlg-btns .cancel:hover { border-color: var(--accent); color: var(--accent); }

/* 手机：顶栏只留标志不留站名、设置只留图标；助手卡片收窄内边距，把宽度留给正文和卡片 */
@media (max-width: 600px) {
  .brand-name, .icon-btn .lbl { display: none; }
  .brand { margin-right: 4px; }
  header#bar { top: 8px; left: 12px; right: 12px; }
  .msg.assistant .bubble { padding: 12px 16px; }
  .msg.user .bubble { max-width: 88%; }
  #log { padding: 84px 12px 8px; }
  footer { padding-left: 12px; padding-right: 12px; }
}

/* ==========================================================================
   工具结果卡片（web/js/cards.js）
   工具返回的 view 画成图；没有 view 时这些样式一条都用不上。
   ========================================================================== */

/* 工具状态排成一行（「✓ 查行情  ✓ 查交易时段」），各占一行太占地方。
   挂着卡片或点开了详情的那块要整行宽，不然卡片和参数会被挤成一窄条 */
.tool-block { display: inline-block; vertical-align: top; margin: 2px 6px 2px 0; max-width: 100%; }
.tool-block:has(.card), .tool-block:has(details[open]) { display: block; margin: 6px 0; }
.tool-block .tool-chip { margin: 0; }

/*
 * 卡片区：整轮的图统一挂在结论下面（ui.js 的 relocateCards / flush）。
 * 循环期间卡片还在各自的工具气泡里，收尾时才搬进来。
 */
.card-deck { margin-top: 10px; }
.card-deck > .card:first-child { margin-top: 0; }

/* 卡片在白色的助手消息里，用页底的 slate-50 衬出来（不再加阴影，卡里套卡不需要第二层立体感） */
.card {
  margin-top: 8px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--bg);
  padding: 10px 12px 8px;
  font-size: 12.5px;
  overflow: hidden;
}
.card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.card-title { font-weight: 600; font-size: 14px; color: var(--strong); }
.card-badge {
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 11px;
  border: 1px solid currentColor;
}
.card-badge.up { color: var(--up); }
.card-badge.down { color: var(--down); }
.card-badge.flat { color: var(--sub); }
.card-sub { color: var(--sub); font-size: 11.5px; margin-top: 2px; }
.card-body { margin-top: 8px; }
.card-foot { color: var(--sub); font-size: 11px; margin-top: 8px; line-height: 1.5; }

/* ---- K线 ---- */
.card-chart { margin-top: 8px; }
.kchart { width: 100%; height: auto; display: block; overflow: visible; }
.kchart .k-grid { stroke: var(--line); stroke-width: 1; }
.kchart .k-label { fill: var(--sub); font-size: 9.5px; }
.kchart .k-wick { stroke-width: 1; }
.kchart .k-up { fill: var(--up); stroke: var(--up); }
.kchart .k-down { fill: var(--down); stroke: var(--down); }
.kchart .k-vol { opacity: .55; stroke: none; }
.kchart .k-ma { fill: none; stroke-width: 1.2; }
.kchart .k-tag { font-size: 9.5px; fill: currentColor; stroke: none; }
.kchart .k-ma0 { stroke: var(--accent); color: var(--accent); }
.kchart .k-ma1 { stroke: var(--warn); color: var(--warn); }
.kchart .k-ma2 { stroke: var(--sub); color: var(--sub); }

/* ---- 榜单条形图 ---- */
.card-bars { display: flex; flex-direction: column; gap: 3px; }
.bar-row { display: grid; grid-template-columns: 5.5em 1fr 4.5em; align-items: center; gap: 8px; }
.bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 席位榜专用：标签是「中信建投期货」这种 6 字名，5.5em 会截成「中信建投…」。
   由 view 的 label_wide 打开，品种榜（3 字名）不该跟着变宽，条形会白丢一截长度 */
.card-bars.wide-label .bar-row { grid-template-columns: 7.5em 1fr 4.5em; }
.bar-track {
  position: relative;
  height: 13px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--sub) 12%, transparent);
}
/* 有负值时中线就是零轴，正负分列两侧 */
.card-bars.diverging .bar-track::before {
  content: ""; position: absolute; left: 50%; top: 0; bottom: 0;
  border-left: 1px solid var(--line);
}
.bar-fill { position: absolute; top: 1px; bottom: 1px; border-radius: 2px; }
.bar-fill.flat { left: 0; background: var(--accent); }
.bar-fill.up { background: var(--up); }
.bar-fill.down { background: var(--down); }
.bar-value { text-align: right; font-variant-numeric: tabular-nums; }
.bar-value.up { color: var(--up); }
.bar-value.down { color: var(--down); }

/* ---- 指标块 ----
   一格一行（key 左 value 右），不再是带边框的卡格子：竖排两行 + 边框 + 内边距
   一格要 47px，横排后约 25px。分组靠淡分隔线区分，去掉边框后仍认得出边界。

   **列宽是照真机截图定的，别按「多塞几列更省地方」的直觉调小 minmax**：
   96px 那版在 iPhone 16 Pro Max 上排了 3 列（103px）、桌面排了 7 列（112px），
   窄到几乎每格都要折行，反而比不改还高，还让长值溢出到隔壁格上面。
   132px 这版：390px 手机 2 列（约 138px）、430px 手机 2 列（155px）、
   820px 的桌面卡 5 列（151px）——真实字段基本都能一行装下。 */
.card-group { color: var(--sub); font-size: 11px; margin: 7px 0 1px; }
.card-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 0 14px; }
.tile {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  /* 最后的兜底：cards.js 已经先缩字号再通栏，真到这一步说明值里带整句说明，
     那种本来就该折行。折行后 value 靠 margin-left:auto 仍然右对齐，
     不然同一排里折了的左对齐、没折的右对齐，基线全乱（截图里就是这样） */
  flex-wrap: wrap;
  gap: 0 8px;
  padding: 3px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 55%, transparent);
}
/* 缩到头还放不下的独占整行——撑格子会把同排那格一起顶高两行 */
.tile.wide { grid-column: 1 / -1; }

/* 放不下时按档缩字号（cards.js 的 SCALES）。60% 是下限：再小就不是紧凑是看不清。
   只缩 value，key 恒定 10.5px——缩了就读不出这个数字是什么了 */
.tile { --ts: 1; }
.tile.s85 { --ts: .85; }
.tile.s72 { --ts: .72; }
.tile.s60 { --ts: .6; }

.tile-k {
  color: var(--sub); font-size: 10.5px;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tile-v {
  font-size: calc(13px * var(--ts));
  font-variant-numeric: tabular-nums;
  margin-left: auto;        /* 折行后也贴右边，和没折行的那些对齐 */
  /* 硬兜底，别改回 flex:0 0 auto：那样单个 value 比一列还宽时（带整句说明的值），
     折到第二行照样溢出——桌面叠到隔壁格上面，手机被 .card 的 overflow:hidden 裁掉。
     数字断行不好看，但丢数字更糟，而且只有极端值才走到这里 */
  flex: 0 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}
.tile-v.up { color: var(--up); }
.tile-v.down { color: var(--down); }

/* ---- 明细表 ----
   榜单卡/指标卡下面那张表默认收起（cards.js 的 collapsibleTable）：它和上面的
   条形图是同一批数据，展开着 20 行就占 570px，手机上还得横滚。纯 <details>，不写 JS。 */
.card-more { margin-top: 8px; }
.card-more > summary {
  cursor: pointer;
  color: var(--sub);
  font-size: 11.5px;
  padding: 2px 0;
  list-style: none;          /* 自带的三角在两端对齐的卡片里太重 */
  user-select: none;
}
.card-more > summary::-webkit-details-marker { display: none; }
.card-more > summary::before { content: "▸ "; }
.card-more[open] > summary::before { content: "▾ "; }
.card-more .card-table-wrap { margin-top: 2px; }

.card-table-wrap { overflow-x: auto; margin-top: 8px; }
.card-table { border-collapse: collapse; font-size: 12px; width: 100%; }
.card-table th, .card-table td {
  border-bottom: 1px solid var(--line);
  padding: 4px 8px;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.card-table th { color: var(--sub); font-weight: 500; text-align: right; }
.card-table th:first-child, .card-table td:first-child { text-align: left; }
.card-table td.up { color: var(--up); }
.card-table td.down { color: var(--down); }


/* 卡片在手机上降一档密度。数字一个都不少，只是挤得紧一点。
   **这一段必须留在卡片样式后面**：@media 不提升优先级，同特异性下比的是源码顺序，
   写在上面那个 480px 块里会被下面的 .card 原样盖掉。 */
@media (max-width: 480px) {
  .card { padding: 8px 9px 7px; font-size: 12px; }
  .card-title { font-size: 13px; }
  .card-table { font-size: 11.5px; }
  .card-table th, .card-table td { padding: 3px 6px; }
  .bar-row { grid-template-columns: 4.5em 1fr 4em; gap: 6px; }
  /* 特异性比上面的 .card-bars.wide-label 低，不在这儿再写一条就会被它盖掉 */
  .card-bars.wide-label .bar-row { grid-template-columns: 6.5em 1fr 4em; }
}
