/* ============================================================
   聚合客服台 · 商户端自己的样式

   ★ 多 WorkBuddy 账号（2026-09）：名片底下多了一行 .chan-account
     「当前由「昵称」提供服务」。只显示昵称 —— uid / kfid / token
     属于平台内部的东西，商户端看不到（见 platform/core/index.js 的 wbAccountView）。

   这一份只放「商户端独有」的东西。共用骨架在 tokens.css：
   .layout / .sidebar / .topbar / .content / .page-view / .card /
   .stats-grid / table / .nav-badge / 按钮 / 登录页 / toast / .avatar /
   .chip / .field / .empty —— 那些不在这里复述。

/* ── 分页器（四张会长长的列表共用）─────────────────────────────
   .pager 本体（「共 N 条 · 第 x/y 页」+ 上一页/下一页 + 页码按钮）的样式
   在 tokens.css（和运营后台共用那一份，两处必须长得一样）——
   这里只补商户端特有的三件：
     ① 留空时彻底不占位（app.js 的 updatePager 没东西画就给空 div）；
     ② 分页器下面那行口径说明（「搜索只作用于本页」这种话必须写在脸上）；
     ③ 顶部那条分隔线 —— 表格/列表和分页器之间不加线会粘成一块。 */
.pager:empty{display:none}
.pager-note{font-size:11.5px;color:var(--text-3)}
.table-wrap+.pager,.conv-list+.pager{border-top:1px solid var(--edge)}
.bc-history-card .pager{padding:10px 0 2px}
   配色一律用 tokens.css 的变量，一个十六进制字面量都不新加。
   这里管的是间距、圆角、层次、阴影、字号和那几处「只有在
   rgba(255,255,255,α) 这种不需要新色值的边框/底色」上的细活。

   视觉主张：这是「深夜值班台」，不是仪表盘。主角是对话，
   所以侧栏和顶栏刻意安静（边框细、底色沉），把亮度都留给气泡、
   额度条和未读点；青色只用来表示「活的」（在线、已连接、可发送），
   洋红只用来表示「要你看一眼」（未读、失败、危险）。
   ============================================================ */

/* ── 第一条规矩：这个界面上不出现任何下划线 ─────────────────────
   用户已经强调三次了，所以这一次不用「挨个把 text-decoration 删掉」的办法，
   而是反过来写：全部置 none，需要时再显式加回来（目前没有任何地方需要）。

   为什么必须在所有状态上都写：`text-decoration` 在 `a:visited` / `a:hover` /
   `a:active` 上会分别生效 —— 只写一条 `a{text-decoration:none}` 的话，
   浏览器默认样式表里的 `:visited` 和 `:hover` 还能把线加回来。
   `code` / `u` / `abbr` / `ins` / `s` 也都有自己的默认下划线。
   skip-ink 一并关掉：它只在有下划线时才起作用，但留着会让人以为下划线还在。 */
a,a:link,a:visited,a:hover,a:focus,a:active,
u,ins,abbr,abbr[title],code,kbd,samp,var,pre,mark,small,sub,sup,
[data-decoration],.linkish{
  text-decoration:none;
  text-decoration-line:none;
  text-decoration-thickness:auto;
  text-decoration-skip-ink:none;
  -webkit-text-decoration-skip:none;
}
/* 可点的文字靠颜色和底色表达「能点」，不靠下划线 */
a{color:inherit}
a:hover{color:var(--accent-ink)}

/* ── 图标 ──────────────────────────────────── */
/* 尺寸跟着文字走；颜色 currentColor，所以导航选中/悬停时它会自己变 */
.ico{width:16px;height:16px;flex:none;display:block}
.sidebar-logout .ico{width:15px;height:15px}
.topbar-user .ico{width:15px;height:15px;color:var(--text-3)}

/* ── 顶栏右侧：类型 + 到期 ─────────────────────────────────────── */
/* 账号类型和到期时间是「我今天还能不能干活」这件事的唯一答案，
   所以它常驻右上角，而不是藏在设置页里。 */
.plan-chip{
  display:inline-flex;align-items:center;gap:0;flex:none;
  height:26px;border-radius:999px;overflow:hidden;
  border:1px solid var(--edge-strong);background:var(--raise-035);
  font-size:11.5px;line-height:1;white-space:nowrap;
}
.plan-chip .plan-type{
  padding:0 10px;font-weight:600;color:var(--text);
  background:linear-gradient(180deg,rgba(34,211,238,.20),rgba(34,211,238,.10));
  align-self:stretch;display:flex;align-items:center;
}
.plan-chip .plan-exp{
  padding:0 11px;color:var(--text-2);
  align-self:stretch;display:flex;align-items:center;
  font-family:var(--mono);font-size:11px;letter-spacing:-.01em;
}
.plan-chip[data-state="loading"] .plan-type{background:none;color:var(--text-3)}
.plan-chip[data-state="loading"] .plan-exp{color:var(--text-3)}
.plan-chip[data-state="ok"] .plan-type{background:linear-gradient(180deg,rgba(34,211,238,.20),rgba(34,211,238,.10))}
.plan-chip[data-state="forever"] .plan-type{background:linear-gradient(180deg,rgba(52,211,153,.22),rgba(52,211,153,.10))}
.plan-chip[data-state="forever"] .plan-exp{color:var(--text-2)}
/* 7 天内到期：整组变琥珀 —— 这一条是「请去续期」的提示，必须跳出来 */
.plan-chip[data-state="soon"]{border-color:rgba(251,191,36,.45);background:rgba(251,191,36,.10)}
.plan-chip[data-state="soon"] .plan-type{background:linear-gradient(180deg,rgba(251,191,36,.30),rgba(251,191,36,.14));color:#FDE9B8}
.plan-chip[data-state="soon"] .plan-exp{color:var(--warn-ink)}
.plan-chip[data-state="off"]{border-color:rgba(244,114,182,.45);background:rgba(244,114,182,.10)}
.plan-chip[data-state="off"] .plan-type{background:rgba(244,114,182,.22);color:#F9A8D4}
.plan-chip[data-state="off"] .plan-exp{color:#F9A8D4}

/* ── 顶栏：席位（这家商户还能连几个客户）────────────────────────────
   和旁边的 .plan-chip / .linkstate 是同一排东西，所以观感对齐：
   一样高的小胶囊、一样 11.5px 的字、一样不换行。
   ★ 颜色只用令牌，一个写死的色值都没有：border-color 走 currentColor，
     文字色一变边框跟着变 —— 两套主题下自动都不会出现「浅色字写白底」。
   ★ 四种状态：loading（还没拉到，次要文字色）/ ok（空闲）/ warn（偏挤）/ full（占满）。
     三档颜色按占用率分（< 60% / 60~99% / >= 100%）—— 用户第 2 条要的「从空闲到拥挤的颜色过渡」：
     只给「满了」上色是不够的，商户得在**还没满的时候**就看出「快满了」，才有时间清席位。 */
/* ★ 进度条（细长条，宽度按 used/limit）：挂在胶囊**下面**那一行（grid 第二行）。
   宽度由 JS 写 --seat-pct 进来。为什么把宽度放在内层 <i> 而不是条子本身：
   条子的底槽要一直是满宽（否则看不出「总共几个位子」），只有填充部分随占用率变。 */
.seat-chip{
  display:inline-flex;align-items:center;gap:5px;flex:none;
  /* ★ 由 26px 提到 34px（用户第 2 条：席位要显眼）：里面现在是两行（字 + 进度条），
     26px 装不下；席位本来就该比旁边的链接状态更抢眼一点。 */
  min-height:34px;padding:0 10px;border-radius:999px;
  border:1px solid var(--edge-strong);background:var(--raise-035);
  font-size:11.5px;line-height:1;white-space:nowrap;color:var(--text-2);
  justify-content:center;
}
.seat-chip .ico{width:13px;height:13px}
.seat-chip[data-state="loading"]{color:var(--text-3)}
/* 三档颜色：色值只写在这里，JS 只负责给 data-state（不许在 JS 里拼颜色字符串）。
   为什么恰好三档：两档（正常/满）看不出「快满了」，四档以上在 10 个席位上分不出差别
   （每 1 个位子就是 10%，档位比位子还密就没有意义了）。 */
.seat-chip[data-state="ok"]{color:var(--text-2)}
.seat-chip[data-state="warn"]{
  color:var(--warn-ink);border-color:currentColor;background:var(--raise-05);
}
.seat-chip[data-state="full"]{
  color:var(--danger-ink);border-color:currentColor;background:var(--raise-05);
}
/* 顶栏那颗胶囊改成两行网格：图标和文字在第一行，进度条在第二行占满整宽 */
.seat-chip{display:inline-grid;grid-template-columns:auto auto;column-gap:5px;row-gap:4px;align-items:center}
/* 进度条自己占满整行（写死列跨度，不指望自动放置的推断） */
.seat-chip > .seat-bar{grid-column:1 / -1}
/* 占用进度条：底槽 + 填充。填充颜色跟着 .seat-chip / .seat-card 的 data-state 走，
   所以顶栏和数据面板那张卡永远是同一个颜色口径，不用各写一套。 */
.seat-bar{
  display:block;height:3px;border-radius:999px;overflow:hidden;
  background:var(--raise-07);
}
.seat-bar > i{
  display:block;height:100%;width:var(--seat-pct,0%);
  background:var(--text-3);
  transition:width var(--dur),background var(--dur);
}
.seat-chip[data-state="ok"] .seat-bar > i{background:var(--accent-ink)}
.seat-chip[data-state="warn"] .seat-bar > i{background:var(--warn-ink)}
.seat-chip[data-state="full"] .seat-bar > i{background:var(--danger-ink)}

/* 数据面板的席位卡：.stat-card 的皮 + 一条进度条 + 一个「空闲/已满」小字。
   放在第一排（桌面 6 列时与「通道」并排），手机上排到最前面（order:-1，见窄屏媒体查询）。 */
.seat-card .label{color:var(--text-2);font-weight:600}
.seat-value-row{display:flex;align-items:baseline;gap:8px;margin-top:6px;flex-wrap:wrap}
.seat-value-row .value{margin-top:0}
.seat-act{font-size:12px;font-weight:650}
.seat-card .seat-bar{margin-top:8px;height:4px}
.seat-card[data-state="loading"] .seat-act{color:var(--text-3)}
.seat-card[data-state="ok"] .seat-act{color:var(--accent-ink)}
.seat-card[data-state="warn"] .seat-act{color:var(--warn-ink)}
.seat-card[data-state="full"] .seat-act{color:var(--danger-ink)}
.seat-card[data-state="ok"] .seat-bar > i{background:var(--accent-ink)}
.seat-card[data-state="warn"] .seat-bar > i{background:var(--warn-ink)}
.seat-card[data-state="full"] .seat-bar > i{background:var(--danger-ink)}
/* 「等待 N 位」只在真有客户排队时才出现 —— 它是「现在就得动手」的信号，
   一直亮着等于没亮（顺带：0 位时这一段根本不进卡片）。 */
.seat-wait{color:var(--warn-ink);font-weight:600}
.seat-card[data-state="full"] .seat-wait{color:var(--danger-ink)}

/* 顶栏实时/轮询指示灯（值由 app.js 的 setLink 写，语义在 #linkText 上） */
.linkstate{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-3);white-space:nowrap}
.linkstate i{
  width:7px;height:7px;border-radius:50%;background:var(--text-3);
  transition:background var(--dur),box-shadow var(--dur);
}
.linkstate[data-state="live"] i{background:var(--cyan);box-shadow:0 0 9px rgba(34,211,238,.8)}
.linkstate[data-state="poll"] i{background:var(--amber)}
.linkstate[data-state="off"] i{background:var(--magenta)}

/* 侧栏底部那个首字头像：和客户头像同一套观感，但颜色只用主题青 */
.sidebar-avatar{
  width:30px;height:30px;flex:none;border-radius:50%;display:grid;place-items:center;
  font-size:12.5px;font-weight:650;color:var(--accent-ink);
  background:rgba(34,211,238,.14);border:1px solid rgba(34,211,238,.32);
}

/* ── 页面通用 ─────────────────────────────────────────────────── */

/* 内容区是唯一的滚动容器：.layout 钉住整屏高度，长页面在 .content 里滚。
   这样顶栏和侧栏不会跟着内容一起滚走（隔壁也是这个套路）。 */
.layout{height:100dvh}
.main-area{overflow:hidden}
/* .content 用列向 flex：分页子项才能把「想要多高」交给页面自己说。
   普通页（面板/设置）内容多高就多高；工作台写 flex:1 就会自己撑满。 */
.content{overflow-y:auto;display:flex;flex-direction:column}
/* ── 卡片头 / 小方块按钮：修布局，不动 tokens.css ───────────────
   ★ 下面这两组是**覆盖** tokens.css 里的同名规则。
   tokens.css 是和运营后台共用的，约定「可读不可改」，所以修正放在这里。
   改的是同一个真问题：卡片头原本是「标题 + 副标题 + spacer + 一排按钮」
   平铺在一个 flex 里，东西一多就互相压 —— 实测在群发页上出现过
   「收件人」被压成竖排两字、「全选可发」折成两行。中文按字断行，一挤就很难看。
   这里改成 grid（标题固定 / 副标题可截断 / 工具组固定）+ nowrap，三块各归各位。 */
/* ★ 只挑卡片头，别误伤顶栏 —— 顶栏是 .topbar，不是 .card-header。
   这两条以前混在一起写过一版，结果顶栏的「刷新」被推到了最右。 */
.card-header{
  /* ★ 两列，不是三列：多数卡片头只有「标题 + 副标题」。
     声明三列的话，没东西坐的第三列会白占一份宽度 ——
     实测后果是副标题被挤成两行、工具按钮掉到下一行。
     真有三个子元素（标题 / 副标题 / 工具组）时第三个会自动落在隐式第三列上。 */
  display:grid;grid-template-columns:auto minmax(0,1fr);
  align-items:center;gap:12px;padding:14px 16px;
  background:var(--raise-022);
}
.card-title{font-size:13.5px;font-weight:600;white-space:nowrap}
/* 副标题是第一个让步的：宁可它被截断，也不要挤到标题和按钮 */
.card-subtitle{
  font-size:11.5px;color:var(--text-3);
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* grid 布局下这个 flex 占位条没用了（它在 grid 里会白占一列） */
.card-header>.topbar-spacer{display:none}

.quick-btn{
  padding:4px 9px;border-radius:7px;font-size:11.5px;cursor:pointer;
  white-space:nowrap;
  border:1px solid var(--edge-strong);background:none;color:var(--text-2);
}

/* 页面顶部的说明条 */
.page-note{
  margin:0 0 16px;padding-left:12px;
  border-left:2px solid rgba(34,211,238,.35);
  font-size:12.5px;color:var(--text-3);line-height:1.8;max-width:76ch;
}
.page-note b{color:var(--text-2)}
.dash-panel{margin-top:16px}
/* 设置页的卡片竖着排一列，最多 1080px 宽 ——
   两列在 1440 下右边会剩一块空洞，一列拉满又会把 kv 那几行拉成一条长线。 */
.settings-grid{
  display:grid;gap:16px;align-items:start;
  grid-template-columns:minmax(0,1fr);max-width:1080px;
}
.num-col{text-align:right}
.cell-who{display:flex;align-items:center;gap:9px;min-width:0}
.cell-who>span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* 设置页里的小标题（自定义 / 修改密码）：和卡标题区分开，但不能抢 */
.sub-title{
  display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;
  margin:0 0 10px;font-size:12.5px;font-weight:650;color:var(--text);
}
/* 「设置」里的小标题。★ 和下一块之间不再画分隔线（那是装饰），
   改用更大的上边距 + 标题自己的字重把两段分开。 */
.sub-title:not(:first-child){margin-top:26px;padding-top:4px}
.sub-title .card-hint{font-weight:400}

/* 功能开关（标题右边那个）：长得像 switch-row 里的开关，但更小一号。
   凡是「可启用 / 停用」的功能都用它，别处不要再造第二套开关样式。 */
.feature-toggle{display:inline-flex;align-items:center;gap:7px;font-weight:400;cursor:pointer}
.feature-toggle input{
  appearance:none;-webkit-appearance:none;
  width:32px;height:18px;flex:none;margin:0;border-radius:999px;cursor:pointer;position:relative;
  border:1px solid var(--edge-strong);background:var(--raise-06);
  transition:background var(--dur),border-color var(--dur);
}
.feature-toggle input::after{
  content:"";position:absolute;top:2px;left:2px;
  width:12px;height:12px;border-radius:50%;background:var(--text-3);
  transition:transform var(--dur),background var(--dur);
}
.feature-toggle input:checked{background:rgba(34,211,238,.28);border-color:rgba(34,211,238,.55)}
.feature-toggle input:checked::after{transform:translateX(14px);background:var(--cyan)}
.feature-toggle input:disabled{opacity:.5;cursor:not-allowed}
.feature-toggle-text{font-size:11.5px;color:var(--text-3);min-width:3.2em}
.feature-toggle input:checked ~ .feature-toggle-text{color:var(--accent-ink)}

/* ── 数据面板：我的通道摘要 ─────────────────────────────────────
   四行之间原本靠一条发丝线分开；现在用「隔行底色 + 圆角」分层 ——
   同样能看出是四行，但页面上少四条线。 */
.mini-line{
  display:flex;align-items:center;gap:10px;
  padding:9px 10px;border-radius:8px;
}
.mini-line:nth-child(odd){background:var(--raise-02)}
.mini-dot{width:8px;height:8px;border-radius:50%;flex:none;box-shadow:0 0 9px currentColor}
.mini-name{font-size:13px;font-weight:600;min-width:6em}
.mini-state{font-size:12px;color:var(--text-2)}
.mini-extra{margin-left:auto;font-size:11px;color:var(--text-3);white-space:nowrap}

/* ── 客服工作台：两栏（会话列表 + 对话）──────────────────────── */
/*  ★ 这两栏是「同一个页面视图」里的布局，不再是跨页切换。
    data-view=thread 时列表让位给对话 —— 手机上跟微信一样一次只看一层。 */
.page-chat.active{display:flex;flex-direction:column;flex:1;min-height:0}
.page-chat .chat-board{
  flex:1;min-height:0;
  display:grid;grid-template-columns:300px minmax(0,1fr);
  gap:1px;background:var(--edge);
  border:1px solid var(--edge);border-radius:var(--r-panel);overflow:hidden;
  box-shadow:0 30px 70px -60px var(--shadow-2);
}

.pane{
  display:flex;flex-direction:column;min-height:0;min-width:0;
  background:linear-gradient(180deg,var(--panel-d),var(--panel-b));
}
/* 栏头。★ 这一条 border-bottom 是留着的，和全局「去掉装饰线」不矛盾：
   它正好压在滚动区上沿，滚动时列表内容会从它下面消失 ——
   没有它的话，滚到一半的客户名会贴着栏头文字，看着像串行。
   底下的分隔线同理，也是「固定区 / 滚动区」的分界，不是为了好看。 */
.pane-head{
  display:flex;align-items:baseline;gap:10px;flex:none;
  padding:14px 18px 13px;border-bottom:1px solid var(--edge);
}
.pane-head h2{font-size:13.5px;font-weight:600}
.pane-meta{margin-left:auto;font-size:12px;color:var(--text-3)}
.back{display:none}

/* ── 会话列表 ─────────────────────────────────────────────────── */

.conv-list{list-style:none;margin:0;padding:0;flex:1;min-height:0;overflow-y:auto}

/* 会话列表的一条。
   ★ 每条下面原本有一条发丝线；现在靠「每条自己一个圆角块 + 隔行底色」分层，
     悬停时整块提亮，比一堆横线干净。
   ★ <li> 里是「.conv + .conv-more 并列」—— 资料按钮不能嵌进 .conv，
     否则就是 button 套 button（HTML 不允许，浏览器会把 DOM 拆开）。 */
.conv-list>li{
  display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:stretch;
  margin:0 8px 2px;border-radius:10px;
  transition:background var(--dur);
}
.conv-list>li:nth-child(odd){background:var(--raise-018)}
.conv-list>li:hover{background:var(--raise-045)}

.conv{
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-rows:auto auto;
  gap:4px 12px;
  align-items:center;
  width:100%;padding:12px 10px 12px 12px;text-align:left;position:relative;
  background:none;border:0;
  cursor:pointer;transition:background var(--dur);
}
.conv>.avatar{grid-row:1/3;grid-column:1;align-self:center}

/* 右边那个显式「资料」按钮：平时淡，悬停整条时亮起来 */
.conv-more{
  align-self:center;margin-right:10px;flex:none;
  padding:4px 10px;border-radius:8px;cursor:pointer;
  border:1px solid transparent;background:none;
  color:var(--text-3);font-size:11.5px;white-space:nowrap;
  transition:color var(--dur),border-color var(--dur),background var(--dur);
}
.conv-list>li:hover .conv-more{color:var(--text-2);border-color:var(--edge)}
.conv-more:hover{color:var(--accent-ink);border-color:rgba(34,211,238,.45);background:rgba(34,211,238,.10)}
/* 选中的那条：一片从青到透明的底 + 左边一道 2px 的背光。
   ★ 这道背光不是「下划线」—— 它是一条竖向的状态色，和顶部那条 --ch 是同一套语言；
     选中的状态光靠底色在深色界面里不够一眼看出。 */
.conv[aria-selected="true"]{background:linear-gradient(90deg,rgba(34,211,238,.14),transparent 82%)}
.conv[aria-selected="true"]::before{
  content:"";position:absolute;left:0;top:6px;bottom:6px;width:2px;
  border-radius:0 2px 2px 0;background:var(--cyan);
}

.conv-top{grid-column:2;grid-row:1;display:flex;align-items:center;gap:8px;min-width:0}
.conv-who{font-size:13.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.conv-time{grid-column:3;grid-row:1;font-size:11px;color:var(--text-3);white-space:nowrap}

.conv-last{
  grid-column:2;grid-row:2;margin:0;font-size:12.5px;color:var(--text-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

.conv-side{grid-column:3;grid-row:2;display:flex;align-items:center;gap:8px;justify-self:end}

.badge{
  display:inline-block;padding:1px 8px;border-radius:6px;font-size:10.5px;line-height:1.7;
  border:1px solid currentColor;opacity:.9;white-space:nowrap;
}

.unread{
  min-width:19px;height:19px;padding:0 5px;border-radius:999px;
  display:grid;place-items:center;
  font-family:var(--mono);font-size:10.5px;font-weight:700;
  background:var(--magenta);color:#3A0A1E;
}
.unread[data-fresh="true"]{animation:pop .5s var(--ease) 2}
@keyframes pop{0%,100%{transform:scale(1)}45%{transform:scale(1.22)}}

/* 会话列表里只在「发不出去」时才提示额度：能发是常态，不必占位置 */
.blocked-chip{
  padding:1px 8px;border-radius:6px;font-size:10.5px;line-height:1.7;white-space:nowrap;
  border:1px solid rgba(244,114,182,.45);background:rgba(244,114,182,.12);color:#F9A8D4;
}

/* ── 对话 ─────────────────────────────────────────────────────── */

/* 客户名是可点的：点了开「客户资料」。
   ★ 这里不用下划线来做「可点」的提示 —— 它同时还是这一栏的标题，
     给标题加下划线很脏。改用悬停时变青 + 右边那个显式的「资料」按钮。
   ★ 名字要能自己让位：手机上「返回」和两个通话按钮都是钉子（flex:none），
     只剩名字能省略号。flex-grow 必须给 1 —— 不给的话它就是内容宽度，
     长名字会直接顶到胶囊上去（而不是自己变短）。
   头部一排：返回 / 头像 / 名字 / 资料 / 通道胶囊 / 通话按钮。
   ★ .thread-actions 是「状态 / 置顶 / 删除」那一组外面新包的一层：
   桌面 display:contents —— 这一层等于不存在，布局和加它之前逐像素相同；
   手机上才变成真的 flex 容器，整组换到第二行（否则 9 个控件挤一行，
   「状态/置顶/删除」被压成两行字、通话按钮顶出屏幕 —— 实测 360×640）。 */
.thread-head h2{
  flex:1 1 auto;min-width:0;
  font-size:14.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:color var(--dur);
}
.thread-actions{display:contents}
.thread-head h2.linkish{cursor:pointer}
.thread-head h2.linkish:hover{color:var(--accent-ink)}
/* 显式的「资料」按钮：隔壁靠点名字开资料，我们两条路都给（名字 + 这个按钮） */
.head-profile{flex:none;padding:4px 10px;font-size:12px;white-space:nowrap}
.head-profile:disabled{opacity:.35;cursor:not-allowed}
.thread-head .avatar-sm{flex:none}
.thread-head .back{flex:none;white-space:nowrap}
.thread-head .badge{flex:none}
/* ★ .pane-head 用的是 align-items:baseline（会话列表头也用它，那是对的）。
   baseline 会让每个 flex 项按内容宽度收缩 —— 名字就算给了 flex-grow 也长不起来，
   手机上表现就是「张…」被压成两个字。对话头改成 center，名字才能吃掉剩余宽度。 */
.thread-head{align-items:center}

/* 对话头部右侧的通话入口（发起语音/视频）。保留在头部 ——
   通话和「回一条消息」是同一件事的两个做法。 */
.thread-call{display:flex;gap:6px;margin-left:auto;flex:none}
.thread-call .btn-quiet{padding:4px 10px;font-size:12px;white-space:nowrap}

.stream-wrap{flex:1;min-height:0;overflow-y:auto;padding:22px 24px}

.stream{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:14px}

.msg{
  display:flex;align-items:flex-end;gap:10px;
  max-width:min(660px,82%);
  animation:msgIn .22s var(--ease) both;
}
@keyframes msgIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
/* 整段重建时不要每一条都演一遍入场 */
.stream[data-bulk="true"] .msg{animation:none}
/* ★ 自己发的靠右：
   .msg 是 flex 容器且限了宽（max-width:min(660px,82%)），
   光靠 align-self:flex-end 只是把「这个 660px 宽的盒子」推到右边；
   盒子里那个气泡还得自己再贴右，否则宽气泡才会填满、短气泡会飘到左边。
   这一条以前是缺的 —— 短回复看着像对方说的。 */
.msg[data-dir="in"]{align-self:flex-start}
.msg[data-dir="out"]{align-self:flex-end;justify-content:flex-end}

.msg-bubble{display:flex;flex-direction:column;gap:5px;min-width:0}
.msg[data-dir="out"] .msg-bubble{align-items:flex-end}

/* ★ 消息气泡旁没有头像 —— 连 .msg-avatar 这个类都不存在了。
   那条「在消息旁显示头像」的偏好也一并拆掉：一个没人会开的开关，不值得占一行设置。 */

.msg-body{
  margin:0;padding:10px 14px;
  border:1px solid var(--edge);border-radius:var(--r-bubble) var(--r-bubble) var(--r-bubble) 4px;
  background:var(--ink-750);
  white-space:pre-wrap;overflow-wrap:anywhere;
}
.msg[data-dir="out"] .msg-body{
  border-radius:var(--r-bubble) var(--r-bubble) 4px var(--r-bubble);
  background:rgba(34,211,238,.13);border-color:rgba(34,211,238,.34);
}

/* ── 客户发来的图片 / 语音 / 视频 / 文件（2026-09-26，2026-09-27 补媒体落地）
   ★ 地址有两代：老的是通道给的**直链**（微信 CDN，会过期），新的是平台自己落的
     /m/<id>?k=…（永久）。前端优先用后者，加载失败一律退成一枚链接 —— 这里只负责好看。 */
.msg-att{display:flex;flex-direction:column;gap:6px;max-width:100%}
.msg-att-img{
  max-width:min(320px,100%);max-height:280px;width:auto;height:auto;
  border:1px solid var(--edge);border-radius:var(--r-bubble);
  background:var(--raise-03);object-fit:contain;
  cursor:zoom-in;
}
/* 客户发来的视频 / 语音：在会话里直接能看能听（2026-09-26 加） */
.msg-att-video{
  max-width:min(320px,100%);max-height:280px;
  border:1px solid var(--edge);border-radius:var(--r-bubble);
  background:#000;display:block;
}
.msg-att-audio{width:min(260px,100%);height:36px;display:block}
.msg-att-name{
  font-size:12px;color:var(--text-2);
  padding:7px 10px;border:1px solid var(--edge);border-radius:10px;
  background:var(--raise-03);overflow-wrap:anywhere;
}
.msg-att-link{
  align-self:flex-start;font-size:11.5px;color:var(--accent-ink);text-decoration:none;
  border-bottom:1px dashed rgba(34,211,238,.45);
}
.msg-att-link:hover{color:var(--text)}
.msg[data-dir="out"] .msg-att-link{align-self:flex-end}

/* 媒体还没落地（正在下载）/ 落地失败：必须一眼看出是「还没好」而不是「坏了」 */
.msg-att-wait[data-state="pending"] .msg-att-name{color:var(--text-2);border-style:dashed}
.msg-att-wait[data-state="failed"] .msg-att-name{
  color:#FBBF24;border-color:rgba(251,191,36,.42);background:rgba(251,191,36,.08);
}

/* 图片灯箱：会话里的缩略图看不清菜单/价格，客户发的图就是拿来「看」的 */
.lightbox{
  position:fixed;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;
  padding:24px;background:rgba(4,7,14,.88);backdrop-filter:blur(3px);
}
.lightbox-img{
  max-width:94vw;max-height:86vh;border-radius:14px;
  border:1px solid rgba(148,163,184,.25);box-shadow:0 24px 70px rgba(0,0,0,.6);
}
.lightbox-close{
  position:absolute;top:18px;right:22px;padding:8px 14px;font:inherit;font-size:13px;
  color:var(--text);background:rgba(17,24,39,.9);border:1px solid var(--edge);
  border-radius:9px;cursor:pointer;
}
.lightbox-close:hover{border-color:var(--accent-ink);color:var(--accent-ink)}

/* 失败必须看得见：这是产品承诺（失败要给人话原因） */
.msg[data-status="failed"] .msg-body{background:rgba(244,114,182,.1);border-color:rgba(244,114,182,.42)}
.msg-err{margin:0;font-size:11.5px;color:var(--danger-ink);text-align:right}

/* ── 待发（客户还没开口时排下的消息，见 core/pending.js）───────────────
   虚线 + 弱化：一眼看出「还没真发出去」，和已发出的实心气泡区分开。 */
.msg[data-pending] .msg-body{
  background:transparent;border:1px dashed rgba(34,211,238,.45);color:var(--text-2);
}
.msg[data-pending="failed"] .msg-body{border-color:rgba(244,114,182,.42)}
.msg-pending-why{margin:0;font-size:11.5px;color:var(--text-3);text-align:right}
.msg[data-pending="failed"] .msg-pending-why{color:var(--danger-ink)}
.msg[data-pending] .msg-meta{gap:10px}
.link-btn{
  padding:0;border:0;background:none;font:inherit;font-size:11.5px;
  color:var(--accent-ink);cursor:pointer;text-decoration:underline;
}
.link-btn:hover{opacity:.8}

.msg-meta{display:flex;align-items:center;gap:8px;font-family:var(--mono);font-size:10.5px;color:var(--text-3)}
.stream-wrap[data-show-time="false"] .msg-meta{display:none}
.msg[data-dir="out"] .msg-meta{flex-direction:row-reverse}
.msg-layer{opacity:.8}

/* ── 输入区：额度就是主角 ─────────────────────────────────────── */

.composer{
  flex:none;
  border-top:1px solid var(--edge);
  padding:14px 20px 16px;
  background:var(--inset-bg);
}

.quota{display:flex;align-items:center;gap:11px;margin-bottom:11px;min-height:28px}
.quota-num{font-size:25px;font-weight:600;line-height:1;color:var(--accent-ink)}
.quota-unit{font-size:12px;color:var(--text-2)}
.quota-track{display:flex;gap:3px;margin-left:2px}
.quota-track i{width:18px;height:3px;border-radius:1px;background:var(--raise-10);transition:background var(--dur)}
.quota-track i[data-on="true"]{background:var(--cyan)}
.quota[data-low="true"] .quota-num,.quota[data-low="true"] .quota-unit{color:var(--danger-ink)}
.quota[data-low="true"] .quota-track i[data-on="true"]{background:var(--magenta)}
.quota[data-unlimited="true"] .quota-num{font-size:17px}

.composer-row{display:flex;align-items:flex-end;gap:10px}

.composer textarea{
  flex:1;min-height:46px;max-height:168px;resize:none;
  padding:12px 14px;
  border:1px solid var(--edge);border-radius:var(--r-control);
  background:var(--field-bg-3);color:var(--text);
  font:inherit;line-height:1.5;
  transition:border-color var(--dur),box-shadow var(--dur);
}
.composer textarea::placeholder{color:var(--text-3)}
.composer textarea:focus{outline:0;border-color:rgba(34,211,238,.5);box-shadow:0 0 0 3px rgba(34,211,238,.1)}
.composer textarea:disabled{opacity:.5;cursor:not-allowed}

.composer-hint{margin:9px 0 0;font-size:11.5px;color:var(--text-3);min-height:1.2em}
/* 客户会话窗口没开（客户还没发过消息）：把话说清楚，但**不锁**输入框 */
.composer-hint[data-tone="warn"]{color:var(--warn-ink)}
.bc-line[data-queued="1"] .bc-line-tone{color:var(--warn-ink)}
.composer[data-blocked="true"] .composer-hint{color:var(--danger-ink)}

/* ── 输入区工具条（照隔壁 .mia-tools）──────────────────────────── */
/*  表情/图片/文件/视频/录音 + 自定义。五个圆形小按钮，横排在输入框上方。

    ★ 发不了媒体的那四个按钮会带 [data-gated="1"] + disabled：
      半透明 + 禁止光标 + 一条「只能发文字」的说明挂在右边。
      不能发就是不能发，但得让商户知道为什么（title 和点击提示都是 mediaReason）。 */
.quick-pills{
  display:flex;flex-wrap:nowrap;gap:6px;
  margin:0 0 9px;padding:0 1px 2px;
  overflow-x:auto;scrollbar-width:none;
}
.quick-pills::-webkit-scrollbar{display:none}
.quick-pill{
  flex:none;max-width:230px;
  padding:5px 13px;border-radius:999px;cursor:pointer;
  border:1px solid var(--edge);background:var(--raise-03);
  color:var(--text-2);font-size:12px;line-height:1.6;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:color var(--dur),border-color var(--dur),background var(--dur);
}
.quick-pill:hover{color:var(--accent-ink);border-color:rgba(34,211,238,.45);background:rgba(34,211,238,.09)}

.mia-tools{display:flex;align-items:center;gap:4px;margin-bottom:9px;flex-wrap:wrap}

.mini-btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:32px;height:32px;padding:0;flex:none;
  border:0;border-radius:9px;background:transparent;color:var(--text-2);
  cursor:pointer;
  transition:color var(--dur),background var(--dur),opacity var(--dur);
}
.mini-btn .ico{width:18px;height:18px}
.mini-btn:hover:not(:disabled){color:var(--accent-ink);background:rgba(34,211,238,.10)}
.mini-btn[aria-expanded="true"]{color:var(--accent-ink);background:rgba(34,211,238,.14)}
/* 被通道能力挡住的媒体按钮。title 里有原因，点击有提示，但按钮本身是灰的 */
.mini-btn:disabled,.mini-btn[data-gated="1"]{
  opacity:.34;cursor:not-allowed;
  color:var(--text-3);
}
.mini-btn:disabled:hover,.mini-btn[data-gated="1"]:hover{background:transparent;color:var(--text-3)}
/* 自定义按钮靠右一点，和「发消息」的那排分开 */
.mia-tools .tools-more{margin-left:auto}

.tools-note{
  flex:none;font-size:11px;color:var(--text-3);
  padding:2px 9px;border-radius:999px;
  background:var(--raise-05);
  white-space:nowrap;
}

/* ── 录音 / 试听条（照隔壁 openclaw-web 的 .voice-rec / .voice-preview）──
   点 🎤 出现：先是「● 正在录音 00:05 + 取消/完成」，录完换成「试听 + 重录/发送」。
   ★ [hidden] 必须显式写 display:none —— 这两条的 display 是 flex，
     不写的话 hidden 属性会被压过去（面板关不掉，这种坑踩过一次）。 */
.voice-rec,.voice-preview{
  display:flex;align-items:center;gap:10px;
  margin-bottom:9px;padding:8px 12px;border-radius:12px;
  background:var(--raise-04);border:1px solid rgba(34,211,238,.22);
}
.voice-rec[hidden],.voice-preview[hidden]{display:none}
.voice-rec-dot{
  width:9px;height:9px;border-radius:50%;flex:none;background:var(--danger-ink);
  animation:voicePulse 1.1s ease-out infinite;
}
@keyframes voicePulse{
  0%{box-shadow:0 0 0 0 rgba(244,114,182,.5)}
  70%{box-shadow:0 0 0 8px rgba(244,114,182,0)}
  100%{box-shadow:0 0 0 0 rgba(244,114,182,0)}
}
/* 时间用等宽数字：跳秒时不会把右边的按钮挤来挤去 */
.voice-rec-time{font-variant-numeric:tabular-nums;font-size:14px;font-weight:600;color:var(--text);min-width:48px}
.voice-rec-tip{flex:1;min-width:0;font-size:12px;color:var(--text-3)}
.voice-rec .btn-quiet,.voice-rec .btn-primary,
.voice-preview .btn-quiet,.voice-preview .btn-primary{flex:none}
.voice-preview audio{flex:1;min-width:0;height:38px}
/* 手机上按钮要够大（和「工具条 44px」「对话头 44px」同一个口径）；那行提示文字让位 */
@media (max-width:640px){
  .voice-rec,.voice-preview{padding:8px 10px;gap:8px}
  .voice-rec .btn-quiet,.voice-rec .btn-primary,
  .voice-preview .btn-quiet,.voice-preview .btn-primary{min-height:44px;padding:0 14px}
  .voice-rec-tip{display:none}
}


/* ── 表情面板（照隔壁 .emoji-panel）────────────────────────────── */
/*  贴在输入区上方，分类 + 网格。给的是文本表情 [微笑] ——
    微信客服号的出站只认文字，图片表情发不出去，文本表情才是真能发的那个。 */
.emoji-panel{
  position:absolute;left:20px;bottom:calc(100% - 6px);z-index:35;
  width:min(392px,calc(100vw - 36px));
  max-height:322px;display:flex;flex-direction:column;
  border:1px solid var(--edge-strong);border-radius:var(--r-panel);
  background:linear-gradient(170deg,var(--panel-g),var(--panel-c));
  box-shadow:0 34px 70px -34px var(--shadow-1);
  animation:msgIn .16s var(--ease) both;
}
.composer{position:relative}
.emoji-head{
  display:flex;align-items:center;gap:8px;flex:none;
  padding:8px 8px 8px 10px;border-bottom:1px solid var(--edge);
}
.emoji-tabs{display:flex;gap:4px;flex:1;min-width:0;overflow-x:auto;scrollbar-width:none}
.emoji-tabs::-webkit-scrollbar{display:none}
.emoji-tab{
  flex:none;padding:4px 11px;border-radius:999px;cursor:pointer;
  border:1px solid var(--edge);background:none;color:var(--text-2);font-size:12px;
  transition:color var(--dur),border-color var(--dur),background var(--dur);
}
.emoji-tab:hover{color:var(--text)}
.emoji-tab[data-on="true"]{color:var(--accent-ink);border-color:rgba(34,211,238,.45);background:rgba(34,211,238,.12)}
.emoji-close{
  flex:none;width:26px;height:26px;border:0;border-radius:7px;background:none;
  color:var(--text-3);font-size:17px;line-height:1;cursor:pointer;
}
.emoji-close:hover{color:var(--text);background:var(--raise-06)}

.emoji-grid{
  flex:1;min-height:0;overflow-y:auto;
  display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:4px;padding:10px;
}
/* 表情格子。
   ★ 真 emoji：就一个大字形，字号给足（手机上也要一眼认出来）。
   ★ 微信表情：大字形预览 + 下面的中文名 —— 因为发出去的其实是那串中文。 */
.emoji-cell{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  padding:6px 2px;border-radius:8px;cursor:pointer;
  border:1px solid transparent;background:var(--raise-028);
  color:var(--text-2);
  text-align:center;overflow:hidden;
  transition:color var(--dur),background var(--dur),border-color var(--dur),transform var(--dur);
}
.emoji-face{
  font-size:20px;line-height:1.25;
  /* 系统 emoji 字体优先：有些环境里默认字体会把它渲染成黑白轮廓 */
  font-family:"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",var(--sans);
}
.emoji-name{
  font-size:10px;line-height:1.3;color:var(--text-3);
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.emoji-cell:hover{color:var(--accent-ink);background:rgba(34,211,238,.12);border-color:rgba(34,211,238,.35);transform:translateY(-1px)}
/* 微信表情那一栏字号小一点：中文名比一个字宽，格子要装得下 */
.emoji-grid[data-kind="wx"] .emoji-face{font-size:18px}
.emoji-grid[data-kind="wx"] .emoji-cell{padding:5px 1px}
/* 微信表情那一栏中文名多，一行放不下 6 个（格子会挤成竖排） */
.emoji-grid[data-kind="wx"]{grid-template-columns:repeat(5,minmax(0,1fr))}
.emoji-note{
  flex:none;margin:0;padding:9px 12px 11px;border-top:1px solid var(--edge);
  font-size:11px;color:var(--text-3);line-height:1.65;
}
.emoji-note b{color:var(--text-2);font-weight:600}
.emoji-note code{
  font-family:var(--mono);font-size:10.5px;padding:1px 5px;border-radius:5px;
  background:var(--raise-06);color:var(--text-2);
}

/* ── 录音条 / 试听条：已经整体移除 ───────────────────────
   微信客服号发不了语音，而录音面板会占住整个输入区，最后只是一句「发不出去」。
   现在图片走「上传 → 链接当文本发」，语音/文件/视频就是不做 —— 不做比假做好。 */

/* ── 网站总通道：名片 ─────────────────────────────────────────── */
/*  名片是「可点的卡」而不是时间轴上的节点：四张并排，一眼看完本站支持什么。
      但节点语义（data-status / data-open / --ch 色）保持原样，颜色和压暗规则不变。 */

.rail{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(268px,1fr));gap:14px;
}

.line{
  position:relative;
  animation:lineIn .42s var(--ease) both;
  animation-delay:calc(var(--i,0) * 65ms + 80ms);
}
@keyframes lineIn{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}

/* 通道卡片 —— 四个位置是钉死的，未接入的也把卡片画出来。
   ★ 2026-09-26：名片改成**只读展示**。原来是个按钮、点了开抽屉，
     所以有 cursor:pointer + 上浮 + 光晕那一套「可点」的暗示。
     现在它不是按钮了，这些暗示必须一起去掉 —— 否则鼠标变手型、
     按下去没反应，比什么都不做更让人恼火。 */
.chan-card{
  display:flex;flex-direction:column;gap:5px;
  width:100%;height:100%;padding:16px 17px;text-align:left;
  border:1px solid var(--edge);
  border-top:2px solid var(--ch,var(--rail));
  border-radius:var(--r-panel);
  background:linear-gradient(180deg,var(--raise-035),var(--raise-012));
}

/* 名片里四行文字走正常流，不摆 grid-area ——
   卡片最窄 268px，行高让内容自己决定最稳。
   头和胶囊同处一行：名字长了就自己省略号，绝不会顶到胶囊底下。 */
.chan-head{display:flex;align-items:center;gap:8px}
.chan-name{flex:1;min-width:0;font-size:14px;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chan-desc{
  margin:1px 0 0;font-size:11.5px;color:var(--text-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.chan-chip{
  flex:none;
  padding:2px 10px;border-radius:999px;white-space:nowrap;
  font-size:11px;border:1px solid currentColor;color:var(--text-3);
}
/* 名片上那行运营管的字：待完善/已完善 · 启用/关闭 */
.chan-flags{
  margin-top:1px;
  font-size:10.5px;letter-spacing:.02em;color:var(--text-3);opacity:.85;
}
/* 「我这边的接入状态 + 已接入客户数」——商户视角的那半张名片。
   ★ 这里原来是一条 border-top 把上下分开；现在用 1px 高的分层背景，
     看着是一条「面板接缝」而不是一根线。 */
.chan-count{
  margin-top:auto;padding:10px 0 0;
  background-image:linear-gradient(90deg,transparent,var(--raise-10) 18%,var(--raise-10) 82%,transparent);
  background-size:100% 1px;background-repeat:no-repeat;
  font-size:11.5px;color:var(--text-2);
}

/* 未接入：位置留着，但不要抢眼 */
.line[data-status="unbound"] .chan-chip,
.line[data-status="pending"] .chan-chip{color:var(--ch,var(--accent-ink))}
.line[data-status="bound"] .chan-chip{color:var(--ch,var(--accent-ink));background:var(--ch-halo,rgba(34,211,238,.14))}
.line[data-status="error"] .chan-chip{color:var(--danger-ink)}
.line[data-status="unavailable"] .chan-card{opacity:.55;border-top-color:#33405A}
.line[data-status="unavailable"] .chan-chip{color:var(--text-3)}
.line[data-status="unavailable"] .chan-name{color:var(--text-2)}
/* 运营把这张名片关了：压暗，但仍然能点开看原因。
   ★ 不用虚线边 —— 虚线在这里只是「另一种线」，说不了话。
     改成把底色抽掉（它比旁边暗一层），一眼就能看出「这条现在别点」。 */
.line[data-open="0"] .chan-card{
  opacity:.46;background:var(--raise-012);border-top-color:#2A3550;
}
.line[data-open="0"] .chan-name{color:var(--text-2)}
.line[data-open="0"] .chan-card:hover{opacity:.78}
.line[data-open="0"] .chan-flags{color:#6b7891}

/* 抽屉顶部的两个状态药丸（待完善/已完善、启用/关闭） */
.slot-state{display:flex;gap:8px;margin:0 0 10px}
.slot-state .pill{
  padding:3px 12px;border-radius:999px;font-size:11.5px;
  border:1px solid var(--edge-strong);color:var(--text-3);
}
.slot-state .pill[data-on="1"]{color:var(--accent-ink);border-color:rgba(34,211,238,.5);background:rgba(34,211,238,.12)}
.slot-state .pill[data-on="0"]{color:var(--warn-ink);border-color:rgba(251,191,36,.36);background:rgba(251,191,36,.08)}

/* ── 接入抽屉 ─────────────────────────────────────────────────── */

.drawer-veil{position:fixed;inset:0;z-index:40;background:var(--scrim);animation:fade .18s both}
@keyframes fade{from{opacity:0}to{opacity:1}}

.drawer{
  position:fixed;top:0;right:0;bottom:0;z-index:41;
  width:min(460px,100%);
  display:flex;flex-direction:column;
  border-left:1px solid var(--edge-strong);
  background:linear-gradient(180deg,var(--panel-e),var(--panel-c));
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  box-shadow:-40px 0 90px -60px var(--shadow-1);
  animation:slideIn .26s var(--ease) both;
}
@keyframes slideIn{from{transform:translateX(26px);opacity:0}to{transform:none;opacity:1}}

.drawer-head{display:flex;align-items:center;gap:11px;flex:none;
  padding:18px 22px;border-bottom:1px solid var(--edge)}
.drawer-head h2{font-size:15px;flex:1}
.drawer-bar{width:3px;height:18px;border-radius:2px;background:var(--ch,var(--accent-ink))}

.drawer-body{padding:22px;overflow-y:auto;display:flex;flex-direction:column;gap:16px;flex:1}

.drawer-body p{margin:0;font-size:13px;color:var(--text-2);line-height:1.75}

.reason{
  padding:14px 16px;border-radius:var(--r-control);
  border:1px solid rgba(244,114,182,.28);background:rgba(244,114,182,.07);
  font-size:12.5px;color:#F8C7DD;line-height:1.75;
}
.reason b{color:var(--danger-ink);font-weight:600}

.qr-plate{
  width:max-content;margin:4px auto;padding:13px;border-radius:14px;background:#fff;
  box-shadow:0 24px 70px -34px rgba(34,211,238,.85);
}
.qr-plate img{display:block;width:214px;height:214px}

.qr-note{text-align:center;font-size:12.5px;color:var(--text-2)}
.qr-timer{font-family:var(--mono);color:var(--text)}

/* kv 表：宽屏一行两对、窄屏一行一对。
   一列到底在 1440 下会把「商户 ID」那种短值拉成一条长线，右边整片空着。 */
.kv{
  display:grid;align-items:center;
  grid-template-columns:auto minmax(0,1fr);
  font-size:12.5px;
}
@media (min-width:900px){
  .kv{grid-template-columns:auto minmax(0,1fr) auto minmax(0,1fr);column-gap:26px}
}
.kv dt{color:var(--text-3);padding:10px 0}
.kv dd{
  margin:0;padding:10px 0;overflow-wrap:anywhere;
  font-family:var(--mono);
}
/* 行与行不画线：靠行距和「值比键亮」的层级分开。
   ★ 原来这里靠一条发丝线分上下行；实测在深色底上那些线比文字还显眼，
     反而把「键 → 值」的对应关系切断了。padding 加大一点就够了。 */

.bound-ok{
  padding:14px 16px;border-radius:var(--r-control);
  border:1px solid rgba(34,211,238,.3);background:rgba(34,211,238,.08);
  font-size:13px;color:#B9EEF8;
}

.drawer-actions{display:flex;gap:10px;margin-top:6px;flex-wrap:wrap}

/* 长期二维码那一块 */
.link-row{display:flex;align-items:center;gap:10px;margin-top:2px}
.link-row .secret{margin-top:0;flex:1}
.drawer-sub{margin:8px 0 0;font-size:12.5px;font-weight:600;color:var(--text-3)}
.drawer-note{margin:0;font-size:12px;color:var(--text-3);line-height:1.7}

/* 设置页里那串客服链接：等宽 + 可选中，不换行会把卡片撑破 */
.secret{
  display:block;margin-top:6px;padding:10px 12px;border-radius:9px;
  border:1px solid var(--edge);background:var(--field-bg-4);
  font-family:var(--mono);font-size:12px;color:var(--text-2);
  overflow-wrap:anywhere;
}

/* ── 自定义：常用话术列表 / 开关行 / 通道能力（只读）────────────── */

.reply-list{list-style:none;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:2px}
.reply-item{
  display:flex;align-items:center;gap:10px;
  padding:9px 10px;border-radius:9px;
  transition:background var(--dur);
}
/* 话术列表靠「隔行底色 + 悬停提亮」分辨行，不再一条一条画底线 */
.reply-item:nth-child(odd){background:var(--raise-022)}
.reply-item:hover{background:var(--raise-05)}
.reply-tag{
  flex:none;min-width:3.2em;text-align:center;
  padding:2px 9px;border-radius:6px;font-size:11px;
  color:var(--accent-ink);background:rgba(34,211,238,.11);border:1px solid rgba(34,211,238,.28);
}
.reply-text{
  flex:1;min-width:0;font-size:12.5px;color:var(--text-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.reply-empty{margin:0 0 12px;padding:14px 2px;font-size:12.5px;color:var(--text-3);list-style:none}

.reply-add{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.reply-add input{
  flex:1;min-width:140px;padding:9px 12px;
  border:1px solid var(--edge);border-radius:var(--r-control);
  background:var(--field-bg-3);color:var(--text);font:inherit;font-size:12.5px;
  transition:border-color var(--dur),box-shadow var(--dur);
}
.reply-add input::placeholder{color:var(--text-3)}
.reply-add input:focus{outline:0;border-color:rgba(34,211,238,.5);box-shadow:0 0 0 3px rgba(34,211,238,.1)}
.reply-add #replyTitle{flex:0 0 150px;min-width:110px}
.reply-add .btn-quiet{padding:9px 15px;font-size:12.5px;flex:none}

/* 开关行：整行可点，checkbox 跟着主题青。 */
.switch-row{
  display:flex;align-items:flex-start;gap:11px;
  padding:10px 12px;border-radius:var(--r-control);
  border:1px solid transparent;cursor:pointer;
  transition:background var(--dur),border-color var(--dur);
}
.switch-row:hover{background:var(--raise-03);border-color:var(--edge)}
.switch-row input{
  appearance:none;-webkit-appearance:none;
  width:36px;height:20px;flex:none;margin:1px 0 0;border-radius:999px;
  border:1px solid var(--edge-strong);background:var(--raise-06);
  cursor:pointer;position:relative;transition:background var(--dur),border-color var(--dur);
}
.switch-row input::after{
  content:"";position:absolute;top:2px;left:2px;
  width:14px;height:14px;border-radius:50%;background:var(--text-3);
  transition:transform var(--dur),background var(--dur);
}
.switch-row input:checked{background:rgba(34,211,238,.28);border-color:rgba(34,211,238,.55)}
.switch-row input:checked::after{transform:translateX(16px);background:var(--cyan)}
.switch-text{display:flex;flex-direction:column;gap:1px;min-width:0}
.switch-text b{font-size:12.5px;font-weight:600;color:var(--text)}
.switch-text i{font-style:normal;font-size:11px;color:var(--text-3);line-height:1.5}
.switch-row.compact{padding:9px 10px}

/* 通道能力（只读）：一句话讲清「这条通道能干什么」——
   和输入区那排灰按钮同源，都是 /api/bindings 的 sendMedia。 */
.cap-list{display:flex;flex-direction:column;gap:10px}
.cap-row{
  padding:12px 14px;border-radius:var(--r-control);
  border:1px solid var(--edge);background:var(--raise-022);
}
.cap-row[data-on="0"]{opacity:.72}
.cap-head{display:flex;align-items:center;gap:9px}
.cap-dot{width:8px;height:8px;border-radius:50%;flex:none;box-shadow:0 0 9px currentColor}
.cap-name{font-size:13px;font-weight:600}
.cap-state{margin-left:auto;font-size:11.5px;color:var(--text-3)}
.cap-marks{list-style:none;margin:9px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:6px 14px}
.cap-mark{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--text-2)}
.cap-yes{
  flex:none;min-width:2.6em;text-align:center;
  padding:1px 7px;border-radius:5px;font-size:10.5px;
  border:1px solid currentColor;
}
.cap-mark[data-ok="1"] .cap-yes{color:var(--accent-ink);background:rgba(34,211,238,.1)}
.cap-mark[data-ok="0"] .cap-yes{color:var(--text-3)}
.cap-why{
  margin:9px 0 0;padding-top:9px;
  font-size:11.5px;color:var(--text-3);line-height:1.7;
}

/* ── 统一弹窗（uiConfirm / uiAlert / uiPrompt / 客户资料）─────── */

.modal-veil{
  position:fixed;inset:0;z-index:50;display:grid;place-items:center;padding:22px;
  background:var(--field-bg-3);animation:fade .16s both;
}
.modal-card{
  width:min(440px,100%);max-height:calc(100dvh - 44px);overflow-y:auto;
  padding:22px 24px 18px;
  border:1px solid var(--edge-strong);border-radius:var(--r-panel);
  background:linear-gradient(160deg,var(--panel-f),var(--panel-c));
  box-shadow:0 40px 90px -50px var(--shadow-1);
  animation:msgIn .2s var(--ease) both;
}
.modal-card h2{font-size:15px;margin-bottom:10px}
.modal-body{display:flex;flex-direction:column;gap:6px}
.modal-line{margin:0;font-size:13px;color:var(--text-2);line-height:1.7;overflow-wrap:anywhere}
.modal-input{
  width:100%;margin-top:14px;padding:10px 13px;
  border:1px solid var(--edge);border-radius:var(--r-control);
  background:var(--field-bg);color:var(--text);font:inherit;
}
.modal-input:focus{outline:0;border-color:rgba(34,211,238,.55);box-shadow:0 0 0 3px rgba(34,211,238,.12)}
/* 客户资料那种「表单里的一行输入框」：外面还有 label，不要再叠一层外边距 */
.modal-input.flat{margin-top:0}
.modal-field{display:block;margin:16px 0 0}
.modal-field>span{display:block;margin-bottom:7px;font-size:12px;color:var(--text-2)}
.modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px;flex-wrap:wrap}

/* ── 客户资料卡 ───────────────────────────────────────────────── */
.profile-card{display:flex;flex-direction:column;gap:0}
.profile-hero{display:flex;align-items:center;gap:14px;min-width:0;margin-bottom:16px}
.avatar-lg{width:54px;height:54px}
/* 已选收件人胶囊里那个小头像：比 .avatar-sm(28px) 再小一号，一排里不抢戏 */
.avatar-xs{width:20px;height:20px}
.profile-id{min-width:0}
.profile-name{font-size:15px;font-weight:650;overflow-wrap:anywhere}
.profile-sub{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:5px}
.profile-nick{font-size:11.5px;color:var(--text-3);overflow-wrap:anywhere}
.pf-info{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:1px;
  border:1px solid var(--edge);border-radius:var(--r-control);
  background:var(--edge);overflow:hidden;
}
.pf-item{
  display:flex;flex-direction:column;gap:3px;min-width:0;
  padding:10px 13px;background:var(--panel-a);
}
.pf-k{font-size:11px;color:var(--text-3)}
.pf-v{
  font-size:12.5px;color:var(--text);overflow-wrap:anywhere;
}
.pf-v[data-mono="1"]{font-family:var(--mono);font-size:11.5px;color:var(--text-2)}
.modal-card .card-hint{margin-top:14px}

/* ── 分页控件（客户列表的筛选 / 群发的范围）────────────────────
   隔壁那套叫 .tabs.segmented；我们只需要「一排互斥的小胶囊」，
   所以做得比它更小一号 —— 它是卡片头部的过滤器，不是页面级标签页。 */
.seg{
  display:inline-flex;flex:none;gap:2px;padding:2px;
  border-radius:9px;background:var(--raise-035);
  /* 客户列表的筛选项长到了 5 个（全部/近24小时来过/没备注/有标签/已拉黑）。
     窄屏上换行比横向挤成一坨好读，也不会把卡片头撑破。 */
  flex-wrap:wrap;max-width:100%;
}
.seg-btn{
  padding:5px 11px;border:0;border-radius:7px;cursor:pointer;
  background:none;color:var(--text-3);font-size:11.5px;white-space:nowrap;
  transition:color var(--dur),background var(--dur);
}
.seg-btn:hover{color:var(--text-2)}
.seg-btn.active{color:var(--text);background:rgba(34,211,238,.14)}

/* ── 合并页：顶上的跳转条（沟通记录 / 群发与自动化）─────────────
   ★ 两块在同一页（不做 tab：#vsBody / #callsPager / #bcPickInfo / #autoTabs
     那些契约 id 一个都不用藏起来），这条只是把「另一块」拉进视野 ——
     手机上尤其有用：一页两块，不点就得一路滑到底。 */
.page-jump{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  margin:0 0 16px;
}
.page-jump-note{font-size:11.5px;color:var(--text-3)}
/* 合并页里两块之间的间距（tokens.css 的 .card 自己没有外边距） */
.page-gap{margin-top:18px}
/* ── 客服工作台：会话列表头（搜索 + 刷新）───────────────────── */
/* 这一行比其他 pane-head 高一点：多了一个输入框。
   排成 flex 且上下居中（.pane-head 默认是 baseline，输入框会跟着文字基线跑偏）。 */
.pane-head-chats{flex-wrap:wrap;align-items:center;gap:8px}
.pane-tools{display:flex;align-items:center;gap:6px;margin-left:auto}
.conv-search{
  width:118px;padding:5px 10px;border-radius:8px;
  border:1px solid var(--edge);background:var(--raise-035);color:var(--text);
  font:inherit;font-size:12px;
  transition:width var(--dur),border-color var(--dur),box-shadow var(--dur);
}
.conv-search::placeholder{color:var(--text-3)}
.conv-search:focus{
  outline:0;width:172px;
  border-color:rgba(34,211,238,.5);box-shadow:0 0 0 3px rgba(34,211,238,.1);
}
.pane-icon-btn{display:inline-flex;align-items:center;justify-content:center;padding:6px;line-height:0}
.pane-icon-btn .ico{width:14px;height:14px}

/* ── 客户列表 ─────────────────────────────────────────────── */
.vs-name{display:block;font-size:13px;color:var(--text)}
.vs-sub{display:block;margin-top:2px;font-size:11px;color:var(--text-3)}
.vs-id{
  font-family:var(--mono);font-size:11px;color:var(--text-2);
  overflow-wrap:anywhere;
}
.actions-col{text-align:right}
.dim{color:var(--text-3)}

/* ── 群发消息 ─────────────────────────────────────────────── */
/* 群发：正文第一行的批量勾选条（全选可发 / 选有未读的 / 清空勾选）
   ★ 这三个按钮改的是同一份 state.bcPicked，不是「切换模式」 */
.bc-picks{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 10px}

/* ── 已选收件人（右边）：和左边列表同一份 state 的另一种渲染 ── */
.bc-picked-wrap{margin:0 0 12px}
.bc-picked-head{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:7px}
.bc-picked{display:flex;flex-wrap:wrap;gap:6px;min-height:26px}
.bc-picked-empty{font-size:12px;color:var(--text-3)}
.bc-picked-chip{
  display:inline-flex;align-items:center;gap:6px;max-width:100%;
  padding:3px 4px 3px 6px;border-radius:999px;
  border:1px solid var(--edge);background:rgba(34,211,238,.07);
  font-size:12px;color:var(--text);
}
/* 额度用完的那几位：留在已选里但看得出来，省得商户以为是漏勾了 */
.bc-picked-chip[data-off="1"]{background:var(--raise-03);border-color:var(--edge);opacity:.72}
.bc-picked-chip b{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:8em}
.bc-picked-flag{font-style:normal;font-size:10.5px;color:var(--warn-ink)}
.bc-picked-flag[data-off="0"]{display:none}
.bc-picked-x{
  flex:none;width:17px;height:17px;padding:0;border:0;border-radius:50%;cursor:pointer;
  background:var(--raise-06);color:var(--text-3);font-size:12px;line-height:1;
}
.bc-picked-x:hover{background:rgba(244,114,182,.18);color:var(--danger-ink)}
.bc-grid{
  display:grid;gap:14px;align-items:start;
  grid-template-columns:minmax(0,320px) minmax(0,1fr);
}
.bc-result-card{grid-column:1/-1}
/* 「已选收件人」那一行的小标题（.bc-scope 那个范围选择器的样式已经没人用了，删掉） */
.bc-scope-label{font-size:12px;color:var(--text-3)}
.bc-pills{margin-bottom:10px}

.bc-targets{list-style:none;margin:10px 0 0;padding:0;display:flex;flex-direction:column;gap:2px;max-height:420px;overflow-y:auto}
.bc-target{
  display:flex;align-items:center;gap:8px;
  padding:7px 8px;border-radius:9px;transition:background var(--dur);
}
.bc-target:hover{background:var(--raise-035)}
.bc-target[data-off="1"]{opacity:.5}
.bc-target-main{display:flex;align-items:center;gap:9px;flex:1;min-width:0;cursor:pointer}
.bc-target-main input{flex:none;accent-color:var(--accent-ink);cursor:pointer}
.bc-target-text{display:flex;flex-direction:column;gap:1px;min-width:0}
.bc-target-text b{font-size:12.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bc-target-text i{font-style:normal;font-size:11px;color:var(--text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bc-empty{margin:0;padding:20px 2px;font-size:12.5px;color:var(--text-3)}

.bc-bar{display:flex;align-items:center;gap:10px;margin:12px 0 0}
.bc-bar-track{flex:1;height:4px;border-radius:2px;background:var(--raise-08);overflow:hidden}
.bc-bar-track i{display:block;height:100%;width:0;border-radius:2px;background:var(--cyan);transition:width .18s var(--ease)}
.bc-bar-text{font-size:11.5px;color:var(--text-2);white-space:nowrap}

.bc-result{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1px;max-height:340px;overflow-y:auto}
.bc-line{display:flex;align-items:baseline;gap:10px;padding:7px 9px;border-radius:8px;font-size:12.5px}
.bc-line:nth-child(odd){background:var(--raise-02)}
.bc-line-tone{flex:none;min-width:2.9em;font-size:11px}
.bc-line[data-ok="1"] .bc-line-tone{color:var(--accent-ink)}
.bc-line[data-ok="0"] .bc-line-tone{color:var(--warn-ink)}
.bc-line-name{flex:none;max-width:11em;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bc-line-why{flex:1;min-width:0;color:var(--text-3);overflow-wrap:anywhere}

/* ── 群发历史（跨会话留痕的那一张）─────────────────────────
   和上面的「发送结果」长得很像是有意的：同一件事的两个时间尺度 ——
   上面是这一次，下面是历次。 */
.bc-history-card{grid-column:1/-1}
.bc-history{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px;max-height:320px;overflow-y:auto}
.bc-hist{
  padding:9px 11px;border-radius:9px;
  border:1px solid var(--edge);background:var(--raise-022);
}
/* 发到一半断掉的那条要一眼看得出来 */
.bc-hist[data-running="1"]{border-color:rgba(244,184,96,.42);background:rgba(244,184,96,.06)}
.bc-hist-top{display:flex;align-items:center;gap:9px;margin-bottom:4px}
.bc-hist-time{font-size:11.5px;color:var(--text-2)}
.bc-hist-scope{
  font-size:10.5px;padding:1px 7px;border-radius:999px;
  border:1px solid var(--edge-strong);color:var(--text-3);
}
.bc-hist-stat{flex:none;font-size:11.5px;color:var(--text-2)}
.bc-hist[data-running="1"] .bc-hist-stat{color:var(--warn-ink)}
.bc-hist-text{
  margin:0;font-size:12px;color:var(--text-3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* ── 消息自动化（规则列表 / 战报 / 台账）─────────────────── */
/* 今日战报：四个数字格子。★ 数字大、标签小 —— 扫一眼就知道今天自动回了多少 */
.auto-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:10px;margin-bottom:10px}
.auto-stat{
  display:flex;flex-direction:column;gap:2px;
  padding:11px 13px;border-radius:10px;
  border:1px solid var(--edge);background:var(--raise-022);
}
.auto-stat-num{font-size:21px;font-weight:650;line-height:1.2}
.auto-stat-label{font-size:11px;color:var(--text-3)}
.auto-stat[data-tone="ok"] .auto-stat-num{color:var(--accent-ink)}
.auto-stat[data-tone="warn"] .auto-stat-num{color:var(--warn-ink)}

/* 规则列表 */
.auto-rules{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.auto-rule{
  padding:11px 13px;border-radius:10px;
  border:1px solid var(--edge);background:var(--raise-022);
  transition:border-color var(--dur),background var(--dur);
}
.auto-rule:hover{border-color:var(--edge-strong)}
/* 停用的规则压暗，但仍然看得清内容 —— 它随时可能被重新打开 */
.auto-rule[data-on="0"]{opacity:.62}
.auto-rule-top{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.auto-rule-kw{font-size:13px;font-weight:650}
.auto-rule-match{
  flex:none;padding:1px 8px;border-radius:999px;font-size:10.5px;
  border:1px solid var(--edge-strong);color:var(--text-3);
}
.auto-rule-text{
  margin:6px 0 0;font-size:12.5px;color:var(--text-2);line-height:1.65;
  overflow-wrap:anywhere;
}
.auto-rule-acts{display:flex;gap:6px;margin-top:9px;flex-wrap:wrap}
.auto-rule-empty{margin:0;padding:18px 2px;font-size:12.5px;color:var(--text-3);list-style:none}

/* 台账：一行一条，左侧一个结果词 */
.auto-log{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1px;max-height:340px;overflow-y:auto}
.auto-log-row{
  display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  padding:8px 9px;border-radius:8px;font-size:12.5px;
}
.auto-log-row:nth-child(odd){background:var(--raise-02)}
.auto-log-tone{flex:none;min-width:2.9em;font-size:11px}
.auto-log-row[data-ok="ok"] .auto-log-tone{color:var(--accent-ink)}
.auto-log-row[data-ok="bad"] .auto-log-tone{color:var(--warn-ink)}
.auto-log-row[data-ok="off"] .auto-log-tone{color:var(--text-3)}
.auto-log-kind{flex:none;font-size:11px;color:var(--text-3)}
.auto-log-who{flex:none;font-weight:600;max-width:10em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.auto-log-text{flex:1;min-width:0;color:var(--text-2);overflow-wrap:anywhere}
.auto-log-why{flex:1 1 100%;color:var(--text-3);font-size:11.5px;overflow-wrap:anywhere}

/* ── 二维码与落地页 ─────────────────────────────────── */
/* 两栏：左边二维码本体（样式/尺寸/说明文案），右边落地页（表单 + 实时预览）。
   ★ 为什么是两栏而不是三栏：码和落地页是同一件事的两面（码是入口，落地页是入口后面那一页），
     中间再插一栏预览，手就要来回跳 —— 隔壁 #page-wechat 也是把它们摆在一起、
     改一边另一边立刻变。窄屏变一列（见下面的媒体查询）。 */
.qr-wrap{
  display:grid;gap:14px;align-items:start;
  grid-template-columns:minmax(0,320px) minmax(0,1fr);
}

/* 左栏：码下面那行说明文案（下载时一起印出去） */
.qr-caption{
  margin:12px 0 0;font-size:13px;line-height:1.5;text-align:center;
  color:var(--text-2);max-width:100%;overflow-wrap:anywhere;
}
.qr-caption[data-on="0"]{color:var(--text-3);font-size:12px}

/* 尺寸：一条滑杆 + 当前像素 */
.qr-size-row{display:flex;align-items:center;gap:10px;margin:12px 0 2px}
.qr-size-label{font-size:12px;color:var(--text-2);white-space:nowrap}
.qr-size-row input[type="range"]{flex:1;min-width:0;accent-color:var(--accent-ink);cursor:pointer}
.qr-size-num{font-size:12px;color:var(--text-2);min-width:3.2em;text-align:right}

/* 右栏：表单 + 实时预览并排（同一张卡里，改一个字右边就变） */
.qr-live{display:grid;gap:16px;align-items:start;grid-template-columns:minmax(0,1fr) minmax(0,310px)}
.qr-live-preview{display:flex;flex-direction:column;align-items:center;gap:10px}
.qr-logo-row{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:6px}
/* 右上角那句状态：正在改 / 正在存 / 已保存 / 没存上 */
#qrSaveState[data-tone="ok"]{color:var(--accent-ink)}
#qrSaveState[data-tone="bad"]{color:var(--warn-ink)}
.qr-color-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:12px 0 4px}
.field-inline{display:flex;align-items:center;gap:8px}
.field-inline>span{font-size:12px;color:var(--text-2);white-space:nowrap}
.field-inline input[type="color"]{
  width:34px;height:30px;padding:2px;cursor:pointer;
  border:1px solid var(--edge);border-radius:8px;background:var(--field-bg-4);
}
.field-inline input[type="text"]{
  width:92px;padding:6px 9px;font-size:12px;
  border:1px solid var(--edge);border-radius:8px;
  background:var(--field-bg-3);color:var(--text);
}

/* 手机壳：固定宽高比，里面是真实落地页（iframe，srcdoc 写进去的那一份） */
.qr-phone{
  width:100%;max-width:302px;aspect-ratio:390/720;
  border:1px solid var(--edge-strong);border-radius:22px;overflow:hidden;
  background:#fff;box-shadow:0 26px 60px -40px var(--shadow-1);
}
.qr-phone iframe{width:100%;height:100%;border:0;display:block;background:#fff}

/* 主题选择：几个小卡片，选中的带主题色边 */
.qr-themes{display:flex;gap:8px;flex-wrap:wrap}
.qr-theme{
  display:flex;align-items:center;gap:7px;
  padding:7px 12px;border-radius:9px;cursor:pointer;
  border:1px solid var(--edge);background:var(--raise-028);color:var(--text-2);font-size:12.5px;
  transition:border-color var(--dur),background var(--dur),color var(--dur);
}
.qr-theme:hover{border-color:var(--edge-strong);color:var(--text)}
.qr-theme[data-on="true"]{border-color:rgba(34,211,238,.5);background:rgba(34,211,238,.1);color:var(--text)}
.qr-theme-dot{width:12px;height:12px;border-radius:50%;flex:none}
/* ── 标签 / 拉黑（客户资料卡 + 客户列表）───────────────── */
/* 小胶囊：客户列表里贴在名字旁边，扫一眼就知道这人被标了什么 */
.tag-pill{
  display:inline-block;margin:0 4px 0 0;padding:1px 8px;border-radius:999px;
  font-size:10.5px;line-height:1.75;white-space:nowrap;
  border:1px solid rgba(167,139,250,.36);background:rgba(167,139,250,.12);color:#C4B5FD;
}
.tag-pill.big{font-size:11.5px;padding:2px 9px;margin:0}

/* ── 客户状态（带颜色的小圆点 / 胶囊 / 选择器 / 目录编辑）──────────
   ★ 下面这几处的 background 是**行内**写进去的颜色，值来自租户自己的状态目录；
     服务端在存之前已经校验过只认 #rgb|#rrggbb（api/routes.js sanitizeStatusDir），
     所以这里可以放心当颜色用。 */
.status-dot{display:inline-block;width:7px;height:7px;border-radius:50%;flex:none}
.status-chip{
  display:inline-flex;align-items:center;gap:5px;margin:0 4px 0 0;
  padding:1px 8px 1px 6px;border-radius:999px;font-size:11.5px;line-height:1.75;
  border:1px solid var(--edge-strong);color:var(--text-2);white-space:nowrap;
}

/* 客户资料里的状态选择：一排可点的胶囊，选中那个描边发亮 */
.status-pick{display:flex;flex-wrap:wrap;gap:6px}
.status-pick-btn{
  display:inline-flex;align-items:center;gap:6px;
  padding:4px 11px;border-radius:999px;cursor:pointer;font:inherit;font-size:12px;
  border:1px solid var(--edge-strong);background:none;color:var(--text-2);
  transition:border-color var(--dur),color var(--dur),background var(--dur);
}
.status-pick-btn:hover{color:var(--text)}
.status-pick-btn[data-on="1"]{color:var(--text);border-color:rgba(34,211,238,.55);background:rgba(34,211,238,.1)}
.status-pick-clear{
  padding:4px 9px;border:0;border-radius:999px;cursor:pointer;
  background:none;color:var(--text-3);font:inherit;font-size:11.5px;
}
.status-pick-clear:hover{color:var(--text-2)}

/* 设置页的「客户状态」目录编辑 */
.status-dir{list-style:none;margin:0 0 10px;padding:0;display:flex;flex-direction:column;gap:8px}
.status-dir-row{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.status-dir-name{flex:1;min-width:120px;max-width:220px}
.status-dir-colors{display:flex;gap:5px}
.status-swatch{
  width:18px;height:18px;padding:0;border-radius:50%;cursor:pointer;
  border:2px solid transparent;outline:1px solid var(--edge-strong);outline-offset:1px;
}
.status-swatch[data-on="1"]{border-color:var(--text);outline-color:var(--text)}
.status-dir-empty{margin:0 0 10px;font-size:12.5px;color:var(--text-3)}
/* 胶囊上的 × ：比胶囊本体稍小，但点得到（手机上也够） */
.tag-pill-x{
  margin-left:5px;padding:0 2px;border:0;background:none;cursor:pointer;
  color:inherit;font-size:13px;line-height:1;opacity:.6;
}
.tag-pill-x:hover{opacity:1}

.tag-editor{display:flex;flex-direction:column;gap:9px}
.tag-editor-list{display:flex;flex-wrap:wrap;gap:6px;min-height:22px;align-items:center}
.tag-editor-input{width:100%}

/* 拉黑的客户在列表里压暗 —— 一眼看得出「这些我现在不接」 */
tbody tr[data-off="1"]{opacity:.55}

/* 客户列表里那行「备注 / 标签」的间距 */
td .chip + .tag-pill{margin-left:6px}

/* ── 落地页的操作步骤编辑 ────────────────── */
.qr-steps{list-style:none;margin:0 0 10px;padding:0;display:flex;flex-direction:column;gap:6px}
.qr-step{display:flex;align-items:center;gap:8px}
.qr-step-num{
  flex:none;width:22px;height:22px;border-radius:50%;
  display:grid;place-items:center;font-size:11px;
  background:rgba(34,211,238,.14);color:var(--accent-ink);
}
.qr-step input{
  flex:1;min-width:0;padding:7px 10px;font-size:12.5px;
  border:1px solid var(--edge);border-radius:8px;
  background:var(--field-bg-3);color:var(--text);
}
.qr-step input:focus{outline:0;border-color:rgba(34,211,238,.5)}
.qr-step-empty{margin:0;padding:12px 2px;font-size:12.5px;color:var(--text-3);list-style:none}

/* ── 通知/提示开关在设置页里的一行（比 switch-row 紧凑）─── */
.switch-row + .switch-row{margin-top:2px}

/* 字段标题旁边的小注解（例：用户 ID → 平台发的，不可改）*/ 
.field-hint{margin-left:7px;font-size:11px;color:var(--text-3);font-weight:400}

/* 卡片头右上角的一组按钮。
   ★ 为什么要包一层：.card-header 是 grid（列宽 auto / minmax(0,1fr)），
     直接往里丢两个按钮，第一个占 auto 列、第二个落进那个 1fr 列 → 被拉伸成整行宽。
     包成一格之后整组落在 auto 列里，按内容宽度排。 */
.card-tools{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-self:start}

/* 自动化的三个 tab：快捷回复 / 欢迎语 / 关键词回复。
   ★ 原来是 .auto-grid（两栏并排的欢迎语 + 规则卡），改成 tab 之后不再需要网格 ——
     同一时刻只显示一个面板，挤成两栏反而看不出哪块归哪块。 */
.seg + .auto-panel{margin-top:14px}
.auto-panel{min-width:0}
.auto-note-card{margin-top:14px}
.auto-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.auto-row{
  display:flex;align-items:flex-start;gap:11px;
  padding:11px 12px;border-radius:10px;
  transition:background var(--dur);
}
.auto-row:nth-child(odd){background:var(--raise-02)}
.auto-dot{
  flex:none;width:8px;height:8px;margin-top:6px;border-radius:50%;
  background:var(--text-3);
}
.auto-row[data-on="1"] .auto-dot{background:var(--cyan);box-shadow:0 0 9px rgba(34,211,238,.7)}
.auto-text{display:flex;flex-direction:column;gap:3px;min-width:0}
.auto-text b{font-size:13px;font-weight:600;color:var(--text)}
.auto-row[data-on="0"] .auto-text b{color:var(--text-2)}
.auto-text i{font-style:normal;font-size:11.5px;color:var(--text-3);line-height:1.7}

/* ── 响应式 ───────────────────────────────────────────────────── */
/*  侧栏在 860px 变底部导航（tokens.css 已写好）；这里把两栏聊天
    收成一栏，列表 / 对话二选一 —— 和微信一个手感。 */

@media (max-width:1100px){
  .page-chat .chat-board{grid-template-columns:272px minmax(0,1fr)}
  .stream-wrap{padding:20px}
}

@media (max-width:860px){
  /* ── 手机端「滑不到底」：按实测值修的（2026-09-26）──────────────────
     实测（Playwright 390×844 / isMobile，改之前）：
       · 文档根本不滚：document.scrollingElement 的
         scrollHeight === clientHeight === 844（每一页都是）；
         唯一的滚动容器是 .content（overflow-y:auto，clientHeight 730 / scrollHeight 1644）；
       · 底部导航 .sidebar 是 position:fixed，实测高 65px，
         而 tokens.css 只给 .layout 留了 padding-bottom:58px
         → .content 的下沿（786）落在导航上沿（779）**下面 7px**：
           最后一段内容压在导航底下，滑到头也翻不出来；
       · index.html 的 meta viewport 开了 viewport-fit=cover，
         但全项目没有一处用 env(safe-area-inset-*)：
         手势条 / 小白条那一段（iPhone 上是 34px）根本没人留。
     所以：① 按实测的 65px 留位置（不是 58），② 把手势条那一段一起留出来。
     ★ 这里**不写** height:100vh 兜底：老浏览器不认 dvh 时 height 整条作废，
       .layout 变回自适应高度、文档自己就能滚 —— 那正好是我们要的兜底；
       补一条 vh 反而会把壳层重新钉死，又变成滚不到底。 */
  .layout{padding-bottom:65px;padding-bottom:calc(65px + env(safe-area-inset-bottom,0px))}
  .sidebar{padding-bottom:8px;padding-bottom:calc(8px + env(safe-area-inset-bottom,0px))}
  /* 内容区是唯一的滚动容器：滚到头的橡皮筋别带着整页晃，顺手打开 iOS 惯性滚动 */
  .content{overscroll-behavior-y:contain;-webkit-overflow-scrolling:touch}
  .content{padding:16px 14px 26px}
  .page-chat.active{display:flex}
  .page-chat .chat-board{
    grid-template-columns:minmax(0,1fr);
    border-radius:var(--r-control);
  }
  .page-chat .pane-thread{display:none}
  .page-chat[data-view="thread"] .pane-chats{display:none}
  .page-chat[data-view="thread"] .pane-thread{display:flex}
  .page-chat[data-view="thread"] .back{display:inline-block}
  /* 手机上对话头部：返回 + 头像 + 名字一行，通话按钮紧跟名字 */
  .pane-head{padding:12px 14px;gap:8px}
  .thread-head h2{font-size:14px}
  .thread-call .btn-quiet{padding:4px 9px;font-size:11.5px}

  .stats-grid{grid-template-columns:repeat(auto-fit,minmax(142px,1fr))}
  .rail{grid-template-columns:minmax(0,1fr)}
  .settings-grid{grid-template-columns:minmax(0,1fr);max-width:none}
  .stream-wrap{padding:16px 14px}
  .msg{max-width:90%}
  .composer{padding:12px 14px 14px}
  .emoji-panel{left:14px;bottom:calc(100% - 6px);width:min(392px,calc(100vw - 28px))}
  .emoji-grid{grid-template-columns:repeat(5,minmax(0,1fr))}
  .tools-note{display:none}
  .mini-extra{display:none}
  .topbar-user{display:none}
  .drawer{width:min(420px,100%)}
  .modal-card{padding:20px 18px 16px}

  /* 群发：收件人与内容上下排，而不是左右两栏 */
  .bc-grid{grid-template-columns:minmax(0,1fr)}
  .bc-result-card{grid-column:auto}
  .bc-targets{max-height:300px}
  /* 二维码页：两栏在窄屏上叠成一栏；落地页那张卡里的「表单 + 预览」也竖过来 */
  .qr-wrap{grid-template-columns:minmax(0,1fr)}
  .qr-live{grid-template-columns:minmax(0,1fr)}
  /* 预览在窄屏上排到表单下面，就给一个稳定的高度（aspect-ratio 撑不起来时也不会塌） */
  .qr-phone{width:100%;max-width:300px;height:520px;aspect-ratio:auto}
  /* 自动化页：统计卡从四列折成两列，规则标题不跟开关抢宽度 */
  .auto-stats{grid-template-columns:repeat(2,minmax(0,1fr))}
  .auto-rule{grid-template-columns:minmax(0,1fr) auto}
  .auto-rule-main{grid-column:1/-1}
  /* 底部导航：页面从 8 页长到 9 页（多了「二维码」）之后，tokens.css 那一版
     （min-width:56px + space-around）在 390px 手机上放不下 —— 九个 56px 就是 504px，
     最后两个「通道 / 设置」被挤到屏幕外，看得见点不着。
     tokens.css 是和运营后台共用的，不能改，所以在这里就地收紧并做成明确的横向滚动：
     每条 46px、均匀排列、滚动条藏掉（手机上那一根很丑，能横滑是常识）。 */
  .sidebar-nav{
    justify-content:flex-start;min-width:max-content;
    overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;
  }
  .sidebar-nav::-webkit-scrollbar{display:none}
  .sidebar-nav a{min-width:46px;padding:6px 5px}
  /* 卡片头在窄屏上改回两行：搜索框/筛选器单独占第二行，
     不跟标题抢那点宽度（中文一挤就断行）。 */
  .card-header{grid-template-columns:auto minmax(0,1fr)}
  .card-header .search-input{grid-column:1/-1;width:100%;min-width:0}
  .card-header .seg{grid-column:1/-1;justify-self:center}
  /* 会话搜索框在窄屏上小一号，别把标题挤没 */
  .conv-search{width:96px}
  .conv-search:focus{width:132px}
}

/* 窄屏（手机竖屏）：顶栏那排东西挤不下，按重要性依次让位 ——
   先摘掉页面标题，再摘掉刷新，类型+到期和「实时/轮询」必须留着。 */
@media (max-width:520px){
  /* 顶栏在窄屏上本来就快满了，再加一个席位就会溢出去：
     允许换行，同时把固定高度换成 min-height —— 不然多出来的那一行会被 56px 裁掉。 */
  .topbar{gap:9px;padding:0 10px;flex-wrap:wrap;height:auto;min-height:56px;row-gap:6px}
  .topbar-title{display:none}
  /* 手机上席位只留字：图标和内边距全省下来给数字（完整解释还在 title 里） */
  .seat-chip{padding:0 8px;font-size:10.5px}
  .seat-chip .ico{display:none}
  /* 手机上把席位卡排到第一排最前：这一条是「要动手」的，不该被别的统计卡挤到看不见 */
  .seat-card{order:-1}
  .topbar-user{display:none}
  #refresh{padding:5px 9px;font-size:12px}
  .plan-chip .plan-type{padding:0 8px}
  .plan-chip .plan-exp{padding:0 9px;font-size:10.5px}
  .content{padding:13px 12px 24px}
  .card-header{padding:13px 14px}
  .card-body{padding:14px}
  .emoji-grid{grid-template-columns:repeat(4,minmax(0,1fr))}
  .pf-info{grid-template-columns:minmax(0,1fr)}
  .reply-add #replyTitle{flex:1 1 100%}
  /* 对话头：头像和「资料」文字按钮让位给名字，通话按钮只留图标
     （aria-label 还在，读屏读得出来；名字本身仍然可点开资料） */
  .thread-head .avatar-sm{display:none}
  .thread-head .badge{padding:1px 7px;font-size:10px}
  .head-profile{display:none}
  .thread-call .btn-quiet{padding:4px 7px;font-size:11px}
  .thread-call .call-label{display:none}
}

@media (max-width:400px){
  #refresh{display:none}
  .plan-chip .plan-exp{font-size:10px}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important}
}

/* ── 多 WorkBuddy 账号：名片上的服务账号 ─────────────────────────────
   「当前由「昵称」提供服务」就一行小字，跟在「N 个客户在用」下面。
   没有账号（或者这张名片背后不是 WorkBuddy）时整个节点是 hidden 的，不占位置。 */
.chan-account{
  font-size:11px;color:var(--text-3);margin-top:2px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.chan-account[hidden]{display:none}

/* ── 名片里那块「这个通道能做什么」（第 6 条：默认收起、点一下展开）────
   ★ 名片整张可点（手机上好按），.chan-more 是明面上的那个按钮：
     键盘 Tab 停在它上面、读屏念得出「这个通道能做什么」和展开/收起状态。
   ★ 里面那几行沿用原来那张能力表的 .cap-marks / .cap-mark / .cap-yes
     （见上面「通道能力（只读）」那一段），所以观感是同一套。 */
.chan-more{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  width:100%;margin-top:10px;padding:7px 10px;cursor:pointer;
  border:1px solid var(--edge);border-radius:8px;background:none;
  font-size:11.5px;color:var(--text-2);white-space:nowrap;
  transition:color var(--dur),background var(--dur),border-color var(--dur);
}
.chan-more:hover{color:var(--text);border-color:var(--edge-strong)}
.chan-more[aria-expanded="true"]{color:var(--text);border-color:rgba(34,211,238,.4);background:rgba(34,211,238,.08)}
.chan-more-arrow{flex:none;font-size:11px;color:var(--text-3);transition:transform var(--dur),color var(--dur)}
.chan-more[aria-expanded="true"] .chan-more-arrow{transform:rotate(180deg);color:var(--accent-ink)}
/* 可点的暗示：手型只给名片自己（名字、状态那些字仍然可选） */
.chan-card{cursor:pointer}
/* 展开的面板。默认 hidden —— tokens.css 里有 [hidden]{display:none!important} */
.chan-cap{
  margin-top:10px;padding:11px 12px;border-radius:var(--r-control);
  border:1px solid var(--edge);background:var(--raise-022);
  animation:capIn .18s var(--ease) both;
}
@keyframes capIn{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}
/* 面板第一行就是「可以/不行」那排，不要再顶一段空白 */
.chan-cap .cap-marks{margin:0}
/* 「额度 / 公网 / 状态」：一句「值 + 说明」，和上面那排「可以/不行」区分开 */
.cap-facts{
  list-style:none;margin:10px 0 0;padding:9px 0 0;
  display:flex;flex-direction:column;gap:5px;
  background-image:linear-gradient(90deg,transparent,var(--raise-10) 18%,var(--raise-10) 82%,transparent);
  background-size:100% 1px;background-repeat:no-repeat;
}
.cap-fact{display:flex;align-items:baseline;gap:8px;font-size:11.5px;line-height:1.6}
.cap-fact-k{flex:none;min-width:4.6em;color:var(--text-3)}
.cap-fact-v{min-width:0;color:var(--text-2);overflow-wrap:anywhere}
/* ── 提示音音量那一行（设置 → 店铺与提醒）────────────────────────
   默认开的时候一定要能调：嫌吵的人否则只能整个关掉。
   关掉开关时这一行压暗 —— 它还在（可以先调好再开），但一眼看得出不生效。 */
.vol-row{
  display:flex;align-items:center;gap:10px;
  padding:7px 0 7px 2px;
  transition:opacity var(--dur);
}
.vol-row[data-off="1"]{opacity:.45}
.vol-label{font-size:12.5px;color:var(--text-2);flex:none}
.vol-row input[type="range"]{flex:1;min-width:80px;accent-color:var(--accent-ink);cursor:pointer}
.vol-num{flex:none;font-size:11.5px;color:var(--text-3);min-width:2.2em;text-align:right}

/* ── 顶栏的「声音提醒」按钮（照隔壁 openclaw-web 的 #soundToggleBtn）──
   开着的时候钮身和文字变青 —— 一眼看得出「现在会响」。 */
.sound-btn{display:inline-flex;align-items:center;gap:6px}
.sound-btn .ico{width:15px;height:15px}
.sound-btn[data-on="1"]{color:var(--accent-ink);border-color:rgba(34,211,238,.45);background:rgba(34,211,238,.1)}


/* ── 聊天框上边的「客户状态」下拉（照隔壁 openclaw-web 的 .tag-dd）──────
   按钮上直接显示当前状态名 + 一个颜色点 —— 接待时扫一眼就知道这个客户
   走到哪一步了，不用点开看。 */
.status-dd{position:relative;display:inline-flex}
.status-dd-btn{display:inline-flex;align-items:center;gap:6px}
.status-dd-btn[data-on="1"]{color:var(--text)}
.status-dd-menu{
  position:absolute;top:calc(100% + 6px);right:0;z-index:30;
  min-width:132px;padding:5px;
  border:1px solid var(--edge-strong);border-radius:10px;
  background:var(--ink-800,#171a21);
  box-shadow:0 18px 40px -18px var(--shadow-3);
}
.status-dd-item{
  display:flex;align-items:center;gap:8px;width:100%;
  padding:7px 9px;border:0;border-radius:7px;cursor:pointer;
  background:none;color:var(--text-2);font:inherit;font-size:12.5px;text-align:left;
}
.status-dd-item:hover{background:var(--raise-06);color:var(--text)}
.status-dd-item[data-on="1"]{color:var(--text);background:rgba(34,211,238,.1)}
.status-dd-item.clear{color:var(--text-3);font-size:11.5px;border-top:1px solid var(--edge);border-radius:0 0 7px 7px;margin-top:3px;padding-top:8px}

/* 会话列表里的置顶标记：一个细的针尖图标 + 行本身往前排 */
.conv[data-pinned="1"] .conv-pin{display:inline-block}
.conv-pin{display:none;font-size:10px;opacity:.85;margin-left:4px}
.pane-icon-btn.danger:hover{color:var(--danger-ink);border-color:rgba(244,114,182,.45)}

/* 通话头像那一行：左边预览、右边按钮（设置 → 通话显示） */
.call-avatar-row{display:flex;align-items:center;gap:14px;margin-bottom:14px}
.call-avatar-row .avatar-lg{width:56px;height:56px;font-size:20px}
.call-avatar-acts{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
.call-avatar-acts .card-hint{flex-basis:100%;margin:2px 0 0}

/* 会话行里的客户状态小胶囊（改了状态要在这里看得见） */
.conv-status{
  display:inline-flex;align-items:center;gap:4px;flex:none;
  padding:0 6px;border-radius:999px;font-size:10.5px;line-height:1.6;
  border:1px solid var(--edge-strong);color:var(--text-2);white-space:nowrap;
  max-width:8em;overflow:hidden;text-overflow:ellipsis;
}
/* 对话头部那两个带字按钮 */
.head-action{padding:3px 9px;font-size:11.5px}
.head-action.danger:hover{color:var(--danger-ink);border-color:rgba(244,114,182,.45)}
.head-action[data-on="1"]{color:var(--accent-ink);border-color:rgba(34,211,238,.45);background:rgba(34,211,238,.1)}

/* ============================================================
   浅色模式下的定点覆盖（写死的颜色，见 tokens.css 里同名的说明块）
   —— 这些值原本是给深色底挑的：浅粉色字写在白底上只有 1.5:1，
      浅青色字 1.2:1，全都等于看不见。这里只改颜色，不动尺寸和布局。
   ============================================================ */
[data-theme="light"] .plan-chip[data-state="soon"] .plan-type{color:#7C4A03}
[data-theme="light"] .plan-chip[data-state="off"] .plan-type,
[data-theme="light"] .plan-chip[data-state="off"] .plan-exp{color:#9D174D}
[data-theme="light"] .blocked-chip{color:#9D174D;border-color:rgba(190,24,93,.32);background:rgba(190,24,93,.08)}
[data-theme="light"] .line[data-status="unavailable"] .chan-card{border-top-color:#94A3B8}
[data-theme="light"] .line[data-open="0"] .chan-card{border-top-color:#B6C0CF}
[data-theme="light"] .line[data-open="0"] .chan-flags{color:#475569}
[data-theme="light"] .reason{color:#7F1D3A;border-color:rgba(190,24,93,.24);background:rgba(190,24,93,.05)}
[data-theme="light"] .bound-ok{color:#0E7490;border-color:rgba(14,116,144,.3);background:rgba(14,116,144,.07)}
[data-theme="light"] .tag-pill{color:#5B21B6;border-color:rgba(91,33,182,.32);background:rgba(91,33,182,.09)}

/* ============================================================
   数据面板补充（用户 2026-09-26：「面板的统计不够统计，需补充完善」）
   ============================================================ */

/* ── 近 7 天消息柱 ──────────────────────────────────────────────
   ★ 和运营后台 platform/web/admin.css 里那套**同名、同视觉**（用户要求两个控制台
     看起来是同一个产品）。五个类名逐个对齐：.trend-bars / .trend-col /
     .trend-bar / .trend-n / .trend-d —— 柱高上限 44px、容器 150px、间距 10px
     都一样。改这里的时候记得同步改 admin.css（★ 不许删掉那边那份）。
   ★ 柱子高度是 JS 按「这 7 天最大值」算出来的百分比，容器给固定高度；
     数字在柱子上、日期在下面，一眼看出哪天忙。 */
.trend-bars{display:flex;align-items:flex-end;gap:10px;height:150px;padding:10px 4px 0}
.trend-col{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;gap:4px}
.trend-bar{width:100%;max-width:44px;min-height:2px;border-radius:4px 4px 0 0;
  background:linear-gradient(180deg,var(--accent,#22d3ee),rgba(34,211,238,.35));transition:height .2s}
.trend-n{font-size:11.5px;color:var(--text-2);font-variant-numeric:tabular-nums}
.trend-d{font-size:11px;color:var(--text-3)}

/* 面板下半部分：左趋势、右套餐。窄屏堆成一列（趋势图挤到半宽就没法看了） */
.dash-panel{
  display:grid;grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);
  gap:16px;margin-top:16px;align-items:start;
}
.dash-col{min-width:0}
@media (max-width:1180px){ .dash-panel{grid-template-columns:minmax(0,1fr)} }

/* 套餐卡里的键值行。★ 不用设置页那个 .kv —— 它在宽屏会摊成 4 列，
   塞进这个窄栏会把「商户 ID」这种短值拉成一条长线。这里恒定两列。
   ★ column-gap 不能省：dt 列宽 = 最宽的那个标签（「到期时间」四个字），
     两个字数的标签（「套餐」「账号」）自带空隙，四字的（到期时间/开通时间/
     当前通道/账号状态）就**零间距**粘成一坨 —— 实测截图里就是「到期时间不过期」。 */
.plan-kv{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:baseline;
  column-gap:12px;margin:0;font-size:12.5px}
.plan-kv dt{color:var(--text-3);padding:7px 0;white-space:nowrap}
.plan-kv dd{margin:0;padding:7px 0;font-family:var(--mono);overflow-wrap:anywhere}
.plan-kv dd .chip{margin-left:4px;vertical-align:1px}

/* 手机端专用的「退出登录」卡：桌面端隐藏（侧栏底部那个才是桌面的入口，
   这样两边都只有一个，不会出现「同一件事两个按钮」）。 */
#signOutCard{display:none}
/* 剩余天数单独一行大字：商户最关心的就是这一格 */
.plan-days{
  display:flex;align-items:baseline;gap:8px;
  margin:0 0 12px;padding:12px 14px;border-radius:var(--r-control);
  border:1px solid var(--edge);background:var(--raise-035);
}
.plan-days .n{font-size:26px;font-weight:650;line-height:1;color:var(--accent-ink)}
.plan-days[data-tone="soon"] .n{color:var(--warn-ink)}
.plan-days[data-tone="over"] .n{color:var(--danger-ink)}
.plan-days .u{font-size:12px;color:var(--text-2)}
.plan-days .tip{margin-left:auto;font-size:11.5px;color:var(--text-3)}

/* ============================================================
   设置 → 外观
   ============================================================ */

/* 三个选项：浅色 / 暗色 / 跟随系统。
   ★ 用 button + role=radio，不用 <input type=radio>：和后台那些按钮式选择器
     （.pill / .tgl）同一套做法 —— 好按、键盘能聚焦、状态由 aria-checked 说明。 */
.theme-picker{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(196px,1fr))}
.theme-opt{
  display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;
  gap:3px 10px;padding:12px 14px;cursor:pointer;text-align:left;
  border:1px solid var(--edge);border-radius:var(--r-control);
  background:var(--raise-022);color:var(--text-2);
  transition:border-color var(--dur),background var(--dur),color var(--dur);
}
.theme-opt:hover{border-color:var(--edge-strong);background:var(--raise-045)}
.theme-opt.on{border-color:rgba(34,211,238,.5);background:rgba(34,211,238,.10)}
.theme-swatch{
  grid-row:1 / span 2;width:26px;height:26px;border-radius:8px;
  border:1px solid var(--edge-strong);
}
.theme-swatch[data-kind="light"]{background:linear-gradient(160deg,#FFFFFF,#E4EBF6)}
.theme-swatch[data-kind="dark"]{background:linear-gradient(160deg,#1B2436,#0A0E17)}
.theme-swatch[data-kind="auto"]{background:linear-gradient(160deg,#FFFFFF 0 50%,#0A0E17 50% 100%)}
.theme-opt-name{font-size:13px;font-weight:600;color:var(--text)}
.theme-opt-note{grid-column:2;font-size:11px;color:var(--text-3);line-height:1.5}
#themeHint{margin-top:10px}

/* ══ 手机端可用性（2026-09-27 实测：360 / 390 / 430 三种宽度 × 全部页面）══════
   用真机尺寸 + Playwright 把六个页面整页滚动扫了一遍，量出来三类问题：
     ① 点击区：微信那排媒体按钮 32×32、分段筛选 28px 高、分页按钮 26×27、
        待发「撤回」23×18、通话按钮 31×27 —— 触屏上全是难点（Apple HIG 要 44×44）；
     ② 字号：底栏标签 10.5px、消息时间 10.5px、表头/编号 11px；
     ③ 对话头：9 个控件挤一行，「状态 / 置顶 / 删除」被压成两行、通话按钮顶出屏幕。
   这一节只修「手指够不够得着、眼睛看不看得清」，配色和版式一个字不动；
   桌面（>860px）完全不生效。

   ★ 位置：整块放在**文件最末尾**。第一版插在 prefers-reduced-motion 前面，
     结果被后面几条同优先级的规则盖掉了（.extra / .trend-d / .nav-badge
     在 1725 行还有一份定义）—— 实测审计里它们仍然报 11px。 */
@media (max-width:860px){
  /* ① 触达：可点控件至少 44px 高（Apple HIG），窄按钮至少 44px 宽 */
  /* ★ 只抬高度、不加宽左右内边距：客户表格里一排四个按钮，
     加宽会把表格顶出横向滚动（实测 390px 刚好放下）。 */
  .btn-quiet,.btn-primary,.btn-danger{min-height:44px}
  .thread-head .btn-quiet,.thread-actions .btn-quiet{min-width:44px}
  .mini-btn{width:44px;min-width:44px;height:44px}
  .mini-btn .ico{width:20px;height:20px}
  .seg-btn{min-height:44px;padding:0 13px}
  .quick-btn{min-height:40px;min-width:44px;padding:0 12px}
  .quick-pill{min-height:40px;padding:0 15px}
  .pager button{min-width:44px;min-height:40px;padding:0 11px}
  .pager{gap:6px;padding:10px 6px}
  .link-btn{min-height:40px;min-width:44px}
  .pane-icon-btn{width:44px;min-width:44px;height:40px}
  /* 输入类控件：触屏上点进输入框也要够高（原来 30~39px） */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]),
  select,textarea{min-height:44px}
  /* 手风琴头（「这个通道能做什么」）：整行可点，别只有 34px */
  .chan-more{min-height:44px}
  /* 开关行 / 功能开关：整行是热区（checkbox 只是被样式化的 32×18 小方块） */
  .switch-row{padding:12px}
  .switch-row,.feature-toggle{min-height:44px}
  /* 客户表格里一排四个行内按钮（资料/拉黑/去对话/删除）也要点得准 */
  td.actions .btn-quiet,td.actions .btn-danger{min-height:40px;min-width:44px;padding:0 12px}
  .btn-quiet{min-width:44px}
  /* 收件人胶囊上的「×」：视觉还是 22px，热区靠内边距撑到 38px（负外边距抵消占位） */
  .bc-picked-x{width:22px;height:22px;font-size:13px;line-height:1;position:relative}
  /* ★ 视觉仍是 22px（胶囊不能被撑大），热区靠伪元素外扩到 38px：
     伪元素点到的就是按钮本身，盒模型一个字没动。 */
  .bc-picked-x::after{content:"";position:absolute;inset:-8px}

  /* ② 字号下限：手机上 11.5px 是还能一眼读清的最小值（原来 10~11px） */
  .sidebar-nav a{font-size:11.5px}
  .nav-badge{font-size:11.5px;min-width:17px;height:17px;line-height:17px}
  .thread-head .badge{font-size:11px;padding:2px 8px}
  .msg-meta,.msg-layer{font-size:11.5px}
  th,.vs-id,.chip,.trend-d,.card-hint,.extra,.reply-tag,.auto-stat-label,
  .theme-opt-note,.chan-flags,.pf-k{font-size:11.5px}
  /* ★ tokens.css 里那份是 .stat-card .extra（双类，权重 0,2,0），
     单类压不住 —— 照着它的权重再写一条，否则还是 11px。 */
  .stat-card .extra{font-size:11.5px}
  .conv-time,.conv-pin,.unread{font-size:11.5px}
  /* ★ 顶栏两枚状态胶囊（套餐 / 席位）不跟着放大：它们的宽度是挤出来的，
     放大反而把顶栏顶成两行 —— 颜色本身就是信号，字号保持原样。 */

  /* ③ 对话头：**两行**。
     ★ 第一版只写了 flex-wrap，结果浅色截图里变成四行：
       「返回+名字」/「微信客服」/「状态置顶删除」/「通话按钮」——
       因为 .thread-actions 在 DOM 里排在通话按钮**前面**，basis:100% 一撑就
       把后面的通话按钮挤到了第 4 行，而胶囊自己单独占了一行。
     现在用 order 把通话按钮提到动作组前面，并让名字不再抢剩余宽度
     （放开 flex-grow，剩余宽度留给 .thread-call 的 margin-left:auto）——
     于是稳定两行：返回 名字 …… 📞 🎥 / 状态 置顶 删除。 */
  .thread-head{flex-wrap:wrap;row-gap:8px;padding:10px 12px}
  /* ★ 名字的 flex-basis 压到 60px：flex 排行看的是**假设主尺寸**，
     写 auto 的话名字一次就把第一行占满，通话按钮只能掉到第二行（实测三行）。
     写 60px 之后第一行能容下「返回 / 头像 / 名字 / 通话」，
     名字再靠 flex-grow 把剩下的宽度长回来（约 10 个字，超出省略号）。 */
  .thread-head #peerName{flex:1 1 60px;min-width:0}
  .thread-head > .thread-call{order:1}
  /* ★ 通道胶囊（微信客服）在手机上收掉：它只有「挤得下就留在第一行、
     挤不下就掉到第二行」两种命运 —— 同一个页面在浅色/暗色截图里落点都不一样，
     看着像布局坏了。而它是**恒定信息**（一家商户只有一个通道），
     客户资料卡里也写着，属于可以让位的那一个 —— 让位给客户名字。 */
  .thread-head .badge{display:none}
  .thread-head > .thread-actions{order:2;flex:0 1 auto;margin-left:auto;min-width:0}
  .thread-actions{display:flex;align-items:center;gap:8px}
  .thread-actions .btn-quiet{min-width:44px}
  .thread-call{gap:8px}
  .thread-call .btn-quiet{min-width:44px;padding:0 10px;font-size:15px}

  /* ④ 顶栏：声音只留图标（44×44），一行放得下 */
  .topbar{gap:8px;padding:0 10px}
  #soundBtnText{display:none}
  .sound-btn{width:44px;min-width:44px;padding:0;justify-content:center}

  /* 消息里的「查看原图 / 下载 xxx.png」：实测只有 19px 高，指头点不着。
     它同时是图片/文件的唯一出口，必须给足热区。 */
  .msg-att-link{display:inline-flex;align-items:center;min-height:40px;padding:0 4px}

  /* ⑦ 手机端的退出登录（桌面端侧栏那个在这块布局里是 display:none，点不到） */
  #signOutCard{display:block}
  .signout-body{display:flex;flex-direction:column;gap:8px}
  .signout-btn{width:100%;justify-content:center;gap:8px;min-height:48px;font-size:14px}
  .signout-body .card-hint{text-align:center;margin:0}

  /* ⑤ 客户列表行：手机上把行高收一点，一屏多看一个客户 */
  #vsBody td{padding:9px 10px}
}

/* 更窄（≤400）：连「实时」两个字都放不下 → 只留那颗状态灯，
   「声音已开」已经只剩图标，顶栏这才稳在 56px 一行（实测 360×640 原来两行 112px）。 */
@media (max-width:400px){
  #linkText{display:none}
  .linkstate{padding:0 6px}
}
