/* ===========================================================
 * 进销存管理系统 · 样式表（纯 CSS，无依赖）
 * =========================================================== */
:root {
  --primary: #2563eb;
  --primary-d: #1d4ed8;
  --success: #16a34a;
  --danger: #dc2626;
  --warning: #f59e0b;
  --purple: #7c3aed;
  --text: #1e293b;
  --text-2: #64748b;
  --border: #e2e8f0;
  --bg: #f1f5f9;
  --card: #ffffff;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* 手机顶栏高度：iOS 刘海机要加上状态栏高度，否则顶栏被系统状态栏压住。
   env() 不被支持时 --tb-pt 保持 0px，calc 依然有效（不会整条声明失效）。 */
:root { --tb-h: 52px; --tb-pt: 0px; }
@supports (padding: env(safe-area-inset-top)) {
  :root { --tb-pt: env(safe-area-inset-top); }
}

/* ---------- 页面固定大小：禁止双指张开放大 ----------
   1) manipulation 禁掉双击缩放（保留单指滚动与点击）
   2) iOS 上输入框字号 <16px 会在聚焦时自动放大页面，
      这里关掉自动调整，配合「输入框不小于 16px」双保险 */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
/* 禁双击缩放只在手机版布局下生效。
   手机切「电脑版 / 桌面版网站」时视口变宽（约 980px），
   那时应该恢复双指缩放。这个类由 JS 的 syncZoomLock 增减。 */
html:not(.zoom-unlocked) { touch-action: manipulation; }

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", "PingFang SC", sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  line-height: 1.6;
}

/* ---------- 布局 ---------- */
/* align-items:flex-start 很关键：默认的 stretch 会让侧栏被拉到与主区等高，
   那样 sticky 没有可滑动空间，底部的账号按钮又会被推到很远的下方 */
.layout { display: flex; min-height: 100vh; align-items: flex-start; }

.sidebar {
  width: 210px;
  background: #0f172a;
  color: #cbd5e1;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  /* 固定在视口高度并吸顶：右侧内容再长，账号与改密码/退出也始终可见 */
  height: 100vh;
  position: sticky;
  top: 0;
}
.logo {
  padding: 18px 18px 14px;
  font-size: 17px;
  font-weight: 700;
  color: #fff;
  border-bottom: 1px solid rgba(255,255,255,.08);
  flex-shrink: 0;
}
.logo small { display: block; font-size: 10px; font-weight: 400; color: #64748b; letter-spacing: .5px; margin-top: 2px; }

/* min-height:0 —— flex 子项默认 min-height:auto，不置 0 就不会收缩、滚不起来 */
.nav { flex: 1 1 auto; min-height: 0; padding: 10px 0; overflow-y: auto; }
/* 隐藏滚动条但仍可滚动：深色侧栏里那条浅色滑块很显眼。
   注意不能改成 hidden/visible，否则就滚不动了 */
.nav { scrollbar-width: none; -ms-overflow-style: none; }
.nav::-webkit-scrollbar { width: 0; height: 0; display: none; }
/* 滚动条藏了，顶部加一道淡淡的渐变提示「上面还有内容」。
   background-attachment: local 是关键：滚到顶时它自动消失，
   向下滚动才出现，不用 JS 也不用动画（动画会影响整个菜单） */
.nav {
  background-image: linear-gradient(rgba(148, 163, 184, .16), rgba(148, 163, 184, 0));
  background-repeat: no-repeat;
  background-size: 100% 16px;
  background-position: 0 0;
  background-attachment: local;
}
.nav:hover {
  background-image: linear-gradient(rgba(148, 163, 184, .26), rgba(148, 163, 184, 0));
}
.nav-group {
  padding: 12px 18px 4px;
  font-size: 11px;
  color: #64748b;
  letter-spacing: 1px;
}
.nav a {
  display: block;
  padding: 8px 18px;
  color: #cbd5e1;
  text-decoration: none;
  font-size: 13px;
  cursor: pointer;
  border-left: 3px solid transparent;
}
.nav a:hover { background: rgba(255,255,255,.06); color: #fff; }
.nav a.on {
  background: rgba(37,99,235,.18);
  color: #fff;
  border-left-color: var(--primary);
  font-weight: 600;
}

.sidebar-foot {
  padding: 12px 14px calc(14px + env(safe-area-inset-bottom));
  border-top: 1px solid rgba(255,255,255,.08);
  flex-shrink: 0;               /* 菜单再长也不压缩底部 */
  background: #0f172a;
}
/* 云端同步状态徽标（由 js/cloud.js 动态插入）
   本地模式显示「本地」，让人一眼知道数据存在哪 */
.cloud-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  color: #94a3b8;
  margin-bottom: 8px;
  cursor: default;
}
.cloud-badge::before {
  content: '';
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.cloud-badge.local { color: #94a3b8; }
.cloud-badge.ok { color: #4ade80; }
.cloud-badge.err { color: #f87171; }
.cloud-badge.sync { color: #fbbf24; }
/* 同步中：小圆点呼吸，让人知道在动而不是卡住了 */
.cloud-badge.sync::before { animation: cloudPulse 1s ease-in-out infinite; }
@keyframes cloudPulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

.who { color: #cbd5e1; font-size: 12px; margin-bottom: 8px; line-height: 1.7; }
.who .role {
  display: inline-block;
  background: rgba(37,99,235,.35);
  color: #fff;
  padding: 1px 7px;
  border-radius: 10px;
  font-size: 11px;
  margin-left: 4px;
}
.foot-btns { display: flex; gap: 6px; }
.foot-btns .btn {
  flex: 1;
  justify-content: center;
  background: rgba(255,255,255,.06);
  border-color: rgba(255,255,255,.12);
  color: #cbd5e1;
}
.foot-btns .btn:hover { background: rgba(255,255,255,.14); color: #fff; border-color: rgba(255,255,255,.2); }

.main { flex: 1; padding: 22px 26px; overflow-x: hidden; }

/* ---------- 页头 ---------- */
.page-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: 16px;
  gap: 12px;
  flex-wrap: wrap;
}
.page-head h1 { font-size: 21px; font-weight: 700; }
.page-head .sub { color: var(--text-2); font-size: 12px; margin-top: 2px; }

/* ---------- 卡片 ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px 18px;
  margin-bottom: 16px;
}
.card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  gap: 10px;
  flex-wrap: wrap;
}
.card-head h2 { font-size: 15px; font-weight: 600; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 1100px) { .two-col { grid-template-columns: 1fr; } }
/* grid/flex 子项默认 min-width:auto，会被内部的宽表格撑开：
   卡片被撑到超出屏幕，而 .main 有 overflow-x:hidden 会把溢出部分直接裁掉，
   结果就是「表格滚不动、右边永远看不到」。设成 0 才能让滚动发生在容器内 */
.two-col > *, .kpi-grid > *, .donut-wrap > *, .detail-grid > * { min-width: 0; }
/* 兜底：任何 grid / flex 的子项都不被内容撑开，滚动交给内层容器 */
#app .two-col > .card, #app .card { min-width: 0; max-width: 100%; }
.tbl-wrap { max-width: 100%; }

/* ---------- KPI ---------- */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}
.kpi {
  background: var(--card);
  border: 1px solid var(--border);
  border-left: 4px solid var(--primary);
  border-radius: 8px;
  padding: 14px 16px;
}
.kpi.b-blue { border-left-color: var(--primary); }
.kpi.b-green { border-left-color: var(--success); }
.kpi.b-orange { border-left-color: var(--warning); }
.kpi.b-purple { border-left-color: var(--purple); }
.kpi.b-red { border-left-color: var(--danger); }
.kpi-l { font-size: 12px; color: var(--text-2); }
.kpi-v { font-size: 22px; font-weight: 700; margin: 2px 0; }
.kpi-s { font-size: 11px; color: var(--text-2); }

/* ---------- 表格 ---------- */
.tbl-wrap { overflow-x: auto; }

/* 表格可横滑的提示：默认不显示，窄屏才出现 */
.swipe-tip { display: none; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
thead th {
  text-align: left;
  padding: 9px 10px;
  background: #f8fafc;
  border-bottom: 1px solid var(--border);
  color: var(--text-2);
  font-weight: 600;
  font-size: 12px;
  white-space: nowrap;
}
tbody td { padding: 9px 10px; border-bottom: 1px solid #f1f5f9; vertical-align: middle; }
tbody tr:hover { background: #f8fafc; }
th.num, td.num { text-align: right; }
.mono { font-family: ui-monospace, Consolas, Menlo, monospace; font-size: 12px; }
.empty { padding: 26px; text-align: center; color: var(--text-2); font-size: 13px; }

/* ---------- 单据详情 ---------- */
.detail-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.detail-actions .vo-print, .detail-actions #vo-print { margin-left: auto; }
.vo-type { font-size: 13px; font-weight: 600; color: var(--text); }
.vo-sum {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 12px;
}
.vo-sum > div {
  background: var(--bg, #f8fafc);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  min-width: 0;
}
.vo-sum span { display: block; font-size: 11px; color: var(--text-2); margin-bottom: 2px; }
.vo-sum b { font-size: 16px; font-weight: 600; word-break: break-all; }
.vo-sum .vo-un { color: var(--danger); }
/* 负数金额统一标红：退货单的数量与金额一眼可辨 */
.num.neg, td.neg, th.neg, b.neg { color: var(--danger) !important; }
.vo-grid > div { min-width: 0; overflow-wrap: anywhere; }
.vo-remark { grid-column: 1 / -1; }
.vo-sub { font-size: 11px; color: var(--text-2); font-weight: 400; margin-top: 1px; }
/* 列宽由表头的百分比决定（table-layout:fixed），
   这样合计行的数量 / 金额与上面每一行的商品明细严格对齐，
   不会因为「合计」两字与商品名长度不同而错位 */
.vo-items { table-layout: fixed; }
.vo-items th, .vo-items td { overflow-wrap: anywhere; }
.vo-items tfoot th {
  background: #f8fafc;
  border-top: 2px solid var(--border);
  /* tfoot 的 th 不在 thead 里，不补这两条就会：
     padding 为 0（贴边）、text-align 为浏览器默认的 center，
     导致合计行的数字与上面商品行的数字对不齐 */
  padding: 9px 10px;
  text-align: left;
  font-size: 13px;
}
.vo-items tfoot th.num { text-align: right; }
.vo-wrap { margin-top: 4px; }

/* ---------- 标签 ---------- */
.tag {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 10px;
  font-size: 11px;
  line-height: 18px;
  white-space: nowrap;
}
.t-green { background: #dcfce7; color: #166534; }
.t-red { background: #fee2e2; color: #b91c1c; }
.t-orange { background: #ffedd5; color: #c2410c; }
.t-blue { background: #dbeafe; color: #1e40af; }
.t-purple { background: #f3e8ff; color: #7e22ce; }
.t-gray { background: #f1f5f9; color: #64748b; }

/* ---------- 按钮 ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 13px;
  border: 1px solid var(--border);
  background: #fff;
  color: var(--text);
  border-radius: 6px;
  font-size: 13px;
  cursor: pointer;
  font-family: inherit;
}
.btn:hover { background: #f8fafc; border-color: #cbd5e1; }
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-sm { padding: 3px 9px; font-size: 12px; }
.btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-d); border-color: var(--primary-d); }
.btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger:hover { background: #b91c1c; border-color: #b91c1c; }

/* ---------- 表单 ---------- */
.field { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 120px; }
.field label { font-size: 12px; color: var(--text-2); }
.input, .select {
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
  font-family: inherit;
  background: #fff;
  color: var(--text);
  width: 100%;
}
.input:focus, .select:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px rgba(37,99,235,.12); }
/* 只读输入框（如非管理员看到的单据号）：灰底灰字，一眼看出改不了 */
.input:disabled, .select:disabled {
  background: #f1f5f9;
  color: var(--text-2);
  cursor: not-allowed;
  border-color: var(--border);
}
.input.num { text-align: right; }
.form-row { display: flex; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; }
.filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* 筛选结果统计条 */
.stat-bar {
  font-size: 12.5px; color: var(--text-2); line-height: 1.7;
  padding: 6px 2px 2px; border-top: 1px dashed var(--border); margin-bottom: 8px;
}
.stat-bar b { color: var(--text); }
/* 明细视图的范围说明：卡片是商品行，跟「多少张单据」不是一个口径 */
.o-item-tip {
  font-size: 12px;
  color: var(--text-2);
  padding: 4px 8px;
  margin: 0 0 8px;
  background: #eff6ff;
  border-left: 3px solid var(--primary);
  border-radius: 4px;
  line-height: 1.7;
}
.o-item-tip b { color: var(--primary); }
/* 单号命中高亮 */
.stat-bar + .tbl-wrap mark, .tbl-wrap mark {
  background: #fef08a; color: inherit; padding: 0 1px; border-radius: 2px;
}
.chk { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; color: var(--text-2); white-space: nowrap; }
.hint { font-size: 12px; color: var(--text-2); line-height: 1.7; margin-top: 4px; }
.note-box {
  background: #f8fafc;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  font-size: 13px;
  color: var(--text-2);
  line-height: 1.9;
}
.note-box code { background: #e2e8f0; padding: 1px 5px; border-radius: 4px; font-size: 12px; }
.readonly-tip {
  background: #fffbeb;
  border-left: 3px solid var(--warning);
  padding: 8px 12px;
  border-radius: 0 6px 6px 0;
  font-size: 12px;
  color: #92400e;
  margin-bottom: 12px;
}

/* ---------- 标签页 ---------- */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 14px; }
.tabs a {
  padding: 8px 16px;
  font-size: 13px;
  color: var(--text-2);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tabs a:hover { color: var(--text); }
.tabs a.on { color: var(--primary); border-bottom-color: var(--primary); font-weight: 600; }

/* ---------- 详情栅格 ---------- */
.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px 16px;
  font-size: 13px;
}
.detail-grid b { color: var(--text-2); font-weight: 500; font-size: 12px; }

/* ---------- 图表 ---------- */
.chart-box { width: 100%; overflow: hidden; }
.chart-svg { width: 100%; height: 220px; display: block; }
.chart-legend { display: flex; gap: 16px; justify-content: center; margin-top: 6px; font-size: 12px; color: var(--text-2); }
.chart-legend span { display: inline-flex; align-items: center; gap: 5px; }
.chart-legend i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }

.donut-wrap { display: flex; gap: 20px; align-items: center; flex-wrap: wrap; }
.donut { width: 160px; height: 160px; flex-shrink: 0; }
.donut-list { flex: 1; min-width: 200px; }
.dl-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  font-size: 13px;
  border-bottom: 1px solid #f1f5f9;
}
.dl-item i { width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0; }
.dl-n { flex: 1; }
.dl-v { font-weight: 600; }
.dl-p { color: var(--text-2); width: 50px; text-align: right; font-size: 12px; }

/* ---------- 弹窗 ---------- */
.modal-mask {
  position: fixed;
  inset: 0;
  background: rgba(15,23,42,.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
  overflow-y: auto;
}
.modal {
  background: #fff;
  border-radius: 12px;
  width: 100%;
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 50px rgba(0,0,0,.25);
}
.modal-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
.modal-head h3 { font-size: 16px; font-weight: 600; }
/* 可拖动：标题栏变成抓手 */
.modal-head.drag-handle { cursor: move; user-select: none; }
.modal.dragging { opacity: .96; box-shadow: 0 24px 60px rgba(0, 0, 0, .3); }
.modal.dragging .modal-head.drag-handle { cursor: grabbing; }
.modal-x {
  border: none;
  background: none;
  font-size: 22px;
  color: var(--text-2);
  cursor: pointer;
  line-height: 1;
  padding: 0 4px;
}
.modal-x:hover { color: var(--text); }
.modal-body { padding: 16px 18px; overflow-y: auto; }
.modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 18px;
  border-top: 1px solid var(--border);
}

/* ---------- 提示 ---------- */
#toast-root { position: fixed; top: 18px; right: 18px; z-index: 200; display: flex; flex-direction: column; gap: 8px; }
.toast {
  background: #1e293b;
  color: #fff;
  padding: 10px 16px;
  border-radius: 8px;
  font-size: 13px;
  box-shadow: 0 8px 20px rgba(0,0,0,.2);
  opacity: 0;
  transform: translateX(20px);
  transition: all .25s;
  max-width: 320px;
}
.toast.show { opacity: 1; transform: translateX(0); }
.toast.success { background: var(--success); }
.toast.error { background: var(--danger); }

/* ---------- 自动编码提示 ---------- */
.auto-hint { font-size: 11px; color: var(--primary); margin-top: 3px; min-height: 14px; }
.hint.inline { display: inline; margin-left: 8px; }
.tabs-row { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.detail-actions { margin-bottom: 12px; display: flex; align-items: center; flex-wrap: wrap; gap: 4px; }

/* 单据列表的「商品」列：最多两行，超出省略，悬停看全部 */
td.pdt {
  max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12.5px; color: var(--text-2, #475569);
}

/* 整行可点击（如账龄表点开单据详情） */
tbody tr.row-link { cursor: pointer; }
tbody tr.row-link:hover > td { background: #f1f5f9; }

/* 批量操作条：已选张数 + 批量按钮 */
.sel-bar {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.sel-bar .sel-info { font-size: 12px; color: #334155; white-space: nowrap; }
.sel-bar .sel-info b { color: var(--primary); font-size: 13px; }
.sel-bar:empty { display: none; }

/* ---------- 搜索区折叠 ---------- */
.f-badge {
  display: inline-block;
  min-width: 16px;
  padding: 0 4px;
  margin-left: 2px;
  background: var(--danger);
  color: #fff;
  border-radius: 9px;
  font-size: 11px;
  line-height: 16px;
  text-align: center;
  font-weight: 600;
}
.btn-primary .f-badge { background: rgba(255, 255, 255, .32); }

/* 「单据列表」标题旁的搜索折叠按钮：收起时高亮，提示当前是筛过的状态 */
#btn-ftoggle { white-space: nowrap; }
/* card-head 是 space-between，三个元素会被均匀拉开、按钮跑到中间。
   margin-right:auto 把右侧说明文字顶到最右，按钮就紧挨标题了 */
.card-head > h2 + #btn-ftoggle { margin-right: auto; margin-left: -4px; }
#btn-ftoggle.fold-on {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

/* 折叠后的一行摘要：说明「结果被筛过」，避免误以为数据不全 */
.f-summary:empty { display: none; }
.f-summary-inner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 6px 0 0;
  padding: 7px 10px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  border-radius: 6px;
  font-size: 12.5px;
  color: #1e40af;
}

/* 列设置：复选框两列排布 */
.col-cfg {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 8px 12px;
  padding: 4px 0;
}
.col-cfg .chk { white-space: nowrap; }
.col-cfg input:disabled { opacity: .6; cursor: not-allowed; }

/* ---------- 行勾选 ---------- */
th.ck-col, td.ck-col {
  width: 36px;
  text-align: center;
  padding-left: 6px;
  padding-right: 6px;
}
th.ck-col input, td.ck-col input {
  cursor: pointer;
  width: 15px;
  height: 15px;
  vertical-align: middle;
}
/* 勾选中的行：浅蓝底 + 左侧色条，便于确认选了哪些 */
tbody tr.row-sel > td {
  background: #eff6ff;
}
tbody tr.row-sel > td:first-child {
  box-shadow: inset 3px 0 0 var(--primary, #2563eb);
}
tbody tr.row-sel:hover > td { background: #dbeafe; }

.sel-bar {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-right: 8px;
}

/* 视图切换行：与筛选条件分开，单独一行，整体左对齐 */
.view-bar {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 4px;
  margin: 2px 0 10px;
  padding: 8px 10px;
  background: #f8fafc;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 8px;
}
.view-bar .hint {
  margin: 0 0 0 10px;
}
.view-bar .sel-bar {
  margin-left: 10px;
}

/* ---------- 表格合计行（tfoot） ---------- */
table tfoot td {
  position: sticky; bottom: 0;
  background: #f1f5f9;
  border-top: 2px solid var(--border, #e2e8f0);
  font-weight: 600;
  color: var(--text, #0f172a);
  padding: 9px 10px;
  font-size: 13px;
  white-space: nowrap;
}
table tfoot td.ft-label {
  text-align: right;
  color: var(--text-2, #475569);
  font-weight: 500;
  background: #f8fafc;
}
table tfoot td.ft-amt { color: var(--primary, #2563eb); }
table tfoot td.ft-unpaid { color: var(--danger, #dc2626); }
/* 未收付大于 0 的单元格：正文里也标红，便于一眼看出哪些单还没结清 */
td.ft-unpaid { color: var(--danger, #dc2626); }

/* ---------- 打印预览 ---------- */
.print-preview { position: fixed; inset: 0; background: rgba(15,23,42,.55); overflow-y: auto; z-index: 150; padding: 24px; }
.pp-bar {
  max-width: 820px; margin: 0 auto 14px;
  background: #fff; border-radius: 8px; padding: 10px 14px;
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  box-shadow: 0 4px 16px rgba(0,0,0,.2);
}
.pp-title { font-weight: 600; font-size: 14px; }
.pp-btns { display: flex; gap: 8px; align-items: center; }
.pp-paper { background: #fff; margin: 0 auto; box-shadow: 0 6px 24px rgba(0,0,0,.25); }

/* 预览纸张：与真实打印尺寸一致 */
.pp-paper.paper-receipt { width: 241mm; min-height: 93.3mm; padding: 4mm 5mm; }
.pp-paper.paper-a4 { width: 210mm; min-height: 297mm; padding: 14mm; }

/* 单据正文（默认按收款收据 24.1×9.33cm 排版，横向紧凑、纵向省空间） */
.print-doc { font-size: 10.5px; color: #000; line-height: 1.45; }

/* 抬头：标题居中，单号贴右上角（同一行，省垂直空间） */
.print-doc .p-head {
  position: relative;
  text-align: center;
  padding-bottom: 5px;
  margin-bottom: 5px;
  border-bottom: 2px solid #000;
}
.print-doc .p-title {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 6px;
  text-indent: 6px;      /* 抵消末字后的字距，保证真正居中 */
}
.print-doc .p-no {
  position: absolute;
  right: 0; bottom: 4px;
  font-size: 10px;
  color: #333;
  letter-spacing: .3px;
}

/* 元信息：一行横向铺开，窄条纸高度只有 9.33cm，不能用两列网格 */
.print-doc .p-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 18px;
  margin-bottom: 4px;
  padding: 3px 0;
  border-bottom: 1px dashed #bbb;
}
.print-doc .kv { display: flex; gap: 5px; font-size: 10px; white-space: nowrap; }
.print-doc .kv span { color: #666; flex-shrink: 0; }
.print-doc .kv b { font-weight: 600; }

/* 明细表 */
/* table-layout: fixed —— 列宽由表头的百分比决定，合计栏用 colspan 跨列时
   才能与上面每一行的列线精确对齐 */
.print-doc .p-table { width: 100%; border-collapse: collapse; font-size: 10px; table-layout: fixed; }
.print-doc .p-table th,
.print-doc .p-table td { border: 1px solid #333; padding: 2px 5px; height: 17px; overflow: hidden; }
.print-doc .p-table th { background: #f2f2f2; font-weight: 600; }
.print-doc .p-table td.c { text-align: center; }
.print-doc .p-table td.r { text-align: right; }
.print-doc .p-table .spec { display: block; font-size: 8.5px; color: #666; }
.print-doc .p-table tfoot td { background: #fafafa; font-weight: 600; }

/* 合计栏：票据样式——左「合计金额（大写）」右「合计金额 ¥x,xxx.xx」
   紧贴表格下方、去掉上边框：表格已有下边框，再加一条就成了双横线 */
/* 合计金额栏：作为 tfoot 的一行，靠 colspan 与表格列线对齐 —— 两格之间的
   竖线就是表格原生的「金额列右边界」，不用另外画线，天然严丝合缝 */
.print-doc .p-table tr.sum-row td {
  padding: 3px 7px;
  font-size: 10.5px;
  white-space: nowrap;
  background: #fcfcfc;
}
.print-doc .p-table tr.sum-row .lb { color: #333; font-weight: 400; margin-right: 6px; }
.print-doc .p-table tr.sum-row b { font-weight: 700; }
/* 左格大写靠左；右格标签贴左、金额靠右（正好落在金额列右边界上） */
.print-doc .p-table tr.sum-row td.p-cn { text-align: left; }
.print-doc .p-table tr.sum-row td.p-num { text-align: right; }
.print-doc .p-table tr.sum-row td.p-num .lb { float: left; }
.print-doc .p-table tr.sum-row td.p-cn b { font-size: 11px; }
.print-doc .p-table tr.sum-row td.p-num b { font-size: 13px; }

.print-doc .p-remark { margin-top: 2px; font-size: 9.5px; color: #333; }
.print-doc .p-amount { display: flex; align-items: baseline; gap: 8px; white-space: nowrap; }
.print-doc .p-amount-label { font-size: 10.5px; color: #333; }
.print-doc .p-amount-val { font-size: 15px; font-weight: 700; }

/* 签字栏：三个等宽格（不用上横线，直接留白分隔，更清爽） */
.print-doc .p-foot {
  display: flex;
  gap: 18px;
  margin-top: 10px;
  padding-top: 6px;
  font-size: 10px;
}
.print-doc .sign { flex: 1; color: #333; }
.print-doc .sign-val { font-weight: 600; }
.print-doc .p-tip { margin-top: 4px; text-align: right; font-size: 8.5px; color: #999; }

/* A4 时字号放大、元信息回到两列（A4 高度充裕） */
.pp-paper.paper-a4 .print-doc { font-size: 13px; }
.pp-paper.paper-a4 .print-doc .p-title { font-size: 22px; }
.pp-paper.paper-a4 .print-doc .p-no { font-size: 12px; }
.pp-paper.paper-a4 .print-doc .p-meta { gap: 4px 24px; margin-bottom: 8px; padding: 5px 0; }
.pp-paper.paper-a4 .print-doc .kv { font-size: 12px; }
.pp-paper.paper-a4 .print-doc .p-table { font-size: 12.5px; }
.pp-paper.paper-a4 .print-doc .p-table th,
.pp-paper.paper-a4 .print-doc .p-table td { padding: 4px 7px; height: auto; }
.pp-paper.paper-a4 .print-doc .p-remark { font-size: 12px; margin-top: 6px; }
.pp-paper.paper-a4 .print-doc .p-table tr.sum-row td { font-size: 12.5px; padding: 5px 10px; }
.pp-paper.paper-a4 .print-doc .p-table tr.sum-row td.p-cn b { font-size: 13px; }
.pp-paper.paper-a4 .print-doc .p-table tr.sum-row td.p-num b { font-size: 16px; }
.pp-paper.paper-a4 .print-doc .p-foot { font-size: 12px; margin-top: 26px; padding-top: 10px; }

/* 批量打印：张与张之间分页，每张单独立一页 */
.p-page-break { height: 0; }
@media print {
  .p-page-break { page-break-before: always; break-before: page; height: 0; }
}
/* 预览里用虚线提示分页位置 */
.pp-paper .p-page-break {
  height: auto;
  margin: 10px 0;
  border-top: 1px dashed #bbb;
  position: relative;
}
.pp-paper .p-page-break::after {
  content: '分页';
  position: absolute;
  right: 0; top: -8px;
  background: #fff;
  padding: 0 4px;
  font-size: 9px;
  color: #999;
}
@media print {
  .pp-paper .p-page-break { margin: 0; border: none; height: 0; }
  .pp-paper .p-page-break::after { display: none; }
}

/* ---------- 实际打印：只输出纸张内容 ---------- */
@media print {
  body * { visibility: hidden !important; }
  #print-root, #print-root * { visibility: visible !important; }
  #print-root { position: absolute; left: 0; top: 0; width: 100%; display: block !important; }
  .print-preview { position: static; background: none; padding: 0; overflow: visible; }
  .pp-bar { display: none !important; }
  .pp-paper { box-shadow: none; margin: 0; width: auto; min-height: 0; }
  .print-doc .p-table th, .print-doc .p-table td { border-color: #000; }
  /* @page 尺寸由 js/print.js 动态注入（默认收款收据 241×93.3mm） */
  @page { size: 241mm 93.3mm; margin: 3mm; }
}

/* ===========================================================
 * 手机 / 平板适配
 * 断点：1024（平板竖屏）→ 768（手机）→ 480（小屏手机）
 * =========================================================== */

/* 顶栏与遮罩默认隐藏，只在窄屏出现 */
.topbar { display: none; }
.nav-mask { display: none; }
.sidebar-x { display: none; }

/* ---------- 平板：略微收紧 ---------- */
@media (max-width: 1024px) {
  .sidebar { width: 176px; }
  .main { padding: 18px 18px; }
  .nav a { padding: 8px 14px; }
  .nav-group { padding: 12px 14px 4px; }
}

/* ---------- 手机 ---------- */
@media (max-width: 768px) {

  /* --- 顶栏 ---
     默认用页面背景色（--bg），不再是黑底：整页只有一块深色会显得沉，
     且与下面内容脱节。单据页（采购 / 销售）改成蓝色，
     与紧接其下的蓝色头部连成一体，看起来是一整块。 */
  .topbar {
    display: flex;
    position: fixed;
    top: 0; left: 0; right: 0;
    height: calc(52px + var(--tb-pt));
    background: var(--bg);
    color: var(--text);
    align-items: center;
    padding: var(--tb-pt) 6px 0;
    z-index: 60;
    border-bottom: 1px solid var(--border);
  }
  /* 单据页：与 .mhead 同色同渐变，中间不留缝 */
  body.view-sale .topbar,
  body.view-purchase .topbar {
    background: linear-gradient(135deg, #2563eb, #1d4ed8);
    color: #fff;
    border-bottom: none;
  }
  .icon-btn {
    border: none;
    background: none;
    color: var(--text);
    font-size: 21px;
    line-height: 1;
    width: 42px;
    height: 42px;
    cursor: pointer;
    border-radius: 8px;
  }
  body.view-sale .icon-btn,
  body.view-purchase .icon-btn { color: #fff; }
  .icon-btn:active { background: rgba(15, 23, 42, .08); }
  body.view-sale .icon-btn:active,
  body.view-purchase .icon-btn:active { background: rgba(255, 255, 255, .16); }
  .topbar-title {
    flex: 1;
    text-align: center;
    font-size: 16px;
    font-weight: 600;
  }
  .topbar-pad { width: 42px; }   /* 与菜单按钮等宽，保证标题居中 */

  /* 横屏提示：手机横过来时布局被压扁，给个提示。
     三道限定，缺一个都会误伤：
       1) max-height:600px —— 区分「手机横屏」和「平板横屏」（后者高度够，不必拦）
       2) pointer: coarse —— 电脑把窗口拉扁也会命中 landscape+矮高度，
          但电脑是鼠标（fine），必须排除，否则桌面端也弹这个
       3) body.is-touch —— 由 JS 检测的触摸设备兜底（pointer 查询不被支持时）
     另外要求 body.in-app：登录页是居中卡片，横屏照样能用，别挡着。 */
  /* 默认隐藏写在媒体查询外（见上方 .rotate-tip 说明），这里只管「何时显示」 */
  @media (orientation: landscape) and (max-height: 600px) and (pointer: coarse) {
    body.is-touch.in-app .rotate-tip {
      display: flex;
      position: fixed;
      inset: 0;
      z-index: 200;
      background: rgba(15, 23, 42, .94);
      color: #fff;
      align-items: center;
      justify-content: center;
      font-size: 15px;
      text-align: center;
      padding: 24px;
    }
  }
  /* 点了「仍要横屏」就不再打扰 */
  body.allow-landscape .rotate-tip { display: none !important; }

  /* --- 侧栏改为抽屉 --- */
  .layout { padding-top: calc(52px + var(--tb-pt)); }   /* 给固定顶栏让位 */
  .sidebar {
    position: fixed;
    top: 0; left: 0; bottom: 0;
    height: auto;                 /* 抽屉用 top/bottom 撑满，不要再套 100vh */
    width: 78%;
    max-width: 300px;
    transform: translateX(-100%);
    transition: transform .25s ease;
    z-index: 70;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .sidebar::-webkit-scrollbar { width: 0; height: 0; display: none; }
  .sidebar.open { transform: translateX(0); }
  .sidebar-x {
    display: block;
    position: absolute;
    top: 10px; right: 12px;
    border: none;
    background: none;
    color: #94a3b8;
    font-size: 26px;
    line-height: 1;
    cursor: pointer;
    padding: 0 4px;
  }
  .sidebar-x:active { color: #fff; }
  .logo { position: relative; padding-right: 44px; }
  .nav-mask.show {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, .5);
    z-index: 65;
  }

  /* --- 主区 --- */
  .main {
    padding: 12px 12px calc(32px + env(safe-area-inset-bottom));
    /* hidden 会让 .main 变成滚动容器，导致里面蓝色头部的 sticky 失效；
       clip 同样裁掉横向溢出但不建立滚动容器。老浏览器不支持时退回 hidden。 */
    overflow-x: hidden;
    overflow-x: clip;
    /* min-width:0 很关键：.main 是 .layout 的 flex 子项，默认 min-width:auto
       等于内容的 min-content 宽度。而卡片里的 .mc-sub 是 white-space:nowrap
       （商品·业务员·仓库·备注 拼成一行），它自己有 overflow:hidden 会被截断，
       但 min-content 仍是「全文宽度」，会沿 DOM 一路把 .main 撑宽。
       结果：整个页面向右延伸出视口，右边被 clip 裁掉，
       蓝色头部的时间标签也会少一个（被推到屏幕外）。
       置 0 后 .main 宽度只由 flex 分配，超出的内容各自用省略号处理。 */
    min-width: 0;
  }
  .page-head { align-items: stretch; gap: 8px; margin-bottom: 12px; }
  /* 黑色顶栏（topbar-title）已经显示了当前页面名，
     白底页头里的 h1 就是重复 —— 所有页面统一隐藏。
     这里写成全局而非逐个页面：菜单里的 13 个页面黑顶栏都有标题，
     列举式维护容易漏（曾漏掉库存 / 收付款 / 报表 / 参数 / 备份 / 用户）。 */
  .page-head h1 { display: none; }
  /* 标题没了，副标题升为主信息：字号与颜色提一档，不至于显得孤立 */
  .page-head .sub {
    font-size: 12.5px;
    color: var(--text);
    margin-top: 0;
  }
  /* 主操作按钮（新增单据等）在手机上撑满一行，便于点击 */
  .page-head > :last-child { flex: 1 1 auto; }
  .page-head > div:last-child { display: flex; gap: 6px; }
  .page-head > div:last-child .btn { flex: 1; justify-content: center; }
  .page-head > button:last-child { justify-content: center; padding: 10px; }
  .card { padding: 12px 12px; margin-bottom: 12px; border-radius: 8px; }
  .card-head { margin-bottom: 10px; }

  /* --- KPI：两列，数字缩小 --- */
  .kpi-grid { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .kpi { padding: 10px 12px; }
  .kpi-v { font-size: 18px; }

  /* --- 表格：横向滚动 + 首列固定 --- */
  .tbl-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  /* 列多时保证可读宽度，超出部分横向滑动查看 */
  .tbl-wrap table { min-width: 600px; }
  #tbl-o { min-width: 780px; }          /* 单据列多，保证可读 */

  /* 「左右滑动查看全部列」提示已取消（用户不需要）。
     全局 .swipe-tip 仍是 display:none，这里不再打开它。 */
  table { font-size: 12.5px; }
  thead th { padding: 8px 8px; font-size: 11.5px; }
  tbody td { padding: 8px 8px; }
  /* 首两列固定：滚动时仍能定位是哪一行 */
  thead th:first-child, tbody td:first-child {
    position: sticky; left: 0; z-index: 2;
  }
  thead th:first-child { background: #f8fafc; z-index: 3; }
  tbody td:first-child { background: #fff; }
  tbody tr:hover > td:first-child { background: #f8fafc; }
  tbody tr.row-sel > td:first-child { background: #eff6ff; }
  /* 单据表：勾选列 + 单号列一起固定 */
  #tbl-o thead th:nth-child(2), #tbl-o tbody td:nth-child(2) {
    position: sticky; left: 36px; z-index: 2;
  }
  #tbl-o thead th:nth-child(2) { background: #f8fafc; z-index: 3; }
  #tbl-o tbody td:nth-child(2) { background: #fff; }
  #tbl-o tbody tr:hover > td:nth-child(2) { background: #f8fafc; }
  #tbl-o tbody tr.row-sel > td:nth-child(2) { background: #eff6ff; }
  /* 操作按钮允许折行，避免被挤出屏幕 */
  tbody td:last-child { white-space: normal; }
  /* 整行可点开详情 —— 给个手型光标，否则看不出来能点 */
  #tbl-o tbody tr[data-oid] { cursor: pointer; }
  #tbl-mv tbody tr { cursor: pointer; }

  /* --- 筛选栏：两列排布 --- */
  .filters { gap: 6px; }
  .filters .input, .filters .select {
    flex: 1 1 calc(50% - 4px) !important;
    width: auto !important;
    min-width: 0 !important;
    font-size: 16px;                    /* < 16px 时 iOS 聚焦会自动放大页面 */
  }
  .filters > span.hint { display: none; }   /* 「至」这类连接词在窄屏省略 */
  .view-bar { flex-wrap: wrap; }
  .view-bar .hint, .view-bar .sel-bar { margin-left: 0; }

  /* --- 表单与弹窗 --- */
  .form-row { flex-direction: column; gap: 10px; }
  .field { min-width: 0; }
  .input, .select { font-size: 16px; padding: 9px 10px; }
  .btn { padding: 9px 14px; font-size: 14px; }
  .btn-sm { padding: 6px 10px; font-size: 13px; }

  .modal-mask {
    padding: 0;
    align-items: stretch;
    /* 关键：遮罩本身不滚动，滚动交给弹窗内部。
       之前是遮罩整页滚 + 底栏 sticky，商品一多底栏就会被内容盖住 */
    overflow: hidden;
  }
  .modal {
    max-width: none !important;
    width: 100%;
    /* 固定为视口高度（dvh 适配手机地址栏伸缩），头尾常驻、只有中间内容滚动 */
    height: 100vh;
    height: 100dvh;
    min-height: 0;
    max-height: none;
    border-radius: 0;
  }
  .modal-head { flex: none; padding: 12px 14px; }
  .modal-body {
    flex: 1 1 auto;
    min-height: 0;              /* flex 子项不置 0 不会收缩，滚不起来 */
    overflow-y: auto;
    /* 兜底：弹窗里若某行被撑宽（如多列表格），也能横向滑出来看，
       而不是被 mask 的 overflow:hidden 裁掉 */
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
  }
  .modal-foot {
    flex: none;                 /* 不再用 sticky：由 flex 布局固定在底部 */
    position: static;
    background: #fff;
    box-shadow: 0 -2px 10px rgba(15, 23, 42, .08);
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
  }
  .modal-foot .btn { flex: 1; justify-content: center; padding: 12px; font-size: 15px; }

  /* --- 弹窗内表单：两列排布，整体更紧凑 --- */
  .modal-body .form-row {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 6px;
  }
  .modal-body .form-row > .field { flex: 1 1 calc(50% - 4px); min-width: 0; }
  .modal-body .field label { font-size: 11.5px; margin-bottom: 3px; }
  .modal-body .field { gap: 2px; }
  .modal-body .input, .modal-body .select { padding: 6px 8px; }
  .modal-body .card { padding: 8px 9px; margin: 6px 0; }
  .modal-body .card-head { margin-bottom: 6px; gap: 6px; }
  .modal-body .card-head h2 { font-size: 14px; }
  .modal-body .auto-hint { font-size: 10.5px; }
  .modal-body .hint { font-size: 11px; line-height: 1.5; }

  /* 单据详情的明细表列较多（商品/数量/单价/金额/成本/毛利），
     手机上给足最小宽度，让它能横向滑动查看，而不是被压成一团看不清。
     600px 是刻意留出的余量：宽到明显超出屏幕，手指一滑才有位移感，
     只超几十像素的话用户会以为「滑不动」 */
  .modal-body .tbl-wrap table.vo-items { min-width: 600px; }

  /* --- 开单明细：手机上仍是表格，靠横向滑动看右侧列 ---
     之前把 tr 改成 display:block 做成卡片，结果表格不再超宽，
     .tbl-wrap 的 overflow-x:auto 没有可滚距离，就成了「滑不动」。
     改回真表格 + 商品列固定，滑到哪都知道填的是哪个商品 */
  #o-items { min-width: 520px; }
  #o-items th, #o-items td { padding: 6px 6px; }
  #o-items thead th { font-size: 11px; }
  /* 商品列固定左侧：它是行的标识，滑走就不知道在填谁了 */
  #o-items thead th:first-child, #o-items tbody td:first-child {
    position: sticky; left: 0; z-index: 2;
  }
  #o-items thead th:first-child { background: #f8fafc; z-index: 3; }
  #o-items tbody td:first-child { background: #fff; }
  #o-items .c-pd { min-width: 132px; }
  /* 16px 不是排版需要，是为了不被 iOS 放大：
     聚焦 font-size<16px 的输入框时 Safari 会自动放大整个页面。
     padding 收到 5px 补偿一点高度，保持行紧凑。 */
  #o-items input { padding: 5px 6px; font-size: 16px; min-width: 52px; }
  /* 数量框比单价框宽一点：要容下常显的上下箭头（见下方）
     并留够数字位，否则点箭头时容易碰到旁边的格子 */
  #o-items .c-qty input { min-width: 76px; }
  #o-items .c-price input { min-width: 58px; }
  #o-items .c-amt { white-space: nowrap; }
  #o-items .c-rm { width: 40px; }
  #o-items .c-rm .btn { padding: 4px 8px; font-size: 13px; }

  /* --- 单据详情 --- */
  .vo-sum { gap: 5px; margin-bottom: 8px; }
  .vo-sum > div { padding: 5px 7px; border-radius: 6px; }
  .vo-sum span { font-size: 10.5px; }
  .vo-sum b { font-size: 14.5px; }
  .vo-grid { grid-template-columns: repeat(2, 1fr); gap: 6px 8px; font-size: 12px; }
  .vo-grid b { font-size: 11px; }
  .vo-items { font-size: 12px; }
  .detail-actions { margin-bottom: 6px; gap: 6px; }
  .detail-actions .btn { padding: 5px 9px; }

  /* 明细表：弹窗内也要能横滑 */
  /* 弹窗内表格的最小宽度：要明显大于手机屏宽（375 左右），
     否则只超出几十像素，手指一滑几乎没有位移，用户会以为「滑不动」 */
  .modal-body .tbl-wrap table { min-width: 520px; }

  /* --- 其它 --- */
  .tabs { overflow-x: auto; white-space: nowrap; -webkit-overflow-scrolling: touch; }
  .tabs a { padding: 8px 12px; }
  .tabs-row { gap: 6px; }
  .detail-grid { grid-template-columns: repeat(2, 1fr); gap: 10px 12px; }
  .two-col { gap: 12px; }
  .donut-wrap { gap: 12px; }
  .donut { width: 130px; height: 130px; }

  #toast-root {
    top: 60px; left: 12px; right: 12px;
    align-items: stretch;
  }
  .toast { max-width: none; text-align: center; }

  /* 打印预览：纸张按真实尺寸渲染，允许横向滑动查看 */
  .print-preview { padding: 12px; overflow-x: auto; }
  .pp-bar { flex-wrap: wrap; }
}

/* ---------- 小屏手机 ---------- */
@media (max-width: 480px) {
  .kpi-grid { grid-template-columns: 1fr 1fr; gap: 6px; }
  .kpi-v { font-size: 16px; }
  .kpi-l, .kpi-s { font-size: 11px; }
  .detail-grid { grid-template-columns: 1fr; }
  /* 单据详情保持两列：字段短，单列会拉得很长 */
  .vo-grid { grid-template-columns: repeat(2, 1fr); }
  .page-head h1 { font-size: 17px; }
  /* 筛选栏一行一个，输入更从容 */
  .filters .input, .filters .select { flex: 1 1 100% !important; }
  .filters .btn { flex: 0 0 auto; }
  .btn { padding: 8px 12px; font-size: 13.5px; }
}

/* 数量框的上下箭头常显。
   Chrome 111+ 起默认只在 hover / focus 时才冒出来，
   手机没有 hover —— 不聚焦就看不到，很多人以为没有这功能。
   步长已是 1（见 views.js），点一下就是 ±1。 */
#o-items input[name="qty"]::-webkit-inner-spin-button,
input[name="actual"]::-webkit-inner-spin-button {
  opacity: 1;
  width: 16px;
  margin-left: 2px;
}
/* 输入法箭头上下排，本身较窄；加高一点让手指更好点 */
@media (max-width: 768px) {
  #o-items input[name="qty"]::-webkit-inner-spin-button,
  input[name="actual"]::-webkit-inner-spin-button { width: 20px; }
}

/* 分段切换（与 / 或）：两个按钮贴成一组，不用 margin 否则中间会断开 */
.seg { display: inline-flex; vertical-align: middle; }
.seg .btn { border-radius: 0; margin-left: -1px; }
.seg .btn:first-child { border-radius: 6px 0 0 6px; margin-left: 0; }
.seg .btn:last-child { border-radius: 0 6px 6px 0; }
/* 手机查询页的「与 / 或」一行 */
.ms-lg {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 0 4px; border-top: 1px solid var(--border); margin-top: 10px;
}
.ms-lg > label { font-size: 13.5px; color: var(--muted); }

/* 弹窗打开时锁住背景滚动，避免手机上滑动穿透 */
body.modal-open { overflow: hidden; }

/* ---------- 登录页 ---------- */
.login-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #1e293b 0%, #334155 55%, #2563eb 100%);
  padding: 20px;
}
.login-card {
  width: 100%;
  max-width: 380px;
  background: #fff;
  border-radius: 14px;
  padding: 34px 30px;
  box-shadow: 0 24px 60px rgba(0,0,0,.28);
}
.login-card h1 { font-size: 21px; text-align: center; margin-bottom: 4px; }
.login-card .tip { text-align: center; color: var(--text-2); font-size: 12px; margin-bottom: 22px; }
.login-card .field { margin-bottom: 14px; }
.login-card .btn { width: 100%; justify-content: center; margin-top: 8px; padding: 9px; }
.login-err {
  background: #fee2e2;
  color: #b91c1c;
  font-size: 12px;
  padding: 8px 10px;
  border-radius: 6px;
  margin-bottom: 12px;
  display: none;
}
.login-demo { margin-top: 18px; padding-top: 14px; border-top: 1px dashed var(--border); font-size: 12px; color: var(--text-2); line-height: 1.9; }
.login-demo b { color: var(--text); }
.login-demo .row { display: flex; justify-content: space-between; }
.login-demo .fill { cursor: pointer; color: var(--primary); }
.login-demo .fill:hover { text-decoration: underline; }

@media (max-width: 480px) {
  .login-card { padding: 24px 20px; border-radius: 12px; }
  .login-card h1 { font-size: 19px; }
}

/* ===========================================================
 * 手机版单据列表：蓝色统计头部 + 卡片流
 * 桌面端这些元素全部隐藏，表格照常；窄屏反过来。
 * =========================================================== */
/* 手机端专属元素：桌面必须先隐藏。
   曾经只在 @media (max-width:768px) 里写 display:none，
   结果宽屏时那条规则根本不生效 —— 元素没有任何样式兜底，
   就当成普通 div 直接渲染在页面上了（横屏提示在电脑版显示就是这个原因）。
   凡是「只给手机用」的元素，隐藏必须写在媒体查询外面。 */
.mhead { display: none; }
.m-cards { display: none; }
.rotate-tip { display: none; }

@media (max-width: 768px) {
  /* =========================================================
   * 以下规则只作用于采购 / 销售两个单据页（#app.view-sale / .view-purchase）。
   *
   * 曾写成全局裸规则，结果把商品、往来单位、仓库、员工四个档案页的页头
   * （「+ 新增商品」等按钮就在这里）、筛选框、卡片白底一起藏掉了 ——
   * 表现为手机上找不到新增按钮、也筛不了商品。
   * ========================================================= */
  /* 单据页蓝色头部已有标题与新增按钮，无需再显示桌面页头 */
  #app.view-sale .page-head,
  #app.view-purchase .page-head { display: none; }
  /* 桌面那套筛选栏 / 视图切换 / 表格在手机上全部让位给卡片 */
  #app.view-sale .card > .card-head,
  #app.view-purchase .card > .card-head,
  #app.view-sale #fbar,
  #app.view-purchase #fbar,
  #app.view-sale .view-bar,
  #app.view-purchase .view-bar,
  #app.view-sale #f-summary,
  #app.view-purchase #f-summary,
  #app.view-sale #tbl-o-wrap,
  #app.view-purchase #tbl-o-wrap { display: none !important; }
  /* 统计已并入蓝色头部 */
  #app.view-sale #o-sum,
  #app.view-purchase #o-sum { display: none; }
  #app.view-sale .card,
  #app.view-purchase .card {
    padding: 10px 10px 6px; background: transparent; border: 0; box-shadow: none;
  }

  .mhead {
    display: block;
    background: linear-gradient(135deg, #2563eb, #1d4ed8);
    color: #fff;
    /* 上边界与黑色顶栏下沿重合：顶栏 52px 且 .layout 已 padding-top:52px，
       这里用 -12px 抵消 .main 的 12px 内边距，正好落在 52px 处 */
    margin: -12px -12px 10px;
    padding: 10px 12px 10px;
    /* 顶栏同色时上缘不设圆角，接缝才看不出来；圆角只留底部 */
    border-radius: 0 0 14px 14px;
    box-shadow: 0 4px 14px rgba(37, 99, 235, .22);
    /* 下滑时蓝色区域保持不动。
       注意：sticky 依赖「最近的滚动祖先」——.main 若保持 overflow-x:hidden
       会变成滚动容器，sticky 就失效了，所以下面改成 clip。 */
    position: sticky;
    top: calc(52px + var(--tb-pt));   /* 让开固定的顶栏 */
    z-index: 50;
  }
  /* 标题已由黑色顶栏显示，蓝色区只留右上角按钮 */
  .mhead-top { display: flex; align-items: center; justify-content: flex-end; }
  .mhead-btns { display: flex; gap: 6px; }
  /* 图标按钮：加大触摸区，避免手机上点不准 */
  .micon {
    width: 38px; height: 38px;
    display: inline-flex; align-items: center; justify-content: center;
    background: rgba(255, 255, 255, .16);
    border: 1px solid rgba(255, 255, 255, .28);
    border-radius: 10px;
    color: #fff;
    cursor: pointer;
    padding: 0;
  }
  .micon:active { background: rgba(255, 255, 255, .3); }

  /* 统计不再用白色半透明小框，直接落在蓝色背景上 */
  .mhead-stat {
    display: flex;
    gap: 10px;
    margin: 8px 0 10px;
  }
  .ms-cell {
    flex: 1;
    background: none;
    border-radius: 0;
    padding: 0;
    text-align: center;      /* 与时间标签一致：水平居中分布 */
  }
  .ms-v { font-size: 21px; font-weight: 700; line-height: 1.3; word-break: break-all; }
  .ms-l { font-size: 12px; opacity: .85; margin-top: 2px; }

  /* 四个标签等宽铺满一行（原为内容宽度 + 可横滑，右边会空一截） */
  .mhead-tags { display: flex; gap: 6px; padding-bottom: 2px; }
  .mtag {
    flex: 1 1 0;
    min-width: 0;
    text-align: center;
    padding: 5px 2px;
    font-size: 12px;
    border-radius: 14px;
    border: 1px solid rgba(255, 255, 255, .3);
    background: rgba(255, 255, 255, .1);
    color: #fff;
    cursor: pointer;
  }
  .mtag.on { background: #fff; color: var(--primary); font-weight: 600; border-color: #fff; }

  .m-selbar {
    display: none;
    margin-top: 10px;
    padding-top: 9px;
    border-top: 1px dashed rgba(255, 255, 255, .3);
  }
  /* 分行：统计+全选 / 常用操作 / 危险操作与退出 —— 一行塞 8 个按钮太挤 */
  .msb-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
  }
  .msb-row + .msb-row { margin-top: 8px; }
  .m-selbar .msb-txt { font-size: 13px; flex: 1; }
  .m-selbar .btn {
    background: rgba(255, 255, 255, .18);
    border-color: rgba(255, 255, 255, .32);
    color: #fff;
  }
  /* 删除是破坏性操作，蓝底上也要能一眼认出 */
  .m-selbar .btn-danger {
    background: rgba(220, 38, 38, .88);
    border-color: rgba(255, 255, 255, .4);
    color: #fff;
  }

  .m-cards { display: block; }
  /* 一张单一卡：比 15 列的表格横滑好用的多 */
  .mcard {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 10px 12px;
    margin-bottom: 9px;
    box-shadow: 0 1px 3px rgba(15, 23, 42, .05);
    /* 同上：不让 .mc-sub 的 nowrap 长文本把卡片撑宽 */
    min-width: 0;
    overflow: hidden;
  }
  .mcard:active { background: #f8fafc; }
  .mcard.row-sel { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(37, 99, 235, .18); }
  .mc-hd { display: flex; align-items: center; gap: 7px; }
  .mc-ck { display: flex; align-items: center; }
  .mc-ck input { width: 17px; height: 17px; }
  .mc-no { font-size: 13px; font-weight: 600; flex: 1; word-break: break-all; }
  .mc-tag { flex: 0 0 auto; }
  .mc-pt { font-size: 14px; color: var(--text); margin: 5px 0 2px; font-weight: 500; }
  .mc-mid {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    margin-top: 3px;
  }
  .mc-amt { font-size: 17px; font-weight: 700; color: var(--primary); min-width: 0; overflow: hidden; }
  .mc-amt.neg { color: var(--danger); }
  .mc-date { font-size: 11px; color: var(--text-2); flex: 0 0 auto; }
  .mc-un { font-size: 11px; color: var(--danger); margin-top: 2px; }
  .mc-un.neg { color: var(--warning); }
  .mc-sub {
    font-size: 11px;
    color: var(--text-2);
    margin-top: 4px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .mc-acts {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--border);
  }
  /* 触摸目标不小于 32px，避免点错 */
  .mc-acts .btn { padding: 5px 11px; font-size: 12px; min-height: 32px; }
}

/* ---- 手机查询弹窗（独立一屏的表单） ---- */
.msearch { padding: 2px 0 4px; }
.ms-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 2px;
  border-bottom: 1px solid var(--border);
}
.ms-row > label {
  flex: 0 0 84px;
  font-size: 13px;
  color: var(--text-2);
}
.ms-ctl { flex: 1; display: flex; align-items: center; gap: 6px; min-width: 0; }
.ms-ctl .input,
.ms-ctl .select { flex: 1; min-width: 0; width: 100%; }
.ms-range { display: flex; align-items: center; gap: 5px; flex: 1; min-width: 0; }
.ms-range .input { flex: 1; min-width: 0; padding-left: 6px; padding-right: 6px; }
.ms-to { color: var(--text-2); flex: 0 0 auto; }
.ms-arrow { color: #cbd5e1; font-size: 17px; flex: 0 0 auto; }
/* 编号 / 助记词 / 拼音识别后的回显：让用户确认系统认对了人 */
.ms-hint {
  display: none;
  margin: -4px 0 6px 94px;
  font-size: 12px;
  color: var(--success);
}
.ms-hint.on { display: block; }
.ms-quick { display: flex; flex-wrap: wrap; gap: 6px; padding: 9px 2px 3px; }
@media (max-width: 768px) {
  /* 手机上表单更紧凑，字号不小于 16px 以免 iOS 聚焦放大 */
  .ms-row > label { flex: 0 0 76px; }
  .ms-row { padding: 9px 0; }
  .ms-ctl .input, .ms-ctl .select { font-size: 16px; }
}

/* ===========================================================
 * 参数设置页（仅管理员）
 * =========================================================== */
.pm-row {
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 13px 15px;
  margin-bottom: 10px;
}
.pm-row:last-child { margin-bottom: 0; }
.pm-main { flex: 1; min-width: 0; }
.pm-label { font-size: 14px; font-weight: 600; margin-bottom: 4px; }
.pm-desc { font-size: 12px; color: var(--text-2); line-height: 1.7; }
.pm-ctl { display: flex; align-items: center; gap: 9px; margin: 10px 0 6px; }
.pm-state { font-size: 12px; font-weight: 600; }
.pm-state.on { color: var(--success); }
.pm-state.off { color: var(--text-2); }
.pm-key { font-size: 11px; color: var(--text-2); }
.pm-key code {
  background: #f1f5f9;
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 11px;
}
.pm-note p { font-size: 12.5px; color: var(--text-2); line-height: 1.9; }

/* 开关：比原生 checkbox 大，手机上也好点 */
.switch { position: relative; display: inline-block; width: 44px; height: 24px; flex: 0 0 auto; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider {
  position: absolute;
  cursor: pointer;
  inset: 0;
  background: #cbd5e1;
  border-radius: 24px;
  transition: background .18s;
}
.switch .slider::before {
  content: '';
  position: absolute;
  width: 18px; height: 18px;
  left: 3px; bottom: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform .18s;
}
.switch input:checked + .slider { background: var(--primary); }
.switch input:checked + .slider::before { transform: translateX(20px); }
@media (max-width: 768px) {
  .pm-row { padding: 11px 12px; }
  .pm-ctl { margin: 9px 0 5px; }
}

/* ===========================================================
 * 手机批量选择模式
 * 普通状态下勾选框很小（17px，藏在单号左边），手机上不好点也不好找。
 * 进入批量模式后：复选框放大、点整张卡片即可勾选、操作按钮隐藏防误触。
 * =========================================================== */
.m-cards.batch .mc-ck input { width: 22px; height: 22px; }
.m-cards.batch .mc-ck { flex: 0 0 auto; }
.m-cards.batch .mc-acts { display: none; }
.m-cards.batch .mcard { cursor: pointer; }
.micon.on {
  background: #fff;
  color: var(--primary);
  border-color: #fff;
}
@media (max-width: 768px) {
  .m-selbar .btn { padding: 5px 9px; font-size: 12px; }
}

/* ===========================================================
 * 档案页的窄屏卡片（商品 / 往来单位 / 仓库 / 员工）
 * 由 syncTableCards 从表格转换而来，宽屏不渲染、只显示表格
 * =========================================================== */
.m-list { display: none; }
.xcard {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 11px 13px;
  margin-bottom: 9px;
  box-shadow: 0 1px 3px rgba(15, 23, 42, .05);
}
.xc-hd {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 7px;
}
.xc-t {
  font-size: 15px;
  font-weight: 600;
  flex: 1;
  min-width: 0;
  word-break: break-all;
}
.xc-badge { flex: 0 0 auto; }
.xc-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 5px 10px;
}
.xc-f {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12.5px;
  min-width: 0;
}
.xc-f > span { color: var(--text-2); flex: 0 0 auto; }
.xc-f > b {
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 重点字段（库存、售价、销售额）：一眼能看到数 */
.xc-f.hl > b { font-weight: 700; color: var(--primary); }
.xc-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 9px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
}
/* 超小屏：两列挤不下就单列，避免文字截断 */
@media (max-width: 400px) {
  .xc-grid { grid-template-columns: 1fr; }
}
