/* ============================================================
   仓驭WMS · Utilities 工具类层
   ------------------------------------------------------------
   间距 / 显示 / 文本 / 布局工具类
   ============================================================ */

/* ---------- 显示/隐藏 ---------- */
.hidden{ display:none !important; }
/* 桌面端恢复显示。这里必须用 revert（回退到元素原生显示类型：td/th → table-cell、div → block），
   不能用 initial —— display 的初始值是 inline，会把 <td>/<th> 变成行内盒，
   破坏表格列布局（表头与表体列宽错位、行内单元格按基线对齐而高低不齐）。
   不支持 revert 的旧浏览器会忽略该声明，同样保留原生显示类型。 */
.hide-mobile{ display:revert; }
@media(max-width:860px){ .hide-mobile{ display:none !important; } }

/* ---------- 文本工具 ---------- */
.ta-r{ text-align:right !important; }
.ta-c{ text-align:center !important; }
.mut{ color:var(--text-3); font-weight:400; font-size:.9em; }
.text-brand{ color:var(--brand,#0D9488); }
.link{ color:var(--brand,#0D9488); cursor:pointer; }
.link:hover{ text-decoration:underline; }

/* ---------- 间距工具 ---------- */
.mt-1{ margin-top:4px; }
.mt-2{ margin-top:8px; }
.mt-3{ margin-top:12px; }
.mt-4{ margin-top:16px; }
.mt-5{ margin-top:20px; }
.mt-6{ margin-top:24px; }
.mb-1{ margin-bottom:4px; }
.mb-2{ margin-bottom:8px; }
.mb-3{ margin-bottom:12px; }
.mb-4{ margin-bottom:16px; }
.mb-5{ margin-bottom:20px; }
.mb-6{ margin-bottom:24px; }
.mr-1{ margin-right:4px; }
.mr-2{ margin-right:8px; }
.mr-3{ margin-right:12px; }
.ml-1{ margin-left:4px; }
.ml-2{ margin-left:8px; }
.ml-3{ margin-left:12px; }
.p-2{ padding:8px; }
.p-3{ padding:12px; }
.p-4{ padding:16px; }

/* ---------- Flex 工具 ---------- */
.flex{ display:flex; }
.flex-col{ display:flex; flex-direction:column; }
.flex-1{ flex:1; }
.items-center{ align-items:center; }
.justify-between{ justify-content:space-between; }
.gap-1{ gap:4px; }
.gap-2{ gap:8px; }
.gap-3{ gap:12px; }
.gap-4{ gap:16px; }
.wrap{ flex-wrap:wrap; }

/* ---------- 字号 ---------- */
.fs-xs{ font-size:12px; }
.fs-sm{ font-size:13px; }
.fs-base{ font-size:14px; }
.fs-md{ font-size:16px; }
.fs-lg{ font-size:18px; }
.fs-xl{ font-size:20px; }
.fs-2xl{ font-size:24px; }

/* ---------- 字重 ---------- */
.fw-normal{ font-weight:400; }
.fw-medium{ font-weight:500; }
.fw-semibold{ font-weight:600; }
.fw-bold{ font-weight:700; }

/* ---------- 颜色工具 ---------- */
.text-success{ color:var(--color-success); }
.text-warning{ color:var(--color-warning); }
.text-danger{ color:var(--color-danger); }
.text-info{ color:var(--color-info); }
.text-muted{ color:var(--text-3); }

/* ---------- 背景工具 ---------- */
.bg-surface{ background:var(--surface); }
.bg-surface-2{ background:var(--surface-2); }
.bg-hover{ background:var(--hover); }

/* ---------- 响应式隐藏 ---------- */
@media(max-width:860px){
  /* 同上：必须用 revert 而非 initial（该类当前未被使用，一并修正以免将来启用时踩同一坑） */
  .hide-desktop{ display:revert !important; }
}
@media(min-width:861px){
  .hide-desktop{ display:none !important; }
}

/* ==== v8 CSS 归并补遗：缺失类迁移（自动提取+去重+令牌映射） ==== */
.grid { display:grid; gap:16px }
.text-warn, .warn { color:#d97706 }
.sidebar.collapsed { width:64px }

/* ============================================================
   cy260931 · 体系收口层（最后加载，统一跨组件不一致）
   ------------------------------------------------------------
   目的：把各历史层里"各写各的"控件尺寸/圆角/焦点/表格密度/卡片内距
        统一到同一套令牌，消除"同一界面两种规格"的观感割裂。
   原则：只做归一，不改变布局语义；优先级低于更具体的业务选择器。
   ============================================================ */

/* U1) 计数徽标统一可读 */
.nav-badge,.notif-dot,.unread-dot,.badge-count,.chat-badge,.task-badge,.msg-badge,.seg-badge,
  background:var(--badge-bg) !important;
  color:var(--badge-text) !important;
  font-weight:var(--font-weight-bold);
  font-variant-numeric:tabular-nums;
  letter-spacing:0;
  border-radius:var(--radius-full) !important;
}
.unread-dot{ min-width:7px; min-height:7px; }

/* U2) 表单控件统一高度 / 圆角 / 过渡 / 焦点 */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
select,textarea,.ipt,.input{
  min-height:var(--ctl-h-md);
  border-radius:var(--radius-md);
  font-size:var(--font-size-base);
  transition:var(--t-colors);
}
select{ padding-right:var(--space-6); }
textarea{ min-height:calc(var(--ctl-h-md) * 2); padding:var(--space-2) var(--space-2h); line-height:var(--lh-base); }
input[type="checkbox"],input[type="radio"]{ accent-color:var(--color-primary); width:15px; height:15px; cursor:pointer; }
input[type="checkbox"]:focus-visible,input[type="radio"]:focus-visible{ outline:2px solid var(--color-focus-ring-color); outline-offset:1px; }

/* U3) 按钮尺寸与三态统一（.btn 家族共用一套高度与过渡） */
.btn{ border-radius:var(--radius-md); font-weight:var(--font-weight-medium); transition:var(--t-colors),transform var(--duration-instant) var(--ease-standard); }
.btn:active:not(:disabled){ transform:translateY(1px); }
.btn:disabled{ opacity:var(--state-disabled-opacity); cursor:not-allowed; transform:none; }
.btn:not(.btn-sm):not(.btn-xs):not(.btn-lg){ min-height:var(--ctl-h-md); }
.btn-sm{ min-height:var(--ctl-h-sm); border-radius:var(--radius-sm); }
.btn-lg{ min-height:var(--ctl-h-lg); }
.icon-btn{ width:var(--ctl-h-sm); height:var(--ctl-h-sm); min-width:var(--ctl-h-sm); display:inline-flex; align-items:center; justify-content:center; border-radius:var(--radius-sm); transition:var(--t-colors); }
.icon-btn:hover{ background:var(--state-hover); }
.glass-btn{ border-radius:var(--radius-sm); transition:var(--t-colors); }

/* U4) 表格统一密度与状态（WMS 的主战场） */
.table-wrap table > thead > tr > th{
  background:var(--table-head-bg);
  color:var(--table-head-text);
  font-weight:var(--font-weight-semibold);
  font-size:var(--font-size-xs);
  letter-spacing:var(--ls-wide);
  padding:var(--space-2h) var(--table-cell-px);
  border-bottom:1px solid var(--table-border);
  white-space:nowrap;
}
.table-wrap table > tbody > tr > td{
  padding:var(--table-cell-py) var(--table-cell-px);
  border-bottom:1px solid var(--table-border);
  color:var(--color-text-primary);
  font-size:var(--font-size-sm);
  vertical-align:middle;
}
.table-wrap table > tbody > tr:last-child > td{ border-bottom:none; }
.table-wrap table > tbody > tr:hover > td{ background:var(--table-row-hover); }
.table-wrap table > tbody > tr.row-sel > td,.table-wrap table > tbody > tr.selected > td{ background:var(--table-row-selected); }
.table-wrap{ border-radius:var(--radius-card); overflow:auto; }
.table-wrap table{ width:100%; }

/* U5) 卡片内距与标题区统一 */
.card{ border-radius:var(--radius-card); }
.card > .card-h{ padding:var(--space-3h) var(--card-pad); border-bottom:1px solid var(--color-border-light); display:flex; align-items:center; gap:var(--space-2h); }
.card > .card-b,.card > .card-body{ padding:var(--card-pad); }

/* U6) 分段控件 / 页签统一 */
.seg{ display:inline-flex; gap:var(--space-1); padding:var(--space-1); background:var(--color-surface-2); border-radius:var(--radius-md); }
.seg > button{ border-radius:var(--radius-sm); padding:var(--space-1h) var(--space-3); font-size:var(--font-size-sm); color:var(--color-text-secondary); transition:var(--t-colors); }
.seg > button.on,.seg > button.active{ background:var(--color-surface); color:var(--color-primary); box-shadow:var(--elev-1); }

/* U7) 工具条 / 分页 基线对齐 */
.toolbar{ display:flex; align-items:center; gap:var(--space-2); flex-wrap:wrap; }
.toolbar .spacer{ flex:1; }

/* U8) 焦点可见性统一（键盘导航） */
a:focus-visible,button:focus-visible,[role="button"]:focus-visible,.nav-item:focus-visible,.set-tab:focus-visible,.seg > button:focus-visible{
  outline:2px solid var(--color-focus-ring-color); outline-offset:2px;
}

/* U9) 文字层级语义类（统一次要/说明文字观感） */
.muted,.text-muted,.set-hint,.page-sub,.sub,.hint{ color:var(--color-text-muted); }
.set-hint,.hint,.page-sub{ font-size:var(--font-size-xs); line-height:var(--lh-snug); }
.danger-text{ color:var(--color-danger-text); }
.success-text{ color:var(--color-success-text); }
.warning-text{ color:var(--color-warning-text); }

/* U10) 深色下统一"面板边缘提亮"，避免大面积纯黑 */
[data-theme="dark"] .table-wrap,[data-theme="dark"] .card,[data-theme="dark"] .modal{
  box-shadow:var(--elev-1),inset 0 1px 0 rgba(255,255,255,.035);
}

/* U11) 空态与加载态统一留白 */
.empty{ padding:var(--space-10) var(--space-4); text-align:center; color:var(--color-text-muted); font-size:var(--font-size-sm); }

/* U12) 语义标签：前景必须用 -text 深档，保证 ≥4.5:1（历史层误用饱和基色导致 2.5:1） */
.tags.tag-confirmed,.tag-confirmed{ background:var(--color-success-bg) !important; color:var(--color-success-text) !important; }
.tags.tag-pending,.tag-pending{ background:var(--color-warning-bg) !important; color:var(--color-warning-text) !important; }
.tags.tag-cancelled,.tag-cancelled{ background:var(--color-danger-bg) !important; color:var(--color-danger-text) !important; }
.tags.tag-admin,.tag-admin{ background:var(--color-info-bg) !important; color:var(--color-info-text) !important; }
.tags.tag-user,.tag-user{ background:var(--color-surface-3) !important; color:var(--color-text-secondary) !important; }
.tags.tag-high,.tag-high{ background:var(--color-danger-bg) !important; color:var(--color-danger-text) !important; }
.tags.tag-med,.tag-med{ background:var(--color-warning-bg) !important; color:var(--color-warning-text) !important; }
.tags.tag-low,.tags.tag-info,.tag-low{ background:var(--color-info-bg) !important; color:var(--color-info-text) !important; }
.tag.ok,.tag.success{ background:var(--color-success-bg) !important; color:var(--color-success-text) !important; }
.tag.warn,.tag.warning{ background:var(--color-warning-bg) !important; color:var(--color-warning-text) !important; }
.tag.danger,.tag.error{ background:var(--color-danger-bg) !important; color:var(--color-danger-text) !important; }
.tag.info{ background:var(--color-info-bg) !important; color:var(--color-info-text) !important; }

/* U13) 财务状态徽标同规则（组件内联色 → 语义深档） */
.fin-badge{ font-weight:var(--font-weight-semibold); }

/* U14) 区域图/日历等"彩色底上的小标签"：改为可读的前景 + 半透明底 */
.zb-type{ color:var(--color-success-text) !important; background:color-mix(in srgb,var(--color-surface) 82%,transparent) !important; }
.ms-pct,.cal-num,.cal-wd{ color:var(--color-text-secondary) !important; }

/* U15) 公告标签：语义前景用深档 */
.ann-tag{ background:var(--color-info-bg) !important; color:var(--color-info-text) !important; }
.ann-bar.is-important .ann-tag,.ann-bar.is-warning .ann-tag{ background:var(--color-warning-bg) !important; color:var(--color-warning-text) !important; }
.ann-bar.is-important::before{ background:var(--color-warning); }

/* U16) 激活态页签/分段：彩色浅底上用深档主色，保证 ≥4.5:1 */
.seg > button.on,.seg > button.active,
.fin-tabs button.on,.fin-tabs button.active,
.set-tab.on,.set-tab.active,
.nav-item.active{ color:var(--color-primary-strong) !important; }
.nav-item.active .ni-txt{ color:var(--color-primary-strong) !important; }

/* U17) 彩色底（区域色/日历/进度条）上的文字：统一使用最高对比前景，避免与底色同色 */
.ms-pct,.zb-type,.cal-num,.cal-wd,.zb-name,.zone-box{ }
.ms-pct,.zb-type,.cal-num,.cal-wd{ color:var(--color-text-primary) !important; }

/* ============================================================
   U18) 高特异性收口（对手是 body[data-perf="1"] 这一历史重复层）
   ------------------------------------------------------------
   data-perf 恒为 1，该层用 (0,3,2) 特异性 + !important 重复定义了整套设计，
   导致低特异性的收口规则无法生效。此处以同等特异性 + 后置顺序覆盖。
   ============================================================ */
/* 激活态页签/分段：彩色浅底上用深档主色（≥4.5:1） */
body[data-perf="1"] .seg button.on,
body[data-perf="1"] .seg > button.on,
body[data-perf="1"] .seg button.active,
body[data-perf="1"] .perf-seg button.on,
body[data-perf="1"] .fin-tabs button.on,
body[data-perf="1"] .fin-tabs button.active,
body[data-perf="1"] .set-tab.on,
body[data-perf="1"] .set-tab.active,
body[data-perf="1"] .nav-item.active,
body[data-perf="1"] .nav-item.active .ni-txt{
  color:var(--color-primary-strong) !important;
}

/* 彩色货位/日历/进度条上的文字：改为不透明底片，无论底色调如何都可读 */
body[data-perf="1"] .ms-pct,
body[data-perf="1"] .zb-type,
body[data-perf="1"] .cal-num,
body[data-perf="1"] .cal-wd{
  color:var(--color-text-primary) !important;
  background:var(--color-surface) !important;
  border-radius:var(--radius-sm);
  padding:0 var(--space-1);
}

/* 语义标签在 perf 层的兜底（同特异性覆盖） */
body[data-perf="1"] .tags.tag-confirmed,
body[data-perf="1"] .tag-confirmed{ background:var(--color-success-bg) !important; color:var(--color-success-text) !important; }
body[data-perf="1"] .tags.tag-pending,
body[data-perf="1"] .tag-pending{ background:var(--color-warning-bg) !important; color:var(--color-warning-text) !important; }
body[data-perf="1"] .tags.tag-cancelled,
body[data-perf="1"] .tag-cancelled{ background:var(--color-danger-bg) !important; color:var(--color-danger-text) !important; }
body[data-perf="1"] .tags.tag-admin,
body[data-perf="1"] .tag-admin{ background:var(--color-info-bg) !important; color:var(--color-info-text) !important; }
body[data-perf="1"] .ann-tag{ background:var(--color-info-bg) !important; color:var(--color-info-text) !important; }
.share-tag{ color:var(--color-text-secondary) !important; }

/* U19) 公告/共享标签：文字改用最高对比前景（保持语义底色） */
body[data-perf="1"] .ann-tag{ color:var(--color-text-primary) !important; }
.share-tag{ color:var(--color-text-primary) !important; background:var(--color-surface-3) !important; }

/* ============================================================
   U20) 渲染性能：长列表与大量重复块的渲染隔离
   ------------------------------------------------------------
   content-visibility:auto 让浏览器跳过视口外内容的布局与绘制，
   对"几百行的表格/上千个权限格子"这类页面收益最大；
   不支持该属性的浏览器会忽略，无副作用。
   ============================================================ */
.table-wrap tbody tr{ content-visibility:auto; contain-intrinsic-size:auto 42px; }
.pm-row,.pm-group,.member-card,.list-item,.task-item,.notif-item{ content-visibility:auto; contain-intrinsic-size:auto 56px; }
/* 长表格滚动容器：限制重排范围 */
.table-wrap{ contain:paint style; }
/* 命中高亮/搜索的临时元素不做隔离，避免刚渲染时测量错误 */
.row-sel,.expanded{ content-visibility:visible; }

/* U21) 长表格「显示全部」行 */
.cy-more-row > td{ background:var(--color-surface-2); }
.cy-more-wrap{ display:flex; align-items:center; justify-content:center; gap:var(--space-3); padding:var(--space-2) 0; }

/* ============================================================
   U22–U27 · 用户反馈缺陷的根因修复（cy260936）
   ============================================================ */

/* U22) 弹窗宽度阶梯 —— JS 用的是 .wide / .xl / .size-560|720|900，
   而 CSS 里只有 .modal-lg|xl|xxl（类名不匹配）→「弹窗一直很窄、表单被挤扁」。 */
.modal{ width:min(94vw,560px); }
.modal.wide{ width:min(94vw,780px); }
.modal.xl,.modal.wide.xl{ width:min(96vw,1060px); }
.modal.size-560{ width:min(94vw,560px)!important; }
.modal.size-720{ width:min(94vw,720px)!important; }
.modal.size-900{ width:min(96vw,900px)!important; }
/* 弹窗内表单行允许换行：窄弹窗下多列不再互相挤扁，长字段自动整行 */
.modal-body .form-row{ display:flex; flex-wrap:wrap; gap:var(--space-3) var(--space-4); align-items:flex-end; }
.modal-body .form-row > .fld{ min-width:200px; }

/* U23) 系统设置页签美化 —— 原样式位于未加载的 v328.css，随分层加载丢失（与 .pf-badge 同类） */
.set-tabs{
  display:flex; gap:var(--space-1h); padding:var(--space-1h);
  background:var(--color-surface-2); border:1px solid var(--color-border-light);
  border-radius:var(--radius-lg); margin-bottom:var(--space-4);
  overflow-x:auto; position:sticky; top:8px; z-index:var(--z-sticky);
}
.set-tabs::-webkit-scrollbar{ display:none }
.set-tab{
  flex:0 0 auto; border:1px solid transparent; background:transparent; color:var(--color-text-secondary);
  padding:9px 16px; border-radius:var(--radius-md); font-size:var(--font-size-sm);
  font-weight:var(--font-weight-semibold); cursor:pointer; white-space:nowrap; transition:var(--t-colors);
}
.set-tab:hover{ background:var(--state-hover); color:var(--color-text-primary); }
body[data-perf="1"] .set-tab.on,
body[data-perf="1"] .set-tab.active{
  background:var(--color-surface)!important; color:var(--color-primary-strong)!important;
  border-color:var(--color-border-light); box-shadow:var(--elev-1);
}

/* U24) 缩略图固定方形 —— base.css 的 img{max-width:100%} 会在窄单元格里把 42×42 钳成 24×42（长方形） */
.p-thumb,.thumb,.p-noimg{ max-width:none!important; }
.p-thumb{ width:40px; height:40px; }
.cell-imgs .p-thumb{ width:44px; height:44px; }

/* U25) 表格列宽下限：表头文字撑住最小宽度，列不再被压到 0；超出由容器横向滚动 */
.table-wrap table thead th{ min-width:max-content; }
.table-wrap table thead th[style*="width"]{ min-width:0; }
.table-wrap table tbody td{ max-width:none; }

/* U26) 侧栏收起态：68px 宽装不下 34px logo + 26px 按钮 → 按钮溢出被裁，导致「收起后无法展开」 */
body[data-perf="1"] .sidebar.collapsed .brand,
.sidebar.collapsed .brand{ flex-direction:column; align-items:center; gap:var(--space-1h); padding:var(--space-3) 0 var(--space-2); }
body[data-perf="1"] .sidebar.collapsed .brand .side-collapse,
.sidebar.collapsed .brand .side-collapse{ margin-left:0; }
@media (max-width:860px){
  /* 窄屏侧栏是抽屉：始终全宽，不套用收起态（否则从 localStorage 还原出收起态后无法展开）。
     断点与 JS 及移动端抽屉/hide-mobile 统一为 860：原为 900，而 @media(min-width:861px) 的
     .sidebar.collapsed{width:64px} 在 861~900px 与之重叠，实测该区间点汉堡按钮加了 .collapsed
     宽度仍不变（既不抽屉也不收起）——861~900px 死区即由此而来。 */
  .sidebar.collapsed{ width:var(--sidebar-w); min-width:var(--sidebar-w); }
  .sidebar.collapsed .ni-txt{ display:inline; }
  .sidebar.collapsed .brand-txt{ display:flex; }
  .sidebar.collapsed .nav-group{ display:block; }
  .sidebar.collapsed .nav-item{ justify-content:flex-start; padding:var(--space-2h) var(--space-3); }
  .sidebar.collapsed .brand{ flex-direction:row; align-items:center; padding:var(--space-3h) var(--space-3h) var(--space-3); }
  .sidebar.collapsed .brand .side-collapse{ margin-left:auto; }
}

/* U27) 「可粘贴图片」提示：默认隐藏（hover/聚焦才显示）并移到右上角，
   避免常驻遮挡图片与计数（原 ::after 无 opacity:0，一直可见） */
.paste-able::after{ opacity:0; transform:scale(.96); pointer-events:none; top:var(--space-1); right:var(--space-1); bottom:auto;
  transition:opacity var(--duration-fast) var(--ease-standard),transform var(--duration-fast) var(--ease-standard); }
.paste-able:hover::after,.paste-able:focus-within::after{ opacity:1; transform:none; }
.paste-able:has(img)::after{ display:none; }

/* ============================================================
   U28–U30 · 结构性错位的根因修复（cy260936）
   ------------------------------------------------------------
   共同病因：布局写死了「列数」，而业务数据后来增加了列/子元素，
   多出来的元素落进「隐式列」被压扁，或被裁掉。
   解法统一为「结构自适应」，不再依赖写死的列数。
   ============================================================ */

/* U28) 到货明细行：模板只定义了 7 列，实际有 9 个子元素
   →「采购单号 / 备注」落入隐式列被压成 34px / 38px。
   宽弹窗按 9 列给足最小宽度；窄弹窗改为弹性换行，任一项都不再被压扁。 */
.item-grid{
  display:grid; gap:var(--space-2); align-items:center;
  grid-template-columns:48px minmax(110px,1.05fr) minmax(130px,1.35fr) minmax(96px,.9fr) 84px 84px minmax(118px,1fr) minmax(130px,1.2fr) 32px;
}
.item-grid > .ar-prod-img,.item-grid > .ar-prod-ph{ width:48px; height:48px; }
@media (max-width:1100px){
  .item-grid{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-2); }
  .item-grid > .ar-prod-img,.item-grid > .ar-prod-ph{ flex:0 0 44px; width:44px; height:44px; }
  .item-grid > input{ flex:1 1 140px; min-width:118px; }
  .item-grid > input[data-f="pieces"],.item-grid > input[data-f="spec_qty"]{ flex:0 1 96px; min-width:78px; }
  .item-grid > .icon-btn{ flex:0 0 auto; margin-left:auto; }
}

/* U29) 权限矩阵：行写死 repeat(6,1fr)，而权限列已增至 20+ → 其余列错位/挤压。
   改为弹性行：模块名列固定，操作列等分，列数随数据自适应。 */
.pm-head-row,.pm-row{ display:flex; align-items:center; }
.pm-head-row > .pm-mod,.pm-row > .pm-mod{ flex:0 0 130px; }
.pm-head-row > .pm-act,.pm-row > .pm-act{ flex:1 1 0; min-width:40px; overflow:hidden; }
.pm-head-row > .pm-na,.pm-row > .pm-na{ flex:1 1 0; min-width:40px; }
/* 权限矩阵容器：列多时允许横向滚动，不被压缩 */
.perm-matrix,.pm-table{ overflow-x:auto; }
.pm-table{ min-width:max-content; }

/* U30) 商品图片列：给缩略图留出足够内距，避免 40px 图被 16px 内距挤出列宽 */
.table-wrap table td:has(> .p-thumb),.table-wrap table th:first-of-type + th{ padding-left:var(--space-2h); padding-right:var(--space-2h); }

/* ============================================================
   U31–U33 · 结构性隐患清理（cy260937）
   ------------------------------------------------------------
   由「子元素数 > 定义列数」的运行时扫描发现。
   【确认非缺陷、保持原样】zb-shelf（货架 8 列 × 多层）、cal-grid（日历 7 列 × 5 周）——
     它们本就按多行排布，属设计意图。
   ============================================================ */

/* U31) 到货明细「区域/库位」行：定义了 3 列却有 4 个子元素
   （库位标签、手输库位、总数、货品照片）→ 总数与照片按钮被挤到第二行，
   正是「遮挡总数/遮挡图片」观感的来源。改为弹性单行 + 空间不足时优雅换行。 */
.item-zone{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-2); }
.item-zone > .slot-chips{ flex:1 1 240px; min-width:0; }
.item-zone > .it-zone{ flex:1 1 200px; min-width:150px; }
.item-zone > .it-sum{ flex:0 0 auto; white-space:nowrap; }
.item-zone > .item-photo-btn{ flex:0 0 auto; }

/* U32) 列设置弹窗：每组写死 3 列，而分组内列数不等（1~8）→ 多余项换行错位。
   改为自适应填充，列数随弹窗宽度与条目数自动排布。 */
.pc-colgrid{ grid-template-columns:repeat(auto-fit,minmax(118px,1fr)) !important; }

/* U33) 表单栅格：两列布局下「落单」的最后一个字段自动占满整行，避免半行留白 */
.form-grid > *:last-child:nth-child(odd){ grid-column:1/-1; }

/* U34) 分页「每页条数」行（库存流水 / 供应商 服务端分页） */
.pager-ps-row{ display:flex; justify-content:flex-end; padding:var(--space-2) 0 var(--space-1); }

/* ============================================================
   U35) 浅色对比收尾（cy260939）：把最后一批准语义色前景改为可读档
   ============================================================ */
/* 对讲「同频在线」计数：原用饱和成功色（白底 2.54:1） */
.ic-on{ color:var(--color-success-text) !important; }
/* 公告标签（重要/警告）：琥珀浅底上用深档会导致 4.0，改用最高对比前景 */
body[data-perf="1"] .ann-bar.is-important .ann-tag,
body[data-perf="1"] .ann-bar.is-warning .ann-tag{ color:var(--color-text-primary) !important; }
/* 头像兜底底色：渐变缺失时白色首字不会落在白底上 */
.conv-ava{ background-color:var(--color-primary); }
.member-avatar{ background-color:var(--color-primary); }
.av-ph{ background-color:hsl(var(--avh,210) 62% 40%); }

/* U36) 会话头像：原为「亮青渐变 + 白字」，浅色 3.74、深色仅 1.86（白字压在亮青上必然不达标）。
   身份类元素不随主题变色，改为深青渐变保证白字 ≥5:1；有真实头像时保持透明（不额外加底）。 */
.conv-ava:not(:has(.conv-ava-img)){ background-image:linear-gradient(135deg,#0F766E,#115E59); background-color:#115E59; color:#fff; }

/* ============================================================
   cy260944 聊天页「仿微信」收口层
   ------------------------------------------------------------
   为什么放这里：DESIGN.md §7.5 —— 新样式一律追加到收口层（最后加载），不改历史层。
   气泡配色的特异性陷阱（DESIGN.md §7.4）：历史层有
     body[data-perf="1"][data-theme="light"] .msg-bubble:not(.msg-bare){ background:#ffffff!important }
   特异性 (0,4,1) + !important。所以下面的覆盖必须用 (0,5,1) 级选择器
   （body[data-perf="1"][data-theme=…] .msg-row.mine|other .msg-bubble）并带 !important，
   低特异性写法会静默失效。
   ============================================================ */

/* ---------- 聊天区底色：会话栏白、聊天区浅灰（微信层次） ---------- */
.msg-stream{ background:var(--bg); padding:var(--space-3) var(--space-4); }

/* ---------- 会话列表项：选中态改扁平浅灰，不用渐变 ---------- */
.conv-item{ border-bottom:1px solid var(--line); }
.conv-item.active{ background:var(--hover); }
.conv-ava{ border-radius:var(--radius-md); overflow:hidden; }

/* ---------- 头像：仅聊天页用圆角方形（微信特征），全站头像组件不动 ---------- */
.msg-ava{ border-radius:var(--radius-md); }
.msg-ava .avatar{ border-radius:var(--radius-md) !important; }

/* ---------- 补齐历史层缺失的 flex 声明（既有缺陷，非本次改造引入） ----------
   pages.css:739/740/829/830/833 给 .msg-line / .msg-bubble-wrap 写了 gap 与 flex-direction，
   并给子项写了 flex:0 0 auto，却**从未声明 display:flex** —— 于是 .msg-line 只是个普通 div，
   其中的 <span class="msg-ava"> 是行内盒、后面跟块级的 .msg-col，浏览器把行内盒单独成行，
   表现为「头像被挤到气泡上方」、气泡宽度被压窄。这里补上缺失的 flex 语义。 */
.msg-line{ display:flex; align-items:flex-start; gap:var(--space-2); }
.msg-bubble-wrap{ display:flex; align-items:flex-start; gap:var(--space-2); }

/* ---------- 聊天页纵向布局：让消息流真正滚动、输入区固定在底部 ----------
   真因（用户反馈「聊天框不见了 / 聊天工具栏不见了」，也是本轮重做的首要问题）：
   历史层给 .chat-pane 只写了 min-height:0（pages.css:591/834）—— 那是 flex 属性 ——
   却**从未声明 display:flex**，于是 .chat-pane 只是普通块级 div：
     · 其子元素 .msg-stream 的 flex:1「完全失效」（父元素不是 flex 容器）
     · .msg-stream 的 overflow-y:auto 没有高度约束，于是按内容高度撑开
   实测 52 条消息把消息流撑到 5500px，整块 .chat-compose（聊天框 + 表情/商品/文件/按住说话 工具栏）
   被顶到视口下方约 5 屏之外，既看不见也滚不到（#content 自身并不滚动）。
   这与上面 .msg-line 的问题、以及 DESIGN.md §3.2 是同一类：只写了 flex 属性，没写 display:flex。

   注意「撑爆」与「塌陷」是两个极端，根因同一个：**.chat-pane 没有确定高度**。
     · 只把 .chat-pane 设为 flex 列（不设 flex:1）→ 它仍是内容高度，消息流被撑爆（5500px）
     · 再把消息流设成 flex:1 1 0 / min-height:0 → 没有可分配空间，消息流直接塌成 0 高
       （表现为输入区跑到顶部、消息看不见 —— 这个中间态我实测踩过）
   所以三件事必须同时成立：.chat-pane 填满父列(flex:1) + 成为 flex 列 + 消息流可增长且可收缩。 */
.chat-pane{ flex:1 1 0; min-height:0; display:flex; flex-direction:column; }
.msg-stream{ flex:1 1 0; min-height:0; overflow-y:auto; }

/* ---------- 表情面板：补齐「默认隐藏、.show 才显示」+ 定位参照 ----------
   历史层只在**未被加载**的 v316.css 里写了这套规则：
     .chat-toolbar{ position:relative; ... }
     .emoji-panel{ position:absolute; left:0; bottom:46px; width:344px; height:308px; …
                   opacity:0; visibility:hidden; … pointer-events:none }
     .emoji-panel.show{ opacity:1; visibility:visible; transform:none; pointer-events:auto }
   而 components.css 的 .emoji-panel 只设了 display:flex、**没有任何隐藏约束**，.chat-toolbar 也丢了
   position:relative。结果：表情面板**一直显示**并遮住输入区与工具栏（用户反馈的「显示错乱」之一）。
   属 CSS 合并丢失，非本次改造引入。数值沿用 v316 原值，颜色与圆角走令牌。 */
.chat-toolbar{ position:relative; }
.emoji-panel{
  position:absolute; left:0; bottom:46px; width:344px; max-width:88vw; height:308px;
  display:flex; flex-direction:column; flex-wrap:nowrap;
  padding:0; border-radius:var(--radius-lg); overflow:hidden; z-index:60;
  opacity:0; visibility:hidden; transform:translateY(10px) scale(.97); transform-origin:bottom left;
  transition:opacity .18s ease, transform .22s cubic-bezier(.2,1.2,.3,1), visibility .18s;
  pointer-events:none;
}
.emoji-panel.show{ opacity:1; visibility:visible; transform:none; pointer-events:auto; }

/* ---------- 气泡基础：小圆角、可定位尖角 ---------- */
.msg-bubble{
  position:relative;
  border-radius:var(--radius-md);
  padding:var(--space-2) var(--space-3);
}
body[data-perf="1"] .msg-row .msg-bubble{
  -webkit-backdrop-filter:none !important; backdrop-filter:none !important;
}

/* ---------- 气泡配色：我方 --accent / 对方 --surface（浅色） ---------- */
body[data-perf="1"][data-theme="light"] .msg-row.other .msg-bubble:not(.msg-bare){
  background:var(--surface) !important; border:1px solid var(--line) !important; color:var(--text-1) !important;
}
body[data-perf="1"][data-theme="light"] .msg-row.mine .msg-bubble:not(.msg-bare){
  background:var(--accent) !important; border:1px solid transparent !important; color:var(--on-accent) !important;
}
/* ---------- 气泡配色：深色（同一套令牌，深浅各写一组以便各自微调） ---------- */
body[data-perf="1"][data-theme="dark"] .msg-row.other .msg-bubble:not(.msg-bare){
  background:var(--surface) !important; border:1px solid var(--line) !important; color:var(--text-1) !important;
}
body[data-perf="1"][data-theme="dark"] .msg-row.mine .msg-bubble:not(.msg-bare){
  background:var(--accent) !important; border:1px solid transparent !important; color:var(--on-accent) !important;
}

/* ---------- 气泡小尖角：指向头像一侧。
   这是「装扮性伪元素」的常态例外（DESIGN.md 第四章默认要求默认隐藏）——
   尖角是气泡结构的一部分而非悬停提示，故常显，且 pointer-events:none 不挡点击。 ---------- */
.msg-row.other .msg-bubble:not(.msg-bare)::after,
.msg-row.mine .msg-bubble:not(.msg-bare)::after{
  content:''; position:absolute; top:11px; width:0; height:0;
  border:6px solid transparent; pointer-events:none;
}
.msg-row.other .msg-bubble:not(.msg-bare)::after{ left:-11px; border-right-color:var(--surface); }
.msg-row.mine .msg-bubble:not(.msg-bare)::after{ right:-11px; border-left-color:var(--accent); }

/* ---------- 时间分组：日期分隔 + 间隔提示（renderMessages 产出） ---------- */
.msg-day,.msg-time-sep{ display:flex; justify-content:center; margin:var(--space-2) 0; }
.msg-day span,.msg-time-sep span{
  font-size:var(--font-size-2xs); color:var(--text-3);
  background:color-mix(in srgb,var(--text-3) 14%,transparent);
  padding:2px 8px; border-radius:var(--radius-full);
}

/* ---------- 已读回执：从气泡同行移到气泡下方并弱化 ---------- */
.msg-meta{ display:flex; margin-top:var(--space-0h); }
.msg-row.mine .msg-meta{ justify-content:flex-end; }
.msg-meta .msg-read{ font-size:var(--font-size-2xs); color:var(--text-3); }

/* ---------- 输入区：白底 + 顶部细边 ---------- */
.chat-compose{ background:var(--surface); border-top:1px solid var(--line); }
.chat-send-btn{ color:var(--on-accent); }

/* ============================================================
   cy260945 回收为对讲停靠条预留的底部占位
   ------------------------------------------------------------
   components.css:1556 有 .main{padding-bottom:96px}，原注释写的是「避免 icDock 挡最后一行/分页」——
   那是给常驻 300px 停靠条留的整条占位。现在频道已改为默认收成右下角 56px 小悬浮球
   （见 08-intercom-checks-tasks.js 的 icBubble/icRenderDock），不再需要整条底部留白，
   故置 0，让主布局铺到视口底部。
   取舍：悬浮球仍会覆盖右下角一小块（约 56×56），长列表的最后一行/分页若正好落在右下角会被压住，
   这是「频道真悬浮、主布局拿回空间」的有意代价（用户已确认该形态）。
   ============================================================ */
/* ---------- 界面缩放（body 上的 zoom）下的聊天区高度 ----------
   应用用 document.body.style.zoom 做界面缩放，而 zoom **不影响 vh 单位**、只放大元素的实际渲染尺寸。
   于是历史层的 .chat-layout{height:calc(100vh - 120px)} 在 fontScale=1.15 时会渲染成约 897px 高，
   加上顶栏与内边距就超出视口 → 聊天框底边 963 > 视口 900，输入区掉出屏幕（实测复现）。
   修法：把缩放系数暴露为 --ui-zoom（由 applyFontScale 写入，未设置回退 1），高度除以它。 */
.chat-layout{ height:calc((100vh - 120px) / var(--ui-zoom, 1)); }

.main{ padding-bottom:0; }

/* ============================================================
   cy260947 全局加载遮罩「显隐语义丢失」修复（用户反馈：点消息列表一直加载中）
   ------------------------------------------------------------
   真因：base.css:190 把 .global-loader 写成了**无条件全屏遮罩**——
     .global-loader{ position:fixed; inset:0; z-index:…; display:flex; background:var(--color-mask); … }
   而负责「默认隐藏、.show 才显示」的那两条规则只存在于**未被加载**的 style.css:203/206：
     .global-loader{ opacity:0; pointer-events:none; transition:opacity .2s }
     .global-loader.show{ opacity:1; pointer-events:auto }
   属 CSS 合并丢失（同 cy260943/cy260944 的 .hide-mobile、.msg-line 一类）。

   为什么症状是「一直加载中」而不是「一开始就遮住」：
     js/01-core.js 的 showLoading() 有 260ms 延迟显示——快请求（本机实测 2~20ms）从不创建该元素，
     所以平时看不见问题；一旦某个请求慢过 260ms（弱网 / 冷启动 / 大公司数据 / 服务端抖动），
     元素被创建并加上 .show。请求结束后 hideLoading() 执行 classList.remove('show')，
     但 .show 在已加载的 CSS 里**根本没有对应样式**，移除它不产生任何视觉变化 →
     遮罩连同「加载中…」文案永久停留，且 pointer-events:auto 吞掉后续所有点击
     （实测：请求结束后 elementFromPoint(视口中心) 命中的仍是 DIV.global-loader）。
   消息页最容易踩中：enterChat 连续发起两次非静默请求（/api/members、/api/conversations）。

   修法：按 style.css 原语义补上；额外加 visibility:hidden 兜底（隐藏元素不参与命中测试，
   也从 Tab 焦点序列与无障碍树中移除）。数值沿用原 transition .2s。 */
.global-loader{
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .2s ease, visibility .2s;
}
.global-loader.show{
  opacity:1; visibility:visible; pointer-events:auto;
}

/* ============================================================
   cy260947 消息页左栏在会话多时把聊天框顶出可视区
   ------------------------------------------------------------
   真因（同一类：flex 子项缺 min-height:0）：
     components.css:362  .conv-list{ flex:1; overflow-y:auto }
     components.css:357  .conv-col{ display:flex; flex-direction:column; … }
   两者的 min-height 都是默认的 auto，于是 .conv-list 无法收缩到内容高度以下，
   有多少会话就撑多高。而 .chat-layout 是 display:grid（components.css:351），
   grid 行的自动最小尺寸又由子项 min-content 决定 → 行高被左栏顶起来，
   右栏 .chat-col 随之变高 → 底部的 .chat-compose（聊天框+工具栏）被推到
   .chat-layout 之外，又被其 overflow:hidden 裁掉。
   实测：18 个会话（接口返回的 3 倍）时 .conv-list 高 1175px、.chat-compose 底边
   比视口低 657px —— 即用户看到的「聊天框不见了」。会话越多越严重，
   所以「会话多的账号」最容易复现。修法：让左栏两级都能收缩。 */
.chat-layout .conv-col{ min-height:0; }
.chat-layout .conv-list{ flex:1 1 0; min-height:0; }

/* ============================================================
   cy260947 移动端消息页「列表/详情单栏切换」规则补齐
   ------------------------------------------------------------
   历史层 style.css:633-641 的这段媒体查询在 CSS 合并时整个丢了（未加载的文件），
   导致窄屏下：① .chat-layout 仍是 280px+1fr 两栏，会话列占 280px、聊天区被挤窄；
   ② 点开会话时 openConv 加的 .in-chat 类没有任何样式 → 不会切换成单栏；
   ③ .chat-back{display:none}（pages.css:592）在没有 .chat-back{display:inline-flex}
   的移动规则下永远不显示 → 进去后没有返回入口。
   数值沿用 style.css 原值（断点 760px、高度扣 96px），高度同样按 --ui-zoom 折算，
   避免界面缩放时溢出视口（见上方 .chat-layout 的说明）。 */
@media (max-width:760px){
  .chat-layout{ grid-template-columns:1fr; height:calc((100vh - 96px) / var(--ui-zoom, 1)); }
  .chat-layout .conv-col{ width:100%; border-right:0; }
  .chat-layout .chat-col{ display:none; }
  .chat-layout.in-chat .conv-col{ display:none; }
  .chat-layout.in-chat .chat-col{ display:flex; flex:1; min-height:0; }
  .chat-back{ display:inline-flex; }
  .msg-row{ max-width:88%; }
}

/* ============================================================
   cy260948 移动端侧栏抽屉（原规则只存在于未加载的 style.css）
   ------------------------------------------------------------
   症状：窄屏下点汉堡按钮没有任何反应 —— 抽屉打不开，侧栏始终占着 250px 把内容挤成窄条。
   真因（CSS 合并丢失，第四例）：
     js/10-pages-delegate-init.js:850 在窄屏下往 #sidebar 加 .open、往 #sideMask 加 .show，
     但已加载的 6 个 CSS 里：
       · 没有 .sidebar.open  → 加了类不变形（style.css:226 才有 transform:translateX(0)）
       · .side-mask 只有 components.css:683 的 display:none → 遮罩层根本不显示
         （style.css:227 才有 @media 下的 display:block + .show{opacity:1;pointer-events:auto}）
       · .menu-btn 只有 base.css:132 的 display:none → 汉堡按钮在手机上不可见
         （style.css:229 才有 @media 下的 display:block）
   修法按 style.css:222-229 原语义补回，颜色用令牌（--color-mask）；断点统一 860px：
   JS 原用 900px 判断抽屉，与已加载 CSS 的移动断点（hide-mobile/.hide-desktop 均为 860px）
   不一致，861~900px 会出现「JS 认为是抽屉、CSS 认为是桌面」的死区，故三处判断同步改为 860。 */
@media (max-width:860px){
  .sidebar{
    position:fixed; left:0; top:0; bottom:0; margin:0; z-index:60;
    border-radius:0 var(--radius-xl) var(--radius-xl) 0; height:100vh;
    transform:translateX(-105%); transition:transform .3s cubic-bezier(.2,.8,.3,1);
  }
  .sidebar.open{ transform:translateX(0); }
  .side-mask{
    display:block; position:fixed; inset:0; z-index:55;
    background:var(--color-mask); opacity:0; pointer-events:none; transition:opacity .3s;
  }
  .side-mask.show{ opacity:1; pointer-events:auto; }
  .menu-btn{ display:flex; }
}

/* ============================================================
   cy260949 帮助与反馈中心（.hs-*）
   ------------------------------------------------------------
   三页签：使用帮助 / 提交反馈 / 联系客服。入口：顶栏「？」+ 用户下拉。
   约定：语义色一律成对令牌（-bg 配 -text），不把 --danger 之类当背景（DESIGN.md §7）；
   容器高度用固定 px 而非 vh —— 应用用 body.zoom 缩放界面而 zoom 不影响 vh，
   用 vh 会在缩放到 1.3 时把内容顶出弹窗（同 .chat-layout 踩过的坑）。
   ============================================================ */
/* 顶栏入口 + 未读小红点 */
.hs-help-btn{ position:relative; }
.hs-help-dot{
  position:absolute; top:-4px; right:-4px; min-width:16px; height:16px; padding:0 4px;
  border-radius:999px; background:var(--color-danger-text); color:var(--on-accent); font-style:normal;
  font-size:10px; font-weight:700; line-height:16px; text-align:center;
}
/* 三页签 + 在线状态胶囊 */
.hs-wrap{ display:flex; flex-direction:column; gap:var(--space-3); }
.hs-tabs{ display:flex; align-items:center; gap:var(--space-1); border-bottom:1px solid var(--line); padding-bottom:var(--space-2); }
.hs-tab{
  padding:6px 14px; border:0; background:transparent; border-radius:var(--radius-sm);
  font-size:var(--font-size-base); font-weight:600; color:var(--text-2); cursor:pointer; transition:var(--t-colors);
}
.hs-tab:hover{ background:var(--hover); color:var(--text-1); }
.hs-tab.active{ background:var(--brand-soft); color:var(--color-primary-strong); }
.hs-agent-pill{
  font-size:12px; padding:3px 10px; border-radius:999px; white-space:nowrap;
  background:var(--color-warning-bg); color:var(--color-warning-text);
}
.hs-agent-pill.on{ background:var(--color-success-bg); color:var(--color-success-text); }
.hs-body{ height:470px; display:flex; flex-direction:column; min-height:0; }
.hs-empty{ margin:auto; text-align:center; color:var(--text-3); font-size:var(--font-size-sm); line-height:1.8; }
.hs-foot-tip{ margin-top:var(--space-3); font-size:12px; color:var(--text-3); text-align:center; }

/* ---- 使用帮助 ---- */
.hs-doc{ display:flex; flex-direction:column; height:100%; min-height:0; }
.hs-doc-head{ display:flex; align-items:center; gap:var(--space-2); padding-bottom:var(--space-2); }
.hs-search{
  flex:1; padding:8px 12px; border:1px solid var(--input-border); border-radius:var(--radius-sm);
  background:var(--input-bg); color:var(--text-1); font-size:var(--font-size-base);
}
.hs-doc-count{ font-size:12px; color:var(--text-3); white-space:nowrap; }
.hs-doc-list{ flex:1; min-height:0; overflow-y:auto; }
.hs-group{ padding-bottom:var(--space-2); }
.hs-group-t{
  font-size:12px; font-weight:700; color:var(--text-3); letter-spacing:.04em;
  padding:var(--space-2) 0 var(--space-1); position:sticky; top:0; background:var(--surface);
}
.hs-sec{ border:1px solid var(--line); border-radius:var(--radius-md); margin-bottom:var(--space-1h); background:var(--surface); overflow:hidden; }
.hs-sec>summary{
  display:flex; align-items:center; gap:var(--space-2); cursor:pointer; list-style:none;
  padding:10px var(--space-3); font-weight:600; font-size:var(--font-size-base); color:var(--text-1);
}
.hs-sec>summary::-webkit-details-marker{ display:none; }
.hs-sec>summary::before{ content:'▸'; color:var(--text-3); transition:transform .15s var(--ease-standard); }
.hs-sec[open]>summary::before{ transform:rotate(90deg); }
.hs-sec>summary:hover{ background:var(--hover); }
.hs-sec[open]>summary{ border-bottom:1px solid var(--line); }
.hs-sec-body{ padding:var(--space-3); font-size:var(--font-size-sm); line-height:1.85; color:var(--text-2); }
.hs-sec-body p{ margin:0 0 var(--space-2); }
.hs-sec-body ul,.hs-sec-body ol{ margin:0 0 var(--space-2); padding-left:1.3em; }
.hs-sec-body li{ margin-bottom:4px; }
.hs-sec-body code{ background:var(--code-bg,rgba(127,127,127,.14)); padding:1px 5px; border-radius:4px; font-size:.92em; }
.hs-sec-body b{ color:var(--text-1); }
.hs-tip{ background:var(--color-info-bg); color:var(--color-info-text); border-radius:var(--radius-sm); padding:8px 10px; margin:0; }

/* ---- 表单（反馈 / 客服留言共用） ---- */
.hs-form{ overflow-y:auto; padding-right:2px; }
.hs-field{ display:block; margin-bottom:var(--space-3); }
.hs-field>span{ display:block; font-size:12px; color:var(--text-3); margin-bottom:4px; font-weight:600; }
.hs-field input,.hs-field select,.hs-field textarea{
  width:100%; padding:9px 12px; border:1px solid var(--input-border); border-radius:var(--radius-sm);
  background:var(--input-bg); color:var(--text-1); font-size:var(--font-size-base); font-family:inherit; line-height:1.6;
}
.hs-field textarea{ resize:vertical; min-height:76px; }
.hs-imgs{ display:flex; flex-wrap:wrap; gap:var(--space-2); margin-bottom:var(--space-2); }
.hs-img-item{ position:relative; width:64px; height:64px; border-radius:var(--radius-sm); overflow:hidden; border:1px solid var(--line); }
.hs-img-item img{ width:100%; height:100%; object-fit:cover; display:block; }
.hs-img-item i{
  position:absolute; top:2px; right:2px; width:16px; height:16px; border-radius:50%;
  background:var(--color-mask); color:var(--on-accent); font-style:normal; font-size:11px; line-height:16px; text-align:center; cursor:pointer;
}
.hs-actions{ display:flex; align-items:center; gap:var(--space-3); flex-wrap:wrap; }
.hs-hint{ font-size:12px; color:var(--text-3); }

/* ---- 会话列表 ---- */
.hs-list-title{ font-size:12px; font-weight:700; color:var(--text-3); margin:var(--space-4) 0 var(--space-2); }
.hs-list{ display:flex; flex-direction:column; gap:var(--space-2); }
.hs-thread{
  text-align:left; width:100%; padding:10px 12px; border:1px solid var(--line); border-radius:var(--radius-md);
  background:var(--surface); cursor:pointer; transition:var(--t-colors);
}
.hs-thread:hover{ background:var(--hover); border-color:var(--color-primary); }
.hs-thread.unread{ border-color:var(--color-primary); background:var(--brand-soft); }
.hs-thread-top{ display:flex; align-items:center; gap:var(--space-2); }
.hs-thread-top b{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:var(--font-size-base); }
.hs-thread-time{ font-size:11px; color:var(--text-3); white-space:nowrap; }
.hs-thread-sub{ font-size:12px; color:var(--text-3); margin-top:3px; }
.hs-thread-last{ font-size:12px; color:var(--text-2); margin-top:3px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hs-unread{ color:var(--color-primary-strong); }
.hs-badge{ font-size:11px; padding:1px 8px; border-radius:999px; white-space:nowrap; background:var(--color-info-bg); color:var(--color-info-text); }
.hs-badge.ok{ background:var(--color-success-bg); color:var(--color-success-text); }
.hs-badge.warn{ background:var(--color-warning-bg); color:var(--color-warning-text); }
.hs-badge.muted{ background:var(--hover); color:var(--text-3); }

/* ---- 在线状态卡 ---- */
.hs-agent-card{
  display:flex; align-items:flex-start; gap:var(--space-3); padding:12px 14px; border-radius:var(--radius-md);
  margin-bottom:var(--space-3); background:var(--color-warning-bg);
}
.hs-agent-card.on{ background:var(--color-success-bg); }
.hs-agent-dot{ width:9px; height:9px; border-radius:50%; margin-top:5px; flex:0 0 auto; background:var(--color-warning-text); }
.hs-agent-card.on .hs-agent-dot{ background:var(--color-success-text); box-shadow:0 0 0 4px color-mix(in srgb,var(--color-success-text) 22%,transparent); }
.hs-agent-txt{ min-width:0; }
.hs-agent-txt b{ display:block; font-size:var(--font-size-base); color:var(--text-1); }
.hs-agent-card .hs-agent-txt b{ color:var(--color-warning-text); }
.hs-agent-card.on .hs-agent-txt b{ color:var(--color-success-text); }
.hs-agent-txt span{ font-size:12px; color:var(--text-2); line-height:1.7; }

/* ---- 客服会话 ---- */
.hs-chat-wrap,.hs-chat{ display:flex; flex-direction:column; height:100%; min-height:0; }
.hs-chat-head{ display:flex; align-items:center; gap:var(--space-2); padding-bottom:var(--space-2); border-bottom:1px solid var(--line); }
.hs-chat-head b{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hs-msgs{ flex:1; min-height:0; overflow-y:auto; padding:var(--space-3) var(--space-1); display:flex; flex-direction:column; gap:var(--space-3); }
.hs-msg{ display:flex; flex-direction:column; align-items:flex-start; }
.hs-msg.me{ align-items:flex-end; }
.hs-bubble{ max-width:78%; padding:9px 12px; border-radius:var(--radius-md); background:var(--surface-2); border:1px solid var(--line); }
.hs-msg.me .hs-bubble{ background:var(--color-primary); border-color:transparent; color:var(--on-accent); }
.hs-text{ white-space:pre-wrap; word-break:break-word; font-size:var(--font-size-base); line-height:1.7; }
.hs-img{ max-width:180px; border-radius:var(--radius-sm); margin-top:6px; display:block; }
.hs-meta{ font-size:11px; color:var(--text-3); margin-top:3px; }
.hs-compose{ display:flex; align-items:flex-end; gap:var(--space-2); padding-top:var(--space-2); border-top:1px solid var(--line); }
.hs-compose textarea{
  flex:1; padding:8px 12px; border:1px solid var(--input-border); border-radius:var(--radius-sm);
  background:var(--input-bg); color:var(--text-1); font-size:var(--font-size-base); font-family:inherit; line-height:1.6; resize:vertical; min-height:44px; max-height:120px;
}
/* 窄屏收敛：页签可横向滚动、聊天高度自适应 */
@media (max-width:860px){
  .hs-body{ height:56vh; }
  .hs-tabs{ overflow-x:auto; }
  .hs-agent-pill{ display:none; }
  .hs-bubble,.hs-msg{ max-width:88%; }
  .hs-bubble{ max-width:88%; }
}

/* ============================================================
   cy260950 移动端打磨（按实测溢出量修，不是照抄历史值）
   ------------------------------------------------------------
   用 diag_mobile.js 在 390×844 逐页量测的结论：
     · 页面本身**没有**横向溢出（表格都在 .table-wrap 里滚动，符合预期）
     · 真正的溢出源是**顶栏**：.topbar 的 scrollWidth 比 clientWidth 大 26~42px
       （随页面标题长度变化：仪表盘/供应商 10px，「其他出入库/条码与打印/跨公司共享/自定义表格」42px）
     · 「条码与打印」页另有一个 435px 的下拉（视口 390px）被卡片裁掉
   因此这里只做三件事：标题可收缩省略、账号芯片只留头像、控件更紧凑 + 表单单列。
   注：历史 style.css 里还有 .main/.item-row/.stat-num 等移动端值——.item-row 在当前已加载 CSS
   中已不存在（到货明细已改 .item-grid，其窄屏规则早在收口层），其余按实测量测结果决定不做，
   避免为了对齐历史而引入无依据的改动。 */
@media (max-width:860px){
  /* 顶栏：标题吃掉剩余宽度并省略，控件收紧 */
  .topbar{ padding:0 var(--space-3); gap:var(--space-2); }
  .topbar h1{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:var(--font-size-lg); }
  .top-actions{ gap:4px; min-width:0; }
  /* 账号芯片只留头像（点开仍是同一份用户菜单） */
  .user-chip .uc-name,.user-chip .uc-caret{ display:none; }
  .user-chip{ padding:4px; }
  /* 表单：两列改单列；输入控件一律不超出容器 */
  .form-row{ grid-template-columns:1fr; }
  .fld{ min-width:0; }
  .fld input,.fld select,.fld textarea{ max-width:100%; }
}
@media (max-width:400px){
  /* 超窄屏：界面缩放交给浏览器自带的缩放，避免顶栏（标题+打印+？+铃铛+头像）再溢出 7px */
  #fontDec,#fontInc{ display:none; }
  .topbar{ gap:var(--space-1); }
}
@media (max-width:860px){
  /* 长表单弹窗（盘点/到货/出入库等）：底部那行操作按钮吸附在弹窗底部，
     否则在手机上往下滚表单时主按钮会被滚出视野（实测「新建库存盘点」的操作行在滚动后会跑到 top=-224）。
     只匹配「弹窗 body 的最后一个子 div 且直接含 btn-primary」，不支持 :has 的浏览器整条忽略，无副作用。 */
  #modalBody > div:last-child:has(> button.btn-primary){
    position:sticky; bottom:0; z-index:2;
    padding-top:var(--space-3);
    background:linear-gradient(180deg,transparent,var(--surface) 24%);
  }
}

/* ============================================================
   cy260950 移动端补充：从「未被加载的 ios-pwa.css」里挑出**确实缺失且无副作用**的两条
   ------------------------------------------------------------
   核对过 ios-pwa.css 的其余内容：安全区处理已在 base.css:183-186，扫码浮层 .cam-* 已在
   pages.css:298-313（都迁移过，不是缺口），故不整份加载该历史文件（它用的是 768px 断点 +
   !important，与现行 860px 收口层冲突），只补下面两条：
     1) 点按灰闪与长按系统菜单 —— 已加载 CSS 里原本 0 处命中（实测 grep -c = 0）
     2) iOS 输入聚焦自动放大 —— 用 @supports 限定 iOS，安卓/桌面版式不受影响（本机无 iOS 可验） */
*{ -webkit-tap-highlight-color:transparent; -webkit-touch-callout:none; }
input,textarea,[contenteditable]{ -webkit-user-select:text; user-select:text; }
@supports (-webkit-touch-callout:none){
  @media (max-width:860px){
    input,select,textarea{ font-size:16px; }
  }
}

/* ============================================================
   cy260952 表情面板：Emoji 与 QQ 表情排版统一
   ------------------------------------------------------------
   真因（CSS 合并丢失的又一例）：已加载 CSS 里 .emoji-grid 只写了 scrollbar-width:thin，
   **从未声明 display:grid**，而 pages.css:723 却又按网格写了 .emoji-grid.qq{grid-template-columns:repeat(8,1fr)}
   —— 列数声明在非网格容器上是惰性的。后果（改动前实测）：
     · Emoji 页签：display:block → .emoji-item 按钮按行内流排，单元 21×37、每行 9 个、网格高 74px
     · QQ  页签：display:block + .qq-sticker{display:flex} + img{width:100%}
       → 每个按钮占满整行宽，图片被放大成 60×60，604 项排成 40 行、内容高 **3144px**，
         而面板只有 308px 高且 overflow:hidden → 绝大多数表情被裁掉、也滚不到
   修法：给 .emoji-grid 统一的 8 列网格 + 正方形单元（两种模式完全同构），网格自身可滚动。
   数值：面板宽 344px、左右内边距 2×space-2h、列间距 4px → 单元约 37×37，与原有
   .emoji-item{height:37px} 一致，故 Emoji 视觉不变、QQ 由"整行一张"变为同尺寸网格。 */
.emoji-grid{
  display:grid; grid-template-columns:repeat(8,1fr); gap:var(--space-1);
  padding:0 var(--space-2h) var(--space-2); align-content:start;
  flex:1; min-height:0; overflow-y:auto;   /* 面板是 flex 列，网格吃掉剩余高度并自己滚动 */
}
.emoji-grid .emoji-item{ width:100%; height:auto; aspect-ratio:1/1; display:flex; align-items:center; justify-content:center; }
.emoji-grid .qq-sticker{ width:100%; height:auto; aspect-ratio:1/1; }
.emoji-grid .qq-sticker img{ width:100%; height:100%; object-fit:contain; }

/* ============================================================
   cy260954 条码打印数量弹窗（.lp-*）
   ------------------------------------------------------------
   点「打印条码」（商品管理页单个/批量、条码页）先弹本窗口：逐个商品改张数 + 应用内预览，
   点「打印」才出纸。样式走令牌；列表与预览区各自滚动，避免商品多时把弹窗撑高。 */
.lp{ display:flex; flex-direction:column; gap:var(--space-3); }
.lp-hint{ font-size:12px; color:var(--text-3); line-height:1.7; }
.lp-bulk{ display:flex; align-items:center; gap:var(--space-2); flex-wrap:wrap; padding:var(--space-2) var(--space-3); background:var(--surface-2); border-radius:var(--radius-sm); font-size:var(--font-size-sm); }
.lp-bulk input{ width:72px; padding:5px 8px; text-align:center; border:1px solid var(--input-border); border-radius:var(--radius-sm); background:var(--input-bg); color:var(--text-1); }
.lp-total{ font-size:var(--font-size-sm); color:var(--text-2); }
.lp-total b{ color:var(--color-primary-strong); font-size:var(--font-size-lg); }
.lp-list{ max-height:300px; overflow-y:auto; border:1px solid var(--line); border-radius:var(--radius-sm); }
.lp-row{ display:flex; align-items:center; gap:var(--space-3); padding:var(--space-2) var(--space-3); border-bottom:1px solid var(--line); }
.lp-row:last-child{ border-bottom:0; }
.lp-mid{ flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
.lp-mid b{ font-size:var(--font-size-base); }
.lp-mid span{ font-size:var(--font-size-sm); color:var(--text-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.lp-mid em{ font-style:normal; font-size:var(--font-size-xs); color:var(--text-3); font-family:Consolas,Menlo,monospace; }
.lp-warn{ text-decoration:none; color:var(--color-warning-text); }
.lp-step{ display:flex; align-items:center; gap:var(--space-1); flex:none; }
.lp-step .btn{ width:32px; padding:0; }
.lp-n{ width:64px; padding:5px 6px; text-align:center; border:1px solid var(--input-border); border-radius:var(--radius-sm); background:var(--input-bg); color:var(--text-1); font-variant-numeric:tabular-nums; }
.lp-prev>summary{ cursor:pointer; font-size:var(--font-size-sm); color:var(--text-2); padding:var(--space-1) 0; }
.lp-prev>summary:hover{ color:var(--color-primary-strong); }
.lp-prev-box{ max-height:260px; overflow:auto; padding:var(--space-2); background:var(--surface-2); border-radius:var(--radius-sm); }
.lp-foot-hint{ font-size:11.5px; color:var(--text-3); line-height:1.6; }
/* 桌面端也要吸附：展开预览后内容变高，主按钮不应被挤出可视区（实测截图里「打印」曾被裁掉，需滚动才可见） */
.lp .modal-foot{ position:sticky; bottom:0; z-index:2; padding-top:var(--space-3);
  background:linear-gradient(180deg,transparent,var(--surface) 30%); }
@media (max-width:860px){
  .lp-row{ flex-wrap:wrap; }
  .lp-step{ margin-left:auto; }
  .lp-list,.lp-prev-box{ max-height:220px; }
}

/* ============================================================
   cy260956 成员多选芯片容器（.member-pick）布局丢失修复
   ------------------------------------------------------------
   用户反馈：「新建盘点 → 盘点人员列表排版错乱」。实测两个叠加缺陷：
     1) 容器 .member-pick 在已加载的 6 个 CSS 里**没有任何布局规则** ——
        display:flex;flex-wrap:wrap;gap 只存在于未加载的 style.css:872，
        于是它是个普通 block，「换行」只是 inline-flex 子项按行内流换行的巧合，
        gap 完全不生效（芯片行贴行）。共影响 6 处选择区：新建盘点·盘点人员、
        新建任务·指派给/汇报给、新建会议的参会人员 ×2。
     2) components.css 的 C1 规则把容器类 .ck-asg-pick 与复选框 .asg-chk 并列，
        一起设了 width/height:15px → 盘点人员选择区被压成 **15×15px**，16 个芯片
        全部溢出容器（这才是「错乱」的直接原因）。C1 已改为只含 <input> 类。
   这里按 style.css 原值（flex + wrap + gap:8px + margin-top:4px）用令牌恢复。 */
.member-pick{
  display:flex; flex-wrap:wrap; gap:var(--space-2); margin-top:var(--space-1h);
  align-content:flex-start;
}
/* 双保险：即便有历史规则再把它当复选框，也保证容器不被压小（容器不设尺寸） */
.member-pick.ck-asg-pick{ width:auto; height:auto; }

/* ============================================================
   cy260962 采购工具 + 频道管理（收口层，最后加载）
   —— 约定：颜色/间距/圆角/阴影一律走 tokens；列数一律用 auto-fit；
      任何带 gap / flex-direction 的规则块内必须同时有 display:flex（DESIGN.md §3.2）
   ============================================================ */

/* ---------- 采购工具：页签 ---------- */
.pur-tabs{ display:flex; flex-wrap:wrap; gap:var(--space-1h); padding:var(--space-1h); margin-bottom:var(--space-3);
  border-radius:var(--radius-ctl); }
.pur-tab{ display:inline-flex; align-items:center; gap:var(--space-1h); padding:var(--space-1h) var(--space-3);
  border:1px solid transparent; border-radius:var(--radius-pill); background:transparent; color:var(--text-2);
  font-size:var(--font-size-sm); font-weight:var(--font-weight-medium); cursor:pointer;
  transition:background var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
.pur-tab:hover{ background:var(--bg-soft); color:var(--text-1); }
.pur-tab.on{ background:var(--brand-soft); color:var(--brand); border-color:var(--brand-line); }
.pur-tab-n{ display:none; min-width:16px; height:16px; padding:0 var(--space-0h); border-radius:var(--radius-full);
  background:var(--red); color:var(--color-text-inverse); font-size:var(--font-size-2xs); line-height:16px; text-align:center; }

/* ---------- 通用小块 ---------- */
.pur-card{ padding:var(--card-pad); margin-bottom:var(--space-3); }
.pur-sec-title{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-2); font-size:var(--font-size-md);
  font-weight:var(--font-weight-bold); color:var(--text-1); margin-bottom:var(--space-2); }
.pur-hint{ font-size:var(--font-size-xs); color:var(--text-3); font-weight:var(--font-weight-medium); line-height:1.6; }
.pur-mono{ font-family:var(--font-mono); font-size:var(--font-size-xs); }
.pur-ellip{ display:block; max-width:340px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pur-off{ opacity:.55; }
.pur-err{ display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--space-1h); padding:var(--space-2);
  border:1px solid var(--color-warning-border); background:var(--color-warning-bg); color:var(--color-warning-text);
  border-radius:var(--radius-sm); font-size:var(--font-size-xs); margin-bottom:var(--space-1h); }
.pur-toolbar{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-2); }
.pur-filters{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-2); margin-top:var(--space-2); }
.pur-filters select{ min-width:130px; }
.pur-check{ display:inline-flex; align-items:center; gap:var(--space-1h); font-size:var(--font-size-sm); color:var(--text-2); cursor:pointer; }
.pur-check input{ width:auto; }
.pur-tag{ display:inline-flex; align-items:center; padding:var(--space-0h) var(--space-1h); border-radius:var(--radius-xs);
  background:var(--bg-soft); color:var(--text-2); font-size:var(--font-size-2xs); font-weight:var(--font-weight-medium); }
.pur-price{ font-family:var(--font-num); font-weight:var(--font-weight-bold); color:var(--brand); }
.pur-was{ font-family:var(--font-num); font-size:var(--font-size-2xs); color:var(--text-3); text-decoration:line-through; }
.pur-price-up{ color:var(--red); }
.pur-link{ display:inline-flex; align-items:center; gap:var(--space-0h); color:var(--brand); font-size:var(--font-size-xs);
  text-decoration:none; }
.pur-link:hover{ text-decoration:underline; }
.pur-ord{ display:inline-flex; align-items:center; gap:var(--space-0h); }
.pur-ord .icon-btn[disabled]{ opacity:.35; cursor:default; }

/* ---------- 平台勾选（自定义平台勾选查找） ---------- */
.pur-chips{ display:flex; flex-wrap:wrap; gap:var(--space-1h); align-content:flex-start; }
.pur-chip{ display:inline-flex; align-items:center; gap:var(--space-0h); padding:var(--space-0h) var(--space-2);
  border:1px solid var(--border-color); border-radius:var(--radius-pill); background:var(--bg-soft);
  font-size:var(--font-size-xs); color:var(--text-2); cursor:pointer; }
.pur-chip.on{ border-color:var(--brand-line); background:var(--brand-soft); color:var(--brand); font-weight:var(--font-weight-medium); }
.pur-chip input{ width:auto; margin:0; }

/* ---------- 找货比价 ---------- */
.pur-find-head{ display:flex; flex-wrap:wrap; gap:var(--space-2); align-items:center; }
.pur-find-head .search{ flex:1 1 240px; min-width:180px; }
.pur-find-head select{ flex:0 1 180px; }
.pur-plat-row{ display:flex; flex-wrap:wrap; gap:var(--space-2); align-items:center; margin-top:var(--space-2); }
.pur-lab{ font-size:var(--font-size-xs); color:var(--text-3); font-weight:var(--font-weight-medium); white-space:nowrap; }
.pur-plat-quick{ display:inline-flex; gap:var(--space-1h); margin-left:auto; }
.pur-links{ display:flex; flex-wrap:wrap; gap:var(--space-2); margin-top:var(--space-1h); }
.pur-plat-link{ display:inline-flex; align-items:center; gap:var(--space-1h); padding:var(--space-1h) var(--space-2);
  border:1px solid var(--border-color); border-radius:var(--radius-ctl); background:var(--bg-soft);
  text-decoration:none; color:var(--text-1); font-size:var(--font-size-sm); font-weight:var(--font-weight-medium);
  transition:border-color var(--duration-fast) var(--ease-standard), background var(--duration-fast) var(--ease-standard); }
.pur-plat-link:hover{ border-color:var(--brand-line); background:var(--brand-soft); color:var(--brand); }
.pur-plat-link em{ font-style:normal; font-size:var(--font-size-2xs); color:var(--text-3); }
.pur-plat-link.sm{ padding:var(--space-0h) var(--space-2); font-size:var(--font-size-xs); }
.pur-plat-ic{ font-size:var(--font-size-md); line-height:1; }

/* ---------- 货源卡片 ---------- */
.pur-cards{ display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:var(--space-3); margin-top:var(--space-1h); }
.pur-cards-2{ grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); }
.pur-src-card{ display:flex; flex-direction:column; gap:var(--space-1h); padding:var(--space-3);
  border:1px solid var(--border-color); border-radius:var(--radius-card); background:var(--bg-soft); }
.pur-src-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:var(--space-2); }
.pur-src-head b{ font-size:var(--font-size-sm); color:var(--text-1); line-height:1.5; }
.pur-src-meta{ display:flex; flex-wrap:wrap; gap:var(--space-1); }
.pur-src-foot{ display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--space-2); }
.pur-src-acts{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-1); margin-top:auto;
  padding-top:var(--space-1h); border-top:1px solid var(--divider); }

/* ---------- 批量操作条 ---------- */
.pur-bulk{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-2); margin-top:var(--space-2);
  padding:var(--space-2); border-radius:var(--radius-ctl); background:var(--brand-soft); color:var(--brand);
  font-size:var(--font-size-sm); font-weight:var(--font-weight-medium); }

/* ---------- 比价看板 ---------- */
.pur-cmp-card{ padding:var(--card-pad); margin-bottom:var(--space-3); }
.pur-cmp-head{ display:flex; flex-wrap:wrap; align-items:flex-start; justify-content:space-between; gap:var(--space-3); margin-bottom:var(--space-2); }
.pur-cmp-stat{ display:flex; flex-wrap:wrap; gap:var(--space-4); }
.pur-cmp-stat > div{ display:flex; flex-direction:column; align-items:flex-end; gap:var(--space-0h); }
.pur-cmp-stat b{ font-family:var(--font-num); font-size:var(--font-size-md); }
.pur-best{ background:var(--color-success-bg); }

/* ---------- 盯一下 ---------- */
.pur-events{ display:flex; flex-direction:column; gap:var(--space-1h); }
.pur-ev-row{ display:flex; align-items:flex-start; gap:var(--space-2); padding:var(--space-2);
  border:1px solid var(--border-color); border-radius:var(--radius-sm); background:var(--bg-soft); }
.pur-ev-main{ display:flex; flex-direction:column; gap:var(--space-0h); flex:1 1 0; min-width:0; }
.pur-ev-main b{ font-size:var(--font-size-sm); color:var(--text-1); }
.pur-price-hist{ margin-top:var(--space-3); padding-top:var(--space-2); border-top:1px solid var(--divider); }
.pur-ph-row{ display:flex; align-items:baseline; gap:var(--space-3); padding:var(--space-0h) 0;
  font-size:var(--font-size-xs); color:var(--text-2); }
.pur-ph-row b{ font-family:var(--font-num); color:var(--text-1); }

/* ---------- 找新品 ---------- */
.pur-mini-list{ display:flex; flex-direction:column; gap:var(--space-1h); }
.pur-mini-row{ display:flex; align-items:center; justify-content:space-between; gap:var(--space-2);
  padding:var(--space-1h) var(--space-2); border:1px solid var(--border-color); border-radius:var(--radius-sm); background:var(--bg-soft); }
.pur-mini-row > div:first-child{ flex:1 1 0; min-width:0; }
.pur-mini-acts{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-1); flex:0 0 auto; }
.pur-entry{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-2); padding:var(--space-2) 0;
  border-bottom:1px solid var(--divider); }
.pur-entry:last-child{ border-bottom:none; }
.pur-entry-kw{ flex:0 0 auto; font-size:var(--font-size-sm); font-weight:var(--font-weight-bold); color:var(--text-1); min-width:120px; }

/* ---------- 统计 ---------- */
.pur-stats{ display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); gap:var(--space-3); margin-bottom:var(--space-3); }
.pur-stat{ padding:var(--space-3); text-align:center; }
.pur-stat-n{ font-family:var(--font-num); font-size:var(--font-size-2xl); font-weight:var(--font-weight-bold); color:var(--brand); }
.pur-stat-l{ font-size:var(--font-size-xs); color:var(--text-3); margin-top:var(--space-0h); }
.pur-prov{ display:flex; flex-direction:column; gap:var(--space-2); }
.pur-prov-row{ display:flex; align-items:flex-start; justify-content:space-between; gap:var(--space-3);
  padding:var(--space-2); border:1px solid var(--border-color); border-radius:var(--radius-sm); background:var(--bg-soft); }

/* ---------- 盯控对象选择器 ---------- */
.pur-pick{ display:flex; flex-wrap:wrap; gap:var(--space-1h); align-items:center; }
.pur-pick-res{ display:flex; flex-direction:column; gap:var(--space-0h); margin-top:var(--space-1h); max-height:220px; overflow-y:auto; }
.pur-pick-item{ display:flex; align-items:center; justify-content:space-between; gap:var(--space-2); width:100%;
  padding:var(--space-1h) var(--space-2); border:1px solid var(--border-color); border-radius:var(--radius-xs);
  background:var(--bg-soft); color:var(--text-1); font-size:var(--font-size-xs); text-align:left; cursor:pointer; }
.pur-pick-item:hover{ border-color:var(--brand-line); background:var(--brand-soft); }

/* ---------- 小屏收敛（≤860px，与全站断点一致） ---------- */
@media (max-width:860px){
  .pur-find-head .search{ flex:1 1 100%; }
  .pur-find-head select{ flex:1 1 100%; }
  .pur-plat-quick{ margin-left:0; }
  .pur-cmp-head{ flex-direction:column; }
  .pur-cmp-stat{ width:100%; justify-content:space-between; gap:var(--space-2); }
  .pur-cmp-stat > div{ align-items:flex-start; }
  .pur-ellip{ max-width:200px; }
  .pur-entry-kw{ min-width:0; flex:1 1 100%; }
  .pur-mini-row{ flex-direction:column; align-items:flex-start; }
  .pur-mini-acts{ width:100%; }
  .pur-prov-row{ flex-direction:column; }
  .pur-filters select{ flex:1 1 140px; min-width:0; }
}

/* ---------- cy260962 消息频道在聊天页的呈现 ---------- */
.conv-ava-ch{ background:var(--brand-soft); color:var(--brand); }
.conv-ch-ico{ font-size:var(--font-size-lg); line-height:1; }
.conv-is-channel .conv-name small{ color:var(--brand); }
.chat-ro-bar{ display:flex; align-items:center; gap:var(--space-1h); margin:0 var(--space-2) var(--space-1h);
  padding:var(--space-1h) var(--space-2); border:1px solid var(--color-warning-border); background:var(--color-warning-bg);
  color:var(--color-warning-text); border-radius:var(--radius-sm); font-size:var(--font-size-xs); }
.chat-input-editable.ro{ opacity:.6; cursor:not-allowed; }

/* ---------- cy260963 采购工具 · 官方接口自动取数与密钥配置 ---------- */
/* 未配置密钥时的引导条 */
.pur-cta{ display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:var(--space-3);
  margin-top:var(--space-2); padding:var(--space-3); border:1px dashed var(--brand-line);
  background:var(--brand-soft); border-radius:var(--radius-sm); font-size:var(--font-size-sm); color:var(--text-1); }
/* 取数结果：按数据源分组 */
.pur-fetch-group{ display:flex; flex-direction:column; gap:var(--space-2); }
.pur-fetch-group + .pur-fetch-group{ margin-top:var(--space-3); padding-top:var(--space-3); border-top:1px solid var(--divider); }
.pur-fetch-head{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-1h); }
.pur-fetch-head .btn{ margin-left:auto; }
.pur-fetch-img{ width:100%; height:150px; overflow:hidden; border-radius:var(--radius-xs); background:var(--bg-soft); border:1px solid var(--divider); }
.pur-fetch-img img{ width:100%; height:100%; object-fit:contain; display:block; }
.pur-fetch-card .pur-src-head b{ display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
/* 密钥配置：一行一个数据源，纵向排布 head / fields / acts / res / note。
   这里覆盖 1093 行的 .pur-prov-row 为纵向堆叠，故同样显式声明 display:flex（DESIGN.md §3.2）。 */
.pur-prov-row{ display:flex; flex-direction:column; align-items:stretch; }
.pur-prov-head{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-1h); }
.pur-prov-fields{ display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:var(--space-2); }
.pur-prov-acts{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-1h); }
.pur-prov-kw{ flex:1 1 180px; min-width:0; }
.pur-prov-res:empty{ display:none; }
.pur-ok{ display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--space-1h); padding:var(--space-2);
  border:1px solid var(--color-success-border); background:var(--color-success-bg); color:var(--color-success-text);
  border-radius:var(--radius-sm); font-size:var(--font-size-xs); }
/* 自动巡检开关 */
.pur-switch{ min-width:46px; padding:var(--space-0h) var(--space-1h); border:1px solid var(--border-color);
  border-radius:var(--radius-pill); background:var(--bg-soft); color:var(--text-3);
  font-size:var(--font-size-xs); cursor:pointer; transition:all .18s; }
.pur-switch.on{ border-color:var(--color-success-border); background:var(--color-success-bg); color:var(--color-success-text); font-weight:var(--font-weight-medium); }
/* 窄屏只改方向/占比，容器性质不变，故同时重申 display:flex（DESIGN.md §3.2） */
@media (max-width:860px){
  .pur-cta{ display:flex; flex-direction:column; align-items:flex-start; }
  .pur-prov-kw{ flex:1 1 100%; }
}

/* ---------- cy260968 采购工具 · 平台新品直取（类型/分类/品牌） ---------- */
/* 品牌信息条：logo 是固定尺寸元素，须显式 max-width:none，否则被全站 img 规则钳成扁图（DESIGN.md §三） */
.pur-brand-head{ display:flex; align-items:center; gap:var(--space-2); }
.pur-brand-head > div{ flex:1 1 0; min-width:0; }
.pur-brand-logo{ width:40px; height:40px; max-width:none; flex:0 0 auto; border-radius:var(--radius-sm);
  object-fit:contain; background:var(--bg-soft); border:1px solid var(--divider); }
/* 直取筛选行：复用 .pur-find-head 的弹性换行，这里只补下拉框在窄屏的收敛 */
@media (max-width:860px){
  #purNewType,#purNewCat,#purNewBrand,#purNewSort,#purNewPs,#purNewImpCat{ flex:1 1 100%; }
}

/* ============================================================
   cy260971 · 全局防横向溢出兜底
   根因：grid/flex 的 1fr（minmax(auto,1fr)）与 grid/flex 子项的自动
   最小宽 = 内容 min-content；nowrap 表格/长串会把轨道与卡片撑破容器
   （宽屏加载后再拖窄窗口、展开侧栏时尤其明显，往往刷新才恢复）。
   处理：轨道改用 minmax(0,1fr)（见 components.css 的 dash/stat/form 网格），
   子项统一 min-width:0；超宽表格依旧在 .table-wrap 内横向滚动，
   页面本身不再产生横向溢出。
   ============================================================ */
.dash-grid>*,.stat-grid>*,.form-grid>*,.form-row>*,.form-row-3>*,
.profile-grid>*,.acct-grid>*,.cal-grid>*,.cal-head>*{ min-width:0; }
.card,.glass{ min-width:0; max-width:100%; }
.table-wrap{ min-width:0; max-width:100%; }
label.fld{ min-width:0; }
.content canvas{ max-width:100%; }
.content p,.wrap-break{ overflow-wrap:anywhere; }