/* =============================================================================
   app.css — WMS 组件与动效 v6.0  「深空科幻」
   -----------------------------------------------------------------------------
   参考 Tesla / Apple 官网: 深空底 + 微光粒子 + 玻璃拟态 + 渐变光晕。
   特效原则:
   1) 粒子只做背景氛围, 不干扰内容阅读。
   2) 光晕仅用于品牌色与关键状态, 全站可控。
   3) 玻璃拟态仅用于导航/卡片/浮层, 内容区保持可读。
   4) 渐变仅用于大标题与品牌元素, 不滥用。
============================================================================= */

/* -----------------------------------------------------------------------------
   0. 图标 mask 库
   base.html 与部分页面模板里仍写着 emoji 和错误图标(人头像当库存)。
   这些文件不在本次可改范围内, 所以在 CSS 层用 mask 把它们整体替换掉:
   字号归零 + 背景走 currentColor + mask 打上正确的线性图标。
   结果: 吃 currentColor、随主题变、基线由 CSS 控制 —— emoji 的三个致命伤全解。
----------------------------------------------------------------------------- */
:root{
  --ic-order:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5.5 3.5h9l4 4v13h-13z'/%3E%3Cpath d='M14.5 3.5v4h4'/%3E%3Cpath d='M8.5 11.5h7M8.5 15h7M8.5 18h4'/%3E%3C/svg%3E");
  --ic-inbound:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3v9'/%3E%3Cpath d='M8.5 8.5 12 12l3.5-3.5'/%3E%3Cpath d='M4.5 14.5v6h15v-6'/%3E%3C/svg%3E");
  --ic-tag:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11.6 3.5h8.9v8.9l-8.2 8.2a1.6 1.6 0 0 1-2.3 0l-6.6-6.6a1.6 1.6 0 0 1 0-2.3z'/%3E%3Ccircle cx='16.6' cy='7.4' r='1.3'/%3E%3C/svg%3E");
  --ic-check:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12.4 9.4 17.8 19.5 6.4'/%3E%3C/svg%3E");
  --ic-alert:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.6 21.2 19.6H2.8z'/%3E%3Cpath d='M12 9.6v4.5'/%3E%3Cpath d='M12 17.1h.01'/%3E%3C/svg%3E");
  --ic-ban:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M5.9 18.1 18.1 5.9'/%3E%3C/svg%3E");
  --ic-clock:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M12 6.8V12l3.6 2.2'/%3E%3C/svg%3E");
  --ic-waive:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 2.9 19.8 5.8v6.2c0 4.3-3.1 7.2-7.8 8.9-4.7-1.7-7.8-4.6-7.8-8.9V5.8z'/%3E%3Cpath d='M8.7 11.9 11 14.2l4.3-4.5'/%3E%3C/svg%3E");
  --ic-truck:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8.5h10.5v8h-10.5z'/%3E%3Cpath d='M13 11h3.6l2.9 3.2v2.3h-6.5'/%3E%3Ccircle cx='6.4' cy='18.3' r='1.6'/%3E%3Ccircle cx='16.6' cy='18.3' r='1.6'/%3E%3Ccircle cx='7.8' cy='3.4' r='1.5'/%3E%3Cpath d='M7.8 4.9v1.6'/%3E%3C/svg%3E");
  --ic-dock:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 19.5h19'/%3E%3Cpath d='M5.5 19.5V6.5h13v13'/%3E%3Cpath d='M5.5 6.5h13'/%3E%3Cpath d='M8.5 10.5h7M8.5 14h7'/%3E%3C/svg%3E");
  --ic-calendar:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 5.5h17v15h-17z'/%3E%3Cpath d='M3.5 9.5h17'/%3E%3Cpath d='M8 3.5v4M16 3.5v4'/%3E%3C/svg%3E");
  --ic-search:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.85' stroke-linecap='round'%3E%3Ccircle cx='10.6' cy='10.6' r='6.6'/%3E%3Cpath d='M15.4 15.4 20.6 20.6'/%3E%3C/svg%3E");
  --ic-camera:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 7.5h3.6l1.7-2.5h6.4l1.7 2.5h3.6v12h-17z'/%3E%3Ccircle cx='12' cy='13.2' r='3.4'/%3E%3C/svg%3E");
  --ic-delta:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.6 20V4.4'/%3E%3Cpath d='M4.2 7.8 7.6 4.4 11 7.8'/%3E%3Cpath d='M16.4 4v15.6'/%3E%3Cpath d='M12.9 16.2 16.4 19.6 19.8 16.2'/%3E%3C/svg%3E");
}
/* mask 通用底座 */
.ic-mask,
.mode-ic,
.pill__dot,
.t-empty__ic,
.empty__art,
.u-drop__ic,
.big-drop__ic{
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:contain;mask-size:contain;
}

/* -----------------------------------------------------------------------------
   1. reset
----------------------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
html,body{margin:0;padding:0}
body{
  background:radial-gradient(140% 120% at 20% 0%, var(--n-bg-deep2) 0%, var(--n-bg-deep) 58%, var(--n-bg-deep) 100%);
  background-attachment:fixed;
  color:var(--tx-1);
  font-family:var(--font-ui);
  font-size:var(--fs-body);
  line-height:var(--lh-ui);
  font-weight:var(--fw-reg);
  letter-spacing:0;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  min-height:100vh;
  overflow-x:hidden;
  position:relative;
}
/* NEO 深空氛围层: 3 颗漂移辉光斑 (规范 §6.3)。元素在 base.html 的 .n-deep 里。 */
.n-deep{position:fixed; inset:0; z-index:0; pointer-events:none; overflow:hidden}
.n-blob{position:absolute; width:46vw; height:46vw; border-radius:50%;
  filter:blur(90px); opacity:.8; will-change:transform}
.n-blob--a{left:-10vw; top:-16vh;
  background:radial-gradient(circle at 40% 40%, var(--n-glow), transparent 65%);
  animation:nDriftA 52s ease-in-out infinite alternate}
.n-blob--b{right:-14vw; top:24vh;
  background:radial-gradient(circle at 55% 45%, var(--n-glow2), transparent 65%);
  animation:nDriftB 64s ease-in-out infinite alternate}
.n-blob--c{left:26vw; bottom:-24vh; width:38vw; height:38vw;
  background:radial-gradient(circle at 50% 50%, var(--n-glow3), transparent 65%);
  animation:nDriftC 74s ease-in-out infinite alternate}
@keyframes nDriftA{from{transform:translate(0,0) scale(1)}to{transform:translate(9vw,12vh) scale(1.18)}}
@keyframes nDriftB{from{transform:translate(0,0) scale(1.1)}to{transform:translate(-11vw,-9vh) scale(.92)}}
@keyframes nDriftC{from{transform:translate(0,0) scale(1)}to{transform:translate(7vw,-10vh) scale(1.14)}}
img,svg,video{max-width:100%;height:auto;display:block}
/* 图标基线: 同文档 <use href="#i-*"> 用它; icon() 宏另给内联 width/height 覆盖 */
.i{width:var(--icon);height:var(--icon);vertical-align:-.15em;flex:none;
  stroke-width:1.75;fill:none;stroke:currentColor;display:inline-block}
h1,h2,h3,h4{margin:0;font-weight:var(--fw-semi);line-height:var(--lh-tight);letter-spacing:-.01em}
p{margin:0 0 var(--s3)}
ul{margin:0;padding-left:var(--s5)}
hr{border:0;border-top:var(--hair-w) solid var(--line-1);margin:var(--s5) 0}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit;font-family:inherit}
::selection{background:var(--brand);color:var(--brand-fg)}
:focus{outline:none}
:focus-visible{outline:none;box-shadow:var(--ring)}

/* 滚动条: 中性, 不参与状态语义 */
*::-webkit-scrollbar{width:10px;height:10px}
*::-webkit-scrollbar-track{background:transparent}
*::-webkit-scrollbar-thumb{background:var(--line-2);border-radius:var(--r-pill);
  border:3px solid transparent;background-clip:padding-box}
*::-webkit-scrollbar-thumb:hover{background:var(--line-3);background-clip:padding-box}

/* -----------------------------------------------------------------------------
   2. 排版
   规则: 中文 letter-spacing 恒 0; --fs-600 以上收紧 -.01em (大字收紧小字放松);
        全站禁 text-transform:uppercase 出现在可能含中文的元素上 —— 中文没有大小写。
----------------------------------------------------------------------------- */
.h1,h1{font-size:var(--fs-800);line-height:var(--lh-tight);font-weight:var(--fw-semi);
  letter-spacing:-.02em;color:var(--tx-1);margin:0}
.h2,h2{font-size:var(--fs-600);line-height:var(--lh-tight);font-weight:var(--fw-med);
  letter-spacing:-.01em;color:var(--tx-1);margin:0}
/* 科幻渐变标题: 仅用于 hero 与品牌时刻 */
.grad-text{background:var(--gradient-text);-webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent}
.eyebrow{font-size:var(--fs-100);font-weight:var(--fw-med);color:var(--tx-2);
  text-transform:none;letter-spacing:0}
:root[lang="en"] .eyebrow{letter-spacing:.04em}   /* 唯一允许字距: 纯拉丁 eyebrow */
.sechd{font-size:var(--fs-200);font-weight:var(--fw-med);color:var(--tx-2);
  text-transform:none;letter-spacing:0;margin:0 0 var(--s2)}
.muted,.tiny{color:var(--tx-2)}
.tiny{font-size:var(--fs-200)}
.sub{color:var(--tx-2);font-size:var(--fs-300)}
.serif{font-family:var(--font-ui)}     /* --font-serif 已删, 这里同样收敛到 UI 字族 */

/* 数字 / 单号 / SKU / 库位 / 车牌 —— 全站恒定形态 */
.mono,.num,
table,.dual,.kpi__v,.ocard__no,input[type="number"],td,th{
  font-variant-numeric:tabular-nums lining-nums;
}
.mono,.num{font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums}
.txt-brand{color:var(--brand)} .txt-ok{color:var(--ok)}
.txt-bad{color:var(--bad)}     .txt-warn{color:var(--warn)}

/* 双语: 只显示当前语言 (导航/按钮/表头/药丸/chip/KPI 标签)。
   业务实体名的"主行+次行"由页面自己排, 这里只负责显隐。 */
:root[data-lang="zh"] .ru,body[data-lang="zh"] .ru{display:none!important}
:root[data-lang="ru"] .zh,body[data-lang="ru"] .zh{display:none!important}
/* 所有双语容器: 俄文比中文长 60%, 不许靠"刚好放得下" */
.zh,.ru,.ocard__no,.dual__name,.kpi__lb,.pill,.chip,.t-chip{min-width:0;overflow-wrap:anywhere}

.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.hide{display:none!important}
.spacer{flex:1;min-width:0}
.sep{color:var(--tx-3)}

/* -----------------------------------------------------------------------------
   3. 布局
----------------------------------------------------------------------------- */
.page{padding:var(--s5) 0 var(--s8);position:relative;z-index:var(--z-content)}
.wrap{width:min(1180px,100% - 2*var(--s4));margin-inline:auto}
.stack{display:flex;flex-direction:column;gap:var(--card-gap)}
.row{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
.row--between{justify-content:space-between}
.grid-2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(320px,100%),1fr));gap:var(--card-gap)}
.grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(180px,100%),1fr));gap:var(--card-gap)}
.gap2{gap:var(--s2)} .gap3{gap:var(--s3)}
.mt2{margin-top:var(--s2)} .mt3{margin-top:var(--s3)}
.mt4{margin-top:var(--s4)} .mt5{margin-top:var(--s5)}
.dim{opacity:.55}

/* -----------------------------------------------------------------------------
   4. 顶栏 / 品牌 / 导航
----------------------------------------------------------------------------- */
.topbar{
  position:sticky;top:0;z-index:var(--z-topbar);
  display:flex;align-items:center;gap:var(--s3);
  height:var(--topbar-h);
  padding:0 var(--s4);
  padding-left:calc(var(--s4) + env(safe-area-inset-left));
  padding-right:calc(var(--s4) + env(safe-area-inset-right));
  background:var(--glass);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  border-bottom:var(--hair-w) solid var(--line-1);
}
.topbar::after{content:'';position:absolute;left:0;right:0;bottom:0;height:1px;
  background:linear-gradient(90deg,transparent,var(--brand-line),transparent)}

.brand{display:inline-flex;align-items:center;gap:var(--s2);flex:none;min-width:0}
/* 品牌形状全站收敛为一个: --r-2 圆角方 + 1.75px 描边几何 W */
.brand__mark{
  width:26px;height:26px;flex:none;border-radius:var(--r-2);
  border:var(--hair-w) solid var(--brand-line);
  background:var(--brand-bg);
  color:var(--brand);
  -webkit-mask:none;mask:none;
  position:relative;
}
.brand__mark::after{
  content:'';position:absolute;inset:4px;
  background:currentColor;
  -webkit-mask:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 6 7.6 18 12 8.6 16.4 18 20.5 6'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 6 7.6 18 12 8.6 16.4 18 20.5 6'/%3E%3C/svg%3E") center/contain no-repeat;
}
.brand:hover .brand__mark{border-color:var(--brand)}

/* 主题切换按钮: 按当前主题显隐太阳/月亮 */
.theme-ic{display:inline-flex;align-items:center;justify-content:center}
:root[data-theme="night"] .theme-ic--sun{display:none}
:root[data-theme="night"] .theme-ic--moon{display:inline-flex}
:root[data-theme="deck"] .theme-ic--sun{display:inline-flex}
:root[data-theme="deck"] .theme-ic--moon{display:none}
.brand__name{font-size:var(--fs-400);font-weight:var(--fw-semi);color:var(--tx-1);
  letter-spacing:.01em;display:block;line-height:1.15}
/* 9px + .24em 的「入仓履约」-> 11px / 0 字距 / --tx-2 */
.brand__sub{display:block;font-size:var(--fs-100);font-weight:var(--fw-reg);
  color:var(--tx-2);letter-spacing:0;text-transform:none;line-height:1.2}

.nav{display:flex;align-items:center;gap:var(--s1);min-width:0}
.nav a,.mode-btn{
  display:inline-flex;align-items:center;gap:var(--s2);
  height:36px;padding:0 var(--s3);
  border-radius:var(--r-2);
  border:var(--hair-w) solid transparent;
  color:var(--tx-2);font-size:var(--fs-300);font-weight:var(--fw-med);
  white-space:nowrap;
  transition:background-color var(--t-2) var(--e-out),color var(--t-2) var(--e-out),
             border-color var(--t-2) var(--e-out);
}
.nav a:hover,.mode-btn:hover{background:var(--l2);color:var(--tx-1)}
.nav a.is-active,.nav a.is-on,.nav a.on,.mode-btn.on{
  background:var(--l3);color:var(--tx-1);border-color:var(--line-2);
  box-shadow:0 0 20px rgba(255,107,0,.15)}
/* 「传入仓单」是动作不是地方 —— 但它不是 primary。secondary + 图标即可,
   base.html 里那三条 !important 的 nav-cta 会赢, 所以这里把它压回中性。 */
.nav-cta,.nav-cta:hover,.nav-cta.on{
  background:var(--l2)!important;color:var(--tx-1)!important;
  border:var(--hair-w) solid var(--line-2)!important;
  box-shadow:none!important;font-weight:var(--fw-med)!important}
.nav-cta.on{background:var(--l3)!important}

/* emoji 功能图标 -> mask 线性图标。字号归零, 彩色卡通字形彻底消失。 */
.mode-ic{
  display:inline-block;width:17px;height:17px;flex:none;
  font-size:0!important;line-height:0;color:transparent;
  background:currentColor;
  vertical-align:-.15em;
}
.nav a[href="/"] .mode-ic,.nav a[href="/today"] .mode-ic{
  -webkit-mask-image:var(--ic-order);mask-image:var(--ic-order)}
.nav a[href="/stock"] .mode-ic{
  -webkit-mask-image:var(--ic-tag);mask-image:var(--ic-tag)}
.nav a[href="/upload"] .mode-ic{
  -webkit-mask-image:var(--ic-inbound);mask-image:var(--ic-inbound)}
.nav a[href="/calendar"] .mode-ic{
  -webkit-mask-image:var(--ic-calendar);mask-image:var(--ic-calendar)}

/* -----------------------------------------------------------------------------
   5. 底部 tabbar (手机)
   桌面与手机必须是同一个 symbol —— 修掉"库存 tab 画的是人头像"这个错误图标。
----------------------------------------------------------------------------- */
.tabbar{
  position:fixed;left:0;right:0;bottom:0;z-index:var(--z-topbar);
  display:none;
  height:calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  padding-bottom:env(safe-area-inset-bottom);
  background:var(--l1);
  border-top:var(--hair-w) solid var(--line-2);
}
.tabbar a{
  flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  min-height:var(--tap);
  color:var(--tx-2);font-size:var(--fs-100);font-weight:var(--fw-med);
  position:relative;
  transition:color var(--t-2) var(--e-out);
}
.tabbar a.is-active,.tabbar a.is-on,.tabbar a.on{color:var(--brand)}
.tabbar a svg{display:none}                 /* base.html 内联那三个(含错误的人头像) 一律隐藏 */
.tabbar a::before{
  content:'';width:22px;height:22px;background:currentColor;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:contain;mask-size:contain;
}
.tabbar a[href="/"]::before,.tabbar a[href="/today"]::before{
  -webkit-mask-image:var(--ic-order);mask-image:var(--ic-order)}
.tabbar a[href="/upload"]::before{
  -webkit-mask-image:var(--ic-inbound);mask-image:var(--ic-inbound)}
.tabbar a[href="/stock"]::before{
  -webkit-mask-image:var(--ic-tag);mask-image:var(--ic-tag)}

/* -----------------------------------------------------------------------------
   6. 按钮 三级 + destructive
   主按钮每屏至多 1 个。primary 用 --brand-fg (night 黑字 6.62:1 / deck 白字 6.01:1),
   白字压在 #FF6B00 上只有 2.86:1, 作废。
----------------------------------------------------------------------------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  min-height:var(--tap);padding:0 var(--s5);
  border-radius:var(--r-2);
  border:var(--hair-w) solid var(--line-2);
  background:var(--l2);color:var(--tx-1);
  font-size:var(--fs-400);font-weight:var(--fw-med);
  line-height:1;white-space:nowrap;cursor:pointer;
  text-decoration:none;position:relative;
  transition:background-color var(--t-2) var(--e-out),
             border-color var(--t-2) var(--e-out),
             color var(--t-2) var(--e-out),
             filter var(--t-1) var(--e-out),
             box-shadow var(--t-1) var(--e-out),
             transform var(--t-1) var(--e-out);
}
.btn::after,.btn:hover::after{content:none}      /* wms-sheen 流光: 砍 */
.btn:hover{background:var(--l3);border-color:var(--line-2)}
/* 按下用 translateY 不用 scale —— 压缩感比缩放更像实体键 */
.btn:active{transform:translateY(1px);filter:brightness(.94);transition-duration:60ms}
.btn:focus-visible{box-shadow:var(--ring)}
.btn[disabled],.btn.is-disabled{opacity:.42;pointer-events:none}

.btn--primary{
  background:var(--brand);color:var(--brand-fg);
  border-color:var(--brand);
  font-weight:var(--fw-semi);
  box-shadow:0 0 0 rgba(255,107,0,0);
  transition:background-color var(--t-2) var(--e-out),border-color var(--t-2) var(--e-out),
             color var(--t-2) var(--e-out),box-shadow var(--t-2) var(--e-out),
             transform var(--t-1) var(--e-out);
}
.btn--primary:hover{background:var(--brand-2);border-color:var(--brand-2);
  box-shadow:var(--glow-brand);transform:translateY(-1px)}
.btn--ok{background:var(--ok);color:var(--brand-fg);border-color:var(--ok)}
.btn--ghost{background:transparent;border-color:transparent;color:var(--tx-2)}
.btn--ghost:hover{background:var(--l2);color:var(--tx-1);border-color:transparent}
/* destructive: 放车走 / 冲正 / 豁免。四周留白 >=16px, 且必须二次确认(模态)。 */
.btn--danger{
  background:var(--l2);color:var(--bad);border-color:var(--bad-line);
  margin-inline:var(--s4);
}
.btn--danger:hover{background:var(--bad-bg);border-color:var(--bad);color:var(--bad)}
.btn--icon{padding:0;width:var(--tap);min-width:var(--tap)}
.btn--lg{min-height:52px;padding:0 var(--s6);font-size:var(--fs-500)}
.btn--block{display:flex;width:100%}
.topbar .btn{min-height:36px;height:36px;padding:0 var(--s3);font-size:var(--fs-300)}
.topbar .btn--icon{width:36px;min-width:36px;padding:0}
.topbar .btn svg{stroke-width:1.75}

/* -----------------------------------------------------------------------------
   7. 输入
   font-size 恒 16px —— iOS 聚焦缩放的唯一解, 这是全站唯一允许的字面字号。
----------------------------------------------------------------------------- */
.input,.select,.textarea{
  width:100%;
  min-height:var(--tap);
  padding:0 var(--s3);
  border-radius:var(--r-2);
  border:var(--hair-w) solid var(--line-2);
  background:var(--l1);color:var(--tx-1);
  font-size:16px;
  transition:border-color var(--t-2) var(--e-out),background-color var(--t-2) var(--e-out),box-shadow var(--t-1) var(--e-out);
  position:relative;
}
.textarea{padding:var(--s3);min-height:96px;line-height:var(--lh-read);resize:vertical}
.input::placeholder,.textarea::placeholder{color:var(--tx-2)}
.input:hover,.select:hover,.textarea:hover{border-color:var(--line-3)}
.input:focus,.select:focus,.textarea:focus{border-color:var(--focus);box-shadow:var(--ring)}
.input--num{
  font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums;
  text-align:right;width:96px;
}
.input.is-bad{border-color:var(--bad)}
.field{display:flex;flex-direction:column;gap:var(--s1);min-width:0}
.field__lb{font-size:var(--fs-200);color:var(--tx-2);font-weight:var(--fw-reg);
  text-transform:none;letter-spacing:0}

/* 保存成功: 左缘 3px --ok 竖条 scaleY 0->1, 停 900ms 后淡出 (动效表 #5)。
   失败: 边框变色 + 水平 +-3px x2 (动效表 #6)。 */
.input{--fbw:0}
.field,.dual__in{position:relative}
.hit-ok,.is-hit-ok{position:relative}
.hit-ok::before,.is-hit-ok::before{
  content:'';position:absolute;left:0;top:0;bottom:0;width:var(--bar);
  background:var(--ok);border-radius:var(--r-1);
  transform-origin:50% 50%;
  animation:wms-savebar 1420ms var(--e-out) forwards;
  pointer-events:none;z-index:2;
}
@keyframes wms-savebar{
  0%{transform:scaleY(0);opacity:1}
  22%{transform:scaleY(1);opacity:1}
  85%{transform:scaleY(1);opacity:1}
  100%{transform:scaleY(1);opacity:0}
}
.hit-bad,.is-hit-bad{animation:wms-nudge 180ms var(--e-damp) 1}
@keyframes wms-nudge{0%,100%{transform:translateX(0)}25%{transform:translateX(-3px)}
  75%{transform:translateX(3px)}}

/* 开关 */
.switch{display:inline-flex;align-items:center;gap:var(--s2);cursor:pointer;min-height:var(--tap)}
.switch input{position:absolute;opacity:0;width:0;height:0}
.switch__ui{width:40px;height:22px;border-radius:var(--r-pill);background:var(--l4);
  border:var(--hair-w) solid var(--line-2);position:relative;flex:none;
  transition:background-color var(--t-2) var(--e-out),border-color var(--t-2) var(--e-out)}
.switch__ui::after{content:'';position:absolute;top:2px;left:2px;width:16px;height:16px;
  border-radius:var(--r-pill);background:var(--tx-2);
  transition:transform var(--t-2) var(--e-damp),background-color var(--t-2) var(--e-out)}
.switch input:checked + .switch__ui{background:var(--brand-bg);border-color:var(--brand-line)}
.switch input:checked + .switch__ui::after{transform:translateX(18px);background:var(--brand)}
.switch input:focus-visible + .switch__ui{box-shadow:var(--ring)}
/* -----------------------------------------------------------------------------
   8. 卡片
   纯色表面 + 明度分层。删掉 145deg 渐变 / backdrop-filter / 顶端高光线 / 橙色辉光。
   hover 不改阴影 —— 阴影是 z 轴, hover 不改变 z 轴, 只改边框与底色。
   同心圆角规则: 内元素圆角 = 外圆角 - padding, 结果 <=3 取 0
   => 卡 8px + padding 14px, 所以卡内一律直角或 --r-1。
----------------------------------------------------------------------------- */
.card{
  position:relative;
  background:var(--l1);
  border:var(--hair-w) solid var(--line-1);
  border-radius:var(--r-3);
  padding:var(--card-pad);
  box-shadow:var(--sh-2);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  transition:border-color var(--t-2) var(--e-out),box-shadow var(--t-2) var(--e-out),
             transform var(--t-2) var(--e-out);
  overflow:hidden;
}
.card:hover{border-color:var(--line-2);box-shadow:var(--sh-3);transform:translateY(-2px)}
.card--flat{box-shadow:none;background:transparent}
.card--flat:hover{background:var(--l2)}
.card__hd{display:flex;align-items:flex-start;justify-content:space-between;
  gap:var(--s3);min-width:0}
.card__bd{margin-top:var(--s2);min-width:0}
.card__ft{margin-top:var(--s3);padding-top:var(--s3);
  border-top:var(--hair-w) solid var(--line-1);
  display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
/* 左缘状态竖条 = 位置编码。brand=当前作业 / ok=已入库 / idle=待到仓 / bad=有差异 */
.card::before{content:'';position:absolute;inset:0 auto 0 0;width:0;
  border-radius:var(--r-1) 0 0 var(--r-1);background:transparent}
.card.is-live::before,.ocard.is-live::before{width:var(--bar);background:var(--brand)}
.card.is-live::after{content:none}      /* 3.2s 边框流光: 砍。表达改为竖条。 */
.card.is-ok::before{width:var(--bar);background:var(--ok)}
.card.is-bad::before{width:var(--bar);background:var(--bad)}
.card.is-idle::before{width:var(--bar);background:var(--idle)}

/* 工单卡 —— 四带式, 目标卡高 <=132px */
.ocard{padding-left:calc(var(--card-pad) + var(--bar) + 6px)}
.ocard__no{
  font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums;
  font-size:var(--fs-500);font-weight:var(--fw-med);
  letter-spacing:.01em;color:var(--tx-1);
  background:none;-webkit-text-fill-color:currentColor;   /* 三色切段/渐变: 砍 */
  text-shadow:none;
}
.ocard:hover .ocard__no{color:var(--tx-1)}
.ocard__meta{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  margin-top:2px;font-size:var(--fs-200);color:var(--tx-2);min-width:0}
.ocard__meta b{font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-weight:var(--fw-med);color:var(--tx-1)}
.ocard__pills{display:flex;align-items:center;gap:var(--s1) var(--s2);flex-wrap:wrap;
  margin-top:var(--s2)}
.ocard__thumbs{display:flex;gap:var(--s1);flex-wrap:wrap;margin-top:var(--s2)}
/* 详情页单号: 整串同形, 只放大到 --fs-600。三色切段全部收敛。 */
.ono,.ono__p,.ono__d,.ono__s{
  font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums;
  font-size:var(--fs-600);font-weight:var(--fw-med);
  letter-spacing:.01em;color:var(--tx-1)!important;
  background:none!important;-webkit-text-fill-color:var(--tx-1)!important;
}

/* -----------------------------------------------------------------------------
   9. 状态药丸 六态
   冗余三重: 图标形状 / 边框样式 / 文字后缀。抽掉颜色仍全部可辨(灰度截图硬验收)。
   形状即可供性: 只读药丸 = --r-pill; 可点 chip = --r-2 方角。
----------------------------------------------------------------------------- */
.pill{
  display:inline-flex;align-items:center;gap:var(--s1);
  height:var(--pill-h);padding:0 var(--s2);
  border-radius:var(--r-pill);
  border:var(--hair-w) solid var(--idle-line);
  background:var(--idle-bg);color:var(--tx-2);
  font-size:var(--fs-200);font-weight:var(--fw-med);
  line-height:1;white-space:nowrap;position:relative;
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  transition:background-color var(--t-2) var(--e-out),
             border-color var(--t-2) var(--e-out),
             color var(--t-2) var(--e-out),
             box-shadow var(--t-2) var(--e-out);
}
@media (pointer:coarse){ .pill{height:var(--pill-h-touch)} }
.pill:hover{border-color:var(--line-3)}

/* 左侧 16px 图标槽固定宽度 —— 位置编码, 六态图标都落在同一列 */
.pill__dot{
  width:14px;height:14px;flex:none;border-radius:0;
  background:currentColor;
  -webkit-mask-image:var(--ic-clock);mask-image:var(--ic-clock);
  transition:transform 140ms var(--e-detent) 80ms;
}
.pill--idle{background:var(--idle-bg);border-color:var(--idle-line);color:var(--tx-2)}
.pill--idle .pill__dot{-webkit-mask-image:var(--ic-clock);mask-image:var(--ic-clock)}

.pill--info{background:var(--info-bg);border-color:var(--info-line);color:var(--info)}
.pill--info .pill__dot{-webkit-mask-image:var(--ic-clock);mask-image:var(--ic-clock)}

.pill--ok{background:var(--ok-bg);border-color:var(--ok-line);color:var(--ok);
  box-shadow:0 0 16px rgba(0,212,170,.15)}
.pill--ok .pill__dot{-webkit-mask-image:var(--ic-check);mask-image:var(--ic-check);
  animation:none}

.pill--missing{background:var(--bad-bg);border-color:var(--bad-line);color:var(--bad);
  padding-left:calc(var(--s2) + 4px);
  box-shadow:0 0 16px rgba(255,71,87,.15)}
.pill--missing .pill__dot{-webkit-mask-image:var(--ic-alert);mask-image:var(--ic-alert);
  animation:none}
/* 冗余#2: 左缘 2px --bad 竖条 */
.pill--missing::before{content:'';position:absolute;left:0;top:3px;bottom:3px;width:2px;
  background:var(--bad);border-radius:var(--r-pill)}

.pill--expired{background:transparent;border-style:dashed;border-color:var(--idle-line);
  color:var(--tx-3);text-decoration:line-through;text-decoration-thickness:1px;
  padding-left:calc(var(--s2) + 18px)}
.pill--expired::before{content:'';position:absolute;left:var(--s2);top:50%;
  width:14px;height:14px;margin-top:-7px;background:currentColor;
  -webkit-mask:var(--ic-ban) center/contain no-repeat;mask:var(--ic-ban) center/contain no-repeat}

.pill--waived{background:var(--warn-bg);border-color:var(--warn-line);color:var(--warn)}
.pill--waived .pill__dot{-webkit-mask-image:var(--ic-waive);mask-image:var(--ic-waive)}
/* 冗余#3: 文字后缀「· 豁免」—— 图形失效(逆光/色盲/脏屏)时文字接管 */
.pill--waived::after{content:' · 豁免';font-size:inherit;opacity:.75}
:root[data-lang="ru"] .pill--waived::after{content:' · осв.'}

.pill--uploading{background:var(--info-bg);border-color:var(--info-line);color:var(--info)}
.pill__ring{width:14px;height:14px;flex:none;transform:rotate(-90deg)}
.pill__ring circle{fill:none;stroke-width:2.4}
.pill__ring .trk{stroke:currentColor;opacity:.22}
.pill__ring .arc{stroke:currentColor;stroke-linecap:round;
  stroke-dasharray:37.7;stroke-dashoffset:28;
  transition:stroke-dashoffset 100ms linear}    /* 真进度, 跟随字节, 不是"正在忙" */
.pill--uploading.is-determinate .arc{animation:none}
.pill__hint{display:none;position:absolute;left:0;top:calc(100% + 6px);z-index:var(--z-sticky);
  padding:var(--s2) var(--s3);border-radius:var(--r-2);
  background:var(--l3);border:var(--hair-w) solid var(--line-2);
  color:var(--tx-1);font-size:var(--fs-200);font-weight:var(--fw-reg);
  white-space:normal;width:max-content;max-width:260px;box-shadow:var(--sh-2)}
.pill:hover .pill__hint,.pill:focus-visible .pill__hint{display:block}
/* 顶栏用户药丸: 那是身份不是状态, 保持一个中性小圆点 */
.topbar .pill{border-color:var(--line-2);background:var(--l2);color:var(--tx-2)}
.topbar .pill .pill__dot{-webkit-mask:none;mask:none;width:6px;height:6px;
  border-radius:var(--r-pill);background:var(--tx-3)}
.topbar .pill::before,.topbar .pill::after{content:none}
.livedot{width:6px;height:6px;border-radius:var(--r-pill);background:var(--brand);
  display:inline-block;flex:none}
.livedot::before{content:none}            /* 脉冲: 砍 */

/* -----------------------------------------------------------------------------
   10. 履约条 Rail —— 贴卡左缘 --bar 竖条, 6 段, 段间 2px 缝, 零额外高度
   当前段的强调靠"右侧外伸 tick"(形状编码), 不靠常驻脉冲。
----------------------------------------------------------------------------- */
.rail{position:absolute;left:0;top:var(--s2);bottom:var(--s2);width:var(--bar);
  display:flex;flex-direction:column;gap:2px;z-index:1;pointer-events:none}
.rail__seg{flex:1;border-radius:var(--r-1);background:var(--line-1);position:relative;
  transition:background-color var(--t-2) var(--e-out)}
.rail__seg::before{content:none}
.rail__seg.is-done{background:var(--ok)}
.rail__seg.is-active{background:var(--brand)}
.rail__seg.is-todo{background:var(--line-1)}
.rail__seg.is-bad{background:var(--idle);
  background-image:repeating-linear-gradient(180deg,var(--idle) 0 3px,transparent 3px 6px)}
/* 当前段右侧外伸 4px tick */
.rail__seg.is-active::after{content:'';position:absolute;left:100%;top:50%;
  width:4px;height:2px;margin-top:-1px;background:var(--brand);border-radius:var(--r-1)}
.rail__seg::after{content:''}
.rail__seg:hover::after{content:''}
/* 推进时该段自下而上生长一次 —— 一次性, 无常驻脉冲 */
.rail__seg.is-grow{animation:wms-grow var(--t-3) var(--e-damp) 1}
@keyframes wms-grow{from{clip-path:inset(100% 0 0 0)}to{clip-path:inset(0 0 0 0)}}
:root[data-density="hall"] .rail__seg.is-active::after{width:6px}

/* -----------------------------------------------------------------------------
   11. 筛选 chip —— 方角 = 可点。选中态是底部 2px 指示条, 不是满橙填充。
----------------------------------------------------------------------------- */
.chip,.t-chip{
  display:inline-flex;align-items:center;gap:6px;
  min-height:36px;padding:0 var(--s3);
  border-radius:var(--r-2);
  border:var(--hair-w) solid var(--line-2);
  background:var(--l1);color:var(--tx-2);
  font-size:var(--fs-300);font-weight:var(--fw-reg);
  white-space:nowrap;cursor:pointer;position:relative;
  transition:background-color var(--t-2) var(--e-out),color var(--t-2) var(--e-out),
             border-color var(--t-2) var(--e-out);
}
@media (pointer:coarse){ .chip,.t-chip{min-height:44px} }
.chip:hover,.t-chip:hover{background:var(--l2);color:var(--tx-1);border-color:var(--line-3);
  transform:none}
.chip.is-on,.chip.on,.t-chip.on,.t-chip.is-on{
  background:var(--l3);color:var(--tx-1);border-color:var(--line-2)}
.chip.is-on::after,.chip.on::after,.t-chip.on::after,.t-chip.is-on::after{
  content:'';position:absolute;left:var(--s2);right:var(--s2);bottom:-1px;height:2px;
  background:var(--brand);border-radius:var(--r-1)}
.chip b,.t-chip__n{
  font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums;
  font-size:var(--fs-200);font-weight:var(--fw-med);color:var(--tx-2);opacity:1}
/* 全站计数只在此出现一次: 差异 chip 的数字 >0 时染 --bad */
.chip.is-diff b,.t-chip[data-diff]:not([data-diff="0"]) .t-chip__n{color:var(--bad)}

/* -----------------------------------------------------------------------------
   12. KPI
   使用前提: 数字本身是决策依据才用 KPI。「1 单」不值得。
   值为 0 一律 --tx-3 —— 零是好消息, 应该退场。
----------------------------------------------------------------------------- */
.kpi{
  background:var(--l2);border-radius:var(--r-3);padding:var(--s3);
  border:var(--hair-w) solid var(--line-1);box-shadow:var(--sh-1);position:relative;min-width:0;
}
.kpi::before,.kpi::after{content:none}     /* --sh-brand 光标柔光/辉光: 砍 */
.kpi:hover{background:var(--l2);box-shadow:none;transform:none}
.kpi__lb{font-size:var(--fs-100);color:var(--tx-2);font-weight:var(--fw-reg);
  text-transform:none;letter-spacing:0;margin:0 0 var(--s1)}
.kpi__v{
  display:flex;align-items:baseline;gap:var(--s1);
  font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums;
  font-size:var(--fs-700);line-height:var(--lh-num);font-weight:var(--fw-semi);
  letter-spacing:-.01em;
  color:var(--tx-1);
  background:none;-webkit-text-fill-color:currentColor;
}
.kpi__u{font-size:var(--fs-100);color:var(--tx-2);font-weight:var(--fw-reg);
  font-family:var(--font-ui);-webkit-text-fill-color:var(--tx-2)}
/* 只有越阈值才染色, 并在左侧加 3px 色条 */
.kpi--bad{padding-left:calc(var(--s3) + var(--bar) + 4px)}
.kpi--bad::before{content:'';position:absolute;left:0;top:var(--s2);bottom:var(--s2);
  width:var(--bar);background:var(--bad);border-radius:var(--r-1)}
.kpi--bad .kpi__v{color:var(--bad)}
.kpi--warn .kpi__v{color:var(--warn)}
.kpi--ok .kpi__v,.kpi--brand .kpi__v,.kpi--info .kpi__v{color:var(--tx-1)}
.kpi[data-zero] .kpi__v,.kpi--zero .kpi__v{color:var(--tx-3)}
/* 一行摘要条 —— KPI 卡阵的替代物 */
.cbar{display:flex;align-items:baseline;gap:var(--s3);flex-wrap:wrap;
  padding:var(--s2) 0;margin:0 0 var(--s3);
  font-size:var(--fs-300);color:var(--tx-2);
  border-bottom:var(--hair-w) solid var(--line-1)}
.cbar b{font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums;color:var(--tx-1);font-weight:var(--fw-semi)}
.cbar .is-bad b{color:var(--bad)}
.cbar .is-zero b{color:var(--tx-3)}

/* -----------------------------------------------------------------------------
   13. 表格
   th 无 uppercase 无字距(中文没有大小写, 那是死代码), min-height 非 height(允许俄文两行)。
   .tablewrap 的 max-width 是"数量列距品质列 420px 视线跨度"的解。
----------------------------------------------------------------------------- */
.tablewrap{
  border:var(--hair-w) solid var(--line-1);
  border-radius:var(--r-3);
  overflow-x:auto;
  background:var(--l1);
  box-shadow:var(--sh-1);
}
table.tbl{width:100%;border-collapse:collapse;font-size:var(--fs-table)}
table.tbl th{
  position:sticky;top:var(--topbar-h);z-index:var(--z-sticky);
  background:var(--l2);
  text-align:left;
  padding:var(--s2) var(--s3);
  min-height:var(--row-h);
  font-size:var(--fs-200);font-weight:var(--fw-semi);color:var(--tx-1);
  text-transform:none;letter-spacing:0;
  border-bottom:var(--hair-w) solid var(--line-2);
  white-space:nowrap;
}
table.tbl td{
  padding:var(--s2) var(--s3);
  height:var(--row-h);
  border-bottom:var(--hair-w) solid var(--line-1);
  color:var(--tx-1);vertical-align:middle;
}
@media (pointer:coarse){ table.tbl td{height:var(--row-h-touch)} }
table.tbl .r{text-align:right;
  font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums}
table.tbl tbody tr{transition:background-color var(--t-2) var(--e-out)}
table.tbl tbody tr:hover{background:var(--l2)}
table.tbl tr:last-child td{border-bottom:0}
table.tbl tbody tr.is-bad{position:relative}
table.tbl tbody tr.is-bad td:first-child{box-shadow:inset 2px 0 0 var(--bad)}
:root[data-theme="deck"] table.tbl tbody tr:hover{background:var(--l2)}

/* -----------------------------------------------------------------------------
   14. 双列对照 —— 中缝一根 1px 竖线贯通整表, 那是"对照"的视觉本体。
   放弃左右各铺浅底: 弱对比底色在 deck 强光下会消失。
----------------------------------------------------------------------------- */
.dual{border:var(--hair-w) solid var(--line-1);border-radius:var(--r-3);
  background:var(--l1);overflow:hidden;box-shadow:var(--sh-1)}
.dual__hd{display:grid;grid-template-columns:1.6fr 1px 1fr;align-items:center;
  background:var(--l2);border-bottom:var(--hair-w) solid var(--line-2)}
.dual__hd > div{padding:var(--s2) var(--s3);
  font-size:var(--fs-200);font-weight:var(--fw-semi);color:var(--tx-1);
  text-transform:none;letter-spacing:0}
.dual__hd > div + div{border-left:0}
.dual__hd::after{content:''}
.dual__row{
  display:grid;grid-template-columns:1.6fr 1px 1fr;align-items:center;
  min-height:var(--row-h);
  border-bottom:var(--hair-w) solid var(--line-1);
  position:relative;
  transition:background-color var(--t-2) var(--e-out);
}
@media (pointer:coarse){ .dual__row{min-height:var(--row-h-touch)} }
.dual__row:last-child{border-bottom:0}
.dual__row:hover{background:var(--l2)}
/* 中缝竖线: 用 grid 的 1px 轨道做, 贯通整表 */
.dual__hd::before,.dual__row::before{
  content:'';grid-column:2;justify-self:stretch;align-self:stretch;
  background:var(--line-3);width:1px;position:static;inset:auto;height:auto}
/* ⚠ 列位必须【显式】指定 —— 中缝 ::before 占了 col2 后, 两个 .dual__side 若靠
   自动排布会被挤反(申报跑右列、实收占宽左列), 违反"左申报右实收"铁律。
   业务规则: col1(宽,1.6fr)=客户申报只读, col3(窄,1fr)=我方实收可编辑。 */
.dual__hd > div:first-child,.dual__row > .dual__side:first-child{grid-column:1}
.dual__hd > div:last-child, .dual__row > .dual__side:last-child{grid-column:3}
.dual__side{padding:var(--s2) var(--s3);min-width:0;display:flex;align-items:center;
  gap:var(--s2);flex-wrap:wrap;background:transparent}
.dual__side::before{content:none}
.dual__side + .dual__side{border-left:0;background:transparent}
:root[data-theme="deck"] .dual__side + .dual__side{background:transparent}
.dual__k{font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-size:var(--fs-200);color:var(--tx-2);flex:none}
.dual__name{font-size:var(--fs-table);color:var(--tx-1);min-width:0;
  overflow-wrap:anywhere}
.dual__v{font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums;
  font-size:var(--fs-table);font-weight:var(--fw-med);color:var(--tx-1)}
.dual__in{display:flex;align-items:center;gap:var(--s2);min-width:0}
.dual__in .input{width:96px;min-width:72px}
.dual__diff{display:inline-flex;align-items:center;gap:var(--s1);
  font-size:var(--fs-200);color:var(--tx-3);white-space:nowrap}
.dual__row.is-diff,.dual__row.is-diff-more{background:transparent}
.dual__row.is-diff::before,.dual__row.is-diff-more::before{background:var(--line-3)}
/* 差异行: 左缘 2px --bad + 判定列图标 */
.dual__row.is-diff,.dual__row.is-diff-more{box-shadow:inset 2px 0 0 var(--bad)}
.dual__row.is-diff .dual__v--got,.dual__row.is-diff-more .dual__v--got{color:var(--bad)}
.dual__row.is-diff .dual__diff,.dual__row.is-diff-more .dual__diff{color:var(--bad)}
.dual__row.is-diff .dual__diff::before,.dual__row.is-diff-more .dual__diff::before{
  content:'';width:13px;height:13px;flex:none;background:currentColor;
  -webkit-mask:var(--ic-delta) center/contain no-repeat;
  mask:var(--ic-delta) center/contain no-repeat}
/* 判定标签滑入 (动效表 #9) */
.dual__diff.is-in{animation:wms-slidein var(--t-2) var(--e-damp) 1}
@keyframes wms-slidein{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.dual__row:hover::before{background:var(--line-3)}
:root[data-theme="deck"] .dual__row:hover{background:var(--l2)}

/* -----------------------------------------------------------------------------
   15. 车在场横幅 —— 全站唯一循环动画就在这里(左缘竖条呼吸 .55<->1, 3s)
   现场回退条款: 若真机验证员工"看不见车来了", 改为 background:#B34C00 满底 + 黑字
   + 保留竖条呼吸。【不得】恢复原状(满橙 + 白字 + 9s 流动 + 卡车晃动)。
----------------------------------------------------------------------------- */
.truckbar{
  position:relative;
  display:flex;align-items:center;gap:var(--s2);
  min-height:48px;padding:0 var(--s4) 0 calc(var(--s4) + var(--bar));
  padding-left:calc(var(--s4) + var(--bar) + env(safe-area-inset-left));
  background:var(--brand);
  border-bottom:var(--hair-w) solid var(--brand-line);
  color:var(--brand-fg);font-size:var(--fs-300);
  box-shadow:var(--glow-brand);
  animation:none;
}
.truckbar::before{
  content:'';position:absolute;left:0;top:0;bottom:0;width:var(--bar);
  background:var(--brand-fg);
  animation:wms-breathe 3s var(--e-damp) infinite;
}
@keyframes wms-breathe{0%,100%{opacity:1}50%{opacity:.55}}
:root[data-theme="night"] .truckbar{
  background:var(--l2);border-bottom-color:var(--line-2);color:var(--tx-1);
  box-shadow:0 0 30px rgba(255,107,0,.20)}
:root[data-theme="night"] .truckbar::before{background:var(--brand)}
/* 卡车 emoji / 三角播放符 -> 线性卡车图标 */
.truckbar .truck,.truckbar > span:first-child{
  display:inline-block;width:18px;height:18px;flex:none;
  font-size:0!important;color:transparent;background:currentColor;
  -webkit-mask:var(--ic-truck) center/contain no-repeat;
  mask:var(--ic-truck) center/contain no-repeat;
  animation:none;
}
.truckbar .num{font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-variant-numeric:tabular-nums lining-nums;
  padding:2px var(--s2);border-radius:var(--r-2);
  background:rgba(255,255,255,.18);border:var(--hair-w) solid rgba(255,255,255,.28);
  font-size:var(--fs-200);color:var(--brand-fg)}
:root[data-theme="night"] .truckbar .num{
  background:var(--l3);border-color:var(--line-2);color:var(--tx-1)}
.truckbar .btn{min-height:36px;padding:0 var(--s4);
  background:var(--brand-fg);color:var(--brand);border-color:var(--brand-fg);
  font-weight:var(--fw-semi)}
.truckbar .btn:hover{filter:brightness(1.06);background:var(--brand-fg)}
:root[data-theme="night"] .truckbar .btn{
  background:var(--brand);color:var(--brand-fg);border-color:var(--brand)}
.livebar{}

/* 指令带 —— 软色带:  tinted 底 + 左缘色条 + 圆角 */
.warnstrip,.infostrip,.errstrip{
  position:relative;
  display:flex;align-items:flex-start;gap:var(--s2);
  padding:var(--s2) var(--s3) var(--s2) calc(var(--s3) + var(--bar) + 6px);
  border-radius:var(--r-2);
  background:var(--warn-bg);border:var(--hair-w) solid var(--warn-line);
  color:var(--tx-1);font-size:var(--fs-400);line-height:var(--lh-ui);
  animation:none;
}
.warnstrip::before,.infostrip::before,.errstrip::before{
  content:'';position:absolute;left:0;top:50%;height:12px;width:var(--bar);
  margin-top:-6px;border-radius:var(--r-1);background:var(--warn);animation:none}
.infostrip{background:var(--info-bg);border-color:var(--info-line)}
.infostrip::before{background:var(--info)}
.errstrip{background:var(--bad-bg);border-color:var(--bad-line)}
.errstrip::before{background:var(--bad)}
.errstrip{color:var(--bad)}
.warnstrip::after{content:none}

/* -----------------------------------------------------------------------------
   16. 抽屉 / 模态 / 遮罩
----------------------------------------------------------------------------- */
.scrim{position:fixed;inset:0;z-index:calc(var(--z-drawer) - 1);
  background:var(--scrim);opacity:0;pointer-events:none;
  transition:opacity var(--t-2) var(--e-damp)}
.scrim.is-open{opacity:1;pointer-events:auto}
.drawer{
  position:fixed;z-index:var(--z-drawer);
  background:var(--l1);box-shadow:var(--sh-3);
  border:var(--hair-w) solid var(--line-2);
  top:0;right:0;bottom:0;width:min(420px,92vw);
  border-radius:var(--r-4) 0 0 var(--r-4);
  transform:translateX(100%);
  transition:transform var(--t-3) var(--e-damp);
  display:flex;flex-direction:column;
}
.drawer.is-open{transform:none}
.drawer__hd{padding:var(--s4);border-bottom:var(--hair-w) solid var(--line-1);
  display:flex;align-items:center;gap:var(--s2)}
.drawer__bd{padding:var(--s4);overflow:auto;flex:1;min-height:0}
.drawer__ft{padding:var(--s4);border-top:var(--hair-w) solid var(--line-1);
  display:flex;gap:var(--s2);justify-content:flex-end}
.modal{position:fixed;inset:0;z-index:var(--z-modal);display:grid;place-items:center;
  padding:var(--s4);background:var(--scrim);
  opacity:0;pointer-events:none;transition:opacity var(--t-2) var(--e-damp)}
.modal.is-open{opacity:1;pointer-events:auto}
.modal__box{
  width:min(440px,100%);
  background:var(--l1);border:var(--hair-w) solid var(--line-2);
  border-radius:var(--r-4);box-shadow:var(--sh-3);
  padding:var(--s5);
  opacity:0;transform:scale(.98);
  transition:opacity var(--t-3) var(--e-damp),transform var(--t-3) var(--e-damp);
}
.modal.is-open .modal__box{opacity:1;transform:none}

/* -----------------------------------------------------------------------------
   17. toast
----------------------------------------------------------------------------- */
.toast-host{position:fixed;right:var(--s4);bottom:var(--s4);z-index:var(--z-toast);
  display:flex;flex-direction:column;gap:var(--s2);pointer-events:none}
.toast{
  display:flex;align-items:center;gap:var(--s2);
  min-height:44px;padding:var(--s2) var(--s4);
  border-radius:var(--r-3);
  background:var(--l2);border:var(--hair-w) solid var(--line-2);
  box-shadow:var(--sh-2);color:var(--tx-1);font-size:var(--fs-300);
  pointer-events:auto;max-width:min(420px,86vw);
  animation:wms-toast-in var(--t-2) var(--e-out) 1;
}
.toast::before{content:'';width:16px;height:16px;flex:none;background:var(--tx-2);
  -webkit-mask:var(--ic-clock) center/contain no-repeat;
  mask:var(--ic-clock) center/contain no-repeat}
.toast--ok::before{background:var(--ok);
  -webkit-mask-image:var(--ic-check);mask-image:var(--ic-check)}
.toast--bad::before{background:var(--bad);
  -webkit-mask-image:var(--ic-alert);mask-image:var(--ic-alert)}
.toast--warn::before{background:var(--warn);
  -webkit-mask-image:var(--ic-alert);mask-image:var(--ic-alert)}
.toast.is-out{animation:wms-toast-out var(--t-2) var(--e-out) forwards}
@keyframes wms-toast-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@keyframes wms-toast-out{to{opacity:0;transform:translateY(8px)}}

/* -----------------------------------------------------------------------------
   18. 骨架
   保留现状最专业的一条: 2s 未返回即停微光 —— 弱网下永远闪 = 让人以为卡死。
   骨架微光不计入"全站循环动画 <=1"配额(它是加载指示, 属真实进度类)。
----------------------------------------------------------------------------- */
.sk{background:var(--skel);background-size:200% 100%;border-radius:var(--r-1);
  height:14px;animation:wms-shimmer 1.4s linear infinite}
.sk + .sk{margin-top:var(--s2)}
.sk--row{height:var(--row-h)}
.sk--card{height:116px;border-radius:var(--r-3)}
.sk--w80{width:80%} .sk--w60{width:60%}
.sk::after{content:none}
.sk.is-stalled,.is-stalled .sk{animation:none;background:var(--l2)}
.sk.is-stalled::after,.is-stalled .sk::after{content:none}
:root[data-theme="deck"] .sk::after{content:none}
@keyframes wms-shimmer{from{background-position:200% 0}to{background-position:-200% 0}}

/* -----------------------------------------------------------------------------
   19. 缩略图 / 相机槽
   虚线保留(语义 = 此处应有而尚无); 无图时用中性底 + 相机图标,
   绝不用彩色占位 —— 品红/肉色纯色块在逆光下无法辨认拍了什么。
----------------------------------------------------------------------------- */
.thumb{
  position:relative;display:block;flex:none;
  width:64px;height:64px;border-radius:var(--r-2);
  border:var(--hair-w) solid var(--line-2);
  background:var(--l3);overflow:hidden;
  transition:border-color var(--t-2) var(--e-out);
}
.thumb:hover{border-color:var(--line-3);box-shadow:none;transform:none}
.thumb img{width:100%;height:100%;object-fit:cover;display:block;
  animation:wms-fade var(--t-3) var(--e-out) 1}
.thumb:hover img{transform:none}
.thumb:not(:has(img))::before{
  content:'';position:absolute;inset:0;margin:auto;width:22px;height:22px;
  background:var(--tx-3);
  -webkit-mask:var(--ic-camera) center/contain no-repeat;
  mask:var(--ic-camera) center/contain no-repeat}
.thumb__tag{position:absolute;left:0;right:0;bottom:0;
  padding:2px 4px;background:var(--scrim);color:#fff;
  font-size:var(--fs-100);text-align:center;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.thumb--add{
  border-style:dashed;background:transparent;color:var(--tx-3);
  display:grid;place-items:center;font-size:var(--fs-600);cursor:pointer;
  min-width:var(--tap);min-height:var(--tap)}
.thumb--add:hover{border-color:var(--brand-line);color:var(--brand);background:var(--l2)}
@keyframes wms-fade{from{opacity:0}to{opacity:1}}
/* -----------------------------------------------------------------------------
   20. 空态 —— 32px 图标 + 文字。不用 56px 飘着的 emoji 篮子。
----------------------------------------------------------------------------- */
.empty,.t-empty{
  display:grid;place-items:center;gap:var(--s3);text-align:center;
  padding:var(--s8) var(--s4);
  background:var(--l1);border:var(--hair-w) solid var(--line-2);border-radius:var(--r-3);
  box-shadow:none;
}
.empty::before,.empty::after,.t-empty::before,.t-empty::after{content:none}
.empty__art,.t-empty__ic{
  width:32px;height:32px;font-size:0!important;color:transparent;
  background:var(--tx-3);filter:none;animation:none;
  -webkit-mask-image:var(--ic-dock);mask-image:var(--ic-dock)}
.empty__l1{font-size:var(--fs-500);font-weight:var(--fw-med);color:var(--tx-1)}
.empty__l2,.empty__l3{font-size:var(--fs-300);color:var(--tx-2);max-width:44ch}
.nf{display:grid;place-items:center;gap:var(--s3);text-align:center;padding:var(--s8) var(--s4)}
.nf__code{font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-size:var(--fs-700);color:var(--tx-3);font-weight:var(--fw-semi)}
.nf__msg{font-size:var(--fs-400);color:var(--tx-2)}

/* -----------------------------------------------------------------------------
   21. 拖放区
   可供性由「虚线 + dragover 时虚线转实线」承担, 不由辉光承担。
   bob 4px 保留 —— 它有可供性功能(告诉你这块能接住东西), 且只在 dragover 时播。
----------------------------------------------------------------------------- */
.big-drop{
  display:grid;place-items:center;gap:var(--s2);
  min-height:200px;padding:var(--s6) var(--s4);
  border:var(--hair-w) dashed var(--line-2);border-radius:var(--r-3);
  background:var(--l1);box-shadow:none;text-align:center;cursor:pointer;
  transition:border-color var(--t-2) var(--e-out),background-color var(--t-2) var(--e-out);
}
.big-drop::after{content:none}
.big-drop:hover{border-color:var(--line-3);background:var(--l2);transform:none;box-shadow:none}
.big-drop.is-over,.big-drop.drag{
  border-style:solid;border-color:var(--brand);background:var(--l2);transform:none}
.big-drop.is-over::after,.big-drop.drag::after{content:none}
.big-drop__ic,.big-drop-ic{
  width:32px;height:32px;font-size:0!important;color:transparent;
  background:var(--tx-2);filter:none;animation:none;
  -webkit-mask-image:var(--ic-inbound);mask-image:var(--ic-inbound)}
.big-drop.is-over .big-drop__ic,.big-drop.drag .big-drop-ic{
  background:var(--brand);animation:wms-bob 900ms var(--e-out) infinite alternate}
@keyframes wms-bob{from{transform:translateY(0)}to{transform:translateY(-4px)}}
.big-drop:hover .big-drop__ic,.big-drop:hover .big-drop-ic{background:var(--tx-1)}
.big-drop.is-busy .big-drop__ic,.big-drop.busy .big-drop-ic{background:var(--brand)}
.big-drop.is-busy,.big-drop.busy{border-color:var(--brand-line);pointer-events:none}
.big-drop.is-ok,.big-drop.ok{border-style:solid;border-color:var(--ok-line)}
.big-drop__title,.big-drop-title{font-size:var(--fs-500);font-weight:var(--fw-med);
  color:var(--tx-1);background:none;-webkit-text-fill-color:currentColor;animation:none}
.big-drop__sub,.big-drop-sub,.big-drop__label,.big-drop-label{
  font-size:var(--fs-300);color:var(--tx-2)}
.big-drop__hint,.big-drop-hint{font-size:var(--fs-200);color:var(--tx-3)}
.big-drop__hint code,.big-drop-hint code{font-family:var(--font-num);
  padding:2px 6px;border-radius:var(--r-1);background:var(--l3);color:var(--tx-2)}
/* 真进度条(跟随字节, linear), 不是旋转环 */
.big-drop__bar{height:var(--bar);width:100%;background:var(--l3);border-radius:var(--r-1);overflow:hidden}
.big-drop__bar i{display:block;height:100%;width:0;background:var(--brand);
  transition:width 100ms linear}

/* -----------------------------------------------------------------------------
   22. 遗产 class —— 名字全部保留可用, 视觉表达一律降级为"什么都不做"
   这些是页面模板里已经写死的 class。删掉它们会让 10 个页面报错;
   保留空壳既不炸也不会把旧视觉带回来。
----------------------------------------------------------------------------- */
/* 进场: 仅首次会话播一次, 由 fx.js 用 sessionStorage 把关 */
html.wms-fx .reveal:not(.in){opacity:0}
html.wms-fx .reveal.in{opacity:1;animation:wms-in var(--t-2) var(--e-out) both}
.reveal{opacity:1}
.reveal-d1{animation-delay:28ms} .reveal-d2{animation-delay:56ms} .reveal-d3{animation-delay:84ms}
.stagger > *{animation:wms-in var(--t-2) var(--e-out) both}
.stagger > *:nth-child(1){animation-delay:0ms}
.stagger > *:nth-child(2){animation-delay:28ms}
.stagger > *:nth-child(3){animation-delay:56ms}
.stagger > *:nth-child(4){animation-delay:84ms}
.stagger > *:nth-child(5){animation-delay:112ms}
.stagger > *:nth-child(n+6){animation-delay:112ms}   /* 上限 5 张, 第 6 张起不再累加 */
@keyframes wms-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
/* 里程碑落章 (动效表 #12): 线由中点向两端展开 + 章咬合落下 + 描线, 无粒子 */
.stamp{position:relative;display:inline-flex;align-items:center;gap:var(--s2);
  padding:var(--s1) var(--s3);border-radius:var(--r-2);
  border:var(--hair-w) solid var(--ok-line);background:var(--ok-bg);color:var(--ok);
  font-size:var(--fs-300);font-weight:var(--fw-semi)}
.stamp.is-in{animation:wms-stamp 260ms var(--e-detent) 180ms both}
@keyframes wms-stamp{from{opacity:0;transform:scale(1.18) rotate(-3deg)}
  to{opacity:1;transform:none}}
.mile-rule{height:1px;background:var(--line-2);transform:scaleX(0);
  transition:transform var(--t-3) var(--e-out)}
.mile-rule.is-in{transform:scaleX(1)}
/* 冲正回滚 (动效表 #13): 数字 reverse count 由 JS 做, 这里只管删除线与降级 */
.is-reversed{color:var(--tx-3)!important;position:relative}
.is-reversed::after{content:'';position:absolute;left:0;right:0;top:50%;height:1px;
  background:var(--idle);transform-origin:left;
  animation:wms-strike 240ms var(--e-damp) both}
@keyframes wms-strike{from{transform:scaleX(0)}to{transform:scaleX(1)}}
/* 错误定位引导 (动效表 #14): 竖条常驻至修正 */
.is-locate{box-shadow:inset var(--bar) 0 0 var(--bad)}
/* count-up 期间的轻标记, 无位移 */
.num--tick{transition:color var(--t-2) var(--e-out)}
.num--tick.is-up{color:var(--tx-1)}
/* 筛选切换淡出 (动效表 #15): 高度不做动画 */
.is-swapping{opacity:.4;transition:opacity 100ms var(--e-out)}

/* 旧关键帧名保留 —— 页面模板里可能还在 animation: 里点名它们。全部置空。 */
@keyframes wms-spin{to{transform:rotate(360deg)}}

/* =============================================================================
   23. 页面级覆写
   ---------------------------------------------------------------------------
   为什么要有这一段:
   10 个页面模板各自带 <style>, 且写在 app.css 之后 —— 同权重时页面赢。
   本次任务只允许改 tokens.css / app.css / fx.js, 所以这里用 :root:root 前缀
   把权重抬到 (0,3,0), 把页面里那些"幼稚感来源"就地压掉:
     渐变大标题 / emoji 巨图 / clamp 巨字号 / 玻璃渐变 / 橙色辉光 / 循环装饰动画。
   页面模板逐页迁完之后, 本段可整体删除。
============================================================================= */

/* ---- 通用: 把页面里的 uppercase + 字距(中文上的死代码) 一律关掉 ---- */
:root:root .sechd,:root:root .calhead span,:root:root .ltag,
:root:root .dual__hd > div,:root:root table.tbl th,
:root:root .kpi__lb,:root:root .t-kpi__lb,:root:root .u-sum__lb,
:root:root .brand__sub,:root:root .t-brow,:root:root .u-brow{
  text-transform:none;letter-spacing:0}
:root:root .sechd{font-size:var(--fs-200);color:var(--tx-2);font-weight:var(--fw-med)}

/* ---- today.html ---- */
:root:root .t-brow{display:none}
:root:root .t-hero{align-items:center;padding:0 0 var(--s3);gap:var(--s3)}
:root:root .t-h1{
  font-family:var(--font-ui);font-size:var(--fs-600);font-weight:var(--fw-semi);
  letter-spacing:-.01em;line-height:var(--lh-tight);margin:0;gap:var(--s2)}
:root:root .t-h1 .ic{
  width:20px;height:20px;font-size:0;color:transparent;
  background:var(--tx-2);filter:none;animation:none;
  -webkit-mask:var(--ic-order) center/contain no-repeat;
  mask:var(--ic-order) center/contain no-repeat}
:root:root .t-h1 .t{
  background:none;-webkit-text-fill-color:var(--tx-1);color:var(--tx-1)}
:root:root .t-date{font-size:var(--fs-200);color:var(--tx-2)}
:root:root .t-date .mono{color:var(--tx-1);font-weight:var(--fw-med)}
:root:root .t-sum{display:none}
:root:root .t-kpis{display:none}
:root:root .t-chips{margin-bottom:var(--s3)}
:root:root .unit{border-radius:var(--r-3);box-shadow:none;transition:none}
:root:root .unit:hover{transform:none;box-shadow:none}
:root:root .unit > .card{
  background:var(--l1);border-radius:var(--r-3) var(--r-3) 0 0;box-shadow:none}
:root:root .unit__ft{
  background:var(--l1);border-radius:0 0 var(--r-3) var(--r-3);
  padding:var(--s3) var(--card-pad) var(--s3) calc(var(--card-pad) + var(--bar) + 6px);
  gap:var(--s4)}
:root:root .unit:hover > .card,:root:root .unit:hover > .unit__ft{border-color:var(--line-3)}
:root:root .unit__flag{display:none}
:root:root .t-empty{padding:var(--s8) var(--s4);box-shadow:none;background:var(--l1)}
:root:root .t-empty h2{font-family:var(--font-ui);font-size:var(--fs-500);
  font-weight:var(--fw-med)}
:root:root .t-empty p{font-size:var(--fs-300)}

/* ---- upload.html ---- */
:root:root .u-brow{display:none}
:root:root .u-hero{align-items:flex-start;text-align:left;gap:var(--s2);padding:0 0 var(--s3)}
:root:root .u-h1{
  font-family:var(--font-ui);font-size:var(--fs-600);font-weight:var(--fw-semi);
  letter-spacing:-.01em;justify-content:flex-start;gap:var(--s2)}
:root:root .u-h1 .ic{
  width:20px;height:20px;font-size:0;color:transparent;
  background:var(--tx-2);filter:none;animation:none;
  -webkit-mask:var(--ic-inbound) center/contain no-repeat;
  mask:var(--ic-inbound) center/contain no-repeat}
:root:root .u-h1 .t{background:none;
  -webkit-text-fill-color:var(--tx-1);color:var(--tx-1)}
:root:root .u-sub{font-size:var(--fs-300);text-align:left;max-width:64ch}
:root:root .u-drop{
  min-height:200px;
  border:var(--hair-w) dashed var(--line-2);border-radius:var(--r-3);
  background:var(--l1);box-shadow:none;
  transition:border-color var(--t-2) var(--e-out),background-color var(--t-2) var(--e-out)}
:root:root .u-drop::before,:root:root .u-drop::after{content:none}
:root:root .u-drop:hover,:root:root .u-drop:focus-visible{
  border-color:var(--line-3);background:var(--l2);transform:none;box-shadow:none}
:root:root .u-drop.is-over{
  border-style:solid;border-color:var(--brand);background:var(--l2);
  transform:none;box-shadow:none}
:root:root .u-drop__full{padding:var(--s6) var(--s4);gap:var(--s2)}
:root:root .u-drop__ic{
  width:32px;height:32px;font-size:0;color:transparent;
  background:var(--tx-2);filter:none;
  -webkit-mask:var(--ic-inbound) center/contain no-repeat;
  mask:var(--ic-inbound) center/contain no-repeat}
:root:root .u-drop.is-busy .u-drop__ic{animation:none;background:var(--brand)}
:root:root .u-drop__t{font-family:var(--font-ui);font-size:var(--fs-500);
  font-weight:var(--fw-med);background:none;
  -webkit-text-fill-color:var(--tx-1);color:var(--tx-1)}
:root:root .u-drop__s{font-size:var(--fs-300)}
:root:root .u-drop__s b{font-weight:var(--fw-med)}
:root:root .u-tpl{font-size:var(--fs-200);border-radius:var(--r-2)}
:root:root .u-slim__ic{
  width:20px;height:20px;font-size:0;color:transparent;background:var(--tx-2);
  -webkit-mask:var(--ic-order) center/contain no-repeat;
  mask:var(--ic-order) center/contain no-repeat}
:root:root .u-prop{background:var(--l1);border-radius:var(--r-3);box-shadow:none;
  min-height:0;padding:var(--s3) var(--s4)}
:root:root .u-prop::before{content:none}
:root:root .u-prop:hover{transform:none;box-shadow:none;border-color:var(--line-3)}
:root:root .u-prop .e{
  width:20px;height:20px;font-size:0;color:transparent;background:var(--tx-2);
  -webkit-mask:var(--ic-check) center/contain no-repeat;
  mask:var(--ic-check) center/contain no-repeat}
:root:root .u-prop b{font-size:var(--fs-400);font-weight:var(--fw-med);letter-spacing:0}
:root:root .u-prop span.d{font-size:var(--fs-200)}
:root:root .u-sums{background:var(--l1);border-radius:var(--r-3);box-shadow:none;
  padding:var(--s3) var(--s4)}
:root:root .u-sums::before{content:none}
:root:root .u-sum__v{font-size:var(--fs-700);font-weight:var(--fw-semi);
  background:none;-webkit-text-fill-color:var(--tx-1);color:var(--tx-1)}
:root:root .u-sum--bad .u-sum__v{-webkit-text-fill-color:var(--bad);color:var(--bad)}
:root:root .u-sum__lb{font-size:var(--fs-100);color:var(--tx-2);font-weight:var(--fw-reg)}
:root:root .u-chips code{border-radius:var(--r-1);font-size:var(--fs-100)}
:root:root .urow__qty,:root:root .urow__model{color:var(--tx-1)}
:root:root .urow__eta,:root:root .urow__src{font-size:var(--fs-200);color:var(--tx-2)}

/* ---- order.html ---- */
:root:root .shot{border-radius:var(--r-2);font-size:var(--fs-200);
  font-weight:var(--fw-reg);background:var(--l3);color:var(--tx-2)}
:root:root .shot svg{stroke-width:1.75}
:root:root .shot.is-ok{background:var(--ok-bg);border-color:var(--ok-line);color:var(--ok)}
:root:root .hold{border-radius:var(--r-2);font-weight:var(--fw-med);font-size:var(--fs-300)}
:root:root .kv{font-size:var(--fs-300)}

/* ---- count.html ---- */
:root:root .ltag{font-size:var(--fs-100);font-weight:var(--fw-med);border-radius:var(--r-1)}
:root:root .searchbar svg{stroke-width:1.75}
:root:root .cbar{display:flex;gap:var(--s4);align-items:center;flex-wrap:wrap}
:root:root .cbar .btn{flex:1 1 210px;min-height:52px}
:root:root .planrow,:root:root .blocked{border-radius:var(--r-2);font-size:var(--fs-300);
  font-weight:var(--fw-reg)}
:root:root .planrow .q,:root:root .ledrow .d{font-size:var(--fs-500);font-weight:var(--fw-med)}

/* ---- stock.html ---- */
:root:root .qty{color:var(--tx-1);font-weight:var(--fw-med);font-size:var(--fs-table)}
:root:root .qnote{font-size:var(--fs-100);color:var(--warn);font-weight:var(--fw-med)}
:root:root .ledrow{border-radius:var(--r-2)}
:root:root .ledrow a{font-weight:var(--fw-med)}
:root:root .tip{border-radius:var(--r-2);font-size:var(--fs-200);box-shadow:var(--sh-2)}

/* ---- calendar.html ---- */
:root:root .calday{min-height:68px;border-radius:var(--r-2);background:var(--l1);
  transition:border-color var(--t-2) var(--e-out)}
:root:root .calday:hover{transform:none;border-color:var(--line-3)}
:root:root .calday.is-today{background:var(--l1);border-color:var(--line-2)}
:root:root .calday.is-today .calday__d{
  border:1px solid var(--tx-1);border-radius:var(--r-1);padding:1px 4px;color:var(--tx-1)}
:root:root .calday__d{font-size:var(--fs-300);font-weight:var(--fw-med);color:var(--tx-2)}
:root:root .calday__n{font-size:var(--fs-100);font-weight:var(--fw-reg)}
:root:root .calday__n b{font-size:var(--fs-300);font-weight:var(--fw-med)}
:root:root .calday__bar{height:var(--bar)}
:root:root .calday__dot{
  left:8px;right:auto;top:6px;width:12px;height:12px;border-radius:0;
  background:var(--bad);box-shadow:none;
  -webkit-mask:var(--ic-alert) center/contain no-repeat;
  mask:var(--ic-alert) center/contain no-repeat}
:root:root .callegend{font-size:var(--fs-200)}
:root:root .callegend i{height:var(--bar);border-radius:var(--r-1)}
:root:root .dayrow{border-radius:var(--r-2)}
:root:root .dayrow__no{font-family:var(--font-num);font-feature-settings:var(--ff-num);
  font-size:var(--fs-500);font-weight:var(--fw-med)}
:root:root .calhead span{font-size:var(--fs-100);color:var(--tx-2)}

/* ---- login.html ---- */
:root:root .auth__brand{border-radius:var(--r-3);min-height:0;padding:var(--s7) var(--s6);
  background:var(--l1);border-color:var(--line-2)}
:root:root .auth__brand::before{content:none}
:root:root .auth__logo{font-family:var(--font-ui);font-size:var(--fs-800);
  font-weight:var(--fw-semi);letter-spacing:-.02em;line-height:var(--lh-num);color:var(--tx-1)}
:root:root .auth__rule{width:48px;height:2px;background:var(--brand);border-radius:var(--r-1)}
:root:root .auth__tag{font-size:var(--fs-300)}
:root:root .auth__card{border-radius:var(--r-3);padding:var(--s6);gap:var(--s4)}
:root:root .auth__err{border-radius:var(--r-2);font-size:var(--fs-300);font-weight:var(--fw-reg)}
:root:root .auth__foot{font-size:var(--fs-200)}

/* -----------------------------------------------------------------------------
   24. 响应式
   硬指标: 390px 与 1440px 都不许横向滚动; <=760px 触区 >=48px。
----------------------------------------------------------------------------- */
@media (max-width:760px){
  .topbar .nav{display:none}
  .tabbar{display:flex}
  /* 修 tabbar 遮挡: 现状 tabbar 压在卡片中段 */
  .page,main.page,main{padding-bottom:calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 12px)}
  .wrap{width:calc(100% - 2*var(--s3))}
  .btn,.chip,.t-chip,.input,.select,.thumb--add{min-height:var(--tap)}
  /* 顶栏控件(主题/语言/用户)也是拇指目标 —— 触区硬底 48px 同样适用 */
  .topbar{height:auto;min-height:var(--topbar-h);padding-block:2px}
  .topbar .btn{min-height:48px;height:48px}
  .topbar .btn--icon{width:48px;min-width:48px}
  .truckbar .btn{min-height:48px}      /* 「去点货」是现场主操作, 触区硬底 */
  .toast-host{left:var(--s3);right:var(--s3);bottom:auto;top:calc(var(--topbar-h) + var(--s2))}
  .toast{max-width:none}
  .drawer{top:auto;left:0;right:0;bottom:0;width:auto;max-height:86vh;
    border-radius:var(--r-4) var(--r-4) 0 0;transform:translateY(100%)}
  .drawer.is-open{transform:none}
  /* 双列: 拆两行, 总高 <=108px (现状 ~200px) */
  .dual__hd{display:none}
  .dual__row{grid-template-columns:1fr;row-gap:var(--s1);padding:var(--s2) 0;min-height:0}
  .dual__hd::before,.dual__row::before{display:none}
  .dual__side{padding:0 var(--s3);width:100%}
  .dual__side:first-child{font-size:var(--fs-200);color:var(--tx-2)}
  .dual__side:last-child{gap:var(--s2)}
  .dual__side[data-side]::after{content:attr(data-side);font-size:var(--fs-100);
    color:var(--tx-3);text-transform:none;letter-spacing:0}
  .dual__in .input{flex:1 1 0;min-width:0;width:auto;min-height:var(--tap)}
  table.tbl th{position:static}
  .grid-2,.grid-4{grid-template-columns:1fr}
}
@media (max-width:390px){
  .wrap{width:calc(100% - 2*var(--s2))}
  .btn{padding:0 var(--s4)}
}
/* 触屏一律进 field 密度档 —— 老板要的密度只能从桌面拿, 不许从手机身上拿 */
@media (pointer:coarse){
  :root{--card-pad:16px;--card-gap:10px;
    --fs-body:var(--fs-500);--fs-table:var(--fs-400);--bar:4px}
}

/* -----------------------------------------------------------------------------
   25. prefers-reduced-motion —— 完整降级
   原则: 「降幅不消失」。位移类动画全部撤掉, 语义色变与真进度环必须保留。
----------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:.001ms!important;
    scroll-behavior:auto!important;
  }
  .pill,.rail__seg,.chip,.t-chip,.card,.kpi__v,.num--tick,
  table.tbl tbody tr,.dual__row,.input,.btn{
    transition-property:background-color,border-color,color!important;
    transition-duration:var(--t-2)!important;
  }
  .pill__ring .arc,.big-drop__bar i{transition-duration:100ms!important}
  html.wms-fx .reveal,html.wms-fx .reveal.in,.stagger > *{
    opacity:1!important;transform:none!important;animation:none!important}
  .truckbar::before{animation:none!important;opacity:1!important}
  .sk{animation:none!important;background:var(--l2)}
  .hit-ok::before,.is-hit-ok::before{animation:none!important;opacity:1}
  .hit-bad,.is-hit-bad{animation:none!important}
  .big-drop.is-over .big-drop__ic{animation:none!important}
  .stamp.is-in{animation:none!important;opacity:1;transform:none}
  .mile-rule{transform:scaleX(1)!important}
}
/* =============================================================================
   NEO 液态玻璃签名层 (雷霆规则 docs/NEO_UI_规范.md)
   —— 追加在末尾, 覆盖上面的历史表达, 把关键表面换成 NEO 玻璃/玻璃/弹簧语汇。
   颜色全走 --n-* / 别名令牌, 零写死色。
============================================================================= */

/* ---- 玻璃三件套基材: 半透底 + 上缘高光 + 下缘暗边 (铁律3) ---- */
.card,.ocard,.unit,.sh-kpis,.rack,.loose,.moves,.pw__card,.dual,.tablewrap,
.t-kpis,.drawer,.modal__box,.n-glass{
  background:var(--n-glass-bg)!important;
  -webkit-backdrop-filter:blur(var(--blur-strong)) saturate(1.6);
  backdrop-filter:blur(var(--blur-strong)) saturate(1.6);
  border:1px solid var(--n-edge);
  border-top-color:var(--n-spec);
  border-bottom-color:rgba(0,0,0,.22);
}
:root[data-theme="deck"] .card,:root[data-theme="deck"] .ocard,
:root[data-theme="deck"] .unit,:root[data-theme="deck"] .rack,
:root[data-theme="deck"] .loose,:root[data-theme="deck"] .drawer{border-bottom-color:var(--n-edge)}
[data-backdrop="unsupported"] .card,[data-backdrop="unsupported"] .ocard,
[data-backdrop="unsupported"] .drawer,[data-backdrop="unsupported"] .modal__box{
  background:var(--n-glass-strong)!important}

/* ---- 顶栏 = 灵动岛玻璃条 ---- */
.topbar{
  background:var(--n-glass-bg);
  -webkit-backdrop-filter:blur(var(--blur-strong)) saturate(1.6);
  backdrop-filter:blur(var(--blur-strong)) saturate(1.6);
  border-bottom:1px solid var(--n-edge);
  box-shadow:inset 0 1px 0 var(--n-spec);
}

/* ---- 导航项: 液滴选中态 (铁律4/5.3, 描环不加宽边) ---- */
.nav a,.mode-btn{
  border-radius:var(--r-xs);
  transition:transform var(--t-3) var(--n-spring),color var(--t) var(--e-out),
    background-color var(--t) var(--e-out),box-shadow var(--t-3) var(--e-out);
}
.nav a:active,.mode-btn:active{transform:scale(.96)}
.nav a.is-active,.nav a.is-on,.nav a.on,.mode-btn.on{
  background:linear-gradient(135deg,var(--n-accent-soft),transparent 85%)!important;
  border-color:var(--n-accent-line)!important;color:var(--n-text)!important;
  box-shadow:inset 0 1px 0 var(--n-spec),0 4px 16px var(--n-glow)!important;
}
.nav-cta.on{
  background:linear-gradient(135deg,var(--n-accent),var(--n-accent2))!important;
  color:var(--n-accent-ink)!important;box-shadow:0 8px 22px var(--n-glow)!important}

/* ---- 主行动: 全站唯一写法 = 双色渐变 + 反色墨字 + 800 + glow (铁律5) ---- */
.btn{transition:transform var(--t-3) var(--n-spring),background-color var(--t) var(--e-out),
  color var(--t) var(--e-out),border-color var(--t) var(--e-out),box-shadow var(--t-3) var(--e-out)}
.btn:active{transform:scale(.96);filter:none}
.btn--primary,.btn--ok,.nav-cta.on{
  background:linear-gradient(135deg,var(--n-accent),var(--n-accent2))!important;
  color:var(--n-accent-ink)!important;border-color:transparent!important;
  font-weight:var(--fw-bold)!important;
  box-shadow:0 10px 26px var(--n-glow)!important}
.btn--primary:hover,.btn--ok:hover{filter:brightness(1.07);
  box-shadow:0 12px 30px var(--n-glow)!important;transform:none}
.btn--primary:active{transform:scale(.96)}
/* 危险按钮: NEO 无危险按钮类, 降级成幽灵 + 危险色描边 (§5.14) */
.btn--danger{background:transparent!important;color:var(--n-danger)!important;
  border-color:color-mix(in srgb,var(--n-danger) 50%,transparent)!important}
.btn--danger:hover{box-shadow:0 0 18px color-mix(in srgb,var(--n-danger) 35%,transparent)!important}

/* ---- 输入聚焦: accent 光环 (§5.4) ---- */
.input,.select,input[type=text],input[type=password],input[type=number],
input[type=search],textarea,select{
  border-radius:var(--r-2);
  transition:border-color var(--t) var(--e-out),box-shadow var(--t-3) var(--e-out),
    background-color var(--t) var(--e-out)}
.input:focus,.select:focus,input:focus,textarea:focus,select:focus{
  outline:none;border-color:var(--n-accent-line)!important;
  box-shadow:0 0 0 3px var(--n-accent-soft),0 6px 22px var(--n-glow)!important}

/* ---- 选中态一律描环, 不加宽边 (铁律4) ---- */
.sku-opt.on,.bin-chip.on,.t-chip.on,.t-chip.is-on,.chip.on,.chip.is-on{
  background:linear-gradient(135deg,var(--n-accent-soft),transparent 85%)!important;
  border-color:var(--n-accent-line)!important;
  box-shadow:inset 0 1px 0 var(--n-spec),0 4px 14px var(--n-glow)!important}
.t-chip.on::after,.t-chip.is-on::after,.chip.on::after,.chip.is-on::after{display:none!important}

/* ---- 卡片 hover: 浮起 + 描环 + glow (§5.6) ---- */
.ocard.glow:hover,.unit.glow:hover,.sku-opt:hover{
  transform:translateY(-3px);border-color:var(--n-accent-line);
  box-shadow:var(--n-shadow),0 0 26px -4px var(--n-glow)}

/* ---- 状态药丸: 玻璃胶囊, 圆点自发光 (§5.10) ---- */
.pill{border-radius:var(--r-pill);background:var(--n-surface-3);
  border:1px solid var(--n-line-2);transition:all var(--t) var(--e-out)}
.pill--ok{color:var(--n-ok);border-color:color-mix(in srgb,var(--n-ok) 40%,transparent);
  background:color-mix(in srgb,var(--n-ok) 12%,transparent)}
.pill--bad,.pill--missing{color:var(--n-danger);
  border-color:color-mix(in srgb,var(--n-danger) 40%,transparent);
  background:color-mix(in srgb,var(--n-danger) 12%,transparent)}
.pill--warn{color:var(--n-warn);border-color:color-mix(in srgb,var(--n-warn) 40%,transparent);
  background:color-mix(in srgb,var(--n-warn) 12%,transparent)}
.pill--info{color:var(--n-accent2);border-color:color-mix(in srgb,var(--n-accent2) 40%,transparent);
  background:color-mix(in srgb,var(--n-accent2) 12%,transparent)}
.pill__dot{box-shadow:0 0 8px currentColor}

/* ---- 抽屉/浮层: 玻璃 + 弹簧入场 (§7.4, 无遮罩) ---- */
.drawer{box-shadow:var(--n-shadow)}
.drawer.in{animation:nSlideIn var(--t-4) var(--n-spring)}
@keyframes nSlideIn{from{transform:translateX(18px);opacity:0}to{transform:none;opacity:1}}
.scrim{background:var(--scrim);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}

/* ---- toast: 玻璃胶囊底部居中 (§5.11) ---- */
.toast,.wms-toast{background:var(--n-glass-bg);
  -webkit-backdrop-filter:blur(var(--blur-strong)) saturate(1.6);
  backdrop-filter:blur(var(--blur-strong)) saturate(1.6);
  border:1px solid var(--n-edge);border-top-color:var(--n-spec);
  border-radius:var(--r-pill);box-shadow:var(--n-shadow)}

/* ---- 大标题字重 800 (§3.3), 去掉旧渐变文字(铁律: 靠字重不靠渐变) ---- */
.h1,.h2,h1,h2{font-weight:var(--fw-bold);letter-spacing:.02em}
.h1{-webkit-text-fill-color:currentColor;background:none}

/* ---- 主题按钮增加换肤色环提示 ---- */
.tabbar{background:var(--n-glass-bg);
  -webkit-backdrop-filter:blur(var(--blur-strong)) saturate(1.6);
  backdrop-filter:blur(var(--blur-strong)) saturate(1.6);
  border-top:1px solid var(--n-edge)}

/* ============================================================================
   扫码入库 —— 手机扫码页(scan.html) + 电脑联动扫码卡(order.html .scancard)。
   放这里(基座样式表)而非模板 <style>: 模板只用令牌不许写死色(铁律R5), 而相机取景框
   必须真黑、二维码/标签必须真白(功能色), 这类色归基座。动效关键帧同理归这里(铁律R7)。
============================================================================ */
.scanwrap{max-width:640px;margin:0 auto;display:flex;flex-direction:column;gap:var(--s4)}
.scanbar{display:flex;align-items:center;justify-content:space-between;gap:var(--s3)}
.scanbar .who{font-family:var(--font-num);color:var(--tx-2);overflow-wrap:anywhere}
#cam{position:relative;width:100%;aspect-ratio:4/3;border-radius:var(--r-3);
     overflow:hidden;background:#000;box-shadow:var(--n-shadow,0 8px 40px rgba(0,0,0,.5))}
#cam video,#cam canvas{position:absolute;inset:0;width:100%!important;height:100%!important;
     object-fit:cover}
#cam .reticle{position:absolute;left:8%;right:8%;top:38%;height:24%;
     border:2px solid rgba(255,255,255,.85);border-radius:var(--r-2);
     box-shadow:0 0 0 100vmax rgba(0,0,0,.28);pointer-events:none}
#cam .laser{position:absolute;left:8%;right:8%;top:50%;height:2px;
     background:linear-gradient(90deg,transparent,var(--n-accent),transparent);
     animation:scanline 1.8s ease-in-out infinite}
@keyframes scanline{0%,100%{transform:translateY(-42px)}50%{transform:translateY(42px)}}
@media (prefers-reduced-motion:reduce){#cam .laser{animation:none}}
.scanwrap .toast{min-height:var(--tap);display:flex;align-items:center;gap:var(--s3);
     padding:var(--s3) var(--s4);border-radius:var(--r-2);font-weight:var(--fw-med);
     background:var(--l1);border:var(--hair-w) solid var(--line);
     transition:background var(--t-2),border-color var(--t-2)}
.scanwrap .toast.ok{background:var(--ok-bg);border-color:var(--ok-line);color:var(--ok)}
.scanwrap .toast.bad{background:var(--bad-bg);border-color:var(--bad-line);color:var(--bad)}
.scanwrap .toast .big{font-family:var(--font-num);font-size:var(--fs-500);font-weight:var(--fw-bold)}
.scanwrap .lst{display:flex;flex-direction:column;gap:var(--s2)}
.scanwrap .lrow{display:grid;grid-template-columns:1fr auto auto;gap:var(--s3);align-items:center;
     padding:var(--s3);border-radius:var(--r-2);background:var(--l1);
     border:var(--hair-w) solid var(--line)}
.scanwrap .lrow.done{border-color:var(--ok-line)}
.scanwrap .lrow.over{border-color:var(--warn-line)}
.scanwrap .lrow .sku{font-family:var(--font-num);font-weight:var(--fw-med);overflow-wrap:anywhere}
.scanwrap .lrow .nm{color:var(--tx-3);font-size:var(--fs-200)}
.scanwrap .lrow .cnt{font-family:var(--font-num);font-size:var(--fs-400);white-space:nowrap}
.scanwrap .lrow .cnt b{font-size:var(--fs-500)}
.scanwrap .lrow .cnt .ov{color:var(--warn)}
.scanwrap .lrow .cnt .dn{color:var(--ok)}
.scanwrap .manual{display:flex;gap:var(--s2)}
.scanwrap .manual .input{flex:1}
.scanwrap .totbar{display:flex;justify-content:space-between;align-items:center;
     font-family:var(--font-num);color:var(--tx-2)}
/* 电脑联动扫码卡 */
.scancard .sc-grid{display:flex;gap:var(--s4);align-items:center;flex-wrap:wrap}
.scancard .sc-qr{width:128px;height:128px;flex:none;background:#fff;
     border-radius:var(--r-2);padding:8px;box-shadow:var(--n-shadow-sm,0 2px 8px rgba(0,0,0,.3))}
.scancard .sc-qr svg{width:100%;height:100%;display:block}
.scancard .sc-body{flex:1;min-width:190px;display:flex;flex-direction:column;gap:var(--s3)}
.scancard .sc-cnt{font-family:var(--font-num);font-size:var(--fs-500);color:var(--tx-2)}
.scancard .sc-cnt b{font-size:var(--fs-700);color:var(--tx-1);transition:color var(--t-2)}
.scancard .sc-cnt.live b{color:var(--ok)}

/* ============================================================================
   条码标签打印页(labels.html)。标签必须真黑条真白底才扫得动 —— 功能色, 归基座。
============================================================================ */
.lbl-tools{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap;margin-bottom:var(--s4)}
.lbl-tools .muted{color:var(--tx-3)}
.sheet{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--s3)}
.label{background:#fff;color:#000;border:1px solid #cfcfcf;border-radius:8px;
       padding:10px 12px 8px;display:flex;flex-direction:column;gap:4px;
       break-inside:avoid;page-break-inside:avoid}
.label .nm{font-size:12px;color:#333;line-height:1.25;min-height:1.25em;
           overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.label .bc{display:flex;justify-content:center;align-items:center;height:60px}
.label .bc svg{max-width:100%;height:100%}
.label .sku{font:600 15px/1.1 var(--font-num);letter-spacing:.5px;
            text-align:center;word-break:break-all}
@media print{
  @page{ margin:8mm; }
  body{background:#fff!important}
  .topbar,.n-blob,.n-deep,.truckbar,.lbl-tools,nav,.tabbar{display:none!important}
  main,.wrap,.page{padding:0!important;margin:0!important;max-width:none!important}
  .sheet{gap:6px}
  .label{border:1px solid #999}
}

/* ============================================================================
   条码生成器 (barcodes.html)。条码必须黑白才扫得动/印得出 —— 功能色, 归基座。
============================================================================ */
.bcstudio{display:flex;flex-direction:column;gap:var(--s4)}
.bc-tools{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3)}
@media (max-width:640px){ .bc-tools{grid-template-columns:1fr} }
.bc-field{position:relative;display:flex;align-items:center}
.bc-field .i{position:absolute;left:var(--s3);color:var(--tx-3);pointer-events:none}
.bc-field .input{padding-left:calc(var(--s6) + var(--s1));width:100%;min-height:var(--tap)}
.bc-custom-out{display:flex;align-items:center;gap:var(--s4);flex-wrap:wrap;
  background:#fff;color:#000;border-radius:var(--r-2);padding:var(--s3) var(--s4)}
.bc-custom-out .bc-bc{display:flex;align-items:center;flex:1;min-width:260px;justify-content:center}
.bc-custom-out .bc-bc svg{height:120px;width:auto;max-width:min(88vw,560px)}
.bc-custom-out .bc-sku{font-family:var(--font-num);font-weight:600;color:#000;word-break:break-all}
.bc-bar{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap}
.bc-allbox{display:flex;align-items:center;gap:var(--s2);cursor:pointer;color:var(--tx-2)}
.bc-allbox input,.bc-card .bc-chk{accent-color:var(--n-accent)}
.bc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:var(--s3)}
.bc-card{position:relative;display:flex;flex-direction:column;gap:4px;cursor:pointer;
  background:#fff;color:#000;border:2px solid transparent;border-radius:var(--r-2);
  padding:10px 12px 8px;transition:border-color var(--t-2),transform var(--t-2)}
.bc-card:hover{transform:translateY(-1px)}
.bc-card.sel{border-color:var(--n-accent)}
.bc-card .bc-chk{position:absolute;top:8px;right:8px;width:18px;height:18px}
.bc-card .bc-bc{display:flex;justify-content:center;align-items:center;height:54px}
.bc-card .bc-bc svg{max-width:100%;height:100%}
.bc-card .bc-sku{font-family:var(--font-num);font-weight:600;font-size:14px;
  word-break:break-all;color:#000}
.bc-card .bc-nm{font-size:12px;color:#333;line-height:1.2;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bc-none{color:var(--tx-3);padding:var(--s6);text-align:center}
/* 自定义条码单张打印: 只留那一张 */
@media print{
  body.printing-custom .topbar,body.printing-custom .n-deep,body.printing-custom .tabbar,
  body.printing-custom .bc-tools,body.printing-custom .bc-bar,body.printing-custom .bc-grid,
  body.printing-custom .bc-none{display:none!important}
  body.printing-custom main,body.printing-custom .wrap,body.printing-custom .page{
    padding:0!important;margin:0!important;max-width:none!important}
  body.printing-custom .bc-custom-out{background:#fff}
}

/* ============================================================================
   扫码页 v2 (2026-07-22): 相机优先全屏专注 + 原生 BarcodeDetector 反馈。
   起因: quagga2 真机扫不出 -> 换原生解码; 顺带把手机版做成相机占大头的专注模式。
============================================================================ */
body.scan-page .topbar,
body.scan-page .tabbar,
body.scan-page .truckbar,
body.scan-page .n-deep{ display:none !important; }
body.scan-page main.page{ padding:0; }
body.scan-page .wrap{ max-width:none; padding:var(--s3); }
.scanwrap{ max-width:560px; }
.scanbar{ gap:var(--s2); }
.scanbar .sb-back,.scanbar .sb-new{ flex:none; white-space:nowrap; }
.scanbar .who{ flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  text-align:center;font-family:var(--font-num);font-size:var(--fs-300);color:var(--tx-2); }
/* 相机: 手机上占更大一块 */
#cam{ aspect-ratio:auto; height:min(54vh,68vw); min-height:260px; }
#cam-video{ position:absolute;inset:0;width:100%;height:100%;object-fit:cover;background:#000; }
.cam-btn{ position:absolute;right:12px;bottom:12px;width:46px;height:46px;border-radius:50%;
  border:none;background:rgba(0,0,0,.45);color:#fff;font-size:20px;z-index:3;cursor:pointer;
  display:flex;align-items:center;justify-content:center; }
.cam-btn.on{ background:var(--n-accent); }
/* 扫中/扫错的取景框反馈 (不动那圈暗色遮罩的 box-shadow, 只改边框色 + 抖动) */
#reticle{ transition:border-color .15s; }
#reticle.hit{ border-color:var(--ok,#5fd67a) !important; }
#reticle.miss{ border-color:var(--bad,#ff6b60) !important; animation:retShake .35s ease; }
@keyframes retShake{ 0%,100%{transform:translateX(0)} 25%{transform:translateX(-5px)} 75%{transform:translateX(5px)} }
