:root {
  font-family: 'DM Sans', 'Noto Sans SC', system-ui, sans-serif;
  color: #172033;
  background: #f5f7fa;
  font-synthesis: none;
}

* { box-sizing: border-box; }
body { margin: 0; background: #f5f7fa; cursor: default; }
.login-page { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; background: linear-gradient(135deg, #f0f5ff, #f7f9fc); }
.login-card { width: 100%; max-width: 430px; border-radius: 16px; box-shadow: 0 18px 60px rgba(22, 55, 110, .12); }
.brand-title { margin: 0 !important; color: #172033; }
.login-form { margin-top: 28px; }
.login-error { margin: -3px 0 16px; }
/* 「记住账号密码」：勾选框本身不用占一行 label 高度，收紧一点 */
.login-remember-row { margin-bottom: 12px; }
.login-remember-row .ant-form-item-control-input { min-height: 0; }
.login-note { display: block; text-align: center; font-size: 12px; line-height: 1.6; }
/* 弹窗里的登录表单：整页那套 28px 顶距太松，收紧一点 */
.login-form.is-compact { margin-top: 16px; }
.login-form.is-compact .ant-form-item { margin-bottom: 14px; }
.relogin-hint { margin-bottom: 4px; }
.relogin-modal .login-note { margin-top: 4px; }

/* 应用外壳：整页锁死视口高度，页面本身不滚动 —— 顶部和左侧固定，只有内容区自己滚。
   注意别给 body 加 overflow:hidden，登录页（.login-page）是独立的，内容多时要能滚。 */
.app-layout { height: 100vh; min-height: 0; overflow: hidden; }
/* 右侧那一列（Header + Content）也锁高，否则 Content 的 overflow 不会生效 */
.app-layout > .ant-layout { height: 100%; min-height: 0; display: flex; flex-direction: column; }
.app-sider { position: relative; z-index: 2; overflow: hidden; background: #fff !important; border-right: 1px solid #e9eef5; box-shadow: 2px 0 12px rgba(31, 52, 82, .035); }
.app-sider .ant-layout-sider-children { display: flex; flex-direction: column; height: 100%; }
.app-logo { height: 76px; flex: 0 0 76px; display: flex; align-items: center; gap: 11px; padding: 0 22px; color: #172033; border-bottom: 1px solid #f2f4f7; }
.logo-mark { width: 34px; height: 34px; flex: 0 0 34px; display: inline-flex; align-items: center; justify-content: center; color: #fff; background: #1677ff; border-radius: 9px; font-size: 19px; font-weight: 800; box-shadow: 0 6px 14px rgba(22, 119, 255, .22); }
.logo-copy { min-width: 0; line-height: 1.1; }
.logo-copy strong { display: block; font-size: 16px; letter-spacing: .5px; }
.logo-copy small { display: block; margin-top: 5px; color: #9aa5b5; font-size: 9px; letter-spacing: 1.4px; }
/* 菜单项多了在侧栏内部滚，logo 和底部按钮始终可见 */
.app-menu { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 15px 12px; border-inline-end: 0 !important; background: transparent !important; }
.app-menu .ant-menu-item { width: 100% !important; height: 44px; line-height: 44px; margin: 3px 0 !important; padding: 0 15px !important; color: #667085; border-radius: 8px; }
.app-menu .ant-menu-item .anticon { min-width: 18px; font-size: 16px; }
.app-menu .ant-menu-item:hover { color: #1677ff; background: #f0f6ff; }
.app-menu .ant-menu-item-selected { color: #1677ff; background: #e8f2ff; font-weight: 600; }
.app-menu .ant-menu-item-selected::after { display: none; }
.app-menu .ant-menu-item-selected .anticon { color: #1677ff; }
.app-menu .ant-badge { margin-left: 7px; }
.app-menu .ant-badge-count { min-width: 18px; height: 18px; padding: 0 5px; line-height: 18px; box-shadow: none; font-size: 10px; }
.app-menu .ant-menu-sub { background: transparent !important; cursor: default; }
.app-menu .ant-menu-submenu-title { height: 40px; line-height: 40px; margin: 4px 0 2px !important; color: #1d2939; font-weight: 600; font-size: 13px; border-radius: 8px; cursor: pointer; }
.app-menu .ant-menu-submenu-title:hover { background: #f0f6ff; }
.app-menu .ant-menu-submenu-title .anticon { min-width: 18px; font-size: 16px; }
.app-menu .ant-menu-submenu .ant-menu-item { padding-left: 40px !important; height: 40px; line-height: 40px; font-size: 14px; cursor: pointer; }
.app-menu .ant-menu-submenu .ant-menu-item .anticon { font-size: 15px; }
.ant-layout-sider-collapsed .app-menu .ant-menu-submenu-title { padding: 0 !important; text-align: center; }
.sider-bottom { flex: 0 0 auto; padding: 14px 12px 18px; border-top: 1px solid #f0f2f5; }
/* 「最该做的一件事」浅蓝卡（设计稿 §2.1）：侧栏底部是行动入口，不是广告位。
   文案里的数字来自真实库存（level !== 'ok' 的 SKU 数）。 */
.sider-cta { display: flex; flex-direction: column; gap: 3px; margin-bottom: 12px;
  padding: 12px 13px; border-radius: var(--d-r-sm); background: var(--d-blue-soft); }
.sider-cta b { font-size: 13px; font-weight: 800; letter-spacing: -.02em; color: #1E4E8C; }
.sider-cta span { font-size: 11.5px; line-height: 1.55; color: #3F6EA8; }
.sider-cta u { margin-top: 5px; font-size: 11.5px; font-weight: 700; color: var(--d-blue);
  text-decoration: underline; cursor: pointer; }
.sider-bottom .ant-btn { height: 38px; margin-top: 4px; color: #667085; text-align: left; border-radius: 7px; }
.sider-bottom .ant-btn:hover { color: #1677ff; background: #f5f8fc; }
.sider-bottom .ant-btn-dangerous:hover { color: #ff4d4f; background: #fff1f0; }
.ant-layout-sider-collapsed .app-logo { justify-content: center; padding: 0; }
.ant-layout-sider-collapsed .logo-copy, .ant-layout-sider-collapsed .sider-bottom .ant-btn > span:not(.anticon) { display: none; }
.ant-layout-sider-collapsed .app-menu { padding-inline: 10px; }
.ant-layout-sider-collapsed .app-menu .ant-menu-item { padding: 0 !important; text-align: center; }
.ant-layout-sider-collapsed .app-menu .anticon { margin: 0; }
.ant-layout-sider-collapsed .sider-bottom { padding: 12px 10px; }
.ant-layout-sider-collapsed .sider-bottom .ant-btn { padding: 0; text-align: center; }

/* 注意 line-height：antd 的 .ant-layout-header 默认是 height/line-height 都是 64px，
   这里只改了 height，line-height 会继续往下继承。文字放在普通 div 里看不出来（单行 64px
   仍然塞得进 72px 的 header），但一旦包成 flex 容器、文字变成会换行的块级 flex item，
   就会变成「2 行 × 64px = 128px」把 header 撑破、跟下面重叠。所以这里必须显式收掉。 */
.app-header { height: 72px; flex: 0 0 72px; padding: 0 28px; background: #fff; border-bottom: 1px solid #edf0f5; display: flex; align-items: center; justify-content: space-between; line-height: 1.5; }
.app-header h3 { margin: 3px 0 0 !important; }
/* 内容区：吃掉剩余高度并自己滚，表格再各自限高，就不会把整页撑长 */
/* 内容区：吃掉剩余高度并自己滚，表格再各自限高，就不会把整页撑长。
   宽度**不设上限** —— 订单表列多、宽屏下要给足横向空间（`width: 100%` 跟着外壳走，
   表格自己的横向滚动会按需出现）。之前写死 max-width: 1800px，宽屏两边留白纯浪费。 */
.app-content { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden; width: 100%; }
/* 每个 tab 一个 pane：自己滚自己的，切回旧 tab 时滚动位置和页面状态都还在。
   上下左右的内边距挪到 pane 上（外壳不滚了，padding 留在外壳会变成永远空着的一圈）。 */
.tab-pane { flex: 1 1 auto; min-height: 0; width: 100%; overflow-y: auto; overflow-x: hidden; padding: 28px; }
/* 外壳常驻滚动条，收细一点别抢视线 */
.app-content::-webkit-scrollbar, .tab-pane::-webkit-scrollbar, .app-menu::-webkit-scrollbar { width: 10px; height: 10px; }
.app-content::-webkit-scrollbar-thumb, .tab-pane::-webkit-scrollbar-thumb, .app-menu::-webkit-scrollbar-thumb { background: #d3dae4; border: 2px solid transparent; background-clip: content-box; border-radius: 6px; }
.app-content::-webkit-scrollbar-thumb:hover, .tab-pane::-webkit-scrollbar-thumb:hover, .app-menu::-webkit-scrollbar-thumb:hover { background: #b6c1d0; background-clip: content-box; }
.app-content::-webkit-scrollbar-track, .tab-pane::-webkit-scrollbar-track, .app-menu::-webkit-scrollbar-track { background: transparent; }

/* ── 多标签页：Header 下面那一排 tab ────────────────────────────────── */
.app-tabbar { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; padding: 8px 20px 0; background: #fff; border-bottom: 1px solid #edf0f5; }
/* tab 多了横向滚，滚动条压成 0 高（悬浮时才露出一条细的） */
.app-tabbar-scroll { flex: 1 1 auto; min-width: 0; display: flex; align-items: flex-end; gap: 4px; overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; }
.app-tabbar-scroll::-webkit-scrollbar { height: 4px; }
.app-tabbar-scroll::-webkit-scrollbar-thumb { background: #d3dae4; border-radius: 4px; }
.app-tabbar-scroll::-webkit-scrollbar-track { background: transparent; }
/* 页签 = 顶部圆角小卡：未激活全透明（只剩文字），悬停淡底色；
   激活白底 + 左右描边 + 往下压 1px 盖过分隔线，看起来跟内容区「连」在一起 */
.app-tab { position: relative; flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 6px 0 12px; border: 1px solid transparent; border-bottom: none; border-radius: 8px 8px 0 0; background: transparent; color: rgba(0, 0, 0, .62); font-size: 13px; line-height: 1; cursor: pointer; user-select: none; white-space: nowrap; transition: color .18s, background .18s, border-color .18s, box-shadow .18s; }
.app-tab:hover { color: #1677ff; background: #f5f8fd; }
/* 激活态要一眼可辨：淡蓝底 + 蓝描边 + 通宽 3px 蓝底线 + 轻投影 */
.app-tab.is-active { color: #0958d9; background: #e8f3ff; border-color: #91caff; margin-bottom: -1px; font-weight: 600; box-shadow: 0 2px 8px rgba(22, 119, 255, .16); }
/* 激活页签底部的蓝色短线（页签里的绝对定位，不跟分隔线打架） */
.app-tab.is-active::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; border-radius: 2px 2px 0 0; background: #1677ff; }
.app-tab-icon { display: inline-flex; align-items: center; font-size: 13px; color: rgba(0, 0, 0, .38); transition: color .18s; }
.app-tab:hover .app-tab-icon, .app-tab.is-active .app-tab-icon { color: #1677ff; }
.app-tab-text { max-width: 180px; overflow: hidden; text-overflow: ellipsis; }
.app-tab-close { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 4px; color: rgba(0, 0, 0, .4); font-size: 10px; opacity: .45; transition: opacity .15s, background .15s, color .15s; }
.app-tab:hover .app-tab-close, .app-tab.is-active .app-tab-close { opacity: 1; }
.app-tab-close:hover { background: rgba(0, 0, 0, .08); color: rgba(0, 0, 0, .85); }
/* 页签上的刷新小按钮：跟 × 同款式，默认淡、悬停才显出来 */
.app-tab-refresh { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 4px; color: rgba(0, 0, 0, .38); font-size: 10px; opacity: 0; transition: opacity .15s, background .15s, color .15s; }
.app-tab:hover .app-tab-refresh, .app-tab.is-active .app-tab-refresh { opacity: 1; }
.app-tab-refresh:hover { background: rgba(0, 0, 0, .08); color: rgba(0, 0, 0, .85); }
/* 拖动换位：被拖的半透明，落点页签亮蓝框 */
.app-tab[draggable="true"] { cursor: grab; }
.app-tab.is-drop-target { border-color: #1677ff; box-shadow: 0 0 0 2px rgba(22, 119, 255, .25); }
.app-tab.is-drop-target::before { content: ''; position: absolute; left: -4px; top: 4px; bottom: 4px; width: 2px; border-radius: 2px; background: #1677ff; }
.app-tabbar-extra { flex: 0 0 auto; color: rgba(0, 0, 0, .45); }
/* 单个 tab 崩了时的错误块（别让它把整站拖白） */
.pane-error { padding-top: 8px; }
.pane-error p { margin: 0 0 8px; }
.pane-error-detail { max-height: 220px; overflow: auto; margin: 8px 0; padding: 10px 12px; border-radius: 6px; background: #fff5f5; color: #a8071a; font-size: 12px; white-space: pre-wrap; word-break: break-all; }
.page-stack { width: 100%; }
/* page-stack 有两种实现：antd Space 版（间距靠 Space 自带 gap，子节点都包在
   .ant-space-item 里）和 div 版（商品管理 / 新建系统商品 / 入库页，天生没有间距，
   卡片会贴在一起）。这里给 div 版的相邻子块统一补 16px；
   用 :not(.ant-space-item) 排除 Space 版，避免和它自带的间距叠加。 */
.page-stack > * + *:not(.ant-space-item) { margin-top: 16px; }
.page-heading { display: flex; align-items: flex-start; justify-content: space-between; }
.page-heading h3 { margin: 5px 0 !important; }
.page-heading p { margin: 4px 0 0; }
.stat-card { height: 132px; border: 0; overflow: hidden; }
/* 白底黑字 + 彩色图标徽标（仿参考图：第一行图标+标题，下方大数字，再下方副标题） */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; }
.stat-card { height: auto; min-height: 158px; border: 1px solid #f0f0f0; background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, .04); border-radius: 10px; }
.stat-card .ant-card-body { height: 100%; padding: 18px 22px; display: flex; flex-direction: column; gap: 6px; }
.stat-card .stat-header { display: flex; align-items: center; gap: 8px; color: #595959; }
.stat-card .stat-icon { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 50%; font-size: 13px; }
.stat-card .stat-title { font-size: 14px; color: #262626; }
/* 全局而非只在 .stat-card 内：表头（快递+包装）也会用到这个问号 */
.stat-info { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 50%; background: #f0f0f0; color: #8c8c8c; font-size: 11px; cursor: help; margin-left: 2px; }
/* 「快递+包装」列的数字：虚线下划线提示可悬停看明细 */
.fulfillment-cell { border-bottom: 1px dashed #bfbfbf; cursor: help; }
/* tabular-nums：数字等宽，滚动时千分位变化不会让整行左右跳动 */
.stat-card .ant-statistic-content { font-size: 32px; line-height: 1.1; color: #1f1f1f; font-weight: 600; font-variant-numeric: tabular-nums; }
.stat-card .stat-sub { font-size: 12px; color: #8c8c8c; }
/* 四色图标（浅色圆底 + 彩色图标） */
.stat-card.blue .stat-icon { background: #eaf1fb; color: #4a7fc0; }
.stat-card.cyan .stat-icon { background: #e6f5f4; color: #3a9d96; }
.stat-card.orange .stat-icon { background: #fbeede; color: #d98c45; }
.stat-card.green .stat-icon { background: #e8f4ea; color: #5a9e63; }
.stat-card.purple .stat-icon { background: #f0ecf8; color: #7c6bb0; }
.content-card > .ant-card-head { min-height: 72px; }
.sku-text { font-size: 11px; }
.sku-thumb { flex: none; display: inline-flex; width: 34px; height: 34px; border-radius: 4px; overflow: hidden; background: #f5f5f5; cursor: zoom-in; }
.sku-thumb .ant-image-img { object-fit: cover; }
.sku-thumb .ant-image-mask { cursor: zoom-in; }
.sku-thumb .ant-image-mask-info { font-size: 11px; }
.bar-chart { height: 245px; display: flex; gap: 12px; align-items: flex-end; padding: 28px 12px 4px; border-bottom: 1px solid #f0f0f0; }
.bar-column { height: 100%; flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 7px; font-size: 10px; }
.bar-column > span { color: #8c8c8c; font-size: 10px; }
/* ⚠️ 这几条是「发货统计 / 销售统计」页内图表的柱子，属于页面层 —— 但颜色统一走
   公共层的 --d-blue（全站唯一强调色），别再留 #1677ff，否则同一个 App 里两种蓝。 */
.bar-fill { width: min(28px, 70%); min-height: 8px; background: linear-gradient(180deg, var(--d-blue-2, #93C5FD), var(--d-blue)); border-radius: 5px 5px 2px 2px; }
/* 发货统计：按天趋势的天数可能远超 30 天，柱子给最小宽度后横向滚动，别挤成一条线 */
.bar-chart-scroll { overflow-x: auto; overflow-y: hidden; gap: 8px; }
.bar-chart-scroll .bar-column { min-width: 36px; }
.ship-trend-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin: 20px 0 8px; }
.ship-trend-title { font-size: 14px; color: #262626; }
/* 排行表第一列：名次徽标 + 名称（名称过长省略，靠 title 看全） */
.rank-cell { display: flex; align-items: center; gap: 8px; min-width: 0; }
.rank-badge { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 5px; background: #f0f0f0; color: #8c8c8c; font-size: 11px; font-variant-numeric: tabular-nums; }
.rank-badge.rank-top { background: #e6f4ff; color: #1677ff; font-weight: 600; }
.rank-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ship-code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; }
.ant-table-thead > tr > th, .ant-table-tbody > tr > td { font-size: 12px; }
.ant-table-tbody > tr.store-row-active > td { background: #e8f2ff; }
.ant-table-tbody > tr.store-row-total > td { background: #fafafa; font-weight: 600; }
.ant-card { border-radius: 10px; }
.ant-badge { line-height: 1; }
.ant-badge-count { box-shadow: none; }
.ant-statistic-content-prefix { margin-right: 7px; font-size: 19px; }
/* 库存明细：SKU 可点击 + 同商品 SKU 弹窗 */
.sku-link { color: #1677ff; font-size: 12px; cursor: pointer; }
.sku-link:hover { text-decoration: underline; }
/* 分类并入商品列：跟在 SKU 后面，紧凑一点，别把商品列撑宽 */
.sku-class-tag { margin-left: 5px; margin-right: 0; padding: 0 5px; font-size: 11px; line-height: 16px; border-radius: 8px; }
.sku-class-none { margin-left: 5px; font-size: 11px; color: #bfbfbf; }
.sku-group-summary { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 12px; font-size: 13px; color: #8c8c8c; }
.sku-group-summary .ant-typography { color: #262626; }
.ant-table-tbody > tr.sku-row-current > td { background: #e8f2ff; }
/* 库存明细：在途 / 实际库存 / 可用库存 三列视觉区分
   在途 = 还没到手的期望（蓝，弱化）；实际库存 = 实物基准（中性加粗）；
   可用库存 = 真正能卖的（绿=正常 / 红=负值即超卖欠货）。 */
.stock-num { font-variant-numeric: tabular-nums; font-size: 12px; }
.stock-arriving { display: inline-flex; align-items: center; gap: 3px; padding: 0 6px; border-radius: 9px; background: #e6f4ff; color: #0958d9; border: 1px solid #bae0ff; font-variant-numeric: tabular-nums; line-height: 18px; }
.stock-arriving-zero { display: inline-block; color: #bfbfbf; font-variant-numeric: tabular-nums; }
.stock-arriving-icon { font-size: 12px; opacity: .9; vertical-align: -1px; }
.stock-actual { color: #262626; font-weight: 600; font-variant-numeric: tabular-nums; }
/* 进货链接：不含税成本列。
   等宽数字让同列小数点对齐，便于纵向扫读比价。 */
.cost-value { font-variant-numeric: tabular-nums; color: #262626; }
.stock-available { font-weight: 600; font-variant-numeric: tabular-nums; }
.stock-available-ok { color: #389e0d; }
.stock-available-low { color: #d46b08; }
/* 告急（可用库存 ≤ 1，含 0）和超卖（负数）共用一个红：都是「马上要处理」 */
.stock-available-critical { color: #cf1322; }
.stock-available-negative { color: #cf1322; }
/* 库存明细：每个 SKU 的每日销量迷你曲线（手写 SVG，见 app.js 的 DailySparkline）。
   表头宽度按「合计数字 + 84px 曲线 + 间距」定的（COL_MIN_WIDTH_BY_KEY.dailySeries）。 */
.spark-cell { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
/* 合计数字等宽 + 右对齐，纵向扫读时小数点能对齐 */
.spark-sum { min-width: 26px; text-align: right; font-variant-numeric: tabular-nums; color: #262626; }
/* overflow:visible —— 末点那个 r=2 的小圆点圆心正好在右边界上，默认会被裁掉一半 */
.spark { display: block; flex: none; overflow: visible; cursor: crosshair; }
.spark-line { fill: none; stroke: #1677ff; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.spark-area { fill: rgba(22, 119, 255, .12); stroke: none; }
.spark-dot { fill: #1677ff; }
/* 透明命中区：SVG 只在有绘制内容的地方接鼠标事件，铺一块全尺寸透明 rect 才能整框响应
   （`fill: transparent` 仍然是「有填充」，可命中；`fill: none` 就不行） */
.spark-hit { fill: transparent; }
/* 鼠标停在哪个位置：竖虚线指位 + 那个点放大一号 */
.spark-guide { stroke: #bfbfbf; stroke-width: 1; stroke-dasharray: 2 2; }

/* ── 销售趋势曲线（自绘 SVG，不引图表库；跟 .spark 同一套做法）────────────── */
.stchart { position: relative; width: 100%;
  /* 跟卡片标题之间留一道明确的间隔 —— 实测原来只差 -1px（几乎贴着） */
  margin-top: 10px; }
.stchart-svg { display: block; overflow: visible; }
.stchart-grid { stroke: var(--d-line-2); stroke-width: 1; }
.stchart-max { fill: var(--d-ink-3); font-size: 11px; font-variant-numeric: tabular-nums; }
.stchart-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.stchart-area { stroke: none; opacity: .10; }
/* 圆点描白边：线穿过点时不会糊成一团 */
.stchart-dot { stroke: #fff; stroke-width: 1.5; }
.stchart-dot.is-active { stroke: #fff; stroke-width: 2; }
.stchart-guide { stroke: var(--d-line-2); stroke-width: 1; stroke-dasharray: 3 3; }
.stchart-x { fill: var(--d-ink-3); font-size: 11px; text-anchor: middle; }
.stchart-hit { fill: transparent; cursor: crosshair; }
.stchart-tip { position: absolute; top: 0; transform: translateX(-50%); display: flex;
  flex-direction: column; gap: 1px; padding: 4px 8px; border-radius: var(--d-r-sm);
  background: var(--d-ink); color: #fff; font-size: 11px; line-height: 1.45;
  white-space: nowrap; pointer-events: none; }
.stchart-tip b { font-weight: 700; font-variant-numeric: tabular-nums; }
.spark-dot.is-active { fill: #0958d9; }
/* 热销 SKU（销售标签 = 热销）的曲线染橙红（#fa541c，火山色 6 号）：一屏几十条蓝线里，
   卖得动的那几条自己跳出来。
   ⚠️ 这几行**必须排在下面 .spark.is-flat 之前** —— 两者同时命中时灰线优先：
      全 0 是「一件没卖」的结论，不许被橙色盖成「看着卖得动」。 */
.spark.is-hot .spark-line { stroke: #fa541c; }
.spark.is-hot .spark-area { fill: rgba(250, 84, 28, .14); }
.spark.is-hot .spark-dot { fill: #fa541c; }
.spark.is-hot .spark-dot.is-active { fill: #d4380d; }
/* 全 0（窗口内一件没卖）：整条线走灰色，一眼和「有销量」的蓝色区分开 */
.spark.is-flat .spark-line { stroke: #d9d9d9; }
.spark.is-flat .spark-dot { fill: #d9d9d9; }
/* 悬停提示：只报当前指的那一天（日期 + 件数），不列整段 —— 列一整段反而看不出鼠标指着哪天。
   数字用浅蓝加粗：tooltip 底色是深灰，深蓝 #1677ff 压在上面读不清。 */
.spark-tip { display: flex; align-items: baseline; gap: 12px; }
.spark-tip b { color: #69b1ff; font-size: 15px; font-variant-numeric: tabular-nums; }
/* 手机卡片详情里的曲线：合计 + 曲线横排，合计等宽右对齐跟桌面列一个观感 */
.m-spark { display: inline-flex; align-items: center; gap: 10px; vertical-align: middle; }

/* 库存明细：表头拖拽调宽手柄。
   手柄浮在表头单元格右边缘，hover 时才明显（平时不干扰阅读）。 */
.col-head { position: relative; display: block; height: 100%; }
/* 手柄向左右各外扩，保证列边界两侧 12px 内都能抓到，不用像素级对齐。 */
.col-resizer { position: absolute; top: -10px; right: -22px; width: 26px; height: calc(100% + 20px); min-height: 46px; cursor: col-resize; z-index: 4; touch-action: none; }
.col-resizer::after { content: ''; position: absolute; top: 22%; right: 12px; width: 2px; height: 56%; background: transparent; border-radius: 1px; transition: background .15s; }
.col-resizer:hover::after { background: #1677ff; }
/* 表格限高（scroll.y）后表头会拆进 .ant-table-header，那里是 overflow:hidden，
   上面 right:-22px 的外扩会被整块裁掉，看上去就像拖不动了。改成贴着单元格右边缘内侧，
   可抓范围 16px 仍在列边界附近，hover 竖线也更靠近边界。 */
.ant-table-header .col-resizer { right: -2px; width: 16px; }
.ant-table-header .col-resizer::after { right: 7px; }
body.col-resizing { cursor: col-resize !important; user-select: none; }
body.col-resizing .col-resizer::after { background: #1677ff; }
/* 拖动调宽时不吃排序、不出文字选中、不要列拖拽的手型 */
body.col-resizing .ant-table-thead > tr > th { cursor: col-resize !important; }
body.col-resizing * { user-select: none !important; }

/* 库存明细：列显示配置面板（Popover 里的勾选列表）。 */
.col-cfg-title { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 13px; }
.col-cfg-count { font-size: 12px; font-weight: 400; color: var(--text-3, #8c8c8c); font-variant-numeric: tabular-nums; }
.col-cfg-panel { width: 232px; }
.col-cfg-list { max-height: 300px; overflow-y: auto; display: flex; flex-direction: column; }
.col-cfg-item { display: flex; align-items: center; gap: 8px; padding: 4px 6px; border-radius: 6px; cursor: pointer; font-size: 13px; }
.col-cfg-item:hover { background: #f5f5f5; }
.col-cfg-item.is-locked { cursor: default; opacity: .62; }
.col-cfg-item.is-locked:hover { background: transparent; }
/* 拖动排序：整条 label 都可拖，手柄只是「能拖」的提示。
   draggable 的元素里点复选框有时会触发浏览器拖拽，给手柄加 grab 光标明确交互。 */
.col-cfg-drag { flex: none; display: inline-flex; align-items: center; color: #bfbfbf; cursor: grab; font-size: 12px; }
.col-cfg-item:hover .col-cfg-drag { color: #8c8c8c; }
.col-cfg-drag:active { cursor: grabbing; }
.col-cfg-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.col-cfg-lock { font-size: 11px; color: #8c8c8c; flex: none; }
.col-cfg-actions { display: flex; align-items: center; gap: 4px; padding-top: 2px; }
.col-cfg-actions .ant-btn-link { padding: 0 4px; height: auto; }
.col-cfg-hint { font-size: 11px; color: #8c8c8c; line-height: 1.5; padding: 2px 6px 0; display: block; }
/* 库存货值：占比用一条细进度条 + 百分比，比纯数字更直观。 */
.value-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; margin: 12px 0 4px; font-size: 13px; color: #595959; }
.value-bar { position: relative; display: flex; align-items: center; gap: 8px; }
.value-bar-fill { height: 8px; min-width: 2px; border-radius: 4px; background: linear-gradient(90deg, var(--d-blue), var(--d-blue-2, #93C5FD)); flex: none; max-width: 76px; }
.value-bar-text { flex: none; font-variant-numeric: tabular-nums; color: #595959; }
/* 库存货值 · 按店铺：合计行压一道底色 —— 明细里混着「未对应」这种非店铺行，
   没有这道底色扫读时容易把两段加在一起（规范 §3.1：色块也要带文字冗余，行里本就写着「合计」）。 */
.ant-table-tbody tr.is-total > td { background: rgba(0, 0, 0, .035); font-weight: 600; }
/* 手机端「按店铺」卡片底部的合计行（总额 · 在售/不在售），跟 .value-toolbar 一个观感 */
.value-total { display: flex; flex-wrap: wrap; gap: 4px 16px; padding: 10px 2px 0;
  font-size: 12px; color: #595959; font-variant-numeric: tabular-nums; }

/* 进货链接「显示已隐藏」开关：一行开关 + 文案；被隐藏的行走淡底 + 「不在库存」标记。 */
.stock-empty-state { padding: 48px 0; }
.stock-filter-switch { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: #595959; cursor: pointer; white-space: nowrap; user-select: none; }
.stock-filter-switch .ant-switch { flex: none; }
.stock-filter-switch.is-disabled { cursor: not-allowed; color: rgba(0, 0, 0, 0.25); }
.stock-filter-switch-label { font-variant-numeric: tabular-nums; }
tr.purchase-row-hidden > td { background: #fafafa; }
tr.purchase-row-hidden:hover > td { background: #f5f5f5; }
.purchase-code-hidden { color: rgba(0, 0, 0, 0.45) !important; font-weight: 400 !important; }
.purchase-hidden-tag.ant-tag { margin-left: 6px; padding: 0 5px; font-size: 11px; line-height: 17px; color: #8c8c8c; background: #f5f5f5; border-color: #e0e0e0; }
/* 销售统计：日期快捷项 7 个，给左侧列表加个高度上限，免得把日历面板撑高。 */
.sales-range-presets .ant-picker-ranges { max-height: 268px; overflow-y: auto; }
.sales-range-presets .ant-picker-ranges > li { padding: 4px 12px; }
/* 手机上日期面板的预设行会被裁到视口外（预设是 inline 排开、整个下拉溢出但不可滚动）。
   把预设改成多列换行，再让两个日历在窄屏上竖排，免得它们把预设往右边挤没。 */
@media (max-width: 480px) {
  .sales-range-presets {
    width: calc(100vw - 16px) !important;
    max-width: 360px;
  }
  .sales-range-presets .ant-picker-ranges {
    display: flex;
    flex-wrap: wrap;
    max-height: none;
    border-bottom: 1px solid #f0f0f0;
    padding: 4px 8px 6px;
  }
  .sales-range-presets .ant-picker-ranges > li {
    flex: 0 0 auto;
    margin-bottom: 2px;
  }
  .sales-range-presets .ant-picker-panels {
    display: flex;
    flex-direction: column;
  }
  .sales-range-presets .ant-picker-panel {
    border-left: 0 !important;
  }
}

/* 同商品 SKU 弹窗：整体高度锁在屏幕内，只有表格主体滚动，表头与首列固定。 */
.sku-group-modal .sku-group-summary { position: sticky; top: 0; z-index: 3; background: #fff; margin-bottom: 8px; padding: 4px 0; }
.sku-group-modal .ant-table-body { overscroll-behavior: contain; }
.sku-group-modal .ant-table-thead > tr > th { background: #fafafa; }
.sku-group-modal .ant-table-cell-fix-left { box-shadow: 6px 0 6px -4px rgba(0, 0, 0, 0.12); }

/* 销售统计：更新时间 + 缓存标记 + 刷新按钮 */
.sales-updated { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; }
.sales-updated .anticon { color: #8c8c8c; }
.sales-cache-tag { margin-left: 2px; margin-right: 0; font-size: 11px; line-height: 16px; padding: 0 5px; }

@media (max-width: 991px) { .tab-pane { padding: 20px; } }
@media (max-width: 768px) {
  .tab-pane { padding: 16px; }
  /* 顶栏高度统一交给文件末尾「方向 04 公共层」那层管（桌面 54 / 手机 52）。
     这里不再写 height/min-height —— 老代码写了 min-height:72px，会把新层压回去。 */
  .app-header { padding: 0 14px; gap: 10px; }
  .app-header > .ant-space { gap: 8px !important; }
  /* 手机上标题栏只留当前页名，前缀和同步时间都收掉，否则会换行把 header 撑高 */
  .header-prefix, .header-sync { display: none; }
  .page-heading { display: block; }
  .page-heading > .ant-tag { margin-top: 10px; }
  .content-card > .ant-card-head { height: auto; padding: 14px 16px; }
  /* 手机上卡片内边距从 24px 收到 16px，多出来的宽度留给内容 */
  .content-card > .ant-card-body { padding: 14px 16px; }
  /* 手机上卡片标题和右上角工具栏改成上下两行。
     注意 .ant-card-head-wrapper 是 .ant-card-head 的子元素、不是 .ant-card 的子元素，
     所以不能用 `.content-card > .ant-card-head-wrapper`（写了也匹配不到，标题会被工具栏
     挤成一条竖线）。同理 .ant-card-extra 默认是 float:right，要显式清掉才会换行。
     另外别只圈 .content-card：库存页有张普通 .ant-card 把控件放在 **标题区** 里。 */
  .app-content .ant-card-head > .ant-card-head-wrapper { display: block; }
  .app-content .ant-card-head > .ant-card-head-wrapper > .ant-card-extra { float: none; margin-left: 0; margin-top: 12px; }
  /* 标题区和工具栏里的控件（搜索框+下拉+标签+数字框，一屏放不下）允许换行，
     否则会把整张卡片顶得比视口还宽、页面横向能拖。 */
  .app-content .ant-card-head .ant-card-extra,
  .app-content .ant-card-head .ant-card-head-title,
  .app-content .ant-card-head .ant-card-extra .ant-space,
  .app-content .ant-card-head .ant-card-extra .ant-space-item,
  .app-content .ant-card-head .ant-card-head-title .ant-space,
  .app-content .ant-card-head .ant-card-head-title .ant-space-item { max-width: 100% !important; min-width: 0; }
  .app-content .ant-card-head .ant-space { flex-wrap: wrap !important; }
  .content-card > .ant-card-head .ant-input { width: calc(100vw - 160px) !important; }
  .content-card > .ant-card-head .ant-select { width: 120px !important; }
  /* 待入库：筛选框自己算宽度，别套用上面那条 calc(100vw - 160px)（会把 150px 的搜索框撑破） */
  .inbound-page .content-card > .ant-card-head .ant-input { width: 100% !important; }
  .inbound-page .stat-card { min-height: 86px; }
  .inbound-page .stat-card .ant-card-body { padding: 10px 12px; gap: 2px; }
  .inbound-page .stat-card .ant-statistic-title { font-size: 12px; margin-bottom: 2px; }
  .inbound-page .stat-card .ant-statistic-content { font-size: 20px; }
  .inbound-card-actions .ant-btn { flex: 1 1 auto; }
  /* 出入库记录弹窗：手机上铺满可用宽度，别用 antd 默认的 520px */
  .sku-record-modal { max-width: calc(100vw - 24px); margin: 12px auto; }
  .sku-record-modal .ant-modal-body { padding: 12px; }
  .sku-record-toolbar { align-items: flex-start; }
}

/* ── 手机端外壳：侧栏收进抽屉 ──────────────────────────────────────────
   桌面是「整页锁死视口高度、只有内容区自己滚」，手机不能这么干：键盘弹出、
   地址栏收起都会改视口高度，锁 100vh 会把内容裁掉。窄屏改成整页自然滚动。 */
.app-layout.is-narrow { height: auto; min-height: 100vh; overflow: visible; }
.app-layout.is-narrow > .ant-layout { height: auto; min-height: 0; }
/* 窄屏是整页自然滚动（不是外壳滚），所以 pane 也别锁自己的滚动条，不然内容会被裁掉 */
.app-layout.is-narrow .app-content, .app-layout.is-narrow .tab-pane { overflow: visible; }
.app-layout.is-narrow .app-tabbar { padding: 8px 12px 0; }
.app-layout.is-narrow .app-tab { height: 30px; font-size: 12px; padding-left: 10px; }
/* 窄屏页签空间金贵：图标藏掉，文字 + × 就够 */
.app-layout.is-narrow .app-tab-icon { display: none; }
.app-layout.is-narrow .app-tab-text { max-width: 110px; }
/* 手机上没有 hover，刷新/关闭按钮常显（不然点不到） */
.app-layout.is-narrow .app-tab-refresh, .app-layout.is-narrow .app-tab-close { opacity: 1; }
.app-header-title { display: flex; align-items: center; min-width: 0; white-space: nowrap; }
.header-prefix, .header-sync { white-space: nowrap; }
.nav-toggle { flex: 0 0 auto; margin-right: 4px; padding: 0 8px; font-size: 17px; }
/* 抽屉里复用侧栏那套 logo / 菜单 / 底部按钮，只把高度分配改回 flex 即可 */
.app-nav-drawer .ant-drawer-body { display: flex; flex-direction: column; padding: 0; }
.app-nav-drawer .ant-drawer-body .app-menu { flex: 1 1 auto; min-height: 0; }

/* ── 入库合并页：快捷入库 / 待入库 两个页签 ─────────────────────────── */
.inbound-hub-tabs .ant-tabs-nav { margin-bottom: 16px; }
/* 页签字号大一点，两个都是重页面，别让人看不清自己在哪一签 */
.inbound-hub-tabs .ant-tabs-tab { font-size: 15px; padding: 10px 4px; }

/* ── 待入库：手机优先的卡片列表 ───────────────────────────────────────
   ⚠️ 2026-09-20 迁移到设计变量（用户反馈「展开行的商品卡片样式太丑了」）：
   这一整块原来全是硬编码的旧色（#fff / #e9eef5 / #1677ff / #ff4d4f / #8c93a0 / #cf1322），
   圆角 10px、还带一条 `box-shadow: 0 1px 3px rgba(16,40,80,.04)` 的自定义阴影 ——
   跟方向 04 那套 token 完全不搭，跟别处的卡放一起很跳。

   现在统一（跟 .scard / .skcard 一致）：
   · 底色 --d-surface、描边 --d-line-2、圆角 --d-r-md（16px）
   · 去掉自定义阴影（设计系统只有 --d-sh-1 / --d-sh-2 两级，这里不需要）
   · 弱文字 --d-ink-3、警示 --d-red-soft / --d-red-ink / --d-red
   ══════════════════════════════════════════════════════════════════════════ */
.inbound-cards { display: flex; flex-direction: column; gap: 10px; }
.inbound-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 12px; background: var(--d-surface);
  border: 1px solid var(--d-line-2); border-radius: var(--d-r-md);
}
.inbound-card.is-selected { border-color: var(--d-blue); background: var(--d-blue-soft); }
.inbound-card-head { display: flex; align-items: center; gap: 8px; }
.inbound-card-title { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.inbound-card-title .ant-tag { margin: 0; }
.inbound-card-amount { flex: 0 0 auto; font-weight: 600; font-variant-numeric: tabular-nums; }
.inbound-card-meta { display: flex; flex-wrap: wrap; gap: 6px; }
.inbound-card-meta .ant-tag { margin: 0; }
.inbound-card-sub { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: 12px; color: var(--d-ink-3); }
.inbound-card-actions { display: flex; flex-wrap: wrap; }
/* 行内按钮收敛成「明细 / 收货 / 一键入库 + ⋯」（2026-09-28）：⋯ 是下拉触发器，
   手机上那条 `.ant-btn { flex: 1 1 auto }` 别把它拉成一根大宽条 —— 它本来就该这么窄。 */
.inbound-card-actions .ibd-more { flex: 0 0 auto; }
/* ── 入库单运单号 + 物流轨迹（2026-09-28 用户要求「入库单加个运单号，然后实现跟踪
   物流进度」）────────────────────────────────────────────────────────────────
   三处复用同一套样式：表格列、手机卡片、展开明细里都用 .wb-no 显示单号 ——
   单号是**轨迹的入口**（点了弹轨迹），所以三处长得必须一模一样，用户才学得会。 */
.wb-col { display: flex; flex-direction: column; gap: 2px; align-items: flex-start; }
.wb-card-waybill { display: inline-flex; align-items: center; gap: 6px; }
.wb-no {
  font-variant-numeric: tabular-nums; cursor: pointer; text-decoration: none;
  border-bottom: 1px dashed transparent;
}
.wb-no:hover { color: #1677ff; border-bottom-color: #1677ff; }
.wb-none { font-size: 12px; color: var(--d-ink-3); }
/* 超出 2 条时的「+N」（表格列 / 手机卡片里都用它收尾） */
.wb-more { font-size: 12px; color: var(--d-ink-3); font-variant-numeric: tabular-nums; }
/* 运单号编辑弹窗底部：「再加一条」+ 一行灰字说明 */
.wb-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.wb-detail { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.wb-detail-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 13px; padding: 8px 10px; background: var(--d-line);
  border-radius: var(--d-r-sm, 6px);
}
.wb-detail-row .wb-no { font-weight: 600; }
/* 运单号编辑弹窗里的行：单号 + 快递公司 + 备注 + 删除 */
.wb-edit-list { display: flex; flex-direction: column; gap: 10px; }
.wb-edit-row { display: flex; gap: 8px; align-items: flex-start; flex-wrap: wrap; }
.wb-edit-row .wb-no-input { flex: 1 1 200px; min-width: 160px; }
.wb-edit-row .wb-com { flex: 0 1 150px; min-width: 130px; }
/* 寄件人手机后四位（中通 / 顺丰 / 跨越查轨迹要）：4 位数字而已，给窄一格，
   手机上放不下时整行会 wrap，不会把运单号那格挤没。 */
.wb-edit-row .wb-tail { flex: 0 1 96px; min-width: 84px; }
.wb-edit-row .wb-note { flex: 1 1 140px; min-width: 120px; }
/* 轨迹时间轴：自己画（antd 没引 Timeline），左竖线 + 圆点，最新一条在最上面 */
.wb-trace-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.wb-trace-list { margin-top: 12px; max-height: 54vh; overflow: auto; padding: 4px 4px 4px 0; }
.wb-trace-item {
  position: relative; padding: 0 0 16px 22px;
  border-left: 2px solid var(--d-line-2);
}
.wb-trace-item:last-child { border-left-color: transparent; padding-bottom: 0; }
.wb-trace-item::before {
  content: ''; position: absolute; left: -6px; top: 3px; width: 10px; height: 10px;
  border-radius: 50%; background: var(--d-ink-4); border: 2px solid #fff; box-sizing: content-box;
}
.wb-trace-item.is-latest::before { background: #1677ff; }
.wb-trace-time { font-size: 12px; color: var(--d-ink-3); font-variant-numeric: tabular-nums; }
.wb-trace-text { font-size: 13px; line-height: 1.55; word-break: break-word; }
.wb-trace-item.is-latest .wb-trace-text { font-weight: 600; }
.wb-trace-item.is-latest .wb-trace-time { color: var(--d-ink-2); }
/* 表头展开列那个「一键展开」小加号（2026-09-21 用户要求居中）：
   antd 把表头单元格定成 `text-align: left` + `padding: 12px 8px`，而行首那个同款图标
   在单元格里是正中的 —— 结果表头这格就歪在左边了（实测左 9px / 右 24px）。
   这里只把这一格改回居中，跟行首图标、跟「全选」那格对齐。 */
.inbound-page .ant-table-thead > tr > th.ant-table-row-expand-icon-cell {
  text-align: center;
}
/* 表头这格的字色继承表头的 --d-ink-3（弱化灰 #9CA3AF），而行首同款图标继承 td 的
   --d-ink-2（正文灰 #6B7280）—— 同一个图标一深一浅，用户一眼就看出「不是同一个东西」。
   图标里的 +/− 是 ::before/::after 画底色（currentColor），所以 color 一改就全改了。 */
.inbound-page .ant-table-thead > tr > th.ant-table-row-expand-icon-cell button.ant-table-row-expand-icon {
  color: var(--d-ink-2);
}
.inbound-detail { border-top: 1px dashed var(--d-line-2); padding-top: 12px; }
/* 待入库展开行：一个商品一张卡片（原来桌面是表格、手机是行，统一成卡片）。
   「缺」的整卡标红（红底 + 左侧红条），跟「没到货的排最前面」配合着看。

   ⚠️ 只有**真的缺**（收过一部分、这几件没到）才标红。整单一件都没收过时是「待收」，
   属于正常待办，不上红 —— 一屏十几张全红底，红色就不值钱了。
   2026-09-21：卡宽 236 → 300，因为下面那行数字块要放 4 格（应收/已收/待收/单价），
   236 减去内边距只剩 212，4 格每格不到 50px，「¥128.00」会被省略号吃掉。 */
.inbound-detail-cards { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.inbound-detail-card {
  display: flex; flex-direction: column; gap: 12px;
  padding: 12px; border: 1px solid var(--d-line-2); border-radius: var(--d-r-md);
  background: var(--d-surface);
}
.inbound-detail-card.is-short { border-color: var(--d-red-soft); background: var(--d-red-soft);
  box-shadow: inset 3px 0 0 var(--d-red); }
.inbound-detail-card-top { display: flex; align-items: center; gap: 12px; min-width: 0; }
.inbound-detail-card-title { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.inbound-detail-card-title .ship-code { font-size: 13px; font-weight: 600; }
.inbound-detail-card-spec { font-size: 12px; color: var(--d-ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── 数字块：标签小灰字在上、数字大号在下（待入库明细卡 + 收货弹窗 SKU 卡共用）──
   原来这套只在手机端有，桌面端用的是 antd Tag 行：三个彩色胶囊（应收蓝 / 已收绿 / 缺红）
   挤在一张卡里，又吵又分不出重点，数字还是 12px 的 Tag 字号。
   2026-09-21 两端统一成这套（设计规范 §2.4：桌面和手机共用同一套单元格渲染器，
   别抄两份，口径会漂）—— 只有字号分档，桌面 11/15，手机 12/16（见文件末尾媒体查询）。 */
.ibd-nums { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.ibd-nums.is-three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ibd-num { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ibd-num-k { font-size: 11px; line-height: 1.3; color: var(--d-ink-3); white-space: nowrap; }
.ibd-num-v {
  font-size: 15px; font-weight: 600; line-height: 1.35;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.ibd-num.is-red .ibd-num-v { color: var(--d-red-ink); }
.ibd-num-v, .ibd-num-k { overflow: hidden; text-overflow: ellipsis; }
/* 库位是文字（LOC-01）不是数字，占满一行、不跟数字抢格子 */
.ibd-loc { grid-column: 1 / -1; display: flex; align-items: baseline; gap: 4px;
  font-size: 13px; font-weight: 600; color: var(--d-ink-2);
  font-variant-numeric: tabular-nums; word-break: break-all; }
.ibd-loc .ibd-num-k { font-weight: 400; }
.inbound-bulkbar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  margin-bottom: 12px; padding: 10px 12px;
  background: var(--d-blue-soft); border: 1px solid var(--d-blue-soft); border-radius: var(--d-r-md);
}
.inbound-edit-meta { display: flex; flex-wrap: wrap; gap: 4px 18px; margin-bottom: 10px; }
/* 编辑弹窗里「加商品」的搜索框 */
.inbound-edit-add { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.inbound-edit-spec { color: var(--d-ink-3); font-size: 12px; }
/* 入库单里的 SKU 行：缩略图 + 编码/规格并排。min-width:0 是让长编码能省略而不是撑破格子 */
.inbound-item-cell { display: flex; align-items: center; gap: 8px; }
.inbound-item-text { min-width: 0; }
.inbound-detail-sku { display: flex; align-items: center; gap: 8px; }
.inbound-detail-sku .ship-code { font-weight: 600; }
/* 收货弹窗在手机上把「本次实收 / 散件 / 库位」摊成两列，省得横着拖表格 */
.inbound-field-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 10px; }
.inbound-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.inbound-field > span { color: var(--d-ink-3); font-size: 12px; }

/* 创建入库单弹窗：类型/仓库/外部单号三个并排（窄屏两列自动换行），下面备注 + 商品区 */
.inbound-create-form { display: flex; flex-direction: column; gap: 12px; }
.inbound-create-head { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px 10px; }
.inbound-create-head .inbound-field:last-child { grid-column: auto; }
.inbound-create-items { border-top: 1px dashed #e9eef5; padding-top: 10px; }
.inbound-create-items .ant-empty { margin: 12px 0 4px; }
/* 搜商品那行：左边提示「搜到 N 个规格 · 点一下加一个（可连点）」，右边给一个「全部加入（N）」兜底按钮 */
.inbound-search-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.inbound-search-head .ant-btn { padding: 0; height: auto; }
/* 下拉项的点击区域：铺满整行，点哪儿都算「加入这一项」（点击处理挂在它身上，
   见 app.js 里的说明 —— 不让 antd 处理这次点击，否则输入框会被改写、下拉会收起）。 */
.inbound-opt-label { display: block; width: 100%; cursor: pointer; }
/* 下拉里已经加进单子的规格：文字后面挂个灰标，连点时不至于重复点
   （点重复了只弹提示、不会加两行）。
   ⚠️ 用 inline-block 紧跟文字，别用 float: right —— 下拉项的 `.ant-select-item-option-content`
   带 `overflow: hidden` + `text-overflow: ellipsis`，浮到右边会被省略号逻辑吃掉。 */
.inbound-opt-added {
  display: inline-block; margin-left: 8px; padding: 0 5px; border-radius: 3px;
  background: #f0f0f0; color: rgba(0, 0, 0, .45);
  font-size: 11px; line-height: 16px; vertical-align: 1px;
}
/* 批量填数量 / 按成本价填进货价 */
.inbound-bulkfill {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin-top: 10px; padding: 8px 10px; background: #fafafa;
  border: 1px solid #f0f0f0; border-radius: 6px; font-size: 13px;
}
.inbound-create-footer { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
@media (max-width: 768px) {
  .inbound-create-head { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .inbound-create-footer { flex-direction: column-reverse; align-items: stretch; }
  .inbound-create-footer > .ant-space { justify-content: flex-end; }
}

/* ── 欠货台账（部分入库里没到货的商品）─────────────────────────────────
   行级标红 + 明细里「未入库」排最前面，都是为了「一单几十个 SKU 时，
   缺哪几个能一眼看到」。清单按单分组，卡片头压一行关键信息。 */
/* 页签行到下面统计卡的间距由 .page-stack > * + * 统一给（16px），这里不再单独留 margin */
.inbound-tabs { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.inbound-tabs .ant-radio-group,
.pill-tabs .ant-radio-group { display: flex; flex-wrap: wrap; gap: 6px; }
.inbound-tabs-note { margin: 0; }

/* ── 筛选胶囊（共用类 .pill-tabs）：入库页状态页签 + 销售趋势图的指标切换 ──
   （§3.4）───────────────────────
   ⚠️ 2026-09-20 修（用户反馈「第一排的几个按钮样式没改，很不和谐」）：
   这里是 antd 的 `Radio.Group optionType:'button'`，默认渲染成**连体矩形** ——
   硬边框 + 直角 + 按钮之间一条分割线，跟设计系统的胶囊语言完全不搭。
   外层 `.inbound-tabs` 只改了布局（flex + gap），**按钮本身一直没被覆盖过**，
   所以看着像「忘了改」。

   现在按 `.spill` 那套对齐：独立胶囊、无边框、未选浅灰底、选中浅蓝底 + 蓝字。
   数字跟着 label 一起走，不用单独处理（它是同一个按钮里的文本）。 */
.pill-tabs .ant-radio-button-wrapper {
  height: 30px; line-height: 28px; padding: 0 12px;
  border: none !important; border-radius: var(--d-r-pill) !important;
  background: var(--d-panel); color: var(--d-ink-2);
  font-size: 11.5px; font-weight: 700; white-space: nowrap;
  transition: background .15s, color .15s;
}
/* antd 给「非第一个」按钮加的左分割线（::before）—— 独立胶囊之间不要它 */
.pill-tabs .ant-radio-button-wrapper::before { display: none !important; }
.pill-tabs .ant-radio-button-wrapper:hover { color: var(--d-blue); background: var(--d-blue-soft); }
.pill-tabs .ant-radio-button-wrapper-checked,
.pill-tabs .ant-radio-button-wrapper-checked:first-child {
  background: var(--d-blue-soft) !important; color: var(--d-blue) !important;
  border: none !important; box-shadow: none !important;
}
/* 键盘聚焦时给个可见轮廓（antd 默认那圈蓝框在胶囊上很难看） */
.pill-tabs .ant-radio-button-wrapper:focus-within { outline: 2px solid var(--d-blue-soft); outline-offset: 1px; }
/* 进货月份选择：靠右，跟页签同一行 */
/* 进货月份：2026-09-18 从状态页签行挪到页内标题右侧，靠 .shead-right 收边所以不用再 margin-left:auto */
.inbound-month-pick { display: flex; align-items: center; gap: 6px; }
/* 月度进货统计卡：销售统计页那套 .stat-card，收紧尺寸（标题/图标/数字都小一号） */
.stat-card.is-compact { min-height: 0; }
.stat-card.is-compact .ant-card-body { padding: 10px 14px; gap: 3px; }
.stat-card.is-compact .stat-title { font-size: 13px; }
.stat-card.is-compact .stat-icon { width: 20px; height: 20px; font-size: 11px; }
.stat-card.is-compact .ant-statistic-content { font-size: 20px; }
.stat-card.is-compact .ant-statistic-content-value { font-weight: 600; }
.inbound-short-row > td { background: #fff1f0 !important; }
.inbound-short-row:hover > td { background: #ffe7e5 !important; }
.inbound-short-row > td:first-child { box-shadow: inset 3px 0 0 #ff4d4f; }
.inbound-detail-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; padding-bottom: 12px; }
.inbound-detail-head .ant-tag { margin: 0; }
.inbound-detail-row.is-short { background: var(--d-red-soft); border-left: 3px solid var(--d-red);
  padding-left: 8px; border-radius: var(--d-r-sm); }
.short-missing { color: #cf1322; font-weight: 600; font-variant-numeric: tabular-nums; }
.short-banner { margin-bottom: 0; }
.short-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 12px 0 4px; }
.short-groups { margin-top: 12px; display: flex; flex-direction: column; gap: 12px; }
.short-card { border: 1px solid #ffccc7; border-radius: 8px; overflow: hidden; background: #fff; }
.short-card.is-completed { border-color: #d9d9d9; background: #fafafa; }
.short-card-head {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px;
  padding: 8px 12px; background: #fff7f6; border-bottom: 1px solid #ffe7e5;
}
.short-card.is-completed .short-card-head { background: #f5f5f5; border-bottom-color: #eee; }
.short-card-head .ship-code { font-weight: 600; }
.short-items { display: flex; flex-direction: column; }
.short-item { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; border-bottom: 1px solid #f4f6fa; }
.short-item:last-child { border-bottom: 0; }
.short-item-main { display: flex; align-items: center; gap: 8px; min-width: 0; }
.short-item-text { min-width: 0; }
.short-item-spec { color: #8c8c8c; font-size: 12px; }
.short-item-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.short-item-tags .ant-tag { margin: 0; }
.short-item-controls { display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 8px; }
/* 欠货标记 + 撤回：结清态（不补了 / 已到货收齐）会从「未结清」里消失，多给一个一键撤回按钮。 */
.short-mark-cell { display: flex; align-items: center; gap: 2px; }
.short-mark-cell .ant-btn.short-undo { padding: 0 4px; height: 24px; }
.short-settled-link { padding: 0; height: auto; font-size: 12px; }
.short-confirm-list { max-height: 220px; overflow: auto; font-size: 12.5px; line-height: 1.9; }
.short-confirm-list .ship-code { margin-right: 6px; }
@media (max-width: 768px) {
  /* 页签在手机上会超宽：让它们自己横滚，别把整页顶宽；欠货汇总换到第二行显示 */
  .inbound-tabs { flex-direction: column; align-items: flex-start; gap: 6px; }
  .inbound-tabs .ant-radio-group { max-width: 100%; overflow-x: auto; flex-wrap: nowrap; padding-bottom: 2px; }
  /* 月份选择在手机上不跟页签抢一行，自己占一行靠左 */
  .inbound-month-pick { margin-left: 0; }
  .short-card-head { align-items: flex-start; }
  .short-item-controls { grid-template-columns: minmax(0, 1fr); }
}

/* 接口设置 → 多电脑数据同步：说明文字逐行排开 */
.sync-info { line-height: 1.9; }

/* ── SKU 出入库记录弹窗 ─────────────────────────────────────────────── */
.sku-record-sku { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; }
.sku-record-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 8px 12px; margin-bottom: 12px;
}
.sku-record-summary { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px; font-size: 13px; color: #4b5563; }
.sku-record-hint { display: flex; align-items: center; justify-content: center; padding: 48px 0; }
/* 手机：一条流水一张卡，数量/结存/单据号一屏能读全，不用横着拖表格 */
.sku-record-cards { display: flex; flex-direction: column; gap: 8px; }
.sku-record-card { padding: 10px 12px; border: 1px solid #e8edf5; border-radius: 10px; background: #fff; }
.sku-record-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.sku-record-card-head .ant-tag { margin: 0; }
.sku-record-card-qty { font-size: 15px; font-variant-numeric: tabular-nums; }
.sku-record-card-meta {
  display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 6px;
  font-size: 12.5px; color: #4b5563; font-variant-numeric: tabular-nums;
}
.sku-record-card-sub {
  display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 4px;
  font-size: 12px; color: #8c8c8c; word-break: break-all;
}

/* 店铺销售对比 → 推广费单元格：金额 + 铅笔按钮 */
.promo-cell { display: inline-flex; align-items: center; justify-content: flex-end; gap: 2px; }
.promo-cell .ant-btn-text { padding: 0 4px; color: #1677ff; }
/* 订单数 / 件数后面跟的「剔了多少赠品单」角标 */
.gift-trim {
  display: inline-block; margin-left: 4px; padding: 0 4px;
  font-size: 11px; line-height: 16px; font-variant-numeric: tabular-nums;
  color: #722ed1; background: #f9f0ff; border: 1px solid #d3adf7; border-radius: 8px;
  cursor: help; vertical-align: 1px;
}
.gift-trim.is-warn { color: #d46b08; background: #fff7e6; border-color: #ffd591; }
/* 刷单剔除标记：跟赠品单（紫）区分开，用品红。 */
.gift-trim.is-brush { color: #c41d7f; background: #fff0f6; border-color: #ffadd2; }

/* 推广费按天录入弹窗：每天一行，列表长了在弹窗内部滚动 */
.promo-day-list { max-height: 46vh; overflow-y: auto; margin: 4px 0 12px; }
.promo-day-row {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 2px; border-bottom: 1px solid #f0f0f0;
}
.promo-day-row:last-child { border-bottom: none; }
.promo-day-date { font-variant-numeric: tabular-nums; color: #262626; }
.promo-day-week { width: 32px; color: #8c8c8c; font-size: 12px; }
.promo-day-row .ant-input-number { margin-left: auto; }
.promo-day-sum {
  display: flex; align-items: center; justify-content: space-between;
  padding-top: 10px; border-top: 1px solid #f0f0f0; color: #595959;
}
/* 区间合计的金额：原来是内联 style 写死 #1677ff（旧主色），改走公共层 token */
.promo-day-sum-num { color: var(--d-blue); font-variant-numeric: tabular-nums; }
.promo-modal-footer { display: flex; align-items: center; justify-content: space-between; }

/* ── 快捷入库（1688 → 优易 ERP）：原生 React 页面的布局样式 ───────────── */
.qe-page { display: flex; flex-direction: column; gap: 14px; }
/* 页内标题自带 margin-bottom，flex gap 会叠加 → 归零，间距交给 gap（2026-09-18 设计稿改版） */
.qe-page > .shead { margin-bottom: 0; }
.qe-loading { padding: 70px 0; display: flex; flex-direction: column; align-items: center; gap: 14px; }

/* 步骤条：做成一条浅色卡片，和页面里其它卡片同一套语言 */
.qe-steps { background: var(--d-surface); border: 1px solid var(--d-line-2); border-radius: var(--d-r-md);
  padding: 18px 26px; box-shadow: var(--d-sh-1); }
.qe-steps .ant-steps-item-title { font-size: 13.5px; font-weight: 700; color: var(--d-ink); }
.qe-steps .ant-steps-item-description { font-size: 12px; }
.qe-steps .ant-steps-item-icon { box-shadow: none; }

/* 区块标题 */
.qe-section-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.qe-section-heading h2 { margin: 0; font-size: 15.5px; font-weight: 800; letter-spacing: -.025em; color: var(--d-ink); }
.qe-section-heading p { margin: 5px 0 0; color: var(--d-ink-3); font-size: 12px; line-height: 1.65; max-width: 760px; }
.qe-head-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.qe-sync-note { display: flex; align-items: flex-start; gap: 6px; margin-top: 8px; padding: 7px 11px; border-radius: 8px; background: #f6faff; border: 1px solid #e2eefc; color: #5b6b82; font-size: 11.5px; line-height: 1.55; }
.qe-sync-note .anticon { margin-top: 2px; color: #3b7ddd; }

/* 导入文件：两块分组（每天要传 / 常驻资料） */
.qe-setup-body { display: flex; flex-direction: column; gap: 18px; }
.qe-group { display: flex; flex-direction: column; gap: 12px; }
.qe-group-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.qe-group-title { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 700; color: #172033; }
.qe-group-title::before { content: ''; width: 3px; height: 13px; border-radius: 2px; background: #1677ff; }
.qe-group.is-compact .qe-group-title::before { background: #c7d0dc; }
.qe-group.is-compact .qe-group-title { color: #667085; }
.qe-group-hint { font-size: 12px; color: #98a2b3; }

/* 每天要传：两张并排的主卡 */
.qe-upload-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 900px) { .qe-upload-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* 常驻资料：三张紧凑卡 */
.qe-upload-grid.is-compact { gap: 12px; }
@media (min-width: 700px) { .qe-upload-grid.is-compact { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1150px) { .qe-upload-grid.is-compact { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* 两列时第三张跨列，避免最后一行留空位 */
@media (min-width: 700px) and (max-width: 1149px) { .qe-upload-grid.is-compact > .qe-upload-card:last-child { grid-column: span 2; } }

.qe-upload-card { height: 100%; border: 1px solid #eef1f6; border-radius: 12px; box-shadow: 0 1px 3px rgba(16, 40, 80, .035); transition: box-shadow .18s ease, transform .18s ease, border-color .18s ease; }
.qe-upload-card:hover { border-color: #cfe0f8; box-shadow: 0 8px 22px rgba(22, 119, 255, .10); transform: translateY(-2px); }
.qe-upload-card .ant-card-body { height: 100%; display: flex; flex-direction: column; gap: 11px; padding: 18px; }
.qe-upload-card.is-required { border-color: #cfe0f8; background: linear-gradient(180deg, #f7fbff, #fff 46%); }
/* 常驻资料卡：整体弱化一档，别跟每天要传的抢注意力 */
.qe-upload-card.is-compact { background: #fcfdfe; }
.qe-upload-card.is-compact .ant-card-body { gap: 8px; padding: 14px; }
.qe-upload-card.is-compact .qe-upload-icon { width: 28px; height: 28px; border-radius: 8px; font-size: 14px; }
.qe-upload-card.is-compact h3 { font-size: 13.5px; }
.qe-upload-card.is-compact p { font-size: 11.5px; line-height: 1.55; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.qe-upload-card.is-compact .qe-file-status { white-space: nowrap; overflow: hidden; }
.qe-upload-card.is-compact .qe-file-status > span { -webkit-line-clamp: 1; }
.qe-upload-top { display: flex; align-items: center; gap: 10px; min-width: 0; }
.qe-upload-icon { flex: none; width: 34px; height: 34px; border-radius: 10px; display: inline-flex; align-items: center; justify-content: center; font-size: 16px; }
.qe-upload-icon.blue { background: #eaf1fb; color: #3b7ddd; }
.qe-upload-icon.cyan { background: #e6f5f4; color: #3a9d96; }
.qe-upload-icon.orange { background: #fbeede; color: #d98c45; }
.qe-upload-icon.green { background: #e8f4ea; color: #5a9e63; }
.qe-upload-icon.purple { background: #f0ecf8; color: #7c6bb0; }
.qe-upload-heading { min-width: 0; }
.qe-upload-kicker { font-size: 11px; font-weight: 600; letter-spacing: .06em; color: #98a2b3; }
.qe-upload-card h3 { margin: 2px 0 0; font-size: 14.5px; font-weight: 600; color: #172033; }
.qe-upload-card p { margin: 0; font-size: 12.5px; line-height: 1.65; color: #8a94a6; flex: 1; }
.qe-upload-foot { display: flex; flex-direction: column; align-items: flex-start; gap: 9px; margin-top: 2px; }
/* 一键拉取行：日期 + 按钮并排，跟在「选择订单网页」按钮下面 */
.qe-pull-row { display: flex; align-items: center; gap: 8px; width: 100%; }
.qe-pull-row .ant-picker { flex: 0 0 auto; }
.qe-pull-row .ant-btn { flex: 1 1 auto; min-width: 0; }

/* 文件状态：小圆点 + 两行截断 */
.qe-file-status { display: flex; align-items: flex-start; gap: 6px; width: 100%; font-size: 11.5px; line-height: 1.5; color: #98a2b3; min-width: 0; }
.qe-file-status::before { content: ''; flex: none; width: 6px; height: 6px; margin-top: 5px; border-radius: 50%; background: #d0d5dd; }
.qe-file-status > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.qe-file-status.ready { color: #5a9e63; }
.qe-file-status.ready::before { background: #5a9e63; }
.qe-file-status.error { color: #d9534f; }
.qe-file-status.error::before { background: #d9534f; }

/* 仓库 / 类型设置条：整页的最后一步，上下多留一点气 */
.qe-settings-row { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; margin-top: 6px; padding: 16px 18px; background: #fff; border: 1px solid #eef1f6; border-radius: 12px; box-shadow: 0 1px 3px rgba(16, 40, 80, .035); }
.qe-settings-row label { display: inline-flex; align-items: center; gap: 9px; font-size: 12.5px; color: #667085; }
.qe-settings-row .qe-settings-spacer { flex: 1 1 auto; }

/* 工具栏 / 汇总标签 */
.qe-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.qe-pills { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.qe-pills .ant-tag { margin: 0; border-radius: 20px; padding: 2px 11px; font-size: 12px; }
.qe-help { font-size: 12px; color: #98a2b3; line-height: 1.65; }
.qe-sub-text { font-size: 11.5px; color: #98a2b3; margin-top: 2px; }

/* 核对对应：每行「1688 订单规格 → 优易 ERP 规格」对比卡 */
.qe-match-list { display: flex; flex-direction: column; gap: 14px; }
.qe-match-card { position: relative; overflow: hidden; border: 1px solid #eef1f6; border-radius: 12px; box-shadow: 0 1px 3px rgba(16, 40, 80, .035); }
.qe-match-card::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: #d0d5dd; }
.qe-match-card.status-success::before { background: #52c41a; }
.qe-match-card.status-error::before { background: #ff4d4f; }
.qe-match-card.status-processing::before { background: #1677ff; }
.qe-match-card .ant-card-body { padding: 14px 16px 14px 20px; }
/* 已记忆的规格（`item.remembered` = 命中历史映射、自动套用）：整卡淡蓝底 + 蓝描边，
   跟需要人工核对的「待确认」行一眼分开。⚠️ 别动左边那条 3px 状态色条 ——
   它表示 已确认/异常/待确认，跟「是否已记忆」是两个维度，两者可以同时出现。 */
.qe-match-card.is-remembered { background: #f5f9ff; border-color: #cfe2ff; }
.qe-match-card.is-remembered:hover { box-shadow: 0 3px 10px rgba(22, 119, 255, .10); }
.qe-match-head-tags { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.qe-remembered-tag {
  margin: 0 !important; border-radius: 20px; font-size: 12px;
  background: #e6f4ff; border-color: #91caff; color: #0958d9;
}
.qe-match-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; }
.qe-match-meta { font-size: 12px; color: #98a2b3; }
.qe-match-meta b { color: #475467; font-weight: 600; }

.qe-compare { display: grid; grid-template-columns: minmax(0, 1fr) 26px minmax(0, 1fr) 158px; gap: 12px; align-items: stretch; }
.qe-side { display: flex; flex-direction: column; min-width: 0; border: 1px solid #eef1f6; border-radius: 10px; background: #fcfdfe; }
.qe-side.source { background: #fbfcfe; }
.qe-side.target { background: #f6faff; border-color: #e2eefc; }
.qe-side-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 9px 13px; border-bottom: 1px solid #eef1f6; }
.qe-side-label { font-size: 11px; font-weight: 600; letter-spacing: .07em; color: #8a94a6; }
.qe-side-head a { font-size: 11.5px; }
.qe-side-body { flex: 1; display: flex; gap: 13px; padding: 13px; min-width: 0; }
.qe-side-media { flex: none; }
.qe-side-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 9px; }
.qe-spec-main { font-size: 14.5px; font-weight: 600; color: #172033; line-height: 1.4; word-break: break-all; }
.qe-details { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 14px; }
.qe-detail { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.qe-detail-label { flex: none; font-size: 11.5px; color: #98a2b3; }
.qe-detail-value { font-size: 12.5px; color: #33383f; word-break: break-all; min-width: 0; font-variant-numeric: tabular-nums; }
.qe-detail-value.is-final { font-size: 13.5px; font-weight: 700; color: #1677ff; }
.qe-detail-value.is-missing { font-weight: 600; color: #d9534f; }
.qe-source-title { font-size: 11.5px; color: #98a2b3; line-height: 1.55; word-break: break-all; }
.qe-arrow { display: flex; align-items: center; justify-content: center; color: #c7d0dc; font-size: 18px; }
.qe-sku-code { font-family: "SFMono-Regular", Consolas, Menlo, monospace; font-size: 14px; font-weight: 700; color: #1677ff; word-break: break-all; }
.qe-candidate-select { width: 100%; }
.qe-target-tags { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.qe-mini-tag { margin: 0 !important; font-size: 11px; line-height: 18px; border-radius: 20px; }
.qe-target-hint { font-size: 11.5px; color: #98a2b3; line-height: 1.55; }

/* 行操作区：与对比区分开，按钮等宽竖排 */
.qe-actions { display: flex; flex-direction: column; justify-content: center; gap: 8px; padding-left: 12px; border-left: 1px dashed #e6eaf2; }
.qe-actions .ant-btn { width: 100%; }

/* 统计卡（生成入库单 / 进货统计共用） */
.qe-export-stats { row-gap: 16px; }
.qe-export-stat { height: 100%; border: 1px solid #eef1f6; border-radius: 12px; box-shadow: 0 1px 3px rgba(16, 40, 80, .035); }
.qe-export-stat .ant-card-body { padding: 17px 18px; display: flex; flex-direction: column; gap: 5px; }
.qe-export-stat .qe-stat-top { display: flex; align-items: center; gap: 8px; }
.qe-export-stat .qe-stat-icon { flex: none; width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 13px; }
.qe-export-stat .qe-stat-label { font-size: 13px; color: #667085; }
.qe-export-stat strong { font-size: 26px; font-weight: 700; color: #172033; letter-spacing: -.5px; font-variant-numeric: tabular-nums; line-height: 1.2; }
.qe-export-stat.blue .qe-stat-icon { background: #eaf1fb; color: #3b7ddd; }
.qe-export-stat.cyan .qe-stat-icon { background: #e6f5f4; color: #3a9d96; }
.qe-export-stat.orange .qe-stat-icon { background: #fbeede; color: #d98c45; }
.qe-export-stat.green .qe-stat-icon { background: #e8f4ea; color: #5a9e63; }
.qe-export-stat.purple .qe-stat-icon { background: #f0ecf8; color: #7c6bb0; }

/* 生成入库单：操作条 */
.qe-export-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 15px 18px; background: #fff; border: 1px solid #eef1f6; border-radius: 12px; box-shadow: 0 1px 3px rgba(16, 40, 80, .035); }

/* 图片 / 缩略图 */
.qe-thumb { display: inline-flex; flex: none; border-radius: 8px; overflow: hidden; background: #f5f7fa; cursor: zoom-in; }
.qe-thumb .ant-image-img { object-fit: cover; }
.qe-image-placeholder { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; overflow: hidden; padding: 4px; text-align: center; border: 1px dashed #dde3ec; border-radius: 8px; background: #f8fafc; color: #b0b8c4; font-size: 10.5px; line-height: 1.3; }
.qe-image-placeholder-icon { font-size: 18px; color: #cbd3de; }

/* 进货统计：按月柱状 */
.qe-month-bars { display: flex; flex-direction: column; gap: 7px; }
.qe-month-row { display: grid; grid-template-columns: 54px 1fr 94px; align-items: center; gap: 12px; font-size: 12px; }
.qe-month-row > span { color: #98a2b3; }
.qe-month-row > strong { text-align: right; color: #475467; font-weight: 600; font-variant-numeric: tabular-nums; }
.qe-month-track { height: 10px; background: #f2f4f8; border-radius: 6px; overflow: hidden; }
.qe-month-track > i { display: block; height: 100%; border-radius: 6px; background: linear-gradient(90deg, #9cc9ff, #1677ff); transition: width .3s ease; }
.qe-month-row.is-current > span { color: #1677ff; font-weight: 700; }
.qe-month-row.is-current > strong { color: #1677ff; }

/* 商品编码查进货链接 */
.qe-lookup-row { display: flex; align-items: center; gap: 8px; }
.qe-lookup-row .ant-input-affix-wrapper, .qe-lookup-row .ant-input { flex: 1; min-width: 0; }
.qe-link-results { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.qe-link-result { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border: 1px solid #eef1f6; border-radius: 10px; background: #fbfcfe; }
.qe-link-result > span { flex: none; font-size: 12px; color: #475467; }
.qe-link-result > code { flex: 1; min-width: 0; font-size: 11px; color: #98a2b3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 进货统计里的普通卡片 */
.qe-panel { border: 1px solid #eef1f6; border-radius: 12px; box-shadow: 0 1px 3px rgba(16, 40, 80, .035); }
.qe-panel > .ant-card-head { min-height: 52px; padding: 0 18px; border-bottom: 1px solid #f2f5f9; }
.qe-panel > .ant-card-head .ant-card-head-title { font-size: 14px; font-weight: 600; color: #172033; }
.qe-panel > .ant-card-head .ant-card-extra { font-size: 12.5px; color: #8a94a6; }
.qe-panel > .ant-card-body { padding: 18px; }

/* 映射库弹窗 */
.qe-mapping-list { display: flex; flex-direction: column; gap: 12px; max-height: 52vh; overflow: auto; padding-right: 4px; }
.qe-mapping-row { border: 1px solid #eef1f6; border-radius: 12px; padding: 13px; background: #fcfdfe; }
.qe-mapping-row .qe-compare { grid-template-columns: minmax(0, 1fr) 26px minmax(0, 1fr); }
.qe-mapping-edit { display: flex; align-items: center; gap: 10px; margin-top: 12px; padding-top: 12px; border-top: 1px dashed #e6eaf2; }
.qe-mapping-edit .ant-select { flex: 1; min-width: 0; }

@media (max-width: 1200px) {
  .qe-compare { grid-template-columns: minmax(0, 1fr) 26px minmax(0, 1fr); }
  .qe-actions { flex-direction: row; flex-wrap: wrap; grid-column: 1 / -1; padding-left: 0; padding-top: 10px; border-left: 0; border-top: 1px dashed #e6eaf2; }
  .qe-actions .ant-btn { width: auto; }
}
@media (max-width: 991px) {
  .qe-compare, .qe-mapping-row .qe-compare { grid-template-columns: 1fr; }
  .qe-arrow { transform: rotate(90deg); }
  .qe-details { grid-template-columns: 1fr; }
  .qe-side-body { flex-direction: column; }
}

/* 销售额卡片 Tooltip：把「实付 + 平台优惠 = 应收」口径写清楚 */
.stat-tip { font-size: 12px; line-height: 1.8; }
.stat-tip-formula { font-weight: 600; margin-bottom: 4px; }
.stat-tip-total { margin-top: 2px; font-weight: 600; }
.stat-tip-note { margin-top: 4px; opacity: .75; }

/* 新建订单：整页 flex 纵排 + 顶部吸顶操作条 + 左右两栏，尽量一屏放得下 */
.order-page { display: flex; flex-direction: column; gap: 12px; width: 100%; }
/* 页内标题自带 margin-bottom，flex gap 会叠加 → 归零（2026-09-18 设计稿改版） */
.order-page > .shead { margin-bottom: 0; }
.order-page > .salert { margin-bottom: 0; }
/* 吸顶汇总条：2026-09-18 按设计稿改成深色（标签灰 + 数字白 + 深灰次按钮）。
   原来是白卡 + 浅描边，跳不出页面，扫一眼抓不到「几行 / 几件 / 多少钱」。 */
/* ⚠️ 必须带 .scard 一起选：.scard 的定义在文件更下方，同权重下会盖掉这里的 background。 */
.scard.order-actionbar { position: sticky; top: 0; z-index: 20;
  background: var(--d-ink); border-color: var(--d-ink);
  box-shadow: 0 10px 24px rgba(17, 24, 39, .18); }
.order-actionbar > .order-actionbar-inner { padding: 13px 16px; }
.order-actionbar-inner { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.order-metrics { display: flex; align-items: center; gap: 20px; font-size: 12.5px; color: #6b7688; flex-wrap: wrap; }
.order-metrics b { margin-left: 4px; font-size: 16px; color: #172033; font-variant-numeric: tabular-nums; }
.order-actionbar .order-metrics { color: var(--d-ink-3); }
.order-actionbar .order-metrics b { color: #fff; font-weight: 800; letter-spacing: -.02em; }
/* 次按钮在深色条上要浅底浅字，否则整块发黑看不清 */
.order-actionbar .ant-btn:not(.ant-btn-primary) { background: #374151; border-color: #374151; color: #E5E7EB; }
.order-actionbar .ant-btn:not(.ant-btn-primary):hover { background: #4B5563; border-color: #4B5563; color: #fff; }
/* 「上一单已提交」那行也在深色条里，文字得跟着变浅 */
.order-actionbar .ant-typography { color: #D1D5DB; }
.order-actionbar .order-result { color: #9CA3AF; }
.order-actionbar .order-result .ant-typography { color: #fff; }
.order-actionbar-btns { display: flex; align-items: center; gap: 8px; }
.order-goods-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.order-empty-goods { padding: 14px; border: 1px dashed #e8edf5; border-radius: 8px; background: #fafbfd; color: #98a2b3; font-size: 12.5px; text-align: center; }
/* 「默认带赠品」开关：靠右停在搜索框那一行，不额外占高度。 */
.order-gift-toggle { display: flex; align-items: center; gap: 8px; margin-left: auto; font-size: 12.5px; color: #6b7688; cursor: default; }
.order-gift-toggle code { padding: 1px 5px; border-radius: 4px; background: #f0f3f8; color: #4b5567; font-family: inherit; }
.order-sender-block { padding-top: 10px; border-top: 1px dashed #eef1f6; }
.order-subblock { margin-top: 12px; padding-top: 12px; border-top: 1px dashed #eef1f6; }
.order-sender-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.order-field-label { margin-bottom: 6px; font-size: 12.5px; color: #6b7688; line-height: 1.4; }
.order-required { color: #ff4d4f; }
.order-sender-addr { margin-top: 6px; font-size: 12.5px; color: #6b7688; line-height: 1.6; }
.order-confirm > div { line-height: 1.9; word-break: break-all; }
.order-result { margin-top: 14px; padding: 10px 14px; border-radius: 10px; background: #f6ffed; border: 1px solid #d9f7be; color: #237804; font-size: 13px; }
.order-result .ant-typography { color: #237804; }
/* 寄件人快选：一行一条，选中那条描蓝边 */
.sender-list { display: flex; flex-direction: column; gap: 8px; max-height: 300px; overflow: auto; }
.sender-option { display: flex; align-items: flex-start; gap: 10px; padding: 9px 12px; border: 1px solid #e8edf5; border-radius: 10px; background: #fff; cursor: pointer; transition: border-color .15s, background .15s; }
.sender-option:hover { border-color: #91caff; background: #f5faff; }
.sender-option.is-active { border-color: #1677ff; background: #e6f4ff; }
.sender-option .ant-radio-wrapper { margin-right: 0; }
.sender-option-body { flex: 1; min-width: 0; }
.sender-option-head { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; line-height: 1.5; }
.sender-option-head .ant-tag { margin: 0; }
.sender-option-phone { font-size: 12.5px; color: #4b5563; font-variant-numeric: tabular-nums; }
.sender-option .order-sender-addr { margin-top: 2px; }
.sender-option-actions { display: flex; align-items: center; flex-shrink: 0; }
.sender-option-actions .ant-btn { padding: 0 4px; height: 22px; font-size: 12.5px; }

/* ══════════════════════════════════════════════════════════════════════
   手机端布局（≤767px）：核心页从「宽表缩到手机」改成「一屏一张卡」
   ─────────────────────────────────────────────────────────────────────
   桌面 18 列的库存表在 390px 屏上要横向拖 1868px，销售对比表 1536px，
   本质是信息密度不匹配，不是 CSS 没调好。所以核心几页在窄屏换一套
   专为手机写的结构（卡片 / 紧凑列表），表格只在桌面用。
   ══════════════════════════════════════════════════════════════════════ */

/* ⚠️ 根因修复（不限宽度）：.page-stack 是 antd 的 Space(direction=vertical)，
   它的子项 .ant-space-item 默认 min-width:auto，宽度会被内容的 min-content 顶开 ——
   里面放一张 scroll.x=1860 的表，子项就真的撑到 1860，把整个 body 顶宽、整页能左右拖
   （销售统计实测溢出 121px）。锁住 min-width / max-width 后，表格交给自己的
   .ant-table-content 横向滚动，页面本身不再溢出。 */
.page-stack > .ant-space-item { min-width: 0; max-width: 100%; }

/* ── 通用的手机列表卡片（库存明细 / 总览 / 销售 / 发货 共用这套词汇） ── */
.m-list { display: flex; flex-direction: column; gap: 10px; }
.m-row { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; background: #fff; border: 1px solid #e9eef5; border-radius: 10px; }
.m-row.is-open { border-color: #91caff; }
.m-row.is-muted { background: #fafafa; }
.m-row.is-total { background: #fafafa; border-color: #dbe3ef; }
.m-row-head { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
.m-row-title { flex: 1 1 auto; min-width: 0; font-size: 13px; font-weight: 600; line-height: 1.35; }
.m-row-title.is-tap { cursor: pointer; }
.m-row-title .m-row-sub { display: block; margin-top: 2px; font-size: 11px; font-weight: 400; color: #9aa5b5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.m-row-right { flex: 0 0 auto; text-align: right; font-size: 13px; font-variant-numeric: tabular-nums; }
.m-row-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; padding-top: 6px; border-top: 1px dashed #eef1f6; }
.m-row-foot .ant-btn { padding: 0 6px; }
.m-row-note { display: inline-flex; align-items: center; gap: 5px; margin-left: auto; font-size: 11px; color: #8c93a0; }
.m-row-tags { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.m-row-tags .ant-tag { margin: 0; }
.m-row-rows { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: 11.5px; color: #8c93a0; }
.m-metrics { display: grid; gap: 6px; padding: 8px 6px; background: #f7f9fc; border-radius: 8px; }
.m-metrics.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.m-metrics.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.m-metrics.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.m-metric { display: flex; flex-direction: column; align-items: center; gap: 2px; min-width: 0; }
.m-metric-label { font-size: 11px; color: #8c93a0; white-space: nowrap; }
.m-metric-sub { margin-left: 4px; font-size: 10px; font-weight: 400; color: #8c93a0; }
.m-metric-value { font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; }
.m-detail { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; background: #fafbfd; border-radius: 8px; }
.m-detail-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 12px; }
.m-detail-label { color: #8c93a0; }
.m-detail-value { font-variant-numeric: tabular-nums; text-align: right; }
.m-list-page { display: flex; justify-content: center; padding: 14px 0 2px; }

@media (max-width: 767px) {
  /* ── 统计卡：2 列紧凑网格 ──
     原来 .stat-grid 是 auto-fit minmax(200px)，390px 屏下退化成 1 列，
     5 张卡竖排 = 一页 2886px，要滚 3 屏才看到表。 */
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .stat-card { min-height: 100px; border-radius: 9px; }
  .stat-card .ant-card-body { padding: 12px 12px 10px; gap: 3px; }
  .stat-card .stat-header { gap: 6px; }
  .stat-card .stat-title { font-size: 12px; }
  .stat-card .stat-icon { width: 20px; height: 20px; font-size: 12px; }
  .stat-card .ant-statistic-title { font-size: 12px; margin-bottom: 0; }
  .stat-card .ant-statistic-content { font-size: 20px; }
  .stat-card .ant-statistic-content-prefix { margin-right: 4px; font-size: 13px; }
  .stat-card .stat-sub { font-size: 11px; line-height: 1.45; }
  /* 待入库的卡本来就矮，别被上面这套抬高 */
  .inbound-page .stat-card { min-height: 86px; }

  /* 「库存货值」那 4 张普通卡（没有 .stat-card 类）也得缩，否则两位数的金额会顶破两列 */
  .stat-mini .ant-card-body { padding: 10px 12px; }
  .stat-mini .ant-statistic-title { font-size: 12px; margin-bottom: 2px; }
  .stat-mini .ant-statistic-content { font-size: 17px; }
  .stat-mini .ant-statistic-content-prefix { margin-right: 3px; font-size: 12px; }
  .stat-mini .ant-typography { font-size: 11px; line-height: 1.4; }

  /* ── 触控目标：小按钮 / 分页 / 数字框在手机上放到 32px 以上，手指点得准 ── */
  .ant-btn-sm { height: 32px; min-width: 32px; padding: 0 10px; }
  .ant-btn.ant-btn-icon-only.ant-btn-sm { width: 32px; padding: 0; }
  .ant-btn.ant-btn-sm.ant-btn-link { padding: 0 6px; }
  .ant-pagination-item, .ant-pagination-prev .ant-pagination-item-link,
  .ant-pagination-next .ant-pagination-item-link { min-width: 32px; height: 32px; line-height: 30px; }
  .ant-pagination { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px; }
  .ant-pagination-options { margin-left: 0; }
  .ant-pagination-options .ant-select-selector { height: 32px !important; }
  .ant-select-single.ant-select-sm:not(.ant-select-customize-input) .ant-select-selector { height: 32px; }
  .ant-input-number-sm { height: 32px; }
  /* 售完不补开关在 antd 里是 <button>，小号默认只有 16px 高、手指点不准 —— 整颗放大到 22px */
  .ant-switch-small { min-width: 40px; height: 22px; line-height: 20px; }
  .ant-switch-small .ant-switch-handle { width: 18px; height: 18px; top: 2px; left: 2px; }
  .ant-switch-small.ant-switch-checked .ant-switch-handle { left: calc(100% - 20px); right: auto; }
  /* 表头里的工具栏控件也跟着放大，搜索框给足宽度 */
  .content-card > .ant-card-head .ant-input { height: 32px; }

  /* ── 页面级：手机上一屏一张卡，表格不再出现 ── */
  .m-row-title { font-size: 13.5px; }
  .m-metric-value { font-size: 15px; }

  /* 每日趋势图：柱子本身 flex:1 会缩，但柱顶的数字标签有最小宽度（~22px），
     14 天时 22×14 + 间距 12×13 + 内边距 24 ≈ 486px，在 358px 的卡片里溢出 121px
     —— 这就是销售统计「整页能左右拖」的真凶（跟表格无关）。让图自己横向滚。 */
  .bar-chart { overflow-x: auto; overflow-y: hidden; gap: 8px; }
  .bar-chart .bar-column { min-width: 30px; }
}

/* ══════════════════════════════════════════════════════════════════════
   新建系统商品（#/new-product）
   宽屏：表头 + 一行一个规格的 grid；窄屏：一格一张卡（.np-label 才显示）。
   ══════════════════════════════════════════════════════════════════════ */
.np-page .np-notice, .np-page .np-result { margin-bottom: 0; }
.np-basic { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px 16px; }
.np-basic-item { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.np-basic-wide { grid-column: span 2; }
.np-basic-full { grid-column: span 3; }
.np-label { font-size: 12px; color: rgba(0, 0, 0, .45); margin: 0; }

/* 进货信息：基本信息里一行四个小格（厂家 / 链接 / 成本 / 备注），进的是本地「进货链接」 */
.np-link-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr) minmax(0, 116px) minmax(0, 1fr); gap: 8px; }
.np-link-cell { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.np-link-label { font-size: 12px; color: rgba(0, 0, 0, .45); }

/* 库存明细「进货链接」列：链接 + 编辑按钮，厂家挂下面一行 */
.pl-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pl-cell-main { display: flex; align-items: center; gap: 4px; }
.pl-supplier { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-edit { padding: 0 2px !important; height: auto !important; }

/* 加了「图片」列之后一行放不下 10 列，窄一点的屏让表格自己横滚，别把 body 顶宽 */
.np-grid { display: flex; flex-direction: column; gap: 8px; overflow-x: auto; }
.np-head, .np-row {
  display: grid;
  grid-template-columns: 1.1fr 1.4fr 84px 1fr 84px 84px 96px 96px 116px 40px;
  gap: 8px;
  align-items: center;
  min-width: 880px;
}
.np-head { font-size: 12px; color: rgba(0, 0, 0, .45); padding: 0 2px; }
.np-head-cell { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np-row { padding: 6px 2px; border-bottom: 1px dashed #f0f0f0; }
.np-cell { min-width: 0; }
.np-cell .np-label { display: none; }
.np-cell-op { display: flex; justify-content: flex-end; }
.np-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 14px; flex-wrap: wrap; }
.np-result .np-result-codes { color: rgba(0, 0, 0, .65); word-break: break-all; margin-top: 4px; }
.np-confirm-tip { color: rgba(0, 0, 0, .45); font-size: 12px; margin-top: 8px; }

/* ── 图片（商品头图 / 规格图）：缩略图 + 右上角删除 + 虚线「+」───────────
   「+」是 <label> 包着隐藏的 file input，所以点它就会弹系统选择器（手机上还能直接拍照）。 */
.np-imgs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-height: 38px; }
.np-img-wrap { position: relative; display: inline-flex; flex: none; line-height: 0; }
.np-imgs .ant-image { border-radius: 4px; overflow: hidden; }
.np-img-del {
  position: absolute; top: -6px; right: -6px; width: 16px; height: 16px; padding: 0;
  border: none; border-radius: 50%; background: rgba(0, 0, 0, .55); color: #fff;
  font-size: 12px; line-height: 1; cursor: pointer;
}
.np-img-del:hover { background: #ff4d4f; }
.np-img-add {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; flex: none; margin: 0; cursor: pointer;
  border: 1px dashed #d9d9d9; border-radius: 4px; background: #fafafa;
  color: rgba(0, 0, 0, .45); font-size: 20px; line-height: 1;
}
.np-img-add.is-head { width: 64px; height: 64px; font-size: 24px; }
.np-img-add:hover { border-color: #1677ff; color: #1677ff; }
.np-file { display: none; }
/* 进货信息五个框（比新建页多一个「挂到哪个编码」，备注占两格） */
.np-link-wide { grid-column: span 2; }

/* ── 商品管理：列表 / 手机卡片 / 编辑弹窗 ───────────────────────────── */
.pm-edit { padding: 0 2px !important; height: auto !important; }
/* 手机版商品卡片（宽屏走表格，这套 DOM 只在窄屏渲染） */
.pm-cards { display: flex; flex-direction: column; gap: 10px; }
.pm-card { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; border: 1px solid #f0f0f0; border-radius: 8px; }
.pm-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.pm-card-main { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
.pm-card-noimg { width: 52px; height: 52px; flex: none; display: flex; align-items: center; justify-content: center; border: 1px solid #f0f0f0; border-radius: 4px; color: rgba(0, 0, 0, .25); }
.pm-card-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pm-card-title { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 15px; font-weight: 600; }
.pm-card-name { font-size: 13px; color: rgba(0, 0, 0, .65); }
.pm-card-sub { font-size: 12px; color: rgba(0, 0, 0, .45); word-break: break-all; }
.pm-card-row { display: flex; align-items: center; gap: 8px; font-size: 13px; min-width: 0; }
.pm-card-label { flex: none; width: 30px; color: rgba(0, 0, 0, .45); }
.pm-card-value { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: rgba(0, 0, 0, .75); }
/* 手机卡片「分类」行右侧的改分类入口：值继续省略号缩，按钮靠右且不许被挤走 */
.pm-card-act { flex: none; margin-left: auto; padding: 0; height: auto; }
/* 快捷改分类弹窗：三行「标签 + 值」，标签定宽让下拉上下对齐（标签控件不换行，规范 §3.3） */
.pm-cls { display: flex; flex-direction: column; gap: 10px; }
.pm-cls-line { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 13px; }
.pm-cls-label { flex: none; width: 64px; color: rgba(0, 0, 0, .45); }
.pm-cls-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: rgba(0, 0, 0, .75); }
.pm-cls-err { flex: 1; min-width: 0; font-size: 12px; }
.pm-cls-tip { font-size: 12px; color: rgba(0, 0, 0, .45); }
.pm-card-cost { flex: none; font-size: 12px; }
/* 进货链接的 1688 商品 id：卡片上一行放得下就放着，放不下省略（不要顶宽卡片） */
.pm-card-linkid { flex: 1; min-width: 0; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pm-card .pm-edit { padding: 2px 6px !important; }
.pm-pager { display: flex; justify-content: center; margin-top: 12px; }
.pe-modal .ant-modal-body { padding-top: 4px; }
.pe-body { display: flex; flex-direction: column; gap: 12px; }
.pe-loading { padding: 60px 0; text-align: center; }
.pe-alert { margin: 0; }
/* 规格行：只读列（编码/规格信息/单位）+ 可改列（条码/售价/成本/图片）。
   列多，窄屏靠横滚，别把弹窗顶宽。 */
.pe-grid { display: flex; flex-direction: column; gap: 8px; overflow-x: auto; }
.pe-head, .pe-row {
  display: grid;
  grid-template-columns: 1.3fr 1.4fr 64px 1fr 92px 92px 200px;
  gap: 8px;
  align-items: center;
}
.pe-head { font-size: 12px; color: rgba(0, 0, 0, .45); padding: 0 2px; }
.pe-head-cell { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pe-row { padding: 6px 2px; border-bottom: 1px dashed #f0f0f0; }
.pe-cell { min-width: 0; }
.pe-cell .pe-label { display: none; }
.pe-cell-op { display: flex; justify-content: flex-end; }
.pe-ro { display: block; font-size: 12px; color: rgba(0, 0, 0, .65); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pe-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding-top: 4px; }
/* 新建商品改在抽屉里打开：去掉整页留白，只留卡片间距 */
.np-drawer .np-page { padding: 0; }
.np-drawer .np-notice { margin-bottom: 12px; }
@media (max-width: 768px) {
  .np-link-wide { grid-column: auto; }
  .pe-modal { top: 8px; padding-bottom: 8px; }
  .pe-modal .ant-modal-body { max-height: calc(100vh - 116px); overflow-y: auto; }
  /* 卡头的「规格信息 / 只能改…」在手机上会叠在一起，让 extra 掉到第二行 */
  .pe-modal .ant-card-head { flex-wrap: wrap; row-gap: 2px; }
  .pe-modal .ant-card-head-title { white-space: normal; }
  /* 卡头太窄时标题会被挤成两行，干脆把「只能改…」的说明收起来（每格已有标签） */
  .pe-modal .ant-card-extra { display: none; }
  /* 保存按钮贴着弹窗底部：手机上不用滚到底才能点 */
  .pe-foot { position: sticky; bottom: 0; z-index: 2; background: #fff; padding: 10px 0; border-top: 1px solid #f0f0f0; }
  /* 一屏一张卡：每格都带自己的标签，不用横拖表格 */
  .pe-head { display: none; }
  .pe-grid { overflow-x: visible; }
  .pe-row { display: block; border: 1px solid #f0f0f0; border-radius: 8px; padding: 10px 12px; margin-bottom: 10px; }
  .pe-cell { margin-bottom: 8px; }
  .pe-cell .pe-label { display: block; margin-bottom: 4px; font-size: 12px; color: rgba(0, 0, 0, .45); }
  .pe-cell-op { margin-bottom: 0; }
  .pe-cell-op .pe-ro { display: none; }
  .pe-foot { flex-direction: column; align-items: stretch; }
  .pe-foot .ant-space { justify-content: flex-end; }
}

/* 按款式图批量生成规格：一张图 = 一个款式（缩略图 + 可改的款式名 + 编码预览） */
.np-bulk { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.np-bulk-step { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.np-bulk-grid { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-start; min-width: 0; }
.np-bulk-item { width: 104px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.np-bulk-item .ant-input-affix-wrapper,
.np-bulk-item .ant-input { padding: 2px 6px; font-size: 12px; }
.np-bulk-thumb { position: relative; display: inline-flex; align-self: flex-start; line-height: 0; }
.np-bulk-thumb .ant-image { border-radius: 6px; overflow: hidden; }
.np-bulk-sub {
  font-size: 11px; line-height: 1.35; color: rgba(0, 0, 0, .45);
  word-break: break-all; min-height: 15px;
}
.np-bulk-add {
  width: 104px; height: 104px; flex: none; margin: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px dashed #d9d9d9; border-radius: 8px; background: #fafafa;
  color: rgba(0, 0, 0, .45); font-size: 20px; line-height: 1;
}
.np-bulk-add:hover { border-color: #1677ff; color: #1677ff; }
.np-bulk-add-inner { display: inline-flex; flex-direction: column; align-items: center; gap: 4px; }
.np-bulk-add-inner > span:last-child { font-size: 12px; }
.np-bulk-sizes { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; min-width: 0; }
.np-bulk-size-box { display: flex; gap: 8px; flex-wrap: wrap; }
.np-bulk-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; border-top: 1px dashed #f0f0f0; padding-top: 12px;
}

/* ── 1688 SKU 自动读取（新建商品，2026-09-25） ───────────────────────────── */
.np-offer-hint {
  display: flex; align-items: center; gap: 6px;
  font-size: 13px; line-height: 1.7; color: rgba(0, 0, 0, .45);
}
.np-offer-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; min-width: 0; }
.np-offer-subject {
  font-weight: 600; min-width: 0; word-break: break-all;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.np-offer-sizes { display: flex; align-items: center; gap: 8px 16px; flex-wrap: wrap; min-width: 0; }
.np-offer-sizes .np-label { margin: 0; }
.np-offer-grid { max-height: 340px; overflow-y: auto; padding-right: 4px; }
.np-offer-item {
  width: 96px; margin: 0; cursor: pointer; display: flex; flex-direction: column;
  gap: 4px; min-width: 0; padding: 6px; border: 1px solid #f0f0f0; border-radius: 8px;
}
.np-offer-item:hover { border-color: #91caff; }
.np-offer-item .ant-checkbox-wrapper { display: flex; align-items: flex-start; gap: 4px; width: 100%; }
.np-offer-item .ant-checkbox { margin-top: 2px; }
.np-offer-name {
  font-size: 12px; line-height: 1.35; word-break: break-all;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.np-offer-item .ant-image { border-radius: 6px; overflow: hidden; line-height: 0; }
.np-offer-noimg {
  width: 72px; height: 72px; display: inline-flex; align-items: center; justify-content: center;
  background: #fafafa; border-radius: 6px; font-size: 12px; color: rgba(0, 0, 0, .3);
}
.np-offer-sub { font-size: 11px; color: rgba(0, 0, 0, .45); }

@media (max-width: 768px) {
  /* 一屏一张卡：每个输入框都带自己的标签，不再横拖表格 */
  .np-basic { grid-template-columns: minmax(0, 1fr); }
  .np-basic-wide { grid-column: auto; }
  .np-link-grid { grid-template-columns: minmax(0, 1fr); }
  /* 手机上图标按钮太小，撑到能点的尺寸 */
  .pl-edit { padding: 2px 6px !important; }
  .np-basic-full { grid-column: auto; }
  .np-head { display: none; }
  .np-grid { overflow-x: visible; }
  .np-head, .np-row { min-width: 0; }
  .np-row { display: block; border: 1px solid #f0f0f0; border-radius: 8px; padding: 10px 12px; margin-bottom: 10px; }
  .np-cell { margin-bottom: 8px; }
  .np-cell .np-label { display: block; margin-bottom: 4px; }
  .np-cell-op { justify-content: flex-start; margin-bottom: 0; }
  .np-cell-op .ant-btn { min-height: 32px; }
  /* 手机上手点，缩略图和「+」都放大一点 */
  .np-img-add { width: 44px; height: 44px; }
  .np-img-del { width: 20px; height: 20px; font-size: 13px; }
  /* 批量款式图：一行两张，别把卡片顶宽 */
  .np-bulk-item { width: calc(50% - 5px); }
  .np-bulk-add { width: calc(50% - 5px); height: 104px; }
  .np-bulk-sizes { gap: 10px; }
  .np-bulk-foot { flex-direction: column; align-items: stretch; }
  .np-bulk-foot .ant-btn { min-height: 36px; }
  .np-offer-item { width: calc(50% - 5px); }
  .np-offer-grid { max-height: none; }
}

/* ── 订单管理（#/orders，只做桌面表格） ─────────────────────────────────── */
.od-page { display: flex; flex-direction: column; gap: 12px; }
/* 订单列表的卡片标题（「订单列表」+「只读…」那行）已按用户要求删掉，
   原来的 `.od-hint` 是给它用的，一并移除。 */
/* 2026-09-18 设计稿改版：外层 Card → .scard，所以 .ant-card-body 那条改用 .scard-body。
   ⚠️ .od-page 是 flex column（gap 12），区块自带的 margin-bottom 会跟 gap 叠加成 30px，
   所以把 .shead / .salert 的 margin-bottom 归零，间距统一交给 gap。 */
.od-page > .shead, .od-page > .salert { margin-bottom: 0; }
/* 分页条：外面套着 .od-pager，吃不到 `.scard > .spage-antd` 的收边规则，这里补一份。 */
.od-page .od-pager {
  display: flex; justify-content: flex-end; margin: 0;
  padding: 12px 16px 14px; border-top: 1px solid var(--d-line);
}
/* 状态 Tab（待审核 / 待打单 / 已发货 / 异常 / 所有订单）：
   ⚠️ 2026-09-21 用户说「待审核这几个页签做大一点，现在不明显」——
   这是发货时一直在用的主导航，不是筛选条：字号 14 → 16、点击区 6px → 10px，
   选中项加粗、下划线 2px → 3px。（原来那版是按「像筛选条而不是二级导航」压小的，
   口径已改，别照旧注释压回去。）
   刷新按钮在页内标题右侧（跟库存明细/商品管理统一）。 */
.od-status-tabs.ant-tabs { margin-bottom: 0; }
.od-status-tabs .ant-tabs-nav { margin-bottom: 0; }
.od-status-tabs .ant-tabs-nav::before { border-bottom-color: #f0f0f0; }
.od-status-tabs .ant-tabs-tab { padding: 10px 2px; font-size: 16px; }
.od-status-tabs .ant-tabs-tab.ant-tabs-tab-active { font-weight: 600; }
/* ⚠️ 要带 .ant-tabs-top 一起写：antd 的高度规则是 `.ant-tabs-top>.ant-tabs-nav .ant-tabs-ink-bar`
   （3 个类），少写一个类压不过它 —— 实测不写就还是 2px。 */
.od-status-tabs.ant-tabs-top .ant-tabs-ink-bar { height: 3px; border-radius: 2px; }
.od-status-row { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
/* 「异常」页签上的同步异常单数量角标（2026-09-25）。
   antd Badge 的数字泡默认是 `position:absolute` 挂在包裹层右上角 —— 这里页签是行内文字，
   得给包裹层一个相对定位的行内盒子，再把泡泡往右上角偏一点，压住页签文字就难看了。 */
.od-tab-label { display: inline-flex; align-items: center; gap: 6px; }
.od-tab-badge { margin-left: 0; }
.od-tab-badge .ant-badge-count {
  min-width: 16px; height: 16px; line-height: 16px; padding: 0 4px;
  font-size: 11px; border-radius: 8px;
}
/* 有同步异常单：**浅红底 + 红字**（既抢眼又不违反规范 §3.1「禁止纯色底 + 白字」）。
   全站通用的 `.ant-badge-count` 是灰底灰字，压不过它就得写在后面（CSS 同权重看源序）。 */
.od-tab-badge:not(.is-zero) .ant-badge-count {
  background: var(--d-red-soft); color: var(--d-red-ink); font-weight: 800;
}
/* 0 条：灰底浅字，只占位不抢戏，页签宽度也不跳 */
.od-tab-badge.is-zero .ant-badge-count {
  background: var(--d-panel-2); color: var(--d-ink-3); font-weight: 600;
}
.od-status-row .od-status-tabs { flex: 1 1 auto; min-width: 0; }
.od-status-row > .ant-btn { flex: none; }
/* 状态列：状态标签下面挂一行「缺货/锁定/预售/周期购」红字 */
.od-status-cell { display: flex; flex-direction: column; gap: 2px; align-items: flex-start; }
.od-abnormal-tag { font-size: 12px; line-height: 1.3; color: #cf1322; }
/* 状态标签 + 卖家旗帜小标同一行（旗帜 0 = 无旗不画，见 app.js flagIcon） */
.od-status-line { display: inline-flex; align-items: center; gap: 4px; }
/* 「异常」页签的「异常描述」列：完整换行显示（截断会让错误原因看不全，悬停只作兜底）。 */
.od-abnormal-desc { white-space: normal; word-break: break-all; line-height: 1.4; }
/* 人话描述（拆掉 `[ERR_XXX,` 信封后的正文）；错误码原文只在 title 里，别占版面。 */
.od-abnormal-desc-text { color: rgba(0, 0, 0, 0.75); }
/* 「未对应系统商品：去设置」——优易那一列的第二行，链接跳「商品 → 线上商品对应」。
   nowrap：列宽只有 260px，不加会被折成「去设 / 置」两行，看着像断字。 */
.od-abnormal-desc-act { margin-top: 4px; font-size: 12px; white-space: nowrap;
  color: rgba(0, 0, 0, 0.45); }
.od-set-link { color: #1677ff; cursor: pointer; text-decoration: underline; }
.od-set-link:hover { color: #0958d9; }
/* 订单号（异常页第一列第二行）：点一下复制，跟「系统单号」列同一个交互。 */
.od-order-no { cursor: pointer; font-variant-numeric: tabular-nums; }
.od-order-no:hover { color: #1677ff; text-decoration: underline; }
/* 线上 SKU ID：映射页是按 SPUID/SKUID 认商品的，做成等宽小字方便核对。 */
.od-online-sku { font-size: 12px; color: rgba(0, 0, 0, 0.45);
  font-variant-numeric: tabular-nums; cursor: pointer; }
.od-online-sku:hover { color: #1677ff; text-decoration: underline; }
/* 异常页时间格：'YYYY-MM-DD HH:MM' 折成「2026-08- / 29 18:23」两行会看着像数据错位。 */
.od-time-cell { white-space: nowrap; }
/* 异常页「线上商品」的商品名：最多两行、超出打省略号。
   不用 `od-ellipsis`（单行）—— 只能露 ~18 个字，认不出是哪条线上商品；
   也不放开无限换行 —— 一页 4 单 × 每单 1~3 个商品，行高会失控。 */
.od-goods-clamp2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; white-space: normal; word-break: break-all; }
.od-filters { display: flex; flex-wrap: wrap; gap: 12px 16px; align-items: flex-end; }
.od-filter { display: flex; flex-direction: column; gap: 4px; }
.od-filter-label { font-size: 12px; line-height: 1; color: rgba(0, 0, 0, 0.45); }
.od-range { width: 262px; }
.od-select { min-width: 170px; }
.od-input { width: 152px; }
/* 单号查询：类型下拉 + 输入框拼成一条，不用 antd 的 Input.Group（少踩内部结构） */
/* 「单号查询」= 搜索类型下拉 + 关键词输入框，做成**一个连体控件**（antd Input.Group 那种）。
   两条坑（2026-09-18 用户反馈「有组合样式的」就是这两条造成的）：
   ① 内相邻的两个角必须切平。设计层给所有输入/下拉都是 11px 圆角，只按类名写选择器
      （`.od-search-group .od-search-type .ant-select-selector` = 0,3,0）会被设计层那条
      `.ant-select:not(.ant-select-customize-input) .ant-select-selector`（也是 0,3,0）
      按**源码顺序**压过去 —— 实测下拉的右角还是圆的，盖在输入框平直的左边上，
      接缝处鼓出两个白楔，看着像两截没对齐。选择器要提到 0,4,0 才稳。
   ② 两个控件相邻各带一条 1px 描边 → 接缝是 2px，比外框粗一倍。后一个往左压 1px
      让两条线重叠（antd 自家 Input.Group 就是这么干的）。 */
.od-search-group { display: flex; }
.od-search-group .od-search-type { width: 118px; }
.od-search-group .od-search-type.ant-select .ant-select-selector {
  border-top-right-radius: 0; border-bottom-right-radius: 0;
}
.od-search-group .od-search-input {
  width: 190px; border-top-left-radius: 0; border-bottom-left-radius: 0; margin-left: -1px;
}
.od-filter-actions { display: flex; gap: 8px; margin-left: auto; }
/* （原来给 antd Alert / Card 调边距的两条已随 2026-09-18 改版删除：错误提示换成 .salert、
   表格卡换成 .scard，边距由它们自带的规则管。） */
/* 列宽必须被尊重。踩过的坑（2026-09-17）：antd 在「没有任何 `fixed` / `ellipsis` 列」时会给
   `<table>` 用 `table-layout: auto`，浏览器于是**按内容重新分配列宽** —— 「线上商品」那格是
   nowrap 的长商品名，会把这列撑到 542px，把「操作人」挤成 29px、把「付款时间」表头挤成两行。
   订单表每一列都写死了宽度，固定布局才是对的。
   （原来没暴露是因为「系统单号」那列带 `fixed:'right'`，antd 顺手给了 fixed 布局；
   去掉那个 fixed 之后就得自己兜住，别再删这行。）
   `!important` 是必需的：antd 把 `table-layout: auto` 写在 `<table>` 的**行内 style** 上，
   类选择器盖不住它（实测不加就是 auto，加了才是 fixed）。 */
.od-table table { table-layout: fixed !important; }
/* 表格里的次要行（平台单号 / 平台名 / 地区 / 快递单号） */
.od-sub { font-size: 12px; line-height: 1.4; color: rgba(0, 0, 0, 0.45); }
/* 买家行：昵称 + 旺旺图标。图标由阿里挂件注入，不能被 ellipsis 裁掉，
   所以昵称单独做省略、图标固定宽度不参与压缩。 */
.od-buyer-line { display: flex; align-items: center; gap: 2px; min-width: 0; }
.od-buyer-line .od-ellipsis { min-width: 0; flex: 1 1 auto; }
/* 收货信息里的「省市区」段：平台给的是明文（省市区永远明文），比打码街道（`.od-sub` 的 45%）
   深一档，扫一眼就知道发往哪个地区；街道继续浅灰，两段拉开层次（用户要求）。 */
.od-sub .od-region { color: rgba(0, 0, 0, .75); }
/* 地址整条**完整显示**（用户要求 2026-09-17）：不截断，超出就换行。
   原来这条走 `.od-ellipsis`（`white-space: nowrap` + 省略号），212px 的列宽里
   一条「省市区 + 打码街道」只露半截，得悬停才看得全。现在让它自然折行。
   ⚠️ `overflow-wrap: anywhere` 是兜底：打码街道里混着长串**无空格**片段
   （`城**路开元·上**街一鸣超市`、门牌 / 单元号之类的纯 ASCII 串），
   中文本身逐字可断，但纯 ASCII 长串默认不断，会直接顶破列宽。 */
.od-addr { white-space: normal; overflow-wrap: anywhere; }
/* 旺旺图标（挂件会往里塞 a/img，尺寸由它自己控制，别去压它）。
   ⚠️ 挂件点亮时会**整个替换** span 的 class：`J_WangWang od-ww` → `ww-light ww-small`，
   所以真正生效的是 `.ww-light` 这条；`.od-ww` 只管点亮前那一瞬，防止图标冒出来时把昵称挤动。 */
.od-ww,
.od-buyer-line .ww-light { display: inline-block; flex: none; line-height: 1; vertical-align: middle; }
/* 旺旺兜底图标：外网挂件脚本加载不到时，`.J_WangWang` 是空 span（页面上就看不到旺旺），
   这个「旺」字块顶上，点它开旺旺网页版。挂件点亮后（第一个子节点被塞进 a/img）
   这条规则自动把它藏起来，不会跟真图标重影 —— 所以选择器只认位置，不认 class
   （挂件会把 `J_WangWang od-ww` 整个替换成 `ww-light ww-small`）。 */
.od-ww-wrap { display: inline-flex; align-items: center; flex: none; cursor: pointer; }
.od-ww-fallback {
  width: 16px; height: 16px; border-radius: 3px; margin-left: 3px;
  background: #ff9000; color: #fff; font-size: 11px; line-height: 16px;
  text-align: center; user-select: none;
}
.od-ww-wrap > :first-child:not(:empty) + .od-ww-fallback { display: none; }
/* 关注点列（照优易的排版）：合单标记在最上面，下面「付款时间:」「最晚发货:」——
   标签独占一行、值换一行；标签统一玫红色，值用正文色，**不加任何底色**（用户要求）。
   紧迫度不再染整行，只染「剩 X / 超时 X」那句尾巴。 */
.od-focus { display: flex; flex-direction: column; gap: 4px; }
.od-focus-line { line-height: 1.45; }
.od-focus-label { color: #eb2f96; }
.od-focus-val { color: rgba(0, 0, 0, 0.85); }
/* 合单标记：玫红描边小方标（悬停出「合单」说明） */
.od-merge-tag {
  display: inline-block; align-self: flex-start; flex: none;
  padding: 0 4px; margin-bottom: 2px;
  border: 1px solid #ffadd2; border-radius: 2px;
  color: #eb2f96; font-size: 12px; line-height: 16px; cursor: default;
}
/* 「剩 X / 超时 X」尾巴：只靠**文字颜色 + 字重**区分紧迫度，不加背景色
   （之前最急两档带同色 10% 浅底，一屏看下来太花，用户要求去掉）。 */
.od-focus-left { display: inline-block; margin-left: 4px; font-size: 12px; font-weight: 500; }
.od-focus-left-overdue { color: #cf1322; font-weight: 600; }
.od-focus-left-critical { color: #d4380d; font-weight: 500; }
.od-focus-left-soon { color: #fa8c16; }
.od-focus-left-today { color: #d48806; }
.od-focus-left-normal { color: #595959; }
.od-focus-left-ample { color: rgba(0, 0, 0, 0.45); }
/* 已发货尾巴：提前=绿、超时=红（复盘发货时效用） */
.od-focus-ok { color: #389e0d; }
.od-focus-over { color: #cf1322; font-weight: 500; }
/* 付款时间的相对词：今天 / 昨天**两个词两种颜色**（用户 2026-09-23 要求）——
   今天=蓝（新单，跟商品数量角标同一个蓝）、昨天=橙（搁了一天，该先处理）。
   只染这一个词，后面的 HH:MM 保持正文色；不相对的日子整串不染。
   （这两色跟「最晚发货」的紧迫度尾巴不在同一行，不会混。） */
.od-payday-today { color: #1677ff; }
.od-payday-yesterday { color: #fa8c16; }
/* 「付款时间:」标签不染色（用户 2026-09-23 要求）—— 那一行的值已经有蓝/橙的相对词，
   标签再玫红整行就花了。其余标签（最晚发货 / 发货时间）照旧玫红。 */
.od-focus-label.is-plain { color: rgba(0, 0, 0, 0.85); }
/* 商品列：一行的每个 SKU 一行「缩略图 + 数量角标 + 编码规格 + 商品名」 */
.od-goods { display: flex; flex-direction: column; gap: 10px; }
.od-goods-line { display: flex; align-items: center; gap: 8px; min-width: 0; }
.od-goods-pic { position: relative; flex: none; width: 50px; height: 50px; }
/* 50px 商品图，点一下用 antd Image 自带的 lightbox 放大 */
.od-goods-img {
  width: 50px; height: 50px; object-fit: cover; border-radius: 4px;
  background: #fafafa; display: block; cursor: zoom-in;
}
.od-goods-noimg {
  width: 50px; height: 50px; display: flex; align-items: center; justify-content: center;
  background: #fafafa; border-radius: 4px; color: rgba(0, 0, 0, 0.25); font-size: 12px;
}
/* 组合商品的封面图：正常显示 50px 图，右下角压一个橙色「组合」小标。
   图来自 `searchErpSoD4ComList`（折叠后的组合行），不是组件行的图 ——
   组件行顺序不固定，用它当封面会跟组合名对不上。 */
.od-goods-combo-wrap { position: relative; display: block; width: 50px; height: 50px; }
.od-goods-combo-badge {
  position: absolute; right: 0; bottom: 0; padding: 0 3px;
  border-radius: 2px 0 3px 0; background: #ffac31; color: #fff;
  font-size: 10px; line-height: 14px; white-space: nowrap;
  pointer-events: none; text-shadow: 0 1px 1px rgba(0, 0, 0, .25);
}
/* 拿不到组合封面时的兜底：50px 橙色「组合」色块（别用组件图顶上）。 */
.od-goods-combo-pic {
  width: 50px; height: 50px; display: flex; align-items: center; justify-content: center;
  background: #ffac31; color: #fff; border-radius: 4px;
  font-size: 13px; line-height: 1; font-weight: 500; letter-spacing: 0.5px;
}
.od-goods-combo-pic-label { white-space: nowrap; }
/* 数量角标：压在缩略图右上角，蓝底**圆角矩形**（2026-09-21 用户要求；原来写的 9px 全圆角，
   单个数字时就是个圆）。4px 跟旁边的图块（`.od-goods-pic img` / 组合色块）同一档。 */
.od-goods-qty {
  position: absolute; top: -6px; right: -6px; min-width: 16px; height: 16px;
  padding: 0 4px; border-radius: 4px; background: #1677ff; color: #fff;
  font-size: 11px; line-height: 16px; text-align: center; font-variant-numeric: tabular-nums;
}
.od-goods-text { font-size: 12px; line-height: 1.4; min-width: 0; color: rgba(0, 0, 0, 0.85); }
.od-goods-name { font-size: 12px; line-height: 1.4; min-width: 0; color: rgba(0, 0, 0, 0.45); }
.od-goods-meta { min-width: 0; }
/* 商品列底部：件数/款数 + 五项金额 */
/* 组合商品**合并成一行**显示组合本身（组件不铺开）——列表和**展开明细**都是这一套
   （用户要求：展开行里的组合也跟外面一样，不拆成组件）。
   `od-goods-combo` 只做标记、不给样式：⚠️ 这一行**不另加底色**（用户明确要求），
   原来给过浅橙底 + 橙描边，整列看下去很花；现在只靠图上的橙色「组合」小标
   （`od-goods-combo-badge`／拿不到封面时的 `od-goods-combo-pic` 色块，色号照优易
   bundle 里 `combineTagRender` 写死的 `#FFAC31`）区分，别改成蓝的。 */
/* 平台小标（品牌色小方标 + 首字） */
.od-source { display: flex; align-items: center; gap: 5px; min-width: 0; }
.od-plogo {
  flex: none; width: 18px; height: 18px; border-radius: 4px;
  color: #fff; font-size: 11px; line-height: 18px; text-align: center;
}
.od-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 留言/备注：**正常换行显示完整内容**，只有超长（超过 4 行）才省略，悬停 title 看全文。
   之前挂的是 .od-ellipsis（单行 nowrap 截断），实测留言中位 14 字、最长 22 字，
   「发申通【泡芙｜09-15 22:00:20】」这种 20 字出头的就被截成半截，看着像丢了字。 */
.od-memo-wrap { display: flex; flex-direction: column; gap: 3px; }
.od-memo { display: flex; align-items: flex-start; gap: 4px; }
/* [留言] 绿色 = 买家下单时的留言；[备注] 蓝色 = 卖家对订单的备注（会回传平台）。 */
.od-memo-tag {
  flex: none; padding: 0 4px; border-radius: 2px;
  font-size: 11px; line-height: 17px; white-space: nowrap;
  background: #f6ffed; color: #389e0d;
}
.od-memo-seller .od-memo-tag { background: #f0f5ff; color: #2f54eb; }
.od-memo-text {
  flex: 1 1 auto; min-width: 0;
  font-size: 12px; line-height: 1.5;
  white-space: normal; word-break: break-word;
  /* 超过 4 行才折叠出省略号；4 行以内整段显示 */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4;
  overflow: hidden;
}
.od-memo-seller .od-memo-text { color: rgba(0, 0, 0, .6); }
/* 订单备注（2026-09-26 起对接优易）：**行上的笔直接编辑优易卖家备注**，
   保存后由优易回传平台；[备注] 行尾挂一枚「编辑」图标按钮，点开弹窗（.od-note-modal）再输入。
   没写过的单整行是「加备注」入口（.od-my-note，同一套结构）。 */
.od-my-note {
  display: flex; align-items: center; gap: 4px;
}
/* 没备注时这截就是入口：整块可点，颜色浅、别跟真内容抢眼 */
.od-my-note-text {
  flex: 1 1 auto; min-width: 0;
  font-size: 12px; line-height: 18px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.od-my-note-text.is-empty { color: #bfbfbf; cursor: pointer; }
.od-my-note-text.is-empty:hover { color: #1677ff; }
.od-my-note-btn {
  flex: none; width: 20px; height: 20px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid #d9d9d9; border-radius: 3px;
  background: #fff; color: #8c8c8c; cursor: pointer;
  font-size: 12px; line-height: 1;
}
.od-my-note-btn:hover { background: #f0f5ff; border-color: #1677ff; color: #1677ff; }
.od-my-note-btn:focus-visible { outline: 2px solid #1677ff; outline-offset: 1px; }
.od-my-note-btn .anticon { font-size: 12px; }
/* 备注弹窗：正文一行说明（写优易、回传平台）+ 多行正文 + 同步开关 + 提示 */
.od-note-form { display: flex; flex-direction: column; gap: 8px; }
.od-note-sub, .od-note-tip { font-size: 12px; line-height: 1.6; color: rgba(0, 0, 0, .45); }
.od-note-ta { display: block; }
.od-note-sync { display: flex; align-items: center; gap: 6px; font-size: 13px; }
.od-note-sync-tip { color: #bfbfbf; display: inline-flex; cursor: help; }
.od-code { cursor: pointer; font-variant-numeric: tabular-nums; }
.od-code:hover { color: #1677ff; text-decoration: underline; }
/* ── 运单号旁的复制图标（2026-09-29 用户要求「物流单号做个快捷复制的图标」）────
   做成一个**看得见**的小方块按钮，而不是像系统单号那样「点文字复制」——
   运单号那格还压着快递公司名，文字本身已经是灰字副行了，再让用户去点灰字
   猜不到能复制。图标默认淡灰，hover 才变蓝（跟 `.od-code` 的 hover 反馈同一套）。 */
.od-express-line { display: flex; align-items: center; gap: 6px; min-width: 0; }
.od-express-line > .od-sub { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.od-copy {
  flex: none; cursor: pointer; color: rgba(0, 0, 0, 0.3); font-size: 13px;
  padding: 1px 3px; border-radius: 4px; line-height: 1;
}
.od-copy:hover { color: #1677ff; background: rgba(22, 119, 255, 0.08); }
/* ── 「打单」列（2026-09-29 用户要求「列表要显示是已打还是待打」）────────────
   画法照优易打单弹窗：打过 = 蓝勾 + 文字划掉；没打 = 空心小方框 + 灰字。
   空心方框用 border 画（不引图标），免得未打的单摆一片灰勾看着像都打过了。 */
.od-print-flags { display: flex; flex-direction: column; gap: 1px; align-items: flex-start; }
.od-print-flag {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12px; color: rgba(0, 0, 0, 0.45); line-height: 1.4;
}
.od-print-flag-box {
  width: 9px; height: 9px; box-sizing: border-box; flex: none;
  border: 1px solid rgba(0, 0, 0, 0.25); border-radius: 2px;
}
.od-print-flag.is-done { color: #1677ff; }
.od-print-flag.is-done .od-print-flag-t { text-decoration: line-through; }
/* 打印选号（batchNo）：等宽数字，跟运单号/系统单号同一套 tabular-nums */
.od-batch { font-variant-numeric: tabular-nums; font-size: 12px; }
/* （.od-pager 的样式统一写在文件上方 .od-page 那一段：卡片内边距 + 上细线） */
/* 行内展开区：明细直接铺在订单行下面（参考优易），不弹窗 */
.od-expand { padding: 4px 0 10px; }
/* （原 `.od-expand-head`「商品明细（N 行）· 只读…」那行已按用户要求删掉） */
.od-expand-busy {
  display: flex; align-items: center; gap: 8px; padding: 16px 4px;
  color: rgba(0, 0, 0, 0.45);
}
/* 展开行自己就是一条 tr，别继承列表行的斑马纹/选中态。
   底色要跟白色订单行**明显区分**（浅蓝），不然一屏看不出哪几行是展开的。 */
.od-table .ant-table-expanded-row > td { background: #eef3fb; }
.od-table .ant-table-expanded-row:hover > td { background: #eef3fb; }
.od-table .ant-table-expanded-row .ant-table-expanded-row-fixed { padding: 8px 0; }
/* 排序列**不染底**（用户要求）：antd 默认给排序列的**整列**铺灰 —— 表头 #f5f5f5、
   单元格 #fafafa（`td.ant-table-column-sort`）。订单列表默认就按「关注点」的付款时间
   倒序，于是关注点这一列常年比别的列暗一档，看着像「选中 / 禁用」状态。
   排序状态表头那个蓝色小箭头已经说清楚了，底色纯属噪音。
   注意：下面这条 specificity 跟 antd 的 hover 规则一样高，会盖掉它，
   所以必须把 hover 色显式补回来，否则鼠标扫过整行时会单留这一格是白的。 */
/* ⚠️ 表头也要透明：老版设计里「所有表头都是 #fafafa」，所以排序列表头写 #fafafa 是
   **恰好同色**；公共层把表头统一改成透明后，这条 #fafafa 就变成「只有它灰一档」，
   必须跟着改成 transparent（2026-09-18 被 verify-orders.py 抓到）。 */
.od-table .ant-table-thead > tr > th.ant-table-column-sort { background: transparent; }
.od-table .ant-table-tbody > tr > td.ant-table-column-sort { background: transparent; }
.od-table .ant-table-tbody > tr.ant-table-row:hover > td.ant-table-column-sort,
.od-table .ant-table-tbody > tr > td.ant-table-cell-row-hover.ant-table-column-sort {
  background: #e6f4ff;
}
/* 明细表：整体**透明**，透出展开行那一个底色（之前表头是 #fff、底部汇总也是 #fff，
   浅蓝底上戳两块白，一屏看下来像三种背景）。 */
.od-sku-table .ant-table { background: transparent; }
.od-sku-table .ant-table-thead > tr > th { background: transparent; }
/* 行 hover 也别再冒出第二块颜色，只留一点白色浮起感即可 */
.od-sku-table .ant-table-tbody > tr:hover > td,
.od-sku-table .ant-table-tbody > tr > td { background: transparent; }
.od-sku-cell { display: flex; gap: 8px; align-items: flex-start; }
.od-sku-meta { min-width: 0; }
.od-sku-img { border-radius: 4px; object-fit: cover; flex: none; }
.od-sku-noimg {
  width: 50px; height: 50px; flex: none; display: flex; align-items: center;
  justify-content: center; background: rgba(0, 0, 0, .04); border-radius: 4px;
  color: rgba(0, 0, 0, 0.25);
}
.od-sku-name { line-height: 1.35; }
.od-sku-tag { margin-left: 6px; transform: scale(0.86); transform-origin: left center; }
/* 底部汇总行（买家留言 / 卖家备注 + 五项金额）：同样**不给独立底色**，
   靠一条分隔线跟上面的明细隔开，保持整块展开区只有一个背景色。
   分左右两组：留言/备注靠左，**五项金额贴右**（用户要求右对齐）——
   `margin-left:auto` 而不是 `justify-content:space-between`，
   这样窄屏折行时金额那组仍会整组靠右，不会跟留言挤成一坨。
   两组各自 `flex-wrap`，组内标签和数值按 baseline 对齐。 */
.od-expand-foot {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 18px;
  /* 左右各留 12px：留言/金额贴着表格边缘太挤（2026-09-19 用户要求）。
     border-top 在 padding 外面，分隔线仍是全宽的，只是文字往里收。 */
  margin-top: 10px; padding: 8px 12px 0;
  border-top: 1px solid rgba(0, 0, 0, .08);
  font-size: 12px; line-height: 20px;
}
.od-fee-left, .od-fee-right { display: flex; flex-wrap: wrap; gap: 4px 18px; }
.od-fee-right { margin-left: auto; justify-content: flex-end; }
.od-fee { white-space: nowrap; }
/* 展开区左侧的「有 N 行没有成本价」提示：琥珀色，够扎眼但不抢毛利的戏 */
.od-fee-warn { color: #d48806; font-size: 12px; }
.od-fee-label { color: rgba(0, 0, 0, 0.45); }
.od-fee-value { color: #1677ff; font-variant-numeric: tabular-nums; }
/* 展开区「可用库存」列：普通行就是一个数；组合行逐个组件一行
   （编码左、数字右，数字用 tabular-nums 上下对齐，扫一列就能比大小）。 */
.od-stock-parts { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.od-stock-part {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-variant-numeric: tabular-nums;
}
.od-stock-code {
  color: rgba(0, 0, 0, 0.45); font-size: 12px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 库存为 0：红字提示（跟「毛利为负」同一套红）。查不到的「—」不带色 —— 那是数据缺失，不是缺货。 */
.od-stock-zero { color: #cf1322; font-weight: 600; }

/* ── 表格行 hover 统一浅蓝 ──────────────────────────────────────────────
   用户要求：鼠标扫过列表行时用**浅蓝**（antd blue-1 #e6f4ff），替掉 antd 自带的 #fafafa 灰。
   作用范围是**全站表格**（用户只说「列表」，先按全局做；哪个页面想留着灰说一声）。
   ⚠️ specificity 必须压过 antd 自带的两条行 hover ——
   `.ant-table-tbody > tr.ant-table-row:hover > td`（0,4,0）和运行时给 td 加的
   `.ant-table-cell-row-hover`（antd 那条是 0,3,0）。这里两个选择器都提到 0,4,0；
   **不能只靠顺序**：antd 样式是运行时注入 <head>，排在静态 style.css 之后，同分它赢。 */
.ant-table-wrapper .ant-table-tbody > tr.ant-table-row:hover > td,
.ant-table-wrapper .ant-table-tbody > tr.ant-table-row > td.ant-table-cell-row-hover {
  background: #e6f4ff;
}
/* 上面那条会把「故意保留自己底色」的三类行也一起染蓝，逐条盖回来（都放它后面、同分或更高分）： */
/* ① 订单展开区里的商品明细表：整块透明，只透出展开行那一种底 ——
     不然鼠标扫进展开区会冒出第二种颜色，一屏看着花。 */
.od-sku-table.ant-table-wrapper .ant-table-tbody > tr.ant-table-row:hover > td,
.od-sku-table.ant-table-wrapper .ant-table-tbody > tr.ant-table-row > td.ant-table-cell-row-hover {
  background: transparent;
}
/* ② 待入库的缺货行：hover 保持红底（那是在提示少货，不能被蓝盖掉）。 */
.ant-table-wrapper .ant-table-tbody > tr.inbound-short-row:hover > td,
.ant-table-wrapper .ant-table-tbody > tr.inbound-short-row > td.ant-table-cell-row-hover {
  background: #ffe7e5;
}
/* ③ 采购表里被隐藏的行：hover 仍用灰，跟正常行区分开。 */
.ant-table-wrapper .ant-table-tbody > tr.purchase-row-hidden:hover > td,
.ant-table-wrapper .ant-table-tbody > tr.purchase-row-hidden > td.ant-table-cell-row-hover {
  background: #f5f5f5;
}


/* ── 线上商品对应（#/mapping）────────────────────────────────────────────
   订单异常页「去设置」的落地页：列出没对应系统商品的线上商品，并且能就地确认对应。
   排版走**卡片流**（不是 antd Table）：这一页是「店铺 → 线上款 → 线上SKU」三层，
   表格装不下（而且列宽会被内容重分配，见 .od-table 那段教训）；卡片在手机上也能直接竖排。 */
.gm-page { display: flex; flex-direction: column; gap: 12px; }
.gm-hint { margin: 0; }
.gm-filters { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; }
/* 「只看这一单」标签：内容是长平台单号 + 条数，antd 的 Tag 默认不换行，
   390px 下会顶出 2px 造成整页横向滚动（2026-09-25 实测 392/390）。让它换行收缩。 */
.gm-only { margin: 0; max-width: 100%; white-space: normal; }
.gm-empty { padding: 44px 0; text-align: center; }
.gm-store { display: flex; flex-direction: column; gap: 8px; }
.gm-store-head { display: flex; align-items: baseline; padding: 4px 2px 0;
  font-size: 13px; color: #1d2939; }
.gm-card { border-radius: 10px; }
.gm-card .ant-card-head { min-height: 0; padding: 10px 14px; }
.gm-card .ant-card-body { padding: 8px 14px 12px; display: flex;
  flex-direction: column; gap: 6px; }
.gm-card-title { display: flex; gap: 10px; align-items: center; }
.gm-online-pic img { border-radius: 6px; object-fit: cover; display: block; }
.gm-noimg { width: 48px; height: 48px; border-radius: 6px; background: #f2f4f7;
  color: #98a2b3; display: flex; align-items: center; justify-content: center; font-size: 12px; }
.gm-online-meta { min-width: 0; }
.gm-online-name { font-size: 13px; font-weight: 600; color: #1d2939; line-height: 1.4;
  max-width: 560px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gm-online-sub { font-size: 12px; color: #667085; line-height: 1.6; }
.gm-platform { color: #344054; }
.gm-link { font-size: 12px; }
/* 一行线上 SKU。桌面一行三段（线上 / 系统 / 操作），手机竖排。 */
.gm-sku { display: flex; gap: 12px; align-items: center; padding: 8px 10px;
  border: 1px solid #eaecf0; border-radius: 8px; background: #fff; }
.gm-sku.is-done { background: #fafafa; border-color: #f0f0f0; }
/* 从异常单「去设置」跳过来时，把**这一单真正要对应的那几条**标出来：
   一款底下可能挂着几十个 SKU（实测 33 个 / 14 个待确认），不标就完全看不出该点哪一条。
   左侧一道琥珀色竖条 + 淡黄底，扫列表时一眼能停住。 */
.gm-sku.is-target { background: #fffbe6; border-color: #ffe58f;
  box-shadow: inset 3px 0 0 #faad14; }
.gm-sku.is-target.is-done { background: #fffbe6; border-color: #ffe58f; }
.gm-target-tag { margin-right: 6px; }
/* 点名横幅：自动滚到目标行之后它会跑到视野外（目标可能在第 30 行），
   钉在滚动容器顶部 —— 边往下看边知道自己到底在找哪一条。 */
.gm-target-hint { margin: 0; position: sticky; top: 0; z-index: 5; }
.gm-sku-main { flex: 1 1 42%; min-width: 0; }
/* 每行 SKU 的缩略图：同一款底下几十条 SKU，编码长得很像（a432杏粉+花灰+甘石L /
   a432杏粉+甘石+黑灰L），光看文字容易对错行 —— 有图一眼就能认出是哪条。 */
.gm-sku-pic { flex: 0 0 auto; }
.gm-sku-pic img { border-radius: 6px; object-fit: cover; display: block; }
.gm-sku-noimg { width: 40px; height: 40px; border-radius: 6px; background: #f2f4f7;
  color: #98a2b3; display: flex; align-items: center; justify-content: center; font-size: 12px; }
.gm-sku-code { font-size: 13px; color: #1d2939; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.gm-sku-meta { font-size: 12px; color: #98a2b3; font-variant-numeric: tabular-nums; }
.gm-sku-sys { flex: 1 1 38%; min-width: 0; display: flex; gap: 8px; align-items: center; }
.gm-sku-sysname { font-size: 12px; color: #475467; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.gm-sku-tag, .gm-sku-act { flex: 0 0 auto; }
/* 写操作前的确认框：把「哪条线上商品 → 哪个系统商品」摆清楚。 */
.gm-confirm-row { display: flex; gap: 10px; padding: 4px 0; }
.gm-confirm-k { flex: 0 0 76px; font-size: 12px; color: #98a2b3; }
.gm-confirm-v { flex: 1 1 auto; color: #1d2939; word-break: break-all; }
.gm-confirm-target { font-weight: 600; color: #0958d9; }
.gm-confirm-warn { margin-top: 10px; padding: 8px 10px; border-radius: 6px;
  background: #fff7e6; color: #ad6800; font-size: 12px; line-height: 1.6; }
/* ── 批量对应（2026-09-27）：行首勾选 / 工具条 / 写前清单 ───────────────────── */
.gm-sku-pick { flex: 0 0 auto; display: flex; align-items: center; }
.gm-card-extra { display: flex; gap: 10px; align-items: center; }
/* 工具条用淡绿底（写前还在「可反悔」阶段），跟琥珀确认框、红色结果区分开。 */
.gm-batchbar { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center;
  padding: 8px 12px; border: 1px solid #d9f7be; border-radius: 8px; background: #f6ffed; }
.gm-batchbar-tip { font-size: 12px; color: #667085; }
.gm-batch { display: flex; flex-direction: column; gap: 10px; }
.gm-batch-alert { margin: 0; }
.gm-batch-prep { display: flex; gap: 10px; align-items: center; justify-content: center;
  padding: 14px 0; font-size: 13px; color: #475467; }
.gm-batch-sec-h { font-size: 12px; font-weight: 600; color: #667085; margin-bottom: 4px; }
/* 清单可能上百条（一款 90 行的那种）：限高滚动，别把确认框撑出屏。 */
.gm-batch-list { display: flex; flex-direction: column; gap: 4px;
  max-height: 44vh; overflow: auto; padding-right: 4px; }
.gm-batch-item { display: flex; gap: 8px; align-items: baseline; font-size: 12px;
  padding: 5px 8px; border: 1px solid #eaecf0; border-radius: 6px; background: #fafbfc; }
.gm-batch-item.is-bad { border-color: #ffccc7; background: #fff2f0; }
.gm-batch-status { flex: 0 0 auto; font-weight: 700; color: #389e0d; }
.gm-batch-item.is-bad .gm-batch-status { color: #cf1322; }
.gm-batch-online { color: #344054; word-break: break-all; }
.gm-batch-arrow { flex: 0 0 auto; color: #98a2b3; }
.gm-batch-target { color: #0958d9; font-weight: 600; word-break: break-all; }
.gm-batch-err { color: #cf1322; font-weight: 500; word-break: break-all; }
/* 逐条耗时（2026-09-28 加）：靠右一列小灰字，别抢「成功/失败」的注意力。 */
.gm-batch-ms { flex: 0 0 auto; margin-left: auto; color: #98a2b3;
  font-variant-numeric: tabular-nums; }
.gm-batch-ms-sum { font-size: 12px; color: #667085; margin: 2px 0 6px;
  font-variant-numeric: tabular-nums; }
.gm-pick-online { font-size: 12px; color: #667085; word-break: break-all; }
.gm-pick-list { display: flex; flex-direction: column; gap: 6px;
  max-height: 46vh; overflow: auto; }
.gm-pick-item { display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  padding: 8px 10px; border: 1px solid #eaecf0; border-radius: 8px; }
.gm-pick-item:hover { background: #f0f6ff; border-color: #91caff; }
.gm-pick-pic img { width: 40px; height: 40px; border-radius: 6px;
  object-fit: cover; display: block; }
.gm-pick-meta { flex: 1 1 auto; min-width: 0; }
.gm-pick-code { font-size: 13px; color: #1d2939; word-break: break-all; }
.gm-pick-name { font-size: 12px; color: #667085; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
/* 换商品的搜索结果展开**商品下面的规格**（2026-09-28 用户要求：需要对应的是具体的 sku）。
   对应关系本来就是规格级的 —— 款级「选它」按优易原规则取 `skus[-1]`（最后一条），
   一款底下挂几十条规格时必然对应错。头行留着（图 + 款号 + 名称 + 「规格 N 条 ↓」），
   规格单独一块、**自己滚**（`max-height`），免得 20 个结果 × 几十条规格把弹窗撑爆。 */
.gm-pick-head { display: flex; gap: 10px; align-items: center;
  flex: 1 1 auto; min-width: 0; cursor: pointer; }
.gm-pick-item.has-skus .gm-pick-head { cursor: default; }
.gm-pick-skuhint { flex: none; font-size: 12px; color: #0958d9;
  font-weight: 600; white-space: nowrap; }
.gm-pick-skus { flex: 1 1 100%; margin-top: 2px; padding-top: 6px;
  border-top: 1px dashed #eaecf0; max-height: 176px; overflow: auto;
  display: flex; flex-direction: column; gap: 4px; }
.gm-pick-sku { display: flex; gap: 8px; align-items: center; padding: 4px 8px;
  border: 1px solid transparent; border-radius: 6px; cursor: pointer; }
.gm-pick-sku:hover { background: #f0f6ff; border-color: #91caff; }
.gm-pick-sku-code { flex: 1 1 auto; min-width: 0; font-size: 12.5px; color: #1d2939;
  font-family: ui-monospace, Consolas, monospace; word-break: break-all; }
.gm-pick-sku-name { flex: 0 1 auto; min-width: 0; max-width: 42%; font-size: 12px;
  color: #667085; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 确认框里「对应到的规格」跟「对应到」（款号）并列摆出来，别只看见款号就点确认。 */
.gm-confirm-sku { font-weight: 600; color: #0958d9; }
.gm-pager { display: flex; justify-content: flex-end; padding-top: 4px; }
/* 「新建组合商品」弹窗：线上 SKU 的编码本身就是组合名（`a433小小花花+燕麦螺纹+花边直条M`），
   图就是线上那张。把组合名 / 编码 / 组件 / 成本一次摆清楚 —— 这几个值写进优易就是真的，
   建之前必须让人看明白。 */
.gm-combo { display: flex; flex-direction: column; gap: 10px; }
/* 组合名称（可手动改）：2026-09-22 加。用户在这里改名字 → 点「校验名称」→
   下面的编码 / 组件 / 成本按新名字重画 → 才允许点「创建并对应」。 */
.gm-combo-nameedit { margin: 8px 0 12px; padding: 10px 12px; border: 1px solid #eaecf0;
  border-radius: 8px; background: #fafbfc; }
.gm-combo-nameedit-row { display: flex; align-items: center; gap: 8px; }
.gm-combo-nameedit-row .gm-combo-k { flex: none; margin-right: 0; }
.gm-combo-name-input { flex: 1 1 auto; min-width: 0; }
.gm-combo-nameedit-hint { margin-top: 6px; font-size: 12px; line-height: 1.7; color: #98a2b3;
  word-break: break-word; }
.gm-combo-nameedit-hint code { padding: 0 4px; border-radius: 3px; background: #f2f4f7;
  color: #475467; }
.gm-combo-nameedit-err { margin-top: 6px; font-size: 12px; line-height: 1.7; color: #cf1322; }
.gm-combo-nameedit-ok { margin-top: 6px; font-size: 12px; line-height: 1.7; color: #389e0d; }
/* 窄屏：一行放不下「标签 + 输入框 + 按钮」→ 竖排、按钮占满一行。
   ⚠️ 输入框字号必须 16px（≤991px 那档）：iOS 聚焦到小字号输入框会整页放大。 */
@media (max-width: 991px) {
  .gm-combo-name-input { font-size: 16px; }
}
@media (max-width: 767px) {
  .gm-combo-nameedit-row { flex-wrap: wrap; }
  .gm-combo-name-input { flex: 1 1 100%; }
  .gm-combo-nameedit-row .ant-btn { width: 100%; }
}
.gm-combo-online { font-size: 12px; color: #667085; word-break: break-all; }
.gm-combo-k { margin-right: 6px; color: #98a2b3; }
.gm-combo-head { display: flex; gap: 12px; align-items: flex-start; }
.gm-combo-pic img { width: 72px; height: 72px; border-radius: 8px;
  object-fit: cover; display: block; }
.gm-combo-pic .gm-noimg { width: 72px; height: 72px; }
.gm-combo-meta { flex: 1 1 auto; min-width: 0; }
.gm-combo-name { font-size: 14px; font-weight: 600; color: #1d2939;
  line-height: 1.5; word-break: break-all; }
.gm-combo-sub { font-size: 12px; color: #667085; line-height: 1.7;
  font-variant-numeric: tabular-nums; word-break: break-all; }
.gm-combo-items { display: flex; flex-direction: column; gap: 4px; }
.gm-combo-items-head { font-size: 12px; color: #98a2b3; }
.gm-combo-item { display: flex; gap: 10px; align-items: baseline; padding: 6px 10px;
  border: 1px solid #eaecf0; border-radius: 6px; background: #fcfcfd; font-size: 12px; }
/* 组件在系统商品库里找不到 → 这个组合建不了，红底标出来，别让人点了个报错 */
.gm-combo-item.is-missing { border-color: #ffccc7; background: #fff2f0; }
.gm-combo-item-name { flex: 0 0 40%; color: #1d2939; word-break: break-all; }
.gm-combo-item-code { flex: 1 1 auto; color: #475467; word-break: break-all; }
/* 线上叫法 ≠ 系统叫法时把别名带出来（`a487甜奶杏` 是照 `a487杏` 搜到的）—— 小一号别抢戏 */
.gm-combo-alias { margin-left: 6px; color: #98a2b3; }
.gm-combo-item-cost { flex: 0 0 auto; color: #475467; font-variant-numeric: tabular-nums; }
.gm-combo-tip { margin: 0; }
@media (max-width: 767px) {
  .gm-online-name { max-width: none; }
  /* 手机上：缩略图 + 编码同一行，系统商品和按钮各自换行 ——
     整行改 column 的话那个 40px 的图会单独占一行，白白吃掉一条。 */
  .gm-sku { flex-wrap: wrap; align-items: center; gap: 6px 8px; }
  .gm-sku-main { flex: 1 1 60%; }
  .gm-sku-sys { flex: 1 1 100%; flex-direction: column; align-items: flex-start; gap: 4px; }
  .gm-sku-act { flex: 1 1 100%; display: flex; justify-content: flex-end; }
  .gm-confirm-k { flex: 0 0 62px; }
  /* 手机上组件名占满一行，编码和成本换到第二行 —— 390px 下三列挤成一团看不清 */
  .gm-combo-item { flex-wrap: wrap; gap: 2px 10px; }
  .gm-combo-item-name { flex: 1 1 100%; }
}

/* ═══════════════════════════════════════════════════════════════════════
   方向 04「轻盈」落地层 —— 与 design/pages.css 同一套 token
   ⚠️ 这一层只服务「已按效果图重做」的页面（目前：销售统计）。
      老页面的类名（.stat-card/.content-card/.m-row…）全部保留不动，
      免得 20+ 个 verify-*.py 变红。
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  /* 中性色：全部带一点点蓝调（chroma ≈ .005），不用纯灰 */
  --d-page: #EDEDEF;
  --d-surface: #FFFFFF;
  --d-panel: #F3F4F6;
  --d-panel-2: #F8F9FB;
  --d-ink: #111827;
  --d-ink-2: #6B7280;
  --d-ink-3: #9CA3AF;
  --d-line: #F0F1F4;
  --d-line-2: #E5E7EB;
  /* 强调色：只有一个主色 + 三个语义色 */
  --d-blue: #3B82F6;
  --d-blue-soft: #EAF2FE;
  --d-amber: #F59E0B;
  --d-amber-ink: #B4761A;
  --d-amber-soft: #FEF4E4;
  --d-green: #10B981;
  --d-green-ink: #0E8A66;
  --d-green-soft: #E7F7F1;
  --d-violet: #8B5CF6;
  --d-violet-soft: #F1ECFE;
  --d-red: #EF4444;
  --d-red-ink: #D64545;
  --d-red-soft: #FEECEC;
  /* 圆角：三档，不要出现第四种 */
  --d-r-lg: 22px;
  --d-r-md: 16px;
  --d-r-sm: 11px;
  --d-r-pill: 999px;
  /* 阴影：只有两级 */
  --d-sh-1: 0 1px 2px rgba(17, 24, 39, .04);
  --d-sh-2: 0 1px 2px rgba(17, 24, 39, .04), 0 16px 40px rgba(17, 24, 39, .07);
}

/* ── 页内标题（页面自己的大标题 + 副标题 + 右侧操作） ─────────────── */
.shead { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 18px; }
.shead h1 { margin: 0; font-size: 25px; font-weight: 800; letter-spacing: -.035em; color: var(--d-ink); }
.shead p { margin: 7px 0 0; font-size: 13px; color: var(--d-ink-3); }
.shead p b { color: var(--d-ink-2); font-weight: 700; }
.shead-right { margin-left: auto; flex: 0 0 auto; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; justify-content: flex-end; }

/* ── 口径提示条 ────────────────────────────────────────────────────── */
.salert { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-radius: 13px;
  font-size: 12px; line-height: 1.65; margin-bottom: 14px; }
.salert svg { width: 16px; height: 16px; flex: 0 0 16px; margin-top: 2px; }
.salert b { font-weight: 800; }
.salert.info { background: var(--d-blue-soft); color: #1E4E8C; }
.salert.warn { background: var(--d-amber-soft); color: #8A5A10; }
.salert.err { background: var(--d-red-soft); color: #A63232; }
.salert .salert-x { margin-left: auto; flex: 0 0 auto; cursor: pointer; opacity: .55; font-size: 12px; padding: 0 2px; }
.salert .salert-x:hover { opacity: 1; }
/* 提示条右端的控件（补货建议的「覆盖 N 天」）：跟文案同一行、靠右、不换行 */
.salert-ctrl { margin-left: auto; flex: 0 0 auto; display: inline-flex; align-items: center;
  font-weight: 700; white-space: nowrap; }
.salert-ctrl .ant-input-number { border-radius: 8px; }

/* ── KPI 横排：图标胶囊 + 1px 细线分隔（不做卡片） ─────────────────── *
 * 比四张卡省一半纵向空间。规范：KPI 不做卡片，靠留白和细线分层。      */
.skpis { display: flex; background: var(--d-surface); border-radius: var(--d-r-md);

/* 销售统计：KPI 数据块兼作趋势图的指标开关（点哪个看哪个，2026-09-23 用户要求）。
   只改文字色 —— 这排靠 1px 细线分层，加背景块会破坏分隔感；
   「当前看的是哪个」在趋势图标题里也回显了一份。 */
.skpis .sk.is-clickable { cursor: pointer; }
.skpis .sk.is-clickable:hover .lab,
.skpis .sk.is-clickable:hover .num { color: var(--d-blue); }
.skpis .sk.is-active .lab,
.skpis .sk.is-active .num { color: var(--d-blue); }
  box-shadow: var(--d-sh-1); padding: 20px 18px; margin-bottom: 18px; }
.sk { flex: 1 1 0; min-width: 0; display: flex; gap: 11px; padding: 0 16px;
  border-right: 1px solid var(--d-line-2); }
.sk:first-child { padding-left: 0; }
.sk:last-child { border-right: none; padding-right: 0; }
.sk-ic { width: 38px; height: 38px; flex: 0 0 38px; border-radius: 12px;
  display: flex; align-items: center; justify-content: center; font-size: 17px; }
.sk-tx { min-width: 0; flex: 1 1 auto; }
.sk-tx .lab { display: flex; align-items: center; gap: 4px; font-size: 12px; color: var(--d-ink-2); white-space: nowrap; }
.sk-tx .num { margin-top: 7px; font-size: 23px; font-weight: 800; letter-spacing: -.035em;
  font-variant-numeric: tabular-nums; line-height: 1.2; color: var(--d-ink); white-space: nowrap; }
.sk-tx .num em { font-style: normal; font-size: 10.5px; font-weight: 700; margin-left: 6px; letter-spacing: 0; }
.sk-tx .num .sk-unit { font-size: 12px; font-weight: 700; margin-left: 3px; color: var(--d-ink-2); }
.sk-tx .sub { margin-top: 6px; font-size: 10.5px; color: var(--d-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sk-tx .sub .sk-trim { font-weight: 700; color: var(--d-ink-3); border-bottom: 1px dashed var(--d-line-2); cursor: help; }
/* 图标胶囊配色：跟 KPI 语义绑定，不随意换 */
.sk-ic.is-blue { background: var(--d-blue-soft); color: var(--d-blue); }
.sk-ic.is-cyan { background: #E4F6F6; color: #2E9A96; }
.sk-ic.is-violet { background: var(--d-violet-soft); color: var(--d-violet); }
.sk-ic.is-amber { background: var(--d-amber-soft); color: var(--d-amber-ink); }
.sk-ic.is-green { background: var(--d-green-soft); color: var(--d-green-ink); }

/* ── 表格：表头细线 + 48px 行高 + 数字右对齐加粗（无斑马纹） ───────── */
/* ── 已发货退货台账（2026-09-30）────────────────────────────────────────────
   两块：卡里的汇总/提示行，和「记一笔」弹窗的两列表单。手机上表单塌成一列。 */
.ret-sum { font-size: 12.5px; line-height: 1.8; margin-bottom: 10px; }
.ret-sum .ret-warn { color: #A63232; }
.ret-sub { font-size: 11.5px; color: var(--d-ink-3); }
/* 不在本区间的退货行：淡一点 + 一个标签（**绝不藏起来** —— 藏了就成了「提交了却看不见」，
   2026-09-30 用户就是这么撞上的） */
.ret-row-out > td { opacity: .62; }
.ret-row-out:hover > td { opacity: .9; }
.ret-out-tag { margin-left: 6px; font-size: 11px; }
.m-card.is-out { opacity: .62; }
.ret-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 12px; }
.ret-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ret-field > label { font-size: 12px; color: var(--d-ink-3); }
.ret-field-switch { justify-content: flex-start; }
.ret-field-switch .ant-switch { margin-top: 2px; }
.ret-tip { margin-top: 12px; font-size: 12px; color: var(--d-ink-3); line-height: 1.7; }
/* 「填平台单号 → 查一下」那一块：输入框和按钮并排，商品清单整行铺开 */
.ret-field-wide { grid-column: 1 / -1; }
.ret-lookup { margin-top: 6px; align-self: flex-start; }
.ret-info { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 6px; }
.ret-note { grid-column: 1 / -1; font-size: 12px; color: var(--d-ink-3); line-height: 1.7; }
.ret-cands { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 6px; }
.ret-goods { border: 1px solid var(--d-line); border-radius: 10px; overflow: hidden; }
.ret-goods-row {
  display: flex; align-items: center; gap: 10px; padding: 7px 10px;
  font-size: 12.5px; border-bottom: 1px solid var(--d-line);
}
.ret-goods-row:last-child { border-bottom: none; }
.ret-goods-row.is-gift { background: var(--d-panel-2); }
.ret-goods-sku { flex: 0 0 108px; font-weight: 700; color: var(--d-ink); }
.ret-goods-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--d-ink-2); }
.ret-goods-spec { margin-left: 6px; color: var(--d-ink-3); font-size: 11.5px; }
.ret-goods-qty { flex: 0 0 58px; text-align: right; color: var(--d-ink-2); }
.ret-goods-money { flex: 0 0 86px; text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--d-ink); }
@media (max-width: 767px) {
  .ret-grid { grid-template-columns: 1fr; }
  .ret-goods-sku { flex-basis: 84px; }
}

.stable-wrap { width: 100%; }
.stable-wrap .ant-table-thead > tr > th { background: transparent !important; border-bottom: 1px solid var(--d-line-2) !important;
  color: var(--d-ink-3); font-size: 11px; font-weight: 700; letter-spacing: .02em; }
/* antd 的排序列常年铺灰底，重做后按规范去掉 */
.stable-wrap .ant-table-thead > tr > th::before { display: none !important; }
.stable-wrap .ant-table-thead > tr > th.ant-table-column-sort, .stable-wrap .ant-table-thead > tr > th.ant-table-column-has-sorters:hover { background: transparent !important; }
.stable-wrap .ant-table-thead > tr > th.ant-table-column-has-sorters:hover { color: var(--d-ink-2); }
.stable-wrap .ant-table-tbody > tr > td { border-bottom: 1px solid var(--d-line) !important; color: var(--d-ink-2); }
.stable-wrap .ant-table-tbody > tr:last-child > td { border-bottom: none !important; }
.stable-wrap .ant-table-tbody > tr > td.ant-table-cell { padding-top: 12px; padding-bottom: 12px; }
/* 数字列等宽 + 加粗 */
.stable-wrap .num-cell { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--d-ink); }
.stable-wrap .money-cell { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--d-ink); }
/* 合计行：淡底 + 加粗，跟数据行分层 */
.stable-wrap .ant-table-tbody > tr.store-row-total > td { background: var(--d-panel-2) !important; font-weight: 800; color: var(--d-ink); }
.stable-wrap .ant-table-tbody > tr.store-row-active > td { background: var(--d-blue-soft) !important; }
/* 商品单元格：缩略图 + 名称 + 编码 */
.pcell { display: flex; align-items: center; gap: 10px; min-width: 0; }
.pthumb { width: 32px; height: 32px; flex: 0 0 32px; border-radius: 9px; overflow: hidden; }
.pthumb .ant-image, .pthumb .ant-image-img { width: 32px; height: 32px; display: block; }
.pthumb .ant-image-img { object-fit: cover; }
.pcell-tx { min-width: 0; }
.pcell-tx b { display: block; font-size: 12.5px; font-weight: 700; color: var(--d-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcell-tx span { display: block; margin-top: 2px; font-size: 10.5px; color: var(--d-ink-3); }
.pcell-tx span em { font-style: normal; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* ── 柱状图：圆角 4px 顶部，最高值 / 今天用琥珀强调 ────────────────── */
.barchart { padding-top: 8px; }
/* ⚠️ 必须是 align-items: stretch（默认值），不能写 flex-end。
   柱子高度是百分比，参照的是 .b 的高度；一旦 flex-end，.b 就不被拉伸、高度收缩成内容高（=柱子自身），
   百分比高度变成循环依赖 → 解析为 auto → 所有柱子只剩 min-height，看上去「一根线、没有高度」（2026-09-20 修复）。
   贴底靠 .b 自己的 justify-content: flex-end，不靠这里。 */
.barchart .bars { display: flex; align-items: stretch; gap: 6px; height: 150px; padding-top: 24px; }
.barchart .b { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; justify-content: flex-end; position: relative; }
.barchart .b u { display: block; border-radius: 4px 4px 2px 2px; background: var(--d-blue); text-decoration: none;
  min-height: 6px; transition: opacity .15s; }
.barchart .b u.amber { background: var(--d-amber); }
.barchart .b:hover u { opacity: .85; }
/* 柱顶金额：跟柱子一起抬高 —— bottom 由 app.js 按同一个百分比内联给出（`calc(<pct>% + 5px)`）。
   这里的 bottom:0 只是没拿到内联值时的兜底。 */
.barchart .b .v { position: absolute; left: 0; right: 0; bottom: 0; margin-bottom: 0;
  text-align: center; font-size: 10.5px; font-weight: 700; color: var(--d-ink-2);
  font-variant-numeric: tabular-nums; }
/* 天数多（>15，app.js 加 .is-many）柱子就窄，柱顶金额会互相压住 —— 窄屏干脆不显示，
   金额改挂柱子 title（悬停 / 长按看）。宽屏卡片够宽，数字仍放得下，保留。 */
.barchart.is-many .b .v { display: none; }
@media (min-width: 1400px) { .barchart.is-many .b .v { display: block; } }
.barchart .x { display: flex; gap: 6px; margin-top: 8px; }
.barchart .x span { flex: 1 1 0; min-width: 0; text-align: center; font-size: 10px; color: var(--d-ink-3);
  font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ── 分页条：文案在左，页码胶囊在右（不用 antd 默认样式） ──────────── */
.spage { display: flex; align-items: center; gap: 10px; padding: 14px 0 0; font-size: 11.5px; color: var(--d-ink-3); }
.spage .pgs { margin-left: auto; display: flex; align-items: center; gap: 5px; }
.spage .pg { min-width: 27px; height: 27px; padding: 0 7px; border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center; font-size: 11.5px;
  font-weight: 700; color: var(--d-ink-2); background: var(--d-panel-2); cursor: pointer;
  border: none; font-variant-numeric: tabular-nums; }
.spage .pg:hover { background: var(--d-panel); color: var(--d-ink); }
.spage .pg.on { background: var(--d-blue); color: #fff; }
.spage .pg[disabled] { opacity: .4; cursor: default; }
.spage .pg[disabled]:hover { background: var(--d-panel-2); color: var(--d-ink-2); }

/* 用 antd Pagination 但套成 spage 风格（商品明细沿用 antd 的分页逻辑） */
.spage-antd { display: flex; align-items: center; padding: 14px 0 0; font-size: 11.5px; color: var(--d-ink-3); }
.spage-antd .ant-pagination { margin-left: auto; }
.spage-antd .ant-pagination-item, .spage-antd .ant-pagination-prev .ant-pagination-item-link,
.spage-antd .ant-pagination-next .ant-pagination-item-link { border: none; border-radius: 8px; background: var(--d-panel-2); }
.spage-antd .ant-pagination-item a { color: var(--d-ink-2); font-weight: 700; font-size: 11.5px; }
.spage-antd .ant-pagination-item-active { background: var(--d-blue); }
.spage-antd .ant-pagination-item-active a { color: #fff; }
.spage-antd .ant-pagination-item:hover { background: var(--d-panel); }
.spage-antd .ant-pagination-item-active:hover { background: var(--d-blue); }
.spage-antd .ant-pagination-item-active:hover a { color: #fff; }

/* ── 内容卡 / 区块标题（§6）────────────────────────────────────────── *
 * 规范 §4 禁止「万物皆卡片 / 卡片套卡片」：页面里的区块优先用 .scard    *
 * （一层）+ .ssec 标题（无卡片背景），不要在 .scard 里再套 .scard。      *
 * 桌面是白底白卡，靠 1px 细描边 + 极轻阴影分层（跟公共层的 .ant-card 一致）。*/
.scard { background: var(--d-surface); border: 1px solid var(--d-line-2); border-radius: var(--d-r-md);
  box-shadow: var(--d-sh-1); overflow: hidden; }
.scard.is-flat { background: transparent; border: none; box-shadow: none; border-radius: 0; }
.scard-h { display: flex; align-items: center; gap: 10px; padding: 15px 16px 12px; }
.scard-h h2 { margin: 0; font-size: 15.5px; font-weight: 800; letter-spacing: -.025em; color: var(--d-ink); }
.scard-h .sub { font-size: 11.5px; color: var(--d-ink-3); }
.scard-h .right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.scard-body { padding: 0 16px 16px; }
/* 表格塞进 .scard 时：表头/末行不要各自留边，卡片自己收边 */
.scard > .stable-wrap:first-child, .scard > .ant-table-wrapper:first-child { margin-top: 4px; }
.scard > .stable-wrap:last-child, .scard > .ant-table-wrapper:last-child { margin-bottom: -1px; }
.scard > .spage-antd, .scard > .spage { padding: 12px 16px 14px; margin: 0; border-top: 1px solid var(--d-line); }
.scard.is-pad { padding: 16px; }
.scard.is-pad > .stable-wrap:first-child { margin-top: 0; }
/* 卡片里那些「散装」内容（骨架屏 / 空态 / 手机卡列表 / 批量操作条）得自己补内边距 ——
   表格是直接子元素、本来就该贴边，这些不是。 */
.scard > .ant-skeleton { padding: 0 16px 16px; }
.scard > .ant-empty { padding: 8px 16px 24px; }
.scard > .inbound-cards { padding: 0 16px 16px; }
.scard > .inbound-bulkbar { margin: 0 16px 12px; }

/* 区块标题（没有卡片背景时用；总览的「库存健康度 / 库存货值」） */
.ssec { display: flex; align-items: center; gap: 10px; margin: 16px 0 10px; }
.ssec h2 { margin: 0; font-size: 15.5px; font-weight: 800; letter-spacing: -.025em; color: var(--d-ink); }
.ssec .sub { font-size: 11.5px; color: var(--d-ink-3); }
.ssec .right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.ssec:first-child { margin-top: 0; }

/* ── 胶囊 / 小标签（§6）────────────────────────────────────────────── */
.spill { display: inline-flex; align-items: center; gap: 7px; height: 30px; padding: 0 12px;
  border-radius: var(--d-r-pill); border: 1px solid var(--d-line-2); font-size: 11.5px; font-weight: 700;
  color: var(--d-ink-2); background: var(--d-surface); white-space: nowrap; }
.spill.soft { border-color: transparent; background: var(--d-panel); }
/* 三重编码：色块 + 文字 + 圆点（§3.4，色弱/强光下也要分得清） */
.chip { display: inline-flex; align-items: center; gap: 6px; height: 22px; padding: 0 9px;
  border-radius: var(--d-r-pill); font-size: 11px; font-weight: 700; white-space: nowrap; }
.chip i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 6px; }
.chip.amber { background: var(--d-amber-soft); color: var(--d-amber-ink); }
.chip.green { background: var(--d-green-soft); color: var(--d-green-ink); }
.chip.gray { background: var(--d-panel); color: var(--d-ink-3); }
.chip.red { background: var(--d-red-soft); color: var(--d-red-ink); }
.chip.blue { background: var(--d-blue-soft); color: var(--d-blue); }
.chip.violet { background: var(--d-violet-soft); color: var(--d-violet); }
.chip.plain { background: transparent; border: 1px solid var(--d-line-2); color: var(--d-ink-3); }

/* ── 筛选条 / 次级按钮 / 选择器（§3.1、列表页配方 §2.3②）─────────────── */
.sfilter { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-bottom: 14px; }
.sfilter .sep { flex: 1 1 auto; }
/* 筛选条里的纯文字标签（「近期发货量统计近」「进货月份」）：跟数字框/选择器配对用，
   也可能出现在页内标题右侧（入库页的月份），所以不放在 .sfilter 作用域里。 */
.sfilter-label { font-size: 11.5px; color: var(--d-ink-3); white-space: nowrap; }
.sbtn { display: inline-flex; align-items: center; justify-content: center; gap: 7px; height: 34px;
  padding: 0 15px; border-radius: var(--d-r-sm); font-size: 12.5px; font-weight: 700; white-space: nowrap;
  background: var(--d-panel-2); color: var(--d-ink-2); border: 1px solid var(--d-line-2);
  cursor: pointer; transition: background .15s, border-color .15s, color .15s; }
.sbtn:hover { background: var(--d-panel); color: var(--d-ink); }
.sbtn.primary { background: var(--d-blue); color: #fff; border-color: var(--d-blue); }
.sbtn.primary:hover { background: #2f74e0; color: #fff; }
.sbtn.dark { background: var(--d-ink); color: #fff; border-color: var(--d-ink); }
.sbtn.icon { width: 34px; padding: 0; }
.sbtn.sm { height: 28px; padding: 0 11px; font-size: 11.5px; border-radius: 9px; }
.sbtn[disabled], .sbtn.is-disabled { opacity: .45; cursor: not-allowed; }
.sinput { display: inline-flex; align-items: center; gap: 8px; height: 34px; padding: 0 13px;
  border-radius: var(--d-r-sm); background: var(--d-panel-2); border: 1px solid var(--d-line-2);
  font-size: 12.5px; color: var(--d-ink-3); }
.sinput.wide { width: 100%; }
.sinput.pill { border-radius: var(--d-r-pill); }
.sselect { display: inline-flex; align-items: center; gap: 8px; height: 34px; padding: 0 11px 0 13px;
  border-radius: var(--d-r-sm); background: var(--d-panel-2); border: 1px solid var(--d-line-2);
  font-size: 12.5px; font-weight: 600; color: var(--d-ink-2); white-space: nowrap; }

/* ── 独立小卡（§5：只有需要额外说明的块才用，如「库存货值」）─────────── */
.skcard { background: var(--d-surface); border: 1px solid var(--d-line-2); border-radius: var(--d-r-md);
  padding: 15px 16px 16px; box-shadow: var(--d-sh-1); }
.skcard .lab { font-size: 11.5px; color: var(--d-ink-3); }
.skcard .num { margin-top: 9px; font-size: 22px; font-weight: 800; letter-spacing: -.035em;
  font-variant-numeric: tabular-nums; line-height: 1; color: var(--d-ink); }
.skcard .sub { margin-top: 9px; font-size: 10.5px; color: var(--d-ink-3); }

/* ══════════════════════════════════════════════════════════════════════════
   右栏（§2.2）—— 只有「仪表盘页」（库存总览 / 发货统计）才挂，316px。
   判断标准写在规范里：数据密集分析 / 列表 / 表单 / 向导 / 卡片树一律不要。
   加右栏会让内容区从 1084 掉到 768，页面里的 scroll.x 常量要跟着改。
   ══════════════════════════════════════════════════════════════════════════ */
.sbody { display: flex; align-items: flex-start; gap: 0; width: 100%; min-height: 0; }
.smain { flex: 1 1 auto; min-width: 0; }
/* 有右栏时给主区留出间距（右栏 316 + 间距 14） */
.sbody.has-rail .smain { padding-right: 14px; }
.srail { width: 316px; flex: 0 0 316px; }
.srail-in { background: var(--d-panel); border-radius: 18px; display: flex; flex-direction: column;
  padding: 20px 16px 16px; }
.sprofile { text-align: center; }
.savatar { width: 58px; height: 58px; margin: 0 auto; border-radius: 50%; position: relative;
  display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 800;
  color: #fff; letter-spacing: -.02em; }
.savatar i { position: absolute; right: 0; bottom: 1px; width: 14px; height: 14px; border-radius: 50%;
  background: var(--d-green); border: 2.5px solid var(--d-panel); }
.sprofile b { display: block; margin-top: 11px; font-size: 14.5px; font-weight: 800; letter-spacing: -.02em;
  color: var(--d-ink); }
.sprofile span { display: block; margin-top: 3px; font-size: 11px; color: var(--d-ink-3); }
.sacts { display: flex; justify-content: center; gap: 9px; margin-top: 14px; }
.sact { width: 40px; height: 40px; border-radius: 13px; background: var(--d-surface);
  display: flex; align-items: center; justify-content: center; color: var(--d-ink-2);
  box-shadow: var(--d-sh-1); cursor: pointer; font-size: 17px; transition: color .15s; }
.sact:hover { color: var(--d-blue); }
.sdiv { margin: 18px 0 12px; padding-top: 14px; border-top: 1px solid var(--d-line-3);
  font-size: 12px; font-weight: 700; color: var(--d-ink-2); }
.sdiv.is-left { text-align: left; }
.sfeed { min-height: 0; }
.sitem { display: flex; gap: 10px; margin-bottom: 14px; }
.sitem-av { width: 28px; height: 28px; flex: 0 0 28px; border-radius: 50%; display: flex;
  align-items: center; justify-content: center; font-size: 10px; font-weight: 800; color: #fff; }
.sitem-bd { flex: 1 1 auto; min-width: 0; }
.sitem-hd { display: flex; align-items: baseline; gap: 8px; }
.sitem-hd b { font-size: 11.5px; font-weight: 800; color: var(--d-ink); }
.sitem-hd span { margin-left: auto; font-size: 10px; color: var(--d-ink-3); }
.sitem-tx { margin-top: 3px; font-size: 10.5px; color: var(--d-ink-3); line-height: 1.5; }
.sitem-bub { margin-top: 6px; background: var(--d-surface); border-radius: 11px; padding: 9px 11px;
  font-size: 10.5px; line-height: 1.6; color: var(--d-ink-2); }
.srail-empty { background: var(--d-surface); border-radius: 13px; padding: 14px 13px; font-size: 11px;
  line-height: 1.7; color: var(--d-ink-3); }
.srail-empty b { display: block; color: var(--d-ink-2); font-size: 12px; margin-bottom: 4px; }
/* 「最该做的一件事」浅蓝卡（规范 §2.1：这不是广告位，是当前最该做的一件事） */
.srail-cta { background: var(--d-blue-soft); border-radius: 15px; padding: 14px 14px 13px; }
.srail-cta b { display: block; font-size: 13px; font-weight: 800; letter-spacing: -.015em; color: var(--d-ink); }
.srail-cta span { display: block; margin-top: 4px; font-size: 10.5px; line-height: 1.6; color: var(--d-ink-2); }
.srail-cta u { display: inline-flex; align-items: center; height: 30px; margin-top: 11px; padding: 0 15px;
  border-radius: var(--d-r-pill); background: var(--d-blue); color: #fff; font-size: 11px; font-weight: 700;
  text-decoration: none; cursor: pointer; }
.srail-list { display: flex; flex-direction: column; gap: 8px; }
.srail-row { display: flex; align-items: center; gap: 10px; background: var(--d-surface);
  border-radius: 13px; padding: 11px 12px; cursor: pointer; }
.srail-row:hover { background: var(--d-blue-soft); }
.srail-row-bd { flex: 1 1 auto; min-width: 0; }
.srail-row-bd b { display: block; font-size: 12px; font-weight: 700; color: var(--d-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.srail-row-bd span { display: block; margin-top: 2px; font-size: 10.5px; color: var(--d-ink-3); }
.srail-num { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--d-ink); }

/* 独立小卡一排（库存货值那种「需要额外说明的块」，§5） */
.skcard-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 4px; }
.skcard-row.is-2 { grid-template-columns: repeat(2, 1fr); }
/* 卡片并排（发货统计的三个排行：平台 / 快递 / 仓库） */
.scard-row { display: flex; gap: 14px; align-items: flex-start; }
.scard-row > * { flex: 1 1 0; min-width: 0; }

/* 排行行（右栏「发货状态」和卡片里的占比条）：标签 + 数值 + 细条，§3.6 */
.rstats { display: flex; flex-direction: column; gap: 2px; }
.rstat { display: flex; align-items: center; gap: 10px; height: 40px; padding: 0 4px; }
.rstat .k { font-size: 11.5px; color: var(--d-ink-2); min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.rstat .v { margin-left: auto; font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--d-ink); }
.rstat .bar { width: 54px; height: 5px; border-radius: 3px; background: var(--d-line-2); overflow: hidden; }
.rstat .bar i { display: block; height: 100%; border-radius: 3px; }

/* 柱状图：最高的那天用琥珀强调 */
.bar-fill.is-max { background: linear-gradient(180deg, #FBC96B, var(--d-amber)); }

/* ── 加载遮罩：白底半透明，别用 antd 默认的灰 ──────────────────────── */
.skpis .ant-skeleton-input, .stable-wrap .ant-spin-blur { opacity: .45; }

/* ── 窄屏（390px）：KPI 换两列网格、标题竖排、提示条收紧 ───────────── *
 * 规范硬要求：390px 下必须能用，行高 ≥ 52px，不许出现横向滚动条。      */
@media (max-width: 767px) {
  /* 页内标题：右侧操作换到下一行，日期 / 店铺选择器各占一半宽 */
  .shead { flex-direction: column; gap: 10px; margin-bottom: 14px; }
  .shead h1 { font-size: 21px; }
  .shead p { margin-top: 5px; font-size: 12px; }
  .shead-right { margin-left: 0; width: 100%; justify-content: flex-start; gap: 8px; }
  .shead-right .ant-picker { flex: 1 1 auto; min-width: 0; }
  .shead-right .ant-select { flex: 1 1 auto; min-width: 0; width: auto !important; }
  .shead-right .ant-select-selector { width: 100%; }

  /* 提示条：字号收到 11.5，行距放松一点，别把首屏挤满 */
  .salert { padding: 10px 12px; font-size: 11.5px; line-height: 1.6; border-radius: 12px; margin-bottom: 12px; }
  /* 右端控件（补货建议的「覆盖 N 天」）在窄屏换到下一行，别把提示文案挤成一条竖线 */
  .salert { flex-wrap: wrap; }
  .salert-ctrl { margin-left: 0; width: 100%; justify-content: flex-start; }

  /* KPI：横排改成 2 列网格（5 个 → 2+2+1），细线分隔改上边线 */
  .skpis { display: grid; grid-template-columns: 1fr 1fr; gap: 0; padding: 6px 14px 14px; }
  .sk { padding: 15px 0; border-right: none; border-bottom: 1px solid var(--d-line); }
  .sk:first-child { padding-left: 0; }
  .sk:last-child { border-right: none; padding-right: 0; }
  /* 第 1、2 项下面有线；最后一行（可能 1 个）不画线 */
  .sk:nth-last-child(-n+1) { border-bottom: none; }
  .sk:nth-child(odd) { padding-right: 12px; border-right: 1px solid var(--d-line); }
  .sk:nth-child(even) { padding-left: 12px; }
  .sk:nth-last-child(-n+2) { border-bottom: none; }
  .sk-ic { width: 32px; height: 32px; flex: 0 0 32px; border-radius: 10px; font-size: 15px; }
  .sk { gap: 9px; }
  /* 数字放大后，毛利/净利润的「数字 + 百分比」在半栏（约 129px）里放不下，
     会把整页顶出横向滚动条 → 窄屏把百分比换到数字下一行（信息不丢，只是竖排）。 */
  .sk-tx .num { font-size: 19px; margin-top: 5px; }
  .sk-tx .num em { display: block; margin-left: 0; margin-top: 3px; font-size: 10px; }
  .sk-tx .lab { font-size: 11px; }
  .sk-tx .num .sk-unit { font-size: 11px; }
  /* 副标题（口径说明）手机上一行放不下，截断靠 title 看全 */
  .sk-tx .sub { margin-top: 5px; font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }

  /* 柱状图：柱子变窄、天数多时横向滚（别挤成一条线） */
  .barchart .bars { height: 118px; gap: 5px; padding-top: 22px; }
  .barchart .x { gap: 5px; }
  .barchart .b .v { font-size: 10px; }

  /* 分页条：手机上「显示 1-3 / 共 128 个」和页码分两行 */
  .spage-antd { flex-wrap: wrap; gap: 8px; }
  .spage-antd .ant-pagination { margin-left: 0; width: 100%; justify-content: flex-end; }

  /* 右栏：手机上不挂（规范 §2.2 右栏是桌面专属；390px 下表格/内容吃满宽度） */
  .srail { display: none; }
  .sbody.has-rail .smain { padding-right: 0; }

  /* 独立小卡一排：手机换两列（跟 KPI 网格一个节奏） */
  .skcard-row { grid-template-columns: 1fr 1fr; gap: 10px; }
  /* 并排卡片：手机一律竖排（三栏排行在半栏里没法看） */
  .scard-row { flex-direction: column; gap: 12px; align-items: stretch; }

  /* 区块标题 / 卡片标题：一行放不下就换行（标题 + 胶囊 + 说明 + 右侧操作，
     390px 下一行肯定不够，不 wrap 会把整页顶出横向滚动条 —— 实测过）。 */
  .ssec, .scard-h { flex-wrap: wrap; }
  .ssec .right, .scard-h .right { margin-left: 0; width: 100%; justify-content: flex-start; }
  .ssec .sub, .scard-h .sub { flex: 1 1 100%; }
  .ssec h2, .scard-h h2 { flex: 0 0 auto; }

  /* 内容卡 / 区块标题：内边距收紧，标题字号下一档 */
  .scard-h { padding: 13px 13px 10px; }
  .scard-h h2, .ssec h2 { font-size: 14.5px; }
  .scard-body { padding: 0 13px 13px; }
  .scard.is-pad { padding: 13px; }
  .scard > .spage-antd, .scard > .spage { padding: 11px 13px 12px; }
  .ssec { margin: 13px 0 9px; }
  /* 筛选条：控件一行放不下就换行，搜索框占满整行 */
  .sfilter { gap: 8px; margin-bottom: 12px; }
  .sfilter .sinput.wide, .sfilter .sinput { width: 100%; }
  .sbtn { height: 32px; padding: 0 13px; font-size: 12px; }
  .spill { height: 28px; padding: 0 10px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   方向 04「轻盈」公共层 —— 外壳 + antd 组件
   ──────────────────────────────────────────────────────────────────────────
   上面一层只落了「销售统计」页内那套（.shead/.skpis/.stable-wrap/...）。
   这一层把**全站公共部分**也换成设计稿方向 04：外壳、导航、页签、顶栏，
   以及所有 antd 组件（Button / Input / Select / Table / Card / Modal / Alert /
   Tag / Empty / Pagination / Tooltip / Drawer / Steps / Switch / Badge）。
   值全部取自 design/DESIGN-SYSTEM.md §1，不新造颜色/圆角/间距。

   ⚠️ 三条硬约束（规范 §7）：
     1. 多标签页是自绘的（可拖拽 / 右键菜单 / 切走不卸载）—— 只换皮，别改交互，
        所以这里只覆写颜色/圆角/高度，不动 position/draggable 相关规则。
     2. 20+ 个 verify-*.py 依赖 .app-sider/.app-header/.app-tab/.tab-pane/
        .ant-table-* 这些类名 —— 类名一个都不能删，只改它们的观感。
     3. 圆角只能用 22/16/11/pill 四档；间距只用 4/8/12/16/22/28。
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  --d-line-3: #E3E4E8;
  --d-ink-4: #C7CAD1;
  /* 主蓝的浅一档：只给图表柱顶的渐变用（规范里没有这个 token，图省事补一个） */
  --d-blue-2: #93C5FD;
  /* ⚠️ 外壳/内容区底色 = 白。这是对着 11 张桌面效果图实拍定的：
     内容区在效果图里就是 #FFFFFF，卡片和白底之间靠 1px 细线 + 极轻阴影分开。
     规范的 --d-page:#EDEDEF 保留不动（将来要灰底时再用）。 */
  --d-shell: #FFFFFF;
  --d-g-1: 4px; --d-g-2: 8px; --d-g-3: 12px; --d-g-4: 16px; --d-g-5: 22px; --d-g-6: 28px;
  --d-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  /* 外壳尺寸（设计稿 §2.1）：侧栏 206 / 顶栏 54 / 页签条 44 */
  --d-sider-w: 206px;
  --d-topbar-h: 54px;
  --d-tabs-h: 44px;
}

/* ── 1. 全局底色与字体 ────────────────────────────────────────────────── */
/* 设计稿说「整页锁死视口高度，只有内容区自己滚」—— 那个由 .app-layout 继续管，
   这里只换颜色。注意别动 body 的 overflow（登录页是独立的一整页，要能滚）。
   ⚠️ 外壳底色用 --d-shell（白），不是 --d-page。
   规范里 --page:#EDEDEF 标的是「最外层页面底」，但实测 11 张桌面效果图的内容区
   都是纯白（#FFFFFF）—— 灰底铺满会在卡片周围形成一圈灰边，观感偏「脏」。
   所以这里外壳/内容区统一走白，--d-page 保留给将来真需要灰色底的地方。 */
body {
  background: var(--d-shell);
  color: var(--d-ink);
  font-family: 'Plus Jakarta Sans', 'Noto Sans SC', system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}
/* 所有数字等宽 —— 表格里数字不等宽会左右跳动（规范 §1.5 强制） */
.ant-statistic-content-value, .ant-table-cell, .ant-pagination, .ant-badge-count,
.ant-input-number-input, .count-up, .num, .money-cell, .num-cell,
.app-menu .ant-badge-count, .ant-typography {
  font-variant-numeric: tabular-nums;
}

/* ── 2. 侧栏（设计稿 §3.1）────────────────────────────────────────────── */
/* 设计稿侧栏没有右边框，靠底色差和内容区的留白分层；加一条极浅的分隔线收边。 */
.app-sider {
  background: var(--d-surface) !important;
  border-right: 1px solid var(--d-line);
  box-shadow: none;                     /* 规范 §1.4：深色区块/侧栏不加阴影 */
}
/* logo 区：整体 22px 上留白、没有分隔线（方向 04 的壳） */
.app-logo {
  height: 68px; flex: 0 0 68px; padding: 0 22px;
  border-bottom: none;                  /* 设计稿 logo 下面没有分隔线 */
}
/* 🔴 **图形标保留原来的蓝色圆角方块**（2026-09-19 用户要求「把网站logo换成原来的」）。
   方向 04 的效果图里画的是 24×24 墨色四方拼图，我们照做了一版；用户看过之后要回原来那颗
   —— 所以这里**刻意不覆盖** `.logo-mark`，让它落回文件开头那条原样（34px / #1677ff /
   圆角 9px / 白字「优」/ 蓝色投影）。**别再按效果图改回去**，除非用户又改主意。
   ⚠️ 靠的是**源序**：开头那条是通用（老）规则，这里不写就是它生效 ——
   千万别再往这儿加一条 `.logo-mark { ... }`，加了就会重新盖掉。
   断言见 `verify-design-system.py`「Logo：原来的蓝色圆角方块 34px」。 */
.logo-copy strong { display: block; font-size: 15.5px; font-weight: 800; letter-spacing: -.025em; color: var(--d-ink); }
.logo-copy small { display: block; margin-top: 3px; color: var(--d-ink-3); font-size: 9px; letter-spacing: .12em; font-weight: 700; }

/* 菜单：分组标题 10px 大写字距、菜单项 37px 高、11px 圆角、淡蓝选中 */
.app-menu { padding: 0 14px 16px; }
.app-menu .ant-menu-submenu-title {
  height: 30px; line-height: 30px; margin: 0 !important; padding: 0 10px !important;
  color: var(--d-ink-3); font-weight: 800; font-size: 10px; letter-spacing: .12em;
  border-radius: var(--d-r-sm); cursor: default;
}
.app-menu .ant-menu-submenu-title:hover { background: transparent; color: var(--d-ink-3); }
/* 分组标题不需要展开箭头（四个分组是常开的），箭头也一起藏掉 */
.app-menu .ant-menu-submenu-arrow { display: none; }
.app-menu .ant-menu-submenu-title .anticon { display: none; }
.app-menu .ant-menu-submenu { margin-bottom: 6px; }
.app-menu .ant-menu-submenu .ant-menu-item,
.app-menu .ant-menu-item {
  height: 37px; line-height: 37px; margin: 0 !important;
  padding: 0 10px !important; border-radius: var(--d-r-sm);
  color: var(--d-ink-2); font-size: 13px;
}
.app-menu .ant-menu-submenu .ant-menu-item .anticon,
.app-menu .ant-menu-item .anticon { min-width: 18px; font-size: 17px; margin-right: 11px; color: var(--d-ink-3); }
.app-menu .ant-menu-item:hover { color: var(--d-ink); background: var(--d-panel-2); }
.app-menu .ant-menu-item:hover .anticon { color: var(--d-ink-2); }
/* 选中：浅蓝底 + 蓝字 + 蓝图标（规范 §1.1：主色只出现在「要你注意」的地方） */
.app-menu .ant-menu-item-selected { background: var(--d-blue-soft) !important; color: var(--d-blue) !important; font-weight: 700; }
.app-menu .ant-menu-item-selected .anticon { color: var(--d-blue) !important; }
.app-menu .ant-menu-item-selected::after { display: none; }
/* 菜单右侧的计数徽标（去掉红底、改弱化数字）的规则在文件后段「⑮ 其它」那一节 ——
   必须写在**通用** `.ant-badge-count` 之后才压得住（CSS 同权重看源序），所以不能放这儿。
   ⚠️ 这里原来有一份一模一样的副本，纯属死代码（被后面那份覆盖），已删；改规则去那边改。 */

/* 侧栏底部：三个文字按钮，去掉分隔线、字重变轻 */
.sider-bottom { padding: 10px 14px 16px; border-top: none; }
.sider-bottom .ant-btn { height: 34px; margin-top: 2px; color: var(--d-ink-2); text-align: left; border-radius: var(--d-r-sm); font-size: 12.5px; }
.sider-bottom .ant-btn:hover { color: var(--d-ink); background: var(--d-panel-2); }
.sider-bottom .ant-btn-dangerous { color: var(--d-ink-2); }
.sider-bottom .ant-btn-dangerous:hover { color: var(--d-red-ink); background: var(--d-red-soft); }
/* 折叠态（antd 自带断点触发的 72px）：保持可用，只是收紧留白 */
.ant-layout-sider-collapsed .app-logo { justify-content: center; padding: 0; }
.ant-layout-sider-collapsed .logo-copy, .ant-layout-sider-collapsed .sider-bottom .ant-btn > span:not(.anticon) { display: none; }
.ant-layout-sider-collapsed .app-menu { padding-inline: 12px; }
.ant-layout-sider-collapsed .app-menu .ant-menu-submenu-title { display: none; }
.ant-layout-sider-collapsed .app-menu .ant-menu-item { padding: 0 !important; text-align: center; }
.ant-layout-sider-collapsed .app-menu .anticon { margin: 0; }
.ant-layout-sider-collapsed .sider-bottom { padding: 10px 12px; }
.ant-layout-sider-collapsed .sider-bottom .ant-btn { padding: 0; text-align: center; }

/* ── 3. 顶栏（设计稿 §2.1：54px，面包屑 + 同步）──────────────────────── */
/* ⚠️ line-height 必须显式收掉：antd 的 .ant-layout-header 默认 height/line-height
   都是 64px。原来只改 height，文字包进 flex 容器后换行就会 2×64 撑破顶栏。 */
.app-header {
  height: var(--d-topbar-h); flex: 0 0 var(--d-topbar-h);
  padding: 0 22px 0 4px;
  background: var(--d-surface); border-bottom: none;
  display: flex; align-items: center; justify-content: space-between; line-height: 1.5;
}
.header-prefix { font-size: 12px !important; color: var(--d-ink-3) !important; }
.app-header-title { display: flex; align-items: center; min-width: 0; }
.app-header-title .ant-typography { font-size: 12px; }
.app-header-title .ant-typography strong { font-size: 12px; color: var(--d-ink-2); font-weight: 700; }
.header-sync { font-size: 11.5px !important; color: var(--d-ink-3) !important; }

/* ── 4. 页签条（设计稿 §3.2：44px 条，页签是胶囊）───────────────────── */
/* 自绘页签，交互（拖拽 / 右键 / 关闭）一律不碰，只改观感 —— 从「顶部圆角小卡」
   换成设计稿的「胶囊」：未选中透明，选中浅蓝底 + 蓝字，没有底线和投影。 */
.app-tabbar { flex: 0 0 var(--d-tabs-h); min-height: var(--d-tabs-h); align-items: center; gap: 6px; padding: 0 22px 0 4px; background: var(--d-surface); border-bottom: none; }
.app-tabbar-scroll { align-items: center; }
.app-tab {
  height: 30px; padding: 0 12px; gap: 7px;
  border: none; border-radius: var(--d-r-pill);
  background: transparent; color: var(--d-ink-2); font-size: 12.5px;
  transition: color .18s, background .18s, box-shadow .18s;
}
.app-tab:hover { color: var(--d-ink); background: var(--d-panel-2); }
.app-tab.is-active { color: var(--d-blue); background: var(--d-blue-soft); font-weight: 700; box-shadow: none; margin-bottom: 0; }
/* 旧版那条 3px 蓝底线在胶囊形态下是多余的，去掉 */
.app-tab.is-active::after { display: none; }
.app-tab-icon { font-size: 14px; color: currentColor; opacity: .9; }
.app-tab:hover .app-tab-icon, .app-tab.is-active .app-tab-icon { color: currentColor; }
.app-tab-close, .app-tab-refresh { width: 16px; height: 16px; border-radius: 50%; font-size: 9px; }
.app-tab-close:hover, .app-tab-refresh:hover { background: rgba(17, 24, 39, .08); color: var(--d-ink); }
/* 拖拽落点：换成主蓝细环，跟胶囊形态一致 */
.app-tab.is-drop-target { box-shadow: 0 0 0 2px var(--d-blue-soft), 0 0 0 3px var(--d-blue); }
.app-tab.is-drop-target::before { display: none; }
.app-tabbar-extra { color: var(--d-ink-3); font-size: 12px; }
/* 页签条下面那条极浅的分隔线：设计稿里靠留白分层，这里保留一条最淡的收边 */
.app-tabbar { border-bottom: 1px solid var(--d-line); }

/* ── 5. 内容区（设计稿：padding 22，底色走 --d-shell 白）───────────────── */
.tab-pane { padding: 22px; background: var(--d-shell); }
.app-content { background: var(--d-shell); }
/* 滚动条：形状不变，只把颜色调成新的中性色系 */
.app-content::-webkit-scrollbar-thumb, .tab-pane::-webkit-scrollbar-thumb, .app-menu::-webkit-scrollbar-thumb { background: #D8DADF; border: 2px solid transparent; background-clip: content-box; border-radius: 6px; }
.app-content::-webkit-scrollbar-thumb:hover, .tab-pane::-webkit-scrollbar-thumb:hover, .app-menu::-webkit-scrollbar-thumb:hover { background: #C2C5CC; background-clip: content-box; }

/* ── 6. 卡片（设计稿 §6：.scard 圆角 16 + 细描边 + sh-1）────────────── */
/* 外壳底色是白，卡片也是白 —— 所以卡片必须有一条极细的描边才分得开
   （效果图里就是 1px 的极淡线 + 几乎看不见的阴影，不是靠灰底衬）。 */
.content-card.ant-card, .ant-card {
  border-radius: var(--d-r-md);
  border: 1px solid var(--d-line);
  box-shadow: var(--d-sh-1);
}
.content-card > .ant-card-head {
  min-height: 0; padding: 15px 16px 12px;
  border-bottom: none;                        /* 设计稿卡片头下面不画线 */
  font-size: 15.5px;
}
.content-card > .ant-card-head .ant-card-head-title { font-weight: 800; letter-spacing: -.025em; padding: 0; }
.content-card > .ant-card-head .ant-card-extra { padding: 0; }
.content-card > .ant-card-body { padding: 0 16px 16px; }

/* ── 7. 按钮（设计稿 §3.1：高 34 / 圆角 11 / 无阴影）────────────────── */
/* 次级 = panel-2 底 + line-2 描边；主操作 = 实心主蓝；深色 = 实心 ink。 */
.ant-btn { height: 34px; padding: 0 15px; border-radius: var(--d-r-sm); font-size: 12.5px; font-weight: 700; box-shadow: none; }
.ant-btn > .anticon { font-size: 15px; }
.ant-btn > .anticon + span, .ant-btn > span + .anticon { margin-left: 7px; }
.ant-btn:not(.ant-btn-primary):not(.ant-btn-dangerous):not(.ant-btn-text):not(.ant-btn-link) {
  background: var(--d-panel-2); border-color: var(--d-line-2); color: var(--d-ink-2);
}
.ant-btn:not(.ant-btn-primary):not(.ant-btn-dangerous):not(.ant-btn-text):not(.ant-btn-link):hover {
  background: var(--d-panel); border-color: var(--d-line-3); color: var(--d-ink);
}
.ant-btn-primary { background: var(--d-blue); border-color: var(--d-blue); }
.ant-btn-primary:hover, .ant-btn-primary:focus { background: #2F72E4; border-color: #2F72E4; }
.ant-btn-text { color: var(--d-ink-2); }
.ant-btn-text:hover { background: var(--d-panel-2); color: var(--d-ink); }
.ant-btn-link { color: var(--d-blue); }
.ant-btn-dangerous.ant-btn-text, .ant-btn-dangerous.ant-btn-link { color: var(--d-red-ink); }
.ant-btn-dangerous.ant-btn-text:hover { background: var(--d-red-soft); color: var(--d-red-ink); }
/* 小号 / 迷你号：设计稿给的是 28px */
.ant-btn-sm { height: 28px; padding: 0 11px; font-size: 11.5px; border-radius: 9px; }
.ant-btn-sm > .anticon { font-size: 13px; }
.ant-btn-icon-only { width: 34px; padding: 0; }
.ant-btn-sm.ant-btn-icon-only { width: 28px; }
.ant-btn[disabled] { box-shadow: none; }
/* 顶栏那个「立即同步」是全局唯一的主按钮，且设计稿要求是**深色实心** */
.app-header .ant-btn-primary { background: var(--d-ink); border-color: var(--d-ink); height: 34px; }
.app-header .ant-btn-primary:hover { background: #1F2937; border-color: #1F2937; }

/* ── 8. 输入 / 下拉 / 日期 / 数字（统一 34px / 11px 圆角 / panel-2 底）── */
.ant-input, .ant-input-affix-wrapper, .ant-input-number {
  background: var(--d-panel-2); border-color: var(--d-line-2); border-radius: var(--d-r-sm);
  font-size: 12.5px; color: var(--d-ink);
}
.ant-input, .ant-input-number { height: 34px; }
.ant-input-affix-wrapper { min-height: 34px; padding: 0 13px; }
.ant-input-affix-wrapper > input.ant-input { background: transparent; height: auto; }
.ant-input::placeholder, .ant-input-number-input::placeholder { color: var(--d-ink-3); }
.ant-input:hover, .ant-input-affix-wrapper:hover, .ant-input-number:hover,
.ant-input:focus, .ant-input-affix-wrapper-focused, .ant-input-number-focused {
  border-color: var(--d-blue); box-shadow: none;
}
.ant-input[disabled], .ant-input-affix-wrapper-disabled { background: var(--d-panel); color: var(--d-ink-3); }
.ant-input-number-input { height: 32px; font-size: 12.5px; }
.ant-input-number-sm { height: 28px; }
.ant-input-number-sm .ant-input-number-input { height: 26px; }

.ant-select:not(.ant-select-customize-input) .ant-select-selector {
  background: var(--d-panel-2); border-color: var(--d-line-2); border-radius: var(--d-r-sm);
  font-size: 12.5px; height: 34px; padding: 0 11px;
}
.ant-select-single .ant-select-selector .ant-select-selection-item,
.ant-select-single .ant-select-selector .ant-select-selection-placeholder { line-height: 32px; }
.ant-select:not(.ant-select-disabled):hover .ant-select-selector { border-color: var(--d-blue); }
.ant-select-focused:not(.ant-select-disabled).ant-select:not(.ant-select-customize-input) .ant-select-selector {
  border-color: var(--d-blue); box-shadow: none;
}
.ant-select-sm:not(.ant-select-customize-input) .ant-select-selector { height: 28px; border-radius: 9px; }
.ant-select-sm.ant-select-single .ant-select-selector .ant-select-selection-item,
.ant-select-sm.ant-select-single .ant-select-selector .ant-select-selection-placeholder { line-height: 26px; }
.ant-select-arrow { color: var(--d-ink-3); }

.ant-picker { background: var(--d-panel-2); border-color: var(--d-line-2); border-radius: var(--d-r-sm); height: 34px; font-size: 12.5px; }
.ant-picker:hover, .ant-picker-focused { border-color: var(--d-blue); box-shadow: none; }
.ant-picker-input > input { font-size: 12.5px; color: var(--d-ink); }
.ant-picker-input > input::placeholder { color: var(--d-ink-3); }
.ant-picker-suffix, .ant-picker-clear { color: var(--d-ink-3); }

/* 开关 / 勾选：主蓝 */
.ant-switch-checked { background: var(--d-blue); }
.ant-checkbox-checked .ant-checkbox-inner { background: var(--d-blue); border-color: var(--d-blue); }
.ant-radio-checked .ant-radio-inner { border-color: var(--d-blue); }
.ant-radio-inner::after { background: var(--d-blue); }

/* ── 9. 表格（设计稿 §3.3：表头 11px 弱化、无缝、行 48px、无斑马纹）── */
/* ⚠️ 只在「没套 .stable-wrap」的表上生效，避免和销售页那套打架。
   表头不要背景色，只用一条 --line-2 底边；数字右对齐 + 加粗由列定义负责。 */
.ant-table { font-size: 12.5px; background: transparent; }
.ant-table-thead > tr > th {
  font-size: 11px; font-weight: 700; letter-spacing: .02em; color: var(--d-ink-3);
  background: transparent; border-bottom: 1px solid var(--d-line-2);
  padding: 9px 12px; white-space: nowrap;
}
.ant-table-thead > tr > th::before { display: none !important; }   /* 干掉列之间的分隔竖线 */
.ant-table-thead > tr > th.ant-table-column-sort,
.ant-table-thead > tr > th.ant-table-column-has-sorters:hover { background: transparent; }
.ant-table-thead > tr > th.ant-table-column-has-sorters:hover { color: var(--d-ink-2); }
.ant-table-tbody > tr > td {
  padding: 0 12px; height: 48px;
  border-bottom: 1px solid var(--d-line); color: var(--d-ink-2);
  vertical-align: middle;
}
.ant-table-tbody > tr.ant-table-row:hover > td,
.ant-table-tbody > tr > td.ant-table-cell-row-hover { background: var(--d-panel-2); }
.ant-table-tbody > tr.ant-table-row-selected > td { background: var(--d-blue-soft); }
.ant-table-tbody > tr:last-child > td { border-bottom: none; }
/* 紧凑表：42px（设计稿 §3.3） */
.ant-table-small .ant-table-tbody > tr > td { height: 42px; }
.ant-table-small .ant-table-thead > tr > th { padding: 8px 10px; }
/* 库存明细的行间距（用户 2026-09-18 要求「加点行间距」）：
   这页的缩略图是 50px（比全站默认 34 大一圈），不留白的话图几乎贴着上下两条行细线，看着挤。
   ⚠️ 上面那条全局规则的 `height: 48px` 只是**下限**（td 会被内容撑高），所以真正要加的是
      padding-top/bottom —— 改 height 是没用的。 */
.inv-table .ant-table-tbody > tr > td { padding-top: 9px; padding-bottom: 9px; }
.ant-table-summary > tr > td, .ant-table tfoot > tr > td {
  height: 46px; font-size: 12.5px; font-weight: 800; color: var(--d-ink);
  background: var(--d-panel-2); border-top: 1px solid var(--d-line-2);
}
/* 排序箭头：默认常年铺灰，悬停/激活回到主蓝 */
.ant-table-column-sorter { color: var(--d-ink-4); }
.ant-table-column-sorter-up.active, .ant-table-column-sorter-down.active { color: var(--d-blue); }
.ant-table-filter-trigger { color: var(--d-ink-3); }
.ant-table-filter-trigger.active { color: var(--d-blue); }
/* 展开行 / 空态 / 分页容器：底色跟着内容区走，不要白的 */
.ant-table-expanded-row > td, .ant-table-expanded-row:hover > td { background: var(--d-panel-2); }
.ant-table-placeholder { background: transparent; border-bottom: none; }
.ant-table-placeholder .ant-empty-description { color: var(--d-ink-3); }
.ant-table-cell-fix-left, .ant-table-cell-fix-right { background: var(--d-surface); }
/* 表格被 loading 遮罩盖住时的底色 */
.ant-table-wrapper .ant-spin-blur { opacity: .35; }
/* 表格内的小进度条 */
.ant-table .tbar { background: var(--d-line-2); }
.ant-table .tbar i { background: var(--d-blue); }

/* ── 10. 提示条 Alert（设计稿 §3.5：四色浅底 + 13px 圆角）────────────── */
/* ⚠️ antd 4 的 Alert 是「左侧 4px 色条 + 白底」的形态，跟设计稿的「整块浅底」不是一回事，
   这里整个换成浅底 + 深字。留 .ant-alert-info 等类名，回归脚本还在用。 */
.ant-alert {
  border-radius: 13px; border: none; padding: 12px 14px;
  font-size: 12px; line-height: 1.65; align-items: flex-start;
}
.ant-alert .ant-alert-icon { margin-top: 1px; margin-right: 10px; font-size: 16px; }
.ant-alert-content { min-width: 0; }
.ant-alert-message { font-size: 12px; font-weight: 800; color: inherit; }
.ant-alert-description { font-size: 12px; color: inherit; }
.ant-alert-info { background: var(--d-blue-soft); }
.ant-alert-info .ant-alert-icon, .ant-alert-info .ant-alert-message, .ant-alert-info .ant-alert-description { color: #1E4E8C; }
.ant-alert-warning { background: var(--d-amber-soft); }
.ant-alert-warning .ant-alert-icon, .ant-alert-warning .ant-alert-message, .ant-alert-warning .ant-alert-description { color: #8A5A10; }
.ant-alert-error { background: var(--d-red-soft); }
.ant-alert-error .ant-alert-icon, .ant-alert-error .ant-alert-message, .ant-alert-error .ant-alert-description { color: #A63232; }
.ant-alert-success { background: var(--d-green-soft); }
.ant-alert-success .ant-alert-icon, .ant-alert-success .ant-alert-message, .ant-alert-success .ant-alert-description { color: #0B6B50; }
.ant-alert-close-icon { color: inherit; opacity: .55; font-size: 12px; padding: 0 2px; }
.ant-alert-close-icon:hover { opacity: 1; }
.ant-alert-with-description .ant-alert-message { margin-bottom: 4px; }

/* ── 11. 标签 Tag（设计稿 §3.4：胶囊一律「浅底 + 深字」）────────────── */
/* ⚠️ antd 默认是「纯色底 + 白字」，白字在琥珀上对比度不够，规范明确禁止。 */
.ant-tag {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; margin: 0; padding: 0 9px;
  border: none; border-radius: var(--d-r-pill);
  font-size: 11px; font-weight: 700; line-height: 1;
  background: var(--d-panel); color: var(--d-ink-2);
}
/* 三重编码：色块 + 文字 + 圆点（规范 §3.4）。给 Tag 前面补一个小圆点。 */
.ant-tag::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .85; flex: 0 0 6px; }
.ant-tag.ant-tag-blue, .ant-tag.ant-tag-processing { background: var(--d-blue-soft); color: var(--d-blue); }
.ant-tag.ant-tag-green, .ant-tag.ant-tag-success { background: var(--d-green-soft); color: var(--d-green-ink); }
.ant-tag.ant-tag-gold, .ant-tag.ant-tag-orange, .ant-tag.ant-tag-warning { background: var(--d-amber-soft); color: var(--d-amber-ink); }
.ant-tag.ant-tag-red, .ant-tag.ant-tag-error { background: var(--d-red-soft); color: var(--d-red-ink); }
.ant-tag.ant-tag-purple, .ant-tag.ant-tag-magenta { background: var(--d-violet-soft); color: var(--d-violet); }
.ant-tag.ant-tag-cyan { background: #E4F6F6; color: #2E9A96; }
.ant-tag.ant-tag-default { background: var(--d-panel); color: var(--d-ink-2); }
/* 没有语义的纯标记（如「已隐藏」）不该带圆点，省得看起来像个状态 */
.ant-tag.is-plain::before, .ant-tag.no-dot::before { display: none; }
/* 加号角标（+N / -N）：小一号胶囊，不要圆点 */
.gift-trim::before, .gift-trim-suffix::before { display: none; }

/* ── 12. 空态（设计稿 §3.5：说清「为什么空 + 怎么让它不空」）────────── */
.ant-empty { margin: 0; padding: 28px 16px; }
.ant-empty-image { height: auto; margin-bottom: 10px; display: flex; justify-content: center; }
.ant-empty-image svg { width: 76px; height: 62px; opacity: .55; }
.ant-empty-description { color: var(--d-ink-3); font-size: 12px; }
.ant-empty-normal { margin: 0; }
.ant-empty-small { padding: 16px 12px; }

/* ── 13. 分页（设计稿 §3.7：不要用 antd 默认样式）──────────────────── */
.ant-pagination { font-size: 11.5px; color: var(--d-ink-3); }
.ant-pagination-item {
  min-width: 27px; height: 27px; line-height: 25px; margin-right: 5px;
  border: none; border-radius: 8px; background: var(--d-panel-2);
  font-size: 11.5px; font-weight: 700;
}
.ant-pagination-item a { color: var(--d-ink-2); }
.ant-pagination-item:hover { background: var(--d-panel); }
.ant-pagination-item:hover a { color: var(--d-ink); }
.ant-pagination-item-active { background: var(--d-blue); border-color: var(--d-blue); }
.ant-pagination-item-active a, .ant-pagination-item-active:hover a { color: #fff; }
.ant-pagination-item-active:hover { background: var(--d-blue); }
.ant-pagination-prev .ant-pagination-item-link, .ant-pagination-next .ant-pagination-item-link {
  min-width: 27px; height: 27px; line-height: 25px; border: none; border-radius: 8px;
  background: var(--d-panel-2); color: var(--d-ink-2);
}
.ant-pagination-prev:hover .ant-pagination-item-link, .ant-pagination-next:hover .ant-pagination-item-link {
  background: var(--d-panel); color: var(--d-ink);
}
.ant-pagination-disabled .ant-pagination-item-link, .ant-pagination-disabled:hover .ant-pagination-item-link { color: var(--d-ink-4); background: var(--d-panel-2); }
.ant-pagination-options-quick-jumper input {
  background: var(--d-panel-2); border-color: var(--d-line-2); border-radius: 9px; height: 27px; font-size: 11.5px;
}
.ant-pagination-total-text { color: var(--d-ink-3); }

/* ── 14. 浮层：Tooltip / Dropdown / Modal / Drawer ─────────────────── */
/* 提示卡：设计稿 §3.6 说用「ink 底 + 12px 圆角 + 白字，不用阴影」——
   但表格里的口径说明是长文本，深底大面积读起来累，这里统一成「白底 + 细描边」，
   跟卡片语言一致（深底留给图表的小提示卡）。 */
.ant-tooltip-inner {
  background: var(--d-surface); color: var(--d-ink);
  border: 1px solid var(--d-line-2); border-radius: 12px;
  padding: 9px 11px; font-size: 11.5px; line-height: 1.65;
  box-shadow: var(--d-sh-2); min-height: 0;
}
.ant-tooltip-arrow-content { background: var(--d-surface); }
.ant-tooltip-arrow-content::before { background: var(--d-line-2); }
.ant-tooltip-inner .stat-tip { font-size: 11.5px; line-height: 1.7; }
.ant-tooltip-inner .stat-tip-note { margin-top: 5px; color: var(--d-ink-3); }
.ant-tooltip-inner .stat-tip-total { margin-top: 5px; padding-top: 5px; border-top: 1px solid var(--d-line); font-weight: 800; color: var(--d-ink); }

.ant-dropdown-menu, .ant-select-dropdown {
  border-radius: var(--d-r-sm); padding: 6px; box-shadow: var(--d-sh-2); border: 1px solid var(--d-line);
}
.ant-dropdown-menu-item, .ant-select-item {
  border-radius: 8px; font-size: 12.5px; color: var(--d-ink-2); padding: 7px 10px;
}
.ant-dropdown-menu-item:hover, .ant-select-item-option-active:not(.ant-select-item-option-disabled) { background: var(--d-panel-2); color: var(--d-ink); }
.ant-select-item-option-selected:not(.ant-select-item-option-disabled) { background: var(--d-blue-soft); color: var(--d-blue); font-weight: 700; }
.ant-dropdown-menu-item-danger { color: var(--d-red-ink); }
.ant-dropdown-menu-item-danger:hover { background: var(--d-red-soft); color: var(--d-red-ink); }

/* ⚠️ antd 默认给 .ant-modal-content 挂了三层阴影（0 3px 6px / 0 6px 16px / 0 9px 28px），
   跟规范里「阴影只有两级」冲突，必须显式覆盖，否则只改圆角看着还是旧观感。 */
.ant-modal-content { border-radius: var(--d-r-md); overflow: hidden; box-shadow: var(--d-sh-2); }
.ant-modal-header { border-bottom: none; padding: 20px 22px 0; border-radius: var(--d-r-md) var(--d-r-md) 0 0; }
.ant-modal-title { font-size: 15.5px; font-weight: 800; letter-spacing: -.025em; color: var(--d-ink); }
.ant-modal-body { padding: 16px 22px; font-size: 12.5px; color: var(--d-ink-2); }
.ant-modal-footer { border-top: none; padding: 0 22px 20px; }
.ant-modal-footer .ant-btn + .ant-btn { margin-left: 8px; }
.ant-modal-close { top: 16px; right: 16px; border-radius: 50%; }
.ant-modal-close:hover { background: var(--d-panel-2); }
.ant-modal-mask { background: rgba(17, 24, 39, .45); }

/* 可拖动弹窗（`DragModal`）：`.drag-modal` 是 modalRender 套在 .ant-modal 外面的那层。
   ⚠️ 这里只该管 cursor / user-select，**别碰 position / width / margin** ——
   `.ant-modal-wrap` 是 `position:fixed; overflow:auto`（不是 flex），
   块级 div 天然铺满宽度，`.ant-modal` 靠自己的 `margin: 0 auto` 定中，多这一层不影响它；
   一旦往这层写宽度或定位，那个定中就会被顶掉。 */
.drag-modal .ant-modal-header,
.drag-modal .ant-modal-header .ant-modal-title { cursor: move; }
/* 拖动中：整页光标保持「移动」、并禁掉文字选中。
   不这么做的话指针快速划过别的元素时光标会闪、还会顺手把标题/正文选中留下一片蓝。 */
body.is-dragging-modal, body.is-dragging-modal * {
  cursor: move !important;
  user-select: none !important;
}

.ant-drawer-content { background: var(--d-surface); box-shadow: var(--d-sh-2); }
.ant-drawer-header { border-bottom: 1px solid var(--d-line); padding: 16px 20px; }
.ant-drawer-title { font-size: 15.5px; font-weight: 800; }

/* 计数徽标统一成「浅底 + 深字」（规范 §3.1：禁止纯色底 + 白字，红底白字在小尺寸下最刺眼）。
   ⚠️ 不能用 `.ant-badge-count:not(.app-menu .ant-badge-count)` —— :not() 里塞后代选择器是 CSS4，
   Chrome 虽然能解析但这种写法匹配不到，规则会静默失效。改成「先铺全站、再让菜单覆盖回去」。 */
.ant-badge-count {
  background: var(--d-panel); color: var(--d-ink-2);
  box-shadow: none; border: none; min-width: 18px; height: 18px;
  line-height: 18px; padding: 0 6px; border-radius: var(--d-r-pill);
  font-size: 10px; font-weight: 700;
}
/* 状态点（红点/绿点）保留语义色 —— 它本来就是「一盏灯」，不是文字标签 */
.ant-badge-status-dot { width: 7px; height: 7px; }
/* ⚠️ 菜单里的徽标是「纯数字、无底色」，必须写在上面那条通用规则**之后**才压得住
   （CSS 同权重看源序）。 */

/* 数字要**贴菜单项右边** —— 效果图里「库存明细 1394 / 补货建议 18」是一列右对齐的数字。
   ⚠️ 这一条踩过坑：标签是 `h(Space, null, '库存明细', h(Badge, …))` 包起来的，
   于是「让徽标靠右」需要**两层**同时成立，缺一条数字就贴在文字后面（实测离右边还差 43px）：
     ① `.ant-space` 自己是 `inline-flex`、宽度只等于内容宽 → 得撑到 100%；
     ② auto margin 只有落在 **flex item**（`.ant-space-item`）上才有意义 ——
        写给 `.ant-badge`（space-item 的子节点）完全无效，那是条假规则。 */
.app-menu .ant-badge { margin-left: 0; }
.app-menu .ant-menu-title-content > .ant-space { width: 100%; }
.app-menu .ant-space > .ant-space-item:last-child { margin-left: auto; }
.app-menu .ant-badge-count {
  /* ⚠️ **padding 不能归零**（这里踩过一次，用户 2026-09-19 报「库存明细后面的数字显示不对」）：
     antd 的 `.ant-badge-count` 是 `overflow: hidden` 且宽度按内容算，
     `padding: 0` 会把盒子压到刚好等于数字的 **advance** 宽度，而字形 ink 比 advance 宽一丁点
     → 首尾各被裁掉一点，「1395」四个字挤成一团（看着像重叠）。留 4px 两侧都安全。 */
  min-width: 0; height: auto; padding: 0 4px; line-height: 1; box-shadow: none;
  background: transparent !important; color: var(--d-ink-3) !important;
  font-size: 10.5px; font-weight: 700;
}
.app-menu .ant-menu-item-selected .ant-badge-count { color: var(--d-blue) !important; }

.ant-steps .ant-steps-item-title { font-size: 12.5px; font-weight: 700; }
.ant-steps .ant-steps-item-process .ant-steps-item-icon { background: var(--d-blue); border-color: var(--d-blue); }
.ant-steps .ant-steps-item-finish .ant-steps-item-icon { background: var(--d-green-soft); border-color: transparent; }
.ant-steps .ant-steps-item-finish .ant-steps-item-icon > .ant-steps-icon { color: var(--d-green-ink); }
.ant-steps .ant-steps-item-wait .ant-steps-item-icon { background: var(--d-panel); border-color: transparent; }
.ant-steps .ant-steps-item-wait .ant-steps-item-icon > .ant-steps-icon { color: var(--d-ink-3); }

.ant-spin-dot-item { background: var(--d-blue); }
.ant-skeleton-content .ant-skeleton-title, .ant-skeleton-content .ant-skeleton-paragraph > li { background: var(--d-panel); border-radius: 6px; }
.ant-skeleton-input { background: var(--d-panel); border-radius: 8px; }

.ant-descriptions-item-label { color: var(--d-ink-3); font-size: 11.5px; }
.ant-descriptions-item-content { color: var(--d-ink); font-size: 12.5px; font-weight: 700; }
.ant-descriptions-bordered .ant-descriptions-view { border-color: var(--d-line-2); border-radius: var(--d-r-sm); overflow: hidden; }
.ant-descriptions-bordered .ant-descriptions-item-label, .ant-descriptions-bordered .ant-descriptions-item-content { border-right-color: var(--d-line-2); border-bottom-color: var(--d-line-2); }

.ant-popover-inner { border-radius: var(--d-r-sm); box-shadow: var(--d-sh-2); padding: 12px; }
.ant-popover-inner-content { font-size: 12.5px; color: var(--d-ink-2); }
.ant-popover-message { font-size: 12.5px; padding-bottom: 10px; }
.ant-popover-buttons .ant-btn + .ant-btn { margin-left: 8px; }
.ant-message-notice-content { border-radius: var(--d-r-sm); box-shadow: var(--d-sh-2); font-size: 12.5px; padding: 10px 16px; }
.ant-notification-notice { border-radius: var(--d-r-md); }

/* 头像：回退首字头像（颜色由 app.js 交到这里，别再写死 #1677ff）。
   规范 §1.1：主色只出现在「要你注意」的地方 —— 头像底用极浅蓝 + 蓝字。 */
.ant-avatar { border-radius: var(--d-r-sm); font-weight: 700; font-size: 13px; }
.ant-avatar.sku-thumb-fallback { background: var(--d-blue-soft); color: var(--d-blue); }

/* 分隔线：规范里卡片/分区之间靠间距和 1px 细线，不靠粗分隔条 */
.ant-divider { border-top-color: var(--d-line-2); margin: 12px 0; }
.ant-divider-horizontal.ant-divider-with-text { margin: 14px 0; font-size: 12px; font-weight: 700; color: var(--d-ink-3); }
.ant-divider-horizontal.ant-divider-with-text::before,
.ant-divider-horizontal.ant-divider-with-text::after { border-top-color: var(--d-line-2); }

/* Popconfirm / Popover 气泡：白底 + 细描边 + 二级阴影（跟 tooltip 一套观感） */
.ant-popover-inner { border: 1px solid var(--d-line-2); }
.ant-popconfirm-title { font-size: 13px; font-weight: 700; color: var(--d-ink); }
.ant-popconfirm-description { font-size: 12px; color: var(--d-ink-3); margin-top: 4px; }
.ant-popconfirm-buttons { margin-top: 12px; }
.ant-popconfirm-buttons .ant-btn + .ant-btn { margin-left: 8px; }

/* 日期选择器浮层（日历本体 + 底部快捷区间）：tooltip 之外的唯一「大浮层」，
   圆角/阴影/字号都要跟公共层对齐，否则点开日期框会显得是两个 App。 */
.ant-picker-panel-container { border-radius: var(--d-r-md); box-shadow: var(--d-sh-2); }
.ant-picker-header { padding: 8px 12px; border-bottom: 1px solid var(--d-line); }
.ant-picker-header button { color: var(--d-ink-2); font-weight: 700; font-size: 12px; }
.ant-picker-header-view button { font-size: 13px; font-weight: 800; color: var(--d-ink); }
.ant-picker-content th { font-size: 11px; font-weight: 700; color: var(--d-ink-3); }
.ant-picker-cell { font-size: 12.5px; }
.ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner::before { border-color: var(--d-blue); }
.ant-picker-cell-in-view.ant-picker-cell-selected .ant-picker-cell-inner,
.ant-picker-cell-in-view.ant-picker-cell-range-start .ant-picker-cell-inner,
.ant-picker-cell-in-view.ant-picker-cell-range-end .ant-picker-cell-inner { background: var(--d-blue); border-radius: 8px; }
.ant-picker-cell .ant-picker-cell-inner { border-radius: 8px; }
.ant-picker-cell:hover:not(.ant-picker-cell-selected):not(.ant-picker-cell-range-start):not(.ant-picker-cell-range-end) .ant-picker-cell-inner { background: var(--d-blue-soft); }
.ant-picker-today-btn { color: var(--d-blue); font-weight: 700; }
.ant-picker-ok .ant-btn-primary { background: var(--d-blue); border-color: var(--d-blue); }
.ant-picker-range-separator { color: var(--d-ink-3); }

/* 进度条：主色蓝、去圆角毛刺 */
.ant-progress-bg { background: var(--d-blue) !important; border-radius: var(--d-r-pill); }
.ant-progress-inner { background: var(--d-panel); }
.ant-progress-text { font-size: 12px; font-weight: 700; color: var(--d-ink-2); font-variant-numeric: tabular-nums; }

/* ── 16. 页面级通用小件（跟着公共层一起换）──────────────────────────── */
/* 页标题区：旧版是蓝色小标签 + 大标题，设计稿是大标题 + 灰色副行 */
.page-heading { margin-bottom: 16px; }
.page-heading h2, .page-heading h3 { letter-spacing: -.03em; color: var(--d-ink); }
.dark-summary-bar .ant-btn { border-radius: var(--d-r-sm); }

/* 统计小卡（总览/发货统计等页仍在用 .stat-card / .ant-statistic） */
.stat-card.ant-card { border-radius: var(--d-r-md); box-shadow: var(--d-sh-1); border: none; }
.stat-card .ant-statistic-title { font-size: 12px; color: var(--d-ink-2); }
.stat-card .ant-statistic-content { font-size: 21px; font-weight: 800; letter-spacing: -.035em; color: var(--d-ink); }
.stat-card .ant-statistic-content-prefix { color: var(--d-ink-3); margin-right: 6px; }

/* ── 17. 手机端（设计稿 §2.4 / §11）────────────────────────────────── */
@media (max-width: 767px) {
  /* 顶栏：汉堡 + 页面名 + 同步，52px */
  .app-header { height: 52px; flex: 0 0 52px; padding: 0 14px; }
  .nav-toggle { font-size: 18px; padding: 0 6px; margin-right: 6px; }
  .header-prefix { display: none; }              /* 「优易库存中台 / 」手机上省掉，只留页面名 */
  .app-header-title .ant-typography strong { font-size: 15px; font-weight: 800; letter-spacing: -.03em; }
  .app-header .ant-btn-sm, .app-header .ant-btn { height: 30px; font-size: 12px; padding: 0 12px; }
  .header-sync { display: none; }

  /* 页签条：手机上挤，压到 38px、页签 28px */
  .app-tabbar { flex: 0 0 38px; min-height: 38px; padding: 0 12px; gap: 5px; border-bottom: none; }
  .app-layout.is-narrow .app-tabbar { padding: 0 12px; }
  .app-tabbar .app-tab { height: 28px; font-size: 12px; padding: 0 10px; }
  .app-tabbar .app-tab-icon { display: none; }
  .app-tabbar .app-tab-text { max-width: 100px; }
  .app-tabbar .app-tab-refresh, .app-tabbar .app-tab-close { opacity: 1; }

  /* 内容区：手机留白收到 12；底部再让出底部标签栏的高度（含 iPhone 安全区），
     否则最后一个卡片会被那条固定栏压住。 */
  .tab-pane { padding: 12px; padding-bottom: calc(12px + 62px + env(safe-area-inset-bottom, 0px)); }

  /* 底部标签栏（设计稿 §2.4）：拇指够得到底部、够不到顶部，所以高频入口挪到这儿。
     5 格：总览 / 库存 / 入库 / 订单 / 更多（更多打开完整抽屉菜单）。 */
  .app-mtabbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    display: flex; align-items: stretch; background: rgba(255, 255, 255, .97);
    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
    border-top: 1px solid var(--d-line-2); box-shadow: 0 -6px 20px rgba(17, 24, 39, .06);
    padding: 5px 4px calc(5px + env(safe-area-inset-bottom, 0px)); }
  .app-mtab { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center;
    gap: 3px; padding: 5px 0 3px; border-radius: 12px; color: var(--d-ink-3);
    cursor: pointer; -webkit-tap-highlight-color: transparent; }
  .app-mtab i { font-size: 19px; line-height: 1; display: flex; }
  .app-mtab b { font-size: 10.5px; font-weight: 700; letter-spacing: -.01em; }
  .app-mtab.is-active { color: var(--d-blue); }
  .app-mtab.is-active b { font-weight: 800; }
  .app-mtab:active { background: var(--d-panel); }

  /* 组件在手机上整体瘦一圈，但点按区不小于 44px（除按钮） */
  .ant-btn { height: 32px; padding: 0 13px; }
  .ant-input, .ant-input-affix-wrapper, .ant-input-number,
  .ant-select:not(.ant-select-customize-input) .ant-select-selector,
  .ant-picker { height: 36px; }
  .ant-select-single .ant-select-selector .ant-select-selection-item,
  .ant-select-single .ant-select-selector .ant-select-selection-placeholder { line-height: 34px; }
  .ant-input, .ant-input-affix-wrapper { font-size: 13px; }
  .ant-select:not(.ant-select-customize-input) .ant-select-selector { font-size: 13px; }

  /* 卡片：手机上再紧一档 */
  .content-card > .ant-card-head { padding: 13px 14px 10px; }
  .content-card > .ant-card-body { padding: 0 14px 14px; }
  .ant-card { border-radius: var(--d-r-md); }

  /* 表格：手机端不给宽表（规范 §2.4 一律换卡片），这里只兜底压缩 */
  .ant-table-tbody > tr > td { height: 52px; padding: 0 10px; }
  .ant-table-thead > tr > th { padding: 8px 10px; }

  /* 弹窗：手机上贴边，圆角收到 16 */
  .ant-modal { max-width: calc(100vw - 24px); margin: 12px auto; padding-bottom: 12px; }
  .ant-modal-body { padding: 14px 16px; }
  .ant-modal-header { padding: 16px 16px 0; }
  .ant-modal-footer { padding: 0 16px 16px; }

  /* 空态 / 分页收紧 */
  .ant-empty { padding: 22px 12px; }
  .ant-pagination { flex-wrap: wrap; row-gap: 8px; }

  /* 提示条：字号小一档，跟销售页那套窄屏规则对齐 */
  .ant-alert { padding: 11px 12px; font-size: 11.5px; border-radius: 12px; }
  .ant-alert-message, .ant-alert-description { font-size: 11.5px; }
}

/* ── 移动端：表单控件字号 ≥16px，禁止 iOS 聚焦时自动放大整页 ──────────────
   根因：iOS Safari 在「**被聚焦的元素**字号 < 16px」时会把整个页面缩放 —— 表现就是
   手指点一下输入框/下拉框/日期选择器，页面突然变大、还得捏回去才能继续输。
   本项目输入类字号桌面定 12.5px、窄屏 13px（上面那条），都低于 16px，所以手机上必踩。
   修法：窄屏下把所有可聚焦表单控件字号提到 16px（!important 压过各处 12px/12.5px/13px
   的局部规则），并顺手放开被压扁的小控件高度，免得 16px 的字挤出边框。
   ⚠️ 刻意**不用** viewport 的 maximum-scale=1 / user-scalable=no：那会把用户**手动**
   双指放大一起禁掉（牺牲可访问性），而且 iOS 10+ 本来就无视 user-scalable，光靠它修不牢。
   桌面端（>991px）完全不受影响，仍是 12.5px 那套设计稿尺寸。 */
@media (max-width: 991px) {
  input:not([type="checkbox"]):not([type="radio"]),
  textarea, select,
  .ant-input, .ant-input-affix-wrapper, .ant-input-number-input,
  .ant-select-selector, .ant-select-selection-search-input,
  .ant-picker-input > input { font-size: 16px !important; }

  /* 小尺寸输入（分页跳页、窄卡片里的内联输入）放开高度，别把 16px 的字挤出来 */
  .ant-pagination-options-quick-jumper input { height: 30px; padding: 0 6px; }
  .ant-input-sm, .ant-input-number-sm, .ant-input-number-sm .ant-input-number-input { height: 32px; }

  /* 下拉选中项/占位符的行高跟着字号走，保持垂直居中（antd 默认按 12.5px 算的 32px） */
  .ant-select-single .ant-select-selector .ant-select-selection-item,
  .ant-select-single .ant-select-selector .ant-select-selection-placeholder { line-height: 32px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   销售统计（2026-09-18 用户反馈三条）
   ──────────────────────────────────────────────────────────────────────────
   ① 「店铺销售对比」的店铺名前面挂平台小标（.sl-store，桌面表格 + 手机卡片共用）；
   ② 手机端 KPI 布局重做（原来细线分隔 + 第 5 项只占半格，看着像缺一块）；
   ③ 手机端查询控件弱化（原来「更新于 + 日期 + 店铺」砌三整行，把标题压住了）。
   ⚠️ 字号不能被这里改小：≤991px 那条 `font-size:16px !important` 是防 iOS 聚焦缩放的，
      只能靠「去底色/去描边/并成一行」来减重，不要动字号。
   ══════════════════════════════════════════════════════════════════════════ */
/* ① 平台小标 + 店名（.od-plogo 是公共层那颗 18px 方标） */
.sl-store { display: flex; align-items: center; gap: 7px; min-width: 0; }
.sl-store-tx { min-width: 0; flex: 1 1 auto; }
.sl-store-tx > span:first-child { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-store-sub { margin-top: 2px; font-size: 12px; color: var(--d-ink-3); }

@media (max-width: 767px) {
  /* ② KPI：2 列网格 → 白底细描边小块 + 块间留缝；奇数个时最后一个跨满整行。
     这样读起来是整齐的 2+2+1(满宽)，不再有「右下角空半格 + 一堆分隔线」。 */
  .sales-page .skpis {
    display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
    padding: 0; background: transparent; box-shadow: none;
  }
  /* ⚠️ 内距/图标间距必须比桌面收紧：加了 1px 描边 + 12px 块间缝之后，半栏只剩 178px，
     左边图标一占，¥123,456.78 这种 6 位数会挤出格子（实测差 3px）。这里把内距收到 12px、
     图标 30px、图标-文字间距 8px，给数字留出 ~114px。**别再调大回去**。 */
  .sales-page .sk,
  .sales-page .sk:first-child, .sales-page .sk:last-child,
  .sales-page .sk:nth-child(odd), .sales-page .sk:nth-child(even) {
    padding: 12px; gap: 8px;
    background: var(--d-surface); border: 1px solid var(--d-line-2);
    border-radius: var(--d-r-md);
  }
  .sales-page .sk .sk-ic { width: 30px; height: 30px; flex: 0 0 30px; border-radius: 9px; font-size: 14px; }
  .sales-page .sk:last-child:nth-child(odd) { grid-column: 1 / -1; }

  /* ③ 查询控件：去掉白底描边、改浅灰胶囊；日期 + 店铺各占一半挤进同一行，
     「更新于…」自己占一行（它是数据新鲜度，不能省），刷新按钮收到最右。 */
  .sales-page .shead-right { align-items: center; gap: 8px; }
  .sales-page .shead-right .sales-updated { flex: 1 1 100%; }
  .sales-page .shead-right .ant-picker,
  .sales-page .shead-right .ant-select .ant-select-selector {
    background: var(--d-panel); border-color: transparent;
    box-shadow: none; border-radius: var(--d-r-pill);
  }
  .sales-page .shead-right .ant-picker { flex: 1 1 0; min-width: 0; padding: 0 10px; }
  .sales-page .shead-right .ant-select { flex: 1 1 0; min-width: 0; width: auto !important; }
  .sales-page .shead-right .ant-select .ant-select-selector { padding: 0 11px; }
  .sales-page .shead-right > .ant-btn { flex: 0 0 auto; }
}



/* ══════════════════════════════════════════════════════════════════════════
   订单列表 · 手机端（2026-09-19）
   ──────────────────────────────────────────────────────────────────────────
   DESIGN-SYSTEM §2.4 把「订单列表」列在历史欠账里：桌面那张表 9 列合计 ≈ 1500px，
   390px 屏上要横向拖三屏；展开明细 11 列更宽。这里按 §2.4 全换成卡片：
   筛选条整行铺满 + 订单卡（`.odm-*`）+ 每行一个 SKU 的数字块。
   ⚠️ 字号一律不在这里调小：≤991px 那条 `font-size:16px !important` 是防 iOS
      聚焦整页缩放的（用户报过「点输入框页面放大」），要减重只能靠底色/描边/布局。
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 767px) {
  /* ── 筛选条：默认只留「交易时间 + 单号查询」，低频的店铺 / 平台 / 收件电话收进
     「筛选」按钮后面（`.odm-adv.is-hidden`）—— 六个控件全铺开会占掉近 2/3 屏，
     一进页面连一张订单都看不到。控件整行铺满、标签在控件上方。 ── */
  .od-page .od-filters { flex-direction: column; align-items: stretch; gap: 12px; }
  .od-page .od-filter { width: 100%; }
  /* ⚠️ 收起来的那三项：用 display:none 而不是 height:0 —— 后者在 iOS 上仍会占
     一个 tab 焦点位（键盘 Tab 走到看不见的输入框，屏幕会莫名滚动）。 */
  .od-page .od-filters .odm-adv.is-hidden { display: none; }
  /* 操作行：筛选 / 查询 / 重置 三等分，高度提到 40px（这一行是整块筛选区的主操作，
     32px 在手机上偏小）。 */
  .od-page .odm-adv-toggle.is-open.ant-btn { border-color: var(--d-blue); color: var(--d-blue); }
  .od-page .od-range,
  .od-page .od-select,
  .od-page .od-flag-select,
  .od-page .od-input { width: 100%; min-width: 0; }
  /* 单号查询那个**连体控件**：整行铺开，类型下拉固定一份、输入框吃掉剩下的宽度。
     ⚠️ 别把 `.od-search-group` 改成 flex-direction: column —— 那会丢掉「连体」语义
     （相邻角切平 + 两条 1px 描边重叠，见文件上方 `.od-search-group` 的注释）。 */
  .od-page .od-search-group { width: 100%; }
  .od-page .od-search-group .od-search-type { width: 106px; flex: none; }
  .od-page .od-search-group .od-search-input { flex: 1 1 auto; width: auto; min-width: 0; }
  .od-page .od-filter-actions { margin-left: 0; gap: 8px; }
  .od-page .od-filter-actions .ant-btn { flex: 1 1 0; min-width: 0; height: 40px; padding: 0 8px; }

  /* ── 状态页签：5 个（所有订单 / 待审核 / 待发货 / 已发货 / 异常）在 338px 里排不下。
     antd 默认靠「藏起来 + 右侧 ▾ 下拉」兜，手机上要多点一次；这里改成整行**原生横滑**：
     放开 nav-wrap 的 overflow，并把 antd 那套 transform 位移和「更多」按钮关掉。
     2026-09-21 桌面页签做大到 16px 后，这里单独收小一档并把 antd 的 32px 间距压到 18px ——
     15px + 18px 间距正好五个一屏排得下（225 + 72 ≈ 297 < 338），不用滑也能看全。 ── */
  .od-page .od-status-tabs .ant-tabs-tab { padding: 8px 0; font-size: 15px; }
  .od-page .od-status-tabs .ant-tabs-tab + .ant-tabs-tab { margin-left: 18px; }
  .od-page .od-status-tabs .ant-tabs-nav-wrap { overflow-x: auto; overflow-y: hidden;
    scrollbar-width: none; -ms-overflow-style: none; }
  .od-page .od-status-tabs .ant-tabs-nav-wrap::-webkit-scrollbar { display: none; }
  .od-page .od-status-tabs .ant-tabs-nav-list { transform: none !important; transition: none !important; }
  .od-page .od-status-tabs .ant-tabs-nav-operations { display: none !important; }
  .od-page .od-status-row { margin-bottom: 10px; }

  /* ── 订单卡 ───────────────────────────────────────────────────────────
     卡片本身的留白/描边/圆角走公共 `.m-row`（跟库存 / 销售 / 发货的手机卡同一套词汇），
     这里只加订单特有的几块：头（店铺 + 状态）、订单号行、虚线分隔的内容块、脚。 */
  .od-page .scard > .odm-body { padding: 4px 14px 14px; }
  .odm-row { gap: 9px; }
  .odm-head { display: flex; align-items: flex-start; gap: 8px; }
  /* 店铺名占满左边，状态 Tag 贴右边（手机上不另开一行放状态） */
  .odm-head .odm-store { flex: 1 1 auto; min-width: 0; font-size: 13px; font-weight: 600; }
  .odm-head-status { flex: none; }
  .odm-head-status .ant-tag { margin: 0; }
  .odm-sub { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; }
  .odm-sub .ant-tag { margin: 0; }
  .odm-mini-tag { margin: 0 !important; font-size: 11px; line-height: 18px; }
  .odm-no { font-size: 12px; color: rgba(0, 0, 0, .65); cursor: pointer;
    font-variant-numeric: tabular-nums; }
  .odm-no.is-none { color: rgba(0, 0, 0, .3); cursor: default; }
  .odm-abnormal { font-size: 12px; color: #cf1322; }
  /* 内容块之间用**虚线**分隔，不是再套一层卡片（§4 反模式：卡片套卡片） */
  .odm-block { padding-top: 8px; border-top: 1px dashed #eef1f6; }
  .odm-line { display: flex; align-items: baseline; gap: 6px; font-size: 12px; }
  .odm-key { flex: none; color: #8c93a0; }
  .odm-mute { color: #8c93a0; }
  .odm-foot { display: flex; align-items: center; gap: 8px; padding-top: 8px;
    border-top: 1px dashed #eef1f6; }
  .odm-code-line { display: flex; align-items: baseline; gap: 6px; flex: 1 1 auto;
    min-width: 0; font-size: 12px; }
  .odm-code-line .od-code { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* 「商品明细」是这张卡上唯一的操作，给足点按区（§2.4 触控 ≥44px；32px 的 link 按钮
     手指点不准，而且它两边都是文字，容易误触订单号）。 */
  .odm-toggle.ant-btn { flex: none; height: 40px; padding: 0 4px; }
  /* 行内「审核」：跟「商品明细」同一个触控高度，靠右排在它前面。
     ⚠️ 2026-09-25 起是**文字按钮**（ant-btn-link）—— 选择器必须带上 `.ant-btn-link`，
     否则拼不过上面那条三类的通用规则 `.ant-btn.ant-btn-sm.ant-btn-link { padding: 0 6px }`
     （0,3,0 压 0,2,0），触控区会被缩到 6px 边距。 */
  .odm-audit.ant-btn.ant-btn-link { flex: none; height: 40px; padding: 0 12px; }
  /* 「打单」在手机端**不做**（2026-09-30 用户明确），所以这里原来那条
     `.odm-print` 触控高度规则也一并删了 —— 留着就是给一个不存在的按钮调样式。 */
  /* 展开明细：每行一个 SKU 的数字块（桌面是 11 列表格，手机上没法看） */
  .odm-expand { padding-top: 10px; border-top: 1px dashed #eef1f6; }
  .odm-sku-list { display: flex; flex-direction: column; gap: 8px; }
  .odm-sku { display: flex; flex-direction: column; gap: 5px; padding: 8px 10px;
    background: #f7f9fc; border-radius: 8px; }
  .odm-sku-title { font-size: 12.5px; font-weight: 600; line-height: 1.35;
    word-break: break-all; }
  .odm-sku-sub { font-size: 11px; line-height: 1.4; color: #8c93a0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* 3 列 × 2 行：单价 / 件数 / 小计，可用库存 / 成本价 / 成本小计 */
  .odm-sku-nums { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 5px 8px; }
  .odm-num { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .odm-num-k { font-size: 10.5px; line-height: 1.3; color: #8c93a0; white-space: nowrap; }
  .odm-num-v { font-size: 12.5px; font-weight: 600; font-variant-numeric: tabular-nums;
    line-height: 1.4; }
  /* 可用库存那格在手机上只剩 ~100px：组合的组件清单**一条一行**（桌面那套 `space-between`
     两端对齐保留，但编码必须能缩 —— 不加 min-width:0 时 flex 子项缩不下去，会把数字顶出去）。
     改成上下堆叠试过：一个 3 组件组合要占 6 行，SKU 块被拉高一倍。 */
  .odm-num-v .od-stock-parts { gap: 2px; }
  .odm-num-v .od-stock-part { gap: 5px; }
  .odm-num-v .od-stock-code { font-size: 10.5px; min-width: 0; flex: 0 1 auto; }
  .odm-num-v .od-stock-part > span:last-child { flex: none; }
  /* 整单汇总：标签左、数字右（§3.3 数字右对齐），复用 `.m-detail-row` 那套 */
  .odm-sum { display: flex; flex-direction: column; gap: 5px; margin-top: 10px;
    padding-top: 9px; border-top: 1px dashed #eef1f6; }
  .odm-sum-warn { font-size: 11px; line-height: 1.5; color: #d46b08; }
  /* 加载 / 空态：`.odm-body` 里没有表格兜高度，得自己撑，否则卡片尾剩一截空白 */
  .odm-busy, .odm-empty { display: flex; align-items: center; justify-content: center;
    gap: 8px; padding: 34px 12px; color: #8c93a0; font-size: 12.5px; }
  /* 手机分页条：补上卡片自己的内边距 + 上细线（`.od-pager` 那套是按桌面写的） */
  .od-page .scard > .odm-pager { margin: 0; padding: 14px 14px 16px;
    border-top: 1px solid var(--d-line); }
  .odm-pager .ant-pagination { justify-content: center; }
}

/* ══════════════════════════════════════════════════════════════════════════
   入库 · 手机端明细字号（2026-09-19 用户反馈）
   ──────────────────────────────────────────────────────────────────────────
   「入库页面的移动端收货明细，sku 图片名字数量字都太小了」——查下来是三处：
     ① 缩略图 ProductThumb 默认 34px（桌面明细卡就是 300px 的网格一格，34 正好；
        手机上卡片铺满整屏，34px 只有小拇指甲盖大）；
     ② SKU 编码走公共 `.ship-code` = **12px 等宽字**，规格 12px —— 点货时名字看不清；
        （`.ship-code` 的 12px 是给桌面表格单元格定的，手机明细要单独抬高）
     ③ 数量/单价是 antd Tag（12px）。
   处理：图在 JS 里给 size=56，文字在这里抬字号，数量从 Tag 换成数字块 `.ibd-num`
   （标签 12px / 数字 16px + 等宽数位）——跟订单页手机展开明细的 `.odm-num` 是同一套读法。
   2026-09-21：数字块**提到全局**了（桌面也用，只是字号小一档），这里只留手机这一档的覆盖值。
   ⚠️ 别为了「看着轻」把这些字号调小；输入类控件那 16px 是防 iOS 聚焦缩放的（见文件末尾
      那条 ≤991px 的 `font-size:16px !important`），这里改的是**只读文本**，不冲突。
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 767px) {
  /* ── 待入库展开明细卡：只写跟桌面不一样的部分（公共样式见文件上方的 .inbound-detail-card）── */
  .inbound-detail-card-top { align-items: flex-start; }   /* 规格在手机上折成两行，图要顶对齐 */
  .inbound-detail-card-title { gap: 3px; }
  .inbound-detail-card-title .ship-code {
    font-size: 16px; font-weight: 600; line-height: 1.35; word-break: break-all;
  }
  .inbound-detail-card-spec { font-size: 13.5px; line-height: 1.4; white-space: normal; }

  /* ── 数字块：手机只覆盖「跟桌面不一样」的部分，公共样式见文件上方的 .ibd-nums ──
     手机字号比桌面大一档（标签 12 / 数字 16，桌面是 11 / 15）—— 照片前点货要看得清。
     4 个格子：390px 下每格 ≈75px，「应收 / 已收 / 待收 / 单价」都放得下；
     auto-fit + 64px 下限是为了更窄的屏（320~360px）自动降成 3 列，而不是把数字压扁。 */
  .ibd-nums { grid-template-columns: repeat(auto-fit, minmax(64px, 1fr)); gap: 8px; }
  .ibd-num { gap: 1px; }
  .ibd-num-k { font-size: 12px; }
  .ibd-num-v { font-size: 16px; }
  .ibd-loc { font-size: 14px; }

  /* ── 收货弹窗里的一张 SKU 卡（`.is-sku` 只加在收货弹窗那个循环上，
        不去动「待入库」列表卡和编辑弹窗卡片 —— 那两处的 `.ship-code` 是入库单号，
        字号本来就该跟卡头一致）── */
  .inbound-card.is-sku .inbound-card-head { align-items: flex-start; gap: 10px; }
  .inbound-card.is-sku .inbound-card-title { flex-direction: column; align-items: flex-start; gap: 3px; }
  .inbound-card.is-sku .inbound-card-title .ship-code {
    font-size: 16px; font-weight: 600; line-height: 1.35; word-break: break-all;
  }
  .inbound-card.is-sku .ibd-sku-spec { font-size: 13.5px; line-height: 1.4; color: var(--d-ink-3); }
  /* 三个数字格：应收 / 已收 / 欠 —— 输入框上面这一行是点货时要对着念的，给足字号 */
  .inbound-card.is-sku .ibd-nums { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .inbound-card.is-sku .inbound-field { gap: 4px; }
  .inbound-card.is-sku .inbound-field > span { font-size: 13px; }
}

/* ── 订单「自动添加自选商品」（2026-09-20）────────────────────────────────
   按钮跟在留言/备注那格里（.od-memo-wrap 内的最后一个元素）。
   ⚠️ 窄屏那条「表单控件 ≥16px」管的是**输入框**（聚焦会放大整页）；按钮不用放大，
   保持 12px 跟这一格的正文协调。 */
.od-ss-btn { margin-top: 2px; align-self: flex-start; }
.od-ss-btn > span { font-size: 12px; }
/* 预览弹窗：把「要加什么」摆出来，认不出的名字标红 */
.ss-modal { display: flex; flex-direction: column; gap: 8px; font-size: 13px; }
.ss-line { display: flex; gap: 8px; align-items: flex-start; }
.ss-k { flex: none; width: 76px; color: var(--d-ink-3); }
.ss-remark { word-break: break-word; color: var(--d-ink-2); }
.ss-tip { color: var(--d-ink-3); }
.ss-add {
  display: flex; flex-direction: column; gap: 4px;
  border: 1px solid var(--d-line); border-radius: 6px; padding: 8px 10px; background: #fafafa;
}
.ss-add-row { display: flex; justify-content: space-between; gap: 10px; }
.ss-add-name { font-weight: 600; }
.ss-add-row code { color: var(--d-ink-3); font-family: var(--d-mono); }
.ss-bad { color: #cf1322; line-height: 1.6; word-break: break-word; }
/* ── 确认打单弹窗（2026-09-30 按 design/DESIGN-SYSTEM.md 重排）──────────────────
   规范要点（对着改的，别再自己造值）：
     §1.1 颜色只用 token；主色一屏最多一个主按钮 → 这块**不许用蓝底**（蓝留给「确认打单」）
     §1.2 圆角只有 22/16/11/pill → 卡片 16、小块 11、胶囊 999（**没有 6px**）
     §1.3 间距只有 4/8/12/16/22/28 → gap 一律 var(--d-g-*)（**没有 6/10px**）
     §1.5 所有数字 tabular-nums
     §3.4 状态胶囊三重编码：色块 + 文字 + 圆点（只靠颜色在色弱/强光下失效）
     §3.5 提示条用项目现成的 `.salert`（琥珀 = 需要你注意）
     §4  禁止「万物皆卡片 / 卡片套卡片」→ 分层靠留白 + 1px 分隔线
   三个分区：`.ss-kv` 信息行（dt/dd + 分隔线）· `.ss-grp` 按店铺分行 ·
   `.ss-sec` 发货单那块（panel-2 底 + 描边，不上蓝）。 */
.ss-dim { color: var(--d-ink-3); }
/* Alert 里那个小图标：16px 实心圆 + 琥珀深字，跟 §3.5 的图标尺寸一致 */
.ss-alert-ic {
  flex: 0 0 16px; width: 16px; height: 16px; margin-top: 2px; border-radius: 50%;
  background: var(--d-amber); color: #fff; font-size: 11px; font-weight: 800;
  line-height: 16px; text-align: center;
}
/* 信息行：标签固定一列、值自适应，行与行之间 1px 细线（不是每个值都套盒子） */
.ss-kv { margin: 0; display: flex; flex-direction: column; }
.ss-kv-row {
  display: flex; gap: var(--d-g-3); align-items: baseline; min-width: 0;
  padding: var(--d-g-2) 0;
}
.ss-kv-row + .ss-kv-row { border-top: 1px solid var(--d-line); }
.ss-kv-k { flex: none; width: 60px; margin: 0; color: var(--d-ink-3); }
.ss-kv-v {
  flex: 1; min-width: 0; margin: 0; color: var(--d-ink); word-break: break-word;
}
/* 状态胶囊（§3.4 三重编码）。纯分类用 violet（不带情绪），需要注意用 amber。 */
.ss-pill {
  display: inline-flex; align-items: center; gap: var(--d-g-1);
  flex: none; margin: 0 var(--d-g-1); padding: 0 var(--d-g-2);
  border-radius: var(--d-r-pill); font-size: 11px; line-height: 18px;
  white-space: nowrap;
}
.ss-pill .ss-dot {
  width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none;
}
.ss-pill.is-cat { background: var(--d-violet-soft); color: #5B3FB0; }
.ss-pill.is-amber { background: var(--d-amber-soft); color: var(--d-amber-ink); }
.ss-pill.is-red { background: var(--d-red-soft); color: var(--d-red-ink); }
/* 余额提醒（多组里有一组不够时） */
.ss-note {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--d-g-1);
  margin-top: var(--d-g-2); color: var(--d-amber-ink);
}
/* 按店铺分：标题 + 每行（分类胶囊 / 店名单数 / 该账号余额），行间同样是细线 */
.ss-grp { margin-top: var(--d-g-3); }
.ss-grp-title { color: var(--d-ink-3); margin-bottom: var(--d-g-1); }
.ss-grp-row {
  display: flex; gap: var(--d-g-2); align-items: baseline; min-width: 0;
  padding: var(--d-g-2) 0;
}
.ss-grp-row + .ss-grp-row { border-top: 1px solid var(--d-line); }
.ss-grp-main { flex: 1; min-width: 0; word-break: break-word; }
.ss-grp-quota { flex: none; color: var(--d-ink-2); white-space: nowrap; }
/* 发货单那块：次级底 + 细描边（不是「另一种卡片」，所以不叠阴影） */
.ss-sec {
  margin-top: var(--d-g-3); padding: var(--d-g-3);
  background: var(--d-panel-2); border: 1px solid var(--d-line-2);
  border-radius: var(--d-r-sm);
}
.ss-sec.is-off { opacity: .7; }
.ss-sec-title { color: var(--d-ink-2); margin-bottom: var(--d-g-2); }
.ss-sec-body { display: flex; flex-direction: column; gap: var(--d-g-2); }
/* 「再打一张发货单」那行：勾选框顶到标签前面，跟上面信息行左边缘对齐 */
.ss-delivery { display: flex; gap: var(--d-g-2); align-items: flex-start; }
.ss-delivery .ant-checkbox { margin-top: 2px; }
.ss-delivery-opts { margin-top: var(--d-g-1); }
.ss-delivery-opts .ss-kv-k { width: 40px; }
.ss-delivery-opts .ss-kv-row { padding: 0; }
.ss-delivery-opts .ss-kv-row + .ss-kv-row { border-top: none; }
/* 下拉在网格里必须能收缩：模板名那串「发货单模板_热敏1（102×177.8mm，模板打印机
   Deli DL-888B）」很长，不加 min-width:0 会把弹窗顶出横向滚动条（2026-09-30 实测
   ss-modal 373 > 334）。选中项超长省略号。 */
.ss-delivery-opts .ant-select { flex: 1 1 auto; min-width: 0; width: auto; max-width: 100%; }
.ss-delivery-opts .ant-select-selection-item {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 480px) {
  .ss-kv-k { width: 52px; }
  .ss-grp-row { flex-wrap: wrap; }
  .ss-grp-quota { flex-basis: 100%; }
}
/* ── 打单弹窗里的单据表（2026-09-29 用户要求「打单弹窗显示信息对齐」）────────
   照优易打单弹窗的表头：系统单号 / 运单号 / 收件信息 / 打印选号 / 状态。
   用 CSS grid 而不是 antd Table：行数是「这次要打的几单」（个位数到几十），
   Table 那套排序/分页/空态纯属负担，而且 grid 能在窄屏直接折行不溢出。
   列宽用 fr + minmax(0,1fr)：**每列都必须能收缩到 0**（`minmax(0,…)`），
   否则「收件信息」那列的长地址会把 grid 顶破、整张表横向溢出。 */
.pr-table {
  margin: var(--d-g-2) 0 var(--d-g-1); border: 1px solid var(--d-line);
  border-radius: var(--d-r-sm); overflow: hidden; font-size: 13px;
}
.pr-row {
  display: grid; gap: var(--d-g-2); padding: var(--d-g-1) var(--d-g-2);
  align-items: center; grid-template-columns: 140px 130px minmax(0, 1fr) 120px 68px;
}
.pr-row + .pr-row { border-top: 1px solid var(--d-line); }
.pr-head { background: #fafafa; color: var(--d-ink-3); font-size: 12px; }
.pr-c { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pr-c-code, .pr-c-no, .pr-c-batch { font-variant-numeric: tabular-nums; }
.pr-c-recv { white-space: normal; line-height: 1.45; word-break: break-word; }
/* 打不了的行压暗（但**别**整行变红 —— 红色留给「状态」那格的标签，
   整行红会让人以为出了故障，其实只是这单被优易挡了）。 */
.pr-row.is-blocked { background: #fafafa; color: var(--d-ink-3); }
.pr-row.is-blocked .pr-c-code, .pr-row.is-blocked .pr-c-no { text-decoration: line-through; }
/* 打单弹窗的「面单余额」行（2026-09-30）：照优易的「还剩余 N 个单号」。
   数字是主角 → 等宽 + 加粗；不够时转红，但**只是提醒，不挡提交**，
   所以别做成 antd 那种 error 块（那会让人以为已经拦住了）。
   .ss-val 撑开剩下的宽度，让多个渠道的余额各占一行、对齐在同一条基线上。 */
.ss-val { min-width: 0; display: flex; flex-direction: column; gap: var(--d-g-1); }
.ss-num { font-weight: 600; font-variant-numeric: tabular-nums; }
.ss-num.is-short { color: #cf1322; }
/* ⚠️ 这里**刻意没有**窄屏适配（2026-09-29 用户要求：打单功能手机端用不上）。
   四列表格在 390px 会被压扁，但既然手机端压根不提供打单入口，也走不到这张表。
   哪天真要支持手机打单，得先重新设计（比如卡片式一行一单），别靠压列宽凑合。 */
/* 「手动指定：留言里的写法 → 商品库名字」（2026-09-25）：认不出的名字给一条出路。
   语义走琥珀（提醒/可操作），跟 `.ss-bad` 的红（没通过）分开 —— 这里不是错误，是待办。
   手机上弹窗 390px：输入框必须能收缩（flex:1 + min-width:0），否则整块被长名字撑破。 */
.ss-fix {
  display: flex; flex-direction: column; gap: 6px;
  border: 1px solid #ffe58f; background: #fffbe6; border-radius: 6px; padding: 8px 10px;
}
.ss-fix-title { color: #ad6800; font-weight: 600; display: flex; flex-wrap: wrap;
  gap: 6px; align-items: baseline; }
.ss-fix-sub { font-weight: 400; font-size: 12px; color: var(--d-ink-3); }
.ss-fix-row { display: flex; align-items: center; gap: 6px; min-width: 0; }
.ss-fix-from {
  flex: none; max-width: 42%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--d-ink-2); font-family: var(--d-mono);
}
.ss-fix-row.is-miss .ss-fix-from { color: #cf1322; }
.ss-fix-arrow { flex: none; color: var(--d-ink-3); }
.ss-fix-to { flex: 1; min-width: 0; }
.ss-fix-flag { flex: none; color: #cf1322; font-size: 12px; }
.ss-fix-ok { flex: none; color: #389e0d; font-size: 12px; }
/* 原来这里有一条自造的 `.ss-warn`（琥珀底 + 6px 圆角 + 写死色值），给「审核确认框的
   优易提醒」和「打单确认框的边界提示」用。2026-09-30 按 design/DESIGN-SYSTEM.md
   §3.5 统一到项目现成的 `.salert warn`（圆角 13px、色值走 token），两个弹窗的提示条
   现在是同一个组件 —— 这条自造样式已删，别再加回来。 */

/* ── 订单审核（待审核页签「审核订单」，2026-09-23 用户要求）─────────────────── */
/* 卡头批量按钮跟「一键添加自选」并排，同一个右边距 */
.od-audit-btn { margin-right: 8px; }
/* 行内「审核」列：84px 里只放一个小按钮，别让它把行撑高 */
.od-row-audit.ant-btn { padding: 0 10px; }

/* ── 订单打单（待打单页签「打单」，2026-09-24 用户要求）────────────────────── */
/* 卡头批量按钮跟「审核订单」并排同款；行内「打单」列同 84px 口径 */
.od-print-btn { margin-right: 8px; }
.od-row-print.ant-btn { padding: 0 10px; }
/* 确认框里挡单理由的「展开其余 N 条」：link 按钮贴左，别缩进一格 */
.print-blocked-more.ant-btn { margin-left: -12px; padding: 0; }

/* ── 订单「一键添加自选」（批量）/「同步勾选」+ 多选 + 快捷筛选排 ──────────── */
.od-ssbatch-btn, .od-syncsel-btn { margin-right: 8px; }
/* 「快捷筛选」独立一排（2026-09-21）：留言/备注 + 平台快捷按钮，跟查询控件分开。
   .od-pair = 单选按钮对的拼接样式（选中实心主色、首尾圆角）。 */
.od-quick-row { display: flex; flex-wrap: wrap; gap: 12px 24px; align-items: flex-end; margin-top: 12px; }
.od-pair { display: inline-flex; }
.od-pair .odm-memo-btn, .od-pair .od-platform-btn { margin-right: 0; }
.od-pair .ant-btn:first-child { border-radius: 6px 0 0 6px; }
.od-pair .ant-btn:last-child { border-radius: 0 6px 6px 0; margin-left: -1px; }
/* 旗帜筛选（2026-09-25）：多选下拉，选项/选中 tag 里的旗子小图标和文字对齐 */
.od-flag-select { min-width: 190px; }
.od-flag-opt { display: inline-flex; align-items: center; gap: 6px; }
.ss-batch-list {
  display: flex; flex-direction: column; gap: 6px; max-height: 46vh; overflow: auto;
}
.ss-batch-row {
  border: 1px solid var(--d-line); border-radius: 6px; padding: 6px 10px;
  display: flex; flex-direction: column; gap: 2px;
}
.ss-batch-row.is-off { opacity: .55; }
.ss-batch-head { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
.ss-batch-tag { flex: none; color: var(--d-ink-3); font-size: 12px; }
.ss-batch-skus { color: var(--d-ink-2); word-break: break-word; }
.ss-batch-reason { color: #cf1322; font-size: 12px; word-break: break-word; }

/* ── 订单「自选自动补单」状态条（2026-09-29）────────────────────────────────
   服务端每小时的 :00 / :30 自己跑一轮，这条把「上一轮补了什么、挂了几单」摆出来。
   只挂在「待审核」页签（见 app.js 的 ssAutoBar）。放进 .scard 里算「散装内容」，
   自己补内边距 —— 跟 .inbound-bulkbar 同一条规矩。 */
.od-auto-bar {
  display: flex; align-items: center; gap: 10px;
  margin: 0 16px 12px; padding: 9px 12px;
  background: var(--d-blue-soft); border-radius: var(--d-r-sm);
  font-size: 12px; line-height: 1.5; color: #1E4E8C;
}
.od-auto-bar.is-off { background: var(--d-panel); color: var(--d-ink-2); }
.od-auto-dot { flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%; background: var(--d-ink-4); }
.od-auto-dot.is-on { background: var(--d-green); }
.od-auto-dot.is-off { background: var(--d-ink-4); }
/* 正在跑：琥珀点 + 一圈光晕，跟「静态开着」区分得开 */
.od-auto-dot.is-run { background: var(--d-amber); box-shadow: 0 0 0 3px rgba(245, 158, 11, .22); }
.od-auto-text { flex: 1 1 auto; min-width: 0; }
.od-auto-text b { font-weight: 800; }
.od-auto-err { color: #A63232; font-weight: 700; }
.od-auto-ops { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 8px; }
.od-auto-switch { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
@media (max-width: 767px) {
  /* 窄屏：控件一行放不下，整条改竖排（状态一行、操作一行） */
  .od-auto-bar { flex-wrap: wrap; margin: 0 12px 10px; }
  .od-auto-text { flex: 1 1 100%; }
  .od-auto-ops { flex: 1 1 100%; flex-wrap: wrap; justify-content: flex-start; }
}

/* ── 每月做账（2026-09-30 用户要求）──────────────────────────────────────────
   页面：顶部月份/范围 + 「结账」；页内两个页签（月度资产 / 店铺归属自查）。
   资产 = 库存货值 + 在途库存 + 应收货款 + 支付宝 + 聚合结算；固定费用是**费用**不进资产。
   颜色约定：环比往上用蓝、往下用琥珀 —— **不做红绿**，因为「库存变多」不等于好事，
   这里只表示方向，不表示好坏（财务页最容易犯的错就是给变化上色暗示）。 */
.ac-tab { display: flex; flex-direction: column; gap: 14px; }
.ac-kpis { margin-bottom: 0; }
.ac-num { line-height: 1.35; }
.ac-num-v { font-variant-numeric: tabular-nums; font-weight: 600; }
.ac-num.is-strong .ac-num-v { font-weight: 800; }
.ac-num-d { font-size: 11px; color: var(--d-ink-3); font-variant-numeric: tabular-nums; }
.ac-num-d.is-up { color: var(--d-blue); }
.ac-num-d.is-down { color: var(--d-amber-ink); }
.ac-none { color: var(--d-ink-3); font-size: 12px; }

/* 资产合计：一张独立小卡（跟「库存货值」那张 .skcard 同一档） */
.ac-total { padding: 14px 16px 13px; }
.ac-total-main { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.ac-total-lab { font-size: 12.5px; color: var(--d-ink-2); }
.ac-total-num { font-size: 26px; font-weight: 800; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; }
.ac-total-diff { font-size: 12.5px; color: var(--d-ink-2); }
.ac-total-diff.is-up { color: var(--d-blue); }
.ac-total-diff.is-down { color: var(--d-amber-ink); }
.ac-total-note { margin-top: 7px; font-size: 11.5px; color: var(--d-ink-3); line-height: 1.6; }

/* 手工录入：一行一个店，列宽固定（表头与数据行同宽才对得齐） */
.ac-manual-body { padding: 0 16px 14px; }
.ac-manual-row { display: flex; align-items: center; gap: 10px; padding: 5px 0;
  border-bottom: 1px solid var(--d-line); }
.ac-manual-row:last-child { border-bottom: none; }
.ac-manual-head { color: var(--d-ink-3); font-size: 11.5px; padding-bottom: 7px; }
.ac-manual-store { flex: 1 1 auto; min-width: 0; font-size: 12.5px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.ac-manual-store i { color: var(--d-ink-3); font-style: normal; font-size: 11px; }
.ac-manual-row > span { flex: 0 0 104px; }
.ac-manual-row > span:first-child { flex: 1 1 auto; }
.ac-manual-owner { margin-top: 6px; padding-top: 10px; border-top: 1px dashed var(--d-line-2); }
/* 固定费用：整月、不分店铺，一行一项（房租/物业/水电/网费…），合计进利润 */
.ac-exp-body { padding: 0 16px 14px; display: flex; flex-direction: column; gap: 6px; }
.ac-exp-row { display: flex; align-items: center; gap: 8px; }
.ac-exp-name { flex: 1 1 auto; min-width: 0; }
.ac-exp-amount { flex: 0 0 130px; }
.ac-exp-empty { font-size: 12px; color: var(--d-ink-3); padding: 4px 0 2px; }
.ac-exp-total { display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  margin-top: 4px; padding-top: 9px; border-top: 1px solid var(--d-line-2);
  font-size: 13px; font-weight: 800; }
.ac-exp-total b { font-variant-numeric: tabular-nums; }
/* 时点值 / 期间值 的分组小标题（2026-09-30）：两类数性质不同，必须看得出来 */
.ac-manual-group { padding: 13px 16px 5px; font-size: 11.5px; color: var(--d-ink-3); }
/* 归属自查重扫中：一个小胶囊说明状态。刻意**不遮页面** —— 用户原话「一点就刷新加载，
   没法操作」：遮罩式 loading 会让人以为页面死了，而且想接着改下一行都不行。 */
.ac-attr-busy {
  display: inline-flex; align-items: center; height: 22px; padding: 0 10px;
  border-radius: var(--d-r-pill); background: var(--d-violet-soft); color: #5B3FB0;
  font-size: 11px; line-height: 22px; white-space: nowrap;
}
/* 手动归属：刚归掉的那一行**留在原位**（不删 —— 删了下面的行会往上顶，用户原话
   「手动归属的操作体验很差，动不动跳」）。置灰 + 一个「已归 X」小标签就够说明它做完了，
   不抢注意力，但位置不变 → 你能顺着货值往下改，鼠标底下的行不会跑。 */
.ac-attr-done td { background: var(--d-violet-soft); }
.ac-attr-done td:first-child { box-shadow: inset 3px 0 0 var(--d-violet); }
.ac-done-tag {
  display: inline-block; padding: 0 8px; height: 22px; line-height: 22px;
  border-radius: var(--d-r-pill); background: var(--d-violet-soft); color: #5B3FB0;
  font-size: 11px; white-space: nowrap;
}
/* 「已归 X · 同步中」：服务端还没确认这条（写入是整份 Gist PATCH，要好几秒）。
   说清楚比让人以为丢了好 —— 用户 2026-10-01：「同步后端数据可能还没变，又跳回来」。 */
.ac-done-tag.ac-syncing {
  background: var(--d-amber-soft); color: #9A6B12;
}
/* 「撤销中…（等同步）」：点完撤销、服务端还没确认的那一行。
   它**留在表里**等着重选 —— 不能因为服务端还说「它归着那家店」就把它收走。 */
.ac-undoing {
  display: inline-block; padding: 0 8px; height: 22px; line-height: 22px;
  border-radius: var(--d-r-pill); background: var(--d-amber-soft); color: #9A6B12;
  font-size: 11px; white-space: nowrap;
}
/* 「刚改了 N 行 · 立即对齐」：告诉你还差一次后台对齐，但**不催你**（重扫已改成空闲再发） */
.ac-attr-pending {
  display: inline-flex; align-items: center; height: 22px; padding: 0 4px 0 10px;
  border-radius: var(--d-r-pill); background: var(--d-amber-soft); color: #9A6B12;
  font-size: 11px; line-height: 22px; white-space: nowrap;
}
.ac-attr-pending .ant-btn { height: 22px; padding: 0 6px; font-size: 11px; }

/* 欠货横幅里那句「已跳过 N 张旧欠单」：次要信息，压暗一点别跟主文案抢 */
.sf-dropped { color: var(--d-ink-3); }

/* 「实付订单数」后面那个 ±N：交易时间口径与优易付款口径的差额，鼠标悬停有说明 */
.stat-gap { margin-left: 4px; color: var(--d-ink-3); font-size: 11px; }

/* 「应收货款」的口径提示：接在时点值说明后面的一段小字。这条只能悬停才看得到的
   信息（表头 title）不够 —— 最容易被填错的一列，口径要直接摆在眼前。 */
.ac-manual-hint { margin-left: 8px; }
/* 「不适用」那一格：按渠道判定后这家店走的是别的账户（比如小红书没有支付宝）。
   摆成灰字而不是一个能点的输入框 —— 能填就会有人填，填了资产就错了。 */
.ac-manual-row > span.ac-na {
  flex: 0 0 104px; color: var(--d-ink-3); font-size: 12px; text-align: center;
  opacity: .75; cursor: not-allowed; user-select: none;
}
.ac-manual-row > span.ac-manual-date { flex: 0 0 142px; }
.ac-manual-date .ant-picker { padding: 1px 7px; font-size: 12px; }
/* 结账按钮旁边那个「手工项缺 N 项」提示 */
.ac-hint-warn { font-size: 11.5px; color: var(--d-amber-ink); background: var(--d-amber-soft);
  border-radius: 999px; padding: 3px 9px; }
.ac-input.ant-input { padding: 2px 7px; font-size: 12px; font-variant-numeric: tabular-nums; }

.ac-table .ac-store { font-size: 12.5px; }
.ac-store-tag { margin-left: 6px; font-style: normal; font-size: 11px; color: var(--d-amber-ink);
  background: var(--d-amber-soft); border-radius: 999px; padding: 1px 7px; }
.ac-table .ant-table-summary > tr > td { background: var(--d-panel-2); font-weight: 700; }
.ac-warn { padding: 9px 16px 11px; font-size: 11.5px; line-height: 1.7; color: var(--d-amber-ink);
  background: var(--d-amber-soft); }

/* 利润与对账：左右两栏（成交口径 / 资产差额法），下面一条差额带 */
.ac-profit-body { display: flex; gap: 22px; padding: 0 16px 6px; flex-wrap: wrap; }
.ac-profit-col { flex: 1 1 320px; min-width: 260px; }
.ac-profit-col h3 { margin: 0 0 9px; font-size: 12.5px; font-weight: 800; color: var(--d-ink); }
.ac-profit-rows { display: flex; flex-direction: column; gap: 5px; }
.ac-profit-row { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px;
  color: var(--d-ink-2); }
.ac-profit-row b { color: var(--d-ink); font-variant-numeric: tabular-nums; }
.ac-profit-net { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--d-line-2);
  display: flex; justify-content: space-between; gap: 12px; font-size: 13px; font-weight: 800; }
.ac-profit-net b { font-variant-numeric: tabular-nums; }
.ac-gap { margin: 10px 16px 16px; padding: 11px 13px; border-radius: var(--d-r-sm);
  background: var(--d-panel); font-size: 12px; line-height: 1.7; color: var(--d-ink-2); }
.ac-gap.is-ok { background: var(--d-green-soft); color: var(--d-green-ink); }
.ac-gap.is-warn { background: var(--d-amber-soft); color: var(--d-amber-ink); }
.ac-gap-note { margin-top: 6px; font-size: 11.5px; line-height: 1.75; color: var(--d-ink-2); }

/* 店铺归属自查 */
.ac-attr-sum { padding: 0 16px 14px; }
.ac-attr-big { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.ac-attr-big b { font-size: 22px; font-weight: 800; font-variant-numeric: tabular-nums; }
.ac-attr-big span { font-size: 12.5px; color: var(--d-ink-2); }
.ac-attr-note { margin-top: 7px; font-size: 11.5px; line-height: 1.75; color: var(--d-ink-3); }
/* 「本地归属修正」那块（2026-10-01 重排）：原来 290 条平铺成 290 个药丸堆在正文上方，
   每条还重复一遍超长店名 → 又丑又把真正要干活的「未对应」表挤出屏幕
   （用户原话：「已修正的一堆非常丑，东西堆一堆乱七八糟的」）。
   现在：默认收起只占一行；展开后按店分组 + 固定高度内部滚动 + 可搜可筛。 */
.ac-ov-sum { padding: 0 16px 13px; font-size: 12.5px; color: var(--d-ink-2); }
.ac-ov-body { padding: 0 16px 14px; }
.ac-ov-filter { font-size: 11.5px; color: var(--d-ink-3); margin-bottom: 8px; }
.ac-ov-empty { font-size: 12px; color: var(--d-ink-3); padding: 6px 0; }
/* 固定高度 + 内部滚动：290 条也不把页面撑长（滚动条细一点，别抢注意力） */
.ac-ov-body { max-height: 208px; overflow-y: auto; }
.ac-ov-body::-webkit-scrollbar { width: 8px; }
.ac-ov-body::-webkit-scrollbar-thumb { background: var(--d-line); border-radius: 999px; }
.ac-ov-group + .ac-ov-group { margin-top: 10px; }
.ac-ov-gh {
  display: flex; align-items: baseline; gap: 8px; font-size: 11.5px;
  color: var(--d-ink-3); margin-bottom: 6px; position: sticky; top: 0;
  background: var(--d-panel); padding: 2px 0;
}
.ac-ov-gh b { font-size: 12.5px; color: var(--d-ink-1); font-weight: 700; }
.ac-ov-grid { display: flex; flex-wrap: wrap; gap: 6px; }
/* 组内只留 SKU：店名在组标题写一次就够，不用每条重复（这才是「乱七八糟」的根源） */
.ac-ov-item {
  display: inline-flex; align-items: center; gap: 2px; font-size: 12px; line-height: 22px;
  background: var(--d-panel); border: 1px solid var(--d-line); border-radius: 999px;
  padding: 0 3px 0 10px;
}
.ac-ov-item b { font-weight: 600; font-variant-numeric: tabular-nums; }
.ac-ov-sync { font-size: 10.5px; color: #9A6B12; margin-left: 4px; }
/* 撤销就是一个不起眼的小 ×：hover 才变红，别让 290 个「撤销」链接抢注意力 */
.ac-ov-item .ac-ov-x { height: 20px; padding: 0 5px; font-size: 13px; color: var(--d-ink-3); }
.ac-ov-item .ac-ov-x:hover { color: #C2410C; }

@media (max-width: 767px) {
  /* 窄屏：手工录入一行放不下 4 列 → 店名独占一行、输入框两列一行 */
  .ac-manual-row { flex-wrap: wrap; gap: 6px 8px; }
  .ac-manual-row > span:first-child { flex: 1 1 100%; }
  .ac-manual-row > span { flex: 1 1 40%; }
  .ac-manual-head { display: none; }        /* 表头在窄屏没意义，输入框自带「未填」占位 */
  /* 固定费用：窄屏把金额换到下一行，别把项目名挤成一条线 */
  .ac-exp-row { flex-wrap: wrap; }
  .ac-exp-amount { flex: 1 1 100%; }
  .ac-profit-body { gap: 16px; padding: 0 12px 4px; }
  .ac-gap { margin: 8px 12px 12px; }
  .ac-total-num { font-size: 22px; }
}

/* ── 1688 扫码登录（无屏幕模式：服务器把二维码截成图，这里显示）─────────────
   2026-10-02。云服务器没有 X server，弹不出浏览器窗口，login_1688.py 改成把
   登录页二维码截成 PNG，前端轮询 /api/1688/login-qr 显示。 */
.a1688-qr-box { text-align: center; line-height: 1.7; }
.a1688-qr {
  display: block;
  margin: 12px auto 10px;
  width: 260px;                       /* 截图里二维码约 140px，放大到 260 才好扫 */
  height: auto;
  image-rendering: pixelated;         /* 放大别糊，扫码器对边缘很敏感 */
  border: 1px solid #e8e8e8;
  border-radius: 4px;
  background: #fff;
}
.a1688-qr-hint { font-size: 12px; color: #999; }

/* ── 备案号页脚（工信部要求：所有页面底部可见 + 链到 beian.miit.gov.cn）─────
   2026-10-02。挂在 Layout 层，所以切页面/开弹窗都一直在。 */
.site-footer {
  flex: none;
  padding: 10px 16px 14px;
  text-align: center;
  font-size: 12px;
  line-height: 1.6;
  border-top: 1px solid #f0f0f0;
}
.site-footer a {
  color: #8c8c8c;
  text-decoration: none;
}
.site-footer a:hover { color: #1890ff; text-decoration: underline; }
/* 登录页里的那份：跟着卡片走，不要占满一整行 */
.site-footer-compact {
  border-top: none;
  padding: 14px 0 2px;
}

/* ── 访问口令登录表单 ─────────────────────────────────────────────────── */
.access-form { margin-top: 18px; }

/* ── 点行即选中（2026-10-03 用户要求「订单列表点击行就可以选中」）─────────
   整行给 pointer 提示「这里能点」；但单号复制、审核/打单这些**单元格内的可点元素**
   保持原样 —— 它们点的是自己，不是选整行，光标得说实话。 */
.od-table .od-row-clickable { cursor: pointer; }
.od-table .od-row-clickable > td > a,
.od-table .od-row-clickable .od-code,
.od-table .od-row-clickable .od-order-no,
.od-table .od-row-clickable .od-set-link,
.od-table .od-row-clickable .od-row-audit,
.od-table .od-row-clickable .od-row-print { cursor: pointer; }
/* 选中态 antd 自己会给 .ant-table-row-selected，这里只补一点对比度，
   免得在一堆单据里看不出选中了哪几行 */
.od-table .ant-table-tbody > tr.ant-table-row-selected > td { background: #eaf3ff; }
.od-table .ant-table-tbody > tr.ant-table-row-selected:hover > td { background: #e3eeff; }

/* ── 1688 风控说明弹窗（2026-10-03）────────────────────────────────────
   核心是那两条命令要能一眼看清、能整行复制，所以命令区固定单行 + 横向滚动，
   复制按钮固定在右侧不跟着换行。 */
.a1688-blocked .a1688-step { margin-top: 14px; }
.a1688-blocked .a1688-step > b { display: block; margin-bottom: 6px; font-size: 13px; }
.a1688-blocked .a1688-cmd {
  display: flex; align-items: center; gap: 8px;
  background: #f6f8fa; border: 1px solid #e5e8eb; border-radius: 6px;
  padding: 7px 8px 7px 10px;
}
.a1688-blocked .a1688-cmd > code {
  flex: 1 1 auto; min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; color: #1f2937;
  white-space: nowrap; overflow-x: auto;   /* 长命令横向滚，别把按钮挤下去 */
}
.a1688-blocked .a1688-cmd > .ant-btn { flex: 0 0 auto; }
.a1688-blocked .a1688-hint {
  margin-top: 5px; font-size: 12px; color: #6b7280; line-height: 1.6;
}
.a1688-blocked .a1688-hint > code {
  background: #eef1f4; border-radius: 3px; padding: 0 4px; font-size: 11.5px;
}
