:root{--surface:#f6f6f4;--panel:#fff;--ink:#16181c;--ink-2:#52514e;--ink-3:#8a887f;--hairline:#e7e5df;--grid:#efede8;
--c8:#8fb8e8;--c12:#5590d9;--c16:#2a78d6;--c24:#1a4f96;--bad:#d64545;--bad-soft:rgba(214,69,69,.10);--ok:#2f8a57;--ok-soft:rgba(47,138,87,.10);
--warn:#b7791f;--warn-soft:rgba(183,121,31,.12);--accent:#2a78d6;--accent-soft:rgba(42,120,214,.10);
--gapzone:rgba(138,136,127,.10);--tooltip-bg:#16181c;--tooltip-ink:#fcfcfb;--side:#1d2129;--side-ink:#c9ccd3;--side-active:#fff}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--surface:#17171a;--panel:#201f22;--ink:#f2f1ec;--ink-2:#c3c2b7;--ink-3:#8d8b81;--hairline:#343430;--grid:#2a2a27;
--c8:#1e4f8f;--c12:#2f6fc0;--c16:#5b97e0;--c24:#a4c6ef;--bad:#e66767;--bad-soft:rgba(230,103,103,.14);--ok:#5cbf86;--ok-soft:rgba(92,191,134,.14);--warn:#d9a441;--warn-soft:rgba(217,164,65,.16);
--accent:#5b97e0;--accent-soft:rgba(91,151,224,.14);--gapzone:rgba(141,139,129,.12);--tooltip-bg:#f2f1ec;--tooltip-ink:#1a1a19;--side:#111114;--side-ink:#9a9da6}}
*{box-sizing:border-box}
body{margin:0;background:var(--surface);color:var(--ink);font-family:"Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif;font-size:14.5px;line-height:1.6}
.mono{font-family:"IBM Plex Mono",Consolas,monospace;font-variant-numeric:tabular-nums}
a{color:var(--accent)}
.app{display:flex;min-height:100vh}
nav.side{width:216px;flex:none;background:var(--side);color:var(--side-ink);padding:18px 0;display:flex;flex-direction:column;position:sticky;top:0;height:100vh}
.brand{padding:4px 20px 16px;border-bottom:1px solid rgba(255,255,255,.08)}
.brand b{display:block;color:#fff;font-size:15px;letter-spacing:.02em}
.brand span{font-family:"IBM Plex Mono",monospace;font-size:11px;letter-spacing:.12em;opacity:.6}
nav.side a{display:flex;align-items:center;gap:10px;padding:9px 20px;color:var(--side-ink);text-decoration:none;font-size:14px;border-left:3px solid transparent}
nav.side a.active{color:var(--side-active);background:rgba(255,255,255,.06);border-left-color:var(--accent)}
nav.side a .n{font-family:"IBM Plex Mono",monospace;font-size:11px;opacity:.55;width:14px}
nav.side a .pill{margin-left:auto;font-size:10.5px;padding:0 6px;border-radius:99px;background:rgba(255,255,255,.12)}
nav.side .foot{margin-top:auto;padding:14px 20px;font-size:12px;opacity:.6;border-top:1px solid rgba(255,255,255,.08)}
main{flex:1;min-width:0;padding:26px 30px 60px}
.topbar{display:flex;align-items:center;gap:14px;margin-bottom:18px;flex-wrap:wrap}
.topbar h1{font-size:21px;margin:0;font-weight:700}
.topbar .mock{font-family:"IBM Plex Mono",monospace;font-size:11px;letter-spacing:.1em;padding:2px 8px;border:1px dashed var(--warn);color:var(--warn);border-radius:4px}
.topbar .spacer{flex:1}
.topbar .user{font-size:13px;color:var(--ink-2)}
.page{display:none}.page.active{display:block}
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:20px}
.card{border:1px solid var(--hairline);background:var(--panel);border-radius:10px;padding:14px 16px}
.card .k{font-size:12px;color:var(--ink-3);margin-bottom:2px}
.card .v{font-family:"IBM Plex Mono",monospace;font-size:24px;font-weight:500;line-height:1.2}
.card .v.bad{color:var(--bad)}.card .v.ok{color:var(--ok)}
.card .s{font-size:12px;color:var(--ink-2);margin-top:4px}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media (max-width:980px){.grid2{grid-template-columns:1fr}}
.panel{border:1px solid var(--hairline);background:var(--panel);border-radius:10px;padding:16px 18px;margin-bottom:16px}
.panel h2{font-size:15.5px;margin:0 0 10px;display:flex;align-items:center;gap:10px}
.panel h2 .sub{font-weight:400;font-size:12.5px;color:var(--ink-3)}
.panel p{margin:0 0 10px;color:var(--ink-2);font-size:13.5px}
table.t{border-collapse:collapse;width:100%;font-size:13.5px}
table.t th{text-align:left;font-size:12px;letter-spacing:.05em;color:var(--ink-3);font-weight:500;padding:8px 10px;border-bottom:1px solid var(--hairline);white-space:nowrap}
table.t td{padding:7px 10px;border-bottom:1px solid var(--grid);vertical-align:top}
table.t tr:last-child td{border-bottom:none}
table.t td.num,table.t th.num{font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums;white-space:nowrap}
table.t td.r,table.t th.r{text-align:right}
table.t td.numw{font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums;white-space:normal;min-width:16em}
table.t td:last-child{min-width:14em}
table.t tr.click{cursor:pointer}table.t tr.click:hover td{background:var(--accent-soft)}
table.t tr.sel td{background:var(--accent-soft);box-shadow:inset 3px 0 0 var(--accent)}
.tscroll{overflow-x:auto}
.chip{display:inline-block;font-size:11.5px;padding:1px 8px;border-radius:99px;border:1px solid var(--bad);color:var(--bad);background:var(--bad-soft);white-space:nowrap}
.chip.warn{border-color:var(--warn);color:var(--warn);background:var(--warn-soft)}
.chip.ok{border-color:var(--ok);color:var(--ok);background:var(--ok-soft)}
.chip.muted{border-color:var(--ink-3);color:var(--ink-2);background:transparent}
.chip.acc{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:7px;border:1px solid var(--hairline);background:var(--panel);color:var(--ink);font-size:13.5px;cursor:pointer;font-family:inherit}
.btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.btn.danger{border-color:var(--bad);color:var(--bad)}
.btn:disabled{opacity:.5;cursor:default}
select,input[type=text],input[type=email],input[type=password],input[type=date],input[type=datetime-local],input[type=number],textarea{font:inherit;font-size:13.5px;padding:6px 9px;border:1px solid var(--hairline);border-radius:7px;background:var(--panel);color:var(--ink)}
.row{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:12px}
.row label{font-size:13px;color:var(--ink-2)}
.toggle{display:inline-flex;align-items:center;gap:6px;font-size:13px;color:var(--ink-2);cursor:pointer;user-select:none}
.toggle input{accent-color:var(--accent)}
.sw{width:13px;height:13px;border-radius:3px;display:inline-block;flex:none}
.legend{display:flex;flex-wrap:wrap;align-items:center;gap:14px;font-size:12.5px;color:var(--ink-2);margin:4px 0 10px}
.legend .li{display:inline-flex;align-items:center;gap:6px}
.panels{display:flex;flex-wrap:wrap;gap:16px}
.mapbox{flex:1 1 440px;min-width:0;border:1px solid var(--hairline);background:var(--panel);border-radius:10px;padding:14px 14px 8px}
.mapbox h3{font-size:14px;margin:0 0 2px}
.mapbox .meta{font-size:12px;color:var(--ink-3);margin:0 0 8px}
.svgbox{overflow-x:auto}.svgbox svg{display:block}
.slot{cursor:pointer}.slot:hover{stroke:var(--ink);stroke-width:1.2}
#tip{position:fixed;pointer-events:none;z-index:30;display:none;background:var(--tooltip-bg);color:var(--tooltip-ink);border-radius:7px;padding:8px 11px;font-size:12.5px;line-height:1.5;box-shadow:0 4px 18px rgba(0,0,0,.22);max-width:280px}
#tip .t{font-family:"IBM Plex Mono",monospace;font-weight:500;font-size:13px;margin-bottom:2px}
#tip td{padding:0 0 0 12px;text-align:right;font-family:"IBM Plex Mono",monospace}
#tip td:first-child{padding:0;text-align:left;font-family:inherit;opacity:.75}
/* drawer */
.drawer{position:fixed;top:0;right:0;width:min(560px,100%);height:100vh;background:var(--panel);border-left:1px solid var(--hairline);box-shadow:-8px 0 30px rgba(0,0,0,.15);z-index:20;transform:translateX(100%);transition:transform .2s;overflow-y:auto;padding:22px 24px}
.drawer.open{transform:none}
.drawer h2{font-size:17px;margin:0 0 4px;font-family:"IBM Plex Mono",monospace}
.drawer .close{position:absolute;top:14px;right:16px;border:none;background:transparent;font-size:22px;cursor:pointer;color:var(--ink-3)}
.drawer h3{font-size:13px;letter-spacing:.05em;color:var(--ink-3);font-weight:500;margin:18px 0 6px;text-transform:uppercase}
td.chg{background:var(--warn-soft);font-weight:500}
td.chg small{display:block;font-weight:400;color:var(--warn);font-size:11px}
.bar{display:flex;align-items:flex-end;gap:4px;height:70px;margin:6px 0 2px}
.bar div{flex:1;background:var(--accent);border-radius:3px 3px 0 0;min-height:2px;opacity:.85}
.bar div.ng{background:var(--bad)}
.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--ink-3);font-family:"IBM Plex Mono",monospace}
.dropzone{border:1.5px dashed var(--hairline);border-radius:10px;padding:22px;text-align:center;color:var(--ink-3);font-size:13.5px;background:var(--surface)}
.steps{display:flex;gap:0;margin:0 0 14px;font-size:12.5px}
.steps div{flex:1;padding:8px 10px;border:1px solid var(--hairline);background:var(--surface);color:var(--ink-3);text-align:center}
.steps div:first-child{border-radius:7px 0 0 7px}.steps div:last-child{border-radius:0 7px 7px 0}
.steps div.on{background:var(--accent-soft);color:var(--accent);border-color:var(--accent);font-weight:500}
.check li{margin:3px 0}
.check .ok::before{content:"✓ ";color:var(--ok);font-weight:700}
.check .warn::before{content:"! ";color:var(--warn);font-weight:700}
tr.formrow td{background:var(--accent-soft);padding:12px 14px}
.frm{display:grid;grid-template-columns:auto 1fr;gap:8px 12px;align-items:center;font-size:13px;max-width:640px}
.frm label{color:var(--ink-2);white-space:nowrap}
.phase{font-size:11px;padding:1px 7px;border-radius:4px;background:var(--warn-soft);color:var(--warn);border:1px solid var(--warn);font-family:"IBM Plex Mono",monospace}
@media (max-width:760px){.app{flex-direction:column}nav.side{width:100%;height:auto;position:static;flex-direction:row;flex-wrap:wrap;padding:8px}nav.side .brand{display:none}nav.side .foot{display:none}nav.side a{padding:7px 12px;border-left:none}main{padding:18px 16px 40px}.drawer{width:100%}}
/* ---- 以下为接真实接口后新增（mockup 里没有的部分） ---- */
[hidden]{display:none!important}
.topbar .user{display:flex;align-items:center;gap:10px}
.btn.sm{padding:3px 9px;font-size:12.5px}
.btn.link{border:none;background:transparent;color:var(--ink-3);padding:3px 6px;text-decoration:underline}
.dropzone{cursor:pointer;transition:border-color .15s,background .15s}
.dropzone.over{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.dropzone.disabled{cursor:default;opacity:.55}
.filelist{display:flex;flex-wrap:wrap;gap:8px;margin:10px 0 0;padding:0;list-style:none}
.filelist li{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--hairline);border-radius:7px;padding:3px 6px 3px 10px;font-size:13px;background:var(--surface)}
.filelist li button{border:none;background:transparent;cursor:pointer;color:var(--ink-3);font-size:16px;line-height:1;padding:0 4px}
.msg{font-size:13px;margin:8px 0 0}
.msg.err{color:var(--bad)}.msg.okc{color:var(--ok)}
.empty{color:var(--ink-3);font-size:13.5px;padding:14px 4px}
.spin{display:inline-block;width:13px;height:13px;border:2px solid var(--hairline);border-top-color:var(--accent);border-radius:50%;animation:spin .8s linear infinite;vertical-align:-2px;margin-right:6px}
@keyframes spin{to{transform:rotate(360deg)}}
.loading{color:var(--ink-3);font-size:13.5px;padding:14px 4px}
.loginwrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
.logincard{width:min(380px,100%);border:1px solid var(--hairline);background:var(--panel);border-radius:12px;padding:28px 26px;box-shadow:0 6px 30px rgba(0,0,0,.06)}
.logincard h1{font-size:19px;margin:0 0 2px}
.logincard .eyebrow{font-family:"IBM Plex Mono",monospace;font-size:11px;letter-spacing:.12em;color:var(--ink-3);margin:0 0 18px}
.logincard label{display:block;font-size:13px;color:var(--ink-2);margin:12px 0 4px}
.logincard input{width:100%}
.logincard .btn{width:100%;justify-content:center;margin-top:18px;padding:9px 14px}
.logincard .dtbtn{padding:12px 14px;font-size:15px}
.modalbg{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:40;display:flex;align-items:center;justify-content:center;padding:20px}
.modal{width:min(720px,100%);max-height:90vh;overflow:auto;background:var(--panel);border:1px solid var(--hairline);border-radius:12px;padding:22px 24px;box-shadow:0 10px 40px rgba(0,0,0,.25)}
.modal h2{font-size:17px;margin:0 0 6px}
.modal .acts{display:flex;justify-content:flex-end;gap:10px;margin-top:16px}
#toasts{position:fixed;right:16px;bottom:16px;z-index:60;display:flex;flex-direction:column;gap:8px;max-width:min(420px,calc(100% - 32px))}
.toast{background:var(--tooltip-bg);color:var(--tooltip-ink);border-radius:8px;padding:9px 14px;font-size:13.5px;box-shadow:0 4px 18px rgba(0,0,0,.25)}
.toast.err{background:var(--bad);color:#fff}
.noteedit{display:flex;gap:6px;align-items:center;min-width:16em}
.noteedit input{flex:1;min-width:8em}
.chip.btnchip{cursor:pointer}
.chips{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
a.act{color:var(--accent);cursor:pointer;text-decoration:underline}
@media (max-width:760px){.topbar h1{font-size:18px}.card .v{font-size:20px}.modal{padding:16px}}
/* ---- 第 1b 阶段：项目与设备 ---- */
.topbar .projsel{display:inline-flex;align-items:center;gap:6px;font-size:13px;color:var(--ink-2)}
.projgrid{display:grid;grid-template-columns:minmax(260px,330px) minmax(0,1fr);gap:16px;align-items:start}
@media (max-width:1180px){.projgrid{grid-template-columns:1fr}}
.frm input[type=text]{width:100%;min-width:0}
#mcNewForm{margin:6px 0 12px}
#mcNewForm .toggle{margin-right:6px}
.req{color:#c0392b}
table.t td input[type=text]{width:100%;min-width:7em;padding:3px 7px;font-size:12.5px}
table.t td select{font-size:12.5px;padding:3px 6px}
.chip.model-aisle{border-color:var(--warn);color:var(--warn);background:var(--warn-soft)}
