/* HR 智能工作台 —— 设计系统
   ------------------------------------------------------------------
   面向 HR 专员日常使用，不是面向财务后台或工程师：
     · 浅色、留白充足、圆角柔和，界面本身不制造紧张感
     · 只有「需要你处理的那几行」用颜色说话，其余一律安静
     · 等宽字体只留给真正的技术标识（哈希、作业编号），
       数字对齐改用 tabular-nums —— 数位仍然对齐，但不再像代码

   内网部署、无出站请求（技术方案 C1），因此不加载任何网络字体；
   字体个性靠字重、字号与间距做出来，不靠字体文件。

   浅色是这个产品的样子，不跟随系统：HR 在办公电脑上打开就该是浅色，
   哪怕这台机器的系统主题是深色。深色只在有人主动点「切换主题」时出现
   （[data-theme="dark"]），并记住选择。 */

:root{
  /* 浏览器自带控件（日期选择器、滚动条、下拉箭头）跟的是 color-scheme，
     不写死的话它们会按系统主题渲染 —— 浅色页面上冒出一个深色日历弹层 */
  color-scheme:light;

  /* 中性色：略带暖意的浅灰蓝，比纯白柔和，长时间看不刺眼 */
  --paper:#F4F6FA; --surface:#FAFBFD; --raised:#FFFFFF; --sunk:#EDF0F7;
  --ink:#232838; --ink2:#5A6178; --ink3:#8A91A6;
  --rule:#E3E7F0; --rule-soft:#EFF2F8;

  /* 品牌色：交互控件、选中态、焦点环 */
  --brand:#4C6FD0; --brand-soft:#E9EFFC; --brand-line:#BFD2F5; --on-brand:#FFFFFF;

  /* 语义色。一致 = 安心的绿；金额不符 = 提醒而非报警的玫瑰红；
     单边 = 琥珀；待办/占位 = 中性紫灰。
     刻意避开正红：没有人处于危险中，只是有几个数字需要看一眼。 */
  --ok:#3E8E6E;    --ok-soft:#E4F3EC;    --ok-line:#AEDCC7;
  --alert:#C4566A; --alert-soft:#FBEAEE; --alert-line:#F0B9C4;
  --warn:#AF7A2C;  --warn-soft:#FAF0DC;  --warn-line:#E9CE9C;
  --info:#6A6F91;  --info-soft:#F0F1F7;  --info-line:#C9CCDE;

  --shadow-sm:0 1px 2px rgba(35,40,56,.05);
  --shadow:0 1px 3px rgba(35,40,56,.05), 0 8px 20px -14px rgba(35,40,56,.22);
  --shadow-lg:0 2px 6px rgba(35,40,56,.06), 0 18px 40px -24px rgba(35,40,56,.32);

  --r-sm:8px; --r:12px; --r-lg:16px;
}

:root[data-theme="dark"]{
  color-scheme:dark;
  --paper:#15171E; --surface:#1A1D26; --raised:#20242F; --sunk:#272C39;
  --ink:#E7EAF2; --ink2:#A8AFC2; --ink3:#787F94;
  --rule:#2E3341; --rule-soft:#262A36;
  --brand:#8AA6EA; --brand-soft:#222941; --brand-line:#3B4666; --on-brand:#131722;
  --ok:#6DC2A0;    --ok-soft:#172B25;    --ok-line:#2E5748;
  --alert:#E894A3; --alert-soft:#2E1D22;  --alert-line:#5C3A42;
  --warn:#D9AC64;  --warn-soft:#2B2416;  --warn-line:#57482A;
  --info:#A2A8C6;  --info-soft:#232734;  --info-line:#3D4356;
  --shadow-sm:0 1px 2px rgba(0,0,0,.3);
  --shadow:0 1px 3px rgba(0,0,0,.35), 0 8px 20px -14px rgba(0,0,0,.7);
  --shadow-lg:0 2px 6px rgba(0,0,0,.4), 0 18px 40px -24px rgba(0,0,0,.8);
}

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0; background:var(--paper); color:var(--ink);
  font-family:"PingFang SC","Microsoft YaHei","Hiragino Sans GB","Source Han Sans SC","Noto Sans CJK SC",system-ui,sans-serif;
  font-size:15px; line-height:1.65; -webkit-font-smoothing:antialiased;
}
/* 数位对齐但不用等宽字体 —— 表格里的金额照样成列，界面不像终端 */
.num,.mono,td.num,th.num,td.id,.stat .v{font-variant-numeric:tabular-nums}
.num{text-align:right}
/* 等宽只留给真正的技术标识：SHA-256、作业编号 */
.tech{font-family:ui-monospace,"Cascadia Mono",Consolas,"SF Mono",monospace;font-size:.9em}
:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:4px}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
[hidden]{display:none!important}

/* ---------- 顶栏 ---------- */
.appbar{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px 16px;
  padding:11px 22px;background:var(--raised);color:var(--ink2);
  border-bottom:1px solid var(--rule);font-size:13px;
}
.appbar b{font-weight:700;font-size:14.5px;color:var(--ink);letter-spacing:.01em}
.appbar .sep{opacity:.3}
.appbar .grow{flex:1}
/* 两个按钮当一整块换行，窄屏上不会只掉下来一个「退出」 */
.appbar .acts{display:flex;gap:8px;margin-left:auto}
.appbar button{
  font-family:inherit;font-size:13px;cursor:pointer;
  background:var(--surface);border:1px solid var(--rule);
  color:var(--ink2);border-radius:var(--r-sm);padding:5px 12px;
  transition:background .15s,color .15s;
}
.appbar button:hover{background:var(--sunk);color:var(--ink)}

/* ---------- 布局 ---------- */
.shell{display:grid;grid-template-columns:236px minmax(0,1fr);min-height:calc(100vh - 48px)}
.rail{border-right:1px solid var(--rule);background:var(--surface);padding:20px 14px 28px;display:flex;flex-direction:column;gap:22px}
.brand{padding:2px 8px 16px;border-bottom:1px solid var(--rule-soft)}
.brand .co{font-size:12px;color:var(--ink3)}
.brand .nm{font-size:17px;font-weight:700;margin-top:4px}
.brand .env{display:inline-flex;align-items:center;gap:6px;margin-top:10px;font-size:11.5px;color:var(--ok);border:1px solid var(--ok-line);background:var(--ok-soft);border-radius:999px;padding:3px 10px}
.dot{width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block}

.navsec{display:flex;flex-direction:column;gap:4px}
.navlbl{font-size:12px;color:var(--ink3);padding:0 8px 4px;display:flex;justify-content:space-between;align-items:baseline}
.navitem{display:flex;align-items:center;gap:9px;padding:9px 12px;border-radius:var(--r-sm);font-size:14px;border:1px solid transparent;background:none;color:var(--ink2);width:100%;text-align:left;cursor:pointer;font-family:inherit;transition:background .15s,color .15s}
.navitem:hover{background:var(--sunk);color:var(--ink)}
.navitem.later{color:var(--ink3);font-size:13.5px;padding:8px 12px}
.navitem.later::before{content:"";width:6px;height:6px;border-radius:50%;border:1.5px dashed var(--info-line);flex:none}
.navitem.later:hover{background:var(--sunk);color:var(--ink2)}
.navitem.later .idx{display:none}
/* 选中态必须写在 .later / :hover 之后 —— 同优先级下后写的赢。
   写在前面时，需求池模块被选中后会被 .later 的灰字覆盖，看不出选中。 */
.navitem.on,.navitem.on:hover{background:var(--brand-soft);color:var(--brand);font-weight:600}
.navitem.later.on::before{border-style:solid;border-color:var(--brand)}
.railfoot{margin-top:auto;font-size:12px;color:var(--ink3);padding:14px 8px 0;border-top:1px solid var(--rule-soft);line-height:1.6}

.stage{min-width:0;padding:0 0 64px}
.topbar{display:flex;align-items:center;gap:12px;padding:16px 30px;border-bottom:1px solid var(--rule);background:var(--raised);position:sticky;top:0;z-index:5;flex-wrap:wrap}
.topbar h1{margin:0;font-size:19px;font-weight:700}
.topbar .who{margin-left:auto;display:flex;align-items:center;gap:10px;font-size:13.5px;color:var(--ink2)}
.avatar{width:32px;height:32px;border-radius:50%;background:var(--brand-soft);color:var(--brand);display:grid;place-items:center;font-size:14px;font-weight:600}

/* ---------- 步骤切换 ---------- */
.flow{display:flex;align-items:center;gap:6px;padding:18px 30px 0;flex-wrap:wrap}
.step{display:flex;align-items:center;padding:8px 16px;border:1px solid transparent;border-radius:999px;background:none;color:var(--ink2);cursor:pointer;font-family:inherit;font-size:14px;white-space:nowrap;transition:background .15s,color .15s}
.step:hover:not(:disabled):not(.on){background:var(--sunk);color:var(--ink)}
.step.on{background:var(--raised);border-color:var(--rule);color:var(--ink);font-weight:600;box-shadow:var(--shadow-sm)}
.step:disabled{opacity:.45;cursor:not-allowed}

.screen{display:none;padding:26px 30px 0}
.screen.on{display:block}
h2.sh{font-size:23px;font-weight:700;letter-spacing:-.01em;margin:0 0 6px}
p.sub{margin:0 0 24px;color:var(--ink2);font-size:14px;max-width:72ch;line-height:1.7}

/* ---------- 卡片 ---------- */
.card{background:var(--raised);border:1px solid var(--rule);border-radius:var(--r);box-shadow:var(--shadow)}
.card > .hd{padding:14px 20px;border-bottom:1px solid var(--rule-soft);display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.card > .hd h3{margin:0;font-size:15px;font-weight:600}
.card > .bd{padding:20px}
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:18px}
.stack{display:flex;flex-direction:column;gap:18px}

.chip{display:inline-flex;align-items:center;gap:6px;font-size:12px;padding:3px 10px;border-radius:999px;border:1px solid var(--rule);color:var(--ink2);background:var(--surface);white-space:nowrap}
.chip.ok{color:var(--ok);border-color:var(--ok-line);background:var(--ok-soft)}
.chip.bad{color:var(--alert);border-color:var(--alert-line);background:var(--alert-soft)}
.chip.warn{color:var(--warn);border-color:var(--warn-line);background:var(--warn-soft)}

/* ---------- 结果统计 ----------
   界面上唯一「大声」的地方。一致的那张保持白底安静，
   需要处理的三类给柔和底色 —— 视线自然落到该看的地方。 */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(176px,1fr));gap:14px}
.stat{border:1px solid var(--rule);border-radius:var(--r);background:var(--raised);padding:16px 18px;box-shadow:var(--shadow-sm);text-align:left;font-family:inherit;cursor:pointer;color:var(--ink);transition:box-shadow .15s,transform .15s,border-color .15s}
.stat:hover{box-shadow:var(--shadow);transform:translateY(-1px)}
.stat .k{font-size:13px;color:var(--ink2);display:block}
.stat .v{font-size:36px;font-weight:700;line-height:1.15;display:block;margin-top:6px;letter-spacing:-.02em}
.stat .u{font-size:13px;color:var(--ink3);margin-left:4px;font-weight:400;letter-spacing:0}
.stat.sel{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft),var(--shadow)}
.stat.s-match .v{color:var(--ok)}
.stat.s-amount_diff{background:var(--alert-soft);border-color:var(--alert-line)}
.stat.s-amount_diff .v{color:var(--alert)}
.stat.s-payroll_only,.stat.s-bank_only{background:var(--warn-soft);border-color:var(--warn-line)}
.stat.s-payroll_only .v,.stat.s-bank_only .v{color:var(--warn)}
/* 合同到期预警的 6 个分类，复用对账型的三档配色语义 */
.stat.s-normal .v{color:var(--ok)}
.stat.s-expired,.stat.s-due_30{background:var(--alert-soft);border-color:var(--alert-line)}
.stat.s-expired .v,.stat.s-due_30 .v{color:var(--alert)}
.stat.s-due_60,.stat.s-due_90{background:var(--warn-soft);border-color:var(--warn-line)}
.stat.s-due_60 .v,.stat.s-due_90 .v{color:var(--warn)}
.stat.s-no_expiry .v{color:var(--ink3)}
/* 花名册校验：必填缺失/重复工号或证件号视为严重，性别-出生日期矛盾算需关注 */
.stat.s-ok .v{color:var(--ok)}
.stat.s-missing_required,.stat.s-duplicate{background:var(--alert-soft);border-color:var(--alert-line)}
.stat.s-missing_required .v,.stat.s-duplicate .v{color:var(--alert)}
.stat.s-conflict{background:var(--warn-soft);border-color:var(--warn-line)}
.stat.s-conflict .v{color:var(--warn)}
/* 社保公积金核对：金额不符最重，基数不同/单边次之 */
.stat.s-base_diff,.stat.s-social_insurance_only{background:var(--warn-soft);border-color:var(--warn-line)}
.stat.s-base_diff .v,.stat.s-social_insurance_only .v{color:var(--warn)}
/* 考勤统计：缺卡最重，迟到/早退次之，加班只是记录不是问题 */
.stat.s-missing_punch{background:var(--alert-soft);border-color:var(--alert-line)}
.stat.s-missing_punch .v{color:var(--alert)}
.stat.s-late,.stat.s-early_leave{background:var(--warn-soft);border-color:var(--warn-line)}
.stat.s-late .v,.stat.s-early_leave .v{color:var(--warn)}
/* 加班（考勤）、已统计（人员成本）：中性记录，不是问题，安静展示 */
.stat.s-overtime .v,.stat.s-counted .v{color:var(--info)}

/* ---------- 表格 ---------- */
.tblwrap{overflow-x:auto;border:1px solid var(--rule);border-top:none;background:var(--raised)}
.filters + .tblwrap{border-radius:0}
table{border-collapse:collapse;width:100%;min-width:860px;font-size:14px}
th,td{padding:11px 14px;border-bottom:1px solid var(--rule-soft);text-align:left;white-space:nowrap}
thead th{position:sticky;top:0;background:var(--surface);font-size:12.5px;color:var(--ink3);font-weight:500;border-bottom:1px solid var(--rule);z-index:1}
tbody tr:last-child td{border-bottom:none}
tbody tr:hover td{background:var(--sunk)}
td.num,th.num{text-align:right}
.mark{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;padding:2px 10px;border-radius:999px;border:1px solid;white-space:nowrap}
.m-match{color:var(--ok);border-color:var(--ok-line);background:var(--ok-soft)}
.m-amount_diff{color:var(--alert);border-color:var(--alert-line);background:var(--alert-soft)}
.m-payroll_only,.m-bank_only{color:var(--warn);border-color:var(--warn-line);background:var(--warn-soft)}
.m-normal{color:var(--ok);border-color:var(--ok-line);background:var(--ok-soft)}
.m-expired,.m-due_30{color:var(--alert);border-color:var(--alert-line);background:var(--alert-soft)}
.m-due_60,.m-due_90{color:var(--warn);border-color:var(--warn-line);background:var(--warn-soft)}
.m-no_expiry{color:var(--ink3);border-color:var(--rule);background:var(--surface)}
.m-ok{color:var(--ok);border-color:var(--ok-line);background:var(--ok-soft)}
.m-missing_required,.m-duplicate{color:var(--alert);border-color:var(--alert-line);background:var(--alert-soft)}
.m-conflict{color:var(--warn);border-color:var(--warn-line);background:var(--warn-soft)}
.m-base_diff,.m-social_insurance_only{color:var(--warn);border-color:var(--warn-line);background:var(--warn-soft)}
.m-missing_punch{color:var(--alert);border-color:var(--alert-line);background:var(--alert-soft)}
.m-late,.m-early_leave{color:var(--warn);border-color:var(--warn-line);background:var(--warn-soft)}
.m-overtime,.m-counted{color:var(--info);border-color:var(--info-line);background:var(--info-soft)}
/* 差异行整行淡染，扫一眼就能看出哪几行要处理 */
tr.r-amount_diff td{background:color-mix(in srgb,var(--alert-soft) 60%,transparent)}
tr.r-payroll_only td,tr.r-bank_only td{background:color-mix(in srgb,var(--warn-soft) 50%,transparent)}
tr.r-expired td,tr.r-due_30 td{background:color-mix(in srgb,var(--alert-soft) 60%,transparent)}
tr.r-due_60 td,tr.r-due_90 td{background:color-mix(in srgb,var(--warn-soft) 50%,transparent)}
tr.r-missing_required td,tr.r-duplicate td{background:color-mix(in srgb,var(--alert-soft) 60%,transparent)}
tr.r-conflict td{background:color-mix(in srgb,var(--warn-soft) 50%,transparent)}
tr.r-base_diff td,tr.r-social_insurance_only td{background:color-mix(in srgb,var(--warn-soft) 50%,transparent)}
tr.r-missing_punch td{background:color-mix(in srgb,var(--alert-soft) 60%,transparent)}
tr.r-late td,tr.r-early_leave td{background:color-mix(in srgb,var(--warn-soft) 50%,transparent)}
td.gap{color:var(--alert);font-weight:600}
td.empty{color:var(--ink3)}
/* 历史作业的「统计」一列文字长，允许折行 —— 否则整行把「查看」按钮挤出可视区。
   每项统计各自不断行，换行只发生在项与项之间。 */
td.wrap{white-space:normal;min-width:210px;max-width:360px;line-height:1.7}
td.wrap span{display:inline-block;white-space:nowrap;margin-right:14px}
.tblempty{padding:44px 16px;text-align:center;color:var(--ink3);font-size:14px}

.filters{display:flex;gap:8px;flex-wrap:wrap;align-items:center;padding:14px 16px;border:1px solid var(--rule);border-radius:var(--r) var(--r) 0 0;background:var(--raised);font-size:13.5px}
.filters .flabel{color:var(--ink3);font-size:13px}

/* ---------- 聚合汇总（考勤统计 / 人员成本分析）---------- */
#aggCard .bd{display:flex;flex-direction:column;gap:18px}
.barchart{display:flex;flex-direction:column;gap:10px}
.bar-row{display:grid;grid-template-columns:120px minmax(0,1fr) 110px;align-items:center;gap:12px}
.bar-label{font-size:13.5px;color:var(--ink2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bar-track{height:16px;border-radius:999px;background:var(--sunk);overflow:hidden}
.bar-fill{height:100%;border-radius:999px;background:var(--brand);min-width:3px;transition:width .25s ease}
.bar-val{font-size:13.5px;color:var(--ink)}

.pill{font-family:inherit;font-size:13px;padding:6px 14px;border-radius:999px;border:1px solid var(--rule);background:var(--surface);color:var(--ink2);cursor:pointer;transition:background .15s,color .15s,border-color .15s}
.pill:hover{background:var(--sunk);color:var(--ink)}
.pill.on{background:var(--brand);border-color:var(--brand);color:var(--on-brand);font-weight:500}
.pager{display:flex;align-items:center;gap:10px;padding:13px 16px;font-size:13.5px;color:var(--ink2);border:1px solid var(--rule);border-top:none;border-radius:0 0 var(--r) var(--r);background:var(--raised)}
.pager .grow{flex:1}

/* ---------- 控件 ---------- */
.btn{font-family:inherit;font-size:14px;padding:9px 18px;border-radius:var(--r-sm);border:1px solid var(--rule);background:var(--raised);color:var(--ink);cursor:pointer;display:inline-flex;align-items:center;gap:8px;transition:background .15s,border-color .15s,box-shadow .15s}
.btn:hover:not(:disabled){background:var(--sunk)}
.btn.pri{background:var(--brand);border-color:var(--brand);color:var(--on-brand);font-weight:600;box-shadow:var(--shadow-sm)}
.btn.pri:hover:not(:disabled){filter:brightness(1.07);box-shadow:var(--shadow)}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn.sm{font-size:13px;padding:6px 13px}
.btnrow{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
input[type=text],input[type=password],input[type=month],select{
  font-family:inherit;font-size:14px;padding:9px 12px;border-radius:var(--r-sm);
  border:1px solid var(--rule);background:var(--raised);color:var(--ink);
  transition:border-color .15s,box-shadow .15s;
}
input[type=text]:focus,input[type=password]:focus,input[type=month]:focus{
  outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft);
}
input[type=text]:disabled{opacity:.5}
label.fl{display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--ink2)}

/* ---------- 上传区 ---------- */
.drop{border:1.5px dashed var(--rule);border-radius:var(--r);background:var(--raised);padding:24px;display:flex;flex-direction:column;gap:10px;cursor:pointer;transition:border-color .15s,background .15s}
.drop:hover{border-color:var(--brand-line);background:var(--brand-soft)}
.drop.filled{border-style:solid;border-color:var(--ok-line);background:var(--ok-soft);cursor:default}
.drop.filled:hover{background:var(--ok-soft)}
.drop.over{border-color:var(--brand);background:var(--brand-soft)}
.drop .role{font-size:15px;font-weight:600;color:var(--ink)}
.drop .fname{font-size:14px;color:var(--ink);word-break:break-all;font-weight:500}
.drop .meta{font-size:13px;color:var(--ink2);line-height:1.6}
.drop .hint{font-size:14px;color:var(--ink2)}

/* ---------- 提示 ---------- */
.alert{border:1px solid;border-radius:var(--r);padding:16px 18px;display:flex;gap:14px;align-items:flex-start}
.alert .ttl{font-weight:600;font-size:14.5px;margin:0 0 4px}
.alert p{margin:0;font-size:13.5px;line-height:1.7}
.alert.err{border-color:var(--alert-line);background:var(--alert-soft);color:var(--alert)}
.alert.err p,.alert.err li{color:var(--ink)}
.alert.err .ttl{color:var(--alert)}
.alert.note{border-color:var(--rule);background:var(--raised);color:var(--ink2);box-shadow:var(--shadow-sm)}
.alert.note .ttl{color:var(--ink)}
.alert.warn{border-color:var(--warn-line);background:var(--warn-soft);color:var(--warn)}
.alert.warn p{color:var(--ink)}
.alert .ico{font-weight:700;font-size:13px;border:1.5px solid currentColor;border-radius:50%;width:21px;height:21px;display:grid;place-items:center;flex:none;margin-top:2px}
.alert .body{min-width:0;flex:1}
.alert code{font-family:ui-monospace,Consolas,monospace;font-size:12.5px;background:var(--surface);border:1px solid var(--rule);border-radius:5px;padding:1px 6px}
.alert ul{margin:8px 0 0;padding-left:20px;font-size:13.5px;line-height:1.7}

/* 只读证明：让人安心的那一条，用绿色而不是警示色 */
.readonly{display:flex;align-items:center;gap:12px;padding:14px 18px;border:1px solid var(--ok-line);background:var(--ok-soft);border-radius:var(--r);font-size:13.5px;color:var(--ink2);flex-wrap:wrap}
.readonly b{color:var(--ok);font-size:14.5px}

.kv{display:grid;grid-template-columns:auto 1fr;gap:10px 20px;font-size:13.5px;align-items:baseline;margin:0}
.kv dt{color:var(--ink3);font-size:13px;white-space:nowrap}
.kv dd{margin:0;min-width:0;overflow-wrap:anywhere;line-height:1.7}
.foot{padding:26px 30px 0;color:var(--ink3);font-size:12.5px;line-height:1.8;max-width:86ch}

/* ---------- 登录 ---------- */
.login{min-height:100vh;display:grid;place-items:center;padding:24px;background:var(--paper)}
.login .card{width:min(440px,100%);box-shadow:var(--shadow-lg);border-radius:var(--r-lg)}
.login .hd{padding:22px 26px 18px;align-items:flex-start;justify-content:space-between}
.login .hd h3{font-size:20px}
.login .hd .co{margin:3px 0 0;font-size:13px;color:var(--ink3)}
.login .bd{padding:26px}
.login .fields{display:flex;flex-direction:column;gap:18px}
.login input{width:100%}
.login .btn{justify-content:center;padding:11px 18px}
.login .demo{font-size:13px;color:var(--ink3);border-top:1px solid var(--rule-soft);padding-top:16px;margin-top:2px}
.login .demo p{margin:0;display:flex;align-items:center;gap:10px;line-height:2.1}
.login .demo .lbl{margin-bottom:4px;display:block}
.login .demo code{font-family:ui-monospace,Consolas,monospace;font-size:12.5px;color:var(--ink2);background:var(--surface);border:1px solid var(--rule);border-radius:5px;padding:2px 8px;min-width:172px}

/* ---------- 需求池占位 ---------- */
.ph{display:flex;flex-direction:column;gap:18px;max-width:76ch}
/* 卡片间距由 .ph 的 gap 统一给，标题/说明自带的外边距要清掉，否则疏密不匀 */
.ph > h2.sh,.ph > p.sub{margin:0}
.ph .badge{align-self:flex-start;font-size:12.5px;color:var(--info);border:1px solid var(--info-line);background:var(--info-soft);border-radius:999px;padding:4px 12px}

.spin{display:inline-block;width:14px;height:14px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:sp .7s linear infinite}
@keyframes sp{to{transform:rotate(360deg)}}

.toast{position:fixed;right:22px;bottom:22px;z-index:50;display:flex;flex-direction:column;gap:10px;max-width:min(420px,90vw)}
.toast > div{background:var(--raised);border:1px solid var(--rule);border-left:4px solid var(--ok);border-radius:var(--r-sm);box-shadow:var(--shadow-lg);padding:13px 16px;font-size:13.5px;animation:tin .22s ease-out}
.toast > div.bad{border-left-color:var(--alert)}
@keyframes tin{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

@media (max-width:860px){
  /* 单列时两行都是 auto，网格会把 min-height 的富余高度平分给它们，
     侧栏会被撑到半屏 —— 明确让正文吃掉剩余高度 */
  .shell{grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr)}
  /* 侧栏压成一条横向滚动的模块条。
     竖着排时 12 个模块要占满一屏半，正文被推到看不见的地方 ——
     手机上打开先看到的必须是干活的区域，不是模块清单。 */
  .rail{
    flex-direction:row;align-items:center;gap:10px;
    overflow-x:auto;overscroll-behavior-x:contain;
    padding:9px 14px;border-right:none;border-bottom:1px solid var(--rule);
  }
  .brand,.railfoot{display:none}       /* 顶栏已有同样的名称与说明 */
  .navsec{flex-direction:row;align-items:center;gap:6px}
  #navP1,#navP2{display:flex;gap:6px}   /* 模块按钮的直接父容器，也要横过来 */
  .navlbl{padding:0 2px 0 0;white-space:nowrap;font-size:11.5px}
  .navlbl span{display:none}
  .navitem{width:auto;white-space:nowrap;padding:7px 13px;border-radius:999px}
  .navitem.later{padding:6px 12px}
  .screen,.topbar,.flow,.foot{padding-left:18px;padding-right:18px}
  .stats{grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}
  .stat .v{font-size:30px}
}
@media (max-width:560px){
  /* 顶栏只留身份与操作，阶段说明下面的标题栏会重复一遍 */
  .appbar .sep,.appbar #abPhase{display:none}
  .topbar{padding-top:13px;padding-bottom:13px}
}
