/* grpcpipe 상태 지도 — 바깥 자원 0(CSP style-src 'self'). 색은 토큰으로 · 어두운 판이 기본, 밝은 판은 시스템 설정을 따른다. */
:root {
  --bg: #0b1020; --bg2: #121a33; --fg: #e8ecf8; --mut: #8f9bba; --line: rgba(140, 160, 210, .18);
  --glass: rgba(22, 30, 58, .62); --glass-b: rgba(150, 175, 255, .16);
  --core: #4f8cff; --core2: #9cc4ff; --hub: #8b5cf6; --hub2: #c4b5fd;
  --ok: #22c55e; --ok2: #a7f3c9; --warn: #f59e0b; --bad: #ef4444; --leaf: #38bdf8;
  --link: rgba(120, 160, 255, .32); --link-hi: #9cc4ff; --shadow: rgba(0, 0, 0, .55);
}
@media (prefers-color-scheme: light) {
  :root {
    --bg: #eef2fb; --bg2: #ffffff; --fg: #141a2b; --mut: #5b6684; --line: rgba(40, 60, 120, .14);
    --glass: rgba(255, 255, 255, .72); --glass-b: rgba(60, 90, 180, .16);
    --link: rgba(60, 100, 210, .28); --link-hi: #2463eb; --shadow: rgba(30, 40, 80, .25);
  }
}
* { box-sizing: border-box; }
html, body { margin: 0; }
body {
  min-height: 100vh; color: var(--fg); font: 14px/1.5 system-ui, -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
  background: radial-gradient(1200px 700px at 15% -10%, rgba(79, 140, 255, .22), transparent 60%),
              radial-gradient(900px 600px at 110% 10%, rgba(139, 92, 246, .18), transparent 60%), var(--bg);
}
.muted { color: var(--mut); }
.glass {
  background: var(--glass); border: 1px solid var(--glass-b); border-radius: 16px;
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); box-shadow: 0 10px 30px var(--shadow);
}
h1, h2 { margin: 0 0 8px; font-weight: 650; letter-spacing: -.01em; }
h2 { font-size: 15px; }

/* 머리 */
.top { position: sticky; top: 10px; z-index: 5; margin: 10px 16px; padding: 10px 14px; display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.brand { display: flex; align-items: center; gap: 10px; }
.brand strong { display: block; font-size: 15px; }
.brand span { display: block; color: var(--mut); font-size: 12px; }
.who { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.chip { padding: 3px 10px; border-radius: 999px; background: rgba(79, 140, 255, .16); border: 1px solid var(--glass-b); font-size: 12px; }
.btn { padding: 6px 12px; border-radius: 10px; border: 1px solid var(--glass-b); color: var(--fg); text-decoration: none; font-size: 13px; }
.btn.ghost:hover { background: rgba(79, 140, 255, .14); }

/* 요약 타일 */
.kpis { margin: 0 16px; display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.kpi { padding: 12px 14px; }
.kpi b { display: block; font-size: 24px; font-variant-numeric: tabular-nums; }
.kpi span { color: var(--mut); font-size: 12px; }
.kpi small { display: block; color: var(--mut); font-size: 11px; margin-top: 2px; }
.kpi.ok b { color: var(--ok); } .kpi.warn b { color: var(--warn); } .kpi.bad b { color: var(--bad); }

/* 본문 */
.layout { margin: 12px 16px; display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: 12px; }
@media (max-width: 1080px) { .layout { grid-template-columns: 1fr; } }
.stage { padding: 12px; min-width: 0; }
.stage-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
.legend { display: flex; gap: 12px; flex-wrap: wrap; color: var(--mut); font-size: 12px; align-items: center; }
.dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 5px; vertical-align: -1px; }
.dot.ok { background: var(--ok); } .dot.warn { background: var(--warn); } .dot.bad { background: var(--bad); }
.toggle { display: inline-flex; gap: 5px; align-items: center; cursor: pointer; }
.scene { perspective: 1400px; perspective-origin: 50% 40%; height: min(78vh, 820px); min-height: 460px; overflow: hidden; border-radius: 12px; cursor: grab; }
.scene.drag { cursor: grabbing; }
#graph { width: 100%; height: 100%; transform-style: preserve-3d; transition: transform .25s ease-out; }
.hint { font-size: 12px; margin: 8px 2px 0; }

/* 지도 요소 */
.ring { fill: none; stroke: var(--line); stroke-dasharray: 3 6; }
.link { fill: none; stroke: var(--link); stroke-width: 1.4; transition: stroke .15s, stroke-width .15s, opacity .15s; }
.link.flow { stroke-dasharray: 6 8; animation: flow 1.6s linear infinite; }
@keyframes flow { to { stroke-dashoffset: -28; } }
@media (prefers-reduced-motion: reduce) { .link.flow { animation: none; } #graph { transition: none; } }
.link.hi { stroke: var(--link-hi); stroke-width: 2.6; }
.dim .link:not(.hi) { opacity: .12; }
.dim .node:not(.hi) { opacity: .28; }
.node { cursor: pointer; transition: opacity .15s; }
.node .body { stroke: rgba(255, 255, 255, .55); stroke-width: 1; }
.node.sel .body { stroke: var(--link-hi); stroke-width: 3; }
.node text { fill: var(--fg); font-size: calc(11px / var(--z, 1)); paint-order: stroke; stroke: var(--bg); stroke-width: calc(3px / var(--z, 1)); stroke-linejoin: round; pointer-events: none; }
.node .lbl-leaf { font-size: calc(10.5px / var(--z, 1)); }
.node.quiet .lbl-leaf { opacity: 0; transition: opacity .15s; }
.node.quiet.hi .lbl-leaf, .node.quiet.sel .lbl-leaf, .node.quiet:focus .lbl-leaf { opacity: 1; }
.node .lbl-core { font-size: calc(15px / var(--z, 1)); font-weight: 700; }
.node .lbl-hub { font-size: calc(12.5px / var(--z, 1)); font-weight: 650; }
.badge rect { stroke: rgba(255, 255, 255, .5); stroke-width: .8; }
.badge text { font-size: 10px; font-weight: 700; fill: #fff; stroke: none; }

/* 옆 칸 */
.side { display: grid; gap: 12px; align-content: start; min-width: 0; }
.card { padding: 14px; }
.kv { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 13px; }
.kv dt { color: var(--mut); } .kv dd { margin: 0; word-break: break-word; }
.tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.tag { font-size: 11.5px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--glass-b); background: rgba(127, 140, 200, .1); }
.tag.ok { border-color: rgba(34, 197, 94, .45); } .tag.bad { border-color: rgba(239, 68, 68, .5); }
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 12.5px; font-variant-numeric: tabular-nums; }
th, td { text-align: left; padding: 5px 6px; border-bottom: 1px solid var(--line); white-space: nowrap; }
th { color: var(--mut); font-weight: 600; }
.up { color: var(--ok); } .down { color: var(--bad); } .same { color: var(--mut); }
.bar { height: 8px; border-radius: 999px; background: rgba(127, 140, 200, .2); overflow: hidden; margin: 6px 0 4px; }
.bar i { display: block; height: 100%; background: linear-gradient(90deg, var(--core), var(--hub)); border-radius: inherit; }
.foot { text-align: center; padding: 10px 16px 18px; font-size: 12px; }

/* 로그인 */
.login-page { display: grid; place-items: center; }
.login-wrap { width: min(420px, 100% - 32px); padding: 24px 0; }
.login-card { padding: 22px; display: grid; gap: 12px; }
.login-card label { display: grid; gap: 4px; font-size: 13px; color: var(--mut); }
.login-card input { font: inherit; color: var(--fg); background: rgba(127, 140, 200, .1); border: 1px solid var(--glass-b); border-radius: 10px; padding: 9px 11px; }
.login-card input:focus { outline: 2px solid var(--core); outline-offset: 1px; }
.primary { font: inherit; font-weight: 650; color: #fff; border: 0; border-radius: 10px; padding: 10px; cursor: pointer; background: linear-gradient(135deg, var(--core), var(--hub)); }
.msg.bad { color: var(--bad); margin: 0; }

/* 좁은 화면 — 지도 칸을 지도 비율에 맞춘다(뒤에 두어야 위 .scene 높이를 덮는다) */
@media (max-width: 1080px) { .scene { height: auto; min-height: 0; aspect-ratio: 1080 / 860; } }
.chip:empty { display: none; }
.dot.idle { background: #6b7280; }
.zoom { display: inline-flex; align-items: center; gap: 4px; }
.zoom button { font: inherit; color: var(--fg); background: rgba(127, 140, 200, .14); border: 1px solid var(--glass-b); border-radius: 8px; padding: 2px 9px; cursor: pointer; }
.zoom b { min-width: 38px; text-align: center; font-variant-numeric: tabular-nums; }
.side > * { min-width: 0; }
