/* CityFlow — S3 그래프 뷰 (도시 전체 데이터 흐름 토폴로지)
   소유: S3 워커 */

/* ── 스테이지 ──────────────────────────────────────────────── */
.graph {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background:
    radial-gradient(ellipse 58% 62% at 50% 50%, rgba(var(--accent-rgb), 0.07), transparent 70%),
    radial-gradient(ellipse 90% 80% at 50% 50%, var(--bg), var(--bg-deep) 82%);
  user-select: none;
}

/* 배경 도시 벡터 — 존재감만 (합산 불투명도 0.06) */
.graph-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  opacity: 0.06;
  pointer-events: none;
}
.graph-bg__topo path {
  fill: none;
  stroke: var(--text);
  stroke-width: 1.1;
  stroke-linecap: round;
}
.graph-bg__city path { fill: var(--text); stroke: none; }
.graph-bg__mast path {
  fill: none;
  stroke: var(--text);
  stroke-width: 1.4;
  stroke-linecap: round;
}

/* 엣지 캔버스 + 파티클 캔버스 */
.graph-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  pointer-events: none;
}

/* ── 노드 레이어 ───────────────────────────────────────────── */
.graph-nodes {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* 노드는 좌표점(0×0) 앵커 — 자식이 중심 기준으로 펼쳐진다 */
.graph-node {
  position: absolute;
  width: 0;
  height: 0;
  padding: 0;
  background: none;
  border: 0;
  pointer-events: auto;
  opacity: 1;
  transition: opacity 170ms var(--ease-micro);
}

.graph-node__halo {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--r) * 2.9);
  height: calc(var(--r) * 2.9);
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, var(--cf-color) 0%, transparent 66%);
  opacity: 0.26;
  pointer-events: none;
  transition: opacity 170ms var(--ease-micro), transform 170ms var(--ease-micro);
}

.graph-node__dot {
  position: absolute;
  left: 50%;
  top: 50%;
  display: grid;
  place-items: center;
  width: var(--r);
  height: var(--r);
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--cf-color);
  transition: transform 170ms var(--ease-micro), box-shadow 170ms var(--ease-micro);
}
/* 링 형태 코어 — 관제 화면 타깃 느낌 */
.graph-node__dot::before {
  content: "";
  position: absolute;
  inset: 27%;
  border-radius: 50%;
  background: var(--bg-deep);
  opacity: 0.62;
}

.graph-node__label {
  position: absolute;
  left: 50%;
  top: calc(50% + var(--r) / 2 + 9px);
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-dim);
  pointer-events: none;
  transition: color 170ms var(--ease-micro);
}

.graph-node:hover .graph-node__dot,
.graph-node.is-active .graph-node__dot { transform: translate(-50%, -50%) scale(1.14); }
.graph-node:hover .graph-node__halo,
.graph-node.is-active .graph-node__halo { opacity: 0.5; transform: translate(-50%, -50%) scale(1.1); }
.graph-node:hover .graph-node__label,
.graph-node.is-active .graph-node__label { color: var(--text); }

/* 클러스터 노드 — 이름을 더 강하게 */
.graph-node--cluster .graph-node__dot::before { inset: 22%; opacity: 0.72; }
.graph-node--cluster .graph-node__label {
  top: calc(50% + var(--r) / 2 + 11px);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
}
.graph-node--cluster .graph-node__halo { opacity: 0.2; }

/* ── 중앙 허브 ─────────────────────────────────────────────── */
.graph-node--hub .graph-node__dot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  background: var(--surface-glass-strong);
  /* 액센트 링 2px — 밝은 테마에서 흰 배경 위 흰 원이 되지 않도록 테두리로 초점을 잡는다.
     --glow-accent 는 light에서 토큰 자체가 옅은 그림자로 대체되므로 분기가 필요 없다. */
  border: 2px solid var(--border-accent);
  box-shadow: var(--glow-accent);
  backdrop-filter: blur(8px);
}
.graph-node--hub .graph-node__dot::before { display: none; }
.graph-node--hub .graph-node__halo {
  width: calc(var(--r) * 2.4);
  height: calc(var(--r) * 2.4);
  opacity: 0.3;
}
/* 코어 바깥 1px 액센트 헤어라인 — 배경과 원의 경계를 한 겹 더 세운다 */
.graph-node--hub .graph-hub__rim {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--r) + 12px);
  height: calc(var(--r) + 12px);
  transform: translate(-50%, -50%);
  border: 1px solid var(--accent-line);
  border-radius: 50%;
  pointer-events: none;
}

.graph-hub__icon {
  width: 22px;
  height: 22px;
  stroke: var(--accent);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.graph-hub__name {
  margin-top: 3px;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.graph-hub__num {
  /* 허브 원 안에 "2,847,120"이 들어가야 해 --fs-h2(22px)는 넘치고 --fs-h3는 약하다 */
  font-size: calc(var(--fs-h3) + 2px);
  font-weight: 500;
  letter-spacing: -0.03em;
  color: var(--text);
}
.graph-hub__unit {
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

/* 허브 pulse 링 (무한 반복 허용 대상) */
.graph-hub__pulse {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--r);
  height: var(--r);
  transform: translate(-50%, -50%);
  border: 1px solid var(--accent-line);
  border-radius: 50%;
  pointer-events: none;
  animation: graph-hub-pulse 3.6s var(--ease-micro) infinite;
}
.graph-hub__pulse--2 { animation-delay: 1.8s; }

@keyframes graph-hub-pulse {
  0%   { transform: translate(-50%, -50%) scale(1); opacity: 0.55; }
  70%  { opacity: 0.06; }
  100% { transform: translate(-50%, -50%) scale(1.62); opacity: 0; }
}

/* ── hover 집중 (연결만 살리고 나머지는 dim) ──────────────── */
.graph.is-focused .graph-node { opacity: 0.15; }
.graph.is-focused .graph-node.is-lit { opacity: 1; }

/* ── 합류 연출 (신규 소스 진입) ───────────────────────────── */
/* fill-mode를 backwards로 둬야 연출 종료 후 hover transform이 다시 먹는다 */
.graph-node--new .graph-node__dot {
  animation: graph-join-in var(--dur-enter) var(--ease-enter) backwards;
}
.graph-node--new .graph-node__label {
  color: var(--text);
  animation: graph-join-label var(--dur-enter) var(--ease-enter) backwards;
}
.graph-node--new .graph-node__halo { opacity: 0.55; }

@keyframes graph-join-in {
  from { transform: translate(-50%, -50%) scale(0.2); opacity: 0; }
  to   { transform: translate(-50%, -50%) scale(1); opacity: 1; }
}
@keyframes graph-join-label {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ── 팝오버 ────────────────────────────────────────────────── */
.graph-pop {
  position: absolute;
  z-index: var(--z-overlay);
  width: 264px;
  padding: var(--sp-4);
  background: var(--surface-glass-strong);
  border: 1px solid var(--border-strong);
  border-left: 2px solid var(--cf-color, var(--accent));
  border-radius: var(--radius);
  backdrop-filter: blur(14px);
  animation: graph-pop-in var(--dur-micro) var(--ease-enter) both;
}
.graph-pop[hidden] { display: none; }

@keyframes graph-pop-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

.graph-pop__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-bottom: 6px;
}
.graph-pop__cat {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--cf-color, var(--text-dim));
}
.graph-pop__cat::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--cf-color, var(--text-dim));
}
.graph-pop__title {
  font-size: var(--fs-h3);
  font-weight: 600;
  letter-spacing: -0.01em;
}
.graph-pop__meta {
  margin-top: 2px;
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

.graph-pop__stat {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}
.graph-pop__val {
  font-size: var(--fs-h2);
  font-weight: 500;
  letter-spacing: -0.02em;
}

.graph-pop__spark {
  width: 100%;
  height: 44px;
  margin-top: var(--sp-3);
  overflow: visible;
}
.graph-pop__spark .graph-spark-area { fill: var(--cf-color, var(--accent)); opacity: 0.14; stroke: none; }
.graph-pop__spark .graph-spark-line {
  fill: none;
  stroke: var(--cf-color, var(--accent));
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.graph-pop__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--text-dim);
}

/* ── HUD ───────────────────────────────────────────────────── */
.graph-hud {
  position: absolute;
  z-index: 10;
  pointer-events: none;
}
.graph-hud--tl { left: var(--sp-5); top: var(--sp-5); }
.graph-hud--tr {
  right: var(--sp-5);
  top: var(--sp-5);
  display: flex;
  gap: var(--sp-5);
  text-align: right;
}
.graph-hud--bl { left: var(--sp-5); bottom: var(--sp-5); }
.graph-hud--br { right: var(--sp-5); bottom: var(--sp-5); }

.graph-hud__title {
  margin-top: 2px;
  font-size: var(--fs-h1);
  font-weight: 600;
  letter-spacing: -0.025em;
}
.graph-hud__sub {
  margin-top: 2px;
  font-size: var(--fs-sm);
  color: var(--text-dim);
}

.graph-stat { display: grid; gap: 1px; }
.graph-stat strong {
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -0.01em;
}

.graph-legend {
  display: grid;
  gap: 5px;
  margin-top: 7px;
}
.graph-legend__item {
  display: grid;
  grid-template-columns: 9px 1fr auto;
  align-items: center;
  gap: var(--sp-2);
  min-width: 152px;
  font-size: var(--fs-sm);
  color: var(--text-dim);
  pointer-events: auto;
  cursor: default;
  transition: color var(--t-micro);
}
.graph-legend__item:hover { color: var(--text); }
.graph-legend__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--cf-color);
}
.graph-legend__n { font-size: var(--fs-xs); color: var(--text-faint); }

.graph-hint {
  max-width: 300px;
  text-align: right;
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

/* ── 모션 저감 — 무한 애니 정지 ───────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .graph-hub__pulse { animation: none; opacity: 0.3; }
  .graph-node--new .graph-node__dot,
  .graph-node--new .graph-node__label { animation: none; }
  .graph-pop { animation: none; }
}
