/* ---------- design tokens ---------- */
:root{
  --font:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;--mono:"JetBrains Mono",ui-monospace,Menlo,monospace;
  --bg:#f5f7fb;--bg2:#eef1f6;--card:#ffffff;--card2:#f7f9fc;--line:#e3e8ef;--line2:#d4dbe5;--fg:#0f172a;--fg2:#334155;--muted:#64748b;--muted2:#94a3b8;
  --ok:#16a34a;--ok-bg:#dcfce7;--bad:#dc2626;--bad-bg:#fee2e2;--idle:#d97706;--idle-bg:#fef3c7;--unk:#94a3b8;--unk-bg:#f1f5f9;
  --acc:#2563eb;--acc-bg:#dbeafe;--acc2:#7c3aed;--acc2-bg:#ede9fe;--warp:#ea580c;--warp-bg:#ffedd5;
  --r:10px;--r-sm:7px;--shadow:0 1px 2px rgba(15,23,42,.05),0 1px 3px rgba(15,23,42,.06);--shadow-lg:0 20px 60px rgba(15,23,42,.18);--side:232px}
@media (prefers-color-scheme:dark){:root{--bg:#0b0f17;--bg2:#0f141d;--card:#141a24;--card2:#1a2130;--line:#232c3b;--line2:#2d3748;--fg:#e8edf5;--fg2:#c4ccd8;--muted:#8b97ab;--muted2:#5f6b7f;
  --ok-bg:#0f2e1c;--bad-bg:#3a1416;--idle-bg:#3a2a0c;--unk-bg:#1c2330;--acc-bg:#172554;--acc2-bg:#2e1065;--warp-bg:#431407;--shadow:0 1px 2px rgba(0,0,0,.3);--shadow-lg:0 20px 60px rgba(0,0,0,.6)}}
[v-cloak]{display:none}*{box-sizing:border-box}html,body{margin:0;background:var(--bg);color:var(--fg);font:13.5px/1.5 var(--font);-webkit-font-smoothing:antialiased}
a{color:var(--acc);text-decoration:none;cursor:pointer}.mono{font-family:var(--mono);font-size:12.5px}.muted{color:var(--muted)}.small{font-size:12px}.bad{color:var(--bad)}.ok{color:var(--ok)}.spacer{flex:1}.nowrap{white-space:nowrap}
.sub{font-size:12px;color:var(--muted);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ico{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;flex:none;vertical-align:-3px}
/* ---------- layout ---------- */
#app{display:flex;min-height:100vh}
.side{width:var(--side);flex:none;background:var(--card);border-right:1px solid var(--line);display:flex;flex-direction:column;padding:16px 12px;position:sticky;top:0;height:100vh}
.side .brand{font-weight:700;font-size:15px;letter-spacing:-.01em;display:flex;align-items:center;gap:10px;padding:4px 10px 18px}.logo{width:26px;height:26px;border-radius:8px;background:linear-gradient(135deg,var(--acc),var(--acc2));display:grid;place-items:center;color:#fff;font-size:13px;font-weight:800}
.side .sec{font-size:10.5px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted2);padding:10px 12px 4px}
.side a{display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:8px;color:var(--fg2);font-size:13.5px;font-weight:500}.side a:hover{background:var(--card2);color:var(--fg)}.side a.active{background:var(--acc-bg);color:var(--acc)}.side a .ico{color:inherit;opacity:.9}
.side .cnt{margin-left:auto;font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums}.side .badge{font-size:10.5px;font-weight:600;background:var(--bad);color:#fff;border-radius:999px;padding:1px 7px;margin-left:6px}
.side-foot{display:flex;flex-direction:column;gap:8px;padding:10px 6px 0;border-top:1px solid var(--line);margin-top:10px}.side-foot .st{font-size:11.5px;color:var(--muted);display:flex;align-items:center;gap:6px}.live{width:7px;height:7px;border-radius:50%;background:var(--ok);box-shadow:0 0 0 3px var(--ok-bg)}
main{flex:1;padding:26px 32px 40px;min-width:0;max-width:1600px}main.loading{color:var(--muted);text-align:center;padding-top:80px}
.ph{display:flex;align-items:flex-start;gap:16px;margin-bottom:18px}.ph h1{font-size:21px;letter-spacing:-.01em;margin:0 0 2px;font-weight:700}.ph p{margin:0;font-size:13px;color:var(--muted);max-width:720px}.ph .acts{display:flex;gap:8px;align-items:center;margin-left:auto;flex:none}
/* ---------- stats ---------- */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;margin-bottom:16px}.stat{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:14px 16px;box-shadow:var(--shadow)}.stat .k{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);font-weight:600}.stat .v{margin-top:6px;display:flex;align-items:baseline;gap:6px}.stat .v b{font-size:26px;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums}.stat .of{color:var(--muted);font-size:12.5px}.stat .v.mono{font-size:13px;line-height:1.6;display:block}.stat.alert{border-color:var(--bad);background:var(--bad-bg)}.stat.alert b{color:var(--bad)}
/* ---------- panels & tables ---------- */
.panel{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:16px 18px;margin-bottom:16px;box-shadow:var(--shadow)}.panel.table{padding:0;overflow-x:auto}.panel-h{font-weight:600;font-size:14px;margin-bottom:12px;display:flex;gap:10px;align-items:center}.panel-h .muted{font-weight:400;font-size:12.5px}.panel-h a{margin-left:auto;font-size:12.5px;font-weight:500}
table{width:100%;border-collapse:collapse;font-size:13px}th{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);font-weight:600;text-align:left;padding:11px 14px;border-bottom:1px solid var(--line);white-space:nowrap;background:var(--card2)}td{padding:11px 14px;border-bottom:1px solid var(--line);vertical-align:middle;white-space:nowrap}tbody tr:last-child td{border-bottom:none}
td b{font-weight:600}th.w1,td.w1{width:34px;padding-right:0}td.act,th.act{text-align:right}td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}tr.click{cursor:pointer}tr.click:hover td{background:var(--card2)}td.empty{text-align:center;color:var(--muted);padding:34px;white-space:normal}
table.inner th{background:transparent}table.inner td,table.inner th{padding:9px 10px}
.track{height:6px;width:96px;background:var(--bg2);border-radius:3px;overflow:hidden;display:inline-block;vertical-align:middle}.fill{display:block;height:100%;background:var(--ok);border-radius:3px;transition:width .5s}.fill.acc{background:linear-gradient(90deg,var(--acc),var(--acc2))}
/* ---------- controls ---------- */
button,.btn{background:var(--card);color:var(--fg2);border:1px solid var(--line2);border-radius:var(--r-sm);padding:6px 11px;cursor:pointer;font:inherit;font-size:12.5px;font-weight:500;display:inline-flex;align-items:center;gap:6px;line-height:1.2;transition:.12s;box-shadow:var(--shadow)}button:hover,.btn:hover{border-color:var(--muted2);color:var(--fg)}
button.primary{background:var(--acc);border-color:var(--acc);color:#fff}button.primary:hover{filter:brightness(1.08)}button.danger{color:var(--bad);border-color:color-mix(in srgb,var(--bad) 40%,var(--line2))}button.danger:hover{background:var(--bad-bg)}button.danger.solid{background:var(--bad);border-color:var(--bad);color:#fff}
button.ghost{border-color:transparent;box-shadow:none;background:transparent}button.ghost:hover{background:var(--card2)}button.icon{padding:6px}button:disabled{opacity:.5;cursor:default}
.acts-row{display:inline-flex;gap:4px}.acts-row button{padding:5px 9px}
input,select,textarea{font:inherit;font-size:13px;padding:7px 10px;border:1px solid var(--line2);border-radius:var(--r-sm);background:var(--card);color:var(--fg);max-width:100%}input:focus,select:focus{outline:none;border-color:var(--acc);box-shadow:0 0 0 3px var(--acc-bg)}select{padding-right:26px}
.row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.row.end{justify-content:flex-end;margin-top:18px}.row label{display:flex;gap:8px;align-items:center;font-size:12.5px;color:var(--muted)}
.seg{display:inline-flex;border:1px solid var(--line2);border-radius:var(--r-sm);overflow:hidden;background:var(--card)}.seg button{border:none;border-radius:0;box-shadow:none;padding:6px 12px}.seg button.on{background:var(--acc);color:#fff}
.dot{display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--unk);flex:none;vertical-align:middle}.dot.ok{background:var(--ok);box-shadow:0 0 0 3px var(--ok-bg)}.dot.bad{background:var(--bad);box-shadow:0 0 0 3px var(--bad-bg)}.dot.idle{background:var(--idle);box-shadow:0 0 0 3px var(--idle-bg)}.dot.unk{background:var(--unk)}.dot.busy{background:var(--acc);animation:pulse 1.2s ease-in-out infinite}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 var(--acc-bg)}50%{box-shadow:0 0 0 5px transparent}}
.pill{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;padding:2px 9px;border-radius:999px;white-space:nowrap;background:var(--unk-bg);color:var(--muted)}.pill.ok{background:var(--ok-bg);color:var(--ok)}.pill.bad{background:var(--bad-bg);color:var(--bad)}.pill.idle{background:var(--idle-bg);color:var(--idle)}.pill.acc{background:var(--acc-bg);color:var(--acc)}.pill.warp{background:var(--warp-bg);color:var(--warp)}.pill.busy{background:var(--acc-bg);color:var(--acc)}
.tag{display:inline-flex;align-items:center;gap:4px;font-size:11.5px;font-weight:500;padding:2px 8px;border-radius:6px;border:1px solid var(--line);background:var(--card2);white-space:nowrap;margin-right:4px}.tag.primary{border-color:var(--acc);color:var(--acc)}.tag.legacy{border-color:var(--idle);color:var(--idle)}.tag.current{background:var(--ok-bg);color:var(--ok);border-color:transparent}.tag.valid{background:var(--idle-bg);color:var(--idle);border-color:transparent}.tag.stale{background:var(--bad-bg);color:var(--bad);border-color:transparent}.tag.unknown{color:var(--muted)}.tag button.x{padding:0 2px;margin:0 -4px 0 2px}
.switch{position:relative;width:38px;height:22px;display:inline-block;vertical-align:middle;flex:none}.switch input{opacity:0;width:0;height:0}.slider{position:absolute;inset:0;background:var(--line2);border-radius:22px;cursor:pointer;transition:.2s}.slider::before{content:"";position:absolute;width:16px;height:16px;left:3px;top:3px;background:#fff;border-radius:50%;transition:.2s;box-shadow:0 1px 2px rgba(0,0,0,.3)}.switch input:checked+.slider{background:var(--warp)}.switch input:checked+.slider::before{transform:translateX(16px)}
.ev{display:flex;gap:12px;padding:6px 0;border-bottom:1px solid var(--line);font-family:var(--mono);font-size:12px;white-space:normal;word-break:break-word}.ev:last-child{border-bottom:none}.ev .t{color:var(--muted2);flex:none;width:150px}.ev.error{color:var(--bad)}.ev.ok{color:var(--ok)}.ev.warn{color:var(--idle)}
.err{color:var(--bad);font-size:12.5px;margin:8px 0;background:var(--bad-bg);border-radius:var(--r-sm);padding:8px 12px;white-space:normal}
.busy{color:var(--acc)}
/* ---------- topology ---------- */
.topo-wrap{overflow-x:auto}.topo-svg{width:100%;height:auto;display:block;min-width:900px}
.edge{fill:none;stroke:var(--line2);stroke-width:1.6}.edge.alive{stroke:var(--ok);stroke-dasharray:5 5;animation:flow .9s linear infinite}.edge.idle{stroke:var(--idle)}.edge.dead{stroke:var(--bad)}.edge.warp{stroke:var(--warp)}.edge.thick{stroke-width:2.2}
@keyframes flow{to{stroke-dashoffset:-10}}
.n-box{fill:var(--card);stroke:var(--line2);stroke-width:1.2}.n-box.entry{stroke:var(--acc)}.n-box.donor{stroke:var(--acc2)}.n-box.down{stroke:var(--bad);stroke-dasharray:4 3}.n-box.device{fill:var(--card2);stroke:var(--line)}.n-box.group{fill:var(--card);stroke:var(--line2)}.n-box.group.on{stroke:var(--ok)}.n-box.device.on{stroke:var(--ok)}.n-box.exit{fill:var(--card)}.n-box.exit.warp{stroke:var(--warp)}.n-box.exit.direct{stroke:var(--ok)}
.n-title{fill:var(--fg);font-size:12.5px;font-weight:600}.n-sub{fill:var(--muted);font-size:10.5px}.n-small{fill:var(--fg2);font-size:11px;font-weight:500}.n-tiny{fill:var(--muted);font-size:9.5px}
.lbl-bg{fill:var(--card);stroke:var(--line);stroke-width:1;rx:4}.lbl{fill:var(--fg2);font-size:10px;font-family:var(--mono);text-anchor:middle}
.col-h{fill:var(--muted2);font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase}.nodeg{cursor:pointer}.nodeg:hover .n-box{stroke-width:2}
.legend{display:flex;gap:16px;font-size:12px;color:var(--muted);margin-top:8px;flex-wrap:wrap}.legend span{display:inline-flex;align-items:center;gap:6px}.legend i{width:18px;height:0;border-top:2px dashed var(--ok)}.legend i.idle{border-color:var(--idle);border-style:solid}.legend i.dead{border-color:var(--bad);border-style:solid}.legend i.warp{border-color:var(--warp);border-style:solid}.legend i.unk{border-color:var(--line2);border-style:solid}
/* ---------- drawer & modals ---------- */
.overlay{position:fixed;inset:0;background:rgba(15,23,42,.45);z-index:20;backdrop-filter:blur(2px)}.overlay.center{display:flex;align-items:center;justify-content:center}
.drawer{position:absolute;right:0;top:0;bottom:0;width:min(1180px,96vw);background:var(--card);border-left:1px solid var(--line);overflow-y:auto;padding:22px 28px 40px;box-shadow:var(--shadow-lg)}
.dh{display:flex;align-items:center;gap:12px;padding-bottom:14px;border-bottom:1px solid var(--line);margin-bottom:4px}.dh h2{margin:0;font-size:17px;font-weight:700;letter-spacing:-.01em}.dh .sub{margin-top:3px}.dh .acts{display:flex;gap:6px;margin-left:auto}
.dsec{padding:16px 0;border-bottom:1px solid var(--line)}.dsec:last-child{border-bottom:none}.dt{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);font-weight:600;margin-bottom:10px}.dsec.danger{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.dsec.danger .sub{white-space:normal}
.kvgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:10px 18px}.kvgrid.two{grid-template-columns:1fr 1fr;margin-top:8px}.kvgrid div{display:flex;flex-direction:column;min-width:0}.kvgrid span{font-size:11px;color:var(--muted)}.kvgrid b{font-weight:500;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kvgrid small{color:var(--muted);font-weight:400}
.warpbox{display:flex;gap:14px;align-items:flex-start;background:var(--card2);border:1px solid var(--line);border-radius:var(--r);padding:12px 14px}
.box{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:22px 24px;width:min(600px,94vw);max-height:92vh;overflow:auto;box-shadow:var(--shadow-lg)}.box h3{margin:0 0 14px;font-size:16px;font-weight:700}.box p{white-space:normal;color:var(--fg2);margin:0 0 12px}.box ul{margin:0 0 12px;padding-left:18px;color:var(--fg2)}.box li{margin:3px 0}
.box.confirm h3{display:flex;align-items:center;gap:10px}.box.confirm .warnico{width:34px;height:34px;border-radius:10px;background:var(--bad-bg);color:var(--bad);display:grid;place-items:center;flex:none}
.form{display:grid;grid-template-columns:1fr 1fr;gap:12px 14px}.form label{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--muted);font-weight:500}.form label.full{grid-column:1/-1}.form label.chk{flex-direction:row;align-items:center;font-weight:400;color:var(--fg2)}.form label small{color:var(--idle);font-weight:400}
label.chk{display:flex;gap:8px;align-items:center;font-size:13px;color:var(--fg2);white-space:normal;margin:6px 0 2px}
.box.qr img{display:block;margin:0 auto 12px;width:260px;border-radius:8px;background:#fff;padding:8px;border:1px solid var(--line)}.box.qr pre{font-size:11px;background:var(--bg2);padding:10px 12px;border-radius:8px;overflow:auto;max-height:240px;margin:0}
.toasts{position:fixed;right:18px;bottom:18px;display:flex;flex-direction:column;gap:8px;z-index:40;width:min(380px,calc(100vw - 36px));pointer-events:none}
.toast{pointer-events:auto;position:relative;overflow:hidden;display:flex;align-items:flex-start;gap:10px;background:var(--card);color:var(--fg);border:1px solid var(--line);border-radius:10px;padding:11px 12px 13px;font-size:13px;line-height:1.4;box-shadow:var(--shadow-lg)}
.t-ico{flex:none;width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:700;background:var(--acc-bg);color:var(--acc)}
.toast.ok .t-ico{background:var(--ok-bg);color:var(--ok)}.toast.bad .t-ico{background:var(--bad-bg);color:var(--bad)}
.t-msg{flex:1;min-width:0;word-break:break-word;padding-top:1px}.t-n{margin-left:6px;font-size:11px;color:var(--muted)}
.t-x{flex:none;border:none;background:none;box-shadow:none;padding:0 2px;font-size:17px;line-height:1;color:var(--muted);cursor:pointer}.t-x:hover{color:var(--fg)}
.t-bar{position:absolute;left:0;bottom:0;height:2px;width:100%;background:var(--acc);transform-origin:left;animation:toastbar linear forwards}
.toast.ok .t-bar{background:var(--ok)}.toast.bad .t-bar{background:var(--bad)}.toast:hover .t-bar{animation-play-state:paused}
@keyframes toastbar{from{transform:scaleX(1)}to{transform:scaleX(0)}}
.toast-enter-active,.toast-leave-active{transition:all .22s ease}.toast-enter-from{opacity:0;transform:translateY(8px)}.toast-leave-to{opacity:0;transform:translateX(24px)}.toast-move{transition:transform .2s ease}
.login-body{display:flex;align-items:center;justify-content:center;min-height:100vh}.login{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:28px;width:340px;display:flex;flex-direction:column;gap:12px;box-shadow:var(--shadow-lg)}.login .brand{font-size:18px;font-weight:700;margin-bottom:6px;display:flex;align-items:center;gap:10px}.login .logo{width:26px;height:26px;border-radius:8px;display:grid;place-items:center;color:#fff;font-size:13px;font-weight:800}.login label{display:flex;flex-direction:column;gap:5px;font-size:12px;color:var(--muted);font-weight:500}.login .err{margin:0}
@media(max-width:960px){#app{flex-direction:column}.side{width:100%;height:auto;position:static;flex-direction:row;flex-wrap:wrap;align-items:center;padding:10px}.side .brand{padding:4px 10px}.side .sec{display:none}.side-foot{flex-direction:row;margin:0 0 0 auto;border:none;padding:0}.side .spacer{display:none}main{padding:16px}.form{grid-template-columns:1fr}}

.dim{opacity:.14;transition:opacity .2s}.hl .n-box,.n-box.hl{stroke-width:2.4}.edge.hl{stroke-width:3}
.tracebox{display:flex;align-items:center;gap:4px}.tracebox input{width:200px}
.paths{display:flex;flex-direction:column;gap:8px;margin:12px 0 4px}.path{display:flex;align-items:stretch;gap:8px;flex-wrap:wrap;background:var(--card2);border:1px solid var(--line);border-radius:var(--r);padding:8px 12px}
.hop{display:flex;flex-direction:column;min-width:140px;max-width:300px}.hop b{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.hop small{color:var(--muted);font-size:11.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hop.device b{color:var(--fg)}.hop.entry b{color:var(--acc)}.hop.donor b{color:var(--acc2)}.hop.exit b{color:var(--ok)}.arrow{color:var(--muted2);align-self:center;font-size:16px}

.matrix-wrap{overflow-x:auto}.matrix{width:auto;min-width:60%;border-collapse:separate;border-spacing:6px}.matrix th{background:transparent;text-transform:none;letter-spacing:0;font-size:13px;color:var(--fg);padding:8px 10px;border:none;vertical-align:middle;white-space:nowrap}.matrix th.corner{color:var(--muted2);font-size:11px;font-weight:500}.matrix th.click{cursor:pointer}.matrix th .sub{font-weight:400}
.matrix td.cell{border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 12px;min-width:170px;text-align:center;cursor:pointer;vertical-align:middle;background:var(--card2)}.matrix td.cell b{font-size:14px}.matrix td.cell .sub{text-align:center;white-space:normal}
.matrix td.ok{background:var(--ok-bg);border-color:color-mix(in srgb,var(--ok) 45%,transparent)}.matrix td.ok b{color:var(--ok)}
.matrix td.probing{background:var(--acc-bg);border-color:color-mix(in srgb,var(--acc) 45%,transparent)}.matrix td.probing b{color:var(--acc)}
.matrix td.dead{background:var(--idle-bg);border-color:color-mix(in srgb,var(--idle) 45%,transparent)}.matrix td.dead b{color:var(--idle)}
.matrix td.bad{background:var(--bad-bg);border-color:color-mix(in srgb,var(--bad) 45%,transparent)}.matrix td.bad b{color:var(--bad)}
.matrix td.none{background:transparent;border-style:dashed}
.legend i.cell-i{width:14px;height:14px;border:1px solid var(--line);border-radius:4px;border-top:1px solid var(--line)}.legend i.cell-i.ok{background:var(--ok-bg);border-color:var(--ok)}.legend i.cell-i.probing{background:var(--acc-bg);border-color:var(--acc)}.legend i.cell-i.dead{background:var(--idle-bg);border-color:var(--idle)}.legend i.cell-i.bad{background:var(--bad-bg);border-color:var(--bad)}.legend i.cell-i.none{border-style:dashed}

.matrix th.hot{background:var(--card2);border-radius:var(--r-sm)}.matrix td.cell.hot{box-shadow:0 0 0 2px color-mix(in srgb,var(--acc) 35%,transparent)}.matrix td.cell.focus{box-shadow:0 0 0 2px var(--acc);transform:translateY(-1px)}.matrix td.cell{transition:box-shadow .12s,transform .12s}
