/* ============================================================
   styles.css — 모듈 내부 스타일 (숫자 · 증감 · 범례 · 표 · 차트 자리)
   레이아웃 프레임(SNB · 탑바 · 페이지 헤더 · 모듈 그리드 · DatePicker)은
   layout.css 담당. 이 파일은 modules/ 의 부품들이 쓰는 재료만 둔다.
   값은 design-system/styles.css 토큰만 사용. 최소 폰트 15px.
   ============================================================ */


/* ============================================================
   모듈 스타일 — modules/ 의 부품들이 쓰는 클래스
   ============================================================ */

/* ---- 합계 (KPI) ---- 추이는 거점 카드 아래 따로(clientTrend) */
.csum { display: flex; flex-direction: column; }

/* ---- KPI 묶음 ----
   카드를 지표마다 따로 두지 않고 한 컨테이너에 담는다. 칸 사이는 세로 구분선. */
/* 칸 수는 modules/basic.js 의 kpiCols 가 정한다 (줄이 딱 떨어지게).
   구분선은 칸의 테두리로 긋고, 줄 첫 칸의 왼쪽 선과 첫 줄의 위 선만 지운다. */
.kpi-group {
  display: grid; grid-template-columns: repeat(var(--kpi-cols, 4), minmax(0, 1fr));
  margin: calc(var(--spacing-20) * -1);   /* 카드 여백을 걷어내 선이 끝까지 닿게 */
}
.kpi-item { min-width: 0; padding: var(--spacing-20); border-left: 1px solid var(--border); }
/* 줄 첫 칸은 왼쪽 선을 지운다(카드 테두리와 겹친다). 둘째 줄부터는 위 선을 넣는다. */
/* 줄 첫 칸 · 둘째 줄부터는 kpiLayout(parts.js)이 정한다 — 첫 칸이 남는 폭을 가져가면 nth-child 로는 못 센다 */
.kpi-item.is-row-start { border-left: none; }
.kpi-item.is-below { border-top: 1px solid var(--border); }
/* 여정 전환처럼 카드 제목이 따로 있는 묶음 — 숫자를 한 단계 낮춰 제목과 위계를 만든다 */

/* ---- 여정 전환 (퍼널) ----
   GA 퍼널 구조를 따른다 — 전환은 막대로, 이탈은 아래에 숫자로 따로 적는다.
   색으로도 갈라둔다: 파랑 = 다음으로 이어진 몫(전환), 회색 = 빠져나간 몫(이탈).
   그래야 처음 보는 사람도 계산 없이 읽는다. */
.fn { --fn-h: 200px; --fn-head-h: 24px; display: flex; gap: var(--spacing-16); }

/* 세로축 — 라벨을 균등 배치하면 눈금선과 어긋난다.
   각 라벨을 자기 눈금 높이(bottom:%)에 붙이고 반 줄 올려 선 한가운데에 맞춘다. */
.fn-axis {
  position: relative; width: 32px; flex-shrink: 0;
  height: var(--fn-h);
  margin-top: calc(var(--fn-head-h) + var(--spacing-8));
  font-size: var(--chart-label-size); color: var(--text-caption);
}
.fn-axis > span {
  position: absolute; right: 0; transform: translateY(50%);
  line-height: 1; white-space: nowrap;
}

.fn-cols { position: relative; flex: 1; min-width: 0; display: flex; }
/* 눈금선은 칸마다 긋지 않고 차트 영역 전체에 한 번만 — 칸 사이에서 끊기지 않게 */
.fn-cols::before {
  content: ""; position: absolute; left: 0; right: 0; pointer-events: none;
  top: calc(var(--fn-head-h) + var(--spacing-8));
  height: var(--fn-h);
  background-image: repeating-linear-gradient(to top,
    transparent 0, transparent calc(25% - 1px),
    var(--grey-50) calc(25% - 1px), var(--grey-50) 25%);
  /* 바닥선(0%)은 반복 패턴이 안 그려주는 자리라 따로 긋는다 */
  border-bottom: 1px solid var(--grey-50);
}
/* 칸마다 좌우 여백을 똑같이 — 양끝만 여백을 빼면 첫·마지막 막대만 넓어진다 */
.fn-col { flex: 1; min-width: 0; padding: 0 var(--spacing-16); }
.fn-col + .fn-col { border-left: 1px dashed var(--border); }

/* 단계 번호와 이름은 한 줄에 — 자리를 덜 먹고 축과도 맞는다 */
.fn-head {
  display: flex; align-items: baseline; gap: var(--spacing-6);
  height: var(--fn-head-h); margin-bottom: var(--spacing-8);
}
.fn-step { font-size: var(--font-base); font-weight: 600; color: var(--text-caption); flex-shrink: 0; }
.fn-name {
  font-size: var(--font-base); font-weight: 600; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 트랙 = 첫 단계 전체를 100% 로 본 눈금판. 배경은 없다.
   그 안의 stack 하나가 "직전 단계 수"이고, 위쪽 회색이 이탈 · 아래 파랑이 전환이다.
   회색 높이와 아래 이탈 숫자가 같은 것을 가리키게 하려고 이렇게 쌓는다. */
.fn-track { position: relative; height: var(--fn-h); display: flex; align-items: flex-end; }

.fn-stack { position: relative; z-index: 1; width: 100%; display: flex; flex-direction: column; }
.fn-lost {
  flex: 1; min-height: 0; background: var(--grey-50);
  border-radius: var(--radius-4) var(--radius-4) 0 0;
  transition: background-color var(--motion);
}
.fn-lost:hover { background: var(--grey-100); }
.fn-fill {
  width: 100%; min-height: 3px;
  background: var(--blue-500);
  transition: background-color var(--motion);
}
/* 이탈 영역이 없는 첫 칸은 막대 자신이 꼭대기 — 그때만 위 모서리를 둥글게 */
.fn-stack > .fn-fill:first-child { border-radius: var(--radius-4) var(--radius-4) 0 0; }
.fn-fill:hover { background: var(--blue-600); }

/* 전환·이탈을 같은 모양으로 — 한쪽은 수가 아래, 한쪽은 옆에 있으면 비교가 안 된다 */
/* 전환·이탈을 가로로 나란히 — 세로로 쌓으면 카드 높이만 먹고 비교도 안 된다 */
.fn-stats {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-8);
  padding: var(--spacing-12) var(--spacing-8) 0;
}
.fn-stat { display: flex; flex-direction: column; gap: var(--spacing-2); min-width: 0; }
.fn-stat dt {
  display: flex; align-items: center; gap: var(--spacing-6);
  font-size: var(--chart-label-size); color: var(--text-caption);
}
/* 수는 왼쪽, 비율은 오른쪽 끝 — 칸마다 끝자리가 맞는다 */
/* 좁은 칸이라 수와 비율을 위아래로 — 옆에 붙이면 자릿수 많은 매장에서 줄바꿈된다 */
.fn-stat dd {
  display: flex; flex-direction: column; gap: 1px;
  font-size: var(--font-base); font-weight: 600; color: var(--text-primary);
  white-space: nowrap;
}
.fn-stat dd em { font-style: normal; font-weight: 400; color: var(--text-caption); }
.fn-chip { width: 10px; height: 10px; flex-shrink: 0; border-radius: var(--radius-4); }
.fn-chip.is-keep { background: var(--blue-500); }
.fn-chip.is-drop { background: var(--grey-200); }


.fn-col { cursor: default; }

/* ---- 공용 부품 (modules/parts.js) ---- */

/* 큰 숫자 */
.stat { display: flex; flex-direction: column; gap: var(--spacing-8); }
.stat-value {
  font-size: 42px; font-weight: 600; line-height: 1.15;
  letter-spacing: -0.03em; color: var(--grey-800);
  /* 큰 숫자는 고정폭(tabular) 대신 비례폭 — 1 과 쉼표 주변에 구멍이 생기지 않는다.
     표·증감처럼 자리를 맞춰야 하는 곳에서만 tabular-nums 를 쓴다. */
  font-variant-numeric: proportional-nums;
}
.stat.is-sm .stat-value { font-size: 28px; }
.stat.is-empty .stat-value { color: var(--text-disabled); font-weight: 500; }
.stat-unit { font-size: 20px; font-weight: 500; letter-spacing: 0; margin-left: var(--spacing-4); color: var(--text-sub); }
.stat-foot { display: flex; align-items: center; gap: var(--spacing-6); min-height: 21px; }
/* 증감률이 무엇 대비인지 — 위계가 가장 약한 주석 */
.delta-base { font-size: var(--font-base); line-height: 1.4; color: var(--text-caption); }
.stat-note { font-size: var(--font-base); line-height: 1.4; color: var(--text-caption); }

/* 증감 */
.delta {
  display: inline-flex; align-items: center; gap: var(--spacing-2);
  font-size: var(--font-base); font-weight: 500; line-height: 1.4; font-variant-numeric: tabular-nums;
}
.delta-arrow { width: 14px; height: 14px; stroke-width: 2.5; flex-shrink: 0; }
.delta.is-up { color: var(--trend-up); }
.delta.is-down { color: var(--trend-down); }
.delta.is-flat,
.delta.is-none { color: var(--text-caption); }

/* 잴 수 없는 값 — 0 과 헷갈리지 않게. 표기는 화면 어디서나 같은 minus 아이콘.
   글자(하이픈·대시)는 글꼴·자리마다 길이가 달라져서 같은 "없음"이 다르게 보였다. */
.num-na { display: inline-flex; align-items: center; color: var(--text-disabled); }
.num-na[data-tip] { cursor: help; }
.num-na-icon { width: 14px; height: 14px; stroke-width: 2.5; }
/* 정렬이 오른쪽인 칸에서는 아이콘도 오른쪽 끝에 선다 */
.module .table .num .num-na { justify-content: flex-end; width: 100%; }
/* 값이 통째로 없는 KPI — 큰 숫자 자리에 서는 아이콘. 24px (32 는 숫자보다 무거워 보였다, 9/23 슬기님) */
.stat-none-icon { width: 24px; height: 24px; stroke-width: 2; color: var(--text-disabled); }

/* 태그 — 칩이 아니라 글자로. 숫자 옆에서 칩이 뜨면 시선을 뺏는다. */
.tag {
  display: inline-flex; align-items: center;
  font-size: var(--font-base); line-height: 1.4; color: var(--text-caption); white-space: nowrap;
}

/* 범례 */
.legend {
  display: flex; align-items: center; justify-content: center;
  gap: var(--spacing-16); flex-wrap: wrap;
  margin-top: var(--spacing-12);
}
.legend-item {
  display: inline-flex; align-items: center; gap: var(--spacing-6);
  font-size: var(--chart-label-size); line-height: 1.4; color: var(--text-sub);
}
/* 범례 표식 */
.legend-dot { width: 12px; height: 12px; border-radius: var(--radius-4); flex-shrink: 0; }

/* 범례 호버 강조 — 짚은 하나만 남기고 나머지는 물러난다.
   흐린 정도는 차트(modules/chart-setup.js 의 FOCUS_DIM)와 같은 값으로 맞춘다. */
.legend-item[data-series] { cursor: default; }
.legend-item[data-series],
.fn-fill[data-series], .fn-lost[data-series] { transition: opacity var(--motion-focus); }
.is-dim { opacity: var(--focus-dim); }

/* 주석 */
.module-note {
  margin-top: var(--spacing-12);
  font-size: var(--font-base); line-height: 1.5; color: var(--text-caption);
}

/* 빈 상태 */
/* 아직 내용이 없는 모듈은 테두리를 점선으로 — 아직 만들지 않은 자리(.module-ph)와
   같은 표시다. 카드만 보고도 "여기는 아직 비어 있다"가 읽힌다. */
.module:has(> .module-body > .module-empty),
.module:has(> .module-body > .ins.is-pending) { border-style: dashed; }

/* 빈 상태도 모듈 높이를 다 쓴다 — 같은 줄의 다른 모듈은 내용만큼 큰데 이것만
   100px 이면 카드 안에 내용보다 빈 칸이 더 크게 남는다.
   .module-body 가 flex 컬럼이라 flex:1 로 남은 높이를 받는다.
   테두리는 카드가 지므로 여기는 면만 — 점선 안에 점선을 또 두르지 않는다. */
.module-empty {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--spacing-4); min-height: 100px; padding: var(--spacing-16);
  border-radius: var(--radius-8);
  background: var(--bg-soft);
}
.module-empty-text { font-size: var(--font-base); font-weight: 500; line-height: 1.4; color: var(--text-sub); }
.module-empty-sub { font-size: var(--font-base); line-height: 1.4; color: var(--text-caption); }


/* 표 ----------------------------------------------------------------
   design-system 의 컴포넌트 라이브러리에도 .table 정의가 있어서 그대로 두면
   회색 머리글 띠·테두리 상자·행 호버가 섞여 들어온다.
   여기가 기준이므로 .module 아래에서 전부 다시 잡는다. */

/* 감싸개는 가로 스크롤 역할만. 배경·테두리·둥근 모서리 없음(카드가 이미 그 역할) */
.module .table-wrap { overflow-x: auto; background: none; border: none; border-radius: 0; }

/* 카드 안에서 표가 또 하나의 상자로 보이지 않게 구분선을 카드 좌우 끝까지 뺀다.
   대신 첫·마지막 칸에 카드 안쪽 여백만큼 padding 을 돌려준다. */
.module .table-wrap.is-bleed { margin-left: calc(var(--spacing-20) * -1); margin-right: calc(var(--spacing-20) * -1); }
/* 제목이 없는 모듈에서는 표를 카드 위쪽 끝까지 붙인다 — 좌우만 빼면 위가 혼자 남아 어긋나 보인다.
   윗공간은 카드 여백이 아니라 머리글 칸이 직접 갖는다(아래 padding-top). */
.module:not(:has(.module-head)) .module-body > .table-wrap.is-bleed:first-child {
  margin-top: calc(var(--spacing-20) * -1);
}
.module .module-body > .table-wrap.is-bleed:last-child { margin-bottom: calc(var(--spacing-20) * -1); }
/* 카드 끝까지 붙었으니 카드 모서리를 따라간다 */
.module:not(:has(.module-head)) .table-wrap.is-bleed thead th:first-child { border-top-left-radius: var(--radius-12); }
.module:not(:has(.module-head)) .table-wrap.is-bleed thead th:last-child { border-top-right-radius: var(--radius-12); }

.module .table { width: 100%; border-collapse: collapse; }
/* 칸 너비는 partTableHead 가 머리글에 몫(100 ÷ 칸 수 %)만 실어 준다. 여기서는 박지 않는다. */
.module .table thead th,
.module .table tbody td {
  padding: var(--spacing-8) var(--spacing-12);   /* 머리글·데이터 칸 같은 높이 */
  border-bottom: 1px solid var(--grey-50);
  font-size: var(--font-base); font-weight: 500; line-height: 1.4;   /* 표 안 글자는 전부 medium */
  text-align: left; white-space: nowrap; vertical-align: middle;
}
.module .table thead th { background: var(--grey-25); color: var(--text-caption); border-bottom-color: transparent; }
.module .table tbody td { color: var(--text-body); }
/* 칸 사이 세로 구분선 — 머리글부터 본문까지 끝까지 내려간다.
   마지막 칸은 카드 테두리가 대신한다. */
.module .table th:not(:last-child),
.module .table td:not(:last-child) { border-right: 1px solid var(--grey-50); }
/* 오른쪽 정렬만으로 자리가 맞으므로 고정폭은 쓰지 않는다 — 쉼표 주변이 벙벙해진다 */
.module .table .num { text-align: right; font-variant-numeric: proportional-nums; }
.module .table tbody tr:last-child td { border-bottom: none; }
/* 행 호버 — 투명 호버 칩(다른 컨트롤과 같은 값), 전환은 공통 ease-out.
   배경을 tr 이 아니라 td 에 칠한다. tr 배경은 모서리를 깎을 수 없어서
   카드 아래쪽 둥근 모서리 밖으로 삐져나온다. */
.module .table tbody td { transition: background-color var(--motion); }
.module .table tbody tr:hover td { background: var(--row-hover); }
/* 보고 있는 층에는 따로 표시를 두지 않는다.
   면·가장자리 막대·글자색을 다 시도했지만 호버와 겹치거나 시끄러웠다.
   지금 어느 층을 보는지는 툴 밴드의 층 버튼이 말해주고,
   표에서는 그 행에만 쉐브론이 없는 것으로 충분하다. */
/* 표가 카드 맨 아래까지 닿을 때, 마지막 행의 양끝은 카드 모서리를 따라간다 */
.module .module-body > .table-wrap.is-bleed:last-child tbody tr:last-child td:first-child {
  border-bottom-left-radius: var(--radius-12);
}
.module .module-body > .table-wrap.is-bleed:last-child tbody tr:last-child td:last-child {
  border-bottom-right-radius: var(--radius-12);
}
.module .table tbody tr.is-link { cursor: pointer; }

/* 이동 칸 — 내용만큼만 좁게. 쉐브론은 항상 자리를 차지하고 색만 바뀐다. */
/* 이동 칸은 정사각형 — 폭을 행 높이(위아래 여백 8 + 글줄 21)와 같게 잡는다 */
.module .table { --table-cell-h: calc(var(--spacing-8) * 2 + 21px); }
.module .table .col-go { width: var(--table-cell-h); min-width: var(--table-cell-h); padding: 0; text-align: center; line-height: 0; }
/* 칸을 꽉 채운다 — 툴팁도 클릭도 칸 전체에서 잡히도록.
   inline-flex 로 두면 글줄 높이 때문에 아래에 여백이 생겨서 flex 로 둔다. */
.row-go {
  display: flex; align-items: center; justify-content: center;
  width: var(--table-cell-h); height: var(--table-cell-h);
  padding: 0; background: none; border: none; cursor: pointer;
  color: var(--grey-200);
}
.row-go svg { width: var(--icon-size-btn); height: var(--icon-size-btn); }   /* 16px */
.module .table tbody tr.is-link:hover .row-go { color: var(--text-primary); }
/* 보고 있는 층 — 쉐브론은 흔적만 남긴다.
   색 토큰(--text-disabled)이 기본 쉐브론(grey-200)과 같은 값이라 구분이 안 되므로 opacity 로 낮춘다. */
.row-go.is-off { opacity: .25; cursor: default; }

/* 정렬 가능한 머리글 — 칸 전체가 클릭 영역이다.
   칸의 여백을 버튼이 대신 갖도록 옮겨서, 넓어져도 글자 위치는 본문 칸과 그대로 맞는다. */
.module .table th.is-sortable { padding: 0; }
.th-sort {
  display: flex; align-items: center; gap: var(--spacing-4);
  width: 100%; padding: var(--spacing-8) var(--spacing-12);
  background: none; border: none; border-radius: inherit; cursor: pointer;
  font: inherit; color: inherit;
}
.th-sort:hover { color: var(--text-primary); background: var(--transparent-hover); }
/* 표를 카드 끝까지 뺐을 때의 바깥쪽 여백도 버튼이 갖는다 */
.module .table-wrap.is-bleed th.is-sortable:first-child .th-sort { padding-left: var(--spacing-20); }
.module .table-wrap.is-bleed th.is-sortable:last-child .th-sort { padding-right: var(--spacing-20); }
/* 숫자 칸은 화살표를 글자 왼쪽으로 — 오른쪽 끝이 아래 숫자들과 같은 선에 서야 한다.
   글자 칸은 그대로(화살표가 오른쪽) 두어야 왼쪽 끝이 아래 글자들과 맞는다. */
.module .table th.num .th-sort { flex-direction: row-reverse; }

/* 화살표는 하나만 두고 각도로 방향을 말한다 — 아이콘을 바꿔 끼우면 애니메이션이 안 붙는다.
   아래를 향한 상태가 내림차순(기본), 180도 돌면 오름차순. */
.th-sort-icon {
  width: var(--icon-size); height: var(--icon-size); flex-shrink: 0;
  color: var(--text-caption);
  stroke-width: 2.5;   /* 12px 로 줄이면 선이 1px 이 돼 흐려 보인다 */
  transition: transform var(--motion-layout), color var(--motion);
}
.th-sort:hover .th-sort-icon { color: var(--text-sub); }
/* 정렬 중인 칸은 글자색과 같은 진한 회색 — 파랑은 차트에만 쓴다 */
.module .table th[data-dir] .th-sort-icon { color: var(--grey-800); }
.module .table th[data-dir="asc"] .th-sort-icon { transform: rotate(180deg); }
.module .table th[data-dir] { color: var(--text-primary); }

/* 정렬 머리글은 여백을 버튼이 갖는다(위 .th-sort 규칙). 여기서 또 주면 두 번 들어간다. */
.module .table-wrap.is-bleed .table th:not(.is-sortable):first-child,
.module .table-wrap.is-bleed .table td:first-child { padding-left: var(--spacing-20); }
.module .table-wrap.is-bleed .table th:not(.is-sortable):not(.col-go):last-child,
.module .table-wrap.is-bleed .table td:not(.col-go):last-child { padding-right: var(--spacing-20); }


/* Chart.js 캔버스 자리 — 높이는 --chart-h 토큰, spec.height 를 준 모듈만 인라인으로 덮는다 */
.chart { position: relative; width: 100%; height: var(--chart-h); }


/* ---- 성별 (도넛 가운데 글자) ----
   캔버스에 글자를 그리면 폰트·색 규칙을 따로 관리해야 한다. HTML 로 겹쳐 두고
   숫자는 KPI 와 같은 .stat-value 를 그대로 쓴다. 클릭·호버는 캔버스로 흘려보낸다. */
.gd-center {
  position: absolute; inset: 0; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--spacing-2);
}
.gd-center-label { font-size: var(--font-base); line-height: 1.4; color: var(--text-sub); }

/* ---- 주요 구역 ----
   바로 위가 층별 현황 "표"라서, 여기까지 머리글 밑줄 + 세로 구분선 + 오른쪽 정렬
   숫자를 쓰면 한 화면에 표 스타일이 둘이 된다. 표처럼 보이는 신호를 전부 빼고
   행 배경에 막대를 깔아 순위 차트로 읽히게 한다. */
/* 순위 칸 수는 고객사가 재는 것에 따라 2~3 — 칸 수만큼 균등 */
.tz {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  gap: var(--spacing-32);
}
.tz-group { min-width: 0; }
.tz-group-title {
  margin: 0 0 var(--spacing-8);
  font-size: var(--font-base); font-weight: 500; line-height: 1.45; color: var(--text-sub);
}
.tz-list { list-style: none; margin: 0; padding: 0; }
.tz-row {
  display: flex; flex-direction: column; gap: var(--spacing-4);
  padding: var(--spacing-8);
  margin: 0 calc(var(--spacing-8) * -1);   /* 호버 띠만 글자보다 조금 넓게 */
  border-radius: var(--radius-6);
  font-size: var(--font-base); line-height: 1.5;
  transition: background-color var(--motion);
}
.tz-row:hover { background-color: var(--row-hover); }
.tz-main { display: flex; align-items: center; gap: var(--spacing-8); }
/* 값 막대는 글자 뒤가 아니라 글자 밑에 가는 선으로 둔다.
   면으로 깔면 값이 서로 비슷할 때 세 줄이 다 꽉 차서 "선택된 행"으로 읽히고,
   막대 끝이 값 글자 뒤에 숨어 어디까지인지 안 보인다. */
.tz-meter, .rk-meter { display: block; height: 3px; border-radius: var(--radius-4); background: var(--grey-50); }
.tz-meter > i, .rk-meter > i { display: block; height: 100%; border-radius: var(--radius-4); background: var(--blue-500); }
/* 순위에 올릴 게 없는 칸 — 빈 줄을 세 개 두지 않고 이유 한 줄로 끝낸다 */
.tz-none {
  margin: 0; padding: var(--spacing-8) 0;
  font-size: var(--font-base); line-height: 1.5; color: var(--text-caption);
}
.tz-rank {
  width: 20px; flex-shrink: 0;
  color: var(--text-caption); font-variant-numeric: tabular-nums;
}
/* 구역 이름은 실측이 15자를 넘는 것도 있다 — 줄을 늘리지 않고 잘라낸다 */
.tz-name {
  min-width: 0; flex: 1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 500; color: var(--text-primary);
}
/* 층은 뱃지가 아니라 플레인 텍스트 */
.tz-floor { flex-shrink: 0; color: var(--text-caption); }
.tz-value { flex-shrink: 0; margin-left: auto; font-weight: 500; font-variant-numeric: tabular-nums; }


/* ---- 거점 순위 ----
   주요 구역과 같은 규칙 — 표가 아니라 순위 차트다. 막대는 행 배경에 깔고
   1위를 꽉 찬 길이로 잡는다. 눌러서 그 거점으로 들어간다. */
.rk { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.rk-row {
  cursor: pointer;
  display: flex; flex-direction: column; gap: var(--spacing-6);
  padding: var(--spacing-8);
  margin: 0 calc(var(--spacing-8) * -1);
  border-radius: var(--radius-6);
  font-size: var(--font-base); line-height: 1.5;
  transition: background-color var(--motion);
}
.rk-row:hover { background-color: var(--row-hover); }
.rk-main { display: flex; align-items: center; gap: var(--spacing-12); }
.rk-rank { width: 20px; flex-shrink: 0; color: var(--text-caption); font-variant-numeric: tabular-nums; }
/* 이름이 남은 폭을 차지해 값 · 증감 · 셰브론이 늘 오른쪽 끝에 선다(지역 열을 뺀 뒤 자리를 잃었던 것, 9/24 슬기님) */
.rk-name { flex: 1; min-width: 0; font-weight: 500; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rk-value { flex-shrink: 0; font-weight: 500; font-variant-numeric: tabular-nums; }
/* 함께 표시 — 인원 옆의 비율. 값보다 한 단계 약하게, 값 바로 왼쪽에 */
.rk-sub { flex-shrink: 0; color: var(--text-caption); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* 증감은 폭이 들쭉날쭉해서 자리를 잡아둔다 — 안 그러면 값 칸이 줄마다 밀린다 */
/* 증감은 자릿수에 따라 폭이 들쭉날쭉해서 칸을 고정해 둔다 — 안 그러면 값이 줄마다 밀린다.
   다만 "↗ 12.3%" 가 들어갈 만큼만. 넓으면 값과 증감 사이가 벌어져 한 쌍으로 안 읽힌다. */
.rk-delta { flex-shrink: 0; width: 60px; display: flex; justify-content: flex-end; }
.rk-go { flex-shrink: 0; display: flex; color: var(--text-disabled); transition: color var(--motion); }
.rk-go svg { width: var(--icon-size-btn); height: var(--icon-size-btn); }
.rk-row:hover .rk-go { color: var(--text-primary); }

/* ---- 거점 인사이트 카드 ----
   숫자는 다섯 칸만 두고 남은 자리를 문장에 준다. 카드 전체가 그 거점으로 가는 링크. */
/* 제목 띠 — 카드 끝까지 내보내고 여백은 자기가 갖는다.
   아래 margin 은 layout.css 값(모듈 제목 줄 규칙)을 그대로 둔다.
   모서리는 카드가 overflow 로 잘라낸다 — 안쪽 요소마다 radius 를 맞춰두면
   카드 radius 를 바꿀 때 여러 군데를 같이 고쳐야 한다. */
.module:has(.ins) { overflow: hidden; }
.module:has(.ins) .module-head {
  margin-top: calc(var(--spacing-20) * -1);
  margin-left: calc(var(--spacing-20) * -1);
  margin-right: calc(var(--spacing-20) * -1);
  padding: var(--spacing-12) var(--spacing-20);
  background: var(--grey-25);
  border-bottom: 1px solid var(--border);
}
/* 이동 힌트 — 표의 .row-go 와 같은 값. 평소엔 흐리게 있다가 카드에 올리면 진해진다.
   자리는 항상 잡아둔다(레이아웃 시프트 방지). */
.ins-go {
  width: var(--icon-size-btn); height: var(--icon-size-btn); flex-shrink: 0;
  color: var(--text-disabled); transition: color var(--motion);
}
.module.is-link:hover .ins-go { color: var(--text-primary); }
.ins { flex: 1; display: flex; flex-direction: column; gap: var(--spacing-20); }
/* 열 수는 칸 수가 정한다(insCols) — 넷이면 2×2 로 두 줄 다 꽉 찬다. 빈 자리가 남는 배치는 안 만든다 */
.ins-stats { display: grid; grid-template-columns: repeat(var(--ins-cols, 3), minmax(0, 1fr)); gap: var(--spacing-12) var(--spacing-8); }
/* 한 칸 = 이름 / 값 / 증감. 위에서 아래로 "무엇을 · 얼마나 · 어느 쪽으로" 순서다.
   증감을 제목 줄에 하나만 두면 무엇의 증감인지 알 길이 없어서 칸마다 붙인다. */
.ins-stat { display: flex; flex-direction: column; gap: var(--spacing-2); min-width: 0; }
.ins-stat-label {
  font-size: var(--chart-label-size); line-height: 1.4; color: var(--text-caption);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ins-stat-value {
  font-size: 24px; font-weight: 600; line-height: 1.3;
  letter-spacing: var(--letter-spacing); color: var(--grey-800);
  white-space: nowrap; font-variant-numeric: proportional-nums;
}
.ins-stat-value em { font-style: normal; font-size: var(--font-base); font-weight: 500; color: var(--text-sub); margin-left: 1px; }
/* 값 아래 증감은 한 단계 작게 — 셋이 나란히 서면 화살표가 숫자만큼 크게 읽힌다 */
.ins-stat .delta { font-size: var(--chart-label-size); }
.ins-stat .delta-arrow { width: 12px; height: 12px; }
/* 에이전트 자리 — 선으로만 가른다. 면까지 깔면 회색 띠가 카드에 둘이 돼서
   제목 띠와 위계가 같아지고, 카드 여섯 장이 서면 줄무늬로 읽힌다.
   표식은 아이콘 하나로 끝낸다 — 라벨 줄을 하나 더 두면 카드 여섯 장에 여섯 줄이 는다. */
/* 구분선은 두지 않는다 — 위 차트와 사이가 이미 넉넉하고,
   선을 그으면 카드 여섯 장에 가로선이 여섯 개 겹쳐 화면이 시끄러워진다. */
.ins-text {
  flex: 1;
  display: flex; flex-direction: column; gap: var(--spacing-6);
}
/* 한글은 단어 중간에서 끊지 않는다(keep-all) — "입니 / 다"처럼 갈라지면 읽기가 끊긴다 */
.ins-line { margin: 0; font-size: var(--font-base); line-height: 1.6; color: var(--text-body); text-wrap: pretty; word-break: keep-all; }
/* 두 번째 문장부터는 한 단계 약하게 — 첫 줄이 이 카드가 위에 있는 이유다 */
.ins-line + .ins-line { color: var(--text-caption); }
/* 문장 자리의 이름표 — 지표 칸 이름표와 같은 급으로 두고, 문장이 주인공이 되게 약하게 */
.ins-text-label {
  font-size: var(--chart-label-size); line-height: 1.4; color: var(--text-caption);
}
/* 문장을 기다리는 동안 — 지표 칸과 차트는 이미 떠 있고 이 칸만 비어 있다.
   줄 높이를 문장과 같게 둬서 문장이 붙을 때 카드 높이가 튀지 않는다. */
.ins-text.is-waiting { gap: var(--spacing-8); padding-top: var(--spacing-4); }
.ins-text.is-waiting .sk-line { height: 14px; }

/* 연결 준비 중 — 지표 세 칸은 그대로 두고 아래만 한 칸으로 합친다.
   차트와 요약 문장은 둘 다 "데이터가 있어야 나오는 것"이라 따로 비워두면
   빈 상자가 둘이 되고, 무엇이 없는지는 한 번만 말하면 된다.
   높이는 flex 로 받는다 — 같은 줄의 데이터 카드와 키가 저절로 맞는다.
   min-height 는 혼자 놓였을 때를 위한 바닥값 (미니 차트 56 + 사이 20 + 문장 두 줄).
   데이터 카드의 실제 높이보다 크면 같은 줄 카드를 끌어올려 빈 자리가 생기므로 낮게 둔다. */
.ins-pending {
  flex: 1;
  display: flex; align-items: center; justify-content: center;
  min-height: 116px; padding: var(--spacing-16);
  border-radius: var(--radius-8);
  background: var(--bg-soft);
  font-size: var(--font-base); font-weight: 500; line-height: 1.4; color: var(--text-sub);
}


/* 분포도 축 고르개 — X축·Y축 두 개가 한 묶음으로 제목 줄 오른쪽에 선다 */
.axis-pick { display: inline-flex; align-items: center; gap: var(--spacing-8); }




/* 표 칸 안 보조 숫자 — 인원 옆 비율처럼 "그 숫자를 무엇에 비춰 읽는가". 한 단계 작고 흐리게 */
.td-sub { font-style: normal; margin-left: var(--spacing-6); font-size: var(--chart-label-size); color: var(--text-caption); }

/* 방문객 활성도 — KPI 두 칸 아래로 표가 이어진다 */
.module .kpi-group + .table-wrap { margin-top: var(--spacing-20); }

/* 시간대 × 층 히트맵 — 첫 칸은 층 이름, 나머지는 시간대가 같은 폭으로 나눠 갖는다.
   칸 사이 2px 는 바탕색 — 이웃 칸이 한 덩어리로 번지지 않게 한다(dataviz: 2px surface gap). */
.hm {
  display: grid; grid-template-columns: auto repeat(var(--hm-cols), minmax(0, 1fr));
  gap: 2px; align-items: center;
}
.hm-corner { display: block; }
.hm-hour { text-align: center; font-size: var(--chart-label-size); line-height: 1.4; color: var(--text-caption); padding-bottom: var(--spacing-4); }
.hm-floor { padding-right: var(--spacing-12); font-size: var(--chart-label-size); line-height: 1.4; color: var(--text-sub); white-space: nowrap; }
.hm-cell { display: block; height: 32px; border-radius: 3px; transition: box-shadow var(--motion); }
.hm-cell:hover { box-shadow: inset 0 0 0 2px var(--grey-800); }
/* 재지 않는 층 — 0 과 구별되게 칠하지 않고 빗금으로 */
.hm-cell.is-none {
  background: repeating-linear-gradient(135deg, var(--grey-50) 0 4px, var(--white) 4px 8px);
}
.hm-cell.is-none:hover { box-shadow: none; }
/* 범례 — 적음/많음 사이에 단계 칩을 이어 붙인다. 가운데 정렬은 다른 범례와 같다 */
.hm-legend {
  display: flex; align-items: center; justify-content: center; gap: var(--spacing-8);
  margin-top: var(--spacing-12);
  font-size: var(--chart-label-size); line-height: 1.4; color: var(--text-sub);
}
.hm-ramp { display: inline-flex; gap: 2px; }
.hm-ramp i { width: 20px; height: 12px; border-radius: 2px; }

/* 구역 히트맵 — 도면 선이 비쳐 보이게 칠을 살짝 투명하게. 테두리는 흰 선으로 이웃 구역과 가른다 */
.pl-zone.is-heat { border: 1px solid rgba(255, 255, 255, .8); opacity: .88; }
.pl-zone.is-heat:hover { opacity: 1; box-shadow: 0 0 0 2px var(--grey-800); }
/* 칠하지 않는 구역(출입구역 · 값 없음) — 채움 없이 회색 점선. 파란 채움은 범례 단계로 읽혀 뺐다. 호버도 회색 */
.pl-zone.is-off { border: 1px dashed var(--grey-300); background: transparent; }
.pl-zone.is-off:hover { background: rgba(142, 148, 157, .12); box-shadow: 0 0 0 2px var(--grey-300); }


/* 준비 중 거점 행 — 숫자가 없는 게 아니라 아직 없는 곳이다.
   목록에서 빼면 "몇 곳인지"가 어긋나므로 줄은 남기고 위계만 낮춘다. */
.module .table tbody tr.is-pending td { color: var(--text-caption); }

/* ---- 층간 이동 ----
   순위 목록과 같은 규칙 — 막대는 글자 밑 가는 선으로. */
.fp { list-style: none; margin: 0; padding: 0; }
.fp-row {
  display: flex; flex-direction: column; gap: var(--spacing-6);
  padding: var(--spacing-8);
  margin: 0 calc(var(--spacing-8) * -1);
  border-radius: var(--radius-6);
  transition: background-color var(--motion);
}
.fp-row:hover { background-color: var(--row-hover); }
.fp-main { display: flex; align-items: center; gap: var(--spacing-12); }
.fp-meter { display: block; height: 3px; border-radius: var(--radius-4); background: var(--grey-50); }
.fp-meter > i { display: block; height: 100%; border-radius: var(--radius-4); background: var(--blue-500); }
.fp-rank {
  width: 20px; flex-shrink: 0;
  font-size: var(--font-base); color: var(--text-caption); font-variant-numeric: tabular-nums;
}
/* 경로는 줄바꿈을 허용한다 — 구역 이름이 길면 한 줄에 다 안 들어간다 */
.fp-steps {
  min-width: 0; flex: 1;
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--spacing-4);
}
.fp-step {
  padding: 2px var(--spacing-8);
  border-radius: var(--radius-4); background: var(--grey-25);
  font-size: var(--font-base); font-weight: 500; color: var(--text-primary); white-space: nowrap;
}
.fp-arrow { width: 14px; height: 14px; flex-shrink: 0; color: var(--text-disabled); }
.fp-share {
  flex-shrink: 0; margin-left: auto;
  font-size: var(--font-base); font-weight: 500; font-variant-numeric: tabular-nums;
}

/* ---- 층간 이동 (층 겹 그림 + 순서 목록) ----
   왼쪽 층 판, 오른쪽 목록. 좁아지면 위아래로. 색 규칙은 chart-setup 의 거점 팔레트를 층에 빌려 쓴다. */
/* 왼쪽 칸은 그림 폭(640)까지만 — 카드가 넓어져도 그림과 목록 사이가 벌어지지 않고 목록이 남는 폭을 가진다 */
.fs { display: grid; grid-template-columns: minmax(0, 640px) minmax(0, 1fr); gap: var(--spacing-40, 40px); align-items: start; }
@media (max-width: 1100px) { .fs { grid-template-columns: minmax(0, 1fr); } }
/* 폭 상한 = viewBox 폭 — 그 이상 키우지 않아 글자가 17px 를 넘지 않고, 좁은 칸에서는 15px 근처까지만 줄어든다 */
.fl-svg { display: block; width: 100%; max-width: 640px; height: auto; overflow: visible; margin: 0 auto; }
/* 층이 둘뿐이면 건물이 낮다 — 목록 옆 세로 가운데에 둔다 */
.fs-chart { align-self: center; }
/* 순서의 층 이름 — 칩 없이 글자만. 입장 표시는 보조 글자 */
.fp-floor { font-size: var(--font-base); font-weight: 500; color: var(--text-primary); white-space: nowrap; }
.fp-floor small { font-size: var(--font-sub); font-weight: 400; color: var(--text-caption); margin-left: 2px; }
/* 통과한 층 — 연한 글자 + 점선 밑줄. 색만으로 가르지 않는다 */
.fp-floor.is-pass { font-weight: 400; color: var(--text-caption); text-decoration: underline dashed; text-underline-offset: 3px; }
/* 체류 · 통과 범례 — 목록 위 오른쪽 */
.fs-stay-legend {
  display: flex; justify-content: flex-end; gap: var(--spacing-16);
  margin-bottom: var(--spacing-8); font-size: var(--font-sub); color: var(--text-caption);
}
.fs-stay-legend > span { display: inline-flex; align-items: center; gap: var(--spacing-6); }
/* 판 — 값이 없다. 입장 층은 회색, 나머지는 연파랑. 목록을 호버하면 그 순서가 지나는 판만 진한 파랑(is-on) */
.fl-slab .fl-top { fill: var(--blue-50); stroke: var(--blue-100); transition: fill var(--motion-focus, 200ms), stroke var(--motion-focus, 200ms); }
.fl-slab .fl-front { fill: var(--blue-100); stroke: var(--blue-100); transition: fill var(--motion-focus, 200ms), stroke var(--motion-focus, 200ms); }
.fl-slab.is-entry .fl-top { fill: var(--grey-50); stroke: var(--grey-100); }
.fl-slab.is-entry .fl-front { fill: var(--grey-100); stroke: var(--grey-100); }
.fl-slab.is-on .fl-top { fill: var(--blue-300); stroke: var(--blue-400); }
.fl-slab.is-on .fl-front { fill: var(--blue-400); stroke: var(--blue-400); }
/* 입장 층도 호버한 순서에 들면 같은 진한 파랑 — 회색은 "값이 없다"가 아니라 "시작점"이라는 뜻일 뿐 */
.fl-slab.is-entry.is-on .fl-top { fill: var(--blue-300); stroke: var(--blue-400); }
.fl-slab.is-entry.is-on .fl-front { fill: var(--blue-400); stroke: var(--blue-400); }
/* 호버한 순서에 안 드는 판은 물러난다 — .1 은 판이 사라져 보여 .35 */
.fl-slab { transition: opacity var(--motion-focus, 200ms); }
.fl-slab.is-dim { opacity: .35; }
/* 판 호버 — 나머지 판도 같은 만큼 물러난다. 호버한 판은 호버한 순서처럼 진한 파랑 */
.fl-svg:has(.fl-slab:hover) .fl-slab:not(:hover) { opacity: .35; }
.fl-slab:hover .fl-top { fill: var(--blue-300); stroke: var(--blue-400); }
.fl-slab:hover .fl-front { fill: var(--blue-400); stroke: var(--blue-400); }
.fl-lead { stroke: var(--grey-200); stroke-width: 1; stroke-dasharray: 3 3; }
.fl-slab path { cursor: default; }
/* viewBox 단위라 화면에서는 칸 폭에 따라 0.85~1배로 줄어든다 — 17 이면 가장 좁은 칸에서도 15px 근처 */
.fl-label { font-size: 17px; font-weight: 500; fill: var(--text-primary); }
.fl-label-v { font-weight: 400; fill: var(--text-caption); }
/* 뼈대 판은 흐르지 않는다 — svg 안이라 배경색 대신 폴리곤 자체가 회색이고, 깜빡임만 .sk 에서 빌린다 */
.fl-slab.sk { background: none; }
.fp-row { transition: background-color var(--motion), opacity var(--motion-focus, 200ms); }
/* 그 외 순서 — 접힌 줄은 안 보이고, 펼치면 순위 이어서 */
.fs-list .fp-row.is-more { display: none; }
.fs-list.is-open .fp-row.is-more { display: flex; }
/* 전체 보기 줄 — 글자는 가운데. 펼치면 줄 자체가 목록 맨 아래로 내려가 "접기" 자리가 된다(목록은 flex 열이라 order 로 옮긴다) */
.fs-list .fp { display: flex; flex-direction: column; }
.fp-more-toggle { cursor: pointer; }
.fp-more-toggle .fp-main { justify-content: center; }
.fp-more-toggle .fp-rank { display: none; }
.fp-more-toggle .fp-steps { flex: 0 0 auto; }
.fp-more-toggle .fp-step.is-rest { display: inline-flex; align-items: center; gap: var(--spacing-4); }
.fs-list.is-open .fp-more-toggle { order: 99; }
.fp-more-chevron { width: 14px; height: 14px; color: var(--text-disabled); transition: transform var(--motion); }
.fs-list.is-open .fp-more-chevron { transform: rotate(180deg); }

/* 순위 밖 줄(퇴장 · 그 외) — 순위 번호 없이, 회색 칩 */
.fp-row.is-rest .fp-step.is-rest { background: transparent; color: var(--text-caption); font-weight: 400; padding-left: 0; }
.fp-row.is-rest .fp-share { color: var(--text-caption); font-weight: 400; }

/* ---- 구역 동선 (도면) ----
   도면 비율을 그대로 쓰고, 구역·화살표·이름표를 그 위에 비율로 얹는다.
   좌표가 0~1 이라 도면을 어떤 크기로 띄워도 자리가 맞는다. */
.pl { display: flex; flex-direction: column; gap: var(--spacing-16); }
/* 한 층을 볼 때 — 왼쪽 동선 목록, 오른쪽 도면. 고른 동선이 바로 옆에 그려진다.
   도면이 가로로 길어서(1025×628) 폭을 더 준다. */
.pl.is-split {
  display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: var(--spacing-20); align-items: start;
}
.pl-side { min-width: 0; }
/* 왼쪽 열 높이 = 도면 높이. 안쪽을 absolute 로 띄워 줄 높이에 안 끼어들게 하고, 1번은 고정 · 나머지는 스크롤 */
.pl.is-split { align-items: stretch; }
.pl.is-split .pl-side { position: relative; }
.pl-side-inner { position: absolute; inset: 0; display: flex; flex-direction: column; gap: var(--spacing-8); }
/* 스크롤 영역과 1번 줄의 오른쪽 여백을 같게 — 아니면 1번 상자만 넓어 보인다 */
.pl-route-scroll { flex: 1; min-height: 0; overflow-y: auto; padding-right: var(--spacing-4); }
.pl-side-inner > .pl-route { padding-right: var(--spacing-4); }
.pl-route-scroll .pl-route-rest { margin-top: 0; }
@media (max-width: 1100px) {
  .pl.is-split { grid-template-columns: minmax(0, 1fr); }
  /* 한 열로 쌓이면 도면 높이를 빌릴 수 없다 — 제자리로 두고 스크롤 높이만 정한다 */
  .pl-side-inner { position: static; }
  .pl-route-scroll { max-height: 320px; }
}
.pl-canvas {
  position: relative; width: 100%;
  border: 1px solid var(--border); border-radius: var(--radius-8);
  background: var(--grey-25); overflow: hidden;
}
.pl-img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* 크게 보기 버튼 — 도면 오른쪽 위. 구역 · 이름표 위에 뜨고, 흰 바탕이라 도면 위에서도 보인다 */
.pl-zoom {
  position: absolute; top: var(--spacing-8); right: var(--spacing-8); z-index: 5;
  background: var(--white); border: 1px solid var(--border); box-shadow: var(--shadow-sm);
}
.pl-zoom:hover { background: var(--white); }
/* .pl 이 도면 + 범례를 감쌀 때(구역 히트맵) 범례 위 여백은 .pl 의 gap 이 맡는다 */
.pl > .hm-legend { margin-top: 0; }

/* ---- 전체화면(크게 보기) 안의 도면 ----
   도면 상자(.pl-frame)가 자리를 다 채우고(전체 폭 · 전체 높이) 테두리 · 바탕을 맡는다. 도면(.pl-canvas)은 그 안에서
   비율을 지킨 채 가운데 — 도면 상자 자체를 늘리면 위에 얹은 구역이 어긋난다.
   도면 크기는 상자 크기(cqw · cqh)에서 바로 잰다 — 화면 여백을 어림한 숫자가 없다 */
.modal.is-zoom .pl-zoom { display: none; }
.modal.is-zoom .modal-panel { align-items: stretch; justify-content: flex-start; }
.modal.is-zoom .pl { flex: 1; min-height: 0; }
.modal.is-zoom .pl-frame {
  flex: 1; min-height: 0; width: 100%; height: 100%;
  container-type: size;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: var(--radius-8); background: var(--white);
}
.modal.is-zoom .pl-frame .pl-canvas {
  border: none; background: transparent; border-radius: 0;
  width: auto; height: min(100cqh, calc(100cqw * var(--pl-h) / var(--pl-w)));
}
/* 대표 동선 — 왼쪽 목록은 폭 고정 · 전체 높이(1번 고정 · 나머지 스크롤), 오른쪽 도면 상자가 남는 폭 · 전체 높이 */
.modal.is-zoom .pl.is-split {
  width: 100%; grid-template-columns: 280px minmax(0, 1fr); grid-template-rows: minmax(0, 1fr);
  align-items: stretch;
}
/* 구역 — 옅은 파랑 채움 + 파란 테두리. 출입구역은 같은 색 점선 */
.pl-zone {
  position: absolute;
  border: 1px solid var(--blue-500); background: rgba(55, 106, 226, .12);
  border-radius: var(--radius-4);
  transition: background-color var(--motion);
}
/* 상자 호버 = 이름표 · 왼쪽 순서 호버로 서는 모양(.is-hl)과 같다 — 어디서 가리키든 구역은 한 모양으로 선다 */
.pl-zone:hover { background: rgba(55, 106, 226, .32); box-shadow: 0 0 0 2px var(--blue-500); }
/* 출입구역 — 다른 구역보다 진하게 채워 시작점임을 말한다. 지금 보는 동선의 입구는 한 단계 더 */
.pl-zone.is-entrance { background: rgba(55, 106, 226, .22); }
.pl-zone.is-entrance.is-on { background: rgba(55, 106, 226, .38); border-width: 2px; }
.pl-zone.is-entrance[data-entry] { cursor: pointer; }
/* 왼쪽 순서 상자를 호버하면 도면의 그 구역이 선다 */
.pl-zone.is-hl { background: rgba(55, 106, 226, .32); box-shadow: 0 0 0 2px var(--blue-500); }
/* 화살표 — 선 굵기는 도면 확대율과 무관하게 고정 */
.pl-arrows { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.pl-line { stroke: var(--blue-600); stroke-width: 2; vector-effect: non-scaling-stroke; }
.pl-head { fill: var(--blue-600); }
/* 이름표 — 동선에 든 구역만 단다. 28개 구역에 전부 달면 도면이 안 보인다 */
.pl-label {
  position: absolute; transform: translate(-50%, -50%);
  display: inline-flex; align-items: center; gap: var(--spacing-6);
  padding: 2px var(--spacing-8);
  border-radius: var(--radius-4);
  background: var(--white); box-shadow: var(--shadow-sm);
  font-size: var(--chart-label-size); font-weight: 500; color: var(--text-primary);
  white-space: nowrap;
}
/* 출입구역 이름표 — 동선과 무관하게 항상. 고를 수 있으면 눌린다 */
/* 이름표는 상자와 같은 호버 · 클릭 영역 — 상자보다 큰 이름표 위에서도 툴팁 · 강조 · 입구 고르기가 된다 */
.pl-label { pointer-events: auto; cursor: default; }
.pl-label.is-entry { color: var(--blue-800); }
/* 호버로 이름표 색을 바꾸지 않는다 — 지금 보는 입구(is-on)의 파랑이 현재 상태라서, 호버 색이 끼면 둘이 섞인다. 호버는 툴팁만 */
.pl-label.is-entry.is-on { background: var(--blue-500); color: var(--white); }
.pl-label.is-entry.is-on .pl-label-icon { color: var(--white); }
.pl-label.is-entry[data-entry] { cursor: pointer; }
.pl-label-icon { width: 14px; height: 14px; color: var(--blue-600); flex: none; }
.pl-label em {
  font-style: normal; font-size: var(--chart-label-size);
  width: 16px; height: 16px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-pill); background: var(--blue-500); color: var(--white);
}
/* 왼쪽 열 — 번호 + 상자가 한 줄. 1번 입구는 드롭다운(입구가 둘 이상일 때), 2번부터 구역 이름 상자 */
.pl-route, .pl-route-rest { --route-gap: var(--spacing-8); list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--route-gap); }
/* 켜고 끄는 층(.pl-layer)의 display:block 이 flex 를 덮지 않게 — 켜졌을 때도 flex 열 */
.pl-route-rest { margin-top: var(--route-gap); }
.pl-route-rest.pl-layer.is-on { display: flex; }
.pl-route-step { position: relative; display: flex; align-items: center; gap: var(--spacing-12); min-width: 0; }
/* 번호 뒤 세로 선 — 다음 번호까지 이어져 순서가 한 줄로 읽힌다. 마지막 줄에는 없다.
   1번은 다른 목록(.pl-route)에 있어 항상 선을 내리고, 나머지 목록은 마지막 줄만 뺀다 */
.pl-route .pl-route-step::before, .pl-route-rest .pl-route-step:not(:last-child)::before {
  content: ""; position: absolute; left: 10.5px; top: 50%; width: 1px;
  height: calc(100% + var(--route-gap)); background: var(--grey-100);
}
.pl-route-num {
  position: relative; z-index: 1;
  flex: none; width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  /* 도면 위 번호 배지(.pl-label em)와 같은 원형 — 왼쪽 목록과 도면이 같은 번호를 같은 모양으로 */
  border-radius: var(--radius-pill); background: var(--grey-700); color: var(--white);
  font-size: var(--font-sub); font-weight: 600; font-variant-numeric: tabular-nums;
}
.pl-route > .pl-route-step:first-child .pl-route-num { background: var(--blue-500); }
/* 줄에 호버하면 번호가 파랗게 — 도면 위 번호 배지(파랑)와 같은 색으로 "지금 가리키는 구역"이 양쪽에서 같이 선다 */
.pl-route-step:hover .pl-route-num { background: var(--blue-500); }
.pl-route-num { transition: background-color var(--motion); }
/* 상자도 같이 — 호버는 바탕만 바꾸고 테두리는 그대로(컨트롤 공통 규칙). 순위 목록 줄(.fp-row)과 같은 호버 색 */
.pl-route-box { transition: background-color var(--motion); }
.pl-route-step:hover .pl-route-box { background: var(--row-hover); }
.pl-route-box {
  flex: 1; min-width: 0;
  display: inline-flex; align-items: center; gap: var(--spacing-8);
  padding: var(--spacing-8) var(--spacing-12);
  border: 1px solid var(--border); border-radius: var(--radius-6); background: var(--grey-25);
  font-size: var(--font-base); font-weight: 500; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pl-route-icon { width: var(--icon-size); height: var(--icon-size); color: var(--text-sub); flex: none; }
/* 입구 드롭다운은 상자와 같은 생김새 — 프레임 .dd 의 열고 닫기만 빌린다.
   항목이 <button> 이라 브라우저 기본 버튼 모양을 지워 .dd-opt 링크와 같게 맞춘다 */
.pl-route-box { min-height: var(--control-h); }
.pl-route-dd { flex: 1; min-width: 0; display: flex; }
.pl-route-dd .dd-trigger {
  width: 100%; height: auto; justify-content: flex-start; text-align: left;
  padding: var(--spacing-8) var(--spacing-12); border-radius: var(--radius-6); background: var(--white);
}
.pl-route-dd .dd-trigger:hover { background: var(--bg-soft); }
.pl-route-dd.is-open .dd-trigger { background: var(--selected-bg); color: var(--selected-fg); }
.pl-route-dd .dd-trigger > span:not(.dd-chev) { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.pl-route-dd .dd-chev { margin-left: auto; flex: none; }
.pl-route-dd .dd-menu { min-width: 100%; max-width: none; }
.pl-route-dd .dd-opt {
  display: block; width: 100%; text-align: left;
  background: none; border: 0; font: inherit; cursor: pointer;
  padding: var(--spacing-8) var(--spacing-12); border-radius: var(--radius-6);
  font-size: var(--font-base); line-height: 1.4; color: var(--text-body); white-space: nowrap;
}
.pl-route-dd .dd-opt:hover { background: var(--bg-soft); }
.pl-route-dd .dd-opt.is-active { background: var(--selected-bg); color: var(--selected-fg); }

/* 동선 겹치기 — 세 개를 미리 넣어 두고 고른 것만 보인다 */
.pl-layer { display: none; }
.pl-layer.is-on { display: block; }
g.pl-layer.is-on { display: inline; }
.pl-none { margin: 0; font-size: var(--font-base); line-height: 1.5; color: var(--text-caption); }
.pl-route-scroll .pl-none { padding: var(--spacing-8) 0 0 calc(22px + var(--spacing-12)); }
/* 입구가 없으면 왼쪽 칸 한가운데 — 칸 높이는 도면이 정한다 */
.pl-none.is-center { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; text-align: center; }
@media (max-width: 1100px) { .pl-none.is-center { position: static; padding: var(--spacing-24) 0; } }

