:root{
  --ink-900:#0f172a; --ink-700:#334155; --ink-500:#64748b; --ink-300:#cbd5e1; --ink-100:#f1f5f9;
  --paper:#ffffff; --bg:#eef1f8; --accent:#4338ca; --accent-2:#6366f1; --accent-soft:#eef2ff; --line:#e6e9f2; --radius:14px;
  --danger:#e11d48; --danger-soft:#fff1f2; --success:#16a34a; --success-soft:#f0fdf4; --warn:#ca8a04; --warn-soft:#fefce8;
  --shadow-xs:0 1px 2px rgba(15,23,42,.04);
  --shadow-sm:0 1px 3px rgba(15,23,42,.06), 0 1px 2px rgba(15,23,42,.05);
  --shadow-md:0 10px 24px -8px rgba(30,41,89,.16), 0 2px 6px rgba(30,41,89,.06);
  --shadow-lg:0 24px 48px -16px rgba(30,41,89,.28), 0 4px 12px rgba(30,41,89,.08);
  --shadow-inset:inset 0 1px 0 rgba(255,255,255,.6);
}
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
body{
  background:
    radial-gradient(1100px 520px at 100% -8%, rgba(99,102,241,.10), transparent 60%),
    radial-gradient(900px 480px at -10% 110%, rgba(67,56,202,.08), transparent 55%),
    var(--bg);
  color:var(--ink-900);
  font-family:"PingFang SC","Microsoft YaHei","Noto Sans SC","Helvetica Neue",Arial,sans-serif;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none;}
*, *::before, *::after{transition:background-color .15s ease, box-shadow .15s ease, transform .15s ease, opacity .15s ease, border-color .15s ease;}

.layout{display:flex;min-height:100vh;}
.sidebar{
  width:236px; background:linear-gradient(165deg,#26224e 0%,#312e81 46%,#4338ca 100%); color:#fff;
  flex-shrink:0; padding:24px 14px; display:flex; flex-direction:column;
  max-height:100vh; overflow-y:auto; -webkit-overflow-scrolling:touch; position:sticky; top:0;
  box-shadow:4px 0 24px -8px rgba(15,12,50,.35);
}
.sidebar::-webkit-scrollbar{width:6px;}
.sidebar::-webkit-scrollbar-thumb{background:rgba(255,255,255,.18);border-radius:6px;}
.sidebar .brand-card{
  background:rgba(255,255,255,.07); border:1px solid rgba(255,255,255,.14);
  border-radius:14px; padding:12px 14px; margin-bottom:22px;
  display:flex; align-items:center; gap:11px;
  box-shadow:var(--shadow-inset);
}
.sidebar .brand-logo{
  height:32px;width:auto;flex-shrink:0;border-radius:8px;background:#fff;padding:4px 6px;
  box-shadow:0 4px 12px -2px rgba(0,0,0,.25);
}
.sidebar .brand-title{font-size:13.5px;font-weight:750;line-height:1.3;letter-spacing:.01em;}
.sidebar nav{display:flex;flex-direction:column;gap:2px;flex:1;}
.sidebar nav .nav-group{font-size:10.5px;text-transform:uppercase;letter-spacing:.08em;opacity:.5;margin:16px 12px 6px;font-weight:600;}
.sidebar nav .nav-group:first-child{margin-top:0;}
.sidebar nav a{
  padding:9px 12px;border-radius:9px;font-size:13px;color:rgba(255,255,255,.82);
  display:flex;align-items:center;gap:9px;position:relative;font-weight:500;
}
.sidebar nav a:hover{background:rgba(255,255,255,.09);color:#fff;}
.nav-emoji{
  display:inline-flex;align-items:center;justify-content:center;
  width:18px;flex-shrink:0;font-size:14px;line-height:1;
  font-family:"Segoe UI Emoji","Apple Color Emoji","Noto Color Emoji",sans-serif;
}
.sidebar nav a.active{
  background:linear-gradient(90deg,rgba(255,255,255,.20),rgba(255,255,255,.09));
  color:#fff;font-weight:700;box-shadow:var(--shadow-inset), 0 2px 10px -2px rgba(0,0,0,.25);
}
.sidebar nav a.active::before{
  content:"";position:absolute;left:-14px;top:50%;transform:translateY(-50%);
  width:4px;height:18px;border-radius:0 4px 4px 0;background:#c7d2fe;
  box-shadow:0 0 10px 1px rgba(199,210,254,.8);
}
/* 侧边栏模块的悬停子菜单（目前只有"成品检验OQC"用到）：子菜单本体被JS挪到<body>下用
   position:fixed定位（.sidebar是overflow-y:auto的滚动容器，绝对定位的子菜单会被裁掉），
   这里只负责触发链接上的小箭头和子菜单卡片本身的外观。 */
.nav-hoverable{position:relative;}
.nav-caret{margin-left:auto;opacity:.55;font-size:11px;}
.nav-external-hint{margin-left:auto;opacity:.55;font-size:12px;}
.nav-flyout{
  display:none;position:fixed;z-index:40;min-width:170px;padding:6px;
  background:#fff;border-radius:12px;box-shadow:0 12px 32px -8px rgba(15,12,50,.35);
  border:1px solid var(--line);
}
.nav-flyout.show{display:block;}
.nav-flyout a{
  display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:8px;
  font-size:13px;color:var(--ink-700);font-weight:500;
}
.nav-flyout a:hover{background:var(--ink-50,#f7f8fa);}
.nav-flyout .nav-emoji{color:inherit;}
.sidebar .userbox{
  font-size:12px;opacity:.92;border-top:1px solid rgba(255,255,255,.14);padding-top:16px;margin-top:12px;
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
}
.sidebar .userbox .avatar{
  width:34px;height:34px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(135deg,#818cf8,#a5b4fc);color:#26224e;font-weight:700;font-size:13px;
  box-shadow:var(--shadow-inset), 0 2px 8px rgba(0,0,0,.2);
}
.sidebar .userbox .who{flex:1;min-width:0;}
.sidebar .userbox .who .role{opacity:.65;font-size:11px;}
.sidebar .userbox form{width:100%;margin-top:2px;}
.sidebar .userbox button{
  width:100%;background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.14);color:#fff;padding:7px 10px;border-radius:8px;
  font-size:12px;cursor:pointer;font-weight:600;
}
.sidebar .userbox button:hover{background:rgba(255,255,255,.2);}
.sidebar .userbox .change-password-link{
  width:100%;display:block;box-sizing:border-box;background:transparent;border:1px solid rgba(255,255,255,.14);color:#fff;
  padding:7px 10px;border-radius:8px;font-size:12px;cursor:pointer;font-weight:600;text-align:center;text-decoration:none;
  margin-top:2px;opacity:.85;
}
.sidebar .userbox .change-password-link:hover{background:rgba(255,255,255,.12);opacity:1;}

.main{flex:1;padding:28px 34px;max-width:1240px;}
.topbar{
  display:flex;justify-content:space-between;align-items:center;margin-bottom:24px;
  padding-bottom:16px;border-bottom:1px solid var(--line);
}
.topbar h1{font-size:21px;margin:0;font-weight:700;letter-spacing:-.01em;}
.topbar .crumb{font-size:12.5px;color:var(--ink-500);margin-top:3px;}
.topbar-actions{display:flex;align-items:center;gap:12px;flex-wrap:wrap;}
.lang-switch{
  display:inline-flex;background:var(--ink-100);border-radius:999px;padding:3px;gap:2px;
  box-shadow:inset 0 1px 2px rgba(15,23,42,.06);flex-shrink:0;white-space:nowrap;
}
.lang-switch a{
  padding:6px 13px;border-radius:999px;font-size:12px;font-weight:700;color:var(--ink-500);
  white-space:nowrap;
}
.lang-switch a.active{background:#fff;color:var(--accent);box-shadow:var(--shadow-xs);}
.lang-switch a:hover:not(.active){color:var(--ink-700);}

.login-wrap .lang-switch-float{position:absolute;top:22px;right:26px;z-index:2;}
.login-wrap .lang-switch-float .lang-switch{background:rgba(255,255,255,.14);}
.login-wrap .lang-switch-float .lang-switch a{color:rgba(255,255,255,.8);}
.login-wrap .lang-switch-float .lang-switch a.active{background:#fff;color:var(--accent);}

.card{
  background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);
  padding:22px 24px;margin-bottom:20px;box-shadow:var(--shadow-sm);
}
.card h2{font-size:15.5px;margin:0 0 14px;font-weight:700;letter-spacing:-.01em;}

.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin-bottom:22px;}
.kpi{
  background:linear-gradient(165deg,#ffffff, #fbfbff);
  border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px;
  box-shadow:var(--shadow-sm);position:relative;overflow:hidden;
}
.kpi::after{
  content:"";position:absolute;top:0;left:0;right:0;height:3px;
  background:linear-gradient(90deg,var(--accent-2),var(--accent));
}
.kpi:hover{box-shadow:var(--shadow-md);transform:translateY(-2px);}
.kpi .num{font-size:25px;font-weight:800;color:var(--accent);letter-spacing:-.02em;}
.kpi .label{font-size:12.5px;color:var(--ink-500);margin-top:3px;}
.kpi.danger::after{background:linear-gradient(90deg,#fb7185,var(--danger));}
.kpi.danger .num{color:var(--danger);}
.kpi.warn::after{background:linear-gradient(90deg,#fbbf24,var(--warn));}
.kpi.warn .num{color:var(--warn);}
.kpi.success::after{background:linear-gradient(90deg,#4ade80,var(--success));}
.kpi.success .num{color:var(--success);}
.kpi.muted::after{background:var(--ink-300);}
.kpi.muted .num{color:var(--ink-500);}
.kpi .idx{font-size:11px;font-weight:800;color:var(--ink-300);letter-spacing:.02em;}
.kpi .metric-name{font-size:13px;font-weight:700;color:var(--ink-700);margin:2px 0 10px;}

.day-bar{display:flex;flex-wrap:wrap;gap:2px;}
.day-cell{width:9px;height:16px;border-radius:2px;background:var(--ink-100);flex:none;}
.day-cell.ok{background:var(--success);}
.day-cell.warn{background:var(--warn);}
.day-cell.bad{background:var(--danger);}

table{width:100%;border-collapse:collapse;font-size:13.3px;}
th,td{text-align:left;padding:11px 12px;border-bottom:1px solid var(--line);vertical-align:top;}
th{background:var(--ink-100);color:var(--ink-700);font-weight:700;font-size:12px;white-space:nowrap;letter-spacing:.01em;}
th:first-child{border-top-left-radius:8px;}
th:last-child{border-top-right-radius:8px;}
tr:hover td{background:#f7f8ff;}
.table-wrap{overflow-x:auto;border-radius:10px;}
/* 表格列很多、需要横向滚动时，把"操作"这一列固定在右边，滚动的时候查看/操作按钮
   始终看得见，不用非得滚到最右边才能点——目前只给文档管理知识库的文件台账用，
   按需加到别的表格上（加 table-sticky-actions 这个class就行）。
   注意：table默认width:100%会让浏览器把所有列硬挤进容器宽度里（不会真正横向溢出/
   滚动），这样"操作"列一sticky就会跟旁边被挤扁的列重叠。这里给个min-width撑开表格，
   让.table-wrap的overflow-x:auto真正生效成横向滚动，而不是挤压列宽。*/
.table-sticky-actions{width:auto;min-width:100%;}
.table-sticky-actions th,.table-sticky-actions td{white-space:nowrap;}
.table-sticky-actions th:last-child,.table-sticky-actions td:last-child{
  position:sticky;right:0;background:var(--paper);box-shadow:-6px 0 8px -6px rgba(0,0,0,.12);white-space:nowrap;
}
.table-sticky-actions thead th:last-child{background:var(--ink-100);}
.table-sticky-actions tbody tr:hover td:last-child{background:#f7f8ff;}

/* 列很多、内容长（比如车间/仓库全称）又不需要固定右侧操作列的表格，同样需要撑开
   min-width才能让.table-wrap的overflow-x:auto真正横向滚动，而不是把每个长文本单元格
   挤压成多行、行高暴涨——2026-09-14按用户反馈（原始数据查询"报废/调拨/入库"等明细表）
   补上这个轻量版（没有sticky-actions那个固定列的部分）。*/
.table-nowrap{width:auto;min-width:100%;}
.table-nowrap th,.table-nowrap td{white-space:nowrap;}

/* 表格很长时，横向滚动条只会出现在表格最底下（原生行为），要滚到看完全部数据行才摸得到——
   2026-09-14按用户反馈，在.table-wrap上方补一条常驻的"假"横向滚动条，跟真正的表格滚动
   双向同步，不用先滚到底才能横向拖动。宽度由JS按表格实际scrollWidth撑开，具体逻辑见
   base.html的qmsInitTopScrollbars()。*/
.table-topscroll{overflow-x:auto;overflow-y:hidden;height:14px;margin-bottom:6px;}
.table-topscroll>div{height:1px;}

.btn{
  display:inline-flex;align-items:center;gap:6px;padding:9px 17px;border-radius:9px;font-size:13px;font-weight:700;
  border:1px solid transparent;cursor:pointer;color:#fff;letter-spacing:.01em;
  background:linear-gradient(165deg,var(--accent-2),var(--accent));
  box-shadow:0 1px 2px rgba(67,56,202,.15), 0 4px 12px -4px rgba(67,56,202,.55);
}
.btn:hover{transform:translateY(-1px);box-shadow:0 2px 4px rgba(67,56,202,.18), 0 8px 18px -4px rgba(67,56,202,.6);}
.btn:active{transform:translateY(0);}
.btn.secondary{
  background:linear-gradient(165deg,#ffffff,#fafaff);color:var(--ink-700);border-color:var(--line);
  box-shadow:var(--shadow-xs);
}
.btn.secondary:hover{box-shadow:var(--shadow-sm);border-color:var(--ink-300);}
.btn.danger{background:linear-gradient(165deg,#fb7185,var(--danger));box-shadow:0 4px 12px -4px rgba(225,29,72,.55);}
.btn.success{background:linear-gradient(165deg,#4ade80,var(--success));box-shadow:0 4px 12px -4px rgba(22,163,74,.5);}
.btn.sm{padding:5px 12px;font-size:12px;}

.badge{display:inline-block;padding:3.5px 11px;border-radius:999px;font-size:12px;font-weight:700;letter-spacing:.01em;}
.badge.gray{background:var(--ink-100);color:var(--ink-700);}
.badge.blue{background:var(--accent-soft);color:var(--accent);}
.badge.red{background:var(--danger-soft);color:var(--danger);}
.badge.green{background:var(--success-soft);color:var(--success);}
.badge.yellow{background:var(--warn-soft);color:var(--warn);}
.badge.purple{background:#f3e8ff;color:#7e22ce;}

.tab-bar{display:flex;gap:6px;border-bottom:1px solid var(--line);}
.tab-bar .tab-item{
  padding:9px 16px;font-size:13.5px;font-weight:600;color:var(--ink-700);text-decoration:none;
  border-bottom:2px solid transparent;margin-bottom:-1px;
}
.tab-bar .tab-item:hover{color:var(--accent);}
.tab-bar .tab-item.active{color:var(--accent);border-bottom-color:var(--accent);}

form.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;}
form.form-grid .full{grid-column:1/-1;}
.field{display:flex;flex-direction:column;gap:6px;margin-bottom:2px;}
.field label{font-size:12.5px;font-weight:700;color:var(--ink-700);}
.field input, .field select, .field textarea{
  width:100%;max-width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:9px;font-size:13.5px;font-family:inherit;background:#fff;
  box-shadow:var(--shadow-xs);
}
.field input:focus, .field select:focus, .field textarea:focus{
  outline:none;border-color:var(--accent-2);box-shadow:0 0 0 3px rgba(99,102,241,.15);
}
.field textarea{resize:vertical;min-height:70px;}
.actions-row{display:flex;gap:10px;margin-top:6px;}

/* 全站输入框+建议列表自绘下拉（见 base.html 里的 qmsPersonPickerInit）：手机浏览器对
   原生 datalist 弹出建议基本不支持，改成自己画一个悬浮列表，跟桌面端行为一致。
   position:fixed+挂到<body>下（JS里用getBoundingClientRect()量出输入框位置摆过去），
   不用position:absolute相对本地小容器定位——不然一旦这个输入框所在的卡片/表格容器有
   overflow:hidden/auto（比如.table-wrap、.sidebar那种滚动容器），建议列表会被裁掉或被
   后面的卡片盖住，跟.nav-flyout之前踩过的坑是同一个原因、同一个解法。 */
.combo-suggest-box{
  position:fixed;z-index:9999;
  background:var(--paper);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow-md);
  max-height:240px;overflow-y:auto;display:none;
}
.combo-suggest-item{padding:9px 12px;font-size:13px;color:var(--ink-900);cursor:pointer;}
.combo-suggest-item:hover, .combo-suggest-item:active{background:var(--accent-soft);}
.combo-suggest-item + .combo-suggest-item{border-top:1px solid var(--line);}

/* 紧凑横排字段：几个短小的数字/文本框（如抽检数量、AC/RE）横向并排展示，即使在手机端
   也不希望像 form-grid 那样在窄屏下被强制变成一列一个、占满一整行、要来回滚动。所有框统一
   同一个基准宽度、等比例伸缩，让整排（方法/工具、抽检数量、不良数量、AQL值、检验水平、
   允收数AC、拒收数RE共7项）平均分布，不会有的宽有的窄。 */
.compact-row{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:6px;grid-column:1/-1;}
.compact-row .field{min-width:0;margin-bottom:0;}
.compact-row .field label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.compact-row .field input,.compact-row .field select{width:100%;min-width:0;padding:8px 4px;font-size:12px;text-align:center;}

/* 横向条形图：合格率/不合格次数排行的可视化，不引入第三方图表库。合格率类的条默认用
   主题色，低于90%（质量偏低，需要重点盯防）改用danger红色，颜色之外仍然有数值文字，
   不是只靠颜色传达信息。 */
.bar-chart{display:flex;flex-direction:column;gap:10px;}
.bar-row{display:grid;grid-template-columns:minmax(70px,150px) 1fr 54px;align-items:center;gap:10px;}
.bar-row .bar-label{font-size:12.5px;color:var(--ink-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.bar-track{background:var(--ink-100);border-radius:999px;height:14px;overflow:hidden;}
.bar-fill{height:100%;border-radius:999px;background:linear-gradient(90deg,var(--accent-2),var(--accent));}
.bar-fill.danger{background:linear-gradient(90deg,#fb7185,var(--danger));}
.bar-value{font-size:12.5px;font-weight:700;color:var(--ink-700);text-align:right;}
@media (max-width:480px){
  .bar-row{grid-template-columns:minmax(60px,90px) 1fr 46px;gap:6px;}
}

/* 尺寸类实测值：每个样品一个小格子，横向排列、自动换行 */
.dim-samples-row{display:flex;flex-wrap:wrap;gap:8px;}
.dim-samples-row input{
  width:64px;padding:8px 6px;border:1px solid var(--line);border-radius:8px;font-size:13px;text-align:center;
  font-family:inherit;background:#fff;box-shadow:var(--shadow-xs);
}

.login-wrap{
  min-height:100vh;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;
  background:linear-gradient(135deg,#1e1b4b 0%,#312e81 40%,#4338ca 75%,#6366f1 100%);
}
.login-wrap::before, .login-wrap::after{
  content:"";position:absolute;border-radius:50%;filter:blur(60px);opacity:.5;
}
.login-wrap::before{width:420px;height:420px;background:#818cf8;top:-140px;right:-100px;}
.login-wrap::after{width:380px;height:380px;background:#4f46e5;bottom:-160px;left:-100px;}
.login-card{
  position:relative;z-index:1;
  background:rgba(255,255,255,.96);backdrop-filter:blur(6px);
  border-radius:20px;padding:42px 40px;width:370px;
  box-shadow:var(--shadow-lg), 0 0 0 1px rgba(255,255,255,.4) inset;
}
.login-card .card-logo{height:40px;width:auto;display:block;margin:0 auto 18px;}
.login-card h1{font-size:19px;margin:0 0 4px;font-weight:800;letter-spacing:-.01em;text-align:center;}
.login-card p.sub{color:var(--ink-500);font-size:13px;margin:0 0 22px;text-align:center;}
.login-card .field{margin-bottom:14px;}
.login-card .btn{width:100%;justify-content:center;padding:11px;margin-top:6px;font-size:14px;}
.demo-accounts{margin-top:18px;padding-top:14px;border-top:1px solid var(--line);font-size:11.5px;color:var(--ink-500);}
.demo-accounts code{background:var(--ink-100);padding:1px 5px;border-radius:4px;}

.lock-card{width:400px;text-align:center;}
.lock-icon{
  width:56px;height:56px;border-radius:16px;margin:0 auto 16px;display:flex;align-items:center;justify-content:center;
  font-size:26px;background:linear-gradient(165deg,#fde68a,#f59e0b);
  box-shadow:0 6px 18px -4px rgba(245,158,11,.55), var(--shadow-inset);
}
.lock-card h1{text-align:center;}
.lock-card .field{text-align:left;}
.lock-card .demo-accounts{text-align:left;}
.lock-back{display:block;margin-top:16px;font-size:12.5px;color:var(--ink-500);text-align:center;}
.lock-back:hover{color:var(--accent);}

.alert{padding:13px 16px;border-radius:11px;font-size:13px;margin-bottom:18px;box-shadow:var(--shadow-xs);}
.alert.error{background:var(--danger-soft);color:var(--danger);border:1px solid #fecdd3;}
.alert.success{background:var(--success-soft);color:var(--success);border:1px solid #bbf7d0;}
.alert.warn{background:var(--warn-soft);color:var(--warn);border:1px solid #fde68a;}
.alert code{background:rgba(0,0,0,.06);padding:1px 6px;border-radius:5px;}

.detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 24px;font-size:13.5px;}
.detail-grid .k{color:var(--ink-500);font-size:12px;margin-bottom:2px;}
.detail-grid .v{color:var(--ink-900);}
.detail-grid .full{grid-column:1/-1;}

.filter-bar{display:flex;gap:10px;margin-bottom:16px;flex-wrap:wrap;align-items:center;}
.filter-bar select, .filter-bar input{padding:8px 11px;border:1px solid var(--line);border-radius:9px;font-size:13px;background:#fff;box-shadow:var(--shadow-xs);}

.empty{color:var(--ink-500);font-size:13.5px;padding:30px 0;text-align:center;}

/* ---- 驾驶舱看板 ---- */
.cockpit-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:16px;margin-bottom:16px;}
.cockpit-grid > *{min-width:0;}
/* 每个模块单独占一行，不跟其它模块并排挤在一起 */
.cockpit-grid-1col{grid-template-columns:1fr;}
.section-card h2{display:flex;align-items:center;justify-content:space-between;font-size:14.5px;}
.section-card h2 .tag{font-size:11px;font-weight:500;color:var(--ink-500);}
.mini-kpis{display:flex;gap:18px;flex-wrap:wrap;margin-bottom:14px;}
.mini-kpis .mini{min-width:70px;}
.mini-kpis .mini .n{font-size:20px;font-weight:800;color:var(--accent);}
.mini-kpis .mini.danger .n{color:var(--danger);}
.mini-kpis .mini.warn .n{color:var(--warn);}
.mini-kpis .mini.success .n{color:var(--success);}
.mini-kpis .mini .l{font-size:11.5px;color:var(--ink-500);margin-top:1px;}
.bar-row{display:flex;align-items:center;gap:10px;margin-bottom:10px;font-size:12.5px;}
.bar-row .bar-label{width:98px;flex-shrink:0;color:var(--ink-700);}
.bar-row .bar-track{flex:1;height:9px;background:var(--ink-100);border-radius:99px;overflow:hidden;box-shadow:inset 0 1px 2px rgba(15,23,42,.08);}
.bar-row .bar-fill{height:100%;background:linear-gradient(90deg,#6366f1,#4338ca);border-radius:99px;}
.bar-row .bar-fill.danger{background:linear-gradient(90deg,#fb7185,#e11d48);}
.bar-row .bar-fill.warn{background:linear-gradient(90deg,#fbbf24,#ca8a04);}
.bar-row .bar-val{width:78px;flex-shrink:0;text-align:right;color:var(--ink-900);font-weight:700;}
.grade-pills{display:flex;gap:8px;flex-wrap:wrap;}
.grade-pill{flex:1;min-width:56px;text-align:center;padding:11px 6px;border-radius:11px;background:var(--ink-100);box-shadow:var(--shadow-xs);}
.grade-pill .n{font-size:18px;font-weight:800;}
.grade-pill .l{font-size:11px;color:var(--ink-500);}

/* ---- 版本日志时间线 ---- */
.timeline{position:relative;padding-left:26px;}
.timeline::before{content:"";position:absolute;left:5px;top:6px;bottom:6px;width:2px;background:var(--line);}
.timeline-item{position:relative;padding-bottom:26px;}
.timeline-item:last-child{padding-bottom:0;}
.timeline-dot{
  position:absolute;left:-26px;top:3px;width:12px;height:12px;border-radius:50%;
  background:linear-gradient(165deg,var(--accent-2),var(--accent));
  box-shadow:0 0 0 4px var(--accent-soft), 0 2px 6px rgba(67,56,202,.4);
}
.timeline-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;}
.timeline-title{font-size:14.5px;font-weight:700;color:var(--ink-900);}
.timeline-date{font-size:12px;color:var(--ink-500);margin-left:auto;}
.timeline-content{white-space:pre-line;font-size:13px;color:var(--ink-700);margin-top:8px;line-height:1.7;}
.timeline-meta{font-size:12px;color:var(--ink-500);margin-top:10px;}

.changelog-preview{padding:12px 14px;background:var(--accent-soft);border-radius:10px;margin-bottom:14px;}
.changelog-preview-title{font-size:13.5px;font-weight:700;margin-left:8px;}
.changelog-preview-date{font-size:11.5px;color:var(--ink-500);margin-top:4px;}

/* ---- 响应式：手机/平板上侧边栏收起为可点击展开的抽屉，核心布局改单列 ---- */
.menu-toggle{
  display:none; position:fixed; top:14px; left:14px; z-index:40;
  width:40px;height:40px;border-radius:10px;border:none;
  background:linear-gradient(165deg,var(--accent-2),var(--accent)); color:#fff; font-size:18px; cursor:pointer;
  box-shadow:var(--shadow-md); align-items:center; justify-content:center;
}
.sidebar-backdrop{display:none; position:fixed; inset:0; background:rgba(15,12,50,.45); z-index:29;}
.sidebar-backdrop.show{display:block;}

@media (max-width: 860px){
  .menu-toggle{display:flex;}
  .sidebar{
    position:fixed; top:0; left:0; height:100vh; height:100dvh; z-index:30;
    transform:translateX(-100%); box-shadow:4px 0 32px -8px rgba(15,12,50,.5);
  }
  .sidebar.open{transform:translateX(0);}
  .main{padding:66px 16px 24px; max-width:100%;}
  .topbar{flex-direction:column; align-items:flex-start; gap:12px;}
  .topbar-actions{width:100%;}
  form.form-grid{grid-template-columns:1fr;}
  .detail-grid{grid-template-columns:1fr;}
  .cockpit-grid{grid-template-columns:1fr;}
  .kpi-grid{grid-template-columns:repeat(auto-fit,minmax(130px,1fr));}
  /* iOS Safari 在输入框字号小于16px时会自动放大页面方便看清，导致输入时页面跳动；
     这里单独把手机端的输入框字号提到16px，避免这个自动放大行为，页面保持不动。 */
  .field input, .field select, .field textarea, .filter-bar select, .filter-bar input{font-size:16px;}
  .bar-row{flex-wrap:wrap;}
  .bar-row .bar-label{width:100%;}
  .bar-row .bar-val{width:auto;}

  /* 列数偏多的列表表格在手机上横向滚动体验很差，加了 responsive-table 这个class的表格
     改成逐行变卡片：每个<td>用data-label当左边的字段名，值靠右对齐。先在不合格品管理试点，
     其它列表页效果好的话再照搬这个class。 */
  table.responsive-table thead{display:none;}
  table.responsive-table, table.responsive-table tbody, table.responsive-table tr, table.responsive-table td{
    display:block; width:100%;
  }
  table.responsive-table tr{
    border:1px solid var(--line); border-radius:10px; margin-bottom:10px; padding:4px 12px; background:var(--paper);
  }
  table.responsive-table td{
    display:flex; justify-content:space-between; align-items:center; gap:10px;
    padding:7px 0; border:none; text-align:right; font-size:13px;
  }
  table.responsive-table td:not(:last-child){border-bottom:1px solid var(--ink-100);}
  table.responsive-table td[data-label]::before{
    content:attr(data-label); font-weight:700; color:var(--ink-700); text-align:left; flex-shrink:0;
  }
  table.responsive-table td[data-label=""]::before{content:none;}
  table.responsive-table td[data-label=""]{justify-content:flex-end;}
}
