/* ═══ common.css ═══════════════════════════
 * 전역 CSS 변수, 리셋, 공통 컴포넌트
 * 모든 페이지에서 공유. 개별 스타일은 각 CSS 파일에서 관리.
 * ═════════════════════════════════════════ */

/* ─── CSS 변수 (라이트 모드 기본) ─────────── */
:root {
  /* 색상 */
  --color-bg: #ffffff;
  --color-text: #1a1a2e;
  --color-primary: #000000;
  --color-primary-hover: #333333;
  --color-primary-glow: rgba(0, 47, 255, 0.08);
  --color-success: #16a34a;
  --color-warning: #c97000;
  --color-danger: #dc2626;
  --color-danger-hover: #b91c1c;
  --color-border: #dddde8;
  --color-focus: #000000;
  --color-muted: #66667a;
  --color-module-bg: #f8f8fc;

  /* 카드/섹션 */
  --color-card-bg: #ffffff;
  --color-section-bg: #ffffff;
  --color-glass-border: rgba(0, 0, 0, 0.05);

  /* 테이블 */
  --color-table-bg: #ffffff;
  --color-table-row-bg: #ffffff;
  --color-table-th-bg: #f0f0f8;
  --color-table-hover: rgba(0, 0, 0, 0.04);

  /* 배지 */
  --badge-info-bg: rgba(0, 0, 0, 0.08);
  --badge-info-text: #000000;
  --badge-default-bg: rgba(102, 102, 122, 0.12);
  --badge-default-text: #66667a;

  /* 레이아웃 */
  --color-header: #131313;
  --color-sidebar: #131313;
  --color-sidebar-hover: rgba(255, 255, 255, 0.08);
  --color-sidebar-active: rgba(255, 255, 255, 0.15);
  /* 어두운 머리(.topbar·.app-header) 위 글자 — 두 테마 같은 값 */
  --color-header-text: #ffffff;
  --color-header-muted: #cbd5e1;
  --color-header-icon: #e2e8f0;
  --color-header-accent: #93c5fd;

  /* 그림자 */
  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.06);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.07), 0 2px 4px -2px rgb(0 0 0 / 0.08);
  --shadow-glass: 0 10px 40px -10px rgba(0, 0, 0, 0.08);

  /* 간격 / border-radius */
  --radius-sm: 5px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;

  /* 폰트 */
  /* 글꼴 순서는 영문 → 한글 → 시스템(ui.md §2). 영문 글꼴에 없는 한글만 다음 글꼴로 간다 */
  --font-family: "Roboto", "Pretendard Variable", "Pretendard", "Noto Sans KR", -apple-system, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace, "Pretendard Variable", "Pretendard";
  /* 글자 크기 5단계 (2026-10-07) — 관리 화면 전체가 이 값만 쓴다. 최소 13px, 기본 14px(메뉴·목록·버튼·입력), 배지만 12px.
     설문 참여 화면(survey/css/ui.css)·웹진·뉴스레터 결과물은 따로다. 아이콘 글리프·통계 큰 숫자는 토큰을 쓰지 않는다 */
  --fs-xs: 13px;        /* 설명·힌트·메타·작은 단추·표 머리줄 */
  --fs-sm: 14px;        /* 기본 — body·모든 메뉴·표·목록·단추·입력칸 */
  --fs-md: 15px;        /* 중간 제목 — 패널·카드·대화창 */
  --fs-lg: 16px;        /* 모달 제목·강조 */
  --fs-xl: 17px;        /* 화면(페이지) 제목 */
  --fs-base: var(--fs-sm);
  --fs-code: 13px;
  --fs-badge: 12px;

  /* 컨트롤 (button·form-input·form-select·trigger) 세로 패딩
   * 초소형 4px · 소형 6px · 기본 8px · 대형 10px.
   * 수평 패딩은 컴포넌트별 자율(버튼 16px·입력 10px 등).
   * 높이는 자연 계산 (padding × 2 + 컨텐츠 + border) — min-height 강제 없음 */
  --ctrl-py-xs: 4px;
  --ctrl-py-sm: 6px;
  --ctrl-py: 8px;
  --ctrl-py-lg: 10px;
  --ctrl-gap: 8px;          /* 한 컨트롤 안에 세로로 쌓이는 요소(체크·입력·힌트) 사이 최소 간격 (ui.md §3) */

  /* 상태 배경·테두리·텍스트 (components.md §5) */
  --color-success-bg: #e6f7ed;
  --color-success-border: #b7e6c8;
  --color-success-text: #0a7a3b;
  --color-danger-bg: #fdecec;
  --color-danger-border: #f5b4b4;
  --color-danger-text: #b91c1c;
  --color-warning-bg: #fff7e6;
  --color-warning-border: #ffd79a;
  --color-warning-text: #854d0e;
  --color-info-bg: #eff6ff;
  --color-info-border: #bfdbfe;
  --color-info-text: #1d4ed8;
}

/* ─── 다크 모드 ──────────────────────────── */
[data-theme="dark"] {
  --color-bg: #101318;
  --color-text: #e9edf3;
  --color-primary: #54d6b5;
  --color-primary-hover: #7fe3c9;
  --color-primary-glow: rgba(84, 214, 181, 0.18);
  --color-success: #22c55e;
  --color-warning: #f59e0b;
  --color-danger: #ef4444;
  --color-danger-hover: #dc2626;
  --color-border: #2a3039;
  --color-focus: #54d6b5;
  --color-muted: #a0a9b8;
  --color-module-bg: #101318;

  --color-card-bg: #181c23;
  --color-section-bg: #1e242c;
  --color-glass-border: #2a3039;

  --color-table-bg: #181c23;
  --color-table-row-bg: #181c23;
  --color-table-th-bg: #1e242c;
  --color-table-hover: #1e242c;

  --badge-info-bg: rgba(139, 184, 247, 0.16);
  --badge-info-text: #8bb8f7;
  --badge-default-bg: rgba(115, 128, 147, 0.2);
  --badge-default-text: #a0a9b8;

  --color-header: #181c23;
  --color-sidebar: #181c23;
  --color-sidebar-hover: #1e242c;
  --color-sidebar-active: #20362f;
  /* 어두운 머리(.topbar·.app-header) 위 글자 — 두 테마 같은 값 */
  --color-header-text: #e9edf3;
  --color-header-muted: #a0a9b8;
  --color-header-icon: #e9edf3;
  --color-header-accent: #54d6b5;

  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.6);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.6), 0 2px 4px -2px rgb(0 0 0 / 0.6);
  --shadow-glass: 0 10px 40px -10px rgba(0, 0, 0, 0.9);

  /* 다크 상태 토큰 */
  --color-success-bg: #17372f;
  --color-success-border: #2a5a4c;
  --color-success-text: #54d6b5;
  --color-danger-bg: rgba(239, 68, 68, 0.18);
  --color-danger-border: rgba(239, 68, 68, 0.45);
  --color-danger-text: #fca5a5;
  --color-warning-bg: rgba(245, 158, 11, 0.18);
  --color-warning-border: rgba(245, 158, 11, 0.45);
  --color-warning-text: #fde68a;
  --color-info-bg: rgba(139, 184, 247, 0.16);
  --color-info-border: rgba(139, 184, 247, 0.4);
  --color-info-text: #8bb8f7;
}

/* ─── 리셋 ───────────────────────────────── */
* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: var(--font-family);
  font-size: var(--fs-base);
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  transition: background 0.3s ease, color 0.3s ease;
}

/* 폼 컨트롤: 브라우저 기본 폰트를 덮어쓰고 Pretendard Variable 상속 강제 */
input,
select,
textarea,
button,
optgroup,
option {
  font-family: var(--font-family);
}

/* ─── 버튼 ───────────────────────────────── */
.btn {
  padding: var(--ctrl-py) 16px;
  box-sizing: border-box;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.2;    /* icon vs text 동일 content height 보장 */
  cursor: pointer;
  background: var(--color-card-bg);
  color: var(--color-text);
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 4px;
}

/* 버튼 내부 아이콘은 text line-height 와 동일하게 렌더 */
.btn > i,
.btn-sm > i,
.btn-xs > i {
  line-height: inherit;
}

.btn:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.btn.is-active {
  background: var(--color-primary);
  color: #ffffff;
  border-color: var(--color-primary);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-primary {
  background: #000000;
  color: #ffffff;
  border-color: #000000;
}
.btn-primary:hover,
.btn-primary:active,
.btn-primary.is-active {   /* 라이트: 검정 → 조금 밝은 검정, 글자는 흰색 그대로(ui.md §5) */
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
  color: #ffffff;
}

.btn-secondary {
  background: var(--color-card-bg);
  color: var(--color-text);
  border: 1px solid var(--color-border);
}
.btn-secondary:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.btn-danger { background: #ef4444; color: #ffffff; border: 1px solid #ef4444; }
.btn-danger:hover { background: #dc2626; border-color: #dc2626; color: #ffffff; }

.btn-warning { background: var(--color-card-bg); color: var(--color-warning); border: 1px solid var(--color-warning); }
.btn-warning:hover { background: var(--color-warning); color: #ffffff; border-color: var(--color-warning); }

.btn-sm { padding: var(--ctrl-py-sm) 12px; font-size: var(--fs-xs); }
.btn-xs { padding: var(--ctrl-py-xs) 6px; font-size: var(--fs-code); }

/* 다크모드 버튼 */
[data-theme="dark"] .btn {
  background: var(--color-card-bg);
  color: var(--color-text);
  border-color: var(--color-border);
}
[data-theme="dark"] .btn:hover {
  background: var(--color-section-bg);
  border-color: #3a4350;
  color: var(--color-text);
}
[data-theme="dark"] .btn.is-active {
  background: var(--color-primary);
  color: #101318;
  border-color: var(--color-primary);
}
[data-theme="dark"] .btn-primary {
  background: var(--color-primary);
  color: #101318;
  border-color: var(--color-primary);
}
[data-theme="dark"] .btn-primary:hover,
[data-theme="dark"] .btn-primary:active,
[data-theme="dark"] .btn-primary.is-active {   /* 다크: 청록 → 밝은 청록, 글자는 #101318 그대로 */
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
  color: #101318;
}
[data-theme="dark"] .btn-secondary {
  background: var(--color-card-bg);
  color: var(--color-text);
  border-color: var(--color-border);
}
[data-theme="dark"] .btn-secondary:hover {
  background: #2a2a2a;
  border-color: #3a3a3a;
  color: var(--color-text);
}
[data-theme="dark"] .btn-warning {
  background: transparent;
  color: var(--color-warning);
  border-color: var(--color-warning);
}
[data-theme="dark"] .btn-warning:hover {
  background: var(--color-warning);
  color: #000;
}
[data-theme="dark"] .btn-danger {
  background: #ef4444;
  color: #ffffff;
  border-color: #ef4444;
}
[data-theme="dark"] .btn-danger:hover {
  background: #dc2626;
  border-color: #dc2626;
  color: #ffffff;
}

.btn-icon {
  background: none;
  border: none;
  color: var(--color-primary);
  cursor: pointer;
  padding: var(--ctrl-py-xs) 8px;
  font-size: 14px;
  line-height: 1;
  border-radius: var(--radius-sm);
  transition: color 0.2s, background 0.2s;
}
.btn-icon:hover {
  color: var(--color-primary-hover);
  background: var(--color-primary-glow);
}

/* 테이블 더보기 버튼 (관리 컬럼 2개 이상 액션) */
.btn-table-more {
  width: 28px;
  height: 28px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-muted);
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s, color 0.15s;
}
.btn-table-more:hover {
  background: var(--color-primary-glow);
  color: var(--color-primary);
}

/* 테이블 컨텍스트 팝업 메뉴 */
.table-ctx-menu {
  position: fixed;
  z-index: 9999;
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  min-width: 160px;
  padding: 4px 0;
  animation: tableCtxFadeIn 0.12s ease-out;
}
@keyframes tableCtxFadeIn {
  from { opacity: 0; transform: scale(0.95) translateY(-4px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
.table-ctx-menu__item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 14px;
  background: none;
  border: none;
  cursor: pointer;
  font-size: var(--fs-sm);
  color: var(--color-text);
  text-align: left;
  white-space: nowrap;
  transition: background 0.15s;
}
.table-ctx-menu__item:hover {
  background: var(--color-primary-glow);
  color: var(--color-primary);
}
.table-ctx-menu__item--danger {
  color: #dc2626;
}
.table-ctx-menu__item i {
  width: 14px;
  text-align: center;
  font-size: 12px;
  flex-shrink: 0;
}
.table-ctx-menu__divider {
  height: 1px;
  background: var(--color-border);
  margin: 4px 8px;
}

/* ─── 배지 ───────────────────────────────── */
/* ─── 마크다운 본문 (.md-body) — marked 로 그린 HTML 의 모양 한 벌 (docview·ai 미리보기·intranet 게시글) ────
 * 글자 크기는 토큰만. 목록 들여쓰기 24px, 중첩 목록은 위아래 여백 없이 붙이고, 항목 간격 4px.
 * 코드 글꼴은 고정폭 뒤에 var(--font-family) — 코드 안 한글이 OS 기본 글꼴로 새지 않게. 화면마다 다시 쓰지 않는다 */
.md-body { line-height: 1.7; color: var(--color-text); word-break: break-word; }
.md-body > :first-child { margin-top: 0; }
.md-body h1, .md-body h2, .md-body h3, .md-body h4 { font-weight: 600; line-height: 1.3; }
.md-body h1 { font-size: var(--fs-xl); margin: 0 0 16px; padding-bottom: 8px; border-bottom: 1px solid var(--color-border); }
.md-body h2 { font-size: var(--fs-lg); margin: 32px 0 12px; }
.md-body h3 { font-size: var(--fs-md); margin: 24px 0 8px; }
.md-body h4 { font-size: var(--fs-sm); margin: 16px 0 8px; }
.md-body p, .md-body ul, .md-body ol, .md-body table, .md-body pre, .md-body blockquote { margin: 0 0 12px; }
.md-body ul, .md-body ol { padding-left: 24px; }
.md-body li + li { margin-top: 4px; }
.md-body li > p { margin: 0; }
.md-body li > ul, .md-body li > ol { margin: 4px 0 0; }
.md-body li > input[type="checkbox"] { margin: 0 6px 0 -20px; vertical-align: middle; }
.md-body a { color: var(--color-primary); text-decoration: underline; }
.md-body code { font-family: var(--font-mono); font-size: var(--fs-code); padding: 1px 5px; border-radius: var(--radius-sm); background: var(--color-section-bg); }
.md-body pre { padding: 12px 14px; overflow-x: auto; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-section-bg); font-size: var(--fs-code); line-height: 1.55; }
.md-body pre code { padding: 0; background: none; font-size: inherit; }
.md-body blockquote { padding: 8px 14px; border-left: 3px solid var(--color-border); background: var(--color-section-bg); color: var(--color-muted); }
.md-body blockquote > :last-child { margin-bottom: 0; }
.md-body table { border-collapse: collapse; width: 100%; font-size: var(--fs-sm); }
.md-body th, .md-body td { padding: 6px 10px; border: 1px solid var(--color-border); text-align: left; vertical-align: top; }
.md-body th { background: var(--color-table-th-bg); font-weight: 600; text-align: center; }
.md-body tr:hover td { background: var(--color-table-hover); }
.md-body hr { margin: 24px 0; border: 0; border-top: 1px solid var(--color-border); }
.md-body img { max-width: 100%; }

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 20px;
  font-size: var(--fs-badge);
  font-weight: 600;
}

/* 의미 기반(의미 기반 우선) — 신규 코드는 이 이름 사용 */
.badge-success  { background: rgba(22, 163, 74, 0.12);  color: #15803d; }
.badge-danger   { background: rgba(220, 38, 38, 0.12);  color: #b91c1c; }
.badge-warning  { background: rgba(201, 112, 0, 0.12);  color: #c97000; }
.badge-info     { background: var(--badge-info-bg);     color: var(--badge-info-text); }
.badge-default  { background: var(--badge-default-bg);  color: var(--badge-default-text); }

/* 레거시 별칭 — DB seed(migrate_portal_init.sql `badge_cls` JSON) 호환. 신규 코드 사용 금지 */
.badge-active   { background: rgba(22, 163, 74, 0.12);  color: #15803d; }
.badge-inactive { background: rgba(220, 38, 38, 0.12);  color: #b91c1c; }
.badge-pending  { background: rgba(201, 112, 0, 0.12);  color: #c97000; }

[data-theme="dark"] .badge-success  { background: rgba(34, 197, 94, 0.15);  color: #86efac; }
[data-theme="dark"] .badge-danger   { background: rgba(239, 68, 68, 0.15);  color: #fca5a5; }
[data-theme="dark"] .badge-warning  { background: rgba(245, 158, 11, 0.15); color: #fcd34d; }
[data-theme="dark"] .badge-active   { background: rgba(34, 197, 94, 0.15);  color: #86efac; }
[data-theme="dark"] .badge-inactive { background: rgba(239, 68, 68, 0.15);  color: #fca5a5; }
[data-theme="dark"] .badge-pending  { background: rgba(245, 158, 11, 0.15); color: #fcd34d; }

/* ─── 카드 ───────────────────────────────── */
.card {
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  margin-bottom: 16px;
  box-shadow: var(--shadow-sm);
  transition: background 0.3s ease, border-color 0.3s ease;
  flex-shrink: 0;   /* flex column 부모에서 자연 높이 유지 */
}

.card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  background: var(--color-module-bg);
  border-bottom: 1px solid var(--color-border);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.card__title { font-size: var(--fs-md); font-weight: 600; }
.card__header-meta { font-size: var(--fs-xs); color: var(--color-muted); }
.card__header-meta a { color: var(--color-primary); text-decoration: none; }
.card__body { padding: 16px; }
.card__body--flush { padding: 0; }

/* ─── 테이블 ─────────────────────────────── */
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

.table th {
  text-align: center;       /* 모든 표의 헤더 글자는 가운데가 기본 (rules/ui.md §5) */
  padding: 10px 16px;
  background: var(--color-table-th-bg);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.table td {
  padding: 10px 16px;
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text);
  transition: background-color 0.2s;
}

.table tr:hover td { background: var(--color-table-hover); }

/* ─── 알럿 ───────────────────────────────── */
.alert {
  display: none;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  font-size: var(--fs-sm);
  margin-bottom: 12px;
  align-items: center;
  gap: 8px;
}

.alert.visible { display: flex; }

/* 사용자에게 보이는 알림 글자색(ui.md §1, 2026-10-14): 오류·경고는 빨강, 정보는 파랑, 성공은 초록 */
.alert--success { background: var(--color-success-bg); color: var(--color-success-text); border: 1px solid var(--color-success-border); }
.alert--error { background: var(--color-danger-bg); color: var(--color-danger-text); border: 1px solid var(--color-danger-border); }
.alert--info { background: var(--color-info-bg); color: var(--color-info-text); border: 1px solid var(--color-info-border); }
.alert--warning { background: var(--color-warning-bg); color: var(--color-danger-text); border: 1px solid var(--color-warning-border); }

/* ─── 다이얼로그 (alert / confirm) ──────── */
.dialog-overlay {
  position: fixed;
  inset: 0;
  z-index: 99998;
  background: rgba(0, 0, 0, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  animation: dialogFadeIn 0.15s ease;
}

.dialog-overlay--hiding {
  animation: dialogFadeOut 0.15s ease forwards;
}

.dialog {
  background: var(--color-card-bg, #fff);
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
  min-width: 280px;
  max-width: 420px;
  padding: 24px 28px 20px;
  text-align: center;
  animation: dialogScaleIn 0.15s ease;
}

.dialog-overlay--hiding .dialog {
  animation: dialogScaleOut 0.15s ease forwards;
}

.dialog__icon {
  font-size: 28px;
  margin-bottom: 8px;
}

.dialog__icon--success { color: var(--color-success); }
.dialog__icon--error { color: var(--color-danger, #dc2626); }
.dialog__icon--warning { color: var(--color-danger); }
.dialog__icon--info { color: var(--color-info-text); }
.dialog__icon--question { color: var(--color-primary); }

.dialog__title {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--color-text);
  margin-bottom: 6px;
}

.dialog__message {
  font-size: var(--fs-xs);
  color: var(--color-muted);
  line-height: 1.5;
  margin-bottom: 18px;
  word-break: keep-all;
}

.dialog__actions {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.dialog__actions .btn {
  min-width: 80px;
}

@keyframes dialogFadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes dialogFadeOut { from { opacity: 1; } to { opacity: 0; } }
@keyframes dialogScaleIn { from { transform: scale(0.9); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes dialogScaleOut { from { transform: scale(1); opacity: 1; } to { transform: scale(0.9); opacity: 0; } }

/* ─── 토스트 알림 ───────────────────────── */
#toastContainer {
  position: fixed;
  top: 64px;
  right: 16px;
  z-index: 99999;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-width: 260px;
  max-width: 400px;
  padding: 12px 16px;
  border-radius: var(--radius-lg);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1.5;
  pointer-events: auto;
  animation: toastSlideIn 0.25s ease;
}

.toast--hiding {
  animation: toastSlideOut 0.4s ease forwards;
}

.toast__icon { font-size: 16px; flex-shrink: 0; line-height: 1.5; }
.toast__msg {
  flex: 1;
  min-width: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.toast__close {
  background: none;
  border: none;
  font-size: 18px;
  cursor: pointer;
  padding: 0 2px;
  line-height: 1;
  opacity: 0.5;
  color: inherit;
}
.toast__close:hover { opacity: 1; }

.toast--success { background: #f0fdf4; color: #15803d; border: 1px solid #bbf7d0; }
.toast--error   { background: #fef2f2; color: #991b1b; border: 1px solid #fecaca; }
.toast--warning { background: #fffbeb; color: #854d0e; border: 1px solid #fde68a; }
.toast--info    { background: #eff6ff; color: #1e40af; border: 1px solid #bfdbfe; }

[data-theme="dark"] .toast--success { background: #0d2b1e; color: #86efac; border-color: #1a4d3a; }
[data-theme="dark"] .toast--error   { background: #2b0e0e; color: #fca5a5; border-color: #4d1a1a; }
[data-theme="dark"] .toast--warning { background: #2b1f06; color: #fcd34d; border-color: #4d3a10; }
[data-theme="dark"] .toast--info    { background: #1a1a1a; color: #e5e5e5; border-color: #333333; }

[data-theme="dark"] .dialog {
  background: #1a1a1a;
}

@keyframes toastSlideIn {
  from { transform: translateX(100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

@keyframes toastSlideOut {
  from { transform: translateX(0); opacity: 1; }
  to { transform: translateX(100%); opacity: 0; }
}

/* ─── 로딩 오버레이 ─────────────────────── */
.loading-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: var(--color-card-bg);
  opacity: 0.85;
  z-index: 10;
  border-radius: var(--radius-lg);
}

.loading-overlay__spinner {
  width: 28px;
  height: 28px;
  border: 3px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: loading-spin 0.6s linear infinite;
}

.loading-overlay__text {
  font-size: var(--fs-sm);
  color: var(--color-muted);
}

@keyframes loading-spin {
  to { transform: rotate(360deg); }
}

/* ─── 진행 표시 — 단추 진행 · 진행 막대 · 진행 목록 (.claude/docs/components/progress.md, rules/ui.md §9) ─── */
.btn.is-loading { cursor: progress; opacity: 1; }   /* 잠긴 단추의 흐림(opacity .5) 대신 진행 중임을 보인다 */
.btn__spinner {
  display: inline-block; width: 1em; height: 1em; flex: 0 0 auto;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  animation: loading-spin 0.7s linear infinite;
}
.progress-bar {
  position: relative; height: 4px; overflow: hidden; border-radius: var(--radius-sm);
  background: var(--color-border);
}
.progress-bar::after {
  content: ''; position: absolute; inset: 0 auto 0 0; width: calc(var(--value, 0) * 1%);
  background: var(--color-primary); transition: width 0.2s ease;
}
.progress-bar--indeterminate::after { width: 30%; animation: progress-flow 1.2s ease-in-out infinite; }
@keyframes progress-flow { from { left: -30%; } to { left: 100%; } }
.progress-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.progress-list__item {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4px 8px;
  font-size: var(--fs-sm);
}
.progress-list__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.progress-list__state { color: var(--color-info-text); white-space: nowrap; }
.progress-list__item .progress-bar { grid-column: 1 / -1; }
.progress-list__item.is-done .progress-list__state { color: var(--color-success-text); }
.progress-list__item.is-failed .progress-list__state { color: var(--color-danger-text); white-space: normal; }
@media (prefers-reduced-motion: reduce) {
  .btn__spinner, .progress-bar--indeterminate::after { animation: none; }
}

/* ─── 유틸리티 ───────────────────────────── */
.hidden { display: none !important; }
.text-muted { color: var(--color-muted); }
.text-sm { font-size: var(--fs-sm); }
.text-xs { font-size: var(--fs-xs); }

/* ─── 검색 가능 Selectbox (공통 컴포넌트) ──
 * JS: common/js/searchable-select.js
 * 사용: SearchableSelect.from('#id') 또는 createSearchableSelect(el, opts)
 * BEM: .search-select (block) / __element / --modifier 규칙 준수
 */

.search-select {
  position: relative;
  display: inline-block;
  width: 100%;
  font-size: var(--fs-xs);
  color: var(--color-text);
}

.search-select__trigger {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: var(--ctrl-py) 10px;
  box-sizing: border-box;
  line-height: 1.2;
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: 6px;
  cursor: pointer;
  text-align: left;
  transition: border-color 0.15s, box-shadow 0.15s;
  font: inherit;
  color: inherit;
}

.search-select__trigger:hover {
  border-color: var(--color-border);
}

.search-select__trigger:focus,
.search-select--open .search-select__trigger {
  outline: none;
  box-shadow: 0 0 0 2px var(--color-primary-glow);
}

.search-select__trigger-text {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.search-select__trigger-text.is-placeholder {
  color: var(--color-muted);
}

.search-select__trigger-clear {
  width: 18px;
  height: 18px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--color-muted);
  font-size: 16px;
  cursor: pointer;
  border-radius: 50%;
  line-height: 1;
  flex-shrink: 0;
}

.search-select__trigger-clear:hover {
  background: var(--color-border);
  color: var(--color-text);
}

.search-select__caret {
  color: var(--color-muted);
  font-size: 12px;
  line-height: 1;           /* 부모 min-height 유지 — 아이콘이 line-box 를 늘리지 않도록 */
  flex-shrink: 0;
  transition: transform 0.15s;
}

.search-select--open .search-select__caret {
  transform: rotate(180deg);
}

.search-select__panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 100;
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.search-select__panel[hidden] {
  display: none;
}

.search-select__search {
  width: 100%;
  padding: 6px 10px;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  font-size: var(--fs-xs);
  background: var(--color-section-bg);
  color: var(--color-text);
}

.search-select__search:focus {
  outline: none;
  box-shadow: 0 0 0 2px var(--color-primary-glow);
}

.search-select__list {
  overflow-y: auto;
  overflow-x: hidden;
  margin: 0;
  padding: 0;
}

.search-select__option {
  padding: 7px 10px;
  font-size: var(--fs-xs);
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  user-select: none;
}

.search-select__option.is-highlighted {
  background: var(--color-primary-glow);
}

.search-select__option.is-selected {
  background: var(--color-primary);
  color: #fff;
  font-weight: 500;
}

.search-select__option.is-selected.is-highlighted {
  background: var(--color-primary-hover);
}

.search-select__option.is-disabled {
  color: var(--color-muted);
  cursor: not-allowed;
}

.search-select__empty {
  padding: 16px 10px;
  text-align: center;
  color: var(--color-muted);
  font-size: var(--fs-xs);
}

.search-select--disabled {
  opacity: 0.6;
  pointer-events: none;
}

/* 고정 폭 modifier — 기본 width:100% 를 override (form__input--w* 대응) */
.search-select--w120 { width: 120px; }
.search-select--w160 { width: 160px; }
.search-select--w200 { width: 200px; }
.search-select--w240 { width: 240px; }

/* 다크 테마 호환 (data-theme="dark" 루트에서 변수 재정의됨) */
[data-theme="dark"] .search-select__panel {
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
}

/* ═════════════════════════════════════════════
 * 공통 컴포넌트 (components.md §2 기준)
 * 프로젝트·화면 구분 없이 공유. 접두사(admin-, wz-, nl-) 사용 금지.
 * 상태 클래스는 .is-* / .has-* 접두사만 허용.
 * ═══════════════════════════════════════════ */

/* ─── .split-panel — 분할 레이아웃 (components.md §2-1) ─────
 * 높이는 반드시 **부모 flex 체인** 에서 공급받는다.
 * `.page-content > .split-panel { flex:1; min-height:0 }` 규칙이 매칭되어야 화면 높이를 채우고
 * 각 `__left/__right/__col` 내부에서만 스크롤된다.
 * 하드코딩 min-height 금지 — 과거 480px fallback 제거됨. 부모가 height 를 공급하지 않으면
 * split-panel 은 콘텐츠 높이로 축소되므로, 반드시 `.page-content` 같은 flex:1 flex-column 부모에 넣는다.
 * ──────────────────────────────────────────────────────── */
.split-panel {
  display: flex;
  flex: 1;               /* 부모 flex 체인에서 남은 공간을 차지 */
  min-height: 0;         /* flex 자식이 콘텐츠 크기 제약을 받지 않게 해제 */
  gap: 16px;
}

.split-panel__left,
.split-panel__right,
.split-panel__col {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow-y: auto;          /* 각 패널 내부에서 스크롤 처리 */
  overflow-x: hidden;
}

/* 범용 스크롤 원칙 (flex column 부모 → 자식 오버플로우 시 부모 스크롤)
 * ─────────────────────────────────────────────────────────
 *   부모  : display: flex; flex-direction: column;
 *           min-height: 0; overflow-y: auto;
 *   자식 (자연 높이 유지 필요 — 압축되면 안 됨) : flex-shrink: 0
 *   자식 (남은 공간을 채워야 함 — 에디터·미리보기 등) : flex: 1; min-height: 0;
 *
 * 아래 공통 컴포넌트들은 flex column 부모 안에서 기본 flex-shrink:0 을 적용해
 * 내용 총 높이가 부모를 초과하면 부모가 스크롤하도록 한다
 * (각자 자연 높이 유지).
 *   .accordion, .panel-header, .panel-toolbar, .selector-bar,
 *   .filter-bar, .tabs, .settings-card, .card
 * 개별 정의에서 이미 flex-shrink:0 이 지정되어 있거나, 아래 묶음으로 지정됨.
 */

.split-panel__left { flex: 0 0 40%; }
.split-panel__right { flex: 1; }
.split-panel__col { flex: 1 1 0; }

/* 패널 내부 헤더는 스크롤 시 상단 고정 */
/* 최상단 panel-header 만 sticky — 동일 패널에 보조 툴바/필터 행이 있을 경우
 * 겹침을 방지 (보조 행은 자연 스크롤) */
.split-panel__left > .panel-header:first-of-type,
.split-panel__right > .panel-header:first-of-type,
.split-panel__col > .panel-header:first-of-type {
  position: sticky;
  top: 0;
  z-index: 2;
}

/* panel-header 직후 형제에 자동 4px 상단 여백 — 컨텐츠 컴포넌트(list/table/tree 등) 무관하게
 * 좌·우 패널의 panel-header → 컨텐츠 시각 간격을 일관 보장 (components.md §2-1 정책) */
.split-panel__left > .panel-header + *,
.split-panel__right > .panel-header + *,
.split-panel__col > .panel-header + * {
  padding-top: 4px;
}

/* 패널 내부 표준 래퍼 — panel-header 다음 컨텐츠 영역.
 * 스크롤은 패널 자체가 담당하므로 별도 overflow 불필요.
 * 자식에 height:100% 또는 flex layout 이 필요한 컴포넌트(Tabulator, CodeMirror 등)
 * 가 정상 동작하도록 flex column 컨테이너로 운영. */
.split-panel__body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* 라이브러리가 자체적으로 컨테이너 div 에 class 를 부여하는 경우(Tabulator 등)
 * 래퍼의 자연 layout 을 깨지 않도록 자동 fill 처리 */
.split-panel__body > .tabulator,
.split-panel__body > .cm-wrap,
.split-panel__body > .table-host {
  flex: 1;
  min-height: 0;
}

/* Root modifier */
.split-panel--triple { gap: 12px; }
.split-panel--four   { gap: 12px; }
.split-panel--editor { flex: 1; min-height: 0; }
.split-panel--compact { gap: 8px; min-height: 0; }

/* Left modifier */
.split-panel__left--narrow { flex: 0 0 260px; }
.split-panel__left--sidebar { flex: 0 0 220px; }
/* @deprecated — `.split-panel__left--50p` 로 대체. alias 유지(기존 사용처 호환). 신규 사용 금지. */
.split-panel__left--wide { flex: 0 0 50%; }

/* 비율 기반 — 오른쪽은 기본 flex:1 이므로 100% - 좌측% 가 자동 배정.
 * 50p 는 좌/우 5:5 균등 분할. */
.split-panel__left--20p { flex: 0 0 20%; }
.split-panel__left--25p { flex: 0 0 25%; }
.split-panel__left--30p { flex: 0 0 30%; }
.split-panel__left--33p { flex: 0 0 33.333%; }
.split-panel__left--40p { flex: 0 0 40%; }
.split-panel__left--50p { flex: 0 0 50%; }

/* Right modifier */
.split-panel__right--scroll { overflow-y: auto; }

@media (max-width: 1024px) {
  .split-panel--stack\@sm {
    flex-direction: column;
  }
  .split-panel--stack\@sm .split-panel__left,
  .split-panel--stack\@sm .split-panel__right,
  .split-panel--stack\@sm .split-panel__col {
    flex: 1 1 auto;
  }
}

/* ─── .page-header — 페이지 상단 제목/액션 (components.md §2-2A) ─── */
.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: 0 0 auto;
}

.page-header h1,
.page-header__title {
  font-size: var(--fs-xl);
  font-weight: 600;
  color: var(--color-text);
  margin: 0;
}

.page-header__actions {
  display: flex;
  gap: 8px;
}

/* ─── .page-content — main 내부 메뉴 컨텐츠 컨테이너 ────
 * 구조: <main> > <.page-header> + <[id="{project}PageContent"]> .page-content
 * 기본: 자체 스크롤. split-panel 직계 자식이면 overflow:hidden + flex chain.
 * ─────────────────────────────────────────────────── */
.page-content {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  --page-gap: 12px;      /* 자식이 gap 값을 참조해 margin 계산할 수 있게 노출 */
  overflow-y: auto;
}

/* split-panel 이 어느 depth 로 있든 (직계 or nested via .layout-fill) 외부 스크롤은 닫음 */
.page-content:has(.split-panel) {
  overflow: hidden;
}

/* Tabulator 를 포함하는 경우 — Tabulator 가 자체 scroll 처리하므로 부모 overflow 닫음.
 * Tabulator 의 `height: '100%'` 옵션이 definite height 로 해결되도록 flex chain 공급. */
.page-content:has(> .tabulator) {
  overflow: hidden;
}
.page-content > .tabulator {
  flex: 1 1 0;
  min-height: 0;
}

/* 직계 자식 split-panel 기본 흐름 — 부모 flex chain 에서 남은 공간 차지 */
.page-content > .split-panel {
  flex: 1;
  min-height: 0;
}

/* ─── .layout-fill — flex 체인 통과 래퍼 ─────
 * .page-content 와 .split-panel 사이에 중간 wrapper 가 불가피한 경우
 * (예: 탭 + 컨텐츠 패턴의 content 영역) 사용.
 * 부모 flex-column 의 남은 공간을 채우고 내부도 flex-column 으로 연결.
 * ──────────────────────────────────────────── */
.layout-fill {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ─── .panel-header — 패널/섹션 헤더 (components.md §2-2) ─── */
.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 16px;
  min-height: 49px;   /* padding 10+10 + btn-sm min-height 28 + border 1 = 49 */
  border-bottom: 1px solid var(--color-border);
  background: var(--color-section-bg);
  flex-shrink: 0;
  box-sizing: border-box;
}

.panel-header__title {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--color-text);
  margin: 0;
}

.panel-header__actions {
  display: flex;
  gap: 6px;
  align-items: center;
}

/* ─── .panel-body — 패널 본문 (스크롤 영역) ─── */
/* 패널 3분할 표준: panel-header(자연 높이) + panel-body(flex:1, 자체 스크롤) + panel-bottom(자연 높이)
 * 컨텐츠가 영역을 초과하면 panel-body 자체에서만 스크롤 — header/bottom 은 항상 보임 */
.panel-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

/* tabs 가 panel-body 안에 있을 때 tab-content 가 자체 스크롤하도록 layout 분리.
 * modifier(`--editor`, `--form`) 가 별도 overflow 정책을 가지면 그쪽이 우선되도록
 * 기본 셀렉터에는 overflow 미설정 — modifier 없는 base `.tab-content` 만 자체 스크롤. */
.panel-body > .tabs { flex-shrink: 0; }
.panel-body > .tab-content {
  flex: 1;
  min-height: 0;
}
.panel-body > .tab-content:not(.tab-content--editor):not(.tab-content--form) {
  overflow-y: auto;
}

/* ─── .panel-bottom — 패널 하단 액션 영역 ─── */
.panel-bottom {
  flex-shrink: 0;
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: flex-end;
  padding: 10px 16px;
  border-top: 1px solid var(--color-border);
  background: var(--color-section-bg);
  box-sizing: border-box;
}

/* 좌측(위험 액션) + 우측(주 액션) 분리 패턴 — 첫 자식만 좌측으로 밀어냄 */
.panel-bottom--split > :first-child { margin-right: auto; }

/* ─── .is-hidden — 표준 숨김 상태 클래스 ─── */
.is-hidden { display: none !important; }

/* Modifier */
.panel-header--page {
  padding: 16px 20px;
}
.panel-header--page .panel-header__title {
  font-size: var(--fs-xl);
}

.panel-header--sticky {
  position: sticky;
  top: 0;
  z-index: 10;
}

/* ─── .tabs — 탭 (components.md §2-3) ─── */
.tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-section-bg);
  flex-wrap: wrap;
  flex-shrink: 0;
  margin-bottom: 12px;  /* form__group 과 동일 간격 */
}

.tabs__btn {
  padding: var(--ctrl-py) 16px;
  border: none;
  background: transparent;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--color-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
  font-family: inherit;
  line-height: 1.2;
}

.tabs__btn:hover {
  color: var(--color-primary);
  background: rgba(0, 0, 0, 0.06);
}

.tabs__btn.is-active {
  color: var(--color-primary);
  border-bottom-color: var(--color-primary);
  font-weight: 600;
}

/* Modifier */
.tabs--sub {
  background: transparent;
  border-top: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
  padding: 0 4px;
}

.tabs--justify .tabs__btn {
  flex: 1;
  justify-content: center;
  display: inline-flex;
  align-items: center;
}

.tabs--pills {
  border-bottom: none;
  gap: 4px;
  background: transparent;
  padding: 4px;
}
.tabs--pills .tabs__btn {
  border-bottom: none;
  border-radius: var(--radius-sm);
}
.tabs--pills .tabs__btn.is-active {
  background: var(--color-primary);
  color: var(--color-bg);  /* 다크는 primary 가 #fff 라 글자는 배경색으로 */
}

[data-theme="dark"] .tabs__btn:hover {
  background: rgba(255, 255, 255, 0.06);
}

/* ─── .tree — 트리 (components.md §2-4) ─── */
.tree {
  list-style: none;
  margin: 0;
  padding: 4px 0;
  font-size: var(--fs-sm);
  color: var(--color-text);
}

.tree__item {
  margin: 1px 0;
  position: relative;
}

.tree__item.is-collapsed > .tree__children {
  display: none;
}

.tree__node {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 12px;
  min-height: 32px;       /* btn-table-more 유무와 무관하게 모든 트리 노드 동일 높이 */
  box-sizing: border-box;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background 0.15s;
}

/* 트리 노드 내부 더보기 버튼 — list__item--actions 와 동일한 hover-reveal 패턴 */
.tree__node .btn-table-more {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  margin-left: auto;
  opacity: 0;
  transition: opacity 0.15s;
}

.tree__node:hover .btn-table-more,
.tree__node.is-active .btn-table-more {
  opacity: 1;
}

.tree__node.is-active .btn-table-more {
  color: rgba(255, 255, 255, 0.85);
}

.tree__node.is-active .btn-table-more:hover {
  background: rgba(255, 255, 255, 0.2);
  color: #fff;
}

.tree__node:hover {
  background: var(--color-table-hover);
}

.tree__node.is-active {
  background: var(--color-primary);
  color: #ffffff;
}

.tree__node.is-disabled {
  opacity: 0.45;
  pointer-events: none;
}

.tree__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  font-size: 10px;
  color: var(--color-muted);
  flex-shrink: 0;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

.tree__toggle i {
  transition: transform 0.2s;
  transform: rotate(90deg);  /* 기본(펼침): fa-chevron-right 를 90도 회전해 아래로 */
}

.tree__item.is-collapsed > .tree__node > .tree__toggle i {
  transform: rotate(0deg);   /* 접힘: 원래 방향(오른쪽) */
}

.tree__toggle--leaf {
  visibility: hidden;
}

.tree__checkbox {
  margin: 0 4px 0 0;
  cursor: pointer;
  accent-color: var(--color-primary);
  flex: 0 0 auto;
}

.tree__label {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tree__children {
  list-style: none;
  margin: 0;
  padding: 0 0 0 20px;
}

/* Modifier */
.tree--compact .tree__node {
  padding: 3px 10px;
  font-size: var(--fs-xs);
}
.tree--compact .tree__children {
  padding-left: 16px;
}

.tree--sortable .tree__node {
  user-select: none;
}

/* SortableJS 연동 */
.tree .sortable-ghost {
  opacity: 0.3;
  background: rgba(0, 0, 0, 0.12) !important;
}
.tree .sortable-chosen > .tree__node {
  background: rgba(0, 0, 0, 0.12);
}

/* ─── .list — 공통 리스트 (components.md §2-5) ─── */
.list {
  list-style: none;
  margin: 0;
  padding: 4px 0;
}

.list__item {
  padding: 10px 16px;
  cursor: pointer;
  border-bottom: 1px solid var(--color-border);
  transition: background 0.15s;
}

.list__item:hover {
  background: var(--color-table-hover);
}

.list__item.is-active {
  background: var(--color-primary);
  color: var(--color-bg);
}
.list__item.is-active .list__meta {
  color: var(--color-bg);
  opacity: 0.7;
}

.list__item--actions {
  display: flex;
  align-items: center;
  padding: 8px 8px 8px 16px;
  gap: 8px;
}

.list__content {
  flex: 1;
  min-width: 0;
}

.list__name {
  font-size: var(--fs-sm);
  font-weight: 500;
}

.list__meta {
  font-size: var(--fs-xs);
  color: var(--color-muted);
  margin-top: 2px;
}

/* Modifier */
.list--compact .list__item { padding: 6px 12px; }
.list--bordered .list__item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  margin-bottom: 4px;
}
.list--dense .list__item { border-bottom: none; padding: 4px 12px; }
/* 여백 없는 카드 안 목록 — 마지막 줄 밑줄·위아래 4px 가 카드 테두리와 겹쳐 두 줄로 보이던 것 */
.card__body--flush > .list { padding: 0; }
.card__body--flush > .list > .list__item:last-child { border-bottom: none; }

/* ─── .empty-message — 빈 상태 (components.md §2-6) ─── */
.empty-message {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  gap: 12px;
  color: var(--color-muted);
  padding: 24px;
}

.empty-message__icon {
  font-size: 48px;
  opacity: 0.4;
}

.empty-message__text {
  font-size: var(--fs-sm);
  margin: 0;
  text-align: center;
}

/* Modifier */
.empty-message--sm { min-height: 100px; }
.empty-message--sm .empty-message__icon { font-size: 32px; }

.empty-message--lg { min-height: 320px; }
.empty-message--lg .empty-message__icon { font-size: 64px; }

.empty-message--inline {
  flex-direction: row;
  min-height: auto;
  padding: 8px 12px;
}
.empty-message--inline .empty-message__icon { display: none; }

/* ─── .form — 폼 그룹 (components.md §2-7) ─────
 * 공통 .form__* 정의. 레거시 .admin-form__* 는 portal-admin.css 에서
 * selector-list 별칭으로 동일 스타일을 받아 JS 마이그레이션 전까지 병행.
 * ───────────────────────────────────────────── */
.form__group {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  margin-bottom: 12px;
}

.form__group--top { align-items: stretch; }
.form__group--action {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;                 /* 라벨과 단추·설명의 세로 가운데를 맞춘다 */
  justify-content: flex-start;
  gap: 8px 12px;
  margin-top: 16px;
}
.form__group--action .form__label:empty { display: none; }   /* 라벨 없는 조치 줄 — 단추가 입력칸과 같은 왼쪽 선에서 시작한다 */
.form__group--action .form__control {
  width: auto;
  flex: 1 1 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
}
.form__group--action .form__hint { margin-top: 0; }
.form__group--inline {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

/* 남은 높이를 다 쓰는 칸 — 편집기 모달(.modal--editor)의 본문 편집기. 부모가 flex column 이어야 한다 */
.form__group--fill {
  flex: 1;
  min-height: 0;
  margin-bottom: 0;
}
.form__group--fill > .form__control {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.form__label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-text);
  text-align: left;
  line-height: 1.4;
}

.form__control {
  width: 100%;
  min-width: 0;
}

.form__input,
.form__select {
  width: 100%;
  padding: var(--ctrl-py) 10px;
  box-sizing: border-box;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  font-size: var(--fs-sm);
  line-height: 1.2;
  background: var(--color-card-bg);
  color: var(--color-text);
  font-family: inherit;
  transition: background 0.3s ease, border-color 0.3s ease;
}

.form__input:focus,
.form__select:focus {
  outline: none;
  box-shadow: 0 0 0 2px var(--color-primary-glow);
}

.form__input:disabled,
.form__select:disabled {
  background-color: var(--color-module-bg);
  color: var(--color-muted);
  cursor: not-allowed;
}

.form__input.is-invalid,
.form__select.is-invalid {
  border-color: var(--color-danger);
}

textarea.form__input {
  font-family: inherit;
  resize: vertical;
}

/* flex 컨테이너(panel-toolbar/filter-bar) 내부에서 input 이 남은 공간을 채우도록 */
.form__input--stretch {
  flex: 1 1 0;
  min-width: 0;
}

.form__select {
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  /* chevron 아이콘 (라이트) — 우측 10px 여백 + 12px 아이콘 + 8px gap */
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2 4l4 4 4-4' stroke='%23707070' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 12px 12px;
  padding-right: 30px;
}

/* IE 레거시 — 기본 화살표 숨김 */
.form__select::-ms-expand {
  display: none;
}

/* 다크 테마 — chevron 색상만 교체 */
[data-theme="dark"] .form__select {
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2 4l4 4 4-4' stroke='%23a1a1aa' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.form__input--narrow { width: 80px; }
.form__input--sm { width: 100px; }
.form__input--md { width: 160px; }

.form__hint {
  font-size: var(--fs-xs);
  color: var(--color-muted);
  line-height: 1.5;
}
/* 컨트롤 안에 체크·라디오·입력·설명이 둘 이상 세로로 쌓이면 최소 --ctrl-gap 띄운다.
   가로로 펼치는 조치 줄(--action)은 제외. 개별 margin 으로 좁히지 않는다 */
.form__control > * + * { margin-top: var(--ctrl-gap); }
.form__group--action .form__control > * + * { margin-top: 0; }
.form__control > .form__hint { display: block; }
/* 보조 글(small)은 어디서나 --fs-xs 한 크기 — 브라우저 기본(0.83em)을 쓰지 않는다 */
small { font-size: var(--fs-xs); }

/* 상태 안내줄 — 흐린 13px 로는 놓치므로 한 단계 크고 굵게, 오류·경고 빨강 / 정보 파랑 / 성공 초록 */
.form__hint--success,
.form__hint--error,
.form__hint--warning,
.form__hint--info { font-size: var(--fs-sm); font-weight: 500; }
.form__hint--success { color: var(--color-success-text); }
.form__hint--error,
.form__hint--warning { color: var(--color-danger-text); }
.form__hint--info { color: var(--color-info-text); }

/* ─── .search-input — 아이콘 포함 검색 입력 (BEM)
 * 구조:
 *   <div class="search-input">
 *     <i class="fa-solid fa-magnifying-glass search-input__icon"></i>
 *     <input class="search-input__field" placeholder="검색어...">
 *   </div>
 * - 아이콘 슬롯 확보를 위해 좌측 padding 32px 고정
 */
.search-input {
  position: relative;
  display: inline-block;
  width: 100%;
}

.search-input__icon {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--color-muted);
  pointer-events: none;
  font-size: var(--fs-sm);
}

.search-input__field {
  width: 100%;
  padding: var(--ctrl-py) 12px var(--ctrl-py) 32px;
  box-sizing: border-box;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: var(--color-card-bg);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--fs-sm);
  line-height: 1.2;
  outline: none;
  transition: background 0.3s ease, border-color 0.3s ease;
}

.search-input__field:focus {
  box-shadow: 0 0 0 2px var(--color-primary-glow);
}

.search-input__field:disabled {
  background: var(--color-module-bg);
  color: var(--color-muted);
  cursor: not-allowed;
}

/* 고정 폭 modifier */
.search-input--w160 { width: 160px; }
.search-input--w200 { width: 200px; }
.search-input--w240 { width: 240px; }

.form__radios,
.form__checks {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

.form__radio,
.form__check {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-sm);
  cursor: pointer;
}

.form__radio input,
.form__check input {
  accent-color: var(--color-primary);
}

.form__actions {
  margin-top: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.form__actions-right {
  margin-left: auto;
  display: flex;
  gap: 8px;
}

.form__divider {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--color-muted);
  margin: 16px 0 12px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* ─── .filter-bar — 테이블 상단 필터 바 (공통) ─── */
.filter-bar {
  display: flex;
  gap: 8px;
  flex-wrap: nowrap;      /* 한 줄 유지 — 좁은 화면에서 컨트롤 축소 */
  align-items: center;
  flex-shrink: 0;
  min-width: 0;           /* 내부 자식이 필요 시 줄어들도록 */
}

/* 내부 자식은 내용 너비만큼만 차지 — flex grow/shrink 모두 없음 */
.filter-bar > * {
  flex: 0 0 auto;
  min-width: 0;
}

/* 컨트롤이 많은 필터바(시스템 로그처럼 7개 이상)는 줄바꿈 — 기본형은 한 줄 유지가 원칙이라 modifier 로만 */
.filter-bar--wrap {
  flex-wrap: wrap;
  row-gap: 8px;
}

.filter-bar__sep {
  color: var(--color-muted);
  font-size: var(--fs-sm);
  line-height: 1;
}

/* filter-bar 내부 form 컨트롤은 공통 .form__input / .form__select 의 width:100% 를 오버라이드.
 * input 은 브라우저 기본 너비(`size` 속성 또는 ~20ch), select 는 가장 긴 옵션 너비로 자동 조정. */
.filter-bar .form__input,
.filter-bar .form__select {
  width: auto;
}

/* 필터바 안 버튼은 컨트롤(.form__select·.search-input)과 같은 높이 — 세로 패딩·글자 크기를 기본형으로 고정한다.
 * 크기 modifier(.btn-sm·.btn-xs)를 붙여도 높이가 달라지지 않는다 (components/form.md §2, rules/ui.md §3) */
.filter-bar .btn {
  padding-top: var(--ctrl-py);
  padding-bottom: var(--ctrl-py);
  font-size: var(--fs-sm);
  line-height: 1.2;
}

/* ─── .modal — 모달 (components.md §2-9) ─────
 * 공통 .modal 정의. 레거시 .admin-modal 는 portal-admin.css 에서 별칭 처리.
 * 상태: .is-open (기존 .admin-modal.visible 은 별칭 유지).
 * ───────────────────────────────────────────── */
.modal {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1000;
  background: rgba(0, 0, 0, 0.5);
  align-items: center;
  justify-content: center;
}

.modal.is-open {
  display: flex;
}

.modal__content {
  background: var(--color-section-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  width: 100%;
  max-width: 560px;
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
}

.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--color-border);
}

.modal__title {
  font-size: var(--fs-lg);
  font-weight: 600;
  margin: 0;
}

.modal__close {
  background: none;
  border: none;
  font-size: 20px;
  cursor: pointer;
  color: var(--color-muted);
  line-height: 1;
}
.modal__close:hover { color: var(--color-text); }

.modal__body {
  padding: 20px;
}

.modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 20px;
  border-top: 1px solid var(--color-border);
}

/* Modifier */
.modal--sm .modal__content { max-width: 420px; }
.modal--lg .modal__content { max-width: 780px; }
.modal--full .modal__content { max-width: 90vw; max-height: 90vh; }

/* 편집기 모달 (components/overlay.md §1 `--editor`) — 본문 편집기(TinyMCE·textarea·CodeMirror)가 남은 높이를 다 쓴다.
 * 폭 min(1200px, 96vw)·높이 92vh 를 고정하고 header/footer 는 자연 높이, body 가 flex column 이라
 * `.form__group--fill` 한 칸이 나머지를 채운다. 전체화면(`.is-fullscreen`)은 헤더의 `.modal__fullscreen` 이 토글(utils.js). */
.modal--editor .modal__content {
  display: flex;
  flex-direction: column;
  width: 96vw;
  max-width: 1200px;
  height: 92vh;
  max-height: 92vh;
  overflow: hidden;
}
.modal--editor .modal__header,
.modal--editor .modal__footer { flex-shrink: 0; }

/* ─── 화면 설명 모달 (.modal--manual · .manual) — common/js/manual-view.js. 왼쪽 편 목록, 오른쪽 본문(.md-body) ─── */
.modal--manual .modal__content { max-width: min(1100px, 96vw); height: 86vh; display: flex; flex-direction: column; }
.modal--manual .modal__body { flex: 1; min-height: 0; padding: 0; }
.manual { display: flex; height: 100%; }
.manual__nav { flex: 0 0 220px; overflow-y: auto; padding: 12px 8px; border-right: 1px solid var(--color-border); background: var(--color-bg); }
.manual__group { display: flex; align-items: center; gap: 6px; width: 100%; margin: 6px 0 2px; padding: 6px 8px; border: 0; border-radius: var(--radius-sm); background: none; font: inherit; font-size: var(--fs-xs); font-weight: 600; color: var(--color-muted); letter-spacing: 0.02em; text-align: left; cursor: pointer; }
.manual__group:first-child { margin-top: 0; }
.manual__group:hover { background: var(--color-hover-bg, rgba(0, 0, 0, 0.05)); color: var(--color-text); }
.manual__caret { flex-shrink: 0; font-size: 9px; transition: transform 0.15s; }
.manual__group.is-open .manual__caret { transform: rotate(90deg); }
.manual__group-name { flex: 1; min-width: 0; }
.manual__group-count { flex-shrink: 0; font-weight: 400; opacity: 0.7; }
.manual__list { padding-left: 10px; }
@media (prefers-reduced-motion: reduce) { .manual__caret { transition: none; } }
.manual__item { display: block; width: 100%; padding: 6px 10px; border: 0; border-radius: var(--radius-sm); background: none; color: var(--color-text); font: inherit; font-size: var(--fs-sm); text-align: left; cursor: pointer; }
.manual__item:hover { background: var(--color-hover-bg, rgba(0, 0, 0, 0.05)); }
.manual__item.is-active { background: var(--color-primary); color: #fff; }
.manual__doc { flex: 1; min-width: 0; overflow-y: auto; padding: 20px 28px 32px; }
.manual__meta { display: flex; flex-wrap: wrap; gap: 14px; margin: -6px 0 14px; color: var(--color-muted); font-size: var(--fs-xs); }
.manual__img { display: block; max-width: 100%; height: auto; margin: 8px 0 12px; border: 1px solid var(--color-border); border-radius: var(--radius-sm); }
.manual__img-missing, .manual__empty { color: var(--color-muted); font-size: var(--fs-xs); }
.manual__empty { padding: 8px 10px; }
/* 편집(superadmin · 개발 사본) — 본문 자리를 원문 textarea 가 채운다. 머리 단추는 .modal__header-actions(전체화면·편집·닫기) */
.modal--manual.is-editing .manual__doc { display: flex; flex-direction: column; gap: 8px; }
.manual__edit-hint { margin: 0; color: var(--color-muted); font-size: var(--fs-xs); }
.manual__edit-text { flex: 1; min-height: 0; resize: none; font-family: var(--font-mono, ui-monospace, monospace); font-size: var(--fs-sm); line-height: 1.5; white-space: pre; overflow: auto; }
.manual__edit-bar { display: flex; align-items: center; gap: 8px; }
.manual__edit-status { color: var(--color-muted); font-size: var(--fs-xs); }
@media (max-width: 720px) {
  .manual { flex-direction: column; }
  .manual__nav { flex: 0 0 auto; max-height: 30%; border-right: 0; border-bottom: 1px solid var(--color-border); }
}
.modal--editor .modal__body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.modal.is-fullscreen .modal__content {
  width: 100vw;
  max-width: none;
  height: 100vh;
  max-height: none;
  border-radius: 0;
  transform: none !important;   /* 헤더 드래그(modal-drag.js)로 옮겨 둔 위치를 무시 */
}
.modal__header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}
.modal__fullscreen {
  background: none;
  border: none;
  font-size: var(--fs-lg);
  cursor: pointer;
  color: var(--color-muted);
  line-height: 1;
}
.modal__fullscreen:hover { color: var(--color-text); }
/* 편집기 모달의 메타 줄 — 분류·형식·토글처럼 짧은 컨트롤을 한 줄에 (안은 .form__group--inline) */
.modal__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 24px;
  margin-bottom: 12px;
}
.modal__meta .form__group { margin-bottom: 0; }
.modal__meta .form__control { width: auto; }
.modal__meta .form__select { width: auto; }

/* ─── .accordion — 아코디언 (components.md 확장) ──
 * admin-accordion, nl-section 통합. 기본 닫힘, is-open 추가 시 열림.
 * ──────────────────────────────────────────────── */
.accordion {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  margin-bottom: 12px;
  overflow: hidden;
  flex-shrink: 0;   /* flex column 부모 내에서 자연 높이 유지 — 내용이 길면 부모가 스크롤 */
}

.accordion__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  cursor: pointer;
  background: var(--color-table-th-bg);
  user-select: none;
  transition: background 0.15s ease;
}

.accordion__header:hover {
  background: var(--color-table-hover);
}

.accordion__header:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: -2px;
}

.accordion__title {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--color-text);
  margin: 0;
}

.accordion__arrow {
  font-size: 11px;
  color: var(--color-muted);
  transition: transform 0.25s ease;
}

.accordion.is-open .accordion__arrow {
  transform: rotate(180deg);
}

.accordion__body {
  display: none;
  padding: 12px 16px;
  border-top: 1px solid var(--color-border);
}

.accordion.is-open .accordion__body {
  display: block;
}

/* Modifier */
.accordion--card {
  background: var(--color-card-bg);
}
.accordion--card .accordion__header {
  background: var(--color-section-bg);
}

.accordion--static .accordion__header {
  cursor: default;
}
.accordion--static .accordion__header:hover {
  background: var(--color-table-th-bg);
}
.accordion--static .accordion__arrow {
  display: none;
}
.accordion--static .accordion__body {
  display: block;
}

.accordion--flush {
  border: none;
  border-radius: 0;
}
.accordion--flush .accordion__body {
  border-top: 1px solid var(--color-border);
}

/* ═══════════════════════════════════════════════════════════════════
 * 관리 UI 공통 유틸 (2026-04-19 통합)
 *   portal-admin.css 에서 범용 가능한 요소를 이관. context-prefix 금지.
 * ═══════════════════════════════════════════════════════════════════ */

/* ─── Table Toolbar (테이블 상단 컨트롤 바) ──────────────────────── */
.table-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 0;
  position: relative;
  flex-shrink: 0;
}

/* 내부 컨트롤은 내용 너비만큼만 — filter-bar 와 동일 */
.table-toolbar > * {
  flex: 0 0 auto;
  min-width: 0;
}
.table-toolbar .form__input,
.table-toolbar .form__select {
  width: auto;
}

/* 테이블 툴바 바로 다음에 오는 Tabulator 는 부모 flex gap 을 상쇄해 딱 붙여 렌더.
 * .page-content / .split-panel__* gap 이 12px 기준 — 해당 영역에서만 적용. */
.table-toolbar + .tabulator,
.table-toolbar + [id$="Table"] {
  margin-top: calc(-1 * var(--page-gap, 12px));
}

/* ─── Dropdown Panel (컬럼 토글/필터 드롭다운) ─────────────────── */
.dropdown-panel {
  display: none;
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 100;
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  padding: 12px;
  min-width: 180px;
  flex-direction: column;
  gap: 6px;
}
.dropdown-panel.is-open { display: flex; }

/* ─── Multiselect (체크박스 다중선택) ──────────────────────────── */
.multiselect {
  position: relative;
  width: 100%;
}
.multiselect__btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: var(--ctrl-py) 10px;
  box-sizing: border-box;
  line-height: 1.2;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  background: var(--color-card-bg);
  cursor: pointer;
  color: var(--color-text);
}
.multiselect__btn::after {
  content: '▼';
  font-size: 10px;
  color: var(--color-muted);
}
.multiselect__panel {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 100;
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  padding: 8px;
  margin-top: 4px;
  max-height: 200px;
  overflow-y: auto;
}
.multiselect__panel.is-open { display: block; }
.multiselect__all {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-sm);
  font-weight: 600;
  padding-bottom: 6px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--color-border);
  cursor: pointer;
}
.multiselect__item {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-sm);
  padding: 2px 0;
  cursor: pointer;
}
.multiselect__all input,
.multiselect__item input {
  accent-color: var(--color-primary);
}

/* ─── Matrix (권한·서비스·메뉴 매트릭스 테이블 공통) ─────────── */
.matrix {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-sm);
  text-align: center;
  background: var(--color-card-bg);
  border-radius: var(--radius-md);
  overflow: hidden;
  border: 1px solid var(--color-border);
}
.matrix th {
  background-color: var(--color-table-th-bg);
  color: var(--color-muted);
  font-weight: 600;
  padding: 12px 16px;
  border-bottom: 1px solid var(--color-border);
  text-transform: uppercase;
  font-size: var(--fs-xs);
  letter-spacing: 0.05em;
}
.matrix td {
  padding: 10px 16px;
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text);
  transition: background-color 0.2s;
}
.matrix td:first-child { text-align: left; font-weight: 600; }
.matrix tbody tr { transition: background-color 0.2s; }
.matrix tbody tr:hover td { background-color: var(--color-table-hover); }
.matrix tbody tr:last-child td { border-bottom: none; }
.matrix__flags { font-family: var(--font-mono); font-size: var(--fs-code); }
.matrix__empty { color: var(--color-muted); opacity: 0.5; }
.matrix__legend { font-size: var(--fs-code); color: var(--color-muted); margin-top: 8px; }

/* Matrix modifier: compact grid (얇은 표·인라인 입력) */
.matrix--compact {
  border-collapse: collapse;
  font-size: var(--fs-xs);
  border-radius: 0;
}
.matrix--compact th,
.matrix--compact td {
  border: 1px solid var(--color-border);
  padding: 6px 8px;
  vertical-align: middle;
  text-transform: none;
  letter-spacing: normal;
}
.matrix--compact th {
  white-space: nowrap;
}

/* Matrix custom checkbox (body 내부의 권한 체크) */
.matrix input[type="checkbox"].matrix__check {
  appearance: none;
  background-color: var(--color-section-bg);
  margin: 0;
  font: inherit;
  color: currentColor;
  width: 1.3em;
  height: 1.3em;
  border: 2px solid #cbd5e1;
  border-radius: 4px;
  display: grid;
  place-content: center;
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
[data-theme="dark"] .matrix input[type="checkbox"].matrix__check { border-color: #475569; }
.matrix input[type="checkbox"].matrix__check::before {
  content: "";
  width: 0.7em;
  height: 0.7em;
  transform: scale(0);
  transition: 150ms transform cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: inset 1em 1em white;
  background-color: white;
  transform-origin: center;
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
}
.matrix input[type="checkbox"].matrix__check:checked {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
}
.matrix input[type="checkbox"].matrix__check:checked::before { transform: scale(1); }
.matrix input[type="checkbox"].matrix__check:hover { border-color: var(--color-primary-hover); }

/* Matrix row variants */
.matrix__row--highlight td { background: var(--color-primary-glow); font-weight: 600; }
.matrix__row--group td {
  background: var(--color-table-th-bg);
  font-size: var(--fs-code);
  font-weight: 700;
  color: var(--color-muted);
  padding: 4px 12px;
  text-transform: uppercase;
}

/* ─── Info Table (key-value 테이블) ─────────────────────────────── */
.table--info {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 20px;
  font-size: var(--fs-sm);
}
.table--info th,
.table--info td {
  padding: 8px 12px;
  border-bottom: 1px solid var(--color-border);
  text-align: left;
  vertical-align: middle;
}
.table--info th {
  color: var(--color-muted);
  font-weight: 600;
  font-size: var(--fs-xs);
  width: 80px;
  white-space: nowrap;
}
.table--info td { color: var(--color-text); }

/* ─── Icon Grid / Button (아이콘 선택기) ──────────────────────── */
.icon-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.icon-btn {
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-card-bg);
  color: var(--color-muted);
  cursor: pointer;
  font-size: 15px;
  transition: all 0.15s ease;
}
.icon-btn:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}
.icon-btn.is-selected {
  border-color: var(--color-primary);
  background: var(--color-primary-glow);
  color: var(--color-primary);
}

/* ─── Actions Grid (체크박스/버튼 그리드) ────────────────────── */
.actions-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* ─── Form input 너비 유틸 ───────────────────────────────────── */
.form__input--w80  { width: 80px; }
.form__input--w120 { width: 120px; }
.form__input--w160 { width: 160px; }
.form__input--w200 { width: 200px; }
.form__input--w60  { width: 60px; }

/* ─── Badge size modifier ───────────────────────────────────── */
.badge--xs { font-size: var(--fs-badge); padding: 1px 6px; }

/* ─── Pill (작은 라벨/스텝 표시) ─────────────────────────────── */
.pill {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-xs);
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 10px;
  letter-spacing: 0.5px;
}
.pill--primary {
  color: var(--color-primary);
  background: var(--color-primary-glow);
}
.pill--muted {
  color: var(--color-muted);
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
}

/* ─── Section label (uppercase 보조 라벨) ───────────────────── */
.section-label {
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--color-muted);
  text-transform: uppercase;
}

/* ─── Btn pulse (저장 필요 pulsing 애니메이션) ──────────────── */
.btn--pulse { animation: btn-pulse 1.4s ease-in-out infinite; }
@keyframes btn-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.35); }
  50% { box-shadow: 0 0 0 6px rgba(0, 0, 0, 0); }
}

/* ─── Dirty indicator (미저장 상태 표시) ────────────────────── */
.dirty-indicator {
  display: none;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--color-warning);
}
.dirty-indicator.is-visible { display: inline-flex; }
.dirty-indicator__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-warning);
  animation: btn-pulse 1.4s ease-in-out infinite;
}

/* ─── Custom scrollbar ──────────────────────────────────────── */
.custom-scrollbar::-webkit-scrollbar { width: 6px; height: 6px; }
.custom-scrollbar::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: 3px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover { background: var(--color-muted); }

/* ─── Workspace (상단바 + 다중 컬럼 + 하단바 구성) ──────────── */
/* ─── list__item 상태 클래스 확장 ────────────────────────────── */
.list__item.is-dragging { opacity: 0.3; }
.list__item.is-dragover { border-top: 2px solid var(--color-primary); }
.list__item.is-inactive { opacity: 0.5; }
.list__item--highlight {
  background: var(--color-primary-glow);
  border: 1px dashed var(--color-primary);
  font-weight: 600;
}

/* ─── panel-header 보조 ────────────────────────────────────── */
.panel-header__hint {
  font-size: var(--fs-xs);
  color: var(--color-muted);
}

/* ─── Settings card (환경설정 섹션 카드) ────────────────────── */
.settings-card {
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 24px;
  margin-bottom: 16px;
  flex-shrink: 0;
}
.settings-card__title {
  font-size: var(--fs-md);
  font-weight: 600;
  margin-bottom: 16px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--color-border);
}
.settings-card__actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 20px;
}

/* ═══════════════════════════════════════════════════════════════════
 * 공통 sub-elements / helpers — 2026-04-19 2차 확장
 * ═══════════════════════════════════════════════════════════════════ */

/* ─── Hint text (italic muted 보조 문구) ─────────────────────── */
.hint-text {
  font-size: var(--fs-xs);
  color: var(--color-muted);
  font-style: italic;
}

/* ─── Description box (템플릿/모드 설명 카드) ───────────────── */
.description-box {
  padding: 10px 12px;
  background: var(--color-section-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
}
.description-box__name {
  font-weight: 600;
  font-size: var(--fs-xs);
  margin-bottom: 4px;
}
.description-box__meta {
  color: var(--color-muted);
  margin-bottom: 4px;
}
.description-box__meta code {
  font-family: var(--font-mono);
  background: var(--color-card-bg);
  padding: 1px 4px;
  border-radius: 3px;
}
.description-box__text {
  font-style: italic;
  color: var(--color-muted);
}

/* ─── Matrix 보조 요소 (wrap·info·컬럼 너비·셀 유틸) ────────── */
.matrix-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.matrix-info {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 8px;
  background: var(--color-primary-glow);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
}
.matrix-info__cus {
  margin-left: auto;
  color: var(--color-muted);
}
.matrix__col-menu { text-align: left; width: 50%; }
.matrix__col-act  { width: 36px; text-align: center; }
.matrix__cell     { text-align: center; }
.matrix__cell input[type="checkbox"],
.matrix__cell-check input[type="checkbox"] {
  accent-color: var(--color-primary);
  cursor: pointer;
}
.matrix__cell-del { text-align: center; width: 50px; }
.matrix__key {
  font-family: var(--font-mono);
  font-size: var(--fs-code);
  color: var(--color-muted);
}

/* ─── Accordion 추가 sub-elements (header-left, header-actions, summary, arrow--sm) ─── */
.accordion__header-left {
  display: flex;
  align-items: center;
  gap: 12px;
}
/* 헤더 우측 액션 영역 — 버튼 + arrow 를 묶어 space-between 레이아웃에 함께 배치 */
.accordion__header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.accordion__summary {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  font-size: var(--fs-code);
}
.accordion__arrow--sm {
  font-size: 9px;
}

/* ─── List item sub-elements (item 내부 구성요소) ──────────── */
.list__item-title {
  font-weight: 600;
  font-size: var(--fs-sm);
  display: flex;
  align-items: center;
  gap: 6px;
}
.list__item-meta {
  font-size: var(--fs-code);
  color: var(--color-muted);
  display: flex;
  gap: 4px;
}
.list__item-meta code {
  font-family: var(--font-mono);
  background: var(--color-table-th-bg);
  padding: 1px 4px;
  border-radius: 3px;
  font-size: var(--fs-xs);
}
.list__item-desc {
  font-size: var(--fs-code);
  color: var(--color-muted);
  margin-top: 4px;
  font-style: italic;
}
.list__item-label {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  cursor: pointer;
}
.list__item-icon {
  color: var(--color-primary);
  font-size: 14px;
  width: 18px;
  text-align: center;
}
.list__item-name { font-weight: 500; }
.list__item-count {
  color: var(--color-muted);
  font-size: var(--fs-code);
}
.list__item-actions {
  display: flex;
  align-items: center;
  gap: 4px;
}
.list__item-drag {
  padding: 0 6px 0 0;
  display: flex;
  align-items: center;
  color: var(--color-muted);
  font-size: var(--fs-code);
  cursor: grab;
}

/* list item font-weight for active (background/color 는 상위 정의 사용 — 다크모드 대응) */
.list__item.is-active { font-weight: 600; }

/* ─── List 그룹 (섹션 타이틀로 묶기) ────────────────────────── */
.list__group-wrap {
  margin-bottom: 12px;
}
.list__group-wrap + .list__group-wrap {
  margin-top: 12px;
}
.list__group {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* ─── Tree 추가 sub-elements ────────────────────────────────── */

/* ─── form__check 확장 (하이라이트 체크 라벨) ──────────────── */
.form__check--highlight {
  background: var(--color-section-bg);
  border: 1px solid var(--color-border);
  padding: 7px 16px;
  border-radius: 8px;
  transition: all 0.2s ease;
}
.form__check--highlight:hover {
  background: var(--color-table-hover);
  border-color: var(--color-primary);
}

/* ─── Mode switcher (탭·토글 그룹 대체) ────────────────────── */
.mode-switcher {
  display: flex;
  gap: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 12px;
}

/* ─── Form section (폼 그룹 섹션 분리) ─────────────────────── */
.form-section {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--color-border);
}

/* ─── Hint section (점선 구분 보조 영역) ──────────────────── */
.hint-section {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed var(--color-border);
}

/* ─── Split-panel 보조 modifier ─────────────────────────────── */
.split-panel__body--padded { padding: 16px; }
.split-panel__search {
  padding: 8px;
  border-bottom: 1px solid var(--color-border);
}
.split-panel__search input {
  width: 100%;
  font-size: var(--fs-sm);
}

/* ─── Card 상태/modifier 확장 ───────────────────────────────── */
.card.is-active {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 1px var(--color-primary);
}
.card--flush {
  background: var(--color-section-bg);
  border-radius: var(--radius-lg);
  padding: 17px;
  box-shadow: 0 0 0 1px var(--color-border);
  border: none;
}

/* ─── badge 보조 variant ────────────────────────────────────── */
.badge-danger-text {
  background: transparent;
  color: var(--color-danger);
  border: 1px solid var(--color-danger);
}
.btn-danger-text {
  background: transparent;
  color: var(--color-danger);
  border: 1px solid var(--color-danger);
}
.btn-danger-text:hover {
  background: var(--color-danger);
  color: #fff;
}

/* ═══════════════════════════════════════════════════════════════════
 * 이미지맵/에디터 공통 컴포넌트 — 2026-04-19 newsletter 이관
 * ═══════════════════════════════════════════════════════════════════ */

/* ─── Step indicator (단계 표시기) ────────────────────────────── */
.step-indicator {
  display: flex;
  gap: 6px;
  align-items: center;
  padding: 10px 16px;
  background: var(--color-section-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  font-size: var(--fs-xs);
}
.step-indicator__badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: 20px;
  background: var(--color-section-bg);
  color: var(--color-muted);
  font-size: var(--fs-badge);
  letter-spacing: 0.2px;
  user-select: none;
}
.step-indicator__badge.is-active {
  background: var(--badge-info-bg);
  color: var(--badge-info-text);
}
.step-indicator__badge.is-done {
  background: var(--color-success);
  color: #fff;
}
.step-indicator__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.5;
}
.step-indicator__badge.is-active .step-indicator__dot,
.step-indicator__badge.is-done   .step-indicator__dot {
  opacity: 1;
}
.step-indicator__sep {
  color: var(--color-border);
  font-size: var(--fs-sm);
}

/* ─── Node status (서비스/노드 상태 배지) ────────────────────── */
.node-status {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: var(--fs-code);
  font-weight: 500;
  letter-spacing: 0.2px;
  vertical-align: middle;
  border: 1px solid transparent;
  white-space: nowrap;
}
.node-status__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.node-status.is-checking {
  color: var(--color-muted);
  background: var(--color-section-bg);
  border-color: var(--color-border);
}
.node-status.is-checking .node-status__dot {
  animation: status-pulse 1s ease-in-out infinite;
}
.node-status.is-ok {
  color: var(--color-success-text);
  background: var(--color-success-bg);
  border-color: var(--color-success-border);
}
.node-status.is-fail {
  color: var(--color-danger-text);
  background: var(--color-danger-bg);
  border-color: var(--color-danger-border);
  cursor: pointer;
}
@keyframes status-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}

/* ─── Mode display (현재 모드 안내 박스) ─────────────────────── */
.mode-display {
  padding: 8px 12px;
  background: var(--color-section-bg);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
  color: var(--color-muted);
}
.mode-display__label {
  font-weight: 500;
  color: var(--color-text);
}

/* ─── Code output (검은 배경 monospace 출력) ────────────────── */
.code-output {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  background: #0f172a;
  color: #e2e8f0;
  padding: 12px;
  border-radius: var(--radius-sm);
  max-height: 450px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-all;
}

/* ─── Button group (작은 버튼 그룹 — 크기 프리셋 등) ──────── */
.button-group {
  display: inline-flex;
  gap: 4px;
  flex-wrap: wrap;
  padding: 4px;
  background: var(--color-section-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}
.button-group__btn {
  padding: var(--ctrl-py-xs) 10px;
  font-size: var(--fs-xs);
  background: transparent;
  border: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  color: var(--color-muted);
}
.button-group__btn:hover,
.button-group__btn.is-active {
  background: var(--color-primary);
  color: #fff;
}
/* ghost variant (no surrounding container) */
.button-group--ghost {
  background: transparent;
  border: none;
  padding: 0;
}
.button-group--ghost .button-group__btn {
  padding: var(--ctrl-py-xs) 10px;
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
}
.button-group--ghost .button-group__btn:hover,
.button-group--ghost .button-group__btn.is-active {
  background: transparent;
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* ─── Recent cards (가로 스크롤 카드 리스트) ───────────────── */
.recent-list {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 6px 0;
}
.recent-list__item {
  flex-shrink: 0;
  width: 140px;
  padding: 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-card-bg);
  cursor: pointer;
  font-size: var(--fs-xs);
  transition: border-color 0.15s;
}
.recent-list__item:hover {
  border-color: var(--color-primary);
}
.recent-list__thumb {
  width: 100%;
  height: 72px;
  background: var(--color-section-bg);
  border-radius: var(--radius-sm);
  margin-bottom: 6px;
  background-size: cover;
  background-position: center;
}
.recent-list__title {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.recent-list__meta {
  color: var(--color-muted);
  font-size: var(--fs-xs);
  margin-top: 2px;
}

/* ─── Candidate list (아코디언 리스트 — 자동 모드 후보 요소) ── */
.candidate {
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  flex-shrink: 0;   /* .candidate-list flex column 내부에서 자연 높이 유지 — 총 높이 초과 시 부모(list)가 스크롤 */
}
.candidate__header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  cursor: pointer;
  user-select: none;
}
.candidate__header:hover { background: var(--color-table-hover); }
.candidate__selector {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--color-primary);
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.candidate__count {
  font-size: var(--fs-xs);
  color: var(--color-muted);
  white-space: nowrap;
}
.candidate__items {
  border-top: 1px solid var(--color-border);
  padding: 6px 10px;
  display: none;
  flex-direction: column;
  gap: 4px;
  background: var(--color-section-bg);
}
.candidate.is-expanded .candidate__items { display: flex; }
.candidate__item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-xs);
}
.candidate__item input[type="url"],
.candidate__item input[type="text"] {
  flex: 1;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
}

/* ─── Candidate list container (스크롤 트리) ────────────────── */
.candidate-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 340px;
  overflow-y: auto;
  padding: 4px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-section-bg);
}

/* ─── Preview iframe ──────────────────────────────────────── */
.preview-frame {
  width: 100%;
  height: 500px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: #fff;
}

/* ─── Icon-btn 확장 (위험/비활성) ─────────────────────────── */
.icon-btn--danger {
  color: var(--color-danger);
  border-color: var(--color-danger);
}
.icon-btn--danger:hover {
  background: var(--color-danger);
  color: #fff;
  border-color: var(--color-danger);
}

/* ─── Form__meta (form hint 계열의 보조 메타 정보) ────────── */
.form__meta {
  font-size: var(--fs-xs);
  color: var(--color-muted);
  margin-top: 2px;
}

/* ─── Panel toolbar (split-panel 내부 sticky 상단 툴바) ────
 * 에디터 패널의 상단 고정 액션/모드 바. split-panel__col/__right 최상단에 배치.
 * 캔버스 에디터, 코드 에디터, 폼 에디터 등 범용 사용.
 * ─────────────────────────────────────────────────── */
.panel-toolbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--color-card-bg);
  /* border-bottom: 1px solid var(--color-border); */
  padding: 8px 0 4px 0;
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 4px;
  flex-shrink: 0;
}
/* 툴바 내부 인라인 버튼 그룹 (줄바꿈 없음) */
.panel-toolbar__group {
  display: inline-flex;
  gap: 6px;
  flex-shrink: 0;
}
/* 툴바 내부 좌측 정렬·남은 공간 차지 정보 슬롯 (모드 표시용) */
.panel-toolbar__info {
  flex: 1;
  min-width: 160px;
}

/* ─── Canvas editor (이미지맵 드로잉 / 이미지 영역 편집) ──── */
.canvas-editor {
  position: relative;
  line-height: 0;
}
.canvas-editor__wrap {
  flex: 1;
  min-height: 400px;
  border: 2px dashed var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-section-bg);
  overflow: auto;
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  margin-bottom: 12px;
}
.canvas-editor__wrap.is-empty {
  align-items: center;
  color: var(--color-muted);
  font-size: var(--fs-sm);
}
.canvas-editor__img {
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}
.canvas-editor__svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: auto;
  touch-action: none;
  -ms-touch-action: none;
  user-select: none;
}
.canvas-editor__first-marker {
  stroke: var(--color-warning);
  stroke-width: 1.5;
  pointer-events: none;
  animation: marker-pulse 1s ease-in-out infinite;
}
@keyframes marker-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}
.canvas-editor__shape {
  fill: rgba(59, 130, 246, 0.18);
  stroke: var(--color-primary);
  stroke-width: 2;
  cursor: pointer;
}
.canvas-editor__shape--preview {
  fill: rgba(59, 130, 246, 0.10);
  stroke: var(--color-primary);
  stroke-width: 1.5;
  stroke-dasharray: 6 4;
  pointer-events: none;
}
/* href(클릭 시 이동할 URL) 가 설정된 영역 — 푸른색 계열로 강조 */
.canvas-editor__shape.is-configured {
  fill: rgba(37, 99, 235, 0.30);
  stroke: #2563eb;
  stroke-width: 2;
}
.canvas-editor__shape.is-selected {
  fill: rgba(234, 88, 12, 0.22);
  stroke: var(--color-warning);
  stroke-width: 3;
  stroke-dasharray: 4 2;
  cursor: move;
}
/* 선택+설정 동시 상태 — 선택 상태(orange) 우선 */
.canvas-editor__shape.is-configured.is-selected {
  fill: rgba(234, 88, 12, 0.22);
  stroke: var(--color-warning);
  stroke-dasharray: 4 2;
}
.canvas-editor__handle {
  fill: #fff;
  stroke: var(--color-primary);
  stroke-width: 1.5;
  pointer-events: auto;
  transition: r 0.1s, fill 0.1s;
}
.canvas-editor__handle:hover,
.canvas-editor__handle.is-active {
  fill: var(--color-primary);
}
.canvas-editor__handle[data-corner="nw"],
.canvas-editor__handle[data-corner="se"] { cursor: nwse-resize; }
.canvas-editor__handle[data-corner="ne"],
.canvas-editor__handle[data-corner="sw"] { cursor: nesw-resize; }
.canvas-editor__handle[data-corner="n"],
.canvas-editor__handle[data-corner="s"] { cursor: ns-resize; }
.canvas-editor__handle[data-corner="e"],
.canvas-editor__handle[data-corner="w"] { cursor: ew-resize; }

/* ═══════════════════════════════════════════════════════════════════
 * 코드 에디터 / 검증 리스트 / 전송 레이아웃 — 2026-04-19 webzine 이관
 * ═══════════════════════════════════════════════════════════════════ */

/* ─── Code editor (CodeMirror 래퍼 + textarea fallback) ───── */
.code-editor {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.cm-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.cm-wrap .CodeMirror,
.cm-wrap .cm-editor {
  flex: 1;
  height: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  line-height: 1.6;
}
.cm-wrap .cm-editor { overflow: hidden; }
.cm-wrap .cm-scroller { overflow: auto; }

.code-editor__textarea {
  width: 100%;
  min-height: 300px;
  padding: 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.6;
  resize: vertical;
  background: #1e1e2e;
  color: #cdd6f4;
  tab-size: 2;
}
.code-editor__textarea--css {
  font-family: var(--font-mono);
}

/* ─── Validation list (검증 결과 리스트) ─────────────────── */
.validation-list {
  list-style: none;
  margin: 0;
  padding: 12px;
}
.validation-list__item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  font-size: var(--fs-sm);
  border-bottom: 1px solid var(--color-border);
}
.validation-list__item:last-child { border-bottom: none; }
.validation-list__item.is-success { color: var(--color-success-text); }
.validation-list__item.is-error   { color: var(--color-danger-text); }
.validation-list__item.is-warning { color: var(--color-warning-text); }

/* ─── Preview frame content (iframe wrap 확장) ───────────── */
.preview-frame__content {
  width: 100%;
  height: 100%;
  border: none;
  background: #fff;
}

/* ─── Preview layout (iframe + side panel 2열) ─────────── */
.preview-layout {
  display: flex;
  gap: 12px;
  flex: 1;
  min-height: 0;
}
.preview-layout__main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.preview-layout__side {
  flex: 0 0 300px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
}

/* ─── Transfer layout (2개 패널 + 버튼 중앙 — 항목 이동용) ─── */
.transfer-layout {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 12px;
  align-items: stretch;
  min-height: 0;
}
.transfer-layout__panel {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-card-bg);
  overflow: hidden;
  min-height: 0;
}
.transfer-layout__panel-body {
  flex: 1;
  overflow-y: auto;
  padding: 8px;
}
.transfer-buttons {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  padding: 0 8px;
}
.transfer-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background 0.15s;
}
.transfer-item:hover { background: var(--color-table-hover); }
.transfer-item.is-selected {
  background: var(--color-primary-glow);
  color: var(--color-primary);
}

/* ─── Selector bar (상단 고객사·볼륨 선택 바) ─────────── */
.selector-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  flex-shrink: 0;
}
.selector-bar__item {
  display: flex;
  align-items: center;
  gap: 6px;
}
.selector-bar__label {
  font-size: var(--fs-xs);
  color: var(--color-muted);
  font-weight: 500;
  white-space: nowrap;
}
.selector-bar__select {
  min-width: 180px;
}
.selector-bar__fixed {
  display: inline-flex;
  align-items: center;
  min-width: 180px;
  padding: var(--ctrl-py) 10px;
  background: var(--color-section-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  color: var(--color-text);
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.selector-bar__deploy {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
}
.selector-bar__deploy-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--color-section-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
  color: var(--color-text);
  text-decoration: none;
  transition: all 0.15s;
}
.selector-bar__deploy-link:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* ─── Editor content (에디터 본문 영역) ─────────────────── */
.editor-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  gap: 8px;
}
/* @deprecated — `.split-panel__body` 로 통합. 기존 외부 사용 호환을 위해 alias 만 유지. 신규 사용 금지. */
.editor-panel-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.editor-toolbar {
  display: flex;
  gap: 8px;
  padding: 8px 0;
  border-top: 1px solid var(--color-border);
  margin-top: 8px;
}

/* ─── Visual editor placeholder ─────────────────────────── */
.visual-editor {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 300px;
  background: var(--color-section-bg);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-sm);
}
.visual-editor__placeholder {
  color: var(--color-muted);
  text-align: center;
  font-size: var(--fs-sm);
}

/* ─── 배포 확인 배지 (.version-badge) ─────────
 * 헤더 로고 옆(어두운 바탕). common/js/version-badge.js 가 그린다. 명세 .claude/docs/components/overlay.md §5
 * 첫 점(배포 상태): --same 모든 항목 운영과 같음 · --diff 뒤처진 항목 있음 · --none 운영 도장 없음/읽기 실패
 * 둘째 점(운영 상태, __dot--health): --health-ok 정상 · --health-warn 일일 보고·스모크 이상 · --health-none 보고 없음 */
.version-badge { position: relative; display: inline-flex; align-items: center; flex-shrink: 0; font-size: var(--fs-badge); font-weight: 500; line-height: 1.2; }
.version-badge__pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px; border: 1px solid rgba(255, 255, 255, 0.12); border-radius: var(--radius-xl);
  background: rgba(255, 255, 255, 0.08); color: inherit; font: inherit; cursor: pointer;
}
.version-badge__pill:hover { background: rgba(255, 255, 255, 0.16); }
.version-badge__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--color-muted); flex-shrink: 0; }
.version-badge--same .version-badge__dot { background: var(--color-success-border); }
.version-badge--diff .version-badge__dot { background: var(--color-warning-border); }
.version-badge__dot--health { width: 6px; height: 6px; margin-left: 2px; }
.version-badge--health-ok .version-badge__dot--health { background: var(--color-success-border); }
.version-badge--health-warn .version-badge__dot--health { background: var(--color-danger-border); }
.version-badge--health-none .version-badge__dot--health { background: var(--color-muted); }
.version-badge__health { display: flex; gap: 10px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--color-border); color: var(--color-muted); }
.version-badge__health.is-warn { color: var(--color-danger-text); }
.version-badge__health > span:last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.version-badge__text { font-family: var(--font-mono); letter-spacing: 0; white-space: nowrap; }

.version-badge__panel {
  position: absolute; top: calc(100% + 8px); left: 0; z-index: 60; min-width: 600px; max-width: min(820px, calc(100vw - 32px));   /* 항목 한 줄씩 — 상태·제목·커밋이 줄바꿈 없이 */
  padding: 12px 14px; border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-card-bg); color: var(--color-text); box-shadow: var(--shadow-md);
  font-size: var(--fs-xs); font-weight: 400; line-height: 1.45; text-align: left; white-space: normal;
}
.version-badge__row { display: flex; gap: 10px; }
.version-badge__row + .version-badge__row { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--color-border); }
.version-badge__label { flex-shrink: 0; width: 32px; color: var(--color-muted); font-weight: 600; }
.version-badge__body { min-width: 0; flex: 1; }
.version-badge__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.version-badge__hash { font-family: var(--font-mono); font-size: var(--fs-code); font-weight: 600; }
.version-badge__time, .version-badge__extra, .version-badge__deploy, .version-badge__items { color: var(--color-muted); }
.version-badge--diff .version-badge__extra { color: var(--color-warning-text); }
.version-badge__subject { margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.version-badge__link { color: var(--color-text); text-decoration: underline; }
.version-badge__empty { color: var(--color-muted); }
.version-badge__commits-wrap, .version-badge__items-wrap { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--color-border); }
.version-badge__items-table { display: grid; grid-template-columns: auto auto 1fr auto; column-gap: 10px; row-gap: 2px; white-space: nowrap; }
.version-badge__item { display: contents; color: var(--color-muted); }
.version-badge__item.is-behind { color: var(--color-text); }
.version-badge__item-name { font-weight: 600; }
.version-badge__item-state { text-align: right; }
.version-badge__item.is-behind .version-badge__item-state { color: var(--color-warning-text); font-weight: 600; }
.version-badge__unrecorded { margin-top: 6px; color: var(--color-warning-text); }
.version-badge__commits-title { color: var(--color-muted); font-weight: 600; margin-bottom: 4px; }
.version-badge__commits { margin: 0; padding-left: 16px; }
.version-badge__commits li { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ─── .app-shell — 독립 화면 틀(머리·왼쪽 메뉴·본문). 명세 .claude/docs/components/layout.md §0 ───
 * 머리는 포털 .topbar 와 같은 어두운 60px. 오른쪽 단추는 28px 사각 .btn-icon 한 모양. */
.app-shell { display: flex; flex-direction: column; height: 100vh; }
@supports (height: 100dvh) { .app-shell { height: 100dvh; } }   /* 모바일 주소창 — 포털 .shell 과 같은 보정 */
.app-header {
  display: flex; align-items: center; gap: 16px; flex-shrink: 0; height: 60px; padding: 0 20px;
  background: var(--color-header); color: var(--color-header-text);
}
.app-header__brand { display: inline-flex; align-items: center; gap: 8px; flex-shrink: 1; color: var(--color-header-text); text-decoration: none; }
.app-header__icon {
  display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px;
  border-radius: var(--radius-sm); background: var(--color-sidebar-active); color: var(--color-header-accent);
}
.app-header__title { font-size: var(--fs-md); font-weight: 600; }
.app-header__crumb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-xs); color: var(--color-header-muted); }
.app-header__badge { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; text-decoration: none; }   /* 화면 전용 상태 배지(.badge 와 함께) */
.app-header__actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; margin-left: auto; }
.app-header__user { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-xs); color: var(--color-header-muted); white-space: nowrap; }
/* 머리 위 단추(포털 상단바 포함) — 28px 사각, 글자가 있으면 가로 8px */
.app-header .btn-icon,
.topbar .btn-icon {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 28px; min-width: 28px; padding: 0 8px;
  color: var(--color-header-icon); font-size: var(--fs-xs); text-decoration: none;
}
.app-header .btn-icon:hover,
.topbar .btn-icon:hover { background: var(--color-sidebar-hover); color: var(--color-header-text); }
.app-header .btn-icon svg,
.topbar .btn-icon svg { width: 16px; height: 16px; }
.app-header .app-header__menu { display: none; }   /* 메뉴 서랍 단추는 ≤900px 에서만 — .btn-icon 의 inline-flex 보다 앞서게 */
.app-body { display: flex; flex: 1; min-height: 0; position: relative; }
.app-nav {
  display: flex; flex-direction: column; gap: 2px; flex-shrink: 0; width: 220px; padding: 12px 10px;
  background: var(--color-sidebar); overflow-y: auto;
}
.app-nav__section { padding: 12px 10px 4px; font-size: var(--fs-xs); font-weight: 600; color: var(--color-header-muted); }
.app-nav__item {
  display: flex; align-items: center; gap: 13px; padding: 11px 12px; border-radius: 7px;
  color: var(--color-header-muted); font-size: 14px; text-decoration: none; transition: background 0.12s, color 0.12s;
}
.app-nav__item > i { width: 18px; font-size: 18px; text-align: center; }
.app-nav__item:hover { background: var(--color-sidebar-hover); color: var(--color-header-text); }
.app-nav__item.is-active { background: var(--color-sidebar-active); color: var(--color-header-text); font-weight: 600; }
[data-theme="dark"] .app-nav__item.is-active { color: var(--color-primary); }
.app-nav__badge { margin-left: auto; padding: 1px 6px; border-radius: 10px; font-size: var(--fs-badge); background: var(--color-sidebar-active); color: var(--color-header-text); }
.app-nav-backdrop { display: none; }
.app-main { flex: 1; min-height: 0; min-width: 0; overflow-y: auto; padding: 16px; }
/* .page-header + .page-content 구조 화면(SNS 매니저) — 본문은 고정, .page-content 안의 표·카드가 스스로 스크롤 */
.app-main--column { display: flex; flex-direction: column; gap: 12px; padding: 16px 20px; overflow: hidden; }
.app-main--column > .page-header { flex-shrink: 0; }
.app-main--column > .page-content { flex: 1; min-height: 0; }

@media (max-width: 900px) {
  .app-header { gap: 8px; padding: 0 12px; }
  .app-header .app-header__menu { display: inline-flex; }
  .app-header__crumb,
  .app-header__user,
  .app-header .btn-icon > span,
  .app-header > .badge,
  .app-header__badge { display: none; }
  .app-header__brand { min-width: 0; }
  .app-header__title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .app-header__actions { gap: 4px; }
  /* 배포 배지는 점만(포털 상단바와 같은 처리), 패널은 화면 폭으로 */
  .app-header .version-badge { position: static; }
  .app-header .version-badge__text { display: none; }
  .app-header .version-badge__panel { position: fixed; top: 64px; left: 8px; right: 8px; min-width: 0; max-width: none; max-height: calc(100vh - 80px); overflow-y: auto; }
  .app-nav { position: absolute; top: 0; bottom: 0; left: 0; z-index: 60; transform: translateX(-100%); transition: transform 0.2s ease; }
  .app-shell.is-nav-open .app-nav { transform: none; box-shadow: 4px 0 20px rgba(0, 0, 0, 0.4); }
  .app-shell.is-nav-open .app-nav-backdrop { display: block; position: absolute; inset: 0; z-index: 59; background: rgba(0, 0, 0, 0.45); }
  .app-main--column { padding: 12px; overflow-y: auto; }
  .app-main--column > .page-content { flex: none; min-height: 60vh; }
}
