/* ===========================================================
   思维伙伴 · 艾诗   —— 暖砂 + 艾绿，浅色主题
   =========================================================== */
:root{
  --bg:#F6F3EE;
  --bg-2:#EFEAE1;
  --panel:#FFFFFF;
  --panel-2:#FBF9F5;
  --ink:#2E2A26;
  --ink-2:#6B6157;
  --ink-3:#9A9088;
  --line:#E8E2D6;
  --line-2:#F0EBE2;
  --sage:#5F7A63;
  --sage-d:#4E6652;
  --sage-soft:#EDF1EA;
  --sage-line:#D3DFD2;
  --clay:#B5764F;
  --radius:16px;
  --shadow-s:0 1px 2px rgba(60,50,40,.05), 0 4px 14px rgba(60,50,40,.05);
  --shadow-m:0 8px 30px rgba(60,50,40,.10);
  --font:"PingFang SC","Hiragino Sans GB","Microsoft YaHei UI","Microsoft YaHei","Noto Sans SC",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
}

*{box-sizing:border-box;}
html,body{height:100%;}
body{
  margin:0;
  font-family:var(--font);
  color:var(--ink);
  background:var(--bg);
  -webkit-font-smoothing:antialiased;
  overflow:hidden;
}
button{font-family:inherit;cursor:pointer;border:0;background:none;color:inherit;}
textarea{font-family:inherit;}

.app{
  display:grid;
  /* 左栏加宽（33% → 38%）＋ 最小宽度提到 360px：
     2026-10-05 正言去掉模式按钮后要"让出的空间给立绘"。
     立绘是 aspect-ratio 固定、高度撑满，所以**加宽这一栏**才会真的把图放大。 */
  grid-template-columns:minmax(360px,38%) 1fr;
  grid-template-rows:1fr;
  height:100dvh;
}

/* 🔴 `.topbar` 只是**手机上**用来把「立绘条 + 控制条」焊成一块的壳
   （见手机断点里的详注）。桌面上它必须完全消失 ——
   用 display:contents 让 .stage 回到 .app 的第一列，.chat 照旧在第二列。
   桌面只有两个网格项（.stage / .chat），所以不用像手机那样额外排落位。 */
.topbar{display:contents;}

/* ================= 左：角色舞台 ================= */
.stage{
  position:relative;
  overflow:hidden;
  background:linear-gradient(170deg,var(--bg-2) 0%,#F3EFE7 42%,var(--bg) 100%);
  display:flex;
  flex-direction:column;
  justify-content:flex-end;
  border-right:1px solid var(--line-2);
}
.stage-glow{
  position:absolute;
  left:50%; top:34%;
  width:112%; aspect-ratio:1;
  transform:translate(-50%,-50%);
  background:radial-gradient(circle at 50% 45%,rgba(255,255,255,.95) 0%,rgba(240,236,226,.75) 38%,rgba(246,243,238,0) 70%);
  pointer-events:none;
}
.stage::after{
  content:"";
  position:absolute; inset:auto 0 0 0; height:38%;
  background:linear-gradient(to top,var(--bg) 12%,rgba(246,243,238,0));
  pointer-events:none;
}

.char-wrap{
  position:relative;
  flex:1 1 auto;
  min-height:0;
  display:flex;
  align-items:flex-end;
  justify-content:center;
  animation:breathe 4.6s ease-in-out infinite alternate;
}
@keyframes breathe{
  from{transform:translateY(0) scale(1);}
  to{transform:translateY(-4px) scale(1.006);}
}
@media (prefers-reduced-motion:reduce){
  .char-wrap{animation:none;}
}

.char-box{
  position:relative;
  height:100%;
  aspect-ratio:var(--char-aspect, 620/906);
  max-width:100%;
}
/* 换形象的瞬间：整块淡一下，别让新帧"啪"地跳出来 */
.char-box::after{
  content:"";
  position:absolute; inset:-8%;
  background:radial-gradient(ellipse at 50% 60%, var(--bg-2) 0%, rgba(243,239,231,0) 72%);
  opacity:0; pointer-events:none;
  transition:opacity .16s ease;
}
.char-box.is-swapping::after{opacity:1;}
.char-img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:contain;
  object-position:center bottom;
  opacity:0;
  transition:opacity .24s ease;
  will-change:opacity;
  -webkit-user-drag:none;
  user-select:none;
}
.char-img.is-on{opacity:1;}
.char-overlay{transition:none;}

.char-loading{
  position:absolute; left:50%; bottom:44%;
  transform:translateX(-50%);
  display:flex; align-items:center; gap:8px;
  font-size:13px; color:var(--ink-3); letter-spacing:.08em;
}
.char-loading span{
  width:16px;height:16px;border-radius:50%;
  border:2px solid var(--sage-line);border-top-color:var(--sage);
  animation:spin .8s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg);}}

.who{
  position:relative;
  z-index:2;
  /* 底部这块也收一收，把纵向空间让给立绘 */
  padding:0 26px 20px;
  text-align:left;
}
.who h1{
  margin:0;
  font-size:24px;
  font-weight:600;
  letter-spacing:.06em;
  display:flex; align-items:center; gap:10px;
}
.pulse{
  width:8px;height:8px;border-radius:50%;
  background:var(--sage-line);
  transition:background .3s, box-shadow .3s;
}
.pulse.on{
  background:var(--sage);
  box-shadow:0 0 0 0 rgba(95,122,99,.5);
  animation:beat 1.9s ease-out infinite;
}
@keyframes beat{
  0%{box-shadow:0 0 0 0 rgba(95,122,99,.45);}
  70%{box-shadow:0 0 0 11px rgba(95,122,99,0);}
  100%{box-shadow:0 0 0 0 rgba(95,122,99,0);}
}
.who .sub{
  margin:6px 0 0; font-size:13px; color:var(--ink-2); letter-spacing:.14em;
}

/* ---- 形象切换（艾诗 / 小诗）---- */
.char-switch{
  display:inline-flex;
  margin-top:13px;
  padding:3px;
  gap:2px;
  background:rgba(255,255,255,.7);
  border:1px solid var(--line);
  border-radius:999px;
  box-shadow:var(--shadow-s);
}
.cs-btn{
  display:flex; align-items:baseline; gap:5px;
  padding:5px 13px;
  border-radius:999px;
  color:var(--ink-2);
  line-height:1.1;
  transition:background .22s, color .22s, box-shadow .22s;
}
.cs-btn b{font-weight:600; font-size:13.5px; letter-spacing:.06em;}
.cs-btn i{font-style:normal; font-size:10.5px; letter-spacing:.05em; opacity:.62;}
.cs-btn:hover{color:var(--sage-d); background:rgba(95,122,99,.07);}
.cs-btn.is-on{
  background:var(--sage);
  color:#F7FAF6;
  box-shadow:0 2px 8px rgba(79,104,83,.28);
}
.cs-btn.is-on i{opacity:.8;}

/* ---- 说话时的整体起伏 ----
   艾诗有对齐的口型帧，说话由口型驱动，这里不参与；
   小诗那套 20 帧整幅重绘、没有口型帧，用极轻微的起伏带一点"在说话"的感觉。
   🔴 幅度刻意压得很小：宁可不动，也不要做成抽搐。 */
@keyframes talkLift{
  0%   {transform:translateY(0) scale(1);}
  50%  {transform:translateY(-4px) scale(1.004);}
  100% {transform:translateY(0) scale(1);}
}
body[data-char="xiaoshi"] .char-box.is-talking{
  animation:talkLift 1.65s ease-in-out infinite;
}
.who .state{
  margin:14px 0 0;
  font-size:13.5px;
  color:var(--sage-d);
  background:rgba(255,255,255,.72);
  border:1px solid var(--sage-line);
  border-radius:999px;
  padding:6px 14px;
  display:inline-block;
  backdrop-filter:blur(6px);
  transition:opacity .3s;
}

/* ================= 右：对话 ================= */
.chat{
  display:flex;
  flex-direction:column;
  min-width:0;
  /* 🔴 grid 子项的自动最小高度会让它被内容撑到超过 100dvh，
     结果 .thread 永远滚不起来，输入框被顶到屏幕外（踩过）。
     解除办法：min-height:0（overflow:hidden 让自动最小高度归零）。
     .stage 一直没事，就是因为它本来就设了 overflow:hidden。 */
  min-height:0;
  overflow:hidden;
  background:var(--bg);
}

.bar{
  display:flex; align-items:center; gap:14px;
  padding:11px 20px;
  border-bottom:1px solid var(--line-2);
  background:rgba(246,243,238,.86);
  backdrop-filter:blur(10px);
  flex:0 0 auto;
}
/* 顶栏左侧：谁在跟我说话 + 这一轮它站哪个模式（纯提示，不可点） */
.bar-lead{flex:1 1 auto; min-width:0; display:flex; align-items:center; gap:10px;}
.who-inline{display:flex; align-items:baseline; gap:9px; min-width:0;}
.who-inline b{
  font-size:14px; font-weight:600; color:var(--ink-2);
  letter-spacing:.04em; flex:0 0 auto;
}
.who-inline i{
  font-style:normal; font-size:11.5px; color:var(--ink-3);
  letter-spacing:.02em; padding-left:9px;
  border-left:1px solid var(--line-2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

.bar-actions{display:flex; align-items:center; gap:8px; flex:0 0 auto;}
.icon-btn{
  font-size:12.5px;
  color:var(--ink-2);
  padding:7px 12px;
  border-radius:10px;
  border:1px solid var(--line);
  background:var(--panel);
  transition:color .18s,border-color .18s,background .18s;
  white-space:nowrap;
}
.icon-btn:hover{color:var(--sage-d); border-color:var(--sage-line); background:var(--sage-soft);}
.model-sel{
  flex:0 0 auto;
  font-family:inherit; font-size:12.5px; color:var(--ink-2);
  padding:7px 8px; border-radius:10px;
  border:1px solid var(--line); background:var(--panel);
  max-width:132px;
}

/* ---- 消息流 ---- */
.thread{
  flex:1 1 auto;
  min-height:0;
  overflow-y:auto;
  padding:30px 24px 12px;
  scroll-behavior:smooth;
}
.thread::-webkit-scrollbar{width:9px;}
.thread::-webkit-scrollbar-thumb{background:#DED7CB;border-radius:9px;border:3px solid var(--bg);}

.turn{max-width:760px; margin:0 auto 22px; display:flex; gap:12px; align-items:flex-start;}
.turn.me{flex-direction:row-reverse;}
.av{
  flex:0 0 auto; width:34px; height:34px; border-radius:50%;
  background:var(--sage-soft); border:1px solid var(--sage-line);
  display:grid; place-items:center; font-size:12px; color:var(--sage-d);
  overflow:hidden;
}
.av img{width:100%;height:100%;object-fit:cover;object-position:50% 6%;}
.bubble{
  border-radius:16px;
  padding:13px 17px;
  font-size:14px;
  /* 🔴 行距 < 段距：行内紧凑、段落之间透气，
     模型产的空行才能读成"这是换了一层意思"。
     2026-10-05 正言定：字号再小一号、行间距再小一些。 */
  line-height:1.68;
  letter-spacing:.01em;
  white-space:pre-line;
  word-break:break-word;
  max-width:min(600px,84%);
}
.turn.ai .bubble{
  background:var(--panel);
  border:1px solid var(--line-2);
  box-shadow:var(--shadow-s);
  border-top-left-radius:5px;
}
.turn.me .bubble{
  background:linear-gradient(160deg,var(--sage) 0%,var(--sage-d) 100%);
  color:#fff;
  border-top-right-radius:5px;
  box-shadow:0 6px 18px rgba(78,102,82,.20);
}
/* 段距 16px 明显大于行距（14×1.68≈23.5px 的行高里，行与行只差 23.5px）
   —— 这个差值就是"换段"的视觉信号 */
.bubble p{margin:0 0 16px;}
.bubble p:last-child{margin-bottom:0;}
.bubble b,.bubble strong{font-weight:600;color:inherit;}
.turn.ai .bubble strong{color:var(--sage-d);}
.bubble ul,.bubble ol{margin:10px 0 16px; padding-left:21px;}
.bubble li{margin:3px 0; line-height:1.6;}
.bubble .tag-inline{
  display:inline-block; font-size:11.5px; color:var(--sage-d);
  background:var(--sage-soft); border:1px solid var(--sage-line);
  border-radius:6px; padding:1px 6px; margin-right:4px;
}

/* 系统分隔 */
.sys-note{
  max-width:760px; margin:0 auto 22px; text-align:center;
  font-size:12.5px; color:var(--ink-3); letter-spacing:.06em;
}

/* 打字光标 */
.caret{
  display:inline-block; width:7px; height:15px; vertical-align:-2px;
  background:var(--sage); border-radius:2px; margin-left:3px;
  animation:blinkc 1s steps(1) infinite;
}
@keyframes blinkc{50%{opacity:0;}}

.think-line{
  font-size:13px; color:var(--ink-3); letter-spacing:.05em;
}

/* ---- 正在琢磨：推理模型先思考后答，思考那几秒不能空着 ---- */
.think-live{
  display:inline-flex; align-items:center; gap:8px;
  font-size:13px; color:var(--ink-3); max-width:100%;
}
.think-dots{display:inline-flex; gap:3px; flex:0 0 auto;}
.think-dots i{
  width:4px; height:4px; border-radius:50%;
  background:var(--sage); opacity:.35;
  animation:thinkBounce 1.25s ease-in-out infinite;
}
.think-dots i:nth-child(2){animation-delay:.18s;}
.think-dots i:nth-child(3){animation-delay:.36s;}
@keyframes thinkBounce{
  0%,60%,100%{opacity:.28; transform:translateY(0);}
  30%{opacity:.9; transform:translateY(-3px);}
}
.think-peek{
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  opacity:.75;
}
.think-word{opacity:.7;}

/* ---- 候选提示：默认收成一颗灰按钮，点了才展开 ---- */
.hint-box{margin-top:10px;}
/* 按钮是平台加的，不属于艾诗说的话：复制、朗读、导出都跳过它
   （user-select:none 管复制；朗读那边按类名过滤） */
.hint-toggle{
  display:inline-block;
  font-size:12.5px; line-height:1.5; letter-spacing:.02em;
  color:var(--ink-3);
  background:transparent;
  border:1px dashed var(--line-2);
  border-radius:9px;
  padding:3px 10px;
  cursor:pointer;
  user-select:none; -webkit-user-select:none;
  transition:background .18s, border-color .18s, color .18s;
}
.hint-toggle:hover{
  background:var(--sage-soft); border-color:var(--sage-line); color:var(--sage-d);
}
.hint-toggle::before{content:"＋ "; opacity:.7;}
.hint-box[data-open="1"] .hint-toggle::before{content:"− "; opacity:.7;}
.hint-body{
  display:none;
  margin-top:7px; padding:9px 12px;
  border-left:2px solid var(--sage-line);
  border-radius:0 8px 8px 0;
  background:rgba(0,0,0,.018);
}
.hint-box[data-open="1"] .hint-body{display:block; animation:hintIn .22s ease-out;}
@keyframes hintIn{from{opacity:0; transform:translateY(-3px);} to{opacity:1; transform:none;}}
.hint-body .hint-line{
  margin:0;
  font-size:12.5px;              /* 比正文小一档（正文已降到 14px） */
  line-height:1.62;
  color:var(--ink-3);            /* 灰色 —— 明确是附注，不是正文 */
  opacity:.92;
}
.hint-body .hint-more{
  margin-top:4px; font-size:11.5px; opacity:.62;
  padding-top:4px;
}
.hint-body .hint-line strong{font-weight:600; color:inherit;}

/* ---- 设置里的那枚勾：候选自动展开 ---- */
.check-btn{
  display:inline-flex; align-items:center; gap:6px;
  font-size:12.5px; color:var(--ink-2);
  padding:7px 11px; border-radius:10px;
  border:1px solid var(--line); background:var(--panel);
  cursor:pointer; user-select:none; white-space:nowrap;
  transition:color .18s, border-color .18s, background .18s;
}
.check-btn:hover{border-color:var(--sage-line); color:var(--sage-d);}
.check-btn input{
  width:13px; height:13px; margin:0; accent-color:var(--sage-d); cursor:pointer;
}
@media (max-width:719px){
  .check-btn{flex:0 0 auto; font-size:12px; padding:6px 9px;}
  .check-btn span{display:none;}   /* 窄屏只留那枚勾，省地方 */
}

/* ---- 还在说：三个点轻微起伏，表示这句话没说完 ---- */
.caret.more{
  width:auto; height:auto; background:none; margin-left:5px;
  color:var(--ink-3); font-size:13px; letter-spacing:.12em;
  vertical-align:0; animation:pulseMore 1.6s ease-in-out infinite;
}
@keyframes pulseMore{
  0%,100%{opacity:.30;}
  50%{opacity:.95;}
}

/* ---- 停顿记号：让他知道这里有呼吸的时间 ---- */
.pause-dot{
  display:inline-block; width:3px; height:3px; border-radius:50%;
  background:var(--ink-3); opacity:.42; margin:0 7px; vertical-align:3px;
}

/* ---- 输入区 ---- */
.composer{
  flex:0 0 auto;
  padding:10px 24px 18px;
  background:linear-gradient(to top,var(--bg) 62%,rgba(246,243,238,0));
  /* 手机上：刘海屏 / 手势条的安全边距 */
  padding-bottom:calc(18px + env(safe-area-inset-bottom));
}
.composer-inner{
  max-width:760px; margin:0 auto;
  display:flex; align-items:flex-end; gap:10px;
  background:var(--panel);
  border:1px solid var(--line);
  border-radius:18px;
  padding:9px 9px 9px 18px;
  box-shadow:var(--shadow-s);
  transition:border-color .2s, box-shadow .2s;
}
.composer-inner:focus-within{
  border-color:var(--sage-line);
  box-shadow:0 0 0 3px rgba(95,122,99,.10), var(--shadow-s);
}
#input{
  flex:1 1 auto;
  border:0; outline:0; resize:none;
  /* 🔴 16px 是 iOS Safari 的分水岭：小于它，一聚焦就整页放大，再也缩不回去。
     这条是**输入框**，不是正文 —— 正文能降到 14px，它不能动。 */
  font-size:16px; line-height:1.62;
  background:transparent; color:var(--ink);
  max-height:170px; padding:6px 0;
}
#input::placeholder{color:#AFA69C;}
.send{
  flex:0 0 auto;
  width:40px;height:40px;border-radius:13px;
  background:linear-gradient(160deg,var(--sage),var(--sage-d));
  color:#fff; display:grid; place-items:center;
  transition:transform .15s, opacity .2s, background .2s;
}
.send:hover{transform:translateY(-1px);}
.send:disabled{opacity:.35; cursor:not-allowed; transform:none;}
.send[hidden]{display:none;}
.send.stop{background:var(--panel); color:var(--ink-2); border:1px solid var(--line);}

/* ---- 麦克风 ---- */
.mic{
  position:relative;
  flex:0 0 auto;
  width:40px;height:40px;border-radius:13px;
  display:grid; place-items:center;
  background:var(--panel); color:var(--ink-2);
  border:1px solid var(--line);
  transition:transform .15s, color .18s, background .18s, border-color .18s;
}
.mic:hover{color:var(--sage-d); border-color:var(--sage-line); background:var(--sage-soft);}
.mic:active{transform:scale(.96);}
.mic svg{position:relative; z-index:1;}
.mic.is-rec{
  background:linear-gradient(160deg,#CE7A66,#B85F4C);
  border-color:transparent; color:#fff;
  animation:micPulse 1.5s ease-in-out infinite;
}
.mic.is-rec:hover{background:linear-gradient(160deg,#CE7A66,#B85F4C); color:#fff;}
.mic.is-busy{color:var(--sage-d); border-color:var(--sage-line); background:var(--sage-soft);}
.mic.is-speaking{color:var(--sage-d); border-color:var(--sage-line);}
.mic.is-speaking::after{
  content:''; position:absolute; inset:-2px; border-radius:15px;
  border:1.5px solid var(--sage); pointer-events:none;
  animation:speakRing 1.7s ease-out infinite;
}
@keyframes micPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(184,95,76,.34);}
  55%{box-shadow:0 0 0 8px rgba(184,95,76,0);}
}
@keyframes speakRing{
  0%{transform:scale(.98); opacity:.55;}
  100%{transform:scale(1.24); opacity:0;}
}
/* 录音时的音量指示，贴着按钮底边 */
.mic-bar{
  position:absolute; left:1px; right:1px; bottom:1px; height:2.5px;
  border-radius:0 0 12px 12px;
  background:rgba(255,255,255,.92);
  transform:scaleX(0); transform-origin:left center;
  transition:transform .07s linear;
  z-index:0;
}
.voice-sel{max-width:170px;}
.hint{
  max-width:760px; margin:8px auto 0;
  font-size:11.5px; color:#B3A99F; letter-spacing:.04em; text-align:right;
}
.hint-link{
  margin-left:8px; font-size:11.5px; letter-spacing:.04em;
  color:var(--sage-d); text-decoration:underline; text-underline-offset:2px;
}
.hint-link:hover{color:var(--sage);}

/* ================= 麦克风自检卡 ================= */
.mic-help{
  max-width:760px; margin:0 auto 10px;
  background:var(--panel);
  border:1px solid #E8D9CB;
  border-left:3px solid var(--clay);
  border-radius:12px;
  padding:12px 15px 13px;
  box-shadow:var(--shadow-s);
}
.mic-help[hidden]{display:none;}
.mh-head{display:flex; align-items:center; justify-content:space-between; gap:10px;}
.mh-head b{font-size:13.5px; color:var(--ink); letter-spacing:.02em;}
.mh-x{
  flex:0 0 auto; width:22px; height:22px; border-radius:7px;
  display:grid; place-items:center; font-size:15px; line-height:1;
  color:var(--ink-3); transition:background .15s, color .15s;
}
.mh-x:hover{background:var(--bg-2); color:var(--ink-2);}
.mh-why{
  margin:7px 0 0; font-size:12.5px; line-height:1.6; color:var(--ink-2);
}
.mh-why[hidden]{display:none;}
.mh-steps{
  margin:8px 0 0; padding-left:19px;
  font-size:12.5px; line-height:1.75; color:var(--ink-2);
}
.mh-steps[hidden]{display:none;}
.mh-steps li{margin:0 0 3px;}
.mh-steps li:last-child{margin-bottom:0;}
.mh-steps b{color:var(--ink); font-weight:600;}
.mh-acts{display:flex; flex-wrap:wrap; gap:8px; margin-top:11px;}
.mh-acts:empty{display:none;}
.mh-btn{
  font-size:12.5px; letter-spacing:.03em;
  padding:7px 15px; border-radius:9px;
  border:1px solid var(--line); background:var(--panel-2); color:var(--ink-2);
  transition:background .15s, border-color .15s, color .15s, transform .12s;
}
.mh-btn:hover{border-color:var(--sage-line); background:var(--sage-soft); color:var(--sage-d);}
.mh-btn:active{transform:scale(.97);}
.mh-btn.is-primary{
  border-color:transparent;
  background:linear-gradient(160deg,var(--sage),var(--sage-d));
  color:#fff;
}
.mh-btn.is-primary:hover{background:linear-gradient(160deg,#688367,#465C4A); color:#fff;}

.nudge{
  max-width:760px; margin:0 auto 10px;
  font-size:13px; color:var(--sage-d);
  background:var(--sage-soft); border:1px solid var(--sage-line);
  border-radius:12px; padding:9px 14px;
}

/* ================= 抽屉 / 弹层 ================= */
.drawer,.modal{position:fixed; inset:0; z-index:60;}
.drawer[hidden],.modal[hidden]{display:none;}
.drawer-mask,.modal-mask{position:absolute; inset:0; background:rgba(46,42,38,.28); backdrop-filter:blur(3px);}
.drawer-panel{
  position:absolute; right:0; top:0; bottom:0; width:min(380px,88vw);
  background:var(--panel); box-shadow:var(--shadow-m);
  display:flex; flex-direction:column;
  animation:slidein .26s cubic-bezier(.22,.7,.3,1);
  /* 抽屉贴着屏幕边，安全边距要自己让出来 */
  padding-bottom:env(safe-area-inset-bottom);
}
@keyframes slidein{from{transform:translateX(24px);opacity:.4;} to{transform:none;opacity:1;}}
.drawer-head,.modal-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:20px 22px; border-bottom:1px solid var(--line-2);
  flex:0 0 auto;
  /* 抽屉/弹层是贴着屏幕上边的，刘海得让开 */
  padding-top:calc(20px + env(safe-area-inset-top));
}
.drawer-head h2,.modal-head h2{margin:0;font-size:16px;font-weight:600;letter-spacing:.05em;}
.drawer-list{flex:1 1 auto; overflow-y:auto; padding:12px;}
.hist-item{
  position:relative;
  width:100%; text-align:left;
  padding:12px 44px 12px 14px; border-radius:12px;
  border:1px solid transparent;
  margin-bottom:6px; cursor:pointer;
  transition:background .16s,border-color .16s;
}
.hist-item:hover{background:var(--panel-2); border-color:var(--line-2);}
.hist-item.is-on{background:var(--sage-soft); border-color:var(--sage-line);}
.hist-item .t{font-size:14px; font-weight:500; color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.hist-item .d{font-size:11.5px; color:var(--ink-3); margin-top:4px; letter-spacing:.03em;}
.hist-dl{
  position:absolute; right:8px; top:50%; transform:translateY(-50%);
  width:30px;height:30px;border-radius:9px;
  font-size:15px; line-height:1; color:var(--ink-3);
  display:grid; place-items:center;
  transition:background .16s,color .16s;
}
.hist-dl:hover{background:var(--sage-soft); color:var(--sage-d);}
.empty-hint{padding:26px 14px; text-align:center; font-size:13px; color:var(--ink-3);}

.modal-panel{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:min(660px,92vw); max-height:86dvh;
  background:var(--panel); border-radius:20px; box-shadow:var(--shadow-m);
  display:flex; flex-direction:column;
  animation:popin .24s cubic-bezier(.22,.7,.3,1);
}
@keyframes popin{from{transform:translate(-50%,-48%) scale(.97);opacity:.5;} to{transform:translate(-50%,-50%) scale(1);opacity:1;}}
.modal-body{flex:1 1 auto; overflow-y:auto; padding:22px; font-size:14.5px; line-height:1.85;}
.modal-body h3{
  font-size:14px; font-weight:600; color:var(--sage-d);
  margin:22px 0 10px; letter-spacing:.05em;
}
.modal-body h3:first-child{margin-top:0;}
.modal-body ul{margin:6px 0; padding-left:22px;}
.modal-body li{margin:6px 0;}
.modal-foot{
  display:flex; gap:10px; justify-content:flex-end; flex-wrap:wrap;
  padding:16px 22px; border-top:1px solid var(--line-2);
  flex:0 0 auto;
  padding-bottom:calc(16px + env(safe-area-inset-bottom));
}
.ghost-btn{
  font-size:13px; color:var(--ink-2);
  padding:8px 16px; border-radius:11px;
  border:1px solid var(--line); background:var(--panel-2);
  transition:color .16s,border-color .16s,background .16s;
}
.ghost-btn:hover{color:var(--sage-d); border-color:var(--sage-line); background:var(--sage-soft);}

/* ---------- 在线档案口令门 ----------
   样式语言跟着 .modal 那一族走：同一块 `--panel`、同一条 `--line`、
   同一个 popin 动效。做出"这是本站自己的一个抽屉"的分寸，
   而不是浏览器原生弹窗那种外来感。 */
.gate{position:fixed; inset:0; z-index:120;}
.gate-mask{position:absolute; inset:0; background:rgba(30,27,24,.34);}
.gate-panel{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:min(420px,90vw);
  background:var(--panel); border-radius:20px; box-shadow:var(--shadow-m);
  padding:26px 26px 20px; text-align:left;
  animation:popin .24s cubic-bezier(.22,.7,.3,1);
}
.gate-panel h2{
  font-size:15px; font-weight:600; color:var(--ink);
  letter-spacing:.04em; margin:0 0 10px;
}
.gate-why{
  font-size:13px; line-height:1.85; color:var(--ink-3);
  margin:0 0 18px;
}
.gate-panel input#gateIn{
  width:100%; box-sizing:border-box;
  font-size:16px;   /* 🔴 iOS Safari 聚焦缩放的分水岭，不能往下调 */
  color:var(--ink);
  padding:12px 14px; border-radius:12px;
  border:1px solid var(--line); background:var(--panel-2);
  outline:none; transition:border-color .16s,background .16s;
  font-family:inherit;
}
.gate-panel input#gateIn:focus{border-color:var(--sage-line); background:var(--sage-soft);}
.gate-acts{
  display:flex; gap:10px; justify-content:flex-end;
  margin-top:18px;
}
.primary-btn{
  font-size:13px; color:#fff;
  padding:8px 20px; border-radius:11px; border:none;
  background:var(--sage); cursor:pointer;
  transition:background .16s;
}
.primary-btn:hover{background:var(--sage-d);}

/* toast */
.toast{
  position:fixed; left:50%; bottom:38px; transform:translateX(-50%);
  background:rgba(46,42,38,.92); color:#fff;
  font-size:13.5px; padding:11px 20px; border-radius:12px;
  z-index:90; box-shadow:var(--shadow-m); letter-spacing:.03em;
  animation:popin2 .22s ease;
}
@keyframes popin2{from{opacity:0;transform:translate(-50%,8px);} to{opacity:1;transform:translate(-50%,0);}}

/* ================= 响应式 ================= */

/* ---------- 窄屏（平板 / 横屏手机）----------
   两栏放不下，但屏幕还够高：人偶区改成一条横带，聊天在下。
   🔴 人偶只做视觉，上面不放任何控件 —— 手机浏览器的地址栏和状态栏就压在这一带，
      放上去的按钮会被挡住或者很难点到（踩过）。所以姓名、形象切换、模式、动作
      全部落到下面那条「控制条」里（见 .bar）。 */
@media (max-width:880px){
  /* 同样要摘出父网格：只改行不改列的话，.stage 还是被塞进 minmax(300px,33%)
     那一列（见下面手机断点里的详注）。 */
  /* 立绘横带加高一点：控制条少了三个模式按钮，省下的高度给立绘 */
  .app{grid-template-columns:1fr; grid-template-rows:27svh 1fr;}

  .stage{
    padding-top:env(safe-area-inset-top);
    border-right:0; border-bottom:1px solid var(--line-2);
    flex-direction:row; align-items:stretch;
  }
  .char-wrap{flex:0 0 auto; width:44%; margin-left:auto; align-items:flex-start;}
  .char-box{height:150%; aspect-ratio:auto; width:100%;}
  .char-img{object-fit:cover; object-position:50% 4%;}
  .who{
    flex:1 1 auto;
    display:flex; flex-direction:column; justify-content:center;
    padding:10px 14px; max-width:none;
  }
  .who h1{font-size:19px; gap:7px;}
  .who .sub{font-size:11px; letter-spacing:.06em; margin-top:4px;}
  /* 形象切换在窄屏上交给控制条，这里不重复放 */
  .char-switch{display:none;}
  .who .state{
    margin-top:8px; font-size:11.5px; padding:4px 10px;
    max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .stage-glow{left:76%; top:48%; width:62%;}
  .stage::after{display:none;}

  .thread{padding:16px 14px 8px;}
  .turn{gap:9px; margin-bottom:16px;}
  .av{width:30px;height:30px;}
  .bubble{font-size:14px; padding:11px 14px; max-width:86%;}
  .bar{padding:9px 14px; gap:9px;}
  .bar-actions{width:100%; justify-content:flex-end; flex-wrap:wrap; gap:6px;}
  .icon-btn{flex:0 0 auto; font-size:12px; padding:6px 10px;}
  .composer{padding:8px 12px 12px; padding-bottom:calc(12px + env(safe-area-inset-bottom));}
  .composer-inner{padding:7px 7px 7px 13px; gap:8px;}
  .mic,.send{width:40px;height:40px;border-radius:13px;}
  .hint{display:block; text-align:center; margin-top:7px;}
  .hint-text{display:none;}
  .hint-link{margin-left:0; font-size:12px; padding:6px 0;}
  .mic-help{padding:11px 12px 12px;}
  .mh-steps{font-size:12px; padding-left:17px;}
  .mh-btn{flex:1 1 auto; min-width:104px; text-align:center;}
  .cs-btn{padding:5px 11px;}
  .cs-btn b{font-size:13px;}
  .cs-btn i{font-size:10px;}
  /* 弹层在自己的头部里补过安全边距，这里还原，免得顶部空一块 */
  .drawer-head,.modal-head{padding-top:20px;}
  .drawer-panel{padding-bottom:0;}
  .modal-foot{padding:12px 16px; padding-bottom:calc(12px + env(safe-area-inset-bottom));}
  .modal-panel{width:92vw; max-height:88svh;}
  .modal-body{padding:16px; font-size:14.5px;}
  .ghost-btn{flex:1 1 auto; text-align:center; padding:10px 12px;}
}

/* ---------- 手机 ----------
   这里是给正言真正拿在手里那一版做的：手机浏览器的地址栏和状态栏压在上方，
   人偶再占掉两成屏幕，一进来就只剩十几行字可看 —— 所以整条人偶横带收掉。
   改成「顶部控制条（人偶缩在左上角）+ 全屏对话 + 底部输入」。
   立绘不再消失：收进控制条左边那个小圆头像，随情绪立刻换脸，
   点一下还能展开完整立绘（.app.is-comfy）。 */
@media (max-width:640px){

  /* 🔴 .app 从「左右两栏」改成「上下一列」，并且**把原本分属两个容器的东西提到同一行**：
       .stage 在 .topbar 里、.bar 在 .chat 里，手机上要让它们並排成顶部一整块，
       靠的就是 👉 .topbar 和 .chat 都 `display:contents`，
       于是 .stage / .char-wrap / .who / .bar / .thread / .composer
       全都变成 .app 的直接网格项，再由 areas 分配位置。
     顶行用两个 by-name 区域（`stage` 和 `bar`）并排，中间那条 1fr 的缝给身份列用不着 ——
     身份列本身就在 .stage 里面。所以顶行写成 `auto 1fr`：左边头像+名字那块（.stage）、
     右边动作区（.bar），两者之间留白。
     父级 .app 原是 `minmax(300px,33%) 1fr` —— 只改行不改列的话，
     子项仍会被塞进第一列（390px 宽的手机上那列只有 300px），正文被挤成竖排（踩过）。 */
  .app{
    /* 顶行：身份区（.stage，按内容宽度，不能压）| 动作区（.bar，吃掉剩余、内部靠右）。
       🔴 第一版写成 `minmax(0,1fr) auto` 是反的 —— 身份区被压成一条 26px 的缝，
          按钮反而占满整行。头像 88px 是硬宽度，必须 `auto`。 */
    grid-template-columns:auto minmax(0,1fr);
    grid-template-rows:auto 1fr auto;
    grid-template-areas:
      "stage  bar"
      "thread thread"
      "composer composer";
  }
  .topbar{display:contents;}
  .chat{display:contents;}
  .stage{grid-area:stage;}
  .bar{grid-area:bar;}
  .thread{grid-area:thread;}
  .composer{grid-area:composer;}

  /* ===== 顶部：一整块「身份区」=====
     🔴🔴 2026-10-05 正言：红框（立绘+名字）和绿框（控制条）**合并成一块**。
        合并前的问题：① 头像右边到「艾诗」之间空一大片 ② **屏幕上出现两个「艾诗」**
        （`.stage` 里的 `#charName` 和 `.bar` 里的 `#charNameTop` 各写一遍）。
        现在 .stage / .bar 并排落在 .app 顶行（见上面 grid-template-areas 的详注），
        .stage 内部再横着排：头像 | 身份列。 */
  .stage{
    grid-area:stage;
    display:flex; flex-direction:row; align-items:center;
    padding:8px 4px 8px 10px;
    padding-top:calc(8px + env(safe-area-inset-top));
    border-bottom:1px solid var(--line-2);
    background:rgba(246,243,238,.94);
    backdrop-filter:blur(10px);
    z-index:30;
  }
  .stage-glow,.stage::after{display:none;}

  /* 左上角的圆头像：把立绘放大后取「脸」那一块塞进圆里。
     立绘是 620×906，圆只显示头部 ⇒ 用 object-position 框住脸。
     🔴 2026-10-05 正言：「大一倍」⇒ 44px → 88px。
        ↳ 尺寸翻倍后那圈 1px 描边在视觉上变得很细，边框跟着加粗到 1.5px。
        ↳ 圆变大，`object-position` 的百分比不用改（百分比是相对图片算的，与容器无关），
          但**纵向位置要往下挪一点**：圆越高、露出的身体越多，12% 会显得头偏上。 */
  .char-wrap{
    flex:0 0 auto;
    position:relative;
    width:88px; height:88px;
    margin:0; border-radius:50%;
    overflow:hidden;
    background:var(--panel-2);
    border:1.5px solid var(--sage-line);
    box-shadow:0 2px 10px rgba(74,92,74,.10);
    animation:none;
  }
  .char-box{
    width:100%; height:100%;
    aspect-ratio:auto; max-width:none;
    position:absolute; inset:0;
  }
  .char-box::after{display:none;}
  /* 🔴 圆从 44px 涨到 88px 后，同样 12% 的纵向位置会让脸显得偏上（露出的身体变多了），
     压到 20% 把脸重新摆到圆的中间偏上那一档。横向仍居中。 */
  .char-img{object-fit:cover; object-position:50% 20%;}
  /* 说话时不再叠口型（放大后是糊的），改成「圆头像轻轻呼吸」＋底下那圈声波动起来 */
  body[data-char="xiaoshi"] .char-box.is-talking{animation:none;}
  .stage .char-wrap.is-talking{animation:micPulse 1.5s ease-in-out infinite;}
  .char-loading{display:none;}

  /* 身份列：名字 + 模式小字，两行。
     🔴 合并后这里**要补上模式**（原先模式在 .bar 的 .who-inline 里，
        而那个「艾诗」是重复的、已经删掉）。见 index.html 里 .who 内新加的 <i id="modeNow">。 */
  .who{
    flex:1 1 auto; min-width:0;
    display:flex; flex-direction:column; align-items:flex-start;
    gap:3px;
    padding:0 4px 0 11px;
    max-width:none;
  }
  .who h1{
    font-size:19px; gap:6px;
    display:flex; align-items:center; flex-wrap:nowrap;
  }
  .pulse{width:6px;height:6px;}
  .who .sub{display:none;}
  /* 🔴🔴 状态胶囊（「在这儿，随时开口」）在 390px 一行里**必须收掉**（2026-10-05 实测）：
     同一行还要放声音下拉 + 候选勾选 + 沉淀 / 记录 / 新会话 —— 一共 5 个控件。
     胶囊占 110px 的话，动作区只剩 103px 宽，四个控件被挤成 **4 行**、顶栏从 118px 涨到 153px。
     它本来就是「在听 / 在迎你」这类氛围提示，旁边的呼吸点（.pulse）已经在表达同一件事，
     手机上让位给真正要点的东西。 */
  .who .state{display:none;}
  /* 模式小字：不可点，只标示「现在按哪一种陪法在聊」 */
  .who .mode-now{
    font-style:normal; font-size:11px; letter-spacing:.02em;
    color:var(--ink-3); opacity:.9;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%;
  }

  /* ===== 动作区：顶行的右半边 =====
     🔴 .bar 现在跟 .stage 并排（见 .app 的 grid-template-areas）。
        里面那个重复的「艾诗」已从 index.html 删掉，模式文字移进了 .who。 */
  .bar{
    grid-area:bar;
    display:flex; align-items:center; justify-content:flex-end;
    flex-wrap:wrap; gap:6px;
    min-width:0;
    /* 🔴 右上角这一块**不加 top padding**：.stage 那边已经把
       `env(safe-area-inset-top)` 顶开了，同一行里的 .bar 再加一遍会平白多出一截、
       把下拉挤到状态栏底下去（实测第一版下拉被上沿切掉半个字）。
       左右留一点、上下跟着 .stage 的内容居中即可。 */
    padding:8px 10px 8px 0;
    border-bottom:1px solid var(--line-2);
    background:rgba(246,243,238,.94);
  }
  .bar-lead{display:none;}   /* 里面的「发散钩子」已并入身份列 */

  .bar-actions{
    display:flex; align-items:center; justify-content:flex-end;
    flex-wrap:wrap; gap:6px;
    min-width:0;
  }
  /* 🔴 声音下拉必须有个上限：它里面那条音色名不短（「晓晓·温暖知性」），
     不给 max-width 会撑到 159px、反过来把左边身份区压扁
     （实测第一版就是这样：.stage 被挤成 26px 宽的缝）。
     和它并排的按钮都是短词，不需要限制。 */
  #voiceSel{max-width:118px; min-width:0;}

  .model-sel{
    font-size:12px; padding:6px 6px; border-radius:9px;
    min-width:0;
  }
  .icon-btn{
    font-size:12px; padding:6px 8px; border-radius:9px;
    text-align:center;
  }

  /* ===== 聊天区 ===== */
  .thread{padding:14px 12px 8px; -webkit-overflow-scrolling:touch;}
  .turn{gap:8px; margin-bottom:16px; align-items:flex-start;}
  .av{width:30px;height:30px; flex:0 0 auto;}
  .bubble{
    /* 跟桌面同一套口径：字号小一号、行距收紧、段距 > 行距 */
    font-size:14px; line-height:1.66; letter-spacing:.01em;
    padding:12px 14px; border-radius:15px;
    max-width:calc(100% - 40px);
  }
  .bubble p{margin:0 0 15px;}
  .sys-note{margin-bottom:16px; font-size:12px;}

  /* ===== 输入区 ===== */
  .composer{
    padding:8px 12px 10px;
    padding-bottom:calc(10px + env(safe-area-inset-bottom));
    border-top:1px solid var(--line-2);
    background:var(--bg);
  }
  .composer-inner{
    padding:6px 6px 6px 14px; gap:8px; border-radius:20px;
  }
  #input{font-size:16px; padding:8px 0; max-height:128px;}
  .mic,.send{width:40px;height:40px;border-radius:14px;}
  .hint{display:none;}
  /* 提示行收起来不占位，改用「点麦克风直接说」这一句常驻在输入框下方 */
  .nudge{font-size:13px; padding:8px 12px;}

  /* 自检卡在手机上改成浮层：从输入区上方浮出，不再把输入框顶下去 */
  .mic-help{
    position:fixed; left:10px; right:10px;
    bottom:calc(76px + env(safe-area-inset-bottom));
    max-height:56svh; overflow-y:auto;
    margin:0; z-index:55;
    box-shadow:var(--shadow-m);
  }
  .mh-steps{line-height:1.85;}
  .mh-x{width:30px;height:30px;font-size:18px;}

  /* ===== 抽屉 / 弹层 ===== */
  .drawer-panel{width:86vw;}
  .drawer-list{padding:10px;}
  .hist-item{padding:12px 40px 12px 12px;}
  .hist-dl{width:34px;height:34px;}
  .modal-panel{
    width:94vw; max-height:90svh;
    left:auto; right:auto; top:auto; bottom:0;
    transform:none; border-radius:20px 20px 0 0;
    animation:sheetup .26s cubic-bezier(.22,.7,.3,1);
  }
  @keyframes sheetup{from{transform:translateY(22px);opacity:.5;} to{transform:none;opacity:1;}}
  .modal-body{padding:16px; font-size:15px;}
  .modal-foot{padding:12px 14px; padding-bottom:calc(12px + env(safe-area-inset-bottom));}
  .ghost-btn{font-size:12.5px; padding:11px 10px;}

  /* ===== 手机上的「完整立绘」——点左上角展开 ===== */
  .app.is-comfy{position:relative;}
  .app.is-comfy .stage{
    display:block;
    position:absolute; inset:0 0 auto 0;
    height:38svh;
    padding:0;
    overflow:hidden;
    background:linear-gradient(170deg,var(--bg-2) 0%,#F3EFE7 42%,var(--bg) 100%);
  }
  .app.is-comfy .stage-glow{
    display:block; left:72%; top:46%; width:78%;
  }
  .app.is-comfy .stage::after{
    display:block; inset:auto 0 0 0; width:auto; height:34%;
    background:linear-gradient(to top,var(--bg) 12%,rgba(246,243,238,0));
  }
  .app.is-comfy .char-wrap{
    position:absolute; left:0; right:0; top:0; bottom:0;
    width:auto; height:auto; margin:0;
    border-radius:0; border:0; background:none; overflow:visible;
    animation:breathe 4.6s ease-in-out infinite alternate;
  }
  .app.is-comfy .char-box{
    position:relative; inset:auto;
    height:100%; width:100%; max-width:none;
  }
  .app.is-comfy .char-img{object-fit:contain; object-position:center bottom;}
  .app.is-comfy .who{
    position:absolute; left:0; right:0; bottom:0;
    display:flex; flex-direction:column; align-items:flex-start; gap:6px;
    padding:0 16px 10px;
  }
  .app.is-comfy .who h1{font-size:18px;}
  .app.is-comfy .who .sub{display:block; font-size:11px;}
  .app.is-comfy .char-switch{display:inline-flex; margin-top:2px;}
  .app.is-comfy .cs-btn i{display:none;}
  /* 展开时压住下面的聊天区，点别处收回 */
  .app.is-comfy .chat{position:relative; z-index:1; padding-top:38svh;}
  .app.is-comfy .chat::before{
    content:""; position:absolute; inset:0; z-index:2;
  }
  .app.is-comfy .thread,
  .app.is-comfy .composer,
  .app.is-comfy .bar{position:relative; z-index:3;}
}

/* 屏幕特别矮（横屏手机）：人偶横带再压薄一点
   🔴 判据只看「矮」，**不锁宽** —— 手机横过来宽度是 740~930px，
      正好落在 640px 手机断点之外，会掉回 880px 平板那条全高立绘的规则里，
      本来就被压到 360px 高，再顶一条 16svh 的带子就没剩多少聊天区了。 */
@media (max-height:520px){
  /* 🔴🔴 横屏矮屏（740×360 这类）**落在 880px 与 640px 两条断点之间**：
     宽度 740~930px ⇒ 不满足 max-width:640px ⇒ 拿不到手机那套「顶行合并」的 grid；
     而 880px 块给的是「27svh 全高立绘横带 + 下面独立控制条」。
     结果就是 2026-10-05 实测看到的：头像在最左、名字被 .who 撑到 672px 宽给居中到屏幕中间、
     按钮单独掉到第二行，中间空一大片。**这里补一套同口径的合并网格**。 */
  .app{
    grid-template-columns:auto minmax(0,1fr);
    grid-template-rows:auto 1fr auto;
    grid-template-areas:
      "stage  bar"
      "thread thread"
      "composer composer";
  }
  .topbar{display:contents;}
  .chat{display:contents;}
  .stage{grid-area:stage;}
  .bar{grid-area:bar;}
  .thread{grid-area:thread;}
  .composer{grid-area:composer;}

  /* 顶行整条收到 ~58px：横屏最缺的就是纵向字数。 */
  .stage{
    display:flex; flex-direction:row; align-items:center;
    /* 880px 块给的是 `padding-top:env(safe-area-inset-top)` + 全高带子的内距，
       一条 58px 的带子扛不住 —— 这里整条重写。 */
    padding:5px 6px 5px 10px;
    padding-top:calc(5px + env(safe-area-inset-top));
    border-right:0; border-bottom:1px solid var(--line-2);
    background:rgba(246,243,238,.94);
    backdrop-filter:blur(10px);
    z-index:30;
  }
  .stage-glow,.stage::after{display:none;}
  /* 🔴 带子只有 ~58px 高 —— 手机版那个 88px 的圆会顶出容器、被上沿切掉半个头。
     收到 48px 刚好装得下（2026-10-05 实测）。 */
  .char-wrap{
    flex:0 0 auto;
    position:relative;
    width:48px; height:48px;
    margin:0; border-radius:50%;
    overflow:hidden;
    background:var(--panel-2);
    border:1.5px solid var(--sage-line);
    box-shadow:0 2px 10px rgba(74,92,74,.10);
    animation:none;
  }
  .char-box{
    width:100%; height:100%;
    aspect-ratio:auto; max-width:none;
    position:absolute; inset:0;
  }
  .char-box::after{display:none;}
  /* 🔴 880px 块压的是 4%（为的是让全高横带顶端露脸），这档要的是「脸正好落在 48px 圆里」——
     圆矮、露出身体多，压到 26% 把脸摆进圆的中间偏上。 */
  .char-img{object-fit:cover; object-position:50% 26%;}
  body[data-char="xiaoshi"] .char-box.is-talking{animation:none;}
  .char-loading{display:none;}

  .who{
    flex:1 1 auto; min-width:0;
    display:flex; flex-direction:column; align-items:flex-start;
    gap:1px;
    padding:0 4px 0 10px;
    max-width:none;
  }
  .who h1{font-size:17px; gap:6px; display:flex; align-items:center; flex-wrap:nowrap;}
  .pulse{width:6px;height:6px;}
  .who .sub{display:none;}
  /* 矮屏上状态胶囊一整块占掉近 30px 高 —— 收掉，把这一行还给聊天区。 */
  .who .state{display:none;}
  .who .mode-now{
    font-style:normal; font-size:11px; letter-spacing:.02em;
    color:var(--ink-3); opacity:.9;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%;
  }

  /* 动作区：跟 .stage 并排，只占一行。 */
  .bar{
    display:flex; align-items:center; justify-content:flex-end;
    flex-wrap:wrap; gap:5px;
    min-width:0;
    /* 同一行里 .stage 已把 safe-area-inset-top 顶开，这里不再补，免得下拉被推到状态栏底下。 */
    padding:5px 10px 5px 0;
    border-bottom:1px solid var(--line-2);
    background:rgba(246,243,238,.94);
  }
  .bar-lead{display:none;}   /* 模式文字已并入 .who */
  .bar-actions{
    display:flex; align-items:center; justify-content:flex-end;
    flex-wrap:wrap; gap:5px;
    min-width:0;
  }
  /* 🔴 下拉不给上限会撑到 168px，把左边身份区压扁（实测 740px 宽下 voice=168px）。 */
  #voiceSel{max-width:112px; min-width:0;}
  .model-sel{font-size:12px; padding:5px 6px; border-radius:9px; min-width:0;}
  .icon-btn{font-size:12px; padding:5px 8px; border-radius:9px;}

  .hint{display:none;}
  .composer{padding-top:8px; padding-bottom:calc(8px + env(safe-area-inset-bottom));}
  .thread{padding-top:10px;}
}
