﻿/* ==================================================================
 * 设计令牌（Design Tokens）
 * 注意：前缀统一用 --c-* / --sp-* / --fs-* / --r-* / --sh-*，
 * 禁止使用 --doc-* / --a4-*（那两组属于 assets/css/doc.css 的 A4 排版引擎，
 * seal.php 会同时加载 app.css + doc.css，重名会串味）。
 * ================================================================== */
:root{
  /* 全站只有浅色版。声明 color-scheme:light 是为了让原生控件（勾选框、select 箭头、
   * 滚动条）在系统深色模式下也按浅色渲染 —— 否则新加的白色输入框会被系统刷成深灰。 */
  color-scheme: light;
  /* iOS 系统色（IOS-DESIGN-SPEC §1 令牌映射表）。改色不动语义：primary 仍是主色、
   * danger 仍是危险/负数，所以下面散落的 var() 引用不用逐个改。 */
  --c-primary:#007AFF; --c-primary-d:#0062CC;
  --c-success:#34C759; --c-warning:#FF9500; --c-danger:#FF3B30; --c-info:#30B0C7;
  --c-ink:#1C1C1E; --c-sidebar:rgba(255,255,255,.72);
  /* 语义色的「文字版」：iOS 亮色压浅底做 12-13px 正文对比度不足（2.0–3.8:1），
   * 所有「深字压浅底」的场景统一走这三个，避免又散出 #C4271E 之类的字面值。 */
  --c-danger-ink:#C4271E; --c-success-ink:#1E8E3E; --c-warning-ink:#B25E00;
  /* 中性「灰字压浅底」：.badge.gray / .pb-tag.pb-gray 三处在用，同样抽令牌。 */
  --c-gray-ink:#6C6C70;
  /* 五个 -50 浅底：仍保留令牌名（.pm-add 等在用），值换成 iOS 系统色压白的 8–10% 淡色，
   * 否则旧 tailwind 的淡蓝/淡绿底会和新主色同框串味（主理人第二轮要求）。 */
  --c-primary-50:#EBF4FF; --c-success-50:#EBF9EE; --c-warning-50:#FFF4E6;
  --c-danger-50:#FFEBEA;  --c-info-50:#EAF7F9;
  --c-text:#3C3C43; --c-muted:#7C7C82; --c-faint:#AEAEB2;
  --c-line:rgba(60,60,67,.20); --c-line-2:rgba(60,60,67,.10);
  --c-bg:#F2F2F7; --c-surface:#FFFFFF;
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-7:32px;
  --fs-xs:12px; --fs-sm:13px; --fs-md:15px; --fs-lg:17px; --fs-xl:22px; --fs-2xl:28px;
  --r-sm:6px; --r-md:10px; --r-lg:14px; --r-full:999px;
  /* 规范里有两处写死 12px 圆角（§2.6 统计卡、§2.12 看板行、§2.11 登录控件），
   * 之前写的字面值，抽成令牌，以后调圆角只改这一行。 */
  --r-12:12px;
  --sh-1:0 0 0 .5px rgba(0,0,0,.04), 0 1px 3px rgba(0,0,0,.05);
  --sh-2:0 4px 16px rgba(0,0,0,.07);
  --sh-3:0 20px 60px rgba(0,0,0,.16);
  /* ---- iOS 新增令牌（规范 §1.1）---- */
  --c-fill:rgba(120,120,128,.12);      /* systemFill：输入框 / 次要按钮底 */
  --c-fill-2:rgba(120,120,128,.20);    /* 悬停、按下 */
  --c-glass:rgba(255,255,255,.72);     /* 侧栏毛玻璃 */
  --c-glass-2:rgba(255,255,255,.86);   /* 顶栏毛玻璃（更实一点，压住滚动内容） */
  --c-sep:rgba(60,60,67,.20);          /* separator：表格行分隔（1x 屏上要看得见） */
  --c-sep-soft:rgba(60,60,67,.12);     /* 极轻内部分隔：虚线、卡片内分隔 */
  --c-sep-strong:rgba(60,60,67,.28);   /* 表头底线：表头与内容必须分得开 */
  /* 完工后补录标识（order_progress.is_supplement=1）专用三色。
   * 车间强光 + 手机降亮度下要认得出，所以这一组不参与「降对比度」的整体调整。 */
  --c-supp:#FF9500;                    /* 竖条 / 强调 */
  --c-supp-bd:rgba(255,149,0,.35);     /* 徽章描边 */
  --c-supp-bg:rgba(255,149,0,.10);     /* 整行底 */
  --blur:saturate(180%) blur(20px);
  --tap:44px;                          /* 移动端最小触控 */
}

/* 下面这条不许动：seal.php 同时加载 app.css + doc.css，改 * 的 margin/padding
 * 会让合同版式整体位移。font-family 同理（doc.css 依赖继承来的字体度量）。
 * —— 补充：doc.css 的 .a4-sheet 自己声明了 --doc-font，合同排版不继承 body，
 *    所以下面换字体栈只影响界面，打印稿一个字都不会动。 */
* { box-sizing: border-box; margin: 0; padding: 0; }
/* 字体栈：中文优先。
 * 原来的顺序是 -apple-system 打头，Windows 上不认这个关键字，实际落到「微软雅黑」，
 * Mac 上落到「苹方」——结果一样，但少了几个兜底：服务器装的精简版 Windows、
 * Linux 桌面、部分国产系统里没有雅黑，就会掉到 sans-serif 的无衬线默认字体，
 * 中文立刻变宋体或糊成一片。这里把常见中文字体都列进去。
 *
 * 另外删掉了 -webkit-font-smoothing: antialiased。这条是给 Retina 屏的 Mac
 * 准备的（让字细一点），但在 Windows 上它的作用是【关掉 ClearType 次像素渲染】，
 * 换成灰度抗锯齿 —— 12~13px 的汉字笔画本来就细，灰度渲染后笔画边缘发灰、
 * 像蒙了一层雾，这就是「字体不清楚」的直接来源。Windows 默认的 ClearType
 * 才是这个场景下最清晰的渲染方式，不要关。 */
body { font-family: -apple-system, "Microsoft YaHei", "Microsoft YaHei UI", "PingFang SC", "Hiragino Sans GB", "Source Han Sans SC", "Noto Sans SC", sans-serif; font-size: var(--fs-md); line-height: 1.5; color: var(--c-text); background: var(--c-bg); }
a { color: var(--c-primary); text-decoration: none; }
a:hover { text-decoration: underline; }

.layout { display: flex; min-height: 100vh; }
/* 侧栏：深色石板底 → 浅色毛玻璃（规范 §2.1）。文字必须同步由浅色改深色，
 * 否则白底浅灰字等于消失。宽度 200 → 232px（胶囊缩进需要空间）。 */
.sidebar { width: 232px; background: var(--c-glass); -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border-right: .5px solid rgba(0,0,0,.08); color: var(--c-ink); flex-shrink: 0; overflow-y: auto; }
.brand { padding: var(--sp-4); font-size: var(--fs-lg); font-weight: 500; color: var(--c-ink);
  background: transparent; border-bottom: .5px solid rgba(0,0,0,.08); }
.sidebar nav { padding: var(--sp-2) 0; }
.nav-group { padding: var(--sp-3) var(--sp-4) var(--sp-1); font-size: var(--fs-xs); color: var(--c-muted); text-transform: uppercase; }
.sidebar a { display: block; padding: var(--sp-2) var(--sp-4); color: var(--c-ink); font-size: var(--fs-sm); }
.sidebar a:hover { background: rgba(120,120,128,.08); color: var(--c-ink); text-decoration: none; }

.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
/* 顶栏：52 → 56px，白色实底 → 半透明毛玻璃 + 0.5px 发丝线（规范 §2.2） */
.topbar { height: 56px; background: var(--c-glass-2); -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border-bottom: .5px solid rgba(0,0,0,.08); display: flex; align-items: center; justify-content: space-between; padding: 0 var(--sp-5); }
.crumb { font-size: var(--fs-lg); font-weight: 500; color: var(--c-ink); }
.userbox { display: flex; gap: var(--sp-4); align-items: center; color: var(--c-muted); font-size: var(--fs-sm); }
/* 「退出」是破坏性动作，iOS 惯例用 systemRed（规范 §2.2） */
.userbox a { color: var(--c-danger); }
.content { padding: var(--sp-5); }

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: var(--sp-4); margin-bottom: var(--sp-5); }
/* 统计卡：白底描边 → systemFill 浅灰块，无边框无阴影（规范 §2.6） */
/* 统计卡（主理人第二轮 P1）：原来 var(--c-fill) 是 6% 亮度的灰，压在 #F2F2F7 页底上
 * 分不出层，实测「灰上灰」。改白底 + 一条 0.5px 的发丝外描边（不用真实阴影，
 * 避免多卡并排时投影互相叠出脏边）—— iOS 分组列表就是这么做的。 */
.card { background: var(--c-surface); border: 0; border-radius: var(--r-12); padding: var(--sp-4); box-shadow: 0 0 0 .5px rgba(0,0,0,.04); }
.card-label { color: var(--c-muted); font-size: var(--fs-sm); margin-bottom: var(--sp-2); }
.card-value { font-size: 26px; font-weight: 500; color: var(--c-ink); }

/* 注意：.panel 上禁止加 overflow / overflow-x —— 会裁掉 .ss-list 搜索下拉
 * （searchable.css 里是 position:absolute; z-index:60）。 */
.panel { background: var(--c-surface); border: 0; border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); margin-bottom: var(--sp-4); box-shadow: var(--sh-1); }
/* 面板里的 h3 有两种用法，必须分开处理：
 *   A) 独占一行的面板标题  <div class="panel"><h3>客户列表</h3>…
 *   B) 横排工具栏里的标题  <div class="toolbar"><h3>合作方账号</h3>…按钮…
 * 分隔线只给 A（`.panel > h3`）。给 B 会画出一条只到标题宽度一半的横线，
 * 而且 padding-bottom 会把工具栏那一行顶高 —— 全站有 18 处 B 型，会集体裂版。
 * 基础排版（display:flex / 17px / 500）仍然作用于全部 h3，不能只写 > h3，
 * 否则 B 型会退回浏览器默认的 <h3>（block + 粗体 + 1em 外边距）。 */
.panel h3 { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-lg); font-weight: 500; color: var(--c-ink);
  line-height: 1.4; margin-bottom: var(--sp-3); }
.panel > h3 { padding-bottom: 12px; margin-bottom: 14px; border-bottom: .5px solid var(--c-sep-soft); }
/* 看板标题行 / 详情标题行是 flex 横排（旁边挂搜索框、返回链接），按 B 型处理 */
.prod-board-h h3,
.prod-detail-h h3 { border-bottom: 0; padding-bottom: 0; margin-bottom: 0; }
/* 长说明文字（如 modules/sales/out.php 的打印记录提示）不要顶破面板 */
.panel h3 > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* ---- 表格基础（全局只作用在 table.grid 上，禁止写裸 table/td/th 选择器，
 *      否则会渗进 doc.css 的合同表格）---- */
table.grid { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
/* iOS 表格：删掉全部竖线与外框，只留 0.5px 横发丝线（规范 §2.5）。
 * 注：这里用 --c-sep(.20) 而不是 --c-sep-soft(.12) —— .5px 在 1x 屏会被取整成 1px，
 * 12% 的黑在 1px 上几乎看不见，10 行数据会糊成一片（主理人截图 P0）。
 * --c-sep-soft 只留给极轻的内部虚线（.pick-row / .copyblock-actions）。 */
/* 水平 padding 从 14px 收回 12px（主理人第二轮 P0「已收」列被压）：
 * 9 列 × 4px = 36px，把 1366/1280 笔记本上的横向余量还回来。
 * 垂直仍是 12px —— 行高 52px 的舒适档不动。 */
table.grid th, table.grid td { border: 0; border-bottom: .5px solid var(--c-sep); padding: 12px 12px; text-align: left; }
table.grid th { background: transparent; font-weight: 500; color: var(--c-muted); }
table.grid tbody tr:hover { background: rgba(120,120,128,.06); }
table.grid td.num { text-align: right; font-variant-numeric: tabular-nums; }
/* 表头跟随数字列右对齐（主理人第七轮）：此前 th 统一 text-align:left，
 * 而 td.num 是 right，导致「金额 / 已收」表头贴左、数字贴右，视觉错位。 */
table.grid th.num { text-align: right; }
table.grid th.nowrap, table.grid td.nowrap { white-space: nowrap; }
table.grid td.nowrap .btn { margin: 0 2px 0 0; }
table.grid td.nowrap .btn:last-child { margin-right: 0; }
/* 表格内按钮收紧（主理人第二轮 P0：「已收」列被 sticky 操作列压掉）：
 * 只作用于 table.grid 内，工具栏主按钮（+ 新建销售订单 / 筛选 / 重置）的
 * 宽 padding 呼吸感一点不动 —— 那才是 iOS 按钮好看的原因。
 * 三档全部锁在 min-width:1000px 里：车间手机的触屏字号/点击面积不受影响。
 * 实测回收（1366 已收右边缘 → 操作列左边缘的余量）：
 *   现状 −10px → 字号 11.5 −19px → 加 margin 1px −25px → 加 padding 7px −53px。 */
@media (min-width: 1000px) {
  table.grid .btn { padding: 0 7px; }
  table.grid .btn.sm { padding: 0 7px; font-size: 11.5px; }
  table.grid td.nowrap .btn { margin-right: 1px; }
}
.text-red { color: var(--c-danger); }
.text-green { color: var(--c-success); }
.muted { color: var(--c-muted); }

.toolbar { display: flex; gap: var(--sp-2); align-items: center; margin-bottom: var(--sp-3); flex-wrap: wrap; }
.toolbar form { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }

/* ---- 按钮 ----
 * font:inherit 是关键：以前 <button class="btn"> 走浏览器默认字体，
 * 和 <a class="btn"> 字形不一致。
 * iOS 化（规范 §2.3）：默认态由「白底描边」改为「systemFill 填充 + 主色字」，
 * 高度 32→36px，圆角 10px，按下缩放到 .97。描边归零，改由底色区分层级。 */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;
  height:36px;padding:0 16px;border:0;border-radius:var(--r-md);
  background:var(--c-fill);color:var(--c-primary);
  font:inherit;font-size:var(--fs-sm);line-height:1;white-space:nowrap;
  cursor:pointer;transition:background .15s cubic-bezier(.25,.1,.25,1),color .15s cubic-bezier(.25,.1,.25,1),box-shadow .15s cubic-bezier(.25,.1,.25,1),transform .15s cubic-bezier(.25,.1,.25,1)}
.btn:hover{background:var(--c-fill-2);color:var(--c-primary);text-decoration:none}
.btn:active{background:rgba(120,120,128,.24);transform:scale(.97)}
.btn:focus-visible{outline:none;box-shadow:0 0 0 4px rgba(0,122,255,.22)}
.btn[disabled],.btn.is-disabled{opacity:.35;cursor:not-allowed;pointer-events:none}
.btn.primary{background:var(--c-primary);color:#fff}
.btn.primary:hover{background:#0A7CFF;color:#fff}
.btn.primary:active{background:var(--c-primary-d);transform:scale(.97)}
.btn.danger{background:var(--c-danger);color:#fff}
.btn.danger:hover{background:#FF5A50;color:#fff}
/* 作废：危险但低频，用浅底红字。列表里唯一的实心强调色留给「定制」。
 * 只在列表操作列用（out.php 列表）；详情页作废、删除等重操作仍用 .btn.danger 实心红。
 * 文字色必须用 --c-danger-ink 而不是 --c-danger —— 后者压在 10% 浅底上偏灰。 */
.btn.danger-soft{background:rgba(255,59,48,.10);color:var(--c-danger-ink);box-shadow:none}
.btn.danger-soft:hover{background:rgba(255,59,48,.18);color:var(--c-danger-ink)}
.btn.success{background:var(--c-success);color:#fff}
.btn.success:hover{background:#3FD46A;color:#fff}
.btn.sm{height:28px;padding:0 10px;border-radius:8px;font-size:var(--fs-xs)}
.btn.block{display:flex;width:100%}

/* ---- 分段控件 segmented control（主理人第二轮 P1）----
 * 现状：progress.php 的「未完成 / 已完成」是两个独立胶囊按钮并排，中间有缝，
 * 看着像两个按钮碰巧挨着，不像 iOS 的一个控件两段。
 * iOS 的做法：浅灰容器（systemFill）内嵌两段，选中段是白色滑块 + 轻投影。
 * 注意：段内 <a> 不能再带 .btn 类 —— .btn 的 systemFill 填充底会和容器打架。
 * 高度 28px 是有意的：它是切换器不是提交按钮，不跟手机档 .btn 的 44px 走。 */
.seg{display:inline-flex;gap:2px;padding:2px;border-radius:9px;background:var(--c-fill)}
.seg > a{display:inline-flex;align-items:center;height:28px;padding:0 14px;
  border-radius:7px;font-size:var(--fs-sm);color:var(--c-text);text-decoration:none;
  white-space:nowrap;transition:background .15s cubic-bezier(.25,.1,.25,1),color .15s cubic-bezier(.25,.1,.25,1)}
.seg > a:hover{background:rgba(120,120,128,.10);color:var(--c-ink);text-decoration:none}
.seg > a.on{background:var(--c-surface);color:var(--c-ink);font-weight:500;
  box-shadow:0 1px 3px rgba(0,0,0,.10)}
.seg > a.on:hover{background:var(--c-surface);color:var(--c-ink)}

/* ---- 表单控件：统一 13px ----
 * iOS 化（规范 §2.4）：默认态改为「填充式」——无边框、systemFill 浅灰底，
 * 聚焦时变白底 + 1.5px 主色内描边。表格内的控件是例外，见下面「表格内控件」段。 */
input,select,textarea{height:36px;padding:0 var(--sp-2);border:0;border-radius:var(--r-md);
  font:inherit;font-size:var(--fs-sm);line-height:1.4;background:var(--c-fill);color:var(--c-text);
  box-shadow:inset 0 0 0 1px transparent;
  transition:background .15s cubic-bezier(.25,.1,.25,1),box-shadow .15s cubic-bezier(.25,.1,.25,1)}
textarea{height:auto;padding:var(--sp-2);resize:vertical;line-height:1.6}
input:hover,select:hover,textarea:hover{background:rgba(120,120,128,.16)}
input:focus,select:focus,textarea:focus{outline:none;background:var(--c-surface);box-shadow:inset 0 0 0 1.5px var(--c-primary)}
input::placeholder,textarea::placeholder{color:var(--c-faint)}
input[readonly]{background:transparent;color:var(--c-muted);box-shadow:inset 0 0 0 1px var(--c-sep-soft)}
/* 勾选框/单选框不吃上面的填充式底色，否则方框四角会露出一圈灰 */
input[type=checkbox],input[type=radio]{height:auto;padding:0;background:transparent;box-shadow:none}
/* 日期框的原生小日历图标（Chromium）默认是纯黑实心，压在 systemFill 浅灰底上很跳。
 * 降到 45% 不透明、hover 到 70%，作为「次要装饰」出现（主理人第二轮 P2）。 */
input[type=date]::-webkit-calendar-picker-indicator{opacity:.45;cursor:pointer;transition:opacity .15s}
input[type=date]::-webkit-calendar-picker-indicator:hover{opacity:.7}
label { display: block; margin-bottom: var(--sp-3); font-size: var(--fs-sm); color: var(--c-muted); }
label input, label select, label textarea { display: block; width: 100%; margin-top: var(--sp-1); }

.form-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0 var(--sp-4); }

/* ------------------------------------------------------------------
 * 防挤压：label 作为 flex 子项时不能被压成一字一行
 * 症状：flex 容器（如 .toolbar）里的 <label>客户 <select></label> 被压成
 *       「客」「户」竖排两行。
 * 原因：label 默认 flex-shrink:1，容器窄时就挤压文字；文字没有
 *       white-space:nowrap 就会逐字换行。
 * 修法：flex 容器内的 label 不收缩，文字不换行。
 * ------------------------------------------------------------------ */
.toolbar > label,
.toolbar > .fr,
.inline-label,
label[style*="display:flex"],
label[style*="display: flex"] {
  flex-shrink: 0;
  white-space: nowrap;
}
.toolbar > label > select,
.toolbar > label > input,
label[style*="display:flex"] > select,
label[style*="display:flex"] > input { min-width: 140px; }

/* 标签文字 + 星号不允许拆行 */
label .req, label .text-red { white-space: nowrap; }

/* label-over-input form rows: 2 or 3 per line, fixed width feel */
.form-rows { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3) var(--sp-5); margin-bottom: var(--sp-3); }
.form-rows.cols3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.form-rows .fr { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.form-rows .fr > label { font-size: var(--fs-xs); color: var(--c-muted); font-weight: 500; letter-spacing: .2px; }
.form-rows .fr > label .text-red { margin-left: 2px; }
.form-rows .fr > input,
.form-rows .fr > select,
.form-rows .fr > span { width: 100%; box-sizing: border-box; }
.form-rows .full { grid-column: 1 / -1; }
@media (max-width: 820px) { .form-rows, .form-rows.cols3 { grid-template-columns: 1fr; } }
.actions { margin-top: var(--sp-4); display: flex; gap: var(--sp-2); }

/* 提示条：圆角 12px、无边框、浅底深字（规范 §2.8）。
 * 文字色不能用 --c-danger/--c-success —— 那两档已是 iOS 亮色，压在 10% 浅底上偏灰。 */
.alert { padding: 10px var(--sp-3); border-radius: var(--r-12); margin-bottom: var(--sp-3); font-size: var(--fs-sm); border: 0; }
.alert.err { background: rgba(255,59,48,.10); color: var(--c-danger-ink); }
.alert.ok { background: rgba(52,199,89,.12); color: var(--c-success-ink); }
.alert.warn { background: rgba(255,149,0,.12); color: var(--c-warning-ink); }
.alert.info { background: rgba(0,122,255,.10); color: var(--c-primary-d); }

.pager { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: var(--sp-4); font-size: var(--fs-sm); }
.pager .total { margin-right: var(--sp-2); color: var(--c-muted); }
/* 分页按钮：30 → 34px，无边框填充式，字用主色（规范 §2.9） */
.pager a, .pager .cur {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 34px; padding: 0 var(--sp-2);
  border: 0; border-radius: var(--r-md); background: var(--c-fill); color: var(--c-primary);
}
.pager a:hover { background: var(--c-fill-2); color: var(--c-primary); text-decoration: none; }
.pager .cur { background: var(--c-primary); border-color: var(--c-primary); color: #fff; font-weight: 500; }
.pager .gap { color: var(--c-faint); padding: 0 2px; letter-spacing: 1px; }
/* 上一页/下一页：常驻显示，首末页置灰 —— 单页时也看得见，不会误以为分页没做 */
.pager .pgbtn { display: inline-flex; align-items: center; height: 34px; padding: 0 10px; }
.pager .pgbtn.dis {
  border-color: var(--c-line); border-radius: var(--r-md);
  color: var(--c-faint); background: transparent;
  cursor: not-allowed; user-select: none;
}
/* 每页条数：右对齐，下面的 select 压到 34px 高与页码按钮齐平（跟页码按钮同高，不是 30px） */
.pager .pager-size {
  margin-left: auto; display: inline-flex; align-items: center; gap: var(--sp-2);
  color: var(--c-muted); font-size: var(--fs-xs);
}
.pager .pager-size select { height: 34px; padding: 0 var(--sp-2); font-size: var(--fs-xs); }

table.items input, table.items select { width: 100%; padding: 6px; }
table.items td { padding: 4px; }
/* 明细行里的搜索下拉：td 宽度收窄到内容，输入框自适应 */
table.items td:has(> .ss-wrap), table.items td > .ss-wrap { min-width: 0; }
table.items td { overflow: hidden; }

/* ------------------------------------------------------------------
 * 表格内控件：填充式的例外（规范 §2.4 末尾）
 * 表格已经没有竖线了，如果输入框也变浅灰填充，一整格会连成一片灰块，
 * 用户分不清哪里能输入。所以表格内的控件保持「白底 + 1px 内描边」。
 * 用 box-shadow 而不是 border 做描边：border 会撑高行高，把 52px 的行变 54px。
 * :not(.ss-input) 是必要的 —— .ss-input（可搜索下拉）自带描边，
 * 这里再叠一层会变成 2px 双线。
 * ------------------------------------------------------------------ */
table.grid input:not(.ss-input), table.grid select, table.grid textarea,
table.items input:not(.ss-input), table.items select, table.items textarea {
  background: var(--c-surface);
  box-shadow: inset 0 0 0 1px var(--c-sep);
}
table.grid input:not(.ss-input):hover, table.grid select:hover, table.grid textarea:hover,
table.items input:not(.ss-input):hover, table.items select:hover, table.items textarea:hover {
  background: var(--c-surface);
  box-shadow: inset 0 0 0 1px rgba(60,60,67,.34);
}
table.grid input:not(.ss-input):focus, table.grid select:focus, table.grid textarea:focus,
table.items input:not(.ss-input):focus, table.items select:focus, table.items textarea:focus {
  background: var(--c-surface);
  box-shadow: inset 0 0 0 1.5px var(--c-primary);
}
table.grid input[type=checkbox], table.grid input[type=radio],
table.items input[type=checkbox], table.items input[type=radio] {
  background: transparent; box-shadow: none;
}

/* 登录页：深色渐变 → 纯 systemGroupedBackground（规范 §2.11 原本还要求一层极淡径向光晕，
 * 主理人第六轮裁定去掉：截图里左下角发灰、整片不够干净，干净比「有层次」更重要）。
 * 全站至此没有任何渐变背景，登录卡片的投影自己就能把层次做出来。 */
.login-page { display: flex; align-items: center; justify-content: center; min-height: 100vh;
  background-color: var(--c-bg); }
.login-box { background: var(--c-surface); padding: 40px 36px; border-radius: 20px; width: 380px; max-width: calc(100vw - 32px);
  box-shadow: 0 10px 40px rgba(0,0,0,.08); }
.login-box h1 { font-size: var(--fs-2xl); font-weight: 500; color: var(--c-ink); margin-bottom: var(--sp-5); text-align: center; line-height: 1.3; }
/* 登录页控件比站内大一号：输入 44px / 圆角 12px，按钮同高全宽（规范 §2.11） */
.login-box input { height: 44px; border-radius: var(--r-12); }
.login-box .btn.block { height: 44px; border-radius: var(--r-12); font-size: var(--fs-md); }
.login-box .hint { text-align: center; color: var(--c-faint); font-size: var(--fs-xs); line-height: 1.6; margin-top: var(--sp-3); }

/* badge 不折行：曾经因为列宽太窄，把「生效中」挤成一字一行。
 * iOS 徽章＝纯浅底 + 深字，不加描边（规范 §2.7）。 */
.badge{display:inline-block;padding:1px var(--sp-2);border-radius:var(--r-full);font-size:var(--fs-xs);
  line-height:18px;white-space:nowrap;background:rgba(0,122,255,.12);color:var(--c-primary-d)}
.badge.gray{background:rgba(120,120,128,.14);color:var(--c-gray-ink)}
.badge.red{background:rgba(255,59,48,.14);color:var(--c-danger-ink)}
.badge.green{background:rgba(52,199,89,.16);color:var(--c-success-ink)}
.badge.orange{background:rgba(255,149,0,.16);color:var(--c-warning-ink)}
.badge.blue{background:rgba(48,176,199,.16);color:#0F7A94}

/* 收款进度条 */
.paybar { width: 72px; height: 5px; background: rgba(255,149,0,.16); border-radius: var(--r-full); overflow: hidden; margin-top: var(--sp-1); }
.paybar i { display: block; height: 100%; background: var(--c-warning); border-radius: var(--r-full); }


/* ============ 一键识别 ============ */
/* 虚线框颜色对齐 systemBlue（原来是 tailwind blue-300），底改为极淡主色 */
.pickbox { background: rgba(0,122,255,.05); border: 1px dashed rgba(0,122,255,.30); border-radius: var(--r-lg); padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-4); }
.pickbox-head { margin-bottom: var(--sp-2); font-size: var(--fs-sm); }
.pickbox-head strong { color: var(--c-primary-d); margin-right: var(--sp-2); }
.pickbox textarea { width: 100%; font-size: var(--fs-sm); resize: vertical; }
/* 嵌在「开票信息」面板里的识别框：外面已经有虚线框了，这里用轻一点的样式 */
.pickbox-inline { background: var(--c-surface); border: 1px solid var(--c-line); padding: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-3); }
.pickbox-actions { margin-top: var(--sp-2); display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.pick-tip { font-size: var(--fs-xs); color: var(--c-muted); }
/* 小字提示用深一档的语义色：iOS 亮绿/亮红压在浅底上做 12px 文字读不清 */
.pick-tip.ok { color: var(--c-success-ink); }
.pick-tip.err { color: var(--c-danger-ink); }
.pick-preview { margin-top: var(--sp-2); background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-md); padding: 10px 12px; color: var(--c-text); }
/* 识别结果预览：两列对照，未识别项灰掉，用户一眼看出还缺什么 */
.pick-preview { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 20px; }
.pick-row { display: flex; gap: var(--sp-2); padding: 3px 0; border-bottom: 1px dashed var(--c-line-2); font-size: var(--fs-xs); line-height: 1.6; }
.pick-row .k { flex: none; width: 104px; color: var(--c-muted); }
.pick-row .v { flex: 1; min-width: 0; word-break: break-all; }
.pick-row.miss .v { color: var(--c-faint); }
@media (max-width: 1100px) { .pick-preview { grid-template-columns: 1fr; } }

/* 自动填入的字段闪一下：让用户分清哪些是识别来的、哪些要自己补。
 * iOS 化：旧版是 tailwind 的淡黄 → 淡黄棕两级，和新的中性体系串味；
 * 改用 systemBlue 的极淡底 + 主色内描边，和 .copyblock / 焦点态同族。 */
@keyframes pickFlash {
  from { background-color: var(--c-primary-50); box-shadow: inset 0 0 0 3px rgba(0,122,255,.28); }
  to   { background-color: var(--c-surface);  box-shadow: none; }
}
input.pick-filled, textarea.pick-filled, select.pick-filled { animation: pickFlash 1.6s ease-out; }
label.wide { grid-column: 1 / -1; }

/* ============ 一键复制客户信息 ============ */
/* 描边/底改为 systemBlue 淡色（原为 tailwind blue-100）；左侧 3px 主色条保留（这是区块锚点，不是 iOS 导航竖条） */
.copyblock { background: rgba(0,122,255,.05); border: 1px solid rgba(0,122,255,.18); border-left: 3px solid var(--c-primary); border-radius: var(--r-lg); padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-4); }
.copyblock-head { display: flex; gap: var(--sp-2); align-items: baseline; flex-wrap: wrap; margin-bottom: var(--sp-2); }
.copyblock-head strong { font-size: var(--fs-sm); color: var(--c-primary-d); }
.copyblock-head .muted { font-size: var(--fs-xs); }
.copyblock-tb { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.copyblock-tb th { width: 52px; text-align: left; font-weight: 500; color: var(--c-muted); padding: 4px 6px 4px 0; vertical-align: top; white-space: nowrap; }
.copyblock-tb td { padding: 4px 14px 4px 0; color: var(--c-ink); }
.copyblock-actions { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--c-sep); }
.btn.copied { background: var(--c-success) !important; border-color: var(--c-success) !important; color: #fff !important; }
.copymini { font-size: var(--fs-xs); line-height: 1.55; }
.copymini .cp-phone { margin-left: 6px; color: var(--c-text); }
.copymini .btn { margin-top: 4px; }

/* ------------------------------------------------------------------
 * 表格内输入框宽度收敛
 * 症状：盘点单「实盘数量」、开单「数量/单价」输入框被拉伸到整格，
 *       视觉上很松垮。数字类输入框按内容需要给固定宽度即可。
 * ------------------------------------------------------------------ */
table.grid input[type="number"],
table.grid input.num,
table.items input[type="number"] {
  width: 100%;
  max-width: 120px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
table.grid td.num input[type="number"] { max-width: 110px; }
/* 需要更宽的（如单价带 4 位小数）单独放开 */
table.grid input[type="number"][data-wide] { max-width: 150px; }

/* 表格里的文本输入（备注之类）保持自适应，但别顶满 */
table.grid input[type="text"] { width: 100%; max-width: 100%; }

/* 操作列按钮纵向居中、不换行 */
table.grid td.nowrap { white-space: nowrap; }
table.grid th { white-space: nowrap; }

/* ------------------------------------------------------------------
 * 列宽不足保护：表格内容比容器宽时，不要压缩。
 * 症状：客户名「E2E测试客户」、仓库「主仓库」被挤成一字一行。
 * 做法：表格给一个最小宽度，宽度不够就横向滚动，而不是竖排字。
 * ------------------------------------------------------------------ */
table.grid { min-width: max-content; }
.panel:has(> table.grid) { overflow-x: auto; }
.panel > table.grid { display: table; }

/* 横向滚动条要看得见，否则用户以为列被截断了（销售订单总览的操作列就是这样“消失”的） */
.panel:has(> table.grid) { scrollbar-width: thin; scrollbar-color: rgba(60,60,67,.28) transparent; }
.panel:has(> table.grid)::-webkit-scrollbar { height: 10px; }
.panel:has(> table.grid)::-webkit-scrollbar-thumb { background: rgba(60,60,67,.28); border-radius: 6px; }
.panel:has(> table.grid)::-webkit-scrollbar-thumb:hover { background: rgba(60,60,67,.45); }
.panel:has(> table.grid)::-webkit-scrollbar-track { background: transparent; }

/* 操作列吸附在右侧：表格再宽，「查看 / 发货 / 作废」也永远够得着。
 * 底色必须不透明（要盖住从下面滑过去的列），所以悬停色写成实色 #F7F7F8
 * ＝ rgba(120,120,128,.06) 压在白底上的合成值，和表格行 hover 视觉一致。 */
table.grid.sticky-ops > thead > tr > th:last-child,
table.grid.sticky-ops > tbody > tr > td:last-child {
  position: sticky; right: 0; z-index: 2;
  background: var(--c-surface);
  box-shadow: -8px 0 8px -8px rgba(0,0,0,.06);
}
table.grid.sticky-ops > thead > tr > th:last-child { background: var(--c-surface); }
table.grid.sticky-ops > tbody > tr:hover > td:last-child { background: #F7F7F8; }
/* sticky 操作列右侧「露字」补丁（主理人第八轮，实测发现）：
 * .panel 有 --sp-5(20px) 右内边距，滚动容器的 content box 比面板窄 40px，
 * 而 sticky 的 right:0 只贴到 content box 右边缘 —— 面板 padding 那 20px 会露出
 * 一条被遮列的残影（实测：打印列的「生产 N / 送货 N」徽章就从「作废」右边冒出来）。
 * 用继承背景色的伪元素填满这条缝，hover 时随行色一起变。 */
table.grid.sticky-ops > thead > tr > th:last-child::after,
table.grid.sticky-ops > tbody > tr > td:last-child::after {
  content: ""; position: absolute; top: 0; right: calc(-1 * var(--sp-5));
  width: var(--sp-5); height: 100%;
  background: inherit; border-bottom: inherit;
}
/* 手机档（≤820px）取消操作列吸附（主理人第八轮，实测）：
 * 7 个按钮撑到约 335px，已接近 390 的整屏宽 —— 一旦 sticky，其他列全被推出视野，
 * 屏幕上只剩一列按钮，视觉上等于把表格弄坏了。手机上本来就是横滚看全表，
 * 这里退回 static，与改造前的浏览方式一致。 */
@media (max-width: 820px) {
  table.grid.sticky-ops > thead > tr > th:last-child,
  table.grid.sticky-ops > tbody > tr > td:last-child { position: static; box-shadow: none; }
  table.grid.sticky-ops > thead > tr > th:last-child::after,
  table.grid.sticky-ops > tbody > tr > td:last-child::after { display: none; }
}
/* 文本列不参与挤压 */
table.grid td, table.grid th { overflow-wrap: normal; word-break: keep-all; }

/* ==================================================================
 * 表格视觉优化
 * 问题：行高偏紧、表头与内容对比弱、空数据提示太素。
 * iOS 化（规范 §2.5）：表头透明底、12px/500 灰字、10px 14px padding、
 * 底部 0.5px 实分隔；表体单元格 12px 14px（行高约 52px，「舒适」档）。
 * ================================================================== */
table.grid thead th {
  font-size: var(--fs-xs);
  letter-spacing: .3px;
  color: var(--c-muted);
  font-weight: 500;
  background: transparent;
  padding: 10px 12px;
  border-bottom: .5px solid var(--c-sep-strong);   /* 表头底线单独加粗到 .28：表头 ↔ 内容必须分得开 */
}
table.grid tbody tr:last-child td { border-bottom: 0; }

/* 单据号列：用等宽数字，扫读更快 */
table.grid td a b { font-variant-numeric: tabular-nums; letter-spacing: .2px; }

/* 单据号列（td.no-cell）：
 * 该列只用来看，不参与抢宽度 —— 表头写死 width:150px，剩余宽度由客户列吸收。
 * （试过 width:1% 收口：在这个 min-width:max-content 的表格上会把客户列算成 16000px，
 *  不能用百分比。）单号字号下调、合同号再小一号，1920 下该列从 299 收到 178。 */
table.grid td.no-cell { white-space: nowrap; }
table.grid td.no-cell a b { font-size: 12.5px; letter-spacing: 0; }
table.grid td.no-cell .no-ct {
  font-size: 10.5px; margin-top: 1px;
  max-width: 132px; overflow: hidden; text-overflow: ellipsis;
}

/* 空数据行：各页内联只写了 text-align，颜色/字号从这里统一 */
table.grid td[colspan] { padding: var(--sp-7) var(--sp-3) !important; text-align: center; color: var(--c-faint); font-size: var(--fs-sm); }

/* 表格外的滚动容器（宽表在窄屏横向滚动，不撑破布局） */
.grid-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* 面板标题右侧动作区 */
.panel > h3 + .toolbar { margin-top: -2px; }

/* 金额列统一右对齐 + 等宽数字 */
td.num, th.num { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------
 * 宽表挤压兜底：数字列 / 操作列给最小宽度，宁可横向滚动也不竖排字。
 * （只加强，不放松上面 min-width:max-content + word-break:keep-all）
 * ------------------------------------------------------------------ */
table.grid th.num, table.grid td.num { min-width: 96px; }
table.grid th:last-child, table.grid td:last-child.nowrap { min-width: 132px; }

/* 发货 / 物流列（modules/sales/out.php 的 td.ship-cell）：
 * 里面是「已发货」徽章 + 快递公司 + 物流单号三段，宽度不足时会被压成逐字竖排
 * （基线就是「已 / 中 / 377」这样竖着堆）。给最小宽度兜底，宁可横向滚动也不竖排字 ——
 * 操作列已 sticky 吸附在右侧，够得着。
 * 手机档（≤820px）不收这条：手机本来就要横拖，压窄反而少滚两屏。 */
@media (min-width: 821px) {
  table.grid td.ship-cell, table.grid th.ship-cell { min-width: 92px; white-space: nowrap; }
}

/* ==================================================================
 * 生产进度上报：手机拍照 / 录像 / 录音 / 语音转文字
 * 车间用手机操作，所有可点区域都按 ≥44px 做，避免误触。
 * ================================================================== */
.progress-pick input[type=search] { flex: 0 1 auto; }

/* ---------- 上传按钮条 ---------- */
.pm-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.pm-add {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 0 var(--sp-4);
  border: 1px dashed var(--c-primary); border-radius: var(--r-md);
  background: var(--c-primary-50); color: var(--c-primary-d);
  font-size: var(--fs-md); font-weight: 600; cursor: pointer;
  user-select: none; white-space: nowrap;
}
.pm-add:hover { background: rgba(0,122,255,.12); }
.pm-add:active { transform: scale(.98); }
.pm-add span { pointer-events: none; }
.pm-hint { flex: 1 1 240px; min-width: 200px; font-size: var(--fs-xs); color: var(--c-muted); line-height: 1.6; }
.pm-hint b { color: var(--c-text); }

/* ---------- 待上传预览 ---------- */
.pm-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: var(--sp-2); margin-top: var(--sp-3);
}
.pm-empty {
  grid-column: 1 / -1; padding: var(--sp-4);
  border: 1px dashed var(--c-line); border-radius: var(--r-md);
  color: var(--c-faint); font-size: var(--fs-sm); text-align: center;
}
.pm-item { position: relative; }
/* 媒体占位底仍用深色（要衬托白色播放图标），但由 slate 深蓝换成 iOS 中性黑 #1C1C1E */
.pm-thumb {
  display: flex; align-items: center; justify-content: center;
  width: 100%; aspect-ratio: 1 / 1; overflow: hidden;
  border: 1px solid var(--c-line); border-radius: var(--r-md);
  background: #1C1C1E; color: #F2F2F7;
}
.pm-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pm-play { font-size: 22px; color: #F2F2F7; }
.pm-play-audio { font-size: 20px; }
.pm-thumb-audio { background: #2C2C2E; }
.pm-file { font-size: var(--fs-xs); padding: 0 6px; text-align: center; }
.pm-cap { display: block; margin-top: 2px; font-size: 11px; color: var(--c-faint); text-align: center; }

.pm-del {
  position: absolute; top: -6px; right: -6px;
  width: 24px; height: 24px; line-height: 20px; text-align: center;
  border: 0; border-radius: var(--r-full); cursor: pointer;
  background: rgba(28, 28, 30, .82); color: #fff; font-size: 16px; padding: 0;
}
.pm-del:hover { background: var(--c-danger); }
.pm-progress {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-md); background: rgba(28, 28, 30, .55);
  color: #fff; font-size: var(--fs-sm); font-style: normal; font-weight: 600;
}
.pm-err {
  position: absolute; left: 4px; top: 4px;
  width: 20px; height: 20px; line-height: 20px; text-align: center;
  border-radius: var(--r-full); background: var(--c-danger); color: #fff;
  font-size: 13px; font-style: normal; font-weight: 700; cursor: help;
}
.pm-state { display: inline-block; padding-top: 6px; font-size: var(--fs-sm); color: var(--c-muted); }
.pm-state.busy { color: var(--c-primary); font-weight: 600; }

/* ---------- 时间线里的缩略图 ---------- */
.pm-thumbs { display: flex; flex-wrap: wrap; gap: 6px; }
.pm-thumbs .pm-cell {
  position: relative; display: block; width: 64px; height: 64px;
  border: 1px solid var(--c-line); border-radius: var(--r-sm);
  overflow: hidden; background: #1C1C1E;
}
.pm-thumbs .pm-cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pm-thumbs .pm-video { display: flex; align-items: center; justify-content: center; }
.pm-thumbs .pm-play { font-size: 18px; }
.pm-lock {
  position: absolute; right: 0; bottom: 0;
  padding: 0 4px; font-size: 10px; font-style: normal; line-height: 16px;
  background: rgba(28, 28, 30, .8); color: #fff; border-top-left-radius: var(--r-sm);
}
.pm-file { display: inline-block; padding: 4px 8px; border: 1px solid var(--c-line); border-radius: var(--r-sm); font-size: var(--fs-xs); }
.pm-audios { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.pm-audios audio { height: 34px; max-width: 240px; }

/* 进度时间线：用 fixed 布局，1366 笔记本上也不把「客户可见 / 操作」挤出屏幕。
   说明列放开 CJK 换行（全局 table.grid 是 word-break:keep-all）。
   操作列两个按钮并排 —— 原来是 display:block + width:100%，在 62px 的列里
   会竖着叠成两块，删除键直接被卡片边缘切掉（主理人 2026-11-02 截图）。
   列宽在 progress.php 的 <th> 上给足：时间 128 / 阶段 64 / 媒体 196 /
   可见 66 / 操作 104。 */
table.grid.progress-timeline { min-width: 0; table-layout: fixed; }
table.grid.progress-timeline th,
table.grid.progress-timeline td { padding: 8px 10px; }
table.grid.progress-timeline td.nowrap { white-space: normal; word-break: break-word; }
table.grid.progress-timeline td:nth-child(3) { word-break: normal; overflow-wrap: break-word; line-height: 1.55; }
table.grid.progress-timeline .pm-thumbs .pm-cell { width: 58px; height: 58px; }
table.grid.progress-timeline .pm-audios audio { width: 100%; max-width: 208px; height: 32px; }
table.grid.progress-timeline td:last-child { white-space: nowrap; }
table.grid.progress-timeline td:last-child .btn { display: inline-block; width: auto; text-align: center; margin: 0 6px 0 0; }
table.grid.progress-timeline td:last-child .btn:last-child { margin-right: 0; }

/* 完工后补录的那一条（order_progress.is_supplement=1）：
   整行浅橙底 + 首列橙竖条 + 说明列顶部「后补」文字标签。
   三重冗余不是过度设计 —— 车间强光 + 手机降亮度 + 红绿色盲下，仅靠底色区分不出
   「生产期拍的」和「完工后补的」，文字标签才是最稳的那一路。
   iOS 化：底色改 systemOrange 10% 淡底（--c-supp-bg）、竖条改 --c-supp（#FF9500）、
   标签白底橙字 + rgba(255,149,0,.35) 描边（--c-supp-bd），规范 §2.12。
   结构（竖条 3px、白底标签、文字标签）一律不动。 */
table.grid.progress-timeline tr.is-supp > td { background: var(--c-supp-bg); }
table.grid.progress-timeline tr.is-supp > td:first-child { box-shadow: inset 3px 0 0 var(--c-supp); }
.supp-line { margin-bottom: 4px; line-height: 1.4; }
.supp-flag {
  display: inline-block; padding: 0 5px; margin-right: 4px;
  border: 1px solid var(--c-supp-bd); border-radius: 8px;
  background: var(--c-surface); color: var(--c-warning-ink);
  font-size: var(--fs-xs); font-weight: 600; line-height: 17px; white-space: nowrap;
}
.supp-tip { color: var(--c-warning-ink); font-size: var(--fs-xs); }

/* ---------- 语音 ---------- */
.voice-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-bottom: 6px; }
.voice-btn.recording,
#btnRec.recording {
  background: var(--c-danger); border-color: var(--c-danger); color: #fff;
  animation: voicePulse 1.2s ease-in-out infinite;
}
@keyframes voicePulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 59, 48, .45); }
  50%      { box-shadow: 0 0 0 7px rgba(255, 59, 48, 0); }
}
.voice-state { font-size: var(--fs-sm); color: var(--c-primary-d); }
.voice-tip { margin-top: 6px; font-size: var(--fs-xs); color: var(--c-muted); line-height: 1.7; }
.voice-tip b { color: var(--c-text); }

/* ==================================================================
 * 生产看板（modules/sales/progress.php 未完成 tab）
 * 替代原来的「选择生产送货单」下拉框：整体铺开、按紧急度分色、点一行录进度。
 *
 * 三条硬约束（上一轮踩过的坑）：
 *   1) 行一律 flex + flex-wrap，本块禁止 min-width:max-content ——
 *      那一条会把「录进度 ›」推进屏幕外，390px 手机上出横向滚动条。
 *   2) 不许给 .panel 加 overflow（会裁掉 .ss-list 搜索下拉，见文件头注释）。
 *   3) 状态徽章不复用 .badge：旧版 .badge.red / .badge.orange 的淡红淡橙底，
 *      压在旧版淡红淡橙的行底上等于消失。这里另建 .pb-tag（白底 + 同色描边）。
 *
 * 色板（主理人裁定，不许改成黄色。IOS-DESIGN-SPEC §2.12 改为 iOS 语义浅底）：
 *   已超期      文字 var(--c-danger-ink)  / 底 红 8%  / 无描边 / 竖条 5px #FF3B30
 *   无期限超48h 文字 var(--c-warning-ink) / 底 橙 10% / 无描边 / 竖条 5px 竖向断续 var(--c-supp)
 *   待生产      文字 var(--c-primary-d)  / 底 蓝 7%  / 无描边 / 竖条 5px #007AFF
 *   按时完成    文字 var(--c-success-ink) / 底 绿 9%  / 无描边 / 竖条 5px #34C759
 * 注意：这里「rank1..rank4」是 CSS 侧的历史类名，PHP 里 progress_board_rank() 的编号
 * 与规范的措辞不同（代码 rank1=已超期、rank2=无期限超48h、rank3/4=待生产）。
 * 本次只换色值、不改类名与编号，语义一一对应，见 CHANGES.md。
 * ================================================================== */
.is-rank1 { --pb-fg:var(--c-danger-ink); --pb-bg:rgba(255,59,48,.08); --pb-bd:transparent; --pb-bar:#FF3B30; }
.is-rank2 {
  --pb-fg:var(--c-warning-ink); --pb-bg:rgba(255,149,0,.10); --pb-bd:transparent;
  /* 竖向虚线，不是斜纹：5px 宽的竖条上 135°/3px 斜纹会退化成一条实心暗棕，
     和 rank1 的实心红条看不出区别（三重冗余少一重）。180°/6px 断续在小尺寸下可辨。
     iOS 化只换色（旧深橙 → var(--c-supp)），断续节奏 6/10px 与 5px 条宽原样保留。 */
  --pb-bar: repeating-linear-gradient(180deg,var(--c-supp) 0 6px,transparent 6px 10px);
}
.is-rank3, .is-rank4 { --pb-fg:var(--c-primary-d); --pb-bg:rgba(0,122,255,.07); --pb-bd:transparent; --pb-bar:#007AFF; }
.is-ontime { --pb-fg:var(--c-success-ink); --pb-bg:rgba(52,199,89,.09); --pb-bd:transparent; --pb-bar:#34C759; }
.is-late   { --pb-fg:var(--c-success-ink); --pb-bg:rgba(52,199,89,.09); --pb-bd:transparent; --pb-bar:var(--c-supp); }

/* ---------- 面板头 + 搜索 ---------- */
.prod-board-h { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.prod-board-h h3 { margin: 0; min-width: 0; }
.prod-search { margin: 0 0 0 auto; }
.prod-search input[type=search] { flex: 0 1 auto; min-width: 220px; max-width: 320px; }
.prod-sub { font-size: var(--fs-xs); margin: 2px 0 var(--sp-3); }

/* ---------- 图例（0 单不显示数字，避免满屏 0） ---------- */
.prod-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px var(--sp-3);
  padding: 0 0 var(--sp-3); margin-bottom: var(--sp-3);
  border-bottom: .5px solid var(--c-sep-soft);
}
.prod-lg { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: var(--c-muted); white-space: nowrap; }
.prod-lg i { display: inline-block; width: 10px; height: 10px; border-radius: 2px; flex: 0 0 10px; }
.prod-lg i.lg-1 { background: #FF3B30; }
.prod-lg i.lg-2 { background-color: rgba(255,149,0,.10); background-image: repeating-linear-gradient(180deg,var(--c-supp) 0 6px,transparent 6px 10px); border: 0; }
.prod-lg i.lg-3 { background: #007AFF; }
.prod-lg i.lg-4 { background: #34C759; }
.prod-lg b { font-weight: 700; color: var(--c-text); font-variant-numeric: tabular-nums; }

/* ---------- 分组 ---------- */
.prod-group + .prod-group { margin-top: var(--sp-4); }
.prod-group-h {
  display: flex; align-items: center; gap: 6px;
  margin: 0 0 6px; font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: .3px; color: var(--c-muted);
}
/* 分组标题左侧的类型点：8px 圆点，跟图例的小色块同一套视觉。
   以前是 3px 宽 × 12px 高的竖杠 + --pb-bar（rank2 是斜纹），压到 3px 宽就是一块
   黑褐色小脏点；改用纯色 --pb-fg 画圆点。 */
.prod-group-h i { display: inline-block; flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%; background: var(--pb-fg,rgba(60,60,67,.28)); }

/* ---------- 一行（整行就是一个 <a>） ----------
 * iOS 化（规范 §2.12）：圆角 10→12px、描边隐去（iOS 靠底色区分层级，不描边）、
 * 间距走 var(--c-sep-soft) 之后仍是 6px。flex 换行结构、最小高度、5px 竖条位置全部不动。 */
.prod-row {
  position: relative; display: flex; flex-wrap: wrap; align-items: center;
  gap: 2px var(--sp-3);
  min-height: 46px; padding: 8px 10px 8px 15px;
  border: 1px solid var(--pb-bd, transparent); border-radius: var(--r-12);
  background: var(--pb-bg, var(--c-surface)); color: var(--c-text);
  text-decoration: none; overflow: hidden;
}
.prod-row + .prod-row { margin-top: 6px; }
.prod-row:hover { text-decoration: none; box-shadow: var(--sh-2); border-color: transparent; }
.prod-row.is-active { border-color: transparent; box-shadow: 0 0 0 1.5px var(--c-primary) inset; }
.prod-row.is-active::after {
  content: "当前"; position: absolute; top: 0; right: 0;
  padding: 1px 6px; font-size: 10px; line-height: 14px;
  color: #fff; background: var(--c-primary); border-bottom-left-radius: var(--r-sm);
}
/* 5px 而不是 4px：4px 宽放不下 rank2 的断续图案，实心/断续两档就分不出来了 */
.prod-bar { position: absolute; left: 0; top: 0; bottom: 0; width: 5px; background: var(--pb-bar, rgba(60,60,67,.28)); }

.prod-no {
  flex: 0 0 auto; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--fs-sm); font-weight: 700; letter-spacing: .2px;
  white-space: nowrap; color: var(--pb-fg, var(--c-ink));
}
.prod-cust {
  flex: 1 1 90px; min-width: 0; font-size: var(--fs-sm); color: var(--c-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.prod-due { display: inline-flex; align-items: baseline; gap: 6px; flex: 0 1 auto; min-width: 0; white-space: nowrap; }
.prod-due b { font-size: var(--fs-sm); font-weight: 700; font-variant-numeric: tabular-nums; color: var(--pb-fg, var(--c-ink)); }
.prod-due b.is-none { color: var(--c-muted); font-weight: 500; }
.prod-rel { font-style: normal; font-size: var(--fs-xs); color: var(--c-muted); }
/* 12px 小字用深一档的语义色：iOS 亮橙/亮红做正文对比度不够（见 CHANGES.md 风险项） */
.prod-rel.is-warn { color: var(--c-warning-ink); font-weight: 700; }
.is-rank1 .prod-rel { color: var(--c-danger-ink); font-weight: 700; }

.prod-prog { display: inline-flex; align-items: center; gap: 6px; flex: 0 1 auto; min-width: 0; overflow: hidden; }
.prod-steps { font-size: var(--fs-xs); color: var(--c-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.prod-dots { display: inline-flex; gap: 2px; flex: 0 0 auto; }
.prod-dots i { display: inline-block; width: 8px; height: 8px; border-radius: 2px; background: rgba(60,60,67,.18); }
.prod-dots i.on { background: var(--pb-fg, var(--c-primary)); }
.prod-go { flex: 0 0 auto; margin-left: auto; font-size: var(--fs-xs); font-weight: 700; color: var(--c-primary); white-space: nowrap; }

/* ---------- 状态徽章（白底 + 同色深字，压在浅色行底上不会消失） ----------
 * 规范 §2.12：白底同色字、圆角 8px。iOS 不用描边，所以把原来的 1px 描边去掉。 */
.pb-tag {
  display: inline-flex; align-items: center; flex: 0 0 auto;
  height: 20px; padding: 0 6px; border-radius: 8px;
  border: 0; background: #fff;
  font-size: var(--fs-xs); line-height: 1; white-space: nowrap;
}
.pb-tag.pb-red    { color: var(--c-danger-ink); }
.pb-tag.pb-orange { color: var(--c-warning-ink); }
.pb-tag.pb-blue   { color: var(--c-primary-d); }
.pb-tag.pb-green  { color: var(--c-success-ink); }
.pb-tag.pb-gray   { color: var(--c-gray-ink); }

/* ---------- 标题里的分隔圆点 ----------
 * 不要用字符「·」（U+00B7）：h3 / 加粗标题的字体栈取不到该字面时渲染成豆腐块
 * （改造前「生产进度 · SO…」的截图就是两个豆腐块）。这里用 CSS 画一个 3px 圆点，
 * 任何字体下都不会缺字。只用在 h3 / 分组标题这类标题上下文，正文与 .prod-rel 里的
 * 「·」照旧用字符，那里渲染正常。
 * flex:0 0 3px 是必要的：父元素 h3 是 display:flex，不加会被压成 0 宽。 */
.pb-sep {
  display: inline-block; flex: 0 0 3px; width: 3px; height: 3px; border-radius: 50%;
  background: var(--c-faint); vertical-align: middle; margin: 0 7px;
}

/* ---------- 详情面板标题行（左侧「‹ 返回看板」） ---------- */
.prod-detail-h { display: inline-flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; min-width: 0; }
.prod-detail-h h3 { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* ---------- 已完成表：B1 绿行 / B2 绿底 + 橙色左条 ----------
 * iOS 化：底色换 systemGreen 9% 淡底，悬停加深到 16%，左条换 #34C759 / var(--c-supp)。
 * 4px 左条宽度保留（它是「迟交」的唯一提示，缩到 3px 车间屏上看不见）。 */
table.grid tbody tr.is-ontime > td,
table.grid tbody tr.is-late > td { background: var(--pb-bg); }
table.grid tbody tr.is-ontime:hover > td,
table.grid tbody tr.is-late:hover > td { background: rgba(52,199,89,.16); }
table.grid tbody tr.is-ontime > td:first-child { border-left: 4px solid #34C759; }
table.grid tbody tr.is-late > td:first-child { border-left: 4px solid var(--c-supp); }

/* ---------- 看板手机档（≤820px）：每行转纵向卡片 ----------
 * 单号 + 徽章一行 / 客户一行 / 期限 + 进度一行（「录进度 ›」右对齐）。
 * order 值只在 flex 容器里生效，桌面端不写 order，保持 DOM 顺序。
 * ------------------------------------------------------------------ */
@media (max-width: 820px) {
  .prod-board-h { display: block; }
  .prod-board-h h3 { margin-bottom: var(--sp-2); }
  /* 详情标题：.panel h3 是 display:flex，390 下长单号会被压成一字一行（截图里像竖排）。
     手机端退回块级流，圆点改内联，长单号正常折行。 */
  .prod-detail-h { display: block; }
  .prod-detail-h h3 {
    display: block; overflow: visible; text-overflow: clip;
    font-size: var(--fs-md); line-height: 1.45; word-break: break-word;
    margin-top: 8px;
  }
  .prod-detail-h h3 .pb-sep { display: inline-block; vertical-align: middle; margin: 0 6px; }
  /* 详情页顶部按钮（查看送货单 / 客户扫码页 / 补充照片）宁可换行，也不要挤成歪斜的两列 */
  #detail > .toolbar { flex-wrap: wrap; gap: 6px; }
  #detail > .toolbar > span:last-child { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 100%; }
  /* 搜索框和「筛选」按钮必须同一行：.toolbar 默认 flex-wrap:wrap，390 下按钮会被挤到
     第二行、看着像没做完。这里改为 nowrap，输入框吃掉剩余宽度（min-width:0 才允许收缩），
     按钮不收缩。只作用于 .prod-search 内的 .btn，不动全局 .btn。 */
  .prod-search {
    display: flex; flex-wrap: nowrap; align-items: center; gap: 6px;
    margin: 0;
  }
  .prod-search input[type=search] { flex: 1 1 auto; min-width: 0; max-width: none; }
  .prod-search .btn { flex: 0 0 auto; }
  /* 按钮默认 .btn.sm 是 28px，输入框是 36px，align-items:center 会让两者 top 差 4px
     （视觉上看不出，但「同一行」要能被 top 相等量化）。这里把小按钮抬到 36px 与输入框齐平。
     选择器写成 .prod-search .btn.sm 才压得住 .btn.sm（28px）那条，两级类管不到。
     手机档两者再一起抬到 44px（见下面「手机适配」块），仍然保持同高。 */
  .prod-search .btn.sm { height: 36px; }
  .prod-legend { gap: 4px var(--sp-2); }

  .prod-row { gap: 2px var(--sp-2); min-height: 44px; padding: 9px 8px 9px 14px; }
  .prod-no { order: 1; flex: 1 1 auto; min-width: 0; }
  .prod-row .prod-st { order: 2; margin-left: auto; }
  .prod-cust { order: 3; flex: 1 1 100%; }
  .prod-due  { order: 4; }
  .prod-prog { order: 5; }
  /* 「录进度 ›」在手机上隐藏：整行本身就是 <a>，卡片可点，这 44px 会把每行顶出第 4 行 */
  .prod-go   { order: 6; margin-left: auto; display: none; }
  /* 只隐藏「无交货期」这个占位标签（b.is-none）；有交期时 b 不带 is-none，
     显示「交货 10-28」必须保留 —— 千万别写成 .prod-due b{display:none}。
     理由：紧跟其后的 .prod-rel 已经写着「已等待 N 天 · 无合同」，标签是重复信息。 */
  .prod-due b { font-size: var(--fs-xs); }
  .prod-due b.is-none { display: none; }
  .prod-dots i { width: 7px; height: 7px; }

  table.grid tbody tr.is-ontime > td:first-child,
  table.grid tbody tr.is-late > td:first-child { border-left-width: 3px; }
}

/* ---------- 手机 ---------- */
@media (max-width: 820px) {
  .pm-bar { gap: 6px; }
  .pm-add { flex: 1 1 30%; padding: 0 8px; font-size: var(--fs-sm); }
  .pm-hint { flex-basis: 100%; }
  .pm-grid { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); }
  .pm-thumbs .pm-cell { width: 56px; height: 56px; }
  .progress-pick select { min-width: 0 !important; width: 100%; }
  .progress-pick input[type=search] { min-width: 0 !important; flex: 1 1 100%; }
}

/* 上传按钮里的原生 file 控件必须彻底藏掉：
   app.css 里 `label input { display:block }` 会把 [hidden] 覆盖掉，
   结果按钮里露出「选择文件 未选择文件」。 */
.pm-add input[type=file] {
  position: absolute !important;
  width: 1px !important; height: 1px !important;
  padding: 0 !important; margin: -1px !important;
  overflow: hidden !important; border: 0 !important;
  clip: rect(0 0 0 0) !important; white-space: nowrap !important;
  opacity: 0; pointer-events: none;
}

/* ==================================================================
 * 手机适配（≤820px）：侧边栏收成抽屉
 * 车间用手机上报生产进度，必须先把「进得去、点得到」解决掉。
 * 桌面端完全不受影响：.nav-toggle / .nav-mask 默认 display:none。
 * ================================================================== */
.nav-toggle { display: none; }
.nav-mask   { display: none; }

@media (max-width: 820px) {
  /* 抽屉：252 → 280px，右侧 16px 圆角（规范 §4）。浅色毛玻璃后阴影要更淡，
   * 深色时期的深板岩半透明投影压在白底上会显脏。 */
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0; width: 280px;
    border-radius: 0 16px 16px 0;
    transform: translateX(-100%);
    transition: transform .22s ease;
    z-index: 70;
    box-shadow: 0 0 0 .5px rgba(0,0,0,.08), 2px 0 24px rgba(0,0,0,.12);
    -webkit-overflow-scrolling: touch;
  }
  .sidebar.open { transform: none; }

  /* 遮罩：rgba(0,0,0,.3) + blur(4px)（规范 §4）。blur 让抽屉下面的内容退后一层。 */
  .nav-mask {
    display: block; position: fixed; top: 0; right: 0; bottom: 0; left: 0;
    z-index: 65; background: rgba(0,0,0,.3);
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
    opacity: 0; pointer-events: none; transition: opacity .22s ease;
  }
  .nav-mask.show { opacity: 1; pointer-events: auto; }

  /* 汉堡键：40 → 44px（规范 §4 最小触控），白底描边 → systemFill 填充 */
  .nav-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: var(--tap); height: var(--tap); flex: 0 0 auto; margin-right: 8px; padding: 0;
    border: 0; border-radius: var(--r-md);
    background: var(--c-fill); color: var(--c-primary);
    font-size: 20px; line-height: 1; cursor: pointer;
  }

  /* 手机档按钮一律 44px（规范 §4）。.btn.sm 要单独写一遍：它的两级类权重压得过单类 .btn。
   * 顶栏从 50 → 56px，否则 44px 的汉堡键塞进去只剩 3px 上下边距。 */
  .btn, .btn.sm { height: var(--tap); }
  .topbar { height: 56px; padding: 0 var(--sp-3); justify-content: flex-start; gap: 4px; }
  .topbar .crumb {
    font-weight: 500; font-size: var(--fs-md);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    flex: 1 1 auto; min-width: 0;
  }
  .topbar .userbox { flex: 0 0 auto; gap: var(--sp-2); }
  .topbar .userbox > span { display: none; }   /* 手机上只留「退出」 */
  .content { padding: var(--sp-3); }
  .panel { padding: var(--sp-3); }
  /* 看板搜索行：输入框与「筛选」按钮同高 44px，保持「同一行 top 相等」这条不变量 */
  .prod-search input[type=search], .prod-search .btn.sm { height: var(--tap); }
}

/* ==================================================================
 * 窄屏把「进度时间线」由表格改成一条条的卡片
 * 6 列表格在手机上必须横向拖，照片会被推出屏幕外；
 * 改成卡片后时间 / 阶段 / 说明 / 照片 从上往下排，一屏看全。
 * 断点 820 → 1000：时间 128 + 阶段 64 + 媒体 196 + 可见 66 + 操作 104 已经
 * 占掉 558px，再窄下去「说明」只剩几十像素，不如直接换卡片。
 * ================================================================== */
@media (max-width: 1000px) {
  .panel:has(> table.grid.progress-timeline) { overflow-x: visible; }

  table.grid.progress-timeline { min-width: 0; display: block; }
  table.grid.progress-timeline thead { display: none; }
  table.grid.progress-timeline tbody { display: block; }
  table.grid.progress-timeline tbody tr {
    display: block; padding: var(--sp-3) 0;
    border-bottom: 1px solid var(--c-line);
  }
  table.grid.progress-timeline tbody tr:last-child { border-bottom: 0; padding-bottom: 0; }
  table.grid.progress-timeline tbody td {
    display: block; width: auto !important; min-width: 0 !important;
    border: 0; padding: 2px 0 !important;
  }
  table.grid.progress-timeline tbody td:nth-child(1) { font-size: var(--fs-xs); color: var(--c-faint); }
  table.grid.progress-timeline tbody td:nth-child(2) { margin: 2px 0 4px; }
  table.grid.progress-timeline tbody td:nth-child(3) { font-size: var(--fs-md); line-height: 1.7; }
  table.grid.progress-timeline tbody td:nth-child(4) { margin-top: var(--sp-2); }
  table.grid.progress-timeline tbody td:nth-child(5),
  table.grid.progress-timeline tbody td:nth-child(6) { display: inline-block; margin-top: var(--sp-2); margin-right: var(--sp-2); }
  /* 手机上「可见」和两个按钮并成一行，别竖着叠三行占地方 */
  table.grid.progress-timeline tbody td:last-child .btn {
    display: inline-block; width: auto; text-align: center;
    margin: 0 var(--sp-2) 0 0;
  }
  table.grid.progress-timeline tbody td:last-child .btn:last-child { margin-right: 0; }
}

@media (max-width: 820px) {
  .pm-thumbs .pm-cell { width: 72px; height: 72px; }
  .pm-audios audio { width: 100%; max-width: none; }

  /* 三个上传按钮等分一行，别把第三个挤出屏幕 */
  .pm-bar { gap: 6px; }
  .pm-add { flex: 1 1 0; min-width: 0; padding: 0 4px; font-size: var(--fs-sm); }
}
