/* 肇亮校服管理后台 · 第 2 期新增样式（不覆盖 styles.css） */

.toast {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 99;
  background: #17242d;
  color: #fff;
  padding: 12px 18px;
  border-radius: 10px;
  font-size: 13px;
  max-width: 380px;
  line-height: 1.5;
  box-shadow: 0 12px 32px #17242d33;
}

.toast.warn { background: #854f0b; }
.toast.bad { background: #a32d2d; }

.toolbar { align-items: center; }
.toolbar .search { flex: 1 1 200px; }
.toolbar input.filter, .toolbar select.filter { font: inherit; min-width: 108px; }
.toolbar .grow { flex: 1; }

/* 可编辑下拉框（input + datalist，见 admin.js 的 valueDatalist）：
   原生 datalist 不画箭头，光看和普通文本框一模一样，用户不会去点它。
   补一个背景箭头当提示 —— 点箭头就是点输入框本身，Chromium 会展开候选列表。
   ⚠️ styles.css 的 `.filter` 用了 `background:#fff` 简写，会清掉 background-image，
   所以这里必须用 `.filter.combo` 这种更高优先级的选择器，且 admin.css 在其后加载。 */
.toolbar input.filter.combo {
  padding-right: 26px;
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%237a8a90' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 9px center;
  background-size: 10px 6px;
}

.seg { display: flex; border: 1px solid #d9e1df; border-radius: 8px; overflow: hidden; }
.seg button { border: 0; background: #fff; padding: 9px 13px; font: inherit; cursor: pointer; color: #52626a; }
.seg button.on { background: var(--green); color: #fff; font-weight: 700; }

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.chip { background: #f1f5f4; border: 1px solid #e0e8e6; border-radius: 20px; padding: 4px 11px; font-size: 12px; color: #52626a; }

.kv { display: grid; grid-template-columns: 130px 1fr; gap: 9px 16px; font-size: 13px; margin: 0; }
.kv dt { color: #71818a; }
.kv dd { margin: 0; word-break: break-all; }
/* 资质附件行内的材料说明：<dd> 是 grid 的第二列，内联 small 会被「未上传 / 上传」
   挤在同一行，长文案把行高撑乱还读不清 —— 必须独占一行。 */
.kv dd .attach-hint { display: block; margin-top: 4px; line-height: 1.55; }
/* 「下载模板」是 <a>（其余 .link 都是 <span>，天然没有下划线）：补上才与站内链接同观感 */
a.link { text-decoration: none; }
a.link:hover { text-decoration: underline; }

.diff {
  background: #f7f9f8;
  border: 1px solid #e6eceb;
  border-radius: 8px;
  padding: 10px 12px;
  font-family: ui-monospace, monospace;
  font-size: 12px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-all;
  max-height: 240px;
  overflow: auto;
  color: #294049;
  margin: 0;
}

.map-list { display: grid; gap: 10px; }

.alert-item {
  border: 1px solid #f3d2cf;
  background: #fff8f7;
  border-radius: 10px;
  padding: 13px 15px;
  display: flex;
  gap: 13px;
  align-items: center;
}
.alert-item .grow { flex: 1; }
.alert-item small { color: #9a6a6a; display: block; margin-top: 4px; }

.checklist {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 9px;
  max-height: 330px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 13px;
  margin: 14px 0;
}
.checklist label { display: flex; gap: 8px; align-items: center; font-size: 13px; }

dialog input, dialog select, dialog textarea {
  border: 1px solid #d7e0de;
  border-radius: 8px;
  padding: 10px;
  font: inherit;
  width: 100%;
}
dialog input[type=checkbox] { width: auto; }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }
.form-grid .field.full { grid-column: 1 / -1; }

/* 号型勾选（2026-10-09）：款号规格 / 批次声明 / 赋码三处共用同一套标记。
   `.locked` 用于"已被赋码用过的号型"——它必须看起来就不可改（服务端会以 SIZE_IN_USE 拦），
   所以整条置灰 + 禁止指针，而不是只靠一句提示。 */
.size-picker {
  border: 1px solid #e2eae8;
  border-radius: 10px;
  padding: 10px 12px;
  background: #fafcfb;
  max-height: 210px;
  overflow-y: auto;
}
.size-picker > .muted { margin: 0; }
.size-line { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; padding: 5px 0; }
.size-line + .size-line { border-top: 1px dashed #e8efed; }
.size-line > b { flex: none; width: 34px; font-size: 12px; color: #45585f; }
.size-opt {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12.5px; color: #52626a; cursor: pointer; white-space: nowrap;
}
.size-opt.locked { color: #9aa8ae; cursor: not-allowed; }
.size-count { width: 76px; margin-left: auto; padding: 4px 8px; font: inherit; font-size: 12.5px; }

/* 批次声明里的「号型 + 件数」组合（2026-10-10 老板指令：生产批次要支持设置每种号型多少件）。
   勾选框与它自己的件数框必须**裹在同一格**里：`.size-line` 是 flex-wrap 容器，
   如果两者是平级兄弟，窄屏换行时件数框会跑到下一行、离它对应的号型很远，
   操作员填错行是必然的。 */
.size-unit { display: inline-flex; align-items: center; gap: 4px; }
.size-qty {
  width: 68px; padding: 4px 6px; font: inherit; font-size: 12.5px; text-align: right;
}
/* 未勾选的号型不参与提交，件数框就地置灰 —— 只靠"不读它的值"是隐式的，
   屏幕上必须看得出来它当前无效，否则用户会以为填了也算数。 */
.size-qty:disabled { background: #f4f7f6; color: #a9b5b2; }

/* 批次「产量」的只读汇总（= 各号型件数合计，服务端同口径派生）。
   与 .field input 视觉上一致，但**不是输入框** —— 它算出来是什么就是什么，
   做成可编辑的会让人以为能改，而改了也会被服务端按派生值覆盖。 */
.qty-total {
  border: 1px solid #e6eceb; border-radius: 8px; background: #fafcfb;
  padding: 10px; font-size: 13px; color: #2f3f45; min-height: 40px;
}
.qty-total.warn { border-color: #f0dcb4; background: #fdf8ee; color: #8a6414; }

/* styles.css 里 `.warn` 与 admin.css 里 `.mini` 同权重，而 admin.css 后加载 ⇒
   `.mini.warn` 必须显式提权，否则"未设置件数"这类告警会被 .mini 的灰色盖掉。 */
.mini.warn { color: #8a6414; }
.size-opt + .size-count { margin-left: 0; }

.result-box {
  background: #f2f8f5;
  border: 1px solid #d6ebe2;
  border-radius: 10px;
  padding: 14px 16px;
  font-size: 13px;
  line-height: 1.7;
}
.result-box b { color: var(--green-dark); }
.result-box.bad { background: #fff6f5; border-color: #f3d2cf; }
.result-box.bad b { color: var(--red); }

tbody tr.picked { background: #f4faf7; }
.pick-all { cursor: pointer; }
.empty-cell { text-align: center; color: #71818a; padding: 42px 0; }
.mini { font-size: 12px; color: #71818a; }
.nowrap { white-space: nowrap; }
.stack { display: grid; gap: 14px; }

/* 登录页：验证码与学校选择（第 5 期新增） */
.field select {
  border: 1px solid #d7e0de;
  border-radius: 8px;
  padding: 10px;
  font: inherit;
  background: #fff;
}
.captcha-row { display: flex; align-items: center; gap: 10px; }
.captcha-row input { flex: 1; min-width: 0; letter-spacing: 4px; text-transform: uppercase; }
.captcha-row img {
  height: 44px;
  width: 132px;
  border: 1px solid #d7e0de;
  border-radius: 8px;
  cursor: pointer;
  background: #f1f5f9;
  flex: none;
}
.field small.muted { font-size: 12px; color: #71818a; }

/* 全局请求进度条：任意 api() 调用期间显示，统一加载态（第 3 期收尾） */
#progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 0;
  background: var(--green);
  box-shadow: 0 0 8px #087b6e66;
  z-index: 99;
  opacity: 0;
  transition: opacity .2s;
}
#progress.on {
  opacity: 1;
  width: 70%;
  transition: width 1.6s ease-out, opacity .2s;
}



/* 学生与绑定：一行一名学生，名下多件校服（校服/校裤…）以胶囊并列展示 */
.code-list { display: flex; flex-wrap: wrap; gap: 6px; }
.code-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid #e0e8e6;
  background: #f7faf9;
  border-radius: 9px;
  padding: 5px 9px;
  cursor: pointer;
}
.code-chip:hover { border-color: var(--green); background: #f1f8f5; }
.code-chip b { font-family: ui-monospace, monospace; font-size: 12px; color: #294049; letter-spacing: .3px; }
.code-chip .mini { font-size: 11px; }

/* ================================================================ 登录页
   独立版式：左侧品牌面板 + 右侧表单，窄屏收敛为单列。
   登录态由 body.is-login 标记（login() 加、home() 去），据此隐藏后台顶栏。 */
body.is-login header { display: none; }
body.is-login .page { padding: 0; max-width: none; }

.login-wrap {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 40px 24px;
  background:
    radial-gradient(900px 420px at 10% -10%, #0f7a6c29, transparent 62%),
    radial-gradient(720px 400px at 94% 110%, #0f7a6c1f, transparent 64%),
    linear-gradient(180deg, #f8fbfa, #edf4f2);
}

.login-card {
  width: min(940px, 100%);
  display: grid;
  grid-template-columns: 1.04fr 1fr;
  background: #fff;
  border: 1px solid #e2ebe8;
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 28px 72px -20px #17242d33, 0 5px 16px #17242d0f;
}

/* ---- 左：品牌面板 ---- */
.login-brand {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 38px 36px 30px;
  color: #fff;
  background: linear-gradient(158deg, #0a554c 0%, #087b6e 52%, #10957f 100%);
}
/* 两个柔光圆，避免大面积纯色显得呆板 */
.login-brand::before,
.login-brand::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  background: #ffffff1a;
  pointer-events: none;
}
.login-brand::before { width: 210px; height: 210px; top: -78px; left: -70px; }
.login-brand::after { width: 270px; height: 270px; right: -92px; bottom: -104px; background: #ffffff14; }
.login-brand > * { position: relative; z-index: 1; }

.login-logo {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -.3px;
}
.login-logo .brand-mark { width: 30px; height: 30px; background: #ffffff29; color: #fff; }
.login-logo small { font-size: 9px; letter-spacing: 2px; font-weight: 700; opacity: .66; margin-left: 5px; }

.login-brand h1 { margin: 2px 0 0; font-size: 27px; line-height: 1.4; letter-spacing: -.6px; }
.login-sub { margin: 0; font-size: 13px; line-height: 1.78; color: #ffffffc2; }

.login-points { list-style: none; margin: 2px 0 0; padding: 0; display: grid; gap: 13px; }
.login-points li { display: flex; gap: 11px; align-items: flex-start; }
.login-points i {
  flex: none;
  width: 22px; height: 22px;
  border-radius: 7px;
  background: #ffffff26;
  display: grid; place-items: center;
  font-size: 11px; font-style: normal; font-weight: 700;
}
.login-points b { display: block; font-size: 13px; margin-bottom: 2px; }
.login-points span { display: block; font-size: 12px; line-height: 1.6; color: #ffffffb0; }

.login-copy { margin-top: auto; font-size: 11px; color: #ffffff8a; }

/* ---- 右：表单 ---- */
.login-main { display: flex; flex-direction: column; padding: 40px 40px 32px; }
.login-head h2 { margin: 0 0 6px; font-size: 22px; letter-spacing: -.4px; }
.login-head p { margin: 0; font-size: 13px; color: var(--muted); }

.login-fields { flex: 1; }
.login-fields .field { margin: 18px 0 0; }
.login-fields .field label { font-size: 12px; font-weight: 700; color: #45585f; }
.login-fields .field input,
.login-fields .field select {
  height: 44px;
  font-size: 14px;
  border: 1px solid #dbe4e1;
  border-radius: 10px;
  background: #fbfdfc;
  transition: border-color .16s, box-shadow .16s, background .16s;
}
.login-fields .field input:hover,
.login-fields .field select:hover { border-color: #c2d5d0; }
.login-fields .field input:focus,
.login-fields .field select:focus {
  outline: 0;
  background: #fff;
  border-color: var(--green);
  box-shadow: 0 0 0 3.5px #087b6e21;
}

.login-err {
  margin: 16px 0 0;
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--red);
  background: #fdf3f2;
  border: 1px solid #f4d9d6;
  border-radius: 9px;
}
.login-err:empty { display: none; }

/* 密码显隐：输入框右侧贴一个文字按钮（须显式 width:100%，因为外面多了一层包裹） */
.pwd-wrap { position: relative; }
.pwd-wrap input { width: 100%; padding-right: 58px; }
.pwd-toggle {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  padding: 6px 8px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  font: inherit;
  font-size: 12px;
  color: var(--green-dark);
  cursor: pointer;
}
.pwd-toggle:hover { background: #eef8f4; }

.login-submit {
  width: 100%;
  height: 46px;
  margin-top: 22px;
  border-radius: 10px;
  font-size: 15px;
  letter-spacing: 2px;
  box-shadow: 0 8px 20px -7px #087b6e8f;
  transition: transform .12s, box-shadow .16s, background .16s;
}
.login-submit:hover { box-shadow: 0 11px 26px -7px #087b6e9e; }
.login-submit:active { transform: translateY(1px); }

/* 演示账号胶囊（.login-demo / .login-chips / .demo-chip）随凭据泄露问题于 2026-09-28 一并移除，
   样式不留残骸 —— 留着的死样式最容易让人误以为这个功能还在。 */

@media (max-width: 860px) {
  .login-card { grid-template-columns: 1fr; }
  .login-brand { gap: 14px; padding: 26px 24px 22px; }
  .login-brand h1 { font-size: 21px; }
  .login-points, .login-copy { display: none; }
  .login-main { padding: 26px 22px 24px; }
}
@media (max-width: 520px) {
  .login-wrap { padding: 0; place-items: stretch; }
  .login-card { min-height: 100dvh; border: 0; border-radius: 0; }
}

/* ================================================================ 顶部菜单
   当前页高亮：nav(key) 给选中项加 .active（并标 aria-current="page"）。
   子页面（如码详情 / 码历史）传给父菜单 key，因此仍高亮所属菜单。 */
.nav-bar { margin-bottom: 20px; flex-wrap: wrap; }
.nav-btn { transition: background .15s, border-color .15s, color .15s, box-shadow .15s; }
.nav-btn:hover { border-color: var(--green); color: var(--green-dark); background: #f4faf8; }
.nav-btn.active,
.nav-btn.active:hover {
  background: var(--green);
  border-color: var(--green);
  color: #fff;
  box-shadow: 0 6px 15px -7px #087b6e99;
}
.nav-btn.active:focus-visible { outline: 2px solid var(--green-dark); outline-offset: 2px; }

/* ---- 界面打磨（2026-09-22 界面体检后追加） ---- */

/* 禁用态按钮：此前「删除方案」在没有任何已存方案时也可点，点了只会报错。
   全站原本没有 button:disabled 规则，disabled 属性形同虚设。 */
button:disabled { opacity: .45; cursor: not-allowed; }
button:disabled:hover { border-color: var(--border, #d8ddd9); color: inherit; background: inherit; }

/* 双列卡片各自贴合内容高度：工作台「数据缺口待办」（常 3~4 条）与「最新溯源码」（6 条）
   等高拉伸时，内容少的一侧下方留出一大块空白，看起来像页面没加载完。 */
.grid { align-items: start; }

/* 柱状图柱宽封顶：只有 1~2 天有数据时，flex:1 的单根柱会撑满整行，
   看起来像一块色板而不是图表（真实发生过：数据只有一天时趋势图成了一整块绿）。 */
.chart .bar { max-width: 64px; }

/* 宽版弹窗（2026-10-09）：质检报告 PDF 识别后要在弹窗里预览 20+ 条检测明细，
   6 列挤进默认的 480px 会变成竖条，预览就失去意义。 */
dialog.wide { width: min(1040px, calc(100% - 32px)); }

/* 明细预览：固定表头 + 内部滚动。为什么限高而不是让它把弹窗撑长：
   21 条明细能把页面顶到屏幕外，底部的「保存」按钮就点不到了 —— 用户会以为卡住。 */
.item-preview {
  max-height: 260px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 8px;
  margin-top: 6px;
}
.item-preview table { min-width: 720px; }
.item-preview th {
  position: sticky; top: 0; z-index: 1;
  background: #f7f9f8; font-size: 11.5px; padding: 8px 10px;
}
.item-preview td { padding: 7px 10px; font-size: 12px; }
.item-preview .part { color: var(--muted); }

/* PDF 识别结果条：成功/失败要一眼可辨，而不是混在普通说明文字里 */
.parse-note { margin: 6px 0 0; font-size: 12.5px; line-height: 1.6; }
.parse-note.ok { color: #0b725e; }
.parse-note.warn { color: #8a6414; }
.parse-note.bad { color: #b43c3c; }
