:root{
  --ink:#14181F; --mut:#6B7482; --line:#DCE1E9; --bg:#F4F6F9; --card:#fff;
  --ai:#6A5AE0; --ai-bg:#F1EFFE; --ok:#0E9F6E; --doing:#1570EF; --warn:#B54708; --fail:#D92D20;
  --tap:#3B3F47;
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;height:100%;background:#E9ECF1;color:var(--ink);
  font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  font-size:15px;line-height:1.45;overscroll-behavior:none}
button{font:inherit;color:inherit;cursor:pointer}
input,textarea,select{font:inherit;color:var(--ink);background:#fff;border:1px solid var(--line);border-radius:9px;padding:9px 10px;width:100%}
input:focus,textarea:focus,select:focus{outline:2px solid #C9C2F6;outline-offset:-1px}
textarea{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.55;min-height:150px;white-space:pre;resize:vertical}
select{appearance:none;padding-right:26px;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6'><path d='M1 1l4 4 4-4' fill='none' stroke='%236B7482' stroke-width='1.6'/></svg>");
  background-repeat:no-repeat;background-position:right 9px center}
.hide{display:none !important}

.phone{position:relative;width:100%;height:100dvh;max-width:520px;margin:0 auto;background:var(--bg);
  display:flex;flex-direction:column;overflow:hidden}
@media (min-width:560px){.phone{height:min(920px,96dvh);margin:max(2vh,12px) auto;border-radius:26px;
  box-shadow:0 20px 54px rgba(20,24,31,.2),0 0 0 9px #1B1F27}}

/* 登录 */
#gate{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:24px;background:var(--bg);z-index:9}
#gate.pane{display:flex}
.gate-box{width:100%;max-width:330px;background:#fff;border:1px solid var(--line);border-radius:16px;padding:20px}
.gate-brand{font-size:13px;font-weight:700;letter-spacing:1px;color:var(--ai)}
.gate-line{font-size:13.5px;color:var(--mut);margin:8px 0 16px}
.gate-msg{font-size:12.5px;color:var(--fail);min-height:18px;margin-top:8px}

/* 头部 */
header{flex:0 0 auto;background:#fff;border-bottom:1px solid var(--line);padding:10px 12px 8px}
.h-row{display:flex;align-items:center;gap:8px}
.h-row.sub{margin-top:6px;min-height:28px}
.map-pick{flex:1;min-width:0;font-size:16px;font-weight:600;padding:6px 8px;border:1px solid transparent;background:transparent;
  text-overflow:ellipsis;white-space:nowrap;overflow:hidden}
.rev{font-size:11.5px;color:var(--mut);font-variant-numeric:tabular-nums}
.icon-btn{width:34px;height:34px;border-radius:9px;border:1px solid var(--line);background:#fff;font-size:17px;line-height:1;color:var(--tap);flex:0 0 auto}
.icon-btn.sm{width:30px;height:30px;font-size:15px}
.ai-pill{border:1px solid #D8D2FB;background:var(--ai-bg);color:var(--ai);border-radius:8px;font-size:12.5px;font-weight:600;padding:5px 9px}
.live{margin-left:auto;font-size:11.5px;color:var(--mut)}
.live.on{color:var(--ok)}

/* 主区 */
main{flex:1 1 auto;position:relative;overflow:hidden}
.pane{position:absolute;inset:0;display:none;overflow:hidden}
.pane.on{display:block}
.pad{position:absolute;inset:0;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:12px 12px 26px}

/* 画布 */
#p-map{background:radial-gradient(circle at 1px 1px,#E0E5EC 1px,transparent 0) 0 0/22px 22px;touch-action:none}
#viewport{position:absolute;left:0;top:0;transform-origin:0 0;will-change:transform}
#edges{position:absolute;left:0;top:0;overflow:visible;pointer-events:none}
#edges path{fill:none;stroke:#B7BFCC;stroke-width:1.6}
#edges path.ai{stroke:#B0A6F2;stroke-dasharray:5 4}
.n{position:absolute;width:max-content;max-width:200px;display:flex;align-items:center;gap:7px;background:var(--card);
  border:1px solid var(--line);border-radius:10px;padding:8px 10px;min-height:38px;box-shadow:0 1px 2px rgba(20,24,31,.05)}
.n .lb{font-size:14px;font-weight:500;line-height:1.3;flex:1;min-width:0;word-break:break-word}
.n.d0 .lb{font-size:16.5px;font-weight:600}
.n.d1 .lb{font-size:14.5px;font-weight:600}
.n .st{flex:0 0 auto;width:10px;height:10px;border-radius:50%;border:2px solid #C3CBD8}
.st.open{border-color:#B9C0CB}
.st.doing{border-color:var(--doing);background:#DCEAFF}
.st.pend{border-color:var(--ai);background:var(--ai-bg)}
.st.passed{border-color:var(--ok);background:var(--ok)}
.st.failed{border-color:var(--fail);background:var(--fail)}
.st.blocked{border-color:var(--warn);background:#FCEFD8}
.n .tag{flex:0 0 auto;font-size:10px;font-weight:700;color:var(--ai);background:var(--ai-bg);border-radius:4px;padding:2px 4px}
.n.sel{border:2px solid var(--ink)}
.n.pend{border-style:dashed;border-color:#A99CF5;background:#FAF9FF}
.n.code::after{content:"";position:absolute;left:-1px;bottom:-1px;width:11px;height:11px;border-radius:0 0 9px 0;background:#0E9F6E;opacity:.85}
.n.flash{animation:pop .9s ease-out}
@keyframes pop{0%{opacity:0}45%{opacity:1;box-shadow:0 0 0 7px rgba(106,90,224,.3)}100%{opacity:1;box-shadow:0 1px 2px rgba(20,24,31,.05)}}
.tog{position:absolute;right:-9px;bottom:-9px;width:20px;height:20px;border-radius:50%;background:#fff;border:1px solid #C3CBD8;
  color:var(--tap);font-size:11px;line-height:18px;text-align:center;font-weight:700}
.tog.has{background:var(--ink);color:#fff;border-color:var(--ink)}
.zoom{position:absolute;right:12px;top:12px;display:flex;flex-direction:column;gap:6px}
.zoom button{width:38px;height:38px;border-radius:10px;border:1px solid var(--line);background:#fff;font-size:16px;font-weight:600;color:var(--tap)}
.fab{position:absolute;left:12px;bottom:14px;display:flex;gap:8px}
.fab button{height:40px;padding:0 13px;border-radius:20px;border:1px solid #C3CBD8;background:#fff;font-size:13.5px;font-weight:600;color:var(--tap);box-shadow:0 2px 8px rgba(20,24,31,.1)}
.fab button.pri{background:var(--ai);border-color:var(--ai);color:#fff}

/* 通用件 */
.card{background:#fff;border:1px solid var(--line);border-radius:12px;padding:12px;margin-bottom:10px}
.card h3{margin:0 0 8px;font-size:14px;font-weight:600}
.k{font-size:12px;color:var(--mut);font-weight:600;margin:0 0 4px}
.row{display:flex;align-items:center;gap:8px}
.row.wrap{flex-wrap:wrap}
.block{display:block;width:100%}
.btn{height:40px;padding:0 14px;border-radius:10px;border:1px solid var(--line);background:#fff;font-size:13.5px;font-weight:600;color:var(--tap)}
.btn.pri{background:var(--ink);border-color:var(--ink);color:#fff}
.btn.danger{color:var(--fail);border-color:#F3C1BC}
.btn.danger.armed{background:var(--fail);border-color:var(--fail);color:#fff}
.btn:disabled{opacity:.45}
.tall{min-height:78px;font-family:inherit;font-size:14px}
.chip{display:inline-block;font-size:11px;font-weight:600;border-radius:5px;padding:2px 7px;background:#EEF1F6;color:#39404C}
.chip.ai{background:var(--ai-bg);color:var(--ai)}
.chip.ok{background:#E4F7EE;color:var(--ok)}
.chip.no{background:#FDE8E8;color:var(--fail)}
.chip.warn{background:#FCEFD8;color:var(--warn)}
.segs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
.segs button{height:32px;padding:0 10px;border-radius:8px;border:1px solid var(--line);background:#fff;font-size:12.5px;font-weight:600;color:var(--mut)}
.segs button.on{border-color:var(--ink);color:var(--ink);background:#EEF1F6}
.out{margin-top:10px;background:#12161D;color:#D6E0EE;border-radius:10px;padding:10px;font-family:ui-monospace,Menlo,monospace;
  font-size:11.5px;line-height:1.6;white-space:pre-wrap;word-break:break-word;max-height:280px;overflow:auto}
.out .e{color:#FF8A9B}.out .g{color:#7EE2A8}.out .w{color:#FFCF6B}
.mono{font-family:ui-monospace,Menlo,monospace;font-size:11.5px;color:#39404C;line-height:1.6;white-space:pre-wrap;word-break:break-word}
table{width:100%;border-collapse:collapse;font-size:12px}
/* 390 宽上三列都要放得下：定死列宽 + 允许换行，否则"用来干什么"整列被切在屏幕外 */
#apiTable{table-layout:fixed}
#apiTable th:nth-child(1),#apiTable td:nth-child(1){width:17%}
#apiTable th:nth-child(2),#apiTable td:nth-child(2){width:38%;word-break:break-all}
#apiTable th:nth-child(3),#apiTable td:nth-child(3){width:45%;white-space:normal}
#apiTable th,#apiTable td{padding:7px 6px;vertical-align:top;border-bottom:1px solid var(--line);text-align:left}
th,td{text-align:left;padding:7px 6px;border-bottom:1px solid var(--line);vertical-align:top}
th{color:var(--mut);font-size:11px;font-weight:600;white-space:nowrap}
code.m{font-family:ui-monospace,Menlo,monospace;font-size:11px;background:#EEF1F6;border-radius:4px;padding:1px 4px}
.hint{font-size:12px;color:var(--mut);margin-top:8px;line-height:1.55}
.flow{margin:2px 0 0;padding-left:20px;font-size:13.5px;line-height:1.62}
.flow li{margin:7px 0}
.flow b{font-weight:650}
.pend-row{display:flex;gap:8px;align-items:center;background:#fff;border:1px dashed #A99CF5;border-radius:10px;padding:9px 10px;margin-bottom:8px}
.pend-row .t{flex:1;min-width:0;font-size:13.5px;font-weight:500}
.pend-row .u{font-size:11px;color:var(--mut)}
.mini{height:32px;padding:0 10px;border-radius:8px;font-size:12.5px;font-weight:600;border:1px solid var(--line);background:#fff;color:var(--tap)}
.mini.ok{color:var(--ok);border-color:#B4E3CC}.mini.no{color:var(--fail);border-color:#F3C1BC}

/* 底部导航 */
nav{flex:0 0 auto;display:flex;background:#fff;border-top:1px solid var(--line);padding:6px 4px calc(6px + env(safe-area-inset-bottom))}
nav button{flex:1;border:0;background:none;padding:8px 2px 6px;font-size:12.5px;font-weight:600;color:var(--mut)}
nav button.on{color:var(--ink);box-shadow:inset 0 2px 0 var(--ink)}

.toast{position:absolute;left:50%;bottom:78px;transform:translate(-50%,12px);background:rgba(20,24,31,.94);color:#fff;
  pointer-events:none;
  font-size:13px;padding:9px 14px;border-radius:20px;opacity:0;pointer-events:none;transition:.22s;max-width:86%;z-index:20}
.toast.on{opacity:1;transform:translate(-50%,0)}

/* ── 类图投影（PRD §5.5）：框=契约/组件，线=依赖边，泳道=层 ───── */
.vmode{position:absolute;left:12px;top:12px;z-index:3;display:flex;gap:3px;padding:3px;
  background:rgba(255,255,255,.92);border:1px solid var(--line);border-radius:10px;
  box-shadow:0 1px 3px rgba(20,24,31,.07)}
.vmode button{border:0;background:none;font:inherit;font-size:12.5px;font-weight:600;color:var(--mut);
  padding:6px 11px;border-radius:7px;min-height:32px}
.vmode button.on{background:var(--ink);color:#fff}

.lane{position:absolute;border:1px dashed #C9D1DC;border-radius:12px;background:rgba(120,130,150,.05)}
.lane b{position:absolute;left:9px;top:-8px;font-size:10.5px;font-weight:700;letter-spacing:.3px;
  padding:1px 7px;border-radius:6px;background:#8A94A3;color:#fff}

.cn{position:absolute;width:216px;background:var(--card);border:1.5px solid var(--line);
  border-radius:11px;box-shadow:0 1px 3px rgba(20,24,31,.06);overflow:hidden;font-size:12px}
.cn.sel{border-color:var(--ink);box-shadow:0 0 0 3px rgba(20,24,31,.11)}
.cn.pend{border-style:dashed;border-color:#A99CF5}
.chd{display:flex;align-items:center;gap:6px;padding:7px 9px;background:var(--bg);border-bottom:1px solid var(--line)}
.ck{font-size:10px;font-weight:700;padding:1px 5px;border-radius:5px;background:#fff;
  border:1px solid var(--line);color:var(--mut);flex:0 0 auto}
.cnm{flex:1;min-width:0;font-size:13px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lk{font-size:11px;flex:0 0 auto}
.cf,.cs{font-family:ui-monospace,Menlo,monospace;font-size:10.5px;color:var(--mut);padding:4px 9px 0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cs{color:#39404C}
.cm{list-style:none;margin:4px 0 0;padding:0 0 6px}
.cm li{display:flex;align-items:center;gap:6px;padding:4px 9px;font-size:11.5px;
  font-family:ui-monospace,Menlo,monospace}
.cm .st{flex:0 0 auto;width:9px;height:9px;border-radius:50%;border:2px solid #C3CBD8}
.cm li span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cn .cft{border-top:1px dashed var(--line);padding:5px 9px;font-size:10.5px;color:var(--mut);
  display:flex;align-items:center;gap:6px}
.cn .cft span:first-child{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.drift{flex:0 0 auto;font-weight:700}.drift.bad{color:var(--fail)}.drift.good{color:var(--ok)}

#edges path{fill:none;stroke:#98A2B3;stroke-width:1.4}
.de-inherit{stroke:#5A6472;stroke-width:1.6;marker-end:url(#dtri)}
.de-impl{stroke:#5A6472;stroke-width:1.6;stroke-dasharray:5 4;marker-end:url(#dtri)}
.de-owns{stroke:var(--ai);stroke-width:1.8;marker-start:url(#ddia)}
.de-uses{stroke:#8A94A3;stroke-dasharray:3 3;marker-end:url(#darr)}
.de-calls{stroke:var(--ok);stroke-dasharray:6 3 1 3;marker-end:url(#darr)}

.row select{flex:1;min-width:0}
input:disabled,textarea:disabled{background:#F1F3F7;color:#8A94A3}
.dep{display:flex;align-items:center;gap:7px;padding:4px 0;border-bottom:1px dashed var(--line)}
.dep .dt{flex:0 0 auto;font-size:10.5px;font-weight:700;padding:1px 6px;border-radius:5px;
  background:var(--ai-bg);color:var(--ai)}
.dep .dd{flex:1;min-width:0;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
