/* ================= 开单宝 样式 ================= */
:root {
  --primary: #2563eb;
  --primary-dark: #1d4ed8;
  --primary-light: #eff6ff;
  --success: #10b981;
  --success-light: #ecfdf5;
  --warning: #f59e0b;
  --warning-light: #fffbeb;
  --danger: #ef4444;
  --danger-light: #fef2f2;
  --text: #1e293b;
  --text-2: #64748b;
  --text-3: #94a3b8;
  --bg: #f1f5f9;
  --card: #ffffff;
  --border: #e2e8f0;
  --sidebar: #1e293b;
  --sidebar-text: #cbd5e1;
  --radius: 10px;
  --radius-sm: 7px;
  --shadow: 0 1px 2px rgba(15, 23, 42, .06), 0 1px 3px rgba(15, 23, 42, .04);
  --shadow-md: 0 4px 14px rgba(15, 23, 42, .08);
  --shadow-lg: 0 12px 32px rgba(15, 23, 42, .16);
}

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

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

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #94a3b8; }

/* ============ 登录 / 注册 ============ */
.auth-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(140deg, #1e293b 0%, #1e3a8a 55%, #2563eb 100%);
  padding: 24px;
}
.auth-box {
  width: 100%;
  max-width: 940px;
  background: #fff;
  border-radius: 16px;
  box-shadow: var(--shadow-lg);
  display: grid;
  grid-template-columns: 1fr 1fr;
  overflow: hidden;
}
.auth-side {
  background: linear-gradient(160deg, #1e293b, #1e3a8a);
  color: #fff;
  padding: 48px 40px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.auth-brand { font-size: 22px; font-weight: 600; letter-spacing: .5px; }
.auth-brand span { color: #60a5fa; }
/* ★ 品牌字标改用图片（2026-10-12）：高度定死，宽度按比例自适应 */
.auth-logo { height: 38px; display: block; }
.auth-side h3 { font-size: 26px; font-weight: 500; line-height: 1.45; margin-bottom: 16px; }
.auth-side p { color: #94a3b8; font-size: 13.5px; }
.auth-points { margin-top: 28px; display: flex; flex-direction: column; gap: 12px; }
.auth-point { display: flex; gap: 10px; align-items: flex-start; font-size: 13.5px; color: #cbd5e1; }
.auth-point b { color: #fff; font-weight: 500; }
.auth-dot { width: 6px; height: 6px; border-radius: 50%; background: #60a5fa; margin-top: 8px; flex: none; }
.auth-form { padding: 44px 40px; }
.auth-tabs { display: flex; gap: 24px; border-bottom: 1px solid var(--border); margin-bottom: 26px; }
.auth-tab {
  padding: 0 0 12px; font-size: 15px; color: var(--text-2); cursor: pointer;
  border-bottom: 2px solid transparent; background: none; border-left: 0; border-right: 0; border-top: 0;
}
.auth-tab.active { color: var(--primary); border-bottom-color: var(--primary); font-weight: 500; }

/* ============ 表单 ============ */
.form-group { margin-bottom: 16px; }
.form-group label { display: block; font-size: 13px; color: var(--text-2); margin-bottom: 6px; }
.form-group label .req { color: var(--danger); margin-left: 2px; }
.input, .select, .textarea {
  width: 100%; padding: 9px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: 14px; color: var(--text); background: #fff; font-family: inherit;
  transition: border-color .15s, box-shadow .15s;
}
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .12);
}
.input::placeholder { color: var(--text-3); }
.input.is-error { border-color: var(--danger); }
.textarea { resize: vertical; min-height: 66px; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.form-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px; }
.field-error { color: var(--danger); font-size: 12px; margin-top: 4px; display: none; }
.field-error.show { display: block; }
.form-inline-note { font-size: 12px; color: var(--text-3); margin-top: 4px; }

/* ============ 按钮 ============ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 16px; border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: #fff; color: var(--text); font-size: 14px; font-family: inherit;
  cursor: pointer; transition: all .15s; white-space: nowrap;
}
.btn:hover { border-color: #cbd5e1; background: #f8fafc; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
.btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger:hover { background: #dc2626; border-color: #dc2626; }
.btn-success { background: var(--success); border-color: var(--success); color: #fff; }
.btn-success:hover { background: #059669; border-color: #059669; }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-2); }
.btn-ghost:hover { background: #f1f5f9; border-color: transparent; }
.btn-block { width: 100%; }
.btn-sm { padding: 5px 10px; font-size: 13px; }
.btn-link { background: none; border: none; color: var(--primary); cursor: pointer; font-size: 13px; padding: 2px 4px; font-family: inherit; }
.btn-link:hover { text-decoration: underline; }
.btn-link.danger { color: var(--danger); }

/* ============ 布局 ============ */
.layout { display: flex; min-height: 100vh; }
.sidebar {
  width: 216px; flex: none; background: var(--sidebar); color: var(--sidebar-text);
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh;
}
.sidebar-brand {
  padding: 20px 20px 18px; font-size: 16px; font-weight: 600; color: #fff;
  border-bottom: 1px solid rgba(255, 255, 255, .08); letter-spacing: .3px;
}
/* ★ 品牌字标改用图片（2026-10-12）：侧边栏 26px 高，2x 图靠 srcset 自动切。
   为什么用图不用字：字标里的「闪」是「门 + 橙色闪电」，纯文字做不出来。 */
.sidebar-brand .brand-mark { height: 26px; display: block; }
.sidebar-brand small { display: block; font-size: 11px; color: #64748b; font-weight: 400; margin-top: 3px; letter-spacing: 0; }
.nav { flex: 1; overflow-y: auto; padding: 12px 10px; }
.nav-group-title { font-size: 11px; color: #64748b; padding: 12px 10px 6px; letter-spacing: .5px; }
.nav-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: var(--radius-sm);
  color: var(--sidebar-text); cursor: pointer; font-size: 13.5px; margin-bottom: 2px;
  transition: background .15s, color .15s; border: none; background: none; width: 100%; text-align: left; font-family: inherit;
}
.nav-item:hover { background: rgba(255, 255, 255, .07); color: #fff; }
.nav-item.active { background: var(--primary); color: #fff; }
.nav-item .nav-badge {
  margin-left: auto; background: var(--danger); color: #fff; font-size: 11px;
  padding: 0 6px; border-radius: 8px; line-height: 17px; min-width: 18px; text-align: center;
}
.nav-icon { width: 16px; height: 16px; flex: none; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.topbar {
  height: 58px; background: #fff; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; padding: 0 22px; gap: 14px; position: sticky; top: 0; z-index: 20;
}
.topbar h2 { font-size: 16px; font-weight: 500; flex: 1; }
.topbar-user { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--text-2); }
.avatar {
  width: 30px; height: 30px; border-radius: 50%; background: var(--primary-light); color: var(--primary-dark);
  display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 500;
}
.tenant-chip {
  background: var(--primary-light); color: var(--primary-dark); font-size: 12px;
  padding: 3px 10px; border-radius: 20px;
}
.content { padding: 20px 22px 40px; flex: 1; }
.menu-toggle { display: none; }

/* ============ 卡片 ============ */
.card { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 16px; }
.card-head {
  padding: 14px 18px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.card-head h3 { font-size: 14.5px; font-weight: 500; }
.card-head .spacer { flex: 1; }
.card-body { padding: 18px; }
.card-body.tight { padding: 0; }

/* ============ 统计卡 ============ */
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 16px; }
.stat-card { background: var(--card); border-radius: var(--radius); padding: 16px 18px; box-shadow: var(--shadow); }
.stat-card .stat-label { font-size: 12.5px; color: var(--text-2); display: flex; align-items: center; gap: 6px; }
.stat-card .stat-value { font-size: 24px; font-weight: 500; margin: 8px 0 4px; letter-spacing: -.5px; }
.stat-card .stat-value.small { font-size: 20px; }
.stat-card .stat-foot { font-size: 12px; color: var(--text-3); }
.stat-card .stat-foot b { color: var(--success); font-weight: 500; }
.stat-card .stat-foot b.down { color: var(--danger); }
.stat-card.accent { background: linear-gradient(135deg, #2563eb, #1d4ed8); color: #fff; }
.stat-card.accent .stat-label, .stat-card.accent .stat-foot { color: rgba(255, 255, 255, .8); }
.stat-card.accent .stat-foot b { color: #fff; }
.stat-value .unit { font-size: 13px; font-weight: 400; color: var(--text-3); margin-left: 3px; }
.stat-card.accent .stat-value .unit { color: rgba(255, 255, 255, .75); }

/* ============ 表格 ============ */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
thead th {
  text-align: left; padding: 11px 14px; background: #f8fafc; color: var(--text-2);
  font-weight: 500; font-size: 12.5px; white-space: nowrap; border-bottom: 1px solid var(--border);
}
tbody td { padding: 11px 14px; border-bottom: 1px solid #f1f5f9; vertical-align: middle; }
tbody tr:hover { background: #f8fafc; }
tbody tr:last-child td { border-bottom: none; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td.mono { font-family: 'SF Mono', Consolas, monospace; font-size: 12.5px; color: var(--text-2); }
.amount { font-weight: 500; }
.amount.danger { color: var(--danger); }
.amount.success { color: var(--success); }
/* 操作列里排按钮。flex 子项默认可压缩 —— 列一窄按钮就被压扁/换行，
   所以一律 flex:none 让按钮保持自然宽度，再用 nowrap 兜住按钮内的文字。 */
.row-actions { display: flex; gap: 2px; justify-content: flex-end; white-space: nowrap; }
.row-actions > * { flex: none; }

/* ---------------- 调整显示顺序（拖动排序，2026-10-09） ----------------
   只在「调整顺序」模式下出现（见 public/js/master.js）。 */
.reorder-bar {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px; margin: 0;
  background: var(--warning-light); border-bottom: 1px solid #fcd34d;
}
.reorder-tip { flex: 1; font-size: 13px; color: #b45309; line-height: 1.6; }
.reorder-tip b { color: #92400e; }

/* 手柄列：不占太多宽、光标给「可抓」的提示 */
td.drag-grip { color: var(--text-3); cursor: grab; text-align: center; width: 34px; }
td.drag-grip svg { display: block; margin: 0 auto; }
tr[draggable="true"]:hover td.drag-grip { color: var(--text-2); }

/* 正在拖的那一行：淡一点 + 左边一条竖线，让人看清「拿起来了」 */
tr.dragging { opacity: .55; background: var(--bg); }
tr.dragging td:first-child { box-shadow: inset 3px 0 0 var(--primary); }

/* 单据列表：商品明细列。名字长的商品不能把整行撑爆 —— 省略号 + title 悬停看全文 */
.bill-table .cell-items { min-width: 220px; max-width: 340px; }

/* ★ 退货（2026-10-12）：单号列加了「退货单」徽章后会变宽，把日期列挤到换行
   （实测所有行都变成 `2026-\n10-12`）。这两列都定宽、都不折行；
   横向伸缩交给「商品明细」列。 */
.bill-table .col-no { width: 11.5em; white-space: nowrap; }
.bill-table .col-date { width: 6.5em; white-space: nowrap; }
.cell-items-main {
  color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cell-items-sub {
  margin-top: 2px; font-size: 12px; color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 作废单：整行退到背景里去，但保留可读（还要能点进去看来龙去脉） */
tr.row-void td { opacity: .55; }
tr.row-void .amount { text-decoration: line-through; }
/* 汇总条上的「未收合计」——有欠款才变红，其余场合保持安静 */
.prod-summary .sum-due { color: var(--danger); }

/* 单据列表：开单人列固定「一行三个字」，按钮列固定放得下两个按钮。
   用固定宽度的内联块而不是给 td 设宽 —— table-layout 是 auto，
   给 td 的宽只是建议值，商品明细列一长就会被挤回去。 */
.bill-table .col-creator { width: 3em; }
.bill-table .cell-w3 {
  display: inline-block; width: 3em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  vertical-align: middle; color: var(--text-2);
}
.bill-table .col-actions { width: 104px; }
.bill-table .row-actions { min-width: 88px; }

/* ============ 打印队列 ============ */
/* 「有单在等电脑」是最需要被看见的状态：多半意味着店里的电脑没开机。
   做成整条有底色的提示而不是一个小徽章 —— 中老年用户对纯色块更敏感。 */
.print-wait-tip {
  margin: 12px 18px; padding: 10px 14px; border-radius: var(--radius-sm);
  background: var(--warning-light); border: 1px solid #fcd34d;
  color: #b45309; font-size: 13px; line-height: 1.7;
}
.print-wait-tip b { color: #92400e; }
/* 任务编号、打印电脑名：附属信息，压在单号下面一行小字 */
.job-id { display: block; font-size: 11.5px; color: var(--text-3); font-weight: 400; }
/* 失败原因：可能要写「启动浏览器失败：ENOENT」，允许两行后省略，完整内容看 title */
.job-err {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 11.5px; color: var(--danger);
  max-width: 260px; margin-top: 3px; font-weight: 400; white-space: normal;
}
/* 申请人列固定「一行四个字」，与单据列表的开单人列同一套做法 */
.bill-table .col-who { width: 4em; }
.bill-table .cell-w4 {
  display: inline-block; width: 4em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  vertical-align: middle; color: var(--text-2);
}

/* ============ 标签 ============ */
.badge {
  display: inline-block; padding: 2px 8px; border-radius: 20px; font-size: 12px;
  line-height: 18px; white-space: nowrap;
}
.badge-blue { background: var(--primary-light); color: var(--primary-dark); }
.badge-green { background: var(--success-light); color: #047857; }
.badge-amber { background: var(--warning-light); color: #b45309; }
.badge-red { background: var(--danger-light); color: #b91c1c; }
.badge-gray { background: #f1f5f9; color: var(--text-2); }
/* 单据列表里那枚「待上传 / 需处理」徽章：它是个按钮（点开待上传队列）。
   浏览器给 button 的默认边框与字体必须清掉，否则和旁边那些 span 徽章长得不一样。 */
.jxc-local-badge {
  border: none; font-family: inherit; font-size: 12px; line-height: 18px;
  cursor: pointer; vertical-align: middle;
}

/* ============ 筛选条 ============ */
.filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.filters .input, .filters .select { width: auto; min-width: 130px; }
.filters .input.search { min-width: 190px; }

/* ============ 分页 ============ */
.pager { display: flex; align-items: center; gap: 8px; padding: 14px 18px; justify-content: flex-end; font-size: 13px; color: var(--text-2); }
.pager .spacer { flex: 1; }

/* ============ 弹窗 ============ */
.modal-mask {
  position: fixed; inset: 0; background: rgba(15, 23, 42, .45); z-index: 100;
  display: flex; align-items: flex-start; justify-content: center; padding: 40px 16px; overflow-y: auto;
}
.modal {
  background: #fff; border-radius: 12px; box-shadow: var(--shadow-lg); width: 100%;
  max-width: 560px; animation: modalIn .18s ease-out;
}
.modal.wide { max-width: 860px; }
/* 开单弹窗：明细表有 7 列（商品/数量/单价/折扣/优惠/最终金额/删除），
   860px 下每列只剩 90 来像素、数字挤成一团（2026-10-06 每行折扣需求）→ 单开一档 */
.modal.wide.xwide { max-width: 1010px; }
.modal.narrow { max-width: 420px; }
@keyframes modalIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: none; } }
.modal-head {
  padding: 16px 20px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
}
.modal-head h3 { font-size: 15px; font-weight: 500; }
.modal-close { background: none; border: none; font-size: 20px; color: var(--text-3); cursor: pointer; line-height: 1; padding: 0 4px; }
.modal-close:hover { color: var(--text); }
.modal-body { padding: 20px; }
.modal-foot { padding: 14px 20px; border-top: 1px solid var(--border); display: flex; gap: 10px; justify-content: flex-end; }

/* ============ 明细行编辑（开单） ============ */
.items-table th { background: #f8fafc; }
.items-table td { padding: 7px 8px; }
.items-table .input, .items-table .select { padding: 6px 9px; font-size: 13px; }
.items-table .line-amount { font-weight: 500; font-variant-numeric: tabular-nums; padding-right: 10px; }
.bill-total {
  display: flex; justify-content: flex-end; gap: 28px; padding: 14px 8px 2px;
  border-top: 1px solid var(--border); margin-top: 12px; font-size: 14px;
}
.bill-total .label { color: var(--text-2); }
.bill-total .num { font-size: 20px; font-weight: 500; color: var(--primary-dark); font-variant-numeric: tabular-nums; }

/* ============ Toast ============ */
.toast-wrap { position: fixed; top: 18px; left: 50%; transform: translateX(-50%); z-index: 200; display: flex; flex-direction: column; gap: 8px; align-items: center; }
.toast {
  background: #1e293b; color: #fff; padding: 10px 18px; border-radius: 8px; font-size: 13.5px;
  box-shadow: var(--shadow-md); animation: toastIn .2s ease-out; max-width: 90vw;
}
.toast.success { background: #047857; }
.toast.error { background: #b91c1c; }
.toast.warning { background: #b45309; }
@keyframes toastIn { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }

/* ============ 空状态 / 加载 ============ */
.empty { text-align: center; padding: 48px 20px; color: var(--text-3); font-size: 13.5px; }
.empty .big { font-size: 15px; color: var(--text-2); margin-bottom: 6px; }
.loading { text-align: center; padding: 40px; color: var(--text-3); font-size: 13.5px; }

/* ============ 图表 ============ */
.bar-chart { display: flex; align-items: flex-end; gap: 8px; height: 150px; padding: 10px 4px 0; }
.bar-col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; height: 100%; justify-content: flex-end; }
.bar {
  width: 100%; max-width: 46px; background: linear-gradient(180deg, #60a5fa, #2563eb);
  border-radius: 5px 5px 0 0; min-height: 3px; transition: height .3s;
}
.bar-col .bar-label { font-size: 11px; color: var(--text-3); white-space: nowrap; }
.bar-col .bar-value { font-size: 11px; color: var(--text-2); }

/* ============ 响应式 ============ */
@media (max-width: 1100px) {
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 900px) {
  .auth-box { grid-template-columns: 1fr; }
  .auth-side { display: none; }
  .auth-form { padding: 32px 24px; }
  .sidebar {
    position: fixed; left: 0; top: 0; z-index: 60; transform: translateX(-100%);
    transition: transform .22s; box-shadow: var(--shadow-lg);
  }
  .sidebar.open { transform: none; }
  .menu-toggle { display: inline-flex; }
  .form-row, .form-row-3 { grid-template-columns: 1fr; }
  .content { padding: 14px 14px 32px; }
  .topbar { padding: 0 14px; }
  .filters .input, .filters .select, .filters .input.search { width: 100%; flex: 1 1 140px; }
}
@media (max-width: 560px) {
  .stat-grid { grid-template-columns: 1fr; }
  .topbar h2 { font-size: 15px; }
  .tenant-chip { display: none; }
}

/* 遮罩（移动端侧边栏） */
.sidebar-mask { display: none; position: fixed; inset: 0; background: rgba(15, 23, 42, .4); z-index: 55; }
.sidebar-mask.show { display: block; }

/* ============ 工作台 ============ */
.dash-cols { display: grid; grid-template-columns: 1.5fr 1fr; gap: 16px; margin-bottom: 16px; }
.dash-cols > .card { margin-bottom: 0; }

.warn-row, .mini-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 18px; border-bottom: 1px solid #f1f5f9;
}
.warn-row:last-child, .mini-row:last-child { border-bottom: none; }
.warn-name, .mini-name { font-size: 13.5px; }
.warn-sub, .mini-sub { font-size: 12px; color: var(--text-3); margin-top: 2px; }
.mini-row .amount { font-variant-numeric: tabular-nums; }

.quick-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.quick-btn {
  text-align: left; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: #fff; cursor: pointer; font-family: inherit; transition: all .15s;
}
.quick-btn:hover { border-color: var(--primary); background: var(--primary-light); }
.quick-btn b { display: block; font-size: 13.5px; font-weight: 500; color: var(--text); margin-bottom: 3px; }
.quick-btn span { font-size: 12px; color: var(--text-3); line-height: 1.5; }

/* ============ 开单明细行 ============ */
.items-table { width: 100%; border-collapse: collapse; }

/* ---------- 时间区间快捷条（2026-10-06） ----------
   一组 chip + 右边那行"实际区间文字"。文字是必要的：chip 只能说明"大概哪段时间"，
   而用户真正要确认的是"我现在筛的是哪一段"。手改日期后 chip 全灭 + 显示「自定义」。 */
.rbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rchips { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.rchip {
  appearance: none;
  border: 0;
  border-right: 1px solid var(--border);
  background: #fff;
  color: var(--text-2);
  font-size: 13px;
  padding: 7px 14px;
  cursor: pointer;
  line-height: 1.2;
}
.rchip:last-child { border-right: 0; }
.rchip:hover { background: #f5f7fa; }
.rchip.on { background: var(--primary); color: #fff; font-weight: 600; }
.rtext { font-size: 13px; color: var(--text-2); display: inline-flex; align-items: center; gap: 8px; }
.rlabel { color: var(--text-3); }
.rcustom {
  font-size: 12px;
  color: #b45309;
  background: #fffbeb;
  border: 1px solid #fde68a;
  border-radius: 4px;
  padding: 1px 6px;
}

/* 对账单表（2026-10-06 改成 15 列）：字号压小 + 不换行 + 容器可横向滚。
   一个商品一行之后列就多了，挤在弹窗里必须这么处理；换行会让「数字列」参差不齐。 */
.stmt-table { font-size: 12px; }
.stmt-table th, .stmt-table td { padding: 4px 6px; white-space: nowrap; }
.stmt-table th.num, .stmt-table td.num { text-align: right; }
/* 「整单优惠 / 差额调整」这类行提亮：客户一眼看到这是调整行，不是货 */
.stmt-table td.stmt-mark { background: #fffbeb; }
.items-table th {
  text-align: left; padding: 8px 8px; font-size: 12.5px; color: var(--text-2);
  font-weight: 500; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.items-table th.num, .items-table td.num { text-align: right; }
.items-table td { padding: 6px 8px; border-bottom: 1px solid #f1f5f9; vertical-align: middle; }
.items-table .del-btn {
  background: none; border: none; color: var(--text-3); cursor: pointer; font-size: 18px; line-height: 1; padding: 0 6px;
}
.items-table .del-btn:hover { color: var(--danger); }
.line-amount { font-variant-numeric: tabular-nums; font-size: 13.5px; }
/* 「上次 4.50（09-20）」：价格下面那行小字说明这个数从哪来 ——
   不说来源的话，用户看到价格自己变了会以为系统在乱改（2026-10-05 价格记忆） */
.item-price-hint {
  font-size: 11.5px; color: var(--text-3); line-height: 1.4; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 「10箱10套」：数量下面那行拆档提示。
   ★ 2026-10-06 用户要求「字体和颜色要明显一点」：这行是**关键信息**（按箱卖的时候，
   光看「310」得心算半天），所以做成加粗 + 主题色 + 浅底胶囊，跟灰色的「上次价」区分开。 */
.item-qty-hint {
  display: inline-block; margin-top: 3px; padding: 1px 8px;
  font-size: 12.5px; font-weight: 700; line-height: 1.6;
  color: var(--primary-dark); background: var(--primary-light);
  border: 1px solid #bfdbfe; border-radius: 4px;
  white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis;
}
/* ★ 这个胶囊没有内容时必须彻底消失：商品没有单位档位时 hint 文本是空串，
   但 padding + 边框还在 → 空 div 会撑出一条小白边挂在数量下面，
   看着像界面出错了（2026-10-06 放大截图才发现，C1 起就一直在） */
.item-qty-hint:empty { display: none; }
/* 「原价 ¥300.00」：有优惠时挂在「最终金额」输入框下面。
   只显示一个净额的话，用户核不出「让了多少、原来是多钱」（2026-10-06 每行折扣） */
.item-net-hint {
  font-size: 11.5px; color: var(--text-3); line-height: 1.4; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ============ 详情描述列表 ============ */
.detail-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px 20px; }
.detail-item .k { font-size: 12px; color: var(--text-3); margin-bottom: 3px; }
.detail-item .v { font-size: 13.5px; }

/* ============ 列表汇总条 ============ */
.prod-summary {
  display: flex; gap: 26px; flex-wrap: wrap; padding: 12px 18px;
  border-bottom: 1px solid var(--border); font-size: 13px; color: var(--text-2);
}
.prod-summary b { color: var(--text); font-weight: 500; }

/* ============ 标签页 ============ */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 16px; flex-wrap: wrap; }
.tab {
  padding: 9px 16px; font-size: 13.5px; color: var(--text-2); cursor: pointer;
  border: none; background: none; border-bottom: 2px solid transparent; font-family: inherit;
}
.tab:hover { color: var(--text); }
.tab.active { color: var(--primary); border-bottom-color: var(--primary); font-weight: 500; }

/* ============ PC 客户端状态条（只有客户端里才渲染，见 js/client.js） ============
   配色沿用「蓝＝正常、橙＝离线、红＝有事要处理」：
   中老年用户对颜色比对文字敏感，状态条不该只靠一句话表达状态。 */
.jxc-cbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: nowrap;
  height: 34px; padding: 0 18px; font-size: 12.5px;
  background: var(--primary-light); color: var(--primary-dark);
  border-bottom: 1px solid var(--border);
}
/* 登录页（index.html）没有 .main，状态条直接挂在 body 上 ——
   固定在最上方浮着，不参与 .auth-page 的垂直居中布局（否则整页会被顶高 34px）。
   登录页必须有这条栏：地址没填/填错时，用户被困在这里，改地址的入口在登录之后才够得着。 */
body > .jxc-cbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
}
.jxc-cbar-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--primary); flex: none; }
.jxc-cbar-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.jxc-cbar-sep { color: var(--text-3); }
.jxc-cbar-sub { color: var(--text-2); white-space: nowrap; }
.jxc-cbar .spacer { flex: 1; }
.jxc-cbar-btn { flex: none; }
.jxc-cbar.is-offline { background: var(--warning-light); color: #b45309; }
.jxc-cbar.is-offline .jxc-cbar-dot { background: var(--warning); }
.jxc-cbar.is-bad { background: var(--danger-light); color: #b91c1c; }
.jxc-cbar.is-bad .jxc-cbar-dot { background: var(--danger); }
/* 「另有 N 单等本人登录」：跟主文案同一行，但要一眼分得清是另一件事 */
.jxc-cbar-held {
  flex: none; padding: 1px 9px; border-radius: 20px; font-size: 12px;
  background: rgba(255, 255, 255, .7); color: #b45309; white-space: nowrap;
}
.jxc-cbar.is-offline .jxc-cbar-held, .jxc-cbar:not(.is-offline):not(.is-bad) .jxc-cbar-held {
  color: var(--primary-dark);
}

/* 待上传队列浮层 */
.jxc-q-tip { font-size: 12.5px; line-height: 1.75; color: var(--text-2); margin-bottom: 12px; }
.jxc-q-tip b { color: #b91c1c; }
.jxc-q-list { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; max-height: 380px; overflow-y: auto; }
.jxc-q-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 14px;
  border-bottom: 1px solid #f1f5f9; font-size: 13px;
}
.jxc-q-row:last-child { border-bottom: none; }
.jxc-q-main { flex: 1; min-width: 0; }
.jxc-q-title { display: flex; align-items: center; gap: 6px; color: var(--text); }
.jxc-q-no { font-size: 12px; color: var(--text-3); font-family: ui-monospace, Consolas, monospace; }
.jxc-q-sub { font-size: 12px; color: var(--text-3); margin-top: 3px; }
.jxc-q-err { font-size: 12px; color: #b91c1c; margin-top: 3px; }
.jxc-q-amt { width: 100px; text-align: right; font-weight: 500; color: var(--text); flex: none; }
.jxc-q-act { width: 128px; flex: none; display: flex; gap: 10px; justify-content: flex-end; }
.jxc-q-act > * { flex: none; }
.jxc-q-lock { font-size: 12px; color: var(--text-3); }

/* 本机数据说明 */
.jxc-d-row { display: flex; justify-content: space-between; padding: 7px 0; border-bottom: 1px dashed #f1f5f9; font-size: 13.5px; color: var(--text-2); }
.jxc-d-row b { color: var(--text); font-weight: 500; }
.jxc-d-path {
  margin-top: 12px; padding: 9px 11px; background: #f8fafc; border: 1px solid var(--border);
  border-radius: 7px; font-size: 12.5px; color: var(--text-2); word-break: break-all;
  font-family: ui-monospace, Consolas, monospace;
}

/* 「本机数据」浮层里的针式打印区块（并入客户端后新增） */
.jxc-d-sep { height: 1px; background: var(--border); margin: 16px 0 12px; }
.jxc-sw { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--text); cursor: pointer; user-select: none; }
.jxc-sw input { width: 15px; height: 15px; accent-color: var(--primary); cursor: pointer; flex: none; }
.jxc-sw input:disabled { cursor: not-allowed; }

/* 「本机数据」浮层里的快照 / 导 U 盘区块。
   U 盘是这里唯一会进出的东西，所以「选哪个盘」必须一眼看得见 ——
   用卡片式盘片而不是下拉框（下拉框会把两个盘藏起来，而用户经常不知道盘符是哪个）。 */
.jxc-bk-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.jxc-bk-actions .input { flex: 1 1 130px; min-width: 0; }
.jxc-drives { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 6px; }
.jxc-drive {
  display: flex; align-items: center; gap: 8px; text-align: left;
  padding: 8px 10px; background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); cursor: pointer; font-family: inherit;
  font-size: 13px; color: var(--text-2); transition: border-color .12s, background .12s;
}
.jxc-drive:hover { border-color: #cbd5e1; }
.jxc-drive b { font-size: 14px; font-weight: 600; color: var(--text); flex: none; font-variant-numeric: tabular-nums; }
.jxc-drive span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jxc-drive i { flex: none; font-style: normal; font-size: 12px; color: var(--text-3); }
/* 可移动盘给个记号：插着 U 盘时它应该是最扎眼的那个 */
.jxc-drive.rm { border-color: #bfdbfe; background: #f8fbff; }
.jxc-drive.rm b { color: var(--primary-dark); }
.jxc-drive.on { border-color: var(--primary); background: var(--primary-light); box-shadow: 0 0 0 1px var(--primary) inset; }
.jxc-drive.on span, .jxc-drive.on i { color: var(--text); }
.jxc-drives-hint { grid-column: 1 / -1; font-size: 12.5px; line-height: 1.7; color: var(--text-2); }

/* 首次运行：还没填服务器地址。
   蓝底而不是黄底 —— 这不是出错，只是「差一步」，用警告色会把人吓一跳。 */
.jxc-cbar.is-setup { background: var(--primary-light); color: #1e40af; }
.jxc-cbar.is-setup .jxc-cbar-dot { background: var(--primary); }

/* 设置浮层 */
.jxc-field { display: block; margin-top: 6px; }
.jxc-field > span { display: block; font-size: 13px; color: var(--text-2); margin-bottom: 6px; }
.jxc-field .input { width: 100%; font-family: ui-monospace, Consolas, monospace; }
.jxc-setup-msg { min-height: 20px; margin-top: 10px; font-size: 13px; line-height: 1.6; color: var(--text-2); }
.jxc-setup-msg.ok { color: var(--success); }
.jxc-setup-msg.warn { color: #b45309; }
.jxc-setup-msg.bad { color: var(--danger); }
.jxc-path { font-family: ui-monospace, Consolas, monospace; font-size: 12.5px; color: var(--text-2); word-break: break-all; font-weight: 400; }

/* 退出之后停在这一屏。
   不做成空白页：用户会以为「是不是崩了」，而这里要说的正是
   「是正常退出，数据都在，怎么再打开」。 */
.jxc-bye {
  margin: 120px auto 0; max-width: 460px; padding: 28px 26px; text-align: center;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--text-2); font-size: 14px; line-height: 2;
  box-shadow: var(--shadow);
}
.jxc-bye b { display: block; font-size: 16px; color: var(--text); font-weight: 500; margin-bottom: 6px; }

@media (max-width: 1000px) {
  .dash-cols { grid-template-columns: 1fr; }
  .detail-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .detail-grid { grid-template-columns: 1fr; }
  .quick-grid { grid-template-columns: 1fr; }
}

/* ================= 纸单版式（单据详情） =================
 * 2026-10-06：用户拿自家针式机打的实物单来说「开单按这个模板来」，
 * 所以**单据详情就长得跟那张纸一样**：表头两行 + 8 列明细 + 表尾四条。
 *
 * ⚠️ 三处版式必须同源，改一处要三处一起核：
 *    针式打印   src/print-render.js 的 renderBillHtml
 *    网页端详情 本文件 .slip（public/js/bills.js 里拼 HTML）
 *    APP 详情   app-mobile/pages/bill/detail.vue
 *   列名/列顺序/表尾条目顺序都要一致，否则「详情看到的是这样、打出来是那样」。
 *
 * 刻意不用圆角、不用彩色底 —— 纸单上没有这些东西；
 * 深色主题下这块也**始终按「白纸」呈现**（客户拿到手的本来就是白纸黑字）。 */
.slip { background: #fff; color: #1e293b; border: 1px solid var(--border);
        border-radius: var(--radius); padding: 16px; overflow-x: auto; }
.slip-title { text-align: center; font-size: 19px; font-weight: 700; letter-spacing: 4px; padding-bottom: 12px; }
.slip table { width: 100%; min-width: 760px; border-collapse: collapse; table-layout: fixed; }
.slip td { border: 1px solid #94a3b8; padding: 4px 6px; height: 30px; font-size: 13px;
           vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.slip td.head { text-align: center; font-weight: 600; background: #f8fafc; }
.slip td.num { text-align: right; font-variant-numeric: tabular-nums; }
.slip td.blank { height: 30px; }
.slip td.upper { font-weight: 600; }
/* 明细行多了要让表格能滚，而不是把弹窗撑破 */
.slip-scroll { max-height: 46vh; overflow-y: auto; }

/* ══════════ 期初往来金额（2026-10-07，方案 A）══════════
 * 迁移历史账用。设计上刻意做成「他欠我 / 我欠他」两个互斥按钮：
 *   ① 填不出负数（方向由按钮决定，最常见的错在输入层被消灭）
 *   ② 不要求用户理解「应收 / 应付」这组会计术语
 *  整块用虚线蓝框与普通字段区分 —— 它是「偶尔才填」的东西，
 *  每次开客户都摆一个灰框在那里会让人以为必填。 */
.init-box {
  border: 1px dashed #93c5fd;
  background: #f8fbff;
  border-radius: 8px;
  padding: 14px;
  margin: 4px 0 12px;
}
.init-head { font-size: 13px; font-weight: 600; color: #1e40af; margin-bottom: 10px; }
.init-head .init-sub { font-weight: 400; color: var(--text-3); margin-left: 6px; }
.init-seg { display: flex; margin-bottom: 12px; }
.init-seg button {
  flex: 1; padding: 8px; font-size: 13px; cursor: pointer;
  border: 1px solid #cbd5e1; background: #fff; color: var(--text-1);
  font-family: inherit;
}
.init-seg button:first-child { border-radius: 6px 0 0 6px; }
.init-seg button:last-child { border-radius: 0 6px 6px 0; border-left: none; }
.init-seg button.on { background: #2563eb; color: #fff; border-color: #2563eb; font-weight: 500; }
.init-seg button.on.pay { background: #ea580c; border-color: #ea580c; }
.form-hint { font-size: 12px; color: var(--text-3); margin-top: 5px; }
.init-hint {
  font-size: 12.5px; line-height: 1.6; color: #1e40af;
  background: #eff6ff; border-left: 3px solid #3b82f6;
  padding: 8px 10px; border-radius: 4px; margin-top: 10px;
}
.init-hint.warn { color: #92400e; background: #fffbeb; border-left-color: #f59e0b; }
