/* vm-flow — 재사용 애니메이션 플로우 다이어그램 (정적 호스팅용, 의존성 없음) */
.vm-flow {
  --flow-surface: #fcfcfb;
  --flow-border: rgba(11, 11, 11, 0.08);
  --flow-node: #f4f6f8;
  --flow-node-border: #dcddd3;
  --flow-ink: #1a1a1a;
  --flow-ink2: #52514e;
  --flow-sub: #8a8a82;
  --flow-edge: #c7c6bb;
  --flow-elabel: #7c7b73;
  --flow-src: #2a78d6;
  --flow-proc: #0d9488;
  --flow-store: #7c3aed;
  --flow-query: #eb6834;
  --flow-sink: #0ca30c;
  --flow-group-fill: rgba(11, 11, 11, 0.025);
  --flow-group-stroke: #cdccc2;
  --flow-layer-deploy: #2a78d6;
  --flow-layer-observe: #0d9488;
  --flow-layer-state: #7c3aed;
  --flow-layer-access: #d97706;
  margin: 1.4rem 0;
  padding: 14px 16px 8px;
  background: var(--flow-surface);
  border: 1px solid var(--flow-border);
  border-radius: 14px;
}
html.dark .vm-flow {
  --flow-surface: #1b1b1a;
  --flow-border: rgba(255, 255, 255, 0.09);
  --flow-node: #242422;
  --flow-node-border: #3a3a35;
  --flow-ink: #f2f2ef;
  --flow-ink2: #c3c2b7;
  --flow-sub: #9a978d;
  --flow-edge: #4c4b45;
  --flow-elabel: #918e85;
  --flow-src: #4b93e6;
  --flow-proc: #2dd4bf;
  --flow-store: #a78bfa;
  --flow-query: #f0894e;
  --flow-sink: #34d06a;
  --flow-group-fill: rgba(255, 255, 255, 0.035);
  --flow-group-stroke: #45443f;
  --flow-layer-deploy: #4b93e6;
  --flow-layer-observe: #2dd4bf;
  --flow-layer-state: #a78bfa;
  --flow-layer-access: #f59e0b;
}
.vm-flow > script { display: none; }
.vm-flow .flow-svg { display: block; width: 100%; height: auto; margin-inline: auto; }
.vm-flow .flow-elabel-bg { fill: var(--flow-surface); }
.vm-flow .flow-edge { stroke: var(--flow-edge); stroke-width: 1.5; }
.vm-flow .flow-edge.is-dashed { stroke-dasharray: 5 5; opacity: 0.85; }
.vm-flow .flow-arrow { fill: var(--flow-edge); }
.vm-flow .flow-elabel { font-size: 10.5px; fill: var(--flow-elabel); font-weight: 600; }
.vm-flow .flow-rect { fill: var(--flow-node); stroke: var(--flow-node-border); stroke-width: 1.5; transition: none; }
.vm-flow .flow-nlabel {
  fill: var(--flow-ink);
  font-size: 12.5px;
  font-weight: 650;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}
.vm-flow .flow-nsub { fill: var(--flow-sub); font-size: 9.5px; font-weight: 500; }
/* 종류별 강조: 노드 테두리 색 */
.vm-flow .kind-src   .flow-rect { stroke: var(--flow-src); }
.vm-flow .kind-proc  .flow-rect { stroke: var(--flow-proc); }
.vm-flow .kind-store .flow-rect { stroke: var(--flow-store); }
.vm-flow .kind-query .flow-rect { stroke: var(--flow-query); }
.vm-flow .kind-sink  .flow-rect { stroke: var(--flow-sink); }
/* 흐르는 패킷 색 */
.vm-flow .pk-src   { fill: var(--flow-src); }
.vm-flow .pk-proc  { fill: var(--flow-proc); }
.vm-flow .pk-store { fill: var(--flow-store); }
.vm-flow .pk-query { fill: var(--flow-query); }
.vm-flow .pk-sink  { fill: var(--flow-sink); }
/* layer — 평면별 테두리·파티클 색. kind 보다 뒤에 와서 stroke 를 덮는다. fill 은 color-mix 미지원 브라우저면 기본 노드색 유지 */
.vm-flow .layer-deploy  .flow-rect { stroke: var(--flow-layer-deploy);  stroke-width: 2; fill: color-mix(in srgb, var(--flow-layer-deploy) 7%, var(--flow-node)); }
.vm-flow .layer-observe .flow-rect { stroke: var(--flow-layer-observe); stroke-width: 2; fill: color-mix(in srgb, var(--flow-layer-observe) 7%, var(--flow-node)); }
.vm-flow .layer-state   .flow-rect { stroke: var(--flow-layer-state);   stroke-width: 2; fill: color-mix(in srgb, var(--flow-layer-state) 7%, var(--flow-node)); }
.vm-flow .layer-access  .flow-rect { stroke: var(--flow-layer-access);  stroke-width: 2; fill: color-mix(in srgb, var(--flow-layer-access) 7%, var(--flow-node)); }
.vm-flow .pk-layer-deploy  { fill: var(--flow-layer-deploy); }
.vm-flow .pk-layer-observe { fill: var(--flow-layer-observe); }
.vm-flow .pk-layer-state   { fill: var(--flow-layer-state); }
.vm-flow .pk-layer-access  { fill: var(--flow-layer-access); }
/* ghost — 비어 있는 자리(없음·예정·미구현)를 점선 반투명으로. layer/kind 색은 그대로 쓰되 바탕은 없앤다 */
.vm-flow .flow-node.is-ghost .flow-rect { fill: transparent; stroke-dasharray: 5 4; stroke-width: 1.5; opacity: 0.55; }
.vm-flow .flow-node.is-ghost .flow-nlabel, .vm-flow .flow-node.is-ghost .flow-nsub { opacity: 0.6; }
.vm-flow .flow-group-box { fill: var(--flow-group-fill); stroke: var(--flow-group-stroke); stroke-width: 1.3; stroke-dasharray: 4 4; }
.vm-flow .flow-group-label { fill: var(--flow-sub); font-size: 11px; font-weight: 650; }
.vm-flow .flow-caption {
  margin-top: 6px;
  font-size: 12px;
  color: var(--flow-sub);
  text-align: center;
}

/* 토큰 모드 — 파티클을 뿌리는 대신 노드 한 대가 단계를 지나간다 */
.flow-token { stroke: var(--flow-surface, #fcfcfb); stroke-width: 2.5; }

/* 접힌 도식 텍스트 — 노드·간선 라벨은 JSON 안에만 있어서 텍스트로 안 남는다.
   shortcode 가 같은 라벨을 details 로 한 번 더 낸다.
   색은 --flow-sub(캡션 색, #fcfcfb 위에서 3.4:1)이 아니라 --flow-ink2 를 쓴다 —
   11.5px 이라 WCAG AA 는 4.5:1 을 요구하고, summary 는 접힌 상태에서 유일하게
   보이는 인터랙티브 요소다. opacity 로 죽이면 배경과 섞여 그 비율이 다시 깨진다. */
.vm-flow .vm-spec-text { margin-top: 6px; font-size: 11.5px; color: var(--flow-ink2); }
.vm-flow .vm-spec-text summary { cursor: pointer; }
.vm-flow .vm-spec-text ul, .vm-flow .vm-spec-text ol { margin: 4px 0 0 18px; }
