/* 配色全部走变量，页面里不再出现写死的颜色（登录页除外，见文件末尾说明）。
   深色模式就是把这一组变量换一套值——加新页面时只要用这些变量，
   深色自动跟上；写死一个 #fff 就会在深色界面里留一块刺眼的白。

   命名按「这块东西是什么」而不是「它是什么颜色」：--surface 在浅色下是白、
   深色下是深灰，叫 --white 就没法换了。 */
:root{
  color-scheme:light;
  --bg:#fff;              /* 页面底 */
  --surface:#fff;         /* 卡片、菜单、浮层 */
  --surface-2:#fafbfc;    /* 表头、预览底这类比卡片再退一层的面 */
  --field:#fff;           /* 输入框、下拉框 */
  --side:#f7f8fa;
  --side-hover:#eceef3;
  --side-on:#e8ebfd;
  --hover:#eeeeef;        /* 侧栏项、菜单项悬停 */
  --on:#e8e8e9;           /* 侧栏项、菜单项选中 */
  --line:#ececf0;
  --line-soft:#f2f3f6;
  --text:#1c1d1f;
  --text-strong:#111;     /* 选中项、加粗小标题 */
  --text-2:#333;          /* 侧栏项、菜单项正文 */
  --text-3:#4b4c53;       /* 次一级按钮、工具条文字 */
  --muted:#8a8b93;
  --muted-2:#a9aab2;      /* 分组标题、快捷键提示 */
  --muted-3:#b9bac1;      /* 折叠三角、占位符号 */
  --icon:#666;            /* 线描图标 */
  --accent:#4d6bfe;
  --accent-hover:#3f5bf0;
  --accent-soft:#eef1ff;
  --accent-line:#c3cbfd;  /* 输入框聚焦描边 */
  --ok:#12a150;
  --ok-soft:#e8f8ef;
  --warn:#c2740a;
  --warn-soft:#fdf3e3;
  --warn-line:#f2e0bd;
  --err:#e0403f;
  --err-soft:#fdecec;
  --err-line:#f3c9c9;
  --r:12px;
  --shadow:0 1px 2px rgba(16,17,20,.04), 0 4px 16px rgba(16,17,20,.05);
  --shadow-pop:0 10px 34px rgba(16,17,20,.16);
  --mask:rgba(20,21,26,.55);
}

/* 深色。不是把浅色值取反——那样出来的界面发灰发脏。
   面按层次分三档（越靠上的层越亮），文字降到 #e8e9ec 而不是纯白，
   主色提亮一档，否则 #4d6bfe 压在深底上偏暗、按钮看着像禁用。 */
:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:#1b1c1f;
  --surface:#232428;
  --surface-2:#1f2023;
  --field:#2a2b30;
  --side:#171819;
  --side-hover:#26272c;
  --side-on:#2f3140;
  --hover:#2a2b2f;
  --on:#34363c;
  --line:#33343a;
  --line-soft:#2a2b30;
  --text:#e8e9ec;
  --text-strong:#fff;
  --text-2:#d3d4d9;
  --text-3:#b7b9c0;
  --muted:#8e9098;
  --muted-2:#797b83;
  --muted-3:#66686f;
  --icon:#9a9ca3;
  --accent:#6a83ff;
  --accent-hover:#7c92ff;
  --accent-soft:#282c46;
  --accent-line:#4a5490;
  --ok:#3fc37a;
  --ok-soft:#1d3329;
  --warn:#e0a54a;
  --warn-soft:#33291a;
  --warn-line:#4a3a20;
  --err:#ff6b6a;
  --err-soft:#3a2223;
  --err-line:#5a3130;
  --shadow:0 1px 2px rgba(0,0,0,.3), 0 4px 16px rgba(0,0,0,.34);
  --shadow-pop:0 10px 34px rgba(0,0,0,.5);
  --mask:rgba(0,0,0,.62);
}

/* 字体大小。全站的字号是 px 写死的，改根字号带不动，
   所以用整页缩放——字、间距、图标一起按比例走，不会出现字大了但行高没跟上。 */
body{zoom:var(--ui-zoom,1)}
*{box-sizing:border-box}
html,body{margin:0;height:100%}
body{
  font:14.5px/1.7 "PingFang SC","Microsoft YaHei",-apple-system,system-ui,sans-serif;
  background:var(--bg);color:var(--text);
  -webkit-font-smoothing:antialiased;
}
button{
  font:inherit;cursor:pointer;border:1px solid var(--line);background:var(--surface);
  border-radius:10px;padding:7px 14px;color:var(--text);transition:.15s;
}
button:hover{background:var(--side-hover);border-color:var(--line)}
button.primary{background:var(--accent);color:#fff;border-color:var(--accent)}
button.primary:hover{background:var(--accent-hover);color:#fff}
button.ghost{border-color:transparent;background:transparent}
button.ghost:hover{background:var(--side-hover)}
/* 不可撤销的操作用它。做成描边而不是实心红：它跟「停用」「重置密码」
   并排待在表格行里，实心红会把整行的视觉重心拽过去，让人先看见最危险的那个。 */
button.danger{color:var(--err);border-color:var(--err-line)}
button.danger:hover{background:var(--err-soft);border-color:var(--err)}
button:disabled{opacity:.45;cursor:not-allowed}
input,select,textarea{
  font:inherit;padding:9px 12px;border:1px solid var(--line);border-radius:10px;
  background:var(--field);width:100%;color:var(--text);transition:.15s;
}
input:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent-line);box-shadow:0 0 0 3px var(--accent-soft)}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-thumb{background:var(--line);border-radius:6px;border:2px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:var(--muted-3);background-clip:content-box}
::-webkit-scrollbar-track{background:transparent}

/* ---------- 布局 ---------- */
/* 高度先写 100vh 兜底，再用 dvh 盖掉：手机浏览器的地址栏会随滚动收进去又弹出来，
   100vh 取的是「地址栏收起时」的那个高度，于是输入框被顶到屏幕外，得往上划才够得着。
   再除以整页缩放——zoom 会把算出来的高度一起放大，字号选「大」时底部照样被切掉。
   不认识 dvh 的浏览器把整条声明丢掉，退回上面那行，不会塌成 0 高。
   position 是给窄屏的侧栏抽屉和遮罩当定位参照：用 fixed 会被 body 上的 zoom 缩放，
   absolute 挂在这里就跟着同一套坐标走，不会错位。 */
#app{
  display:flex;height:100vh;overflow:hidden;position:relative;
  height:calc(100dvh / var(--ui-zoom,1));
}
#side{
  width:224px;flex:0 0 224px;background:var(--side);
  display:flex;flex-direction:column;border-right:1px solid var(--line);
  position:relative;              /* 管理员菜单贴着侧栏底部定位 */
}
#side .brand{padding:16px 14px 10px;font-size:15px;font-weight:600;letter-spacing:.2px}
/* 放了带字 logo 时的版本。png 自带约一成的上下留白，
   所以内边距要相应收掉，否则这一行会比原来的文字版明显高出一截。 */
#side .brand.has-logo{padding:9px 10px 6px}
#side .brand img{height:36px;width:auto;max-width:100%;display:block}
/* 点它回首页。悬停只淡一下 logo 本身，不给整行铺底色：
   这一行有 224px 宽，铺满底色会比下面的菜单项还抢眼。 */
#side .brand.clickable{cursor:pointer;width:fit-content;border-radius:8px;transition:opacity .15s}
#side .brand.clickable:hover{opacity:.68}
#side .brand.clickable:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
#side .search{padding:0 12px 10px}
#side .search .box{
  display:flex;align-items:center;gap:7px;background:var(--field);border:1px solid var(--line);
  border-radius:10px;padding:7px 10px;font-size:13px;color:var(--muted);
}
#side .search svg.ic{width:16px;height:16px;flex:0 0 16px;color:var(--icon)}
#side .search input{border:0;padding:0;font-size:13px;background:transparent}
#side .search input:focus{box-shadow:none}
#side .search .kbd{
  font-size:11px;color:var(--muted-2);border:1px solid var(--line);border-radius:5px;
  padding:1px 5px;white-space:nowrap;
}
/* 侧栏图标一律走这一套：同样的画布、同样的线宽，颜色跟着所在行的 color 走 */
svg.ic{width:17px;height:17px;flex:0 0 17px;display:block}

/* 导航项固定高度，剩下的竖向空间留给会话历史，长了它自己滚 */
#side nav{flex:0 0 auto;overflow:auto;padding:4px 0}
#side nav a{
  height:40px;margin:2px 8px;padding:0 12px;display:flex;align-items:center;gap:10px;
  border-radius:8px;color:var(--text-2);font-size:14px;font-weight:400;cursor:pointer;transition:.13s;
}
#side nav a:hover{background:var(--hover);text-decoration:none;color:var(--text-2)}
#side nav a.on{background:var(--on);color:var(--text-strong);font-weight:500}
#side nav a .lb{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#side nav a svg.ic{color:var(--icon)}
#side nav a.on svg.ic{color:var(--text-strong)}

/* 侧栏底部：设置入口。会话历史再长也压不动它，永远在最下面。
   原来这里摆的是头像＋姓名＋角色，可对普通客服和只读用户来说那是块死信息——
   他们一项系统权限都没有，点不开任何东西。换成一个三条杠按钮：
   人人可点，进去是设置面板，账号信息挪到面板里。 */
#side .who{
  flex:0 0 52px;height:52px;padding:0 8px;border-top:1px solid var(--line);
  display:flex;align-items:center;
}
/* 尺寸、圆角、间距一律照抄上面的导航项：它就在那一列的正下方，
   差一点都会看出来是两套东西。区别只在它不参与「当前页」高亮。 */
#side .burger{
  height:40px;margin:0;padding:0 12px;border:0;background:transparent;border-radius:8px;
  display:flex;align-items:center;gap:10px;flex:1;min-width:0;
  color:var(--text-2);font-size:14px;font-weight:400;transition:.13s;
}
#side .burger svg{width:17px;height:17px;flex:0 0 17px;display:block;color:var(--icon)}
#side .burger .lb{flex:1;min-width:0;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#side .burger:hover{background:var(--hover)}
#side .burger:hover svg{color:var(--text-2)}
#side .burger.open{background:var(--on);color:var(--text-strong)}
#side .burger.open svg{color:var(--text-strong)}

/* ---------- 设置浮层 ----------
   贴着侧栏底部的「设置」按钮往上弹，不是居中模态：它是个菜单，
   为它压一层遮罩把整屏盖住，代价比它本身还大。 */
/* 高度由 js 按「按钮上方还剩多少」算，这里不写死 max-height：
   写死了小屏上会溢出，写小了大屏上又白白滚动。 */
/* 宽度封顶到视口内：330px 在 320 宽的机器上会横着捅出去一截，
   而这是个贴边弹出的菜单，捅出去的那半边是点不着的。 */
.set-pop{
  position:fixed;z-index:220;width:min(330px,calc(100vw - 16px));overflow:auto;
  background:var(--surface);border:1px solid var(--line);border-radius:14px;
  box-shadow:var(--shadow-pop);padding:8px 10px 10px;
}
/* 一组一行：图标 + 文案 + 朝右的箭头。浮层里只有这五行，一眼扫完；
   点某一行在屏幕中间开一个独立对话框，箭头朝右就是在说「点开是另一个框」，
   朝下会让人以为是就地展开。 */
.set-grp{
  display:flex;align-items:center;gap:10px;height:38px;padding:0 10px;
  border-radius:9px;cursor:pointer;font-size:13.5px;color:var(--text-2);
  user-select:none;transition:.13s;
}
.set-grp:hover{background:var(--hover)}
.set-grp svg.ic{width:17px;height:17px;flex:0 0 17px;color:var(--icon)}
.set-grp .lb{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.set-grp svg.car{
  width:14px;height:14px;flex:0 0 14px;color:var(--muted-3);
  transform:rotate(-90deg);            /* 复用向下的箭头，转成朝右 */
}

/* 设置对话框：居中，宽度按内容给足，不像浮层那样挤在 330px 里 */
.pv-box.set{max-width:520px}
.pv-box.set .pv-hd svg.ic{width:17px;height:17px;flex:0 0 17px;color:var(--icon)}
.set-bd{padding:14px 20px 18px;overflow:auto}

/* 底部动作行：没有展开体，也就不该有箭头占位 */
.set-grp.act svg.car{display:none}
.set-grp.act.danger{color:var(--err)}
.set-grp.act.danger svg.ic{color:var(--err)}
.set-grp.act.danger:hover{background:var(--err-soft)}
.set-sep{height:1px;background:var(--line);margin:6px 4px}
.set-row{
  display:flex;align-items:center;gap:14px;padding:12px 14px;background:var(--surface-2);
  border-radius:11px;margin-bottom:8px;
}
.set-row .lb{flex:1;min-width:0;font-size:13.5px}
.set-row .lb .nm{display:block}
.set-row .lb .ds{display:block;font-size:11.5px;color:var(--muted);margin-top:3px;line-height:1.6}
.set-row select{width:auto;min-width:132px;padding:6px 10px;font-size:13px}
.set-row button.small{padding:6px 13px;font-size:12.5px}
/* 整行可点的入口行（系统管理那几项、修改密码）。样式跟上面的设置项一致，
   是同一组东西，不该长得像两套控件。 */
.set-row.go{cursor:pointer;gap:10px}
.set-row.go:hover{background:var(--hover)}
.set-row.go svg.ic{color:var(--icon);flex:0 0 17px}
.set-row.go:hover svg.ic{color:var(--text-2)}
.set-row.go .lb{font-size:13.5px}
.set-row.danger{color:var(--err)}
.set-row.danger svg.ic,.set-row.danger:hover svg.ic{color:var(--err)}
.set-row.danger:hover{background:var(--err-soft)}

/* 字体大小：滑块加两端标签，中间那格是标准。
   刻度用 datalist 画在轨道下方，拖的时候能看出停在第几档。 */
.set-fs{flex:0 0 auto;display:flex;flex-direction:column;gap:2px;width:190px}
.set-fs input[type=range]{width:100%;padding:0;border:0;background:transparent;accent-color:var(--accent)}
.set-fs input[type=range]:focus{box-shadow:none}
.set-fs .sc{display:flex;justify-content:space-between;font-size:11px;color:var(--muted-2)}
.set-fs .sc b{font-weight:400}

#main{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}
#bar{
  height:54px;flex:0 0 54px;display:flex;align-items:center;
  padding:0 20px;border-bottom:1px solid var(--line-soft);gap:12px;
}
#bar .t{font-weight:600;font-size:15px}
#bar .sub{font-size:12px;color:var(--muted)}
#bar .sp{flex:1}
#view{flex:1;overflow:auto;padding:20px 24px}

/* 顶栏的 ☰ 与抽屉遮罩：宽屏上侧栏一直在，这两样都不出现。
   默认藏起来而不是靠 js 加类，是为了不在窄屏上先闪一下再消失。 */
#menu{
  display:none;flex:0 0 34px;width:34px;height:34px;padding:0;margin-left:-6px;
  align-items:center;justify-content:center;
  border:0;background:transparent;border-radius:9px;color:var(--text-3);
}
#menu:hover{background:var(--hover)}
#menu svg.ic{width:19px;height:19px;flex:0 0 19px;color:var(--icon)}
#scrim{display:none}

/* ---------- 通用卡片 ---------- */
.card{
  background:var(--surface);border:1px solid var(--line);border-radius:14px;
  padding:16px 18px;margin-bottom:14px;
}
.card h3{margin:0 0 12px;font-size:14.5px;font-weight:600}
.grid{display:grid;gap:14px}
.g3{grid-template-columns:repeat(auto-fill,minmax(280px,1fr))}
.g4{grid-template-columns:repeat(auto-fill,minmax(215px,1fr))}
.row{display:flex;gap:9px;align-items:center;flex-wrap:wrap}
.muted{color:var(--muted)}
.small{font-size:12.5px}
.mono{font-family:"SF Mono",Consolas,monospace;font-size:12px}
.tag{
  display:inline-block;padding:2px 9px;border-radius:7px;font-size:12px;
  background:var(--accent-soft);color:var(--accent);white-space:nowrap;
}
.tag.ok{background:var(--ok-soft);color:var(--ok)}
.tag.warn{background:var(--warn-soft);color:var(--warn)}
.tag.err{background:var(--err-soft);color:var(--err)}
.tag.gray{background:var(--surface-2);color:var(--muted)}

/* 表格里放按钮的窄列。th,td 默认 overflow-wrap:anywhere，
   两个按钮挤不下就会各占一行，把整行撑得老高 */
.nw{white-space:nowrap}
.nw button+button{margin-left:5px}

/* 额度进度条。一列数字看不出「谁快满了」，一条一眼就看出来。
   八成以上转黄、满了转红——颜色沿用 tag 那套语义，别另起一套。 */
.qbar{height:4px;border-radius:2px;background:var(--line);overflow:hidden;margin:5px 0 3px}
.qbar i{display:block;height:100%;border-radius:2px;background:var(--accent);
  min-width:2px;transition:width .2s}
.qbar i.warn{background:var(--warn)}
.qbar i.err{background:var(--err)}

/* 额度快用完时插在对话流里的提示。做得比答案轻，不抢注意力 */
.qwarn{margin:10px 0;padding:9px 13px;border-radius:var(--r);font-size:13px;
  background:var(--warn-soft);color:var(--warn);border:1px solid var(--warn-line)}
.qwarn span{color:var(--warn)}

table{width:100%;border-collapse:collapse;font-size:13.5px}
/* 掩码后的密钥是一长串没有空格的星号，不折行的话会把整张表撑歪、
   把左边的标签列挤成一列一个字 */
th,td{text-align:left;padding:9px 11px;border-bottom:1px solid var(--line-soft);
  vertical-align:top;overflow-wrap:anywhere}
th{background:var(--surface-2);font-weight:500;color:var(--muted);position:sticky;top:0;z-index:1;font-size:12.5px}
tbody tr:hover{background:var(--surface-2)}
.wrap{max-height:60vh;overflow:auto;border:1px solid var(--line);border-radius:12px;background:var(--surface)}

/* ---------- 等待动画（流动的点）----------
   三个点依次亮起并微微上浮，一道波从左往右淌过去。
   之前用的是牛顿摆（Uiverse.io by dovatgabriel）：首尾两球来回摆、中间不动。
   那个的问题是重心一直在两端来回跳，眼睛跟着左右扫；等待指示器该是
   「有动静但不抢注意力」，波浪式的流动更贴这个用途，也跟别处的对话工具一致。 */
.loading-dots{
  --dot:5px;
  --gap:5px;
  --speed:1.2s;
  display:flex;align-items:center;gap:var(--gap);flex:0 0 auto;
  height:calc(var(--dot) + 6px);          /* 给上浮留出余量，免得动起来把行高顶开 */
}
.loading-dots i{
  width:var(--dot);height:var(--dot);border-radius:50%;
  background:var(--muted);
  animation:dotflow var(--speed) ease-in-out infinite;
}
/* 相邻两点差 1/6 个周期：错开太少看着像一起闪，太多就断成三段各闪各的 */
.loading-dots i:nth-child(2){animation-delay:calc(var(--speed) / 6)}
.loading-dots i:nth-child(3){animation-delay:calc(var(--speed) / 3)}
@keyframes dotflow{
  0%,60%,100%{opacity:.3;transform:translateY(0)}
  30%{opacity:1;transform:translateY(-3px)}
}
/* 系统里关了动效就静止——它是纯装饰，不动也不影响那句被读屏软件念出来的提示 */
@media (prefers-reduced-motion:reduce){
  .loading-dots i{animation:none;opacity:.55}
}
.msg .a.loading{display:flex;align-items:center;white-space:normal}
/* 只对眼睛隐藏，读屏软件照念。不用 display:none 或 visibility:hidden——
   那两个连读屏软件也一起挡掉，等待中就成了一段没有任何提示的空白。 */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

/* ---------- 快速问答 ---------- */
#chat{display:flex;flex-direction:column;height:100%;max-width:860px;margin:0 auto;width:100%;position:relative}
/* 消息区吃掉剩余高度并自己滚。少了这条，#hello 的 height:100% 没有可撑的容器，
   欢迎语和推荐问题会塌到左上角、输入框跟着顶上去。 */
#msgs{flex:1;overflow:auto;padding:6px 2px 10px}

#hello{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  height:100%;min-height:300px;padding-bottom:30px;
}
#hello h2{font-size:27px;font-weight:600;margin:0 0 6px;letter-spacing:.3px}
#hello p{color:var(--muted);font-size:13.5px;margin:0 0 26px}
#hello .chips{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;max-width:720px}
#hello .chip{
  border:1px solid var(--line);background:var(--surface);border-radius:999px;
  padding:9px 17px;font-size:13.5px;color:var(--text-2);cursor:pointer;transition:.15s;
}
#hello .chip:hover{background:var(--side-hover);border-color:var(--line);transform:translateY(-1px)}

.msg{margin-bottom:22px}
.msg .q{
  background:var(--accent);color:#fff;padding:10px 15px;border-radius:16px 16px 4px 16px;
  display:inline-block;max-width:76%;float:right;clear:both;line-height:1.65;
}
.msg .a{
  clear:both;padding:2px 0 0;max-width:100%;white-space:pre-wrap;line-height:1.8;
}
/* Markdown 渲染后的答案。pre-wrap 必须去掉——段落与列表已经由标签成型，
   再保留原始换行会到处多出空行 */
.msg .a.md{white-space:normal}
.msg .a.md p{margin:0 0 11px}
.msg .a.md p:last-child{margin-bottom:0}
.msg .a.md b{font-weight:600;color:var(--text-strong)}
.msg .a.md code{
  background:var(--surface-2);border:1px solid var(--line-soft);border-radius:5px;
  padding:1px 5px;font-size:.92em;font-family:ui-monospace,Consolas,monospace;
}
/* 「注意事项：」这类小标题。用间距和字重拉开层次，不加分隔线——
   客服答案通常只有两三段，画线反而显得零碎 */
.msg .a.md h4{
  font-size:14.5px;font-weight:600;color:var(--text-strong);
  margin:18px 0 8px;letter-spacing:.2px;
}
.msg .a.md h4:first-child{margin-top:2px}
/* 编号与项目符号挂在文字块左侧，多行步骤能对齐，不会缩回行首 */
.msg .a.md ol,.msg .a.md ul{margin:0 0 11px;padding-left:1.7em}
.msg .a.md ol:last-child,.msg .a.md ul:last-child{margin-bottom:0}
.msg .a.md li{margin:0 0 7px;padding-left:2px}
.msg .a.md li:last-child{margin-bottom:0}
.msg .a.md li::marker{color:var(--muted);font-weight:500}
.msg .meta{clear:both;padding-top:9px;font-size:12.5px;color:var(--muted);display:flex;align-items:center;gap:9px;flex-wrap:wrap}

/* 已发出的那几张，跟着问题气泡走 */
.msg .pics.sent{
  display:flex;gap:6px;flex-wrap:wrap;clear:both;float:right;
  max-width:76%;margin:6px 0 2px;justify-content:flex-end;
}
.msg .pics.sent img{
  width:88px;height:88px;object-fit:cover;border-radius:10px;
  border:1px solid var(--line-soft);
}
/* 型号由图片认出来时的提示条。答案内容全部来自本地资料，但「挂在哪个型号下」
   是图片决定的——认错了整条答案就错了，所以这条必须显眼、必须能一眼复核 */
.msg .imgnote{
  clear:both;margin:8px 0 2px;padding:8px 12px;font-size:13px;
  background:var(--warn-soft);border:1px solid var(--warn-line);border-left:3px solid var(--warn);
  border-radius:8px;line-height:1.7;
}
.msg .imgnote b{font-weight:600}
.msg .meta .dot{color:var(--muted-3)}
.msg details{margin-top:7px}
.msg details summary{cursor:pointer;color:var(--muted);font-size:12.5px;list-style:none}
.msg details summary::-webkit-details-marker{display:none}
.msg details summary:before{content:'▸ ';color:var(--muted-3)}
.msg details[open] summary:before{content:'▾ '}
.msg .src{
  margin-top:8px;background:var(--surface-2);border:1px solid var(--line-soft);
  border-radius:11px;padding:10px 12px;font-size:12.5px;
}
.msg .src .hd{color:var(--muted);margin-bottom:6px}
.msg .src .it{
  margin:5px 0;line-height:1.9;display:flex;align-items:center;gap:7px;flex-wrap:wrap;
}
.msg .src .it .fa-nm{font-size:12.5px}
.msg .srcbox{margin-top:9px}
.msg .srcbox>summary{
  cursor:pointer;color:var(--muted);font-size:12.5px;list-style:none;
  display:inline-block;padding:2px 0;
}
.msg .srcbox>summary::-webkit-details-marker{display:none}
.msg .srcbox>summary:before{content:'▸ ';color:var(--muted-3)}
.msg .srcbox[open]>summary:before{content:'▾ '}
.msg .srcbox>summary:hover{color:var(--accent)}
.msg .att{margin-top:9px}
.msg .att .f{
  margin:3px 0;font-size:12.5px;display:flex;align-items:center;gap:8px;
  padding:4px 0;min-width:0;
}
/* 文件名占满剩余宽度并单行截断，按钮固定在右侧不换行 */
.msg .att .f .fa{flex:1;min-width:0;flex-wrap:nowrap}
.msg .att .f .fa .fa-nm{
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.msg .att .f .fa .fa-btn,.msg .att .f .fa .fa-no{flex:0 0 auto}

/* 话术表插图：直接铺在答案下方，不用点「预览」才看得到。
   宽度给到 220px 是因为配件清单这类图上带小字标号，再小就认不出编号了；
   高度封顶 260px，免得竖构图的长图（如 790x1564 的那张）把整屏顶满。 */
.msg .att-pics{
  display:flex;flex-wrap:wrap;gap:10px;margin:6px 0 2px;
}
.msg .att-pic{
  margin:0;max-width:220px;border:1px solid var(--line);border-radius:6px;
  padding:6px;background:var(--surface);
}
.msg .att-pic img{
  display:block;max-width:100%;max-height:260px;width:auto;height:auto;
  border-radius:4px;cursor:zoom-in;background:var(--surface-2);
}
.msg .att-pic figcaption{
  margin-top:5px;font-size:11.5px;display:flex;align-items:center;gap:5px;
  flex-wrap:wrap;line-height:1.5;
}
.msg .att-pic figcaption .muted{
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.msg .src .it{min-width:0}
.msg .src .it .fa-nm{
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

#composer{padding:8px 0 16px}
#composer .box{
  border:1px solid var(--line);border-radius:18px;background:var(--surface);
  box-shadow:var(--shadow);padding:12px 14px 9px;transition:.15s;
}
#composer .box:focus-within{border-color:var(--accent-line);box-shadow:0 0 0 3px var(--accent-soft),var(--shadow)}
#composer textarea{
  border:0;padding:0;resize:none;height:46px;font-size:14.5px;line-height:1.65;background:transparent;
}
#composer textarea:focus{box-shadow:none}
#composer .tools{display:flex;align-items:center;gap:8px;padding-top:7px}
#composer .tools .sp{flex:1}
#composer .tool{
  display:inline-flex;align-items:center;gap:5px;border:1px solid var(--line);
  background:var(--surface);border-radius:999px;padding:5px 12px;font-size:12.5px;color:var(--text-3);
}
#composer .tool:hover{background:var(--side-hover)}
#composer select.tool{width:auto;padding:5px 10px;border-radius:999px;font-size:12.5px}
#composer .send{
  width:34px;height:34px;padding:0;border-radius:50%;display:flex;
  align-items:center;justify-content:center;font-size:15px;
}

/* ---------- 模型选择器 ---------- */
#composer .tool.mdl{gap:6px;max-width:230px}
#composer .tool.mdl .ic{color:var(--accent);font-size:11px}
#composer .tool.mdl b{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#composer .tool.mdl .car{color:var(--muted-3);font-size:10px}
.msg .meta .usedm{color:var(--muted)}

.mdmenu{
  position:fixed;z-index:210;width:min(344px,calc(100vw - 16px));background:var(--surface);border:1px solid var(--line);
  border-radius:15px;box-shadow:var(--shadow-pop);padding:6px;
  max-height:70vh;overflow:auto;font-size:13px;
}
.mdmenu .mrow{
  display:flex;align-items:center;gap:9px;padding:9px 11px;border-radius:10px;
  cursor:pointer;line-height:1.5;
}
.mdmenu .mrow:hover{background:var(--side-hover)}
.mdmenu .mrow .ic{width:16px;text-align:center;color:var(--muted-2);flex:0 0 16px}
.mdmenu .mrow .lb{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mdmenu .mrow.pick{align-items:flex-start;padding:8px 11px}
.mdmenu .mrow.pick .ic{margin-top:2px}
.mdmenu .mrow.pick .lb{white-space:normal;overflow:visible}
.mdmenu .mrow .lb .nm{display:block}
.mdmenu .mrow .lb .ds{display:block;font-size:11.5px;color:var(--muted);line-height:1.5;margin-top:2px}
.mdmenu .mrow .ck{width:14px;text-align:center;color:var(--ok);font-weight:600;margin-top:1px}
.mdmenu .mrow.pick .tag{margin-top:1px}
.mdmenu .mrow.on .lb .nm{font-weight:500}
.mdmenu .mhd{padding:10px 11px 4px;font-size:11.5px;color:var(--muted-2)}
.mdmenu .mrow.add{border-top:1px solid var(--line-soft);margin-top:5px;border-radius:0 0 10px 10px}
.mdmenu .mrow.add .ic{color:var(--accent)}

.pv-box.mset{max-width:600px}
.mset-bd{padding:6px 20px 18px;overflow:auto}
.mset-hd{font-size:11.5px;color:var(--muted-2);margin:18px 0 8px}
.mset-note{font-size:12px;color:var(--muted);line-height:1.6;margin-bottom:10px}
.mset-row{display:flex;align-items:center;gap:12px;padding:11px 14px;background:var(--surface-2);
  border-radius:11px;margin-bottom:8px}
.mset-row .lb{flex:1;min-width:0;font-size:13.5px}
.mset-row .lb .nm{display:block}
.mset-row .lb .ds{display:block;font-size:11.5px;color:var(--muted);margin-top:2px}
.mset-row select,.mset-row input{width:auto;max-width:62%;padding:6px 10px;font-size:13px;background:var(--field)}
.mset-row button.small{padding:6px 13px;font-size:12.5px}
/* ＋ 添加自定义模型：整行可点，样式跟上面的条目一致，是同一组东西 */
.mset-row.add-entry{cursor:pointer;color:var(--accent);gap:9px}
.mset-row.add-entry:hover{background:var(--side-hover)}
.mset-row.add-entry .ic{font-size:13px}
.mset-adv{margin-top:14px}
.mset-adv summary{cursor:pointer;font-size:12.5px;color:var(--muted);list-style:none;
  padding:6px 0;margin-bottom:6px}
.mset-adv summary::-webkit-details-marker{display:none}
.mset-adv summary:before{content:'▸ ';color:var(--muted-3)}
.mset-adv[open] summary:before{content:'▾ '}
.mset-empty{font-size:12.5px;color:var(--muted);padding:10px 14px}
.mset-msg{padding:0 20px 16px;font-size:12.5px;color:var(--muted);min-height:18px}
.mset-msg.ok{color:var(--ok)}
.mset-msg.err{color:var(--err)}

/* 添加自定义模型对话框 */
.pv-box.addm{max-width:470px}
.addm-bd{padding:16px 22px 6px}
.addm-bd .fld{margin-bottom:15px}
.addm-bd label{display:flex;align-items:baseline;gap:8px;font-size:13px;margin-bottom:7px}
.addm-bd label .hint{font-size:11.5px;color:var(--muted-2)}
.addm-bd input,.addm-bd select{width:100%;font-size:13px;background:var(--surface-2);border-color:transparent}
.addm-bd input:focus,.addm-bd select:focus{background:var(--field);border-color:var(--accent-line)}
.addm-bd .pw{position:relative}
.addm-bd .pw input{padding-right:40px}
.addm-bd .pw .eye{
  position:absolute;right:4px;top:50%;transform:translateY(-50%);
  border:0;background:transparent;padding:4px 8px;font-size:13px;opacity:.5;
}
.addm-bd .pw .eye:hover{background:transparent;opacity:1}
.addm-ft{display:flex;align-items:center;gap:14px;padding:10px 22px 4px}
.addm-ft .small{flex:1;line-height:1.5}

/* 侧栏：最近的问答会话。这一段自己滚，底下的管理员区域不跟着动 */
#convs{padding:2px 8px 8px;overflow:auto;flex:1 1 auto;min-height:0}
/* 分组标题：折叠箭头 + 名称 +（「最近」才有的）··· */
#convs .hd{
  display:flex;align-items:center;gap:5px;font-size:12px;color:var(--muted);
  padding:10px 6px 4px 8px;position:sticky;top:0;background:var(--side);
  cursor:pointer;user-select:none;border-radius:6px;
}
#convs .hd:hover{color:var(--text-2)}
#convs .hd .lb{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#convs .hd svg.car{width:12px;height:12px;flex:0 0 12px;transition:transform .16s}
#convs .hd.folded svg.car{transform:rotate(-90deg)}
/* ··· 跟会话行上的那个一样：平时不占视觉，悬停或聚焦才出现。
   三个点用负字距收紧——默认字距下每个「·」两边都带着自己的空隙，
   三个连排就散成一条虚线了。负值会在最后一个点右边留出等量空白，
   所以右内边距补回去，视觉上才是居中的。 */
#convs .hd .dots{
  border:0;background:transparent;font-size:13px;opacity:0;
  padding:0 5px 0 6px;border-radius:6px;flex:0 0 auto;line-height:1.2;
  color:var(--muted);letter-spacing:-.5px;
}
#convs .hd:hover .dots,#convs .hd .dots:focus{opacity:.75}
#convs .hd .dots:hover{opacity:1;background:var(--on)}
/* 收起时只留标题那一行，下面的会话全部不渲染高度 */
#convs .cvsec.folded .cv{display:none}
#convs .cv{
  display:flex;align-items:center;gap:4px;border-radius:8px;height:32px;
  padding:0 6px 0 12px;margin-bottom:1px;font-size:13.5px;color:var(--text-2);
}
#convs .cv:hover{background:var(--hover)}
#convs .cv.on{background:var(--on);color:var(--text-strong);font-weight:500}
/* 标题单行截断：这里不能用 flex，text-overflow 只对普通行内文本生效 */
#convs .cv .tt{
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer;
}
#convs .cv .tt svg.pin{
  width:12px;height:12px;color:var(--muted);display:inline-block;vertical-align:-1px;margin-right:5px;
}
/* ··· 平时不占视觉，悬停才出现——但键盘可达，不是纯 hover 才存在 */
#convs .cv .dots{
  border:0;background:transparent;padding:0 6px;font-size:13px;opacity:0;
  border-radius:6px;flex:0 0 auto;line-height:1.2;color:var(--muted);letter-spacing:1px;
}
#convs .cv:hover .dots,#convs .cv .dots:focus,#convs .cv.on .dots{opacity:.7}
#convs .cv .dots:hover{opacity:1;background:var(--on)}
#convs .cv .rn{
  flex:1;min-width:0;padding:2px 7px;font-size:13px;border-radius:7px;
  border:1px solid var(--accent);background:var(--field);
}

.cvmenu{
  position:fixed;z-index:220;min-width:158px;background:var(--surface);
  border:1px solid var(--line);border-radius:12px;padding:5px;
  box-shadow:var(--shadow-pop);font-size:13px;
}
.cvmenu .ci{
  display:flex;align-items:center;gap:10px;padding:8px 11px;
  border-radius:8px;cursor:pointer;color:var(--text-2);line-height:1.4;
}
.cvmenu .ci:hover{background:var(--side-hover)}
.cvmenu .ci svg.ic{width:15px;height:15px;flex:0 0 15px;color:var(--icon)}
.cvmenu .ci.danger{color:var(--err)}
.cvmenu .ci.danger svg.ic{color:var(--err)}
.cvmenu .ci.danger:hover{background:var(--err-soft)}

.toast{
  position:fixed;right:22px;bottom:22px;z-index:240;max-width:380px;
  display:flex;align-items:center;gap:12px;
  background:#2b2d31;color:#fff;border-radius:12px;padding:11px 15px;
  font-size:13px;line-height:1.5;box-shadow:0 12px 34px rgba(0,0,0,.24);
}
.toast button{border-color:#43454b;color:#fff;background:transparent;padding:4px 11px;font-size:12px}
.toast button:hover{background:#2b2d31;border-color:#5a5c63}

/* ---------- 管理最近对话 ---------- */
.cvmgr-top{display:flex;align-items:center;gap:10px;max-width:760px;margin:0 auto 6px}
.cvmgr-top .sp{flex:1}
.cvmgr{max-width:760px;margin:0 auto}
.cvmgr-hd{
  font-size:12px;color:var(--muted);padding:16px 4px 6px;letter-spacing:.2px;
}
.cvmgr-row{
  display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:10px;
}
.cvmgr-row:hover{background:var(--side-hover)}
.cvmgr-row .ck{width:16px;height:16px;flex:0 0 16px;accent-color:var(--accent)}
.cvmgr-row .bd{flex:1;min-width:0}
.cvmgr-row .tt{
  display:flex;align-items:center;gap:6px;font-size:14px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.cvmgr-row .tt svg.pin{width:12px;height:12px;flex:0 0 12px;color:var(--muted)}
.cvmgr-row .tt .n{font-size:11.5px;color:var(--muted-2);flex:0 0 auto}
.cvmgr-row .op{display:inline-block;font-size:12.5px;color:var(--muted);margin-top:2px}
.cvmgr-row .op:hover{color:var(--accent);text-decoration:none}
/* 批量模式下贴着底部的那条。粘住是必须的：会话多的时候列表很长，
   勾到一半要滚回底部找按钮就太别扭了。 */
.cvmgr-bar{
  position:sticky;bottom:0;z-index:2;max-width:760px;margin:10px auto 0;
  display:flex;align-items:center;gap:12px;padding:12px 14px;
  background:var(--surface);border:1px solid var(--line);border-radius:12px;
  box-shadow:var(--shadow);
}
.cvmgr-bar input[type=checkbox]{width:16px;height:16px;flex:0 0 16px;accent-color:var(--accent)}
.cvmgr-bar .cnt{font-size:13px;color:var(--muted)}
.cvmgr-bar .sp{flex:1}

/* ---------- 文件行：名称 + 预览/下载按钮 ---------- */
.fa{display:inline-flex;align-items:center;gap:7px;flex-wrap:wrap;vertical-align:middle}
.fa-nm{color:var(--text-2);word-break:break-all}
.fa-btn{
  display:inline-flex;align-items:center;border:1px solid var(--line);background:var(--surface);
  border-radius:7px;padding:2px 10px;font-size:12px;color:var(--text-3);cursor:pointer;
  line-height:1.7;white-space:nowrap;
}
.fa-btn:hover{background:var(--side-hover);border-color:var(--line);text-decoration:none;color:var(--accent)}
.fa-no{font-size:12px;color:var(--muted-2);white-space:nowrap}
td .fa-btn{margin-right:6px}

/* ---------- 预览浮层 ---------- */
.pv-mask{
  position:fixed;inset:0;background:var(--mask);z-index:200;
  display:flex;align-items:center;justify-content:center;padding:32px;
  backdrop-filter:blur(2px);
}
.pv-box{
  background:var(--surface);border-radius:16px;max-width:1000px;width:100%;max-height:100%;
  display:flex;flex-direction:column;overflow:hidden;
  box-shadow:0 24px 64px rgba(0,0,0,.28);
}
.pv-hd{
  display:flex;align-items:center;gap:10px;padding:12px 16px;
  border-bottom:1px solid var(--line);
}
.pv-nm{flex:1;font-size:13.5px;font-weight:500;word-break:break-all}
.pv-dl{
  font-size:12.5px;border:1px solid var(--line);border-radius:8px;padding:4px 12px;
  color:var(--text-3);
}
.pv-dl:hover{background:var(--side-hover);text-decoration:none;color:var(--accent)}
.pv-bd{
  flex:1;overflow:auto;background:var(--surface-2);display:flex;
  align-items:center;justify-content:center;padding:14px;min-height:200px;
}
.pv-bd img{max-width:100%;max-height:72vh;object-fit:contain;border-radius:8px}
.pv-bd video{max-width:100%;max-height:72vh;border-radius:8px;background:#000}
.pv-bd audio{width:min(560px,100%)}
.pv-bd iframe{width:100%;height:72vh;border:0;background:#fff;border-radius:8px}
.pv-text{
  align-self:stretch;width:100%;margin:0;white-space:pre-wrap;word-break:break-word;
  font-family:"SF Mono",Consolas,monospace;font-size:12.5px;line-height:1.7;
  background:var(--surface);border:1px solid var(--line-soft);border-radius:8px;padding:14px;
  max-height:72vh;overflow:auto;
}
.pv-none{
  color:var(--muted);font-size:13.5px;padding:40px;
  text-align:center;line-height:1.8;max-width:34em;
}
.pv-none .small{display:block;color:var(--muted-2);margin-top:2px}

.badge-hi{color:var(--ok);font-weight:500}
.badge-mid{color:var(--warn);font-weight:500}
.badge-lo{color:var(--err);font-weight:500}

/* ---------- 登录 ----------
   左边品牌区、右边登录框。名称与标语都放到左边，登录框只留表单：
   一屏之内先看清这是什么系统，再填账号。 */
/* 背景铺满整页，登录框浮在右侧。这里写的渐变是兜底：
   背景图地址由 app.js 按服务端给的地址设成行内样式，图不在就露出这层渐变，
   页面照样是完整的，不会变成一片白。 */
#login{
  position:fixed;inset:0;z-index:99;display:flex;overflow:auto;
  background:linear-gradient(135deg,#f4f8ff 0%,#e9f1ff 45%,#dfeaff 100%);
  background-size:cover;background-position:center;background-repeat:no-repeat;
}

#login .hero{
  flex:1 1 58%;position:relative;overflow:hidden;display:flex;align-items:center;
  padding:6vh 6vw;
}
/* 文字这一侧压一层由浓到无的白。背景图是深浅不匀的波纹，按 cover 裁切后
   哪一块落在文字下面取决于窗口比例——不铺这层，某些尺寸下深蓝波峰正好顶到
   标题后面，字就糊了。渐变到右侧完全透明，右边的图案该露还是露。 */
#login .hero::before{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(100deg,
    rgba(255,255,255,.88) 0%,rgba(255,255,255,.66) 38%,
    rgba(255,255,255,.18) 70%,rgba(255,255,255,0) 100%);
}
#login .hero-in{position:relative;z-index:1;max-width:640px}
/* 没放 logo 文件时这里是空的，留白高度也一并塌掉，不会顶出一块空档。
   高度按「只有图标、没有字」的那版定：图案在 png 里上下各留了约一成空白，
   84px 的框换算成实际图案约 66px，压得住下面 58px 的标题。
   换成带字的横版 logo 要把这里调回 60px 上下，否则字会大得盖过标题。 */
#login .logo:not(:empty){margin-bottom:22px}
#login .logo img{height:84px;width:auto;max-width:100%;display:block}
#login h1{
  margin:0;font-weight:800;letter-spacing:-.5px;color:#14162b;
  font-size:clamp(32px,4.2vw,58px);line-height:1.16;
}
#login .hero .sub{
  margin:18px 0 0;color:#5b5f7a;font-weight:400;
  font-size:clamp(15px,1.35vw,20px);line-height:1.8;
}

#login .pane{
  flex:0 0 520px;display:flex;align-items:center;justify-content:center;padding:6vh 44px;
}
#login .box{
  width:100%;max-width:392px;padding:38px 34px;border-radius:18px;
  background:rgba(255,255,255,.94);
  box-shadow:0 2px 8px rgba(16,17,20,.05),0 24px 60px rgba(23,42,90,.16);
}
/* 毛玻璃只用来化开卡片边缘，透明度不敢再低：背后是深浅起伏的波纹，
   再透一点，输入框里的字就会跟波峰叠在一起。 */
@supports (backdrop-filter:blur(1px)){
  #login .box{background:rgba(255,255,255,.92);backdrop-filter:blur(12px)}
}
#login .box h2{margin:0 0 22px;font-size:22px;font-weight:600}
#login .f{margin-top:14px}
#login label{display:block;font-size:12.5px;color:var(--muted);margin-bottom:5px}
#login .f button.primary{width:100%;padding:11px;font-size:15px;margin-top:8px}

/* 窄屏改成上下排：品牌区收成一条，别把登录框挤出屏幕。
   提亮层跟着改成自上而下，否则横向渐变在竖排时正好压错地方。 */
@media (max-width:960px){
  #login{flex-direction:column}
  #login .hero{flex:0 0 auto;padding:40px 26px 34px}
  #login .hero::before{
    background:linear-gradient(180deg,
      rgba(255,255,255,.9) 0%,rgba(255,255,255,.7) 55%,rgba(255,255,255,.4) 100%);
  }
  #login .logo:not(:empty){margin-bottom:14px}
  #login .logo img{height:58px}
  #login .pane{flex:1 1 auto;padding:26px;align-items:flex-start}
  #login .box{max-width:none;padding:28px 24px}
}
.err-msg{color:var(--err);font-size:12.5px;margin-top:10px;min-height:17px}
.hidden{display:none!important}
.empty{padding:44px;text-align:center;color:var(--muted);font-size:13.5px}
pre.j{
  background:var(--surface-2);color:var(--text-2);padding:12px;border-radius:11px;overflow:auto;
  font-size:12px;max-height:340px;border:1px solid var(--line-soft);
  font-family:"SF Mono",Consolas,monospace;
}

/* ================================================================
   窄屏（手机）
   ================================================================
   断点取 760px：iPad 竖屏是 768，减掉 224 的侧栏还剩 544 给正文，够用，
   所以让它继续走宽屏那套；再窄就不行了——375 的手机上正文只剩 151px，
   减掉内边距实际可读宽度一百出头，一行放不下几个字。

   这一段只做两件事：把侧栏从「一直占着一列」改成「拉出来的抽屉」，
   以及把为鼠标定的尺寸（悬停才出现的 ···、40px 的行高、32px 的浮层留白）
   换成手指够得着的量。配色、层级、组件结构一概不动。 */
@media (max-width:760px){

  /* ---- 侧栏抽屉 ---- */
  /* absolute 而不是 fixed：body 上挂着 zoom，fixed 的参照系会被缩放，
     字号选「大」时抽屉会比屏幕高出一截。挂到 #app 上就跟正文同一套坐标。
     收起时一并 visibility:hidden——只 translate 出去的话它还在焦点序列里，
     用键盘或读屏一路 Tab 会掉进一个看不见的侧栏里出不来。 */
  #side{
    position:absolute;z-index:100;top:0;bottom:0;left:0;
    width:min(78vw,286px);
    transform:translateX(-100%);visibility:hidden;
    transition:transform .22s ease,visibility .22s;
  }
  #app.side-open #side{transform:none;visibility:visible;box-shadow:var(--shadow-pop)}
  #scrim{
    display:block;position:absolute;inset:0;z-index:90;background:var(--mask);
    opacity:0;pointer-events:none;transition:opacity .22s;
  }
  #app.side-open #scrim{opacity:1;pointer-events:auto}
  #menu{display:flex}

  /* 抽屉里的行高按手指放大。40px 是鼠标的量，手指点着容易蹭到隔壁那条 */
  #side .brand{padding:14px 12px 8px}
  #side nav a{height:44px}
  #side .who{flex:0 0 56px;height:56px}
  #side .burger{height:44px}
  #side .search .kbd{display:none}          /* 手机上没有 Ctrl K 这回事 */
  #convs .cv{height:38px}
  /* ··· 原本是 hover 才浮现的。触摸屏没有 hover，那就等于重命名、置顶、删除
     这几件事在手机上根本摸不到入口，所以这里让它常驻。 */
  #convs .cv .dots,#convs .hd .dots{opacity:.55}

  /* ---- 顶栏与正文 ---- */
  #bar{height:50px;flex:0 0 50px;padding:0 12px;gap:10px}
  #bar .t{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  #bar .sub{display:none}                   /* 补充信息，窄条上让位给标题 */
  #view{padding:12px 12px 14px}

  /* ---- 快速问答 ---- */
  #hello{min-height:200px;padding-bottom:12px}
  #hello h2{font-size:22px}
  #hello p{margin-bottom:18px}
  #hello .chips{gap:8px}
  #hello .chip{padding:8px 14px;font-size:13px}
  .msg{margin-bottom:18px}
  /* 76% 是给宽屏定的，那里一行本来就长。窄屏上留 24% 的空档纯属浪费，
     问句会被切成很多短行 */
  .msg .q,.msg .pics.sent{max-width:88%}
  .msg .pics.sent img{width:72px;height:72px}
  /* 220px 的插图在 351px 正文里排不成两列，索性给满宽，图上的小字标号才认得出 */
  .msg .att-pic{max-width:100%}
  .msg .att-pic img{max-height:300px}

  #composer{padding:6px 0 10px}
  #composer .box{border-radius:16px;padding:10px 12px 8px}
  /* 16px 是 iOS 的线：低于它，Safari 一聚焦就把整页放大，退出输入后也不缩回去，
     用户得自己双指捏合。这里写死 16 而不是跟着 --ui-zoom 走——字号选「小」的人
     顶多是输入框比正文略大一点，比整页被放大要好收拾得多。 */
  #composer textarea{height:42px;font-size:16px}
  /* 375 的机器上这一排只有 325px 可用，＋、品牌、模型、发送必须挤在同一行。
     不能让它 wrap：中间的 .sp 会把剩余宽度吃光，发送键掉到第二行最左边、
     正好落在 ＋ 的正下方，看着像另一个功能键。
     改成允许压缩——型号名本来就是带省略号截断的，短一截不影响认。 */
  #composer .tools{flex-wrap:nowrap;gap:6px}
  #composer .tool{padding:5px 10px}
  /* flex 项默认最小宽度是内容宽度，不显式归零就压不动 */
  #composer .tool.mdl{flex:0 1 auto;min-width:0;max-width:none}
  #composer select.tool{flex:0 1 auto;min-width:0;max-width:32vw}
  #composer .send{flex:0 0 auto}
  #composer .send{width:36px;height:36px}
  #side .search input,#login input,#login select{font-size:16px}

  /* ---- 卡片与表格 ---- */
  .card{padding:13px;border-radius:12px;margin-bottom:11px}
  .grid{gap:10px}
  /* minmax 在这个宽度下本来也只排得下一列，写死省得因内边距变化忽宽忽窄 */
  .g3,.g4{grid-template-columns:1fr}
  table{font-size:13px}
  th,td{padding:7px 8px}
  /* 页面本身已经在滚了，里面再套一个 60vh 的滚动区，两层谁都划不顺手 */
  .wrap{max-height:none}
  .cvmgr-row{padding:9px 8px;gap:10px}

  /* ---- 浮层 ---- */
  /* 32px 的四周留白在手机上等于把本来就不宽的内容再削掉一截，改成铺满整屏。
     铺满了就不该再留圆角——四个角悬在屏幕边上会显得是没对齐 */
  .pv-mask{padding:0}
  .pv-box{border-radius:0;height:100%;max-width:none}
  .pv-bd{padding:10px}
  .pv-bd img,.pv-bd video{max-height:70dvh}
  .pv-bd iframe{height:70dvh}
  .pv-text{max-height:none}
  .pv-box.set,.pv-box.mset,.pv-box.addm{max-width:none}
  .set-bd,.mset-bd{padding-left:14px;padding-right:14px}
  /* 「标签 + 控件」并排在窄屏里会把标签挤成一列一个字，让控件掉到第二行去 */
  .set-row,.mset-row{flex-wrap:wrap;gap:10px}
  .set-fs{width:100%}
  .set-row select,.mset-row select,.mset-row input{width:100%;max-width:none;min-width:0}
  .toast{left:12px;right:12px;bottom:12px;max-width:none}
}

/* 登录页在 960px 处已经改成上下排，但那是按平板定的。到了手机上留白还得再收：
   hero 占掉大半屏的话，登录框要划一下才看得见。 */
@media (max-width:520px){
  #login .hero{padding:30px 20px 24px}
  #login .logo img{height:46px}
  #login .pane{padding:18px 18px 30px}
  #login .box{padding:24px 20px;border-radius:16px}
  #login .box h2{margin-bottom:18px;font-size:20px}
}
